diff --git a/.gitignore b/.gitignore index c497e28d7..aeec2c4b5 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ docs/build/ .phpunit.result.cache ###< phpunit/phpunit ### +/.php-cs-fixer.cache +/.idea/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 68b1bcf08..f76ec4b98 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,50 +1,87 @@ --- -image: registry.gitlab.com/chill-projet/chill-app/php-base-image:7.4 # Select what we should cache between builds cache: - paths: - - tests/app/vendor/ - - .composer - -before_script: - # add extensions to postgres - - PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;" - # Install and run Composer - - mkdir -p $COMPOSER_HOME - - curl -sS https://getcomposer.org/installer | php - - php -d memory_limit=2G composer.phar install - - php tests/app/bin/console doctrine:migrations:migrate -n - - php -d memory_limit=2G tests/app/bin/console cache:clear --env=dev - - php -d memory_limit=3G tests/app/bin/console doctrine:fixtures:load -n - - php -d memory_limit=2G tests/app/bin/console cache:clear --env=test - - echo "before_script finished" + paths: + - tests/app/vendor/ + - .cache # Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service # See http://docs.gitlab.com/ee/ci/services/README.html for examples. services: - - name: postgis/postgis:12-3.1-alpine - alias: db - - name: redis - alias: redis + - name: postgis/postgis:12-3.1-alpine + alias: db + - name: redis + alias: redis # Set any variables we need variables: - # Configure postgres environment variables (https://hub.docker.com/r/_/postgres/) - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - # fetch the chill-app using git submodules - GIT_SUBMODULE_STRATEGY: recursive - REDIS_HOST: redis - REDIS_PORT: 6379 - REDIS_URL: redis://redis:6379 - # change vendor dir to make the app install into tests/apps - COMPOSER_VENDOR_DIR: tests/app/vendor - # cache some composer data - COMPOSER_HOME: .composer + GIT_DEPTH: 1 + # Configure postgres environment variables (https://hub.docker.com/r/_/postgres/) + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + # fetch the chill-app using git submodules + GIT_SUBMODULE_STRATEGY: recursive + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_URL: redis://redis:6379 + # change vendor dir to make the app install into tests/apps + COMPOSER_VENDOR_DIR: tests/app/vendor +stages: + - Composer install + - Tests -# Run our tests -test: - script: - - php -d memory_limit=3G bin/phpunit --colors=never +build: + stage: Composer install + image: registry.gitlab.com/chill-projet/chill-app/php-base-image:7.4 + before_script: + - curl -sS https://getcomposer.org/installer | php + - php -d memory_limit=2G composer.phar config -g cache-dir "$(pwd)/.cache" + script: + - php -d memory_limit=2G composer.phar install --optimize-autoloader --no-ansi --no-interaction --no-progress + cache: + paths: + - .cache/ + artifacts: + expire_in: 30 min + paths: + - bin + - tests/app/vendor/ + +code_style: + stage: Tests + image: registry.gitlab.com/chill-projet/chill-app/php-base-image:7.4 + script: + - bin/grumphp run --tasks=phpcsfixer + artifacts: + expire_in: 30 min + paths: + - bin + - tests/app/vendor/ + +sa_tests: + stage: Tests + image: registry.gitlab.com/chill-projet/chill-app/php-base-image:7.4 + script: + - bin/grumphp run --tasks=phpstan + artifacts: + expire_in: 30 min + paths: + - bin + - tests/app/vendor/ + +unit_tests: + stage: Tests + image: registry.gitlab.com/chill-projet/chill-app/php-base-image:7.4 + script: + - php tests/app/bin/console doctrine:migrations:migrate -n + - php -d memory_limit=2G tests/app/bin/console cache:clear --env=dev + - php -d memory_limit=3G tests/app/bin/console doctrine:fixtures:load -n + - php -d memory_limit=2G tests/app/bin/console cache:clear --env=test + - php -d memory_limit=3G bin/phpunit --colors=never + artifacts: + expire_in: 30 min + paths: + - bin + - tests/app/vendor/ diff --git a/.php_cs.dist.php b/.php_cs.dist.php new file mode 100644 index 000000000..c9cd4d06d --- /dev/null +++ b/.php_cs.dist.php @@ -0,0 +1,79 @@ +getFinder() + ->ignoreDotFiles(false) + ->notPath('tests/app') + ->name(['.php_cs.dist.php']); + +$rules = $config->getRules(); + +$riskyRules = [ + 'final_internal_class' => false, + 'no_useless_sprintf' => false, + 'dir_constant' => false, + 'no_alias_functions' => false, + 'implode_call' => false, + 'combine_nested_dirname' => false, + 'pow_to_exponentiation' => false, + 'comment_to_phpdoc' => false, + 'no_unset_on_property' => false, + 'strict_param' => false, + 'native_constant_invocation' => false, + 'php_unit_test_annotation' => false, + 'php_unit_no_expectation_annotation' => false, + 'declare_strict_types' => false, + 'function_to_constant' => false, + 'is_null' => false, + 'native_function_invocation' => false, + 'ternary_to_elvis_operator' => false, + 'no_trailing_whitespace_in_string' => false, + 'no_unreachable_default_argument_value' => false, + 'php_unit_test_case_static_method_calls' => false, + 'strict_comparison' => false, + 'array_push' => false, + 'ereg_to_preg' => false, + 'error_suppression' => false, + 'fopen_flag_order' => false, + 'fopen_flags' => false, + 'logical_operators' => false, + 'modernize_types_casting' => false, + 'no_homoglyph_names' => false, + 'no_unneeded_final_method' => false, + 'non_printable_character' => false, + 'ordered_traits' => false, + 'php_unit_mock_short_will_return' => false, + 'php_unit_set_up_tear_down_visibility' => false, + 'set_type_to_cast' => false, + 'string_line_ending' => false, + 'ordered_interfaces' => false, + 'php_unit_expectation' => false, + 'php_unit_mock' => false, + 'php_unit_namespaced' => false, + 'random_api_migration' => false, + 'static_lambda' => false, + 'php_unit_construct' => false, + 'psr_autoloading' => false, + 'php_unit_dedicate_assert' => false, +]; + +$rules = array_merge( + $rules, + $riskyRules +); + +$rules['header_comment']['header'] = trim(file_get_contents(__DIR__ . '/resource/header.txt')); + +return $config->setRules($rules); diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e5cdc25b..4acb29efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,19 @@ and this project adheres to ## Unreleased +* Use the user.label in accompanying course banner, instead of username; +* fix: show validation message when closing accompanying course; +## Test releases + +### Test release 2021-11-22 + +* [activity] delete admin_user_show in twig template because this route is not defined and should be defined +* [activity] suggest requestor, user and ressources for adding persons|user|3rdparty +* [calendar] suggest persons, professionals and invites for adding persons|3rdparty|user +* [activity] take into account the restrictions on person|thirdparties|users visibilities defined in ActivityType +* [main] Add currentLocation to the User entity + add a page for selecting this location + add in the user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/133) +* [activity] add user current location as default location for a new activity (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/133) * [task] Select2 field in task form to allow search for a user (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/167) * remove "search by phone configuration option": search by phone is now executed by default * remplacer le classement par ordre alphabétique par un classement par ordre de pertinence, qui tient compte: @@ -29,10 +41,11 @@ and this project adheres to * [person] fix bounds for computing current person address: the new address appears immediatly * [docgen] create a normalizer and serializer for normalization on doc format * [person normalization] the key center is now "centers" and is an array. Empty array if no center +* [accompanyingCourse] Ability to close accompanying course (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/296) +* [task] Select2 field in task form to allow search for a user (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/167) +* [list result] show all courses, except ones with period closed -## Test releases - ### Test release 2021-11-15 * [main] fix adding multiple AddresseDeRelais (combine PickAddressType with ChillCollection) @@ -49,6 +62,8 @@ and this project adheres to * [person] do not ask for center any more on person creation * [3party] do not ask for center any more on 3party creation +## Test releases + ### Test release 2021-11-08 * [person]: Display the name of a user when searching after a User (TMS) diff --git a/LICENSE b/LICENSE index 1cf094aab..be3f7b28e 100644 --- a/LICENSE +++ b/LICENSE @@ -629,12 +629,12 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - chill-bundles - Copyright (C) 2021 Chill Project + + Copyright (C) This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/composer.json b/composer.json index 18722a420..254486913 100644 --- a/composer.json +++ b/composer.json @@ -52,10 +52,9 @@ }, "require-dev": { "doctrine/doctrine-fixtures-bundle": "^3.3", + "drupol/php-conventions": "^5", "fakerphp/faker": "^1.13", "nelmio/alice": "^3.8", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^7.0", "symfony/debug-bundle": "^5.1", 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 bc76f96d6..5ea9d6214 100644 --- a/docs/source/_static/code/exports/CountPerson.php +++ b/docs/source/_static/code/exports/CountPerson.php @@ -1,118 +1,115 @@ - */ 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() - { - 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; - } - - public function getResult($qb, $data) - { - return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); - } - + public function getQueryKeys($data) { // this array match the result keys in the query. We have only // one column. - return array('export_result'); + return ['export_result']; } - - public function getLabels($key, array $values, $data) + + public function getResult($qb, $data) { - - // 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 $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); } - - public function getAllowedFormattersTypes() + + public function getTitle() { - return array(FormatterInterface::TYPE_TABULAR); + return 'Count peoples'; } - - public function buildForm(FormBuilderInterface $builder) { - // this export does not add any form + + public function getType() + { + return Declarations::PERSON_TYPE; } - + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + // 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 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 6ed1e68ef..cd71649c9 100644 --- a/docs/source/development/pagination/example.php +++ b/docs/source/development/pagination/example.php @@ -1,42 +1,47 @@ 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'); - - // create a pagination instance. This instance is only valid for + + // create a pagination instance. This instance is only valid for // the current route and parameters $paginator = $paginatorFactory->create($total); - + // 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 ->setMaxResults($paginator->getItemsPerPage()); - - return $this->render('ChillMyBundle:Item:list.html.twig', array( + + return $this->render( + 'ChillMyBundle:Item:list.html.twig', + [ '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..7d8964903 100644 --- a/docs/source/development/user-interface/widgets/ChillMainConfiguration.php +++ b/docs/source/development/user-interface/widgets/ChillMainConfiguration.php @@ -1,64 +1,61 @@ setWidgetFactories($widgetFactories); + $this->setWidgetFactories($widgetFactories); // we will need the container builder later... - $this->containerBuilder = $containerBuilder; + $this->containerBuilder = $containerBuilder; } - - /** - * {@inheritDoc} - */ + public function getConfigTreeBuilder() { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('chill_main'); + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root('chill_main'); - $rootNode - ->children() + $rootNode + ->children() // ... - - ->arrayNode('widgets') - ->canBeDisabled() - ->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 - ; + ->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; + 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/grumphp.yml b/grumphp.yml new file mode 100644 index 000000000..fd2bfea8b --- /dev/null +++ b/grumphp.yml @@ -0,0 +1,14 @@ +imports: + - { + resource: tests/app/vendor/drupol/php-conventions/config/php73/grumphp.yml, + } + +parameters: + tasks.phpcsfixer.config: .php_cs.dist.php + tasks.license.name: AGPL-3.0 + tasks.license.holder: Champs-Libres + tasks.license.date_from: 2001 + + tasks.phpcsfixer.allow_risky: false + tasks.phpcsfixer.diff: true + tasks.phpstan.level: 1 diff --git a/phpstan-deprecations.neon b/phpstan-deprecations.neon new file mode 100644 index 000000000..bf1ec095e --- /dev/null +++ b/phpstan-deprecations.neon @@ -0,0 +1,1638 @@ +parameters: + ignoreErrors: + - + message: "#^Call to deprecated method getType\\(\\) of class Chill\\\\ActivityBundle\\\\Entity\\\\Activity\\.$#" + count: 3 + path: src/Bundle/ChillActivityBundle/Controller/ActivityController.php + + - + message: "#^Call to deprecated method setType\\(\\) of class Chill\\\\ActivityBundle\\\\Entity\\\\Activity\\.$#" + count: 1 + path: src/Bundle/ChillActivityBundle/Controller/ActivityController.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 2 + path: src/Bundle/ChillActivityBundle/Controller/ActivityController.php + + - + message: "#^Call to deprecated method setType\\(\\) of class Chill\\\\ActivityBundle\\\\Entity\\\\Activity\\.$#" + count: 1 + path: src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 1 + path: src/Bundle/ChillActivityBundle/Entity/ActivityReason.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 1 + path: src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Aggregator\\\\ActivityReasonAggregator\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Aggregator\\\\ActivityTypeAggregator\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Aggregator\\\\ActivityUserAggregator\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\CountActivity\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\ListActivity\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\ListActivity\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Export\\\\StatActivityDuration\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ActivityBundle\\\\Export\\\\Filter\\\\ActivityDateFilter\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Filter\\\\ActivityDateFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Filter\\\\ActivityReasonFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Filter\\\\ActivityTypeFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ActivityBundle\\\\Export\\\\Filter\\\\PersonHavingActivityBetweenDateFilter\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php + + - + message: + """ + #^Return type of method Chill\\\\ActivityBundle\\\\Export\\\\Filter\\\\PersonHavingActivityBetweenDateFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ActivityBundle\\\\Menu\\\\PersonMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\ActivityBundle\\\\Repository\\\\ActivityACLAwareRepository\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\AsideActivityBundle\\\\Menu\\\\UserMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillAsideActivityBundle/src/Menu/UserMenuBuilder.php + + - + message: + """ + #^Class Chill\\\\AMLI\\\\BudgetBundle\\\\Controller\\\\AbstractElementController extends deprecated class Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\: + since Symfony 4\\.2, use "Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\AbstractController" instead\\.$# + """ + count: 1 + path: src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\AMLI\\\\BudgetBundle\\\\Controller\\\\AbstractElementController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php + + - + message: + """ + #^Class Chill\\\\AMLI\\\\BudgetBundle\\\\Controller\\\\ElementController extends deprecated class Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\: + since Symfony 4\\.2, use "Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\AbstractController" instead\\.$# + """ + count: 1 + path: src/Bundle/ChillBudgetBundle/Controller/ElementController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\AMLI\\\\BudgetBundle\\\\Controller\\\\ElementController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillBudgetBundle/Controller/ElementController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\AMLI\\\\BudgetBundle\\\\Menu\\\\UserMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\CalendarBundle\\\\Menu\\\\UserMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php + + - + message: + """ + #^Parameter \\$templating of method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldChoice\\:\\:__construct\\(\\) has typehint with deprecated class Symfony\\\\Bridge\\\\Twig\\\\TwigEngine\\: + since version 4\\.3, to be removed in 5\\.0; use Twig instead\\.$# + """ + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php + + - + message: "#^Used function LogicException not found\\.$#" + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php + + - + message: + """ + #^Parameter \\$templating of method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldDate\\:\\:__construct\\(\\) has typehint with deprecated class Symfony\\\\Bundle\\\\TwigBundle\\\\TwigEngine\\: + since version 4\\.3, to be removed in 5\\.0; use Twig instead\\.$# + """ + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldDate.php + + - + message: + """ + #^Parameter \\$twigEngine of method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldLongChoice\\:\\:__construct\\(\\) has typehint with deprecated class Symfony\\\\Bridge\\\\Twig\\\\TwigEngine\\: + since version 4\\.3, to be removed in 5\\.0; use Twig instead\\.$# + """ + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php + + - + message: + """ + #^Parameter \\$templating of method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldNumber\\:\\:__construct\\(\\) has typehint with deprecated class Symfony\\\\Bundle\\\\TwigBundle\\\\TwigEngine\\: + since version 4\\.3, to be removed in 5\\.0; use Twig instead\\.$# + """ + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php + + - + message: + """ + #^Parameter \\$templating of method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldText\\:\\:__construct\\(\\) has typehint with deprecated class Symfony\\\\Bundle\\\\TwigBundle\\\\TwigEngine\\: + since version 4\\.3, to be removed in 5\\.0; use Twig instead\\.$# + """ + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldText.php + + - + message: + """ + #^Parameter \\$templating of method Chill\\\\CustomFieldsBundle\\\\CustomFields\\\\CustomFieldTitle\\:\\:__construct\\(\\) has typehint with deprecated class Symfony\\\\Bundle\\\\TwigBundle\\\\TwigEngine\\: + since version 4\\.3, to be removed in 5\\.0; use Twig instead\\.$# + """ + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldTitle.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\CustomFieldsBundle\\\\Form\\\\CustomFieldsGroupType\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 1 + path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 3 + path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\DocStoreBundle\\\\Controller\\\\DocumentPersonController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 6 + path: src/Bundle/ChillEventBundle/Controller/EventController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\EventBundle\\\\Controller\\\\EventController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Controller/EventController.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Form/EventType.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Form/Type/PickEventType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\EventBundle\\\\Form\\\\Type\\\\PickEventType\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Form/Type/PickEventType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\EventBundle\\\\Form\\\\Type\\\\PickRoleType\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Form/Type/PickRoleType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\EventBundle\\\\Form\\\\Type\\\\PickStatusType\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Form/Type/PickStatusType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\EventBundle\\\\Menu\\\\PersonMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Menu/PersonMenuBuilder.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Search/EventSearch.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 2 + path: src/Bundle/ChillEventBundle/Search/EventSearch.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillEventBundle/Timeline/TimelineEventProvider.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\AMLI\\\\FamilyMembersBundle\\\\Controller\\\\FamilyMemberController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\AMLI\\\\FamilyMembersBundle\\\\Menu\\\\UserMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillFamilyMembersBundle/Menu/UserMenuBuilder.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php + + - + message: + """ + #^Parameter \\$role of method Chill\\\\MainBundle\\\\CRUD\\\\Controller\\\\CRUDController\\:\\:getReachableCenters\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php + + - + message: + """ + #^Return type of method Chill\\\\MainBundle\\\\CRUD\\\\Controller\\\\CRUDController\\:\\:getTranslator\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php + + - + message: + """ + #^Call to deprecated method getLanguageBundle\\(\\) of class Symfony\\\\Component\\\\Intl\\\\Intl\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use \\{@see Languages\\} or \\{@see Scripts\\} instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php + + - + message: + """ + #^Call to deprecated method getRegionBundle\\(\\) of class Symfony\\\\Component\\\\Intl\\\\Intl\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use \\{@see Countries\\} instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\MainBundle\\\\Controller\\\\ExportController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Controller/ExportController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\MainBundle\\\\Controller\\\\PasswordController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Controller/PasswordController.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php + + - + message: + """ + #^Parameter \\$role of anonymous function has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php + + - + message: + """ + #^Call to deprecated method getLanguageBundle\\(\\) of class Symfony\\\\Component\\\\Intl\\\\Intl\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use \\{@see Languages\\} or \\{@see Scripts\\} instead\\.$# + """ + count: 2 + path: src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php + + - + message: + """ + #^Class Chill\\\\MainBundle\\\\Entity\\\\User implements deprecated interface Symfony\\\\Component\\\\Security\\\\Core\\\\User\\\\AdvancedUserInterface\\: + since Symfony 4\\.1$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Entity/User.php + + - + message: + """ + #^Return type of method Chill\\\\MainBundle\\\\Entity\\\\User\\:\\:getRoles\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Entity/User.php + + - + message: + """ + #^Return type of method Chill\\\\MainBundle\\\\Export\\\\DirectExportInterface\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/DirectExportInterface.php + + - + message: + """ + #^Return type of method Chill\\\\MainBundle\\\\Export\\\\ExportInterface\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/ExportInterface.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/ExportManager.php + + - + message: + """ + #^Parameter \\$translatorInterface of method Chill\\\\MainBundle\\\\Export\\\\Formatter\\\\CSVListFormatter\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php + + - + message: + """ + #^Parameter \\$translatorInterface of method Chill\\\\MainBundle\\\\Export\\\\Formatter\\\\CSVPivotedListFormatter\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php + + - + message: + """ + #^Parameter \\$translatorInterface of method Chill\\\\MainBundle\\\\Export\\\\Formatter\\\\SpreadSheetFormatter\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php + + - + message: + """ + #^Parameter \\$translatorInterface of method Chill\\\\MainBundle\\\\Export\\\\Formatter\\\\SpreadsheetListFormatter\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php + + - + message: + """ + #^Return type of method Chill\\\\MainBundle\\\\Export\\\\ModifierInterface\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Export/ModifierInterface.php + + - + message: + """ + #^Class Chill\\\\MainBundle\\\\Form\\\\Event\\\\CustomizeFormEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Form/Event/CustomizeFormEvent.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\MainBundle\\\\Form\\\\Type\\\\PostalCodeType\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Form/Type/PostalCodeType.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 1 + path: src/Bundle/ChillMainBundle/Form/UserType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\MainBundle\\\\Notification\\\\Mailer\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Notification/Mailer.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 2 + path: src/Bundle/ChillMainBundle/Repository/NotificationRepository.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\MainBundle\\\\Routing\\\\MenuBuilder\\\\SectionMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\MainBundle\\\\Routing\\\\MenuComposer\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Routing/MenuComposer.php + + - + message: + """ + #^Parameter \\$attribute of method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\:\\:userHasAccess\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php + + - + message: + """ + #^Parameter \\$role of method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\:\\:getReachableCircles\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\DefaultVoterHelper\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelper.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\DefaultVoterHelperFactory\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperFactory.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\DefaultVoterHelperGenerator\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperGenerator.php + + - + message: + """ + #^Class Chill\\\\MainBundle\\\\Security\\\\PasswordRecover\\\\PasswordRecoverEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEvent.php + + - + message: "#^Call to deprecated method setTimeout\\(\\) of class Redis\\.$#" + count: 1 + path: src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverLocker.php + + - + message: + """ + #^Class Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcher implements deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 1 + path: src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.php + + - + message: + """ + #^Class Chill\\\\MainBundle\\\\Templating\\\\Events\\\\DelegatedBlockRenderingEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Templating/Events/DelegatedBlockRenderingEvent.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\MainBundle\\\\Validation\\\\Validator\\\\RoleScopeScopePresence\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillMainBundle/Validation/Validator/RoleScopeScopePresence.php + + - + message: + """ + #^Class Chill\\\\PersonBundle\\\\Actions\\\\ActionEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Actions/ActionEvent.php + + - + message: + """ + #^Call to deprecated method getCurrentAccompanyingPeriod\\(\\) of class Chill\\\\PersonBundle\\\\Entity\\\\Person\\: + since 1\\.1 use `getOpenedAccompanyingPeriod instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php + + - + message: + """ + #^Class Chill\\\\PersonBundle\\\\Controller\\\\AccompanyingCourseController extends deprecated class Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\: + since Symfony 4\\.2, use "Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\AbstractController" instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php + + - + message: + """ + #^Parameter \\$trans of method Chill\\\\PersonBundle\\\\Controller\\\\AccompanyingCourseWorkController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php + + - + message: + """ + #^Call to deprecated method getCurrentAccompanyingPeriod\\(\\) of class Chill\\\\PersonBundle\\\\Entity\\\\Person\\: + since 1\\.1 use `getOpenedAccompanyingPeriod instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Controller\\\\HouseholdController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/HouseholdController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Controller\\\\HouseholdMemberController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Controller\\\\PersonController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/PersonController.php + + - + message: + """ + #^Class Chill\\\\PersonBundle\\\\Controller\\\\PersonDuplicateController extends deprecated class Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\Controller\\: + since Symfony 4\\.2, use "Symfony\\\\Bundle\\\\FrameworkBundle\\\\Controller\\\\AbstractController" instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Controller\\\\PersonDuplicateController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php + + - + message: "#^Access to deprecated property \\$proxyAccompanyingPeriodOpenState of class Chill\\\\PersonBundle\\\\Entity\\\\Person\\.$#" + count: 2 + path: src/Bundle/ChillPersonBundle/Entity/Person.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Aggregator\\\\AgeAggregator\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Aggregator/AgeAggregator.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Export\\\\Aggregator\\\\CountryOfBirthAggregator\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Aggregator\\\\CountryOfBirthAggregator\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Export\\\\Aggregator\\\\GenderAggregator\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Aggregator\\\\GenderAggregator\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Export\\\\Aggregator\\\\NationalityAggregator\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Aggregator\\\\NationalityAggregator\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Export\\\\CountPerson\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Export\\\\Export\\\\ListPerson\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Export\\\\ListPerson\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php + + - + message: + """ + #^Call to deprecated method execute\\(\\) of class Doctrine\\\\DBAL\\\\Statement\\: + Statement\\:\\:execute\\(\\) is deprecated, use Statement\\:\\:executeQuery\\(\\) or executeStatement\\(\\) instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Export\\\\Export\\\\ListPersonDuplicate\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Export\\\\ListPersonDuplicate\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Filter\\\\AccompanyingPeriodClosingFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Filter\\\\AccompanyingPeriodFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Filter\\\\AccompanyingPeriodOpeningFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Filter\\\\BirthdateFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Filter/BirthdateFilter.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Export\\\\Filter\\\\GenderFilter\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Filter\\\\GenderFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php + + - + message: + """ + #^Return type of method Chill\\\\PersonBundle\\\\Export\\\\Filter\\\\NationalityFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Export/Filter/NationalityFilter.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php + + - + message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" + count: 1 + path: src/Bundle/ChillPersonBundle/Form/PersonType.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Form/Type/PickPersonType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Form\\\\Type\\\\PickPersonType\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Form/Type/PickPersonType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\PersonBundle\\\\Menu\\\\SectionMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Menu/SectionMenuBuilder.php + + - + message: + """ + #^Class Chill\\\\PersonBundle\\\\Privacy\\\\AccompanyingPeriodPrivacyEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Privacy/AccompanyingPeriodPrivacyEvent.php + + - + message: + """ + #^Class Chill\\\\PersonBundle\\\\Privacy\\\\PrivacyEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Privacy/PrivacyEvent.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriodACLAwareRepository\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepository.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\PersonBundle\\\\Validator\\\\Constraints\\\\Person\\\\PersonHasCenterValidator\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenterValidator.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillPersonBundle/Widget/PersonListWidget.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Controller/ReportController.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 3 + path: src/Bundle/ChillReportBundle/Controller/ReportController.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Export/Export/ReportList.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ReportBundle\\\\Export\\\\Export\\\\ReportList\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Export/Export/ReportList.php + + - + message: + """ + #^Return type of method Chill\\\\ReportBundle\\\\Export\\\\Export\\\\ReportList\\:\\:requiredRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Export/Export/ReportList.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ReportBundle\\\\Export\\\\Export\\\\ReportListProvider\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Export/Export/ReportListProvider.php + + - + message: + """ + #^Return type of method Chill\\\\ReportBundle\\\\Export\\\\Filter\\\\ReportDateFilter\\:\\:addRole\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Form/ReportType.php + + - + message: + """ + #^Parameter \\$role of method Chill\\\\ReportBundle\\\\Form\\\\ReportType\\:\\:appendScopeChoices\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Form/ReportType.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Search/ReportSearch.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillReportBundle/Search/ReportSearch.php + + - + message: + """ + #^Call to deprecated method getReachableScopes\\(\\) of class Chill\\\\MainBundle\\\\Security\\\\Authorization\\\\AuthorizationHelper\\: + Use getReachableCircles$# + """ + count: 2 + path: src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 2 + path: src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\TaskBundle\\\\Controller\\\\SingleTaskController\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php + + - + message: + """ + #^Parameter \\$role of method Chill\\\\TaskBundle\\\\Controller\\\\SingleTaskController\\:\\:setCreateForm\\(\\) has typehint with deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\TaskBundle\\\\Controller\\\\TaskController\\:\\:applyTransitionAction\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Controller/TaskController.php + + - + message: + """ + #^Class Chill\\\\TaskBundle\\\\Event\\\\TaskEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Event/TaskEvent.php + + - + message: + """ + #^Class Chill\\\\TaskBundle\\\\Event\\\\UI\\\\UIEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Event/UI/UIEvent.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 4 + path: src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php + + - + message: + """ + #^Fetching class constant class of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Form/SingleTaskType.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\TaskBundle\\\\Form\\\\SingleTaskType\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Form/SingleTaskType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\TaskBundle\\\\Menu\\\\MenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\TaskBundle\\\\Menu\\\\SectionMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Menu/SectionMenuBuilder.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\TaskBundle\\\\Menu\\\\UserMenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Menu/UserMenuBuilder.php + + - + message: + """ + #^Parameter \\$centerResolverDispatcher of method Chill\\\\TaskBundle\\\\Repository\\\\SingleTaskAclAwareRepository\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\: + Use CenterResolverManager and its interface CenterResolverManagerInterface$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Repository/SingleTaskRepository.php + + - + message: + """ + #^Class Chill\\\\TaskBundle\\\\Security\\\\Authorization\\\\AuthorizationEvent extends deprecated class Symfony\\\\Component\\\\EventDispatcher\\\\Event\\: + since Symfony 4\\.3, use "Symfony\\\\Contracts\\\\EventDispatcher\\\\Event" instead$# + """ + count: 1 + path: src/Bundle/ChillTaskBundle/Security/Authorization/AuthorizationEvent.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 3 + path: src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ThirdPartyBundle\\\\Controller\\\\ThirdPartyController\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ThirdPartyBundle\\\\Form\\\\Type\\\\PickThirdPartyType\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php + + - + message: + """ + #^Parameter \\$translator of method Chill\\\\ThirdPartyBundle\\\\Menu\\\\MenuBuilder\\:\\:__construct\\(\\) has typehint with deprecated interface Symfony\\\\Component\\\\Translation\\\\TranslatorInterface\\: + since Symfony 4\\.2, use Symfony\\\\Contracts\\\\Translation\\\\TranslatorInterface instead$# + """ + count: 1 + path: src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php + + - + message: + """ + #^Instantiation of deprecated class Symfony\\\\Component\\\\Security\\\\Core\\\\Role\\\\Role\\: + since Symfony 4\\.3, to be removed in 5\\.0\\. Use strings as roles instead\\.$# + """ + count: 1 + path: src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php + diff --git a/phpstan-types.neon b/phpstan-types.neon index dca84e17f..a91800d99 100644 --- a/phpstan-types.neon +++ b/phpstan-types.neon @@ -495,11 +495,6 @@ parameters: count: 2 path: src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php - - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" - count: 2 - path: src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelper.php - - message: "#^Call to function in_array\\(\\) requires parameter \\#3 to be set\\.$#" count: 2 diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7943ab3aa..edec00554 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,6 +3,7 @@ parameters: paths: - src/ excludePaths: + - docs/ - src/Bundle/*/Tests/* - src/Bundle/*/tests/* - src/Bundle/*/Test/* @@ -18,7 +19,8 @@ parameters: - src/Bundle/*/src/Resources/* includes: - - phpstan-types.neon - - phpstan-critical.neon - phpstan-baseline.neon + - phpstan-critical.neon + - phpstan-deprecations.neon + - phpstan-types.neon diff --git a/resource/header.txt b/resource/header.txt new file mode 100644 index 000000000..4f6730dc9 --- /dev/null +++ b/resource/header.txt @@ -0,0 +1,5 @@ +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. + 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 @@ serializer = $serializer; } + /** + * Deletes a Activity entity. + * + * @param mixed $id + */ + public function deleteAction(Request $request, $id) + { + $view = null; + + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig'; + } + + $activity = $this->activityRepository->find($id); + + if (!$activity) { + throw $this->createNotFoundException('Unable to find Activity entity.'); + } + + // TODO + // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); + + $form = $this->createDeleteForm($activity->getId(), $person, $accompanyingPeriod); + + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); + + if ($form->isValid()) { + $this->logger->notice('An activity has been removed', [ + 'by_user' => $this->getUser()->getUsername(), + 'activity_id' => $activity->getId(), + 'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null, + 'comment' => $activity->getComment()->getComment(), + 'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null, + 'reasons_ids' => $activity->getReasons() + ->map( + static fn (ActivityReason $ar): int => $ar->getId() + ) + ->toArray(), + 'type_id' => $activity->getType()->getId(), + 'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null, + 'date' => $activity->getDate()->format('Y-m-d'), + 'attendee' => $activity->getAttendee(), + ]); + + $this->entityManager->remove($activity); + $this->entityManager->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The activity has been successfully removed.')); + + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + + return $this->redirectToRoute('chill_activity_activity_list', $params); + } + } + + if (null === $view) { + throw $this->createNotFoundException('Template not found'); + } + + return $this->render($view, [ + 'activity' => $activity, + 'delete_form' => $form->createView(), + 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, + ]); + } + + /** + * Displays a form to edit an existing Activity entity. + */ + public function editAction(int $id, Request $request): Response + { + $view = null; + + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:editPerson.html.twig'; + } + + $entity = $this->activityRepository->find($id); + + if (null === $entity) { + throw $this->createNotFoundException('Unable to find Activity entity.'); + } + + // TODO + // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity); + + $form = $this->createForm(ActivityType::class, $entity, [ + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_ACTIVITY_UPDATE'), + 'activityType' => $entity->getType(), + 'accompanyingPeriod' => $accompanyingPeriod, + ])->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->persist($entity); + $this->entityManager->flush(); + + $this->addFlash('success', $this->get('translator')->trans('Success : activity updated!')); + + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + $params['id'] = $entity->getId(); + + return $this->redirectToRoute('chill_activity_activity_show', $params); + } + + $deleteForm = $this->createDeleteForm($entity->getId(), $person, $accompanyingPeriod); + + /* + * TODO + $event = new PrivacyEvent($person, array( + 'element_class' => Activity::class, + 'element_id' => $entity->getId(), + 'action' => 'edit' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + */ + + if (null === $view) { + throw $this->createNotFoundException('Template not found'); + } + + $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); + + return $this->render($view, [ + 'entity' => $entity, + 'edit_form' => $form->createView(), + 'delete_form' => $deleteForm->createView(), + 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, + 'activity_json' => $activity_array, + ]); + } + /** * Lists all Activity entities. */ @@ -103,7 +256,7 @@ final class ActivityController extends AbstractController $event = new PrivacyEvent($person, [ 'element_class' => Activity::class, - 'action' => 'list' + 'action' => 'list', ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); @@ -121,12 +274,152 @@ final class ActivityController extends AbstractController $view, [ 'activities' => $activities, - 'person' => $person, + 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, ] ); } + public function newAction(Request $request): Response + { + $view = null; + + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:newAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:newPerson.html.twig'; + } + + $activityType_id = $request->get('activityType_id', 0); + $activityType = $this->activityTypeRepository->find($activityType_id); + + if (isset($activityType) && !$activityType->isActive()) { + throw new InvalidArgumentException('Activity type must be active'); + } + + $activityData = null; + + if ($request->query->has('activityData')) { + $activityData = $request->query->get('activityData'); + } + + if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType + || !$activityType->isActive()) { + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + + if (null !== $activityData) { + $params['activityData'] = $activityData; + } + + return $this->redirectToRoute('chill_activity_activity_select_type', $params); + } + + $entity = new Activity(); + $entity->setUser($this->getUser()); + + if ($person instanceof Person) { + $entity->setPerson($person); + } + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $entity->setAccompanyingPeriod($accompanyingPeriod); + } + + $entity->setType($activityType); + $entity->setDate(new DateTime('now')); + + if ($request->query->has('activityData')) { + $activityData = $request->query->get('activityData'); + + if (array_key_exists('durationTime', $activityData)) { + $durationTimeInMinutes = $activityData['durationTime']; + $hours = floor($durationTimeInMinutes / 60); + $minutes = $durationTimeInMinutes % 60; + $duration = DateTime::createFromFormat('H:i', $hours . ':' . $minutes); + + if ($duration) { + $entity->setDurationTime($duration); + } + } + + if (array_key_exists('date', $activityData)) { + $date = DateTime::createFromFormat('Y-m-d', $activityData['date']); + + if ($date) { + $entity->setDate($date); + } + } + + if (array_key_exists('personsId', $activityData)) { + foreach ($activityData['personsId'] as $personId) { + $concernedPerson = $this->personRepository->find($personId); + $entity->addPerson($concernedPerson); + } + } + + if (array_key_exists('professionalsId', $activityData)) { + foreach ($activityData['professionalsId'] as $professionalsId) { + $professional = $this->thirdPartyRepository->find($professionalsId); + $entity->addThirdParty($professional); + } + } + + if (array_key_exists('location', $activityData)) { + $location = $this->locationRepository->find($activityData['location']); + $entity->setLocation($location); + } + + if (array_key_exists('comment', $activityData)) { + $comment = new CommentEmbeddable(); + $comment->setComment($activityData['comment']); + $comment->setUserId($this->getUser()->getid()); + $comment->setDate(new DateTime('now')); + $entity->setComment($comment); + } + } + + $this->denyAccessUnlessGranted(ActivityVoter::CREATE, $entity); + + $form = $this->createForm(ActivityType::class, $entity, [ + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_ACTIVITY_CREATE'), + 'activityType' => $entity->getType(), + 'accompanyingPeriod' => $accompanyingPeriod, + ])->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->persist($entity); + $this->entityManager->flush(); + + $this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); + + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + + $params['id'] = $entity->getId(); + + return $this->redirectToRoute('chill_activity_activity_show', $params); + } + + if (null === $view) { + throw $this->createNotFoundException('Template not found'); + } + + $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); + + $defaultLocationId = $this->getUser()->getCurrentLocation()->getId(); + + return $this->render($view, [ + 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, + 'entity' => $entity, + 'form' => $form->createView(), + 'activity_json' => $activity_array, + 'default_location_id' => $defaultLocationId, + ]); + } + public function selectTypeAction(Request $request): Response { $view = null; @@ -159,7 +452,7 @@ final class ActivityController extends AbstractController ]; } - if ($view === null) { + if (null === $view) { throw $this->createNotFoundException('Template not found'); } @@ -171,143 +464,7 @@ final class ActivityController extends AbstractController ]); } - public function newAction(Request $request): Response - { - $view = null; - - [$person, $accompanyingPeriod] = $this->getEntity($request); - - if ($accompanyingPeriod instanceof AccompanyingPeriod) { - $view = 'ChillActivityBundle:Activity:newAccompanyingCourse.html.twig'; - } elseif ($person instanceof Person) { - $view = 'ChillActivityBundle:Activity:newPerson.html.twig'; - } - - $activityType_id = $request->get('activityType_id', 0); - $activityType = $this->activityTypeRepository->find($activityType_id); - - if (isset($activityType) && !$activityType->isActive()) { - throw new \InvalidArgumentException('Activity type must be active'); - } - - $activityData = null; - if ($request->query->has('activityData')) { - $activityData = $request->query->get('activityData'); - } - - if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType || - !$activityType->isActive()) { - - $params = $this->buildParamsToUrl($person, $accompanyingPeriod); - - if (null !== $activityData) { - $params['activityData'] = $activityData; - } - return $this->redirectToRoute('chill_activity_activity_select_type', $params); - } - - $entity = new Activity(); - $entity->setUser($this->getUser()); - - if ($person instanceof Person) { - $entity->setPerson($person); - } - - if ($accompanyingPeriod instanceof AccompanyingPeriod) { - $entity->setAccompanyingPeriod($accompanyingPeriod); - } - - $entity->setType($activityType); - $entity->setDate(new \DateTime('now')); - - if ($request->query->has('activityData')) { - $activityData = $request->query->get('activityData'); - - if (array_key_exists('durationTime', $activityData)) { - $durationTimeInMinutes = $activityData['durationTime']; - $hours = floor($durationTimeInMinutes / 60); - $minutes = $durationTimeInMinutes % 60; - $duration = \DateTime::createFromFormat("H:i", $hours.':'.$minutes); - if ($duration) { - $entity->setDurationTime($duration); - } - } - - if (array_key_exists('date', $activityData)) { - $date = \DateTime::createFromFormat('Y-m-d', $activityData['date']); - if ($date) { - $entity->setDate($date); - } - } - - if (array_key_exists('personsId', $activityData)) { - foreach($activityData['personsId'] as $personId){ - $concernedPerson = $this->personRepository->find($personId); - $entity->addPerson($concernedPerson); - } - } - - if (array_key_exists('professionalsId', $activityData)) { - foreach($activityData['professionalsId'] as $professionalsId){ - $professional = $this->thirdPartyRepository->find($professionalsId); - $entity->addThirdParty($professional); - } - } - - if (array_key_exists('location', $activityData)) { - $location = $this->locationRepository->find($activityData['location']); - $entity->setLocation($location); - } - - if (array_key_exists('comment', $activityData)) { - $comment = new CommentEmbeddable(); - $comment->setComment($activityData['comment']); - $comment->setUserId($this->getUser()->getid()); - $comment->setDate(new \DateTime('now')); - $entity->setComment($comment); - } - - } - - // TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période - // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity); - - $form = $this->createForm(ActivityType::class, $entity, [ - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_ACTIVITY_CREATE'), - 'activityType' => $entity->getType(), - 'accompanyingPeriod' => $accompanyingPeriod, - ])->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->entityManager->persist($entity); - $this->entityManager->flush(); - - $this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); - - $params = $this->buildParamsToUrl($person, $accompanyingPeriod); - - $params['id'] = $entity->getId(); - - return $this->redirectToRoute('chill_activity_activity_show', $params); - } - - if ($view === null) { - throw $this->createNotFoundException('Template not found'); - } - - $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); - - return $this->render($view, [ - 'person' => $person, - 'accompanyingCourse' => $accompanyingPeriod, - 'entity' => $entity, - 'form' => $form->createView(), - 'activity_json' => $activity_array - ]); - } - - public function showAction(Request $request, $id): Response + public function showAction(Request $request, int $id): Response { $view = null; @@ -327,8 +484,8 @@ final class ActivityController extends AbstractController if (null !== $accompanyingPeriod) { // @TODO: Properties created dynamically. - $entity->personsAssociated = $entity->getPersonsAssociated(); - $entity->personsNotAssociated = $entity->getPersonsNotAssociated(); + $entity->personsAssociated = $entity->getPersonsAssociated(); + $entity->personsNotAssociated = $entity->getPersonsNotAssociated(); } // TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période @@ -344,160 +501,33 @@ final class ActivityController extends AbstractController 'action' => 'show' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - */ + */ - if ($view === null) { + if (null === $view) { throw $this->createNotFoundException('Template not found'); } return $this->render($view, [ - 'person' => $person, - 'accompanyingCourse' => $accompanyingPeriod, - 'entity' => $entity, - 'delete_form' => $deleteForm->createView(), - ]); - } - - /** - * Displays a form to edit an existing Activity entity. - */ - public function editAction($id, Request $request): Response - { - $view = null; - - [$person, $accompanyingPeriod] = $this->getEntity($request); - - if ($accompanyingPeriod instanceof AccompanyingPeriod) { - $view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig'; - } elseif ($person instanceof Person) { - $view = 'ChillActivityBundle:Activity:editPerson.html.twig'; - } - - $entity = $this->activityRepository->find($id); - - if (null === $entity) { - throw $this->createNotFoundException('Unable to find Activity entity.'); - } - - // TODO - // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity); - - $form = $this->createForm(ActivityType::class, $entity, [ - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_ACTIVITY_UPDATE'), - 'activityType' => $entity->getType(), - 'accompanyingPeriod' => $accompanyingPeriod, - ])->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->entityManager->persist($entity); - $this->entityManager->flush(); - - $this->addFlash('success', $this->get('translator')->trans('Success : activity updated!')); - - $params = $this->buildParamsToUrl($person, $accompanyingPeriod); - $params['id'] = $entity->getId(); - - return $this->redirectToRoute('chill_activity_activity_show', $params); - } - - $deleteForm = $this->createDeleteForm($entity->getId(), $person, $accompanyingPeriod); - - /* - * TODO - $event = new PrivacyEvent($person, array( - 'element_class' => Activity::class, - 'element_id' => $entity->getId(), - 'action' => 'edit' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - */ - - if ($view === null) { - throw $this->createNotFoundException('Template not found'); - } - - $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); - - return $this->render($view, [ - 'entity' => $entity, - 'edit_form' => $form->createView(), - 'delete_form' => $deleteForm->createView(), 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, - 'activity_json' => $activity_array + 'entity' => $entity, + 'delete_form' => $deleteForm->createView(), ]); } - /** - * Deletes a Activity entity. - */ - public function deleteAction(Request $request, $id) + private function buildParamsToUrl(?Person $person, ?AccompanyingPeriod $accompanyingPeriod): array { - $view = null; + $params = []; - [$person, $accompanyingPeriod] = $this->getEntity($request); - - if ($accompanyingPeriod instanceof AccompanyingPeriod) { - $view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig'; - } elseif ($person instanceof Person) { - $view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig'; + if (null !== $person) { + $params['person_id'] = $person->getId(); } - $activity = $this->activityRepository->find($id); - - if (!$activity) { - throw $this->createNotFoundException('Unable to find Activity entity.'); + if (null !== $accompanyingPeriod) { + $params['accompanying_period_id'] = $accompanyingPeriod->getId(); } - // TODO - // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); - - $form = $this->createDeleteForm($activity->getId(), $person, $accompanyingPeriod); - - if ($request->getMethod() === Request::METHOD_DELETE) { - $form->handleRequest($request); - - if ($form->isValid()) { - $this->logger->notice("An activity has been removed", [ - 'by_user' => $this->getUser()->getUsername(), - 'activity_id' => $activity->getId(), - 'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null, - 'comment' => $activity->getComment()->getComment(), - 'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null, - 'reasons_ids' => $activity->getReasons() - ->map( - static fn (ActivityReason $ar): int => $ar->getId() - ) - ->toArray(), - 'type_id' => $activity->getType()->getId(), - 'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null, - 'date' => $activity->getDate()->format('Y-m-d'), - 'attendee' => $activity->getAttendee() - ]); - - $this->entityManager->remove($activity); - $this->entityManager->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans("The activity has been successfully removed.")); - - $params = $this->buildParamsToUrl($person, $accompanyingPeriod); - - return $this->redirectToRoute('chill_activity_activity_list', $params); - } - } - - if ($view === null) { - throw $this->createNotFoundException('Template not found'); - } - - return $this->render($view, [ - 'activity' => $activity, - 'delete_form' => $form->createView(), - 'person' => $person, - 'accompanyingCourse' => $accompanyingPeriod, - ]); + return $params; } /** @@ -517,13 +547,13 @@ final class ActivityController extends AbstractController private function getEntity(Request $request): array { - $person = $accompanyingPeriod = null; + $person = $accompanyingPeriod = null; if ($request->query->has('person_id')) { $person_id = $request->get('person_id'); $person = $this->personRepository->find($person_id); - if ($person === null) { + if (null === $person) { throw $this->createNotFoundException('Person not found'); } @@ -532,34 +562,19 @@ final class ActivityController extends AbstractController $accompanying_period_id = $request->get('accompanying_period_id'); $accompanyingPeriod = $this->accompanyingPeriodRepository->find($accompanying_period_id); - if ($accompanyingPeriod === null) { + if (null === $accompanyingPeriod) { throw $this->createNotFoundException('Accompanying Period not found'); } // TODO Add permission // $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); } else { - throw $this->createNotFoundException("Person or Accompanying Period not found"); + throw $this->createNotFoundException('Person or Accompanying Period not found'); } return [ $person, - $accompanyingPeriod + $accompanyingPeriod, ]; } - - private function buildParamsToUrl(?Person $person, ?AccompanyingPeriod $accompanyingPeriod): array - { - $params = []; - - if (null !== $person) { - $params['person_id'] = $person->getId(); - } - - if (null !== $accompanyingPeriod) { - $params['accompanying_period_id'] = $accompanyingPeriod->getId(); - } - - return $params; - } } diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php index 793c9c695..a748641a8 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php @@ -1,38 +1,28 @@ 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 +35,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 +61,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 +136,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..6c48229de 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityReasonController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityReasonController.php @@ -1,38 +1,28 @@ 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 +35,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 +61,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 +136,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/AdminActivityPresenceController.php b/src/Bundle/ChillActivityBundle/Controller/AdminActivityPresenceController.php index a100c3f5d..4bcdcbed5 100644 --- a/src/Bundle/ChillActivityBundle/Controller/AdminActivityPresenceController.php +++ b/src/Bundle/ChillActivityBundle/Controller/AdminActivityPresenceController.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 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 015900043..0da266251 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php @@ -1,48 +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 . + * 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 Chill\PersonBundle\Entity\Person; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\ORM\EntityManagerInterface; 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; class LoadActivity extends AbstractFixture implements OrderedFixtureInterface { use \Symfony\Component\DependencyInjection\ContainerAwareTrait; + private EntityManagerInterface $em; + /** * @var \Faker\Generator */ private $faker; - private EntityManagerInterface $em; public function __construct(EntityManagerInterface $em) { @@ -55,30 +41,53 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface 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->em + ->getRepository(Person::class) + ->findAll(); + + foreach ($persons as $person) { + $activityNbr = rand(0, 3); + + for ($i = 0; $i < $activityNbr; ++$i) { + $activity = $this->newRandomActivity($person); + + if (null !== $activity) { + $manager->persist($activity); + } + } + } + $manager->flush(); + } + + public function newRandomActivity($person): ?Activity + { + $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()) + + for ($i = 0; rand(0, 4) > $i; ++$i) { + $reason = $this->getRandomActivityReason(); + + if (null !== $reason) { + $activity->addReason($reason); + } else { + return null; + } + } + + 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 */ @@ -90,57 +99,38 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface } /** - * 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 - { - $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()) - - for ($i = 0; $i < rand(0, 4); $i++) { - $reason = $this->getRandomActivityReason(); - if (null !== $reason) { - $activity->addReason($reason); - } else { - return null; - } - } - - return $activity; - } - - public function load(ObjectManager $manager) - { - $persons = $this->em - ->getRepository(Person::class) - ->findAll(); - - foreach ($persons as $person) { - $activityNbr = rand(0,3); - - for ($i = 0; $i < $activityNbr; $i ++) { - $activity = $this->newRandomActivity($person); - if (null !== $activity) { - $manager->persist($activity); - } - } - } - $manager->flush(); - } } diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityNotifications.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityNotifications.php index 9ef67a7ac..38ea21c1f 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityNotifications.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityNotifications.php @@ -1,15 +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\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 de3c1d4de..6c641aceb 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php @@ -1,86 +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\DataFixtures\ORM; +use Chill\ActivityBundle\Entity\ActivityType; use Doctrine\Bundle\FixturesBundle\Fixture; 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 Fixture implements OrderedFixtureInterface { + public static $references = []; + public function getOrder() { return 16100; } - public static $references = array(); - public function load(ObjectManager $manager) { $types = [ - # Exange + // Exange [ - 'name' => - ['fr' => 'Entretien physique avec l\'usager'], - 'category' => 'exchange' ], + 'name' => ['fr' => 'Entretien physique avec l\'usager'], + 'category' => 'exchange', ], [ - 'name' => - ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel'], - 'category' => 'exchange' ], + 'name' => ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel'], + 'category' => 'exchange', ], [ - 'name' => - ['fr' => 'Courriel', 'en' => 'Email', 'nl' => 'Email'], - 'category' => 'exchange' ], - # Meeting + 'name' => ['fr' => 'Courriel', 'en' => 'Email', 'nl' => 'Email'], + 'category' => 'exchange', ], + // Meeting [ - 'name' => - ['fr' => 'Point technique encadrant'], - 'category' => 'meeting' ], + 'name' => ['fr' => 'Point technique encadrant'], + 'category' => 'meeting', ], [ - 'name' => - ['fr' => 'Réunion avec des partenaires'], - 'category' => 'meeting' ], + 'name' => ['fr' => 'Réunion avec des partenaires'], + 'category' => 'meeting', ], [ - 'name' => - ['fr' => 'Commission pluridisciplinaire et pluri-institutionnelle'], - 'category' => 'meeting' ], + 'name' => ['fr' => 'Commission pluridisciplinaire et pluri-institutionnelle'], + 'category' => 'meeting', ], ]; foreach ($types as $t) { - print "Creating activity type : " . $t['name']['fr'] . " (cat:". $t['category'] . " \n"; + echo 'Creating activity type : ' . $t['name']['fr'] . ' (cat:' . $t['category'] . " \n"; $activityType = (new ActivityType()) ->setName(($t['name'])) - ->setCategory($this->getReference('activity_type_cat_'.$t['category'])) + ->setCategory($this->getReference('activity_type_cat_' . $t['category'])) ->setSocialIssuesVisible(1) ->setSocialActionsVisible(1); $manager->persist($activityType); - $reference = 'activity_type_'.$t['name']['fr']; + $reference = 'activity_type_' . $t['name']['fr']; $this->addReference($reference, $activityType); static::$references[] = $reference; } diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityTypeCategory.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityTypeCategory.php index 40e45fcf4..e98a9bb7d 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityTypeCategory.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityTypeCategory.php @@ -1,40 +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\ActivityTypeCategory; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\ActivityBundle\Entity\ActivityTypeCategory; /** - * Fixtures for ActivityTypeCategory - * - * @author Champs-Libres Coop + * Fixtures for ActivityTypeCategory. */ class LoadActivityTypeCategory extends Fixture implements OrderedFixtureInterface { - public static $references = array(); + public static $references = []; public function getOrder() { @@ -55,13 +40,13 @@ class LoadActivityTypeCategory extends Fixture implements OrderedFixtureInterfac ]; foreach ($categories as $cat) { - print "Creating activity type category : " . $cat['ref'] . "\n"; + echo 'Creating activity type category : ' . $cat['ref'] . "\n"; $newCat = (new ActivityTypeCategory()) ->setName(($cat['name'])); $manager->persist($newCat); - $reference = 'activity_type_cat_'.$cat['ref']; + $reference = 'activity_type_cat_' . $cat['ref']; $this->addReference($reference, $newCat); static::$references[] = $reference; diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php index 331db2305..4893a87b3 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php @@ -1,37 +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\ActivityBundle\DataFixtures\ORM; +use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; +use Chill\ActivityBundle\Security\Authorization\ActivityVoter; +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 +29,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 +42,52 @@ 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(ActivityVoter::CREATE_ACCOMPANYING_COURSE) + ->setScope($scope); + $roleScopeCreate = (new RoleScope()) + ->setRole(ActivityVoter::CREATE_PERSON) + ->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 f4aeba174..548d34a09 100644 --- a/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php +++ b/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php @@ -1,45 +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\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(); @@ -47,7 +30,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf $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'); @@ -65,33 +48,38 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf $this->prependCruds($container); } + public function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + ActivityVoter::UPDATE => [ActivityVoter::SEE_DETAILS], + ActivityVoter::CREATE_PERSON => [ActivityVoter::SEE_DETAILS], + ActivityVoter::CREATE_ACCOMPANYING_COURSE => [ActivityVoter::SEE_DETAILS], + ActivityVoter::DELETE => [ActivityVoter::SEE_DETAILS], + ActivityVoter::SEE_DETAILS => [ActivityVoter::SEE], + ActivityVoter::FULL => [ + ActivityVoter::CREATE_PERSON, + ActivityVoter::CREATE_ACCOMPANYING_COURSE, + ActivityVoter::DELETE, + ActivityVoter::UPDATE, + ], + ], + ]); + } + /* (non-PHPdoc) * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() */ 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), - ActivityVoter::FULL => [ActivityVoter::CREATE, ActivityVoter::DELETE, - ActivityVoter::UPDATE], - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillActivityBundle/config/routes.yaml', + ], + ], + ]); } protected function prependCruds(ContainerBuilder $container) @@ -107,17 +95,17 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf 'actions' => [ 'index' => [ 'template' => '@ChillActivity/ActivityType/index.html.twig', - 'role' => 'ROLE_ADMIN' + 'role' => 'ROLE_ADMIN', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillActivity/ActivityType/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillActivity/ActivityType/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\ActivityBundle\Entity\ActivityTypeCategory::class, @@ -128,17 +116,17 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf 'actions' => [ 'index' => [ 'template' => '@ChillActivity/ActivityTypeCategory/index.html.twig', - 'role' => 'ROLE_ADMIN' + 'role' => 'ROLE_ADMIN', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillActivity/ActivityTypeCategory/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillActivity/ActivityTypeCategory/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\ActivityBundle\Entity\ActivityPresence::class, @@ -149,19 +137,19 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf 'actions' => [ 'index' => [ 'template' => '@ChillActivity/ActivityPresence/index.html.twig', - 'role' => 'ROLE_ADMIN' + 'role' => 'ROLE_ADMIN', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillActivity/ActivityPresence/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillActivity/ActivityPresence/edit.html.twig', - ] - ] + ], + ], ], - ] + ], ]); } } 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 4ed654c85..85abed5e5 100644 --- a/src/Bundle/ChillActivityBundle/Entity/Activity.php +++ b/src/Bundle/ChillActivityBundle/Entity/Activity.php @@ -1,38 +1,46 @@ reasons = new ArrayCollection(); @@ -178,71 +189,25 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer $this->socialActions = new ArrayCollection(); } - public function getId(): ?int + public function addDocument(Document $document): self { - return $this->id; - } - - public function setUser(UserInterface $user): self - { - $this->user = $user; + $this->documents[] = $document; return $this; } - public function getUser(): User + /** + * Add a person to the person list. + */ + public function addPerson(?Person $person): self { - return $this->user; - } - - public function setDate(\DateTime $date): self - { - $this->date = $date; + if (null !== $person) { + $this->persons[] = $person; + } return $this; } - public function getDate(): \DateTime - { - return $this->date; - } - - public function setDurationTime(?\DateTime $durationTime): self - { - $this->durationTime = $durationTime; - - return $this; - } - - public function getDurationTime(): ?\DateTime - { - return $this->durationTime; - } - - public function setTravelTime(\DateTime $travelTime): self - { - $this->travelTime = $travelTime; - - return $this; - } - - public function getTravelTime(): ?\DateTime - { - return $this->travelTime; - } - - public function setAttendee(ActivityPresence $attendee): self - { - $this->attendee = $attendee; - - return $this; - } - - public function getAttendee(): ?ActivityPresence - { - return $this->attendee; - } - public function addReason(ActivityReason $reason): self { $this->reasons->add($reason); @@ -250,49 +215,6 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer return $this; } - public function removeReason(ActivityReason $reason): void - { - $this->reasons->removeElement($reason); - } - - public function getReasons(): Collection - { - return $this->reasons; - } - - public function setReasons(?ArrayCollection $reasons): self - { - $this->reasons = $reasons; - - return $this; - } - - public function getSocialIssues(): Collection - { - return $this->socialIssues; - } - - public function addSocialIssue(SocialIssue $socialIssue): self - { - if (!$this->socialIssues->contains($socialIssue)) { - $this->socialIssues[] = $socialIssue; - } - - return $this; - } - - public function removeSocialIssue(SocialIssue $socialIssue): self - { - $this->socialIssues->removeElement($socialIssue); - - return $this; - } - - public function getSocialActions(): Collection - { - return $this->socialActions; - } - public function addSocialAction(SocialAction $socialAction): self { if (!$this->socialActions->contains($socialAction)) { @@ -302,67 +224,51 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer return $this; } - public function removeSocialAction(SocialAction $socialAction): self + public function addSocialIssue(SocialIssue $socialIssue): self { - $this->socialActions->removeElement($socialAction); + if (!$this->socialIssues->contains($socialIssue)) { + $this->socialIssues[] = $socialIssue; + } return $this; } - - - - public function setType(ActivityType $type): self + public function addThirdParty(?ThirdParty $thirdParty): self { - $this->type = $type; + if (null !== $thirdParty) { + $this->thirdParties[] = $thirdParty; + } return $this; } - public function getType(): ActivityType + public function addUser(?User $user): self { - return $this->type; - } - - public function setScope(Scope $scope): self - { - $this->scope = $scope; + if (null !== $user) { + $this->users[] = $user; + } return $this; } - public function getScope(): ?Scope - { - return $this->scope; - } - - public function setPerson(?Person $person): self - { - $this->person = $person; - - return $this; - } - - public function getPerson(): ?Person - { - return $this->person; - } - public function getAccompanyingPeriod(): ?AccompanyingPeriod { return $this->accompanyingPeriod; } - public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + public function getActivityType(): ActivityType { - $this->accompanyingPeriod = $accompanyingPeriod; + return $this->activityType; + } - return $this; + public function getAttendee(): ?ActivityPresence + { + return $this->attendee; } /** * get the center - * center is extracted from person + * center is extracted from person. */ public function getCenter(): ?Center { @@ -378,28 +284,39 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer return $this->comment; } - public function setComment(CommentEmbeddable $comment): self + public function getDate(): DateTime { - $this->comment = $comment; - - return $this; + return $this->date; } - /** - * Add a person to the person list - */ - public function addPerson(?Person $person): self + public function getDocuments(): Collection { - if (null !== $person) { - $this->persons[] = $person; - } - - return $this; + return $this->documents; } - public function removePerson(Person $person): void + public function getDurationTime(): ?DateTime { - $this->persons->removeElement($person); + return $this->durationTime; + } + + public function getEmergency(): bool + { + return $this->emergency; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getLocation(): ?Location + { + return $this->location; + } + + public function getPerson(): ?Person + { + return $this->person; } public function getPersons(): Collection @@ -411,13 +328,16 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer { if (null !== $this->accompanyingPeriod) { $personsAssociated = []; + foreach ($this->accompanyingPeriod->getParticipations() as $participation) { if ($this->persons->contains($participation->getPerson())) { $personsAssociated[] = $participation->getPerson(); } } + return $personsAssociated; } + return []; } @@ -425,28 +345,103 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer { if (null !== $this->accompanyingPeriod) { $personsNotAssociated = []; + foreach ($this->persons as $person) { if (!in_array($person, $this->getPersonsAssociated())) { - $personsNotAssociated[] = $person; + $personsNotAssociated[] = $person; } } + return $personsNotAssociated; } + return []; } - public function setPersons(?Collection $persons): self + public function getReasons(): Collection { - $this->persons = $persons; + return $this->reasons; + } + + public function getScope(): ?Scope + { + return $this->scope; + } + + public function getSentReceived(): string + { + return $this->sentReceived; + } + + public function getSocialActions(): Collection + { + return $this->socialActions; + } + + public function getSocialIssues(): Collection + { + return $this->socialIssues; + } + + public function getThirdParties(): Collection + { + return $this->thirdParties; + } + + public function getTravelTime(): ?DateTime + { + return $this->travelTime; + } + + /** + * @deprecated + */ + public function getType(): ActivityType + { + return $this->activityType; + } + + public function getUser(): User + { + return $this->user; + } + + public function getUsers(): Collection + { + return $this->users; + } + + public function isEmergency(): bool + { + return $this->getEmergency(); + } + + public function removeDocument(Document $document): void + { + $this->documents->removeElement($document); + } + + public function removePerson(Person $person): void + { + $this->persons->removeElement($person); + } + + public function removeReason(ActivityReason $reason): void + { + $this->reasons->removeElement($reason); + } + + public function removeSocialAction(SocialAction $socialAction): self + { + $this->socialActions->removeElement($socialAction); return $this; } - public function addThirdParty(?ThirdParty $thirdParty): self + public function removeSocialIssue(SocialIssue $socialIssue): self { - if (null !== $thirdParty) { - $this->thirdParties[] = $thirdParty; - } + $this->socialIssues->removeElement($socialIssue); + return $this; } @@ -455,33 +450,44 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer $this->thirdParties->removeElement($thirdParty); } - public function getThirdParties(): Collection + public function removeUser(User $user): void { - return $this->thirdParties; + $this->users->removeElement($user); } - public function setThirdParties(?Collection $thirdParties): self + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self { - $this->thirdParties = $thirdParties; + $this->accompanyingPeriod = $accompanyingPeriod; return $this; } - public function addDocument(Document $document): self + public function setActivityType(ActivityType $activityType): self { - $this->documents[] = $document; + $this->activityType = $activityType; return $this; } - public function removeDocument(Document $document): void + public function setAttendee(ActivityPresence $attendee): self { - $this->documents->removeElement($document); + $this->attendee = $attendee; + + return $this; } - public function getDocuments(): Collection + public function setComment(CommentEmbeddable $comment): self { - return $this->documents; + $this->comment = $comment; + + return $this; + } + + public function setDate(DateTime $date): self + { + $this->date = $date; + + return $this; } public function setDocuments(Collection $documents): self @@ -491,41 +497,13 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer return $this; } - public function addUser(?User $user): self + public function setDurationTime(?DateTime $durationTime): self { - if (null !== $user) { - $this->users[] = $user; - } - return $this; - } - - public function removeUser(User $user): void - { - $this->users->removeElement($user); - } - - public function getUsers(): Collection - { - return $this->users; - } - - public function setUsers(?Collection $users): self - { - $this->users = $users; + $this->durationTime = $durationTime; return $this; } - public function isEmergency(): bool - { - return $this->getEmergency(); - } - - public function getEmergency(): bool - { - return $this->emergency; - } - public function setEmergency(bool $emergency): self { $this->emergency = $emergency; @@ -533,9 +511,39 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer return $this; } - public function getSentReceived(): string + public function setLocation(?Location $location): Activity { - return $this->sentReceived; + $this->location = $location; + + return $this; + } + + public function setPerson(?Person $person): self + { + $this->person = $person; + + return $this; + } + + public function setPersons(?Collection $persons): self + { + $this->persons = $persons; + + return $this; + } + + public function setReasons(?ArrayCollection $reasons): self + { + $this->reasons = $reasons; + + return $this; + } + + public function setScope(Scope $scope): self + { + $this->scope = $scope; + + return $this; } public function setSentReceived(?string $sentReceived): self @@ -545,21 +553,41 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer return $this; } - /** - * @return Location|null - */ - public function getLocation(): ?Location + public function setThirdParties(?Collection $thirdParties): self { - return $this->location; + $this->thirdParties = $thirdParties; + + return $this; + } + + public function setTravelTime(DateTime $travelTime): self + { + $this->travelTime = $travelTime; + + return $this; } /** - * @param Location|null $location - * @return Activity + * @deprecated */ - public function setLocation(?Location $location): Activity + public function setType(ActivityType $activityType): self { - $this->location = $location; + $this->activityType = $activityType; + + return $this; + } + + public function setUser(UserInterface $user): self + { + $this->user = $user; + + return $this; + } + + public function setUsers(?Collection $users): self + { + $this->users = $users; + return $this; } } diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityPresence.php b/src/Bundle/ChillActivityBundle/Entity/ActivityPresence.php index ed9757549..087469692 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityPresence.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityPresence.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\ActivityBundle\Entity; @@ -23,15 +12,19 @@ namespace Chill\ActivityBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Class ActivityPresence + * Class ActivityPresence. * - * @package Chill\ActivityBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="activitytpresence") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class ActivityPresence { + /** + * @ORM\Column(type="boolean") + */ + private bool $active = true; + /** * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -44,28 +37,6 @@ class ActivityPresence */ private array $name = []; - /** - * @ORM\Column(type="boolean") - */ - private bool $active = true; - - public function getId(): int - { - return $this->id; - } - - public function setName(array $name): self - { - $this->name = $name; - - return $this; - } - - public function getName(): array - { - return $this->name; - } - /** * Get active * return true if the category type is active. @@ -75,9 +46,19 @@ class ActivityPresence return $this->active; } + public function getId(): int + { + return $this->id; + } + + public function getName(): array + { + return $this->name; + } + /** * Is active - * return true if the category type is active + * return true if the category type is active. */ public function isActive(): bool { @@ -86,7 +67,7 @@ class ActivityPresence /** * Set active - * set to true if the category type is active + * set to true if the category type is active. */ public function setActive(bool $active): self { @@ -94,4 +75,11 @@ class ActivityPresence return $this; } + + public function setName(array $name): self + { + $this->name = $name; + + return $this; + } } diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php b/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php index b22dd5281..69adaf843 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 . + * 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 b7afbcb1c..722cdaa08 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php @@ -1,39 +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\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,17 +43,12 @@ 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; @@ -75,13 +65,23 @@ class ActivityReasonCategory */ 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,30 +100,32 @@ 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); } @@ -146,13 +137,16 @@ class ActivityReasonCategory } /** - * 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 c8ae6ca07..0e9b1150a 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php @@ -1,40 +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\ActivityBundle\Entity; use Doctrine\ORM\Mapping as ORM; +use InvalidArgumentException; +use Symfony\Component\Serializer\Annotation\Groups; /** - * Class ActivityType + * Class ActivityType. * - * @package Chill\ActivityBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="activitytype") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class ActivityType { - const FIELD_INVISIBLE = 0; - const FIELD_OPTIONAL = 1; - const FIELD_REQUIRED = 2; + public const FIELD_INVISIBLE = 0; + + public const FIELD_OPTIONAL = 1; + + public const FIELD_REQUIRED = 2; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $accompanyingPeriodLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="boolean") + * @Groups({"read"}) + */ + private bool $active = true; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $attendeeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $attendeeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityTypeCategory") + */ + private ?ActivityTypeCategory $category = null; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $commentLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $commentVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $dateLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 2}) + */ + private int $dateVisible = self::FIELD_REQUIRED; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $documentsLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $documentsVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $durationTimeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $durationTimeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $emergencyLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $emergencyVisible = self::FIELD_INVISIBLE; /** * @ORM\Id @@ -44,249 +117,157 @@ class ActivityType private ?int $id; /** - * @ORM\Column(type="json") - */ - private array $name = []; - - /** - * @ORM\Column(type="boolean") - */ - private bool $active = true; - - /** - * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityTypeCategory") - */ - private ?ActivityTypeCategory $category = null; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=2}) - */ - private int $personVisible = self::FIELD_REQUIRED; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $personLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=2}) - */ - private int $userVisible = self::FIELD_REQUIRED; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $userLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=2}) - */ - private int $dateVisible = self::FIELD_REQUIRED; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $dateLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $placeVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $placeLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $personsVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $personsLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $thirdPartiesVisible = self::FIELD_INVISIBLE; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $thirdPartiesLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $durationTimeVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $durationTimeLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $travelTimeVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $travelTimeLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $attendeeVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $attendeeLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $reasonsVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $reasonsLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $commentVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $commentLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $sentReceivedVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $sentReceivedLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $documentsVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $documentsLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $usersVisible = self::FIELD_OPTIONAL; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $usersLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $emergencyVisible = self::FIELD_INVISIBLE; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $emergencyLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $accompanyingPeriodLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $socialDataVisible = self::FIELD_INVISIBLE; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $socialDataLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $socialIssuesVisible = self::FIELD_INVISIBLE; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $socialIssuesLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $socialActionsVisible = self::FIELD_INVISIBLE; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) - */ - private string $socialActionsLabel = ''; - - /** - * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) - */ - private int $locationVisible = self::FIELD_INVISIBLE; - - /** - * @ORM\Column(type="string", nullable=false, options={"default"=""}) + * @ORM\Column(type="string", nullable=false, options={"default": ""}) */ private string $locationLabel = ''; /** - * @ORM\Column(type="float", options={"default"="0.0"}) + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $locationVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="json") + * @Groups({"read"}) + */ + private array $name = []; + + /** + * @ORM\Column(type="float", options={"default": "0.0"}) */ private float $ordering = 0.0; /** - * Get id + * @ORM\Column(type="string", nullable=false, options={"default": ""}) */ - public function getId(): int - { - return $this->id; - } + private string $personLabel = ''; /** - * Set name + * @ORM\Column(type="string", nullable=false, options={"default": ""}) */ - public function setName(array $name): self - { - $this->name = $name; - - return $this; - } + private string $personsLabel = ''; /** - * Get name + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + * @Groups({"read"}) */ - public function getName(): array + private int $personsVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 2}) + */ + private int $personVisible = self::FIELD_REQUIRED; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $placeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $placeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $reasonsLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $reasonsVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $sentReceivedLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $sentReceivedVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $socialActionsLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $socialActionsVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $socialDataLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $socialDataVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $socialIssuesLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $socialIssuesVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $thirdPartiesLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + * @Groups({"read"}) + */ + private int $thirdPartiesVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $travelTimeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $travelTimeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $userLabel = ''; + + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $usersLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + * @Groups({"read"}) + */ + private int $usersVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 2}) + */ + private int $userVisible = self::FIELD_REQUIRED; + + public function getAccompanyingPeriodLabel(): string { - return $this->name; + return $this->accompanyingPeriodLabel; + } + + public function getAccompanyingPeriodVisible(): int + { + return $this->accompanyingPeriodVisible; } /** @@ -298,228 +279,9 @@ class ActivityType return $this->active; } - /** - * Is active - * return true if the type is active - */ - public function isActive(): bool + public function getAttendeeLabel(): string { - return $this->getActive(); - } - - /** - * Set active - * set to true if the type is active - */ - public function setActive(bool $active): self - { - $this->active = $active; - - return $this; - } - - public function getCategory(): ?ActivityTypeCategory - { - return $this->category; - } - - public function setCategory(?ActivityTypeCategory $category): self - { - $this->category = $category; - - return $this; - } - - public function getPersonVisible(): int - { - return $this->personVisible; - } - - public function setPersonVisible(int $personVisible): self - { - $this->personVisible = $personVisible; - - return $this; - } - - public function getPersonLabel(): string - { - return $this->personLabel; - } - - public function setPersonLabel(string $personLabel): self - { - $this->personLabel = $personLabel; - - return $this; - } - - public function getUserVisible(): int - { - return $this->userVisible; - } - - public function setUserVisible(int $userVisible): self - { - $this->userVisible = $userVisible; - - return $this; - } - - public function getUserLabel(): string - { - return $this->userLabel; - } - - public function setUserLabel(string $userLabel): self - { - $this->userLabel = $userLabel; - - return $this; - } - - public function getDateVisible(): int - { - return $this->dateVisible; - } - - public function setDateVisible(int $dateVisible): self - { - $this->dateVisible = $dateVisible; - - return $this; - } - - public function getDateLabel(): string - { - return $this->dateLabel; - } - - public function setDateLabel(string $dateLabel): self - { - $this->dateLabel = $dateLabel; - - return $this; - } - - public function getPlaceVisible(): int - { - return $this->placeVisible; - } - - public function setPlaceVisible(int $placeVisible): self - { - $this->placeVisible = $placeVisible; - - return $this; - } - - public function getPlaceLabel(): string - { - return $this->placeLabel; - } - - public function setPlaceLabel(string $placeLabel): self - { - $this->placeLabel = $placeLabel; - - return $this; - } - - public function getPersonsVisible(): int - { - return $this->personsVisible; - } - - public function setPersonsVisible(int $personsVisible): self - { - $this->personsVisible = $personsVisible; - - return $this; - } - - public function getPersonsLabel(): string - { - return $this->personsLabel; - } - - public function setPersonsLabel(string $personsLabel): self - { - $this->personsLabel = $personsLabel; - - return $this; - } - - public function getThirdPartiesVisible(): int - { - return $this->thirdPartiesVisible; - } - - public function setThirdPartiesVisible(int $thirdPartiesVisible): self - { - $this->thirdPartiesVisible = $thirdPartiesVisible; - - return $this; - } - - public function getThirdPartiesLabel(): string - { - return $this->thirdPartiesLabel; - } - - public function setThirdPartiesLabel(string $thirdPartiesLabel): self - { - $this->thirdPartiesLabel = $thirdPartiesLabel; - - return $this; - } - - public function getDurationTimeVisible(): int - { - return $this->durationTimeVisible; - } - - public function setDurationTimeVisible(int $durationTimeVisible): self - { - $this->durationTimeVisible = $durationTimeVisible; - - return $this; - } - - public function getDurationTimeLabel(): string - { - return $this->durationTimeLabel; - } - - public function setDurationTimeLabel(string $durationTimeLabel): self - { - $this->durationTimeLabel = $durationTimeLabel; - - return $this; - } - - public function getTravelTimeVisible(): int - { - return $this->travelTimeVisible; - } - - public function setTravelTimeVisible(int $TravelTimeVisible): self - { - $this->travelTimeVisible = $TravelTimeVisible; - - return $this; - } - - public function getTravelTimeLabel(): string - { - return $this->travelTimeLabel; - } - - public function setTravelTimeLabel(string $TravelTimeLabel): self - { - $this->travelTimeLabel = $TravelTimeLabel; - - return $this; + return $this->attendeeLabel; } public function getAttendeeVisible(): int @@ -527,59 +289,9 @@ class ActivityType return $this->attendeeVisible; } - public function setAttendeeVisible(int $attendeeVisible): self + public function getCategory(): ?ActivityTypeCategory { - $this->attendeeVisible = $attendeeVisible; - - return $this; - } - - public function getAttendeeLabel(): string - { - return $this->attendeeLabel; - } - - public function setAttendeeLabel(string $attendeeLabel): self - { - $this->attendeeLabel = $attendeeLabel; - - return $this; - } - - public function getReasonsVisible(): int - { - return $this->reasonsVisible; - } - - public function setReasonsVisible(int $reasonsVisible): self - { - $this->reasonsVisible = $reasonsVisible; - - return $this; - } - - public function getReasonsLabel(): string - { - return $this->reasonsLabel; - } - - public function setReasonsLabel(string $reasonsLabel): self - { - $this->reasonsLabel = $reasonsLabel; - - return $this; - } - - public function getCommentVisible(): int - { - return $this->commentVisible; - } - - public function setCommentVisible(int $commentVisible): self - { - $this->commentVisible = $commentVisible; - - return $this; + return $this->category; } public function getCommentLabel(): string @@ -587,47 +299,19 @@ class ActivityType return $this->commentLabel; } - public function setCommentLabel(string $commentLabel): self + public function getCommentVisible(): int { - $this->commentLabel = $commentLabel; - - return $this; + return $this->commentVisible; } - public function getSentReceivedVisible(): int + public function getDateLabel(): string { - return $this->sentReceivedVisible; + return $this->dateLabel; } - public function setSentReceivedVisible(int $sentReceivedVisible): self + public function getDateVisible(): int { - $this->sentReceivedVisible = $sentReceivedVisible; - - return $this; - } - - public function getSentReceivedLabel(): string - { - return $this->sentReceivedLabel; - } - - public function setSentReceivedLabel(string $sentReceivedLabel): self - { - $this->sentReceivedLabel = $sentReceivedLabel; - - return $this; - } - - public function getDocumentsVisible(): int - { - return $this->documentsVisible; - } - - public function setDocumentsVisible(int $documentsVisible): self - { - $this->documentsVisible = $documentsVisible; - - return $this; + return $this->dateVisible; } public function getDocumentsLabel(): string @@ -635,47 +319,19 @@ class ActivityType return $this->documentsLabel; } - public function setDocumentsLabel(string $documentsLabel): self + public function getDocumentsVisible(): int { - $this->documentsLabel = $documentsLabel; - - return $this; + return $this->documentsVisible; } - public function getUsersVisible(): int + public function getDurationTimeLabel(): string { - return $this->usersVisible; + return $this->durationTimeLabel; } - public function setUsersVisible(int $usersVisible): self + public function getDurationTimeVisible(): int { - $this->usersVisible = $usersVisible; - - return $this; - } - - public function getUsersLabel(): string - { - return $this->usersLabel; - } - - public function setUsersLabel(string $usersLabel): self - { - $this->usersLabel = $usersLabel; - - return $this; - } - - public function getEmergencyVisible(): int - { - return $this->emergencyVisible; - } - - public function setEmergencyVisible(int $emergencyVisible): self - { - $this->emergencyVisible = $emergencyVisible; - - return $this; + return $this->durationTimeVisible; } public function getEmergencyLabel(): string @@ -683,28 +339,202 @@ class ActivityType return $this->emergencyLabel; } - public function setEmergencyLabel(string $emergencyLabel): self + public function getEmergencyVisible(): int { - $this->emergencyLabel = $emergencyLabel; - - return $this; + return $this->emergencyVisible; } - public function getAccompanyingPeriodVisible(): int + /** + * Get id. + */ + public function getId(): int { - return $this->accompanyingPeriodVisible; + return $this->id; } - public function setAccompanyingPeriodVisible(int $accompanyingPeriodVisible): self + public function getLabel(string $field): ?string { - $this->accompanyingPeriodVisible = $accompanyingPeriodVisible; + $property = $field . 'Label'; - return $this; + if (!property_exists($this, $property)) { + throw new InvalidArgumentException('Field "' . $field . '" not found'); + } + + return $this->{$property}; } - public function getAccompanyingPeriodLabel(): string + public function getLocationLabel(): ?string { - return $this->accompanyingPeriodLabel; + return $this->locationLabel; + } + + public function getLocationVisible(): ?int + { + return $this->locationVisible; + } + + /** + * Get name. + */ + public function getName(): array + { + return $this->name; + } + + public function getOrdering(): float + { + return $this->ordering; + } + + public function getPersonLabel(): string + { + return $this->personLabel; + } + + public function getPersonsLabel(): string + { + return $this->personsLabel; + } + + public function getPersonsVisible(): int + { + return $this->personsVisible; + } + + public function getPersonVisible(): int + { + return $this->personVisible; + } + + public function getPlaceLabel(): string + { + return $this->placeLabel; + } + + public function getPlaceVisible(): int + { + return $this->placeVisible; + } + + public function getReasonsLabel(): string + { + return $this->reasonsLabel; + } + + public function getReasonsVisible(): int + { + return $this->reasonsVisible; + } + + public function getSentReceivedLabel(): string + { + return $this->sentReceivedLabel; + } + + public function getSentReceivedVisible(): int + { + return $this->sentReceivedVisible; + } + + public function getSocialActionsLabel(): ?string + { + return $this->socialActionsLabel; + } + + public function getSocialActionsVisible(): ?int + { + return $this->socialActionsVisible; + } + + public function getSocialDataLabel(): string + { + return $this->socialDataLabel; + } + + public function getSocialDataVisible(): int + { + return $this->socialDataVisible; + } + + public function getSocialIssuesLabel(): ?string + { + return $this->socialIssuesLabel; + } + + public function getSocialIssuesVisible(): ?int + { + return $this->socialIssuesVisible; + } + + public function getThirdPartiesLabel(): string + { + return $this->thirdPartiesLabel; + } + + public function getThirdPartiesVisible(): int + { + return $this->thirdPartiesVisible; + } + + public function getTravelTimeLabel(): string + { + return $this->travelTimeLabel; + } + + public function getTravelTimeVisible(): int + { + return $this->travelTimeVisible; + } + + public function getUserLabel(): string + { + return $this->userLabel; + } + + public function getUsersLabel(): string + { + return $this->usersLabel; + } + + public function getUsersVisible(): int + { + return $this->usersVisible; + } + + public function getUserVisible(): int + { + return $this->userVisible; + } + + /** + * Is active + * return true if the type is active. + */ + public function isActive(): bool + { + return $this->getActive(); + } + + public function isRequired(string $field): bool + { + $property = $field . 'Visible'; + + if (!property_exists($this, $property)) { + throw new InvalidArgumentException('Field "' . $field . '" not found'); + } + + return self::FIELD_REQUIRED === $this->{$property}; + } + + public function isVisible(string $field): bool + { + $property = $field . 'Visible'; + + if (!property_exists($this, $property)) { + throw new InvalidArgumentException('Field "' . $field . '" not found'); + } + + return self::FIELD_INVISIBLE !== $this->{$property}; } public function setAccompanyingPeriodLabel(string $accompanyingPeriodLabel): self @@ -714,138 +544,113 @@ class ActivityType return $this; } - public function getSocialDataVisible(): int + public function setAccompanyingPeriodVisible(int $accompanyingPeriodVisible): self { - return $this->socialDataVisible; - } - - public function setSocialDataVisible(int $socialDataVisible): self - { - $this->socialDataVisible = $socialDataVisible; + $this->accompanyingPeriodVisible = $accompanyingPeriodVisible; return $this; } - public function getSocialDataLabel(): string + /** + * Set active + * set to true if the type is active. + */ + public function setActive(bool $active): self { - return $this->socialDataLabel; - } - - public function setSocialDataLabel(string $socialDataLabel): self - { - $this->socialDataLabel = $socialDataLabel; + $this->active = $active; return $this; } - public function isVisible(string $field): bool + public function setAttendeeLabel(string $attendeeLabel): self { - $property = $field.'Visible'; - - if (!property_exists($this, $property)) { - throw new \InvalidArgumentException('Field "'.$field.'" not found'); - } - - return self::FIELD_INVISIBLE !== $this->$property; - } - - public function isRequired(string $field): bool - { - $property = $field.'Visible'; - - if (!property_exists($this, $property)) { - throw new \InvalidArgumentException('Field "'.$field.'" not found'); - } - - return self::FIELD_REQUIRED === $this->$property; - } - - public function getLabel(string $field): ?string - { - $property = $field.'Label'; - - if (!property_exists($this, $property)) { - throw new \InvalidArgumentException('Field "'.$field.'" not found'); - } - - return $this->$property; - } - - public function getOrdering(): float - { - return $this->ordering; - } - - public function setOrdering(float $ordering): self - { - $this->ordering = $ordering; + $this->attendeeLabel = $attendeeLabel; return $this; } - public function getSocialIssuesVisible(): ?int + public function setAttendeeVisible(int $attendeeVisible): self { - return $this->socialIssuesVisible; - } - - public function setSocialIssuesVisible(int $socialIssuesVisible): self - { - $this->socialIssuesVisible = $socialIssuesVisible; + $this->attendeeVisible = $attendeeVisible; return $this; } - public function getSocialIssuesLabel(): ?string + public function setCategory(?ActivityTypeCategory $category): self { - return $this->socialIssuesLabel; - } - - public function setSocialIssuesLabel(string $socialIssuesLabel): self - { - $this->socialIssuesLabel = $socialIssuesLabel; + $this->category = $category; return $this; } - public function getSocialActionsVisible(): ?int + public function setCommentLabel(string $commentLabel): self { - return $this->socialActionsVisible; - } - - public function setSocialActionsVisible(int $socialActionsVisible): self - { - $this->socialActionsVisible = $socialActionsVisible; + $this->commentLabel = $commentLabel; return $this; } - public function getSocialActionsLabel(): ?string + public function setCommentVisible(int $commentVisible): self { - return $this->socialActionsLabel; - } - - public function setSocialActionsLabel(string $socialActionsLabel): self - { - $this->socialActionsLabel = $socialActionsLabel; + $this->commentVisible = $commentVisible; return $this; } - public function getLocationVisible(): ?int + public function setDateLabel(string $dateLabel): self { - return $this->locationVisible; - } - - public function setLocationVisible(int $locationVisible): self - { - $this->locationVisible = $locationVisible; + $this->dateLabel = $dateLabel; return $this; } - public function getLocationLabel(): ?string + public function setDateVisible(int $dateVisible): self { - return $this->locationLabel; + $this->dateVisible = $dateVisible; + + return $this; + } + + public function setDocumentsLabel(string $documentsLabel): self + { + $this->documentsLabel = $documentsLabel; + + return $this; + } + + public function setDocumentsVisible(int $documentsVisible): self + { + $this->documentsVisible = $documentsVisible; + + return $this; + } + + public function setDurationTimeLabel(string $durationTimeLabel): self + { + $this->durationTimeLabel = $durationTimeLabel; + + return $this; + } + + public function setDurationTimeVisible(int $durationTimeVisible): self + { + $this->durationTimeVisible = $durationTimeVisible; + + return $this; + } + + public function setEmergencyLabel(string $emergencyLabel): self + { + $this->emergencyLabel = $emergencyLabel; + + return $this; + } + + public function setEmergencyVisible(int $emergencyVisible): self + { + $this->emergencyVisible = $emergencyVisible; + + return $this; } public function setLocationLabel(string $locationLabel): self @@ -855,4 +660,195 @@ class ActivityType return $this; } + public function setLocationVisible(int $locationVisible): self + { + $this->locationVisible = $locationVisible; + + return $this; + } + + /** + * Set name. + */ + public function setName(array $name): self + { + $this->name = $name; + + return $this; + } + + public function setOrdering(float $ordering): self + { + $this->ordering = $ordering; + + return $this; + } + + public function setPersonLabel(string $personLabel): self + { + $this->personLabel = $personLabel; + + return $this; + } + + public function setPersonsLabel(string $personsLabel): self + { + $this->personsLabel = $personsLabel; + + return $this; + } + + public function setPersonsVisible(int $personsVisible): self + { + $this->personsVisible = $personsVisible; + + return $this; + } + + public function setPersonVisible(int $personVisible): self + { + $this->personVisible = $personVisible; + + return $this; + } + + public function setPlaceLabel(string $placeLabel): self + { + $this->placeLabel = $placeLabel; + + return $this; + } + + public function setPlaceVisible(int $placeVisible): self + { + $this->placeVisible = $placeVisible; + + return $this; + } + + public function setReasonsLabel(string $reasonsLabel): self + { + $this->reasonsLabel = $reasonsLabel; + + return $this; + } + + public function setReasonsVisible(int $reasonsVisible): self + { + $this->reasonsVisible = $reasonsVisible; + + return $this; + } + + public function setSentReceivedLabel(string $sentReceivedLabel): self + { + $this->sentReceivedLabel = $sentReceivedLabel; + + return $this; + } + + public function setSentReceivedVisible(int $sentReceivedVisible): self + { + $this->sentReceivedVisible = $sentReceivedVisible; + + return $this; + } + + public function setSocialActionsLabel(string $socialActionsLabel): self + { + $this->socialActionsLabel = $socialActionsLabel; + + return $this; + } + + public function setSocialActionsVisible(int $socialActionsVisible): self + { + $this->socialActionsVisible = $socialActionsVisible; + + return $this; + } + + public function setSocialDataLabel(string $socialDataLabel): self + { + $this->socialDataLabel = $socialDataLabel; + + return $this; + } + + public function setSocialDataVisible(int $socialDataVisible): self + { + $this->socialDataVisible = $socialDataVisible; + + return $this; + } + + public function setSocialIssuesLabel(string $socialIssuesLabel): self + { + $this->socialIssuesLabel = $socialIssuesLabel; + + return $this; + } + + public function setSocialIssuesVisible(int $socialIssuesVisible): self + { + $this->socialIssuesVisible = $socialIssuesVisible; + + return $this; + } + + public function setThirdPartiesLabel(string $thirdPartiesLabel): self + { + $this->thirdPartiesLabel = $thirdPartiesLabel; + + return $this; + } + + public function setThirdPartiesVisible(int $thirdPartiesVisible): self + { + $this->thirdPartiesVisible = $thirdPartiesVisible; + + return $this; + } + + public function setTravelTimeLabel(string $TravelTimeLabel): self + { + $this->travelTimeLabel = $TravelTimeLabel; + + return $this; + } + + public function setTravelTimeVisible(int $TravelTimeVisible): self + { + $this->travelTimeVisible = $TravelTimeVisible; + + return $this; + } + + public function setUserLabel(string $userLabel): self + { + $this->userLabel = $userLabel; + + return $this; + } + + public function setUsersLabel(string $usersLabel): self + { + $this->usersLabel = $usersLabel; + + return $this; + } + + public function setUsersVisible(int $usersVisible): self + { + $this->usersVisible = $usersVisible; + + return $this; + } + + public function setUserVisible(int $userVisible): self + { + $this->userVisible = $userVisible; + + return $this; + } } diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php index 4b06ca9b5..37b85ce61 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php @@ -1,5 +1,12 @@ id; - } - - /** - * Set name - */ - public function setName(array $name): self - { - $this->name = $name; - - return $this; - } - - /** - * Get name - */ - public function getName(): array - { - return $this->name; - } - /** * Get active * return true if the category type is active. @@ -67,9 +51,27 @@ class ActivityTypeCategory return $this->active; } + public function getId(): ?int + { + return $this->id; + } + + /** + * Get name. + */ + public function getName(): array + { + return $this->name; + } + + public function getOrdering(): float + { + return $this->ordering; + } + /** * Is active - * return true if the category type is active + * return true if the category type is active. */ public function isActive(): bool { @@ -78,7 +80,7 @@ class ActivityTypeCategory /** * Set active - * set to true if the category type is active + * set to true if the category type is active. */ public function setActive(bool $active): self { @@ -87,9 +89,14 @@ class ActivityTypeCategory return $this; } - public function getOrdering(): float + /** + * Set name. + */ + public function setName(array $name): self { - return $this->ordering; + $this->name = $name; + + return $this; } public function setOrdering(float $ordering): self diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php index 3e5cab378..0a5b4904e 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php @@ -1,22 +1,30 @@ translatableStringHelper = $translatableStringHelper; } + 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', [ - 'activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') + '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'); @@ -88,24 +101,6 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali } } - /** - * 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() { return 'activity'; @@ -118,52 +113,37 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali ChoiceType::class, [ 'choices' => [ - 'By reason' => 'reasons', - 'By category of reason' => 'categories' + 'By reason' => 'reasons', + 'By category of reason' => 'categories', ], 'multiple' => false, 'expanded' => true, - 'label' => "Reason's level" + '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->activityReasonRepository->findBy(['id' => $values]); + break; + case 'categories': $this->activityReasonCategoryRepository->findBy(['id' => $values]); + break; + default: - throw new \RuntimeException(sprintf("The level data '%s' is invalid.", $data['level'])); + throw new RuntimeException(sprintf("The level data '%s' is invalid.", $data['level'])); } - return function($value) use ($data) { - if ($value === '_header') { - return $data['level'] === 'reasons' ? 'Group by reasons' : 'Group by categories of reason'; + return function ($value) use ($data) { + if ('_header' === $value) { + return 'reasons' === $data['level'] ? 'Group by reasons' : 'Group by categories of reason'; } switch ($data['level']) { @@ -171,32 +151,63 @@ class ActivityReasonAggregator implements AggregatorInterface, ExportElementVali $r = $this->activityReasonRepository->find($value); return sprintf( - "%s > %s", + '%s > %s', $this->translatableStringHelper->localize($r->getCategory()->getName()), $this->translatableStringHelper->localize($r->getName()) ); + case 'categories': $c = $this->activityReasonCategoryRepository->find($value); return $this->translatableStringHelper->localize($c->getName()); } }; - } public function getQueryKeys($data) { // add select element - if ($data['level'] === 'reasons') { - return array('activity_reasons_id'); + if ('reasons' === $data['level']) { + return ['activity_reasons_id']; } - if ($data['level'] === 'categories') { - return array ('activity_categories_id'); + if ('categories' === $data['level']) { + return ['activity_categories_id']; } - throw new \RuntimeException('The data provided are not recognised.'); - + 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. + * + * @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/ActivityTypeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php index bd90e8eb6..83b5f71e2 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php @@ -1,26 +1,34 @@ translatableStringHelper = $translatableStringHelper; } + public function addRole() + { + return new Role(ActivityStatsVoter::STATS); + } + public function alterQuery(QueryBuilder $qb, $data) { // add select element @@ -38,24 +51,6 @@ class ActivityTypeAggregator implements AggregatorInterface $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() { return 'activity'; @@ -66,23 +61,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): \Closure + public function getLabels($key, array $values, $data): Closure { // for performance reason, we load data from db only once $this->activityTypeRepository->findBy(['id' => $values]); - return function($value): string { - if ($value === '_header') { + return function ($value): string { + if ('_header' === $value) { return 'Activity type'; } @@ -97,4 +82,27 @@ class ActivityTypeAggregator implements AggregatorInterface 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 8e4635ef2..957e3e748 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php @@ -1,13 +1,21 @@ userRepository->findBy(['id' => $values]); - return function($value) { - if ($value === '_header') { + return function ($value) { + if ('_header' === $value) { return 'activity user'; } @@ -61,7 +69,7 @@ class ActivityUserAggregator implements AggregatorInterface public function getQueryKeys($data) { - return [ self::KEY ]; + return [self::KEY]; } public function getTitle(): string diff --git a/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php index 3d5d798f8..3824b059f 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php @@ -1,16 +1,24 @@ '_header' === $value ? 'Number of activities' : $value; + } + + public function getQueryKeys($data) + { + return ['export_count_activity']; + } + + public function getResult($qb, $data) + { + return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); + } + public function getTitle() { return 'Count activities'; @@ -42,9 +73,9 @@ class CountActivity implements ExportInterface return 'activity'; } - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { - $centers = array_map(static fn($el) => $el['center'], $acl); + $centers = array_map(static fn ($el) => $el['center'], $acl); $qb = $this ->activityRepository @@ -59,38 +90,13 @@ class CountActivity implements ExportInterface return $qb; } - public function supportsModifiers() - { - return ['person', 'activity']; - } - public function requiredRole() { return new Role(ActivityStatsVoter::STATS); } - public function getAllowedFormattersTypes() + public function supportsModifiers() { - return [FormatterInterface::TYPE_TABULAR]; + return ['person', 'activity']; } - - public function getLabels($key, array $values, $data) - { - if ($key !== 'export_count_activity') { - throw new \LogicException("the key $key is not used by this export"); - } - - return static fn($value) => $value === '_header' ? 'Number of activities' : $value; - } - - public function getQueryKeys($data) - { - return ['export_count_activity']; - } - - public function getResult($qb, $data) - { - return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); - } - } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php index 12338e225..3409980e1 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php @@ -1,35 +1,38 @@ true, 'expanded' => true, 'choices' => array_combine($this->fields, $this->fields), - 'label' => 'Fields to include in export', + 'label' => 'Fields to include in export', 'constraints' => [new Callback([ - 'callback' => function($selected, ExecutionContextInterface $context) { + 'callback' => function ($selected, ExecutionContextInterface $context) { if (count($selected) === 0) { $context->buildViolation('You must select at least one element') ->atPath('fields') ->addViolation(); } - } - ])] + }, + ])], ]); - } public function getAllowedFormattersTypes() @@ -83,69 +91,72 @@ class ListActivity implements ListInterface public function getDescription() { - return "List activities"; + return 'List activities'; } public function getLabels($key, array $values, $data) { - switch ($key) - { - case 'date' : - return static function($value) { - if ($value === '_header') { + switch ($key) { + case 'date': + return static 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 static function($value) { - if ($value === '_header') { + return static function ($value) { + if ('_header' === $value) { return 'attendee'; } return $value ? 1 : 0; }; - case 'list_reasons' : + + case 'list_reasons': $activityRepository = $this->activityRepository; - return function($value) use ($activityRepository): string { - if ($value === '_header') { + return function ($value) use ($activityRepository): string { + if ('_header' === $value) { return 'activity reasons'; } $activity = $activityRepository->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') { + + case 'circle_name': + return function ($value) { + if ('_header' === $value) { return 'circle'; } return $this->translatableStringHelper->localize(json_decode($value, true)); }; - case 'type_name' : - return function($value) { - if ($value === '_header') { + + case 'type_name': + return function ($value) { + if ('_header' === $value) { return 'activity type'; } return $this->translatableStringHelper->localize(json_decode($value, true)); }; + default: - return static function($value) use ($key) { - if ($value === '_header') { + return static function ($value) use ($key) { + if ('_header' === $value) { return $key; } @@ -176,59 +187,75 @@ class ListActivity implements ListInterface 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)) { + if (!array_key_exists('fields', $data)) { throw new 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; } - } } @@ -244,5 +271,4 @@ class ListActivity implements ListInterface { return ['activity', 'person']; } - } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php index f22623d9f..3e6122621 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php @@ -1,16 +1,24 @@ 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 = []) - { - $centers = array_map( - static fn(array $el): string => $el['center'], - $acl - ); - - $qb = $this->activityRepository->createQueryBuilder('activity'); - - $select = null; - - if ($this->action === self::SUM) { - $select = 'SUM(activity.durationTime) AS export_stat_activity'; - } - - return $qb->select($select) - ->join('activity.person', 'person') - ->join('person.center', 'center') - ->where($qb->expr()->in('center', ':centers')) - ->setParameter(':centers', $centers); - } - - public function supportsModifiers() - { - return ['person', 'activity']; - } - - public function requiredRole() - { - return new Role(ActivityStatsVoter::STATS); } public function getAllowedFormattersTypes() @@ -101,15 +56,22 @@ class StatActivityDuration implements ExportInterface return [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(sprintf('The key %s is not used by this export', $key)); + if ('export_stat_activity' !== $key) { + throw new LogicException(sprintf('The key %s is not used by this export', $key)); } - $header = $this->action === self::SUM ? 'Sum of activities duration' : false; + $header = self::SUM === $this->action ? 'Sum of activities duration' : false; - return static fn(string $value) => $value === '_header' ? $header : $value; + return static fn (string $value) => '_header' === $value ? $header : $value; } public function getQueryKeys($data) @@ -122,4 +84,47 @@ 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( + static fn (array $el): string => $el['center'], + $acl + ); + + $qb = $this->activityRepository->createQueryBuilder('activity'); + + $select = null; + + if (self::SUM === $this->action) { + $select = 'SUM(activity.durationTime) AS export_stat_activity'; + } + + return $qb->select($select) + ->join('activity.person', 'person') + ->join('person.center', 'center') + ->where($qb->expr()->in('center', ':centers')) + ->setParameter(':centers', $centers); + } + + 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 2e0149a38..fd207b22c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php @@ -1,25 +1,33 @@ translator = $translator; } @@ -32,8 +40,11 @@ class ActivityDateFilter implements FilterInterface public function alterQuery(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); @@ -58,9 +69,9 @@ class ActivityDateFilter implements FilterInterface DateType::class, [ 'label' => 'Activities after this date', - 'data' => new \DateTime(), - 'attr' => ['class' => 'datepicker'], - 'widget'=> 'single_text', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', ] ); @@ -70,46 +81,49 @@ class ActivityDateFilter implements FilterInterface DateType::class, [ 'label' => 'Activities before this date', - 'data' => new \DateTime(), - 'attr' => ['class' => 'datepicker'], - 'widget'=> 'single_text', + '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') + )); } } }); @@ -121,8 +135,8 @@ class ActivityDateFilter implements FilterInterface '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') - ] + '%date_to%' => $data['date_to']->format('d-m-Y'), + ], ]; } @@ -130,5 +144,4 @@ class ActivityDateFilter implements FilterInterface { return 'Filtered by date activity'; } - } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php index dbdceaaab..b16d75837 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php @@ -1,30 +1,37 @@ activityReasonRepository = $activityReasonRepository; } + 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') ) - || - (! array_key_exists('activity', $join)) + || (!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) { @@ -65,11 +76,57 @@ class ActivityReasonFilter implements FilterInterface, ExportElementValidatedInt $qb->setParameter('selected_activity_reasons', $data['reasons']); } + public function applyOn() + { + return 'activity'; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('reasons', EntityType::class, [ + 'class' => ActivityReason::class, + 'choice_label' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()), + 'group_by' => fn (ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()), + 'multiple' => true, + 'expanded' => false, + ]); + } + + public function describeAction($data, $format = 'string') + { + // collect all the reasons'name used in this filter in one array + $reasonsNames = array_map( + fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', + $this->activityReasonRepository->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 chosen') + ->addViolation(); + } + } + /** - * Check if a join between Activity and Reason is already defined + * Check if a join between Activity and Reason is already defined. * * @param Join[] $joins - * @return boolean + * @param mixed $alias */ private function checkJoinAlreadyDefined(array $joins, $alias): bool { @@ -81,55 +138,4 @@ class ActivityReasonFilter implements FilterInterface, ExportElementValidatedInt return false; } - - public function applyOn() - { - return 'activity'; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('reasons', EntityType::class, [ - 'class' => ActivityReason::class, - 'choice_label' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()), - 'group_by' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()), - 'multiple' => true, - 'expanded' => false - ]); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['reasons'] === null || count($data['reasons']) === 0) { - $context - ->buildViolation('At least one reason must be chosen') - ->addViolation(); - } - } - - 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( - fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', - $this->activityReasonRepository->findBy(array('id' => $data['reasons']->toArray())) - ); - - return [ - 'Filtered by reasons: only %list%', - [ - '%list%' => implode(", ", $reasonsNames), - ] - ]; - } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php index 7bf1e7210..78ebd794a 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php @@ -1,29 +1,36 @@ activityTypeRepository = $activityTypeRepository; } + public function addRole() + { + return new Role(ActivityStatsVoter::STATS); + } + public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); @@ -47,23 +59,6 @@ class ActivityTypeFilter implements FilterInterface, ExportElementValidatedInter $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() { return 'activity'; @@ -76,20 +71,27 @@ class ActivityTypeFilter implements FilterInterface, ExportElementValidatedInter EntityType::class, [ 'class' => ActivityType::class, - 'choice_label' => fn(ActivityType $type) => $this->translatableStringHelper->localize($type->getName()), + 'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()), 'multiple' => true, - 'expanded' => false + 'expanded' => false, ] ); } - public function validateForm($data, ExecutionContextInterface $context) + public function describeAction($data, $format = 'string') { - if ($data['types'] === null || count($data['types']) === 0) { - $context - ->buildViolation('At least one type must be chosen') - ->addViolation(); - } + // collect all the reasons'name used in this filter in one array + $reasonsNames = array_map( + fn (ActivityType $t): string => '"' . $this->translatableStringHelper->localize($t->getName()) . '"', + $this->activityTypeRepository->findBy(['id' => $data['types']->toArray()]) + ); + + return [ + 'Filtered by activity type: only %list%', + [ + '%list%' => implode(', ', $reasonsNames), + ], + ]; } public function getTitle() @@ -97,24 +99,31 @@ class ActivityTypeFilter implements FilterInterface, ExportElementValidatedInter return 'Filter by activity type'; } - public function addRole() + public function validateForm($data, ExecutionContextInterface $context) { - return new Role(ActivityStatsVoter::STATS); + if (null === $data['types'] || count($data['types']) === 0) { + $context + ->buildViolation('At least one type must be chosen') + ->addViolation(); + } } - public function describeAction($data, $format = 'string') + /** + * 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) { - // collect all the reasons'name used in this filter in one array - $reasonsNames = array_map( - fn(ActivityType $t): string => '"' . $this->translatableStringHelper->localize($t->getName()) . '"', - $this->activityTypeRepository->findBy(['id' => $data['types']->toArray()]) - ); + foreach ($joins as $join) { + if ($join->getAlias() === $alias) { + return true; + } + } - return [ - 'Filtered by activity type: only %list%', - [ - '%list%' => implode(", ", $reasonsNames), - ] - ]; + return false; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php index d150c68e6..5338a0f21 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php @@ -1,35 +1,43 @@ andWhere( $sqb->expr()->in( - 'reasons_person_having_activity', ':person_having_activity_reasons' + 'reasons_person_having_activity', + ':person_having_activity_reasons' ) ); @@ -80,10 +89,14 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, ExportEl } $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']); } @@ -96,76 +109,71 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, ExportEl { $builder->add('date_from', DateType::class, [ 'label' => 'Implied in an activity after this date', - 'data' => new \DateTime(), - 'attr' => ['class' => 'datepicker'], - 'widget'=> 'single_text', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', ]); $builder->add('date_to', DateType::class, [ 'label' => 'Implied in an activity before this date', - 'data' => new \DateTime(), - 'attr' => ['class' => 'datepicker'], - 'widget'=> 'single_text', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', ]); $builder->add('reasons', EntityType::class, [ 'class' => ActivityReason::class, 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()), - 'group_by' => fn(ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()), + 'group_by' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()), 'data' => $this->activityReasonRepository->findAll(), 'multiple' => true, 'expanded' => false, - 'label' => 'Activity reasons for those activities' + 'label' => 'Activity reasons for those activities', ]); - $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { /* @var FormInterface $filterForm */ $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 chosen') - ->addViolation(); - } - } - public function describeAction($data, $format = 'string') { return [ @@ -173,15 +181,15 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, ExportEl . '%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( - ", ", + '%date_to%' => $data['date_to']->format('d-m-Y'), + '%reasons_name%' => implode( + ', ', array_map( - fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', + fn (ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', $data['reasons'] ) - ) - ] + ), + ], ]; } @@ -190,4 +198,11 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, ExportEl 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 chosen') + ->addViolation(); + } + } } diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityPresenceType.php b/src/Bundle/ChillActivityBundle/Form/ActivityPresenceType.php index 42894cc25..105812caa 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityPresenceType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityPresenceType.php @@ -1,13 +1,20 @@ 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, + ]); } public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults(array( - 'data_class' => ActivityPresence::class - )); + $resolver->setDefaults([ + 'data_class' => ActivityPresence::class, + ]); } } 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 5ef08832d..5cba5ad57 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -1,5 +1,12 @@ 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(); @@ -100,12 +109,13 @@ class ActivityType extends AbstractType 'center' => $options['center'], 'role' => $options['role'], // TODO make required again once scope and rights are fixed - 'required' => false + 'required' => false, ]); } /** @var ? \Chill\PersonBundle\Entity\AccompanyingPeriod $accompanyingPeriod */ - $accompanyingPeriod = NULL; + $accompanyingPeriod = null; + if ($options['accompanyingPeriod']) { $accompanyingPeriod = $options['accompanyingPeriod']; } @@ -113,49 +123,53 @@ class ActivityType extends AbstractType if ($activityType->isVisible('socialIssues') && $accompanyingPeriod) { $builder->add('socialIssues', HiddenType::class); $builder->get('socialIssues') - ->addModelTransformer(new CallbackTransformer( - function (iterable $socialIssuesAsIterable): string { - $socialIssueIds = []; - foreach ($socialIssuesAsIterable as $value) { - $socialIssueIds[] = $value->getId(); - } - return implode(',', $socialIssueIds); - }, - function (?string $socialIssuesAsString): array { - if (null === $socialIssuesAsString) { - return []; - } - return array_map( - fn(string $id): ?SocialIssue => $this->om->getRepository(SocialIssue::class)->findOneBy(['id' => (int) $id]), - explode(',', $socialIssuesAsString) - ); - } - )) - ; + ->addModelTransformer(new CallbackTransformer( + function (iterable $socialIssuesAsIterable): string { + $socialIssueIds = []; + + foreach ($socialIssuesAsIterable as $value) { + $socialIssueIds[] = $value->getId(); + } + + return implode(',', $socialIssueIds); + }, + function (?string $socialIssuesAsString): array { + if (null === $socialIssuesAsString) { + return []; + } + + return array_map( + fn (string $id): ?SocialIssue => $this->om->getRepository(SocialIssue::class)->findOneBy(['id' => (int) $id]), + explode(',', $socialIssuesAsString) + ); + } + )); } if ($activityType->isVisible('socialActions') && $accompanyingPeriod) { $builder->add('socialActions', HiddenType::class); $builder->get('socialActions') - ->addModelTransformer(new CallbackTransformer( - function (iterable $socialActionsAsIterable): string { - $socialActionIds = []; - foreach ($socialActionsAsIterable as $value) { - $socialActionIds[] = $value->getId(); - } - return implode(',', $socialActionIds); - }, - function (?string $socialActionsAsString): array { - if (null === $socialActionsAsString) { - return []; - } - return array_map( - fn(string $id): ?SocialAction => $this->om->getRepository(SocialAction::class)->findOneBy(['id' => (int) $id]), - explode(',', $socialActionsAsString) - ); - } - )) - ; + ->addModelTransformer(new CallbackTransformer( + function (iterable $socialActionsAsIterable): string { + $socialActionIds = []; + + foreach ($socialActionsAsIterable as $value) { + $socialActionIds[] = $value->getId(); + } + + return implode(',', $socialActionIds); + }, + function (?string $socialActionsAsString): array { + if (null === $socialActionsAsString) { + return []; + } + + return array_map( + fn (string $id): ?SocialAction => $this->om->getRepository(SocialAction::class)->findOneBy(['id' => (int) $id]), + explode(',', $socialActionsAsString) + ); + } + )); } if ($activityType->isVisible('date')) { @@ -200,7 +214,7 @@ class ActivityType extends AbstractType 'label' => $activityType->getLabel('user'), 'required' => $activityType->isRequired('user'), 'center' => $options['center'], - 'role' => $options['role'] + 'role' => $options['role'], ]); } @@ -213,7 +227,7 @@ class ActivityType extends AbstractType 'choice_label' => function (ActivityReason $activityReason) { return $this->translatableStringHelper->localize($activityReason->getName()); }, - 'attr' => array('class' => 'select2 '), + 'attr' => ['class' => 'select2 '], 'query_builder' => function (EntityRepository $er) { return $er->createQueryBuilder('a') ->where('a.active = true'); @@ -232,43 +246,45 @@ class ActivityType extends AbstractType if ($activityType->isVisible('persons')) { $builder->add('persons', HiddenType::class); $builder->get('persons') - ->addModelTransformer(new CallbackTransformer( - function (iterable $personsAsIterable): string { - $personIds = []; - foreach ($personsAsIterable as $value) { - $personIds[] = $value->getId(); - } - return implode(',', $personIds); - }, - function (?string $personsAsString): array { - return array_map( - fn(string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]), - explode(',', $personsAsString) - ); - } - )) - ; + ->addModelTransformer(new CallbackTransformer( + function (iterable $personsAsIterable): string { + $personIds = []; + + foreach ($personsAsIterable as $value) { + $personIds[] = $value->getId(); + } + + return implode(',', $personIds); + }, + function (?string $personsAsString): array { + return array_map( + fn (string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]), + explode(',', $personsAsString) + ); + } + )); } if ($activityType->isVisible('thirdParties')) { $builder->add('thirdParties', HiddenType::class); $builder->get('thirdParties') - ->addModelTransformer(new CallbackTransformer( - function (iterable $thirdpartyAsIterable): string { - $thirdpartyIds = []; - foreach ($thirdpartyAsIterable as $value) { - $thirdpartyIds[] = $value->getId(); - } - return implode(',', $thirdpartyIds); - }, - function (?string $thirdpartyAsString): array { - return array_map( - fn(string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]), - explode(',', $thirdpartyAsString) - ); - } - )) - ; + ->addModelTransformer(new CallbackTransformer( + function (iterable $thirdpartyAsIterable): string { + $thirdpartyIds = []; + + foreach ($thirdpartyAsIterable as $value) { + $thirdpartyIds[] = $value->getId(); + } + + return implode(',', $thirdpartyIds); + }, + function (?string $thirdpartyAsString): array { + return array_map( + fn (string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]), + explode(',', $thirdpartyAsString) + ); + } + )); } if ($activityType->isVisible('documents')) { @@ -278,29 +294,30 @@ class ActivityType extends AbstractType 'required' => $activityType->isRequired('documents'), 'allow_add' => true, 'button_add_label' => 'activity.Insert a document', - 'button_remove_label' => 'activity.Remove a document' + 'button_remove_label' => 'activity.Remove a document', ]); } if ($activityType->isVisible('users')) { $builder->add('users', HiddenType::class); $builder->get('users') - ->addModelTransformer(new CallbackTransformer( - function (iterable $usersAsIterable): string { - $userIds = []; - foreach ($usersAsIterable as $value) { - $userIds[] = $value->getId(); - } - return implode(',', $userIds); - }, - function (?string $usersAsString): array { - return array_map( - fn(string $id): ?User => $this->om->getRepository(User::class)->findOneBy(['id' => (int) $id]), - explode(',', $usersAsString) - ); - } - )) - ; + ->addModelTransformer(new CallbackTransformer( + function (iterable $usersAsIterable): string { + $userIds = []; + + foreach ($usersAsIterable as $value) { + $userIds[] = $value->getId(); + } + + return implode(',', $userIds); + }, + function (?string $usersAsString): array { + return array_map( + fn (string $id): ?User => $this->om->getRepository(User::class)->findOneBy(['id' => (int) $id]), + explode(',', $usersAsString) + ); + } + )); } if ($activityType->isVisible('location')) { @@ -311,13 +328,13 @@ class ActivityType extends AbstractType if (null === $location) { return ''; } + return $location->getId(); }, function (?string $id): ?Location { return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]); } - )) - ; + )); } if ($activityType->isVisible('emergency')) { @@ -347,7 +364,7 @@ class ActivityType extends AbstractType ->addModelTransformer($durationTimeTransformer); $builder->get($fieldName) - ->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $formEvent) use ( + ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $formEvent) use ( $timeChoices, $builder, $durationTimeTransformer, @@ -356,14 +373,14 @@ class ActivityType extends AbstractType ) { // 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'); + $timezoneUTC = new DateTimeZone('GMT'); /* @var $data \DateTime */ - $data = $formEvent->getData() === NULL ? - \DateTime::createFromFormat('U', 300) : + $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')); + $data->add(new DateInterval('PT' . $seconds . 'S')); // test if the timestamp is in the choices. // If not, recreate the field with the new timestamp @@ -371,9 +388,10 @@ class ActivityType extends AbstractType // the data are not in the possible values. add them $timeChoices[$data->format('H:i')] = $data->getTimestamp(); $form = $builder->create($fieldName, ChoiceType::class, array_merge( - $durationTimeOptions, [ + $durationTimeOptions, + [ 'choices' => $timeChoices, - 'auto_initialize' => false + 'auto_initialize' => false, ] )); $form->addModelTransformer($durationTimeTransformer); @@ -383,12 +401,10 @@ class ActivityType extends AbstractType } } - - public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ - 'data_class' => Activity::class + 'data_class' => Activity::class, ]); $resolver @@ -396,8 +412,7 @@ class ActivityType extends AbstractType ->setAllowedTypes('center', ['null', 'Chill\MainBundle\Entity\Center']) ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role') ->setAllowedTypes('activityType', \Chill\ActivityBundle\Entity\ActivityType::class) - ->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']) - ; + ->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']); } public function getBlockPrefix(): string diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityTypeCategoryType.php b/src/Bundle/ChillActivityBundle/Form/ActivityTypeCategoryType.php index 0c592f519..081f8ac99 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityTypeCategoryType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityTypeCategoryType.php @@ -1,14 +1,21 @@ 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, + ]) ->add('ordering', NumberType::class, [ 'required' => true, - 'scale' => 5 - ]) - ; + 'scale' => 5, + ]); } public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults(array( - 'data_class' => ActivityTypeCategory::class - )); + $resolver->setDefaults([ + 'data_class' => ActivityTypeCategory::class, + ]); } } diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php index d1a46b109..300be5c4c 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php @@ -1,18 +1,25 @@ add('active', ChoiceType::class, [ 'choices' => [ 'Yes' => true, - 'No' => false + 'No' => false, ], - 'expanded' => true + 'expanded' => true, ]) ->add('category', EntityType::class, [ 'class' => ActivityTypeCategory::class, @@ -42,20 +49,20 @@ class ActivityTypeType extends AbstractType ]) ->add('ordering', NumberType::class, [ 'required' => true, - 'scale' => 5 - ]) - ; + 'scale' => 5, + ]); $fields = [ 'persons', 'user', 'date', 'place', 'persons', 'thirdParties', 'durationTime', 'travelTime', 'attendee', 'reasons', 'comment', 'sentReceived', 'documents', - 'emergency', 'accompanyingPeriod', 'socialData', 'users' + 'emergency', 'accompanyingPeriod', 'socialData', 'users', ]; + foreach ($fields as $field) { $builder - ->add($field.'Visible', ActivityFieldPresence::class) - ->add($field.'Label', TextType::class, [ + ->add($field . 'Visible', ActivityFieldPresence::class) + ->add($field . 'Label', TextType::class, [ 'required' => false, 'empty_data' => '', ]); @@ -64,8 +71,8 @@ class ActivityTypeType extends AbstractType public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => \Chill\ActivityBundle\Entity\ActivityType::class - )); + $resolver->setDefaults([ + 'data_class' => \Chill\ActivityBundle\Entity\ActivityType::class, + ]); } } diff --git a/src/Bundle/ChillActivityBundle/Form/Type/ActivityFieldPresence.php b/src/Bundle/ChillActivityBundle/Form/Type/ActivityFieldPresence.php index 8de67b546..960762d35 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/ActivityFieldPresence.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/ActivityFieldPresence.php @@ -1,5 +1,12 @@ setDefaults( - array( + [ 'choices' => [ 'Invisible' => ActivityType::FIELD_INVISIBLE, 'Optional' => ActivityType::FIELD_OPTIONAL, 'Required' => ActivityType::FIELD_REQUIRED, ], - ) + ] ); } + + public function getParent() + { + return ChoiceType::class; + } } 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 f930d3c1a..6b677ada2 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php @@ -1,25 +1,32 @@ activityTypeRepository = $activityTypeRepository; } + public function buildForm(FormBuilderInterface $builder, array $options) + { + /* @var QueryBuilder $qb */ + $qb = $options['query_builder']; + + if (true === $options['active_only']) { + $qb->where($qb->expr()->eq('at.active', ':active')); + $qb->setParameter('active', true, Types::BOOLEAN); + } + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + [ + 'class' => ActivityType::class, + 'active_only' => true, + 'query_builder' => $this->activityTypeRepository + ->createQueryBuilder('at'), + 'choice_label' => function (ActivityType $type) { + return $this->translatableStringHelper->localize($type->getName()); + }, + ] + ); + } + public function getBlockPrefix() { return 'translatable_activity_type'; @@ -37,29 +70,4 @@ class TranslatableActivityType extends AbstractType { return EntityType::class; } - - public function buildForm(FormBuilderInterface $builder, array $options) { - /* @var QueryBuilder $qb */ - $qb = $options['query_builder']; - - if ($options['active_only'] === true) { - $qb->where($qb->expr()->eq('at.active', ':active')); - $qb->setParameter('active', true, Types::BOOLEAN); - } - } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - array( - 'class' => ActivityType::class, - '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/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php index b8ea9bf9a..8c3ed58f3 100644 --- a/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -1,22 +1,27 @@ security = $security; $this->translator = $translator; } - public static function getMenuIds(): array - { - return ['accompanyingCourse']; - } public function buildMenu($menuId, MenuItem $menu, array $parameters) { @@ -39,8 +40,13 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface 'route' => 'chill_activity_activity_list', 'routeParameters' => [ 'accompanying_period_id' => $period->getId(), - ]]) + ], ]) ->setExtras(['order' => 40]); } } + + public static function getMenuIds(): array + { + return ['accompanyingCourse']; + } } diff --git a/src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php index ce7618b6d..e4edb97fe 100644 --- a/src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php +++ b/src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php @@ -1,4 +1,12 @@ security = $security; } - public static function getMenuIds(): array - { - return ['admin_index', 'admin_section', 'admin_activity']; - } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { if (!$this->security->isGranted('ROLE_ADMIN')) { @@ -29,20 +32,25 @@ final class AdminMenuBuilder implements LocalMenuBuilderInterface if (in_array($menuId, ['admin_index', 'admin_section'])) { $menu->addChild('Activities', [ - 'route' => 'chill_admin_activity_index' + 'route' => 'chill_admin_activity_index', ]) ->setExtras([ 'order' => 2000, - 'explain' => "Activity configuration" + 'explain' => 'Activity configuration', ]); } else { $menu ->addChild('Activities', [ - 'route' => 'chill_admin_activity_index' + 'route' => 'chill_admin_activity_index', ]) ->setExtras([ - 'order' => '60' + 'order' => '60', ]); } } -} \ No newline at end of file + + public static function getMenuIds(): array + { + return ['admin_index', 'admin_section', 'admin_activity']; + } +} diff --git a/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php index e44a0f561..d5ae9c528 100644 --- a/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php +++ b/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php @@ -1,68 +1,54 @@ + +/** + * 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; + +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); } } diff --git a/src/Bundle/ChillActivityBundle/Notification/ActivityNotificationRenderer.php b/src/Bundle/ChillActivityBundle/Notification/ActivityNotificationRenderer.php index 1836f599b..79290f2aa 100644 --- a/src/Bundle/ChillActivityBundle/Notification/ActivityNotificationRenderer.php +++ b/src/Bundle/ChillActivityBundle/Notification/ActivityNotificationRenderer.php @@ -1,17 +1,19 @@ getRelatedEntityClass() == Activity::class; - } - public function getTemplate() { return '@ChillActivity/Activity/showInNotification.html.twig'; @@ -21,4 +23,9 @@ final class ActivityNotificationRenderer { return ['notification' => $notification]; } + + public function supports(Notification $notification, array $options = []): bool + { + return $notification->getRelatedEntityClass() == Activity::class; + } } diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php index b498a6090..eb53a6217 100644 --- a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.php +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepository.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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ +declare(strict_types=1); + namespace Chill\ActivityBundle\Repository; use Chill\ActivityBundle\Entity\Activity; -use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\Person; -use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\MainBundle\Entity\Scope; -use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\Query\Expr\Orx; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\Security; - +use function in_array; final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInterface { private AuthorizationHelper $authorizationHelper; - private TokenStorageInterface $tokenStorage; - - private ActivityRepository $repository; + private CenterResolverDispatcherInterface $centerResolverDispatcher; private EntityManagerInterface $em; + private ActivityRepository $repository; + private Security $security; - private CenterResolverDispatcher $centerResolverDispatcher; + private TokenStorageInterface $tokenStorage; public function __construct( AuthorizationHelper $authorizationHelper, - CenterResolverDispatcher $centerResolverDispatcher, + CenterResolverDispatcherInterface $centerResolverDispatcher, TokenStorageInterface $tokenStorage, ActivityRepository $repository, EntityManagerInterface $em, @@ -68,34 +54,11 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte $this->security = $security; } - /** - * @param Person $person - * @param string $role - * @param int|null $start - * @param int|null $limit - * @param array $orderBy - * @return array|Activity[] - */ - public function findByPerson(Person $person, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array - { - $user = $this->security->getUser(); - $center = $this->centerResolverDispatcher->resolveCenter($person); - if (0 === count($orderBy)) { - $orderBy = ['date' => 'DESC']; - } - - $reachableScopes = $this->authorizationHelper - ->getReachableCircles($user, $role, $center); - - return $this->em->getRepository(Activity::class) - ->findByPersonImplied($person, $reachableScopes, $orderBy, $limit, $start); - ; - } - public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array { $user = $this->security->getUser(); $center = $this->centerResolverDispatcher->resolveCenter($period); + if (0 === count($orderBy)) { $orderBy = ['date' => 'DESC']; } @@ -107,6 +70,27 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte ->findByAccompanyingPeriod($period, $scopes, true, $limit, $start, $orderBy); } + /** + * @param array $orderBy + * + * @return Activity[]|array + */ + public function findByPerson(Person $person, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array + { + $user = $this->security->getUser(); + $center = $this->centerResolverDispatcher->resolveCenter($person); + + if (0 === count($orderBy)) { + $orderBy = ['date' => 'DESC']; + } + + $reachableScopes = $this->authorizationHelper + ->getReachableCircles($user, $role, $center); + + return $this->em->getRepository(Activity::class) + ->findByPersonImplied($person, $reachableScopes, $orderBy, $limit, $start); + } + public function queryTimelineIndexer(string $context, array $args = []): array { $metadataActivity = $this->em->getClassMetadata(Activity::class); @@ -115,15 +99,15 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte [$where, $parameters] = $this->getWhereClause($context, $args); return [ - 'id' => $metadataActivity->getTableName() - .'.'.$metadataActivity->getColumnName('id'), - 'type' => 'activity', - 'date' => $metadataActivity->getTableName() - .'.'.$metadataActivity->getColumnName('date'), - 'FROM' => $from, - 'WHERE' => $where, - 'parameters' => $parameters - ]; + 'id' => $metadataActivity->getTableName() + . '.' . $metadataActivity->getColumnName('id'), + 'type' => 'activity', + 'date' => $metadataActivity->getTableName() + . '.' . $metadataActivity->getColumnName('date'), + 'FROM' => $from, + 'WHERE' => $where, + 'parameters' => $parameters, + ]; } private function getFromClauseCenter(array $args): string @@ -132,13 +116,12 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte $metadataPerson = $this->em->getClassMetadata(Person::class); $associationMapping = $metadataActivity->getAssociationMapping('person'); - return $metadataActivity->getTableName().' JOIN ' - .$metadataPerson->getTableName().' ON ' - .$metadataPerson->getTableName().'.'. + return $metadataActivity->getTableName() . ' JOIN ' + . $metadataPerson->getTableName() . ' ON ' + . $metadataPerson->getTableName() . '.' . $associationMapping['joinColumns'][0]['referencedColumnName'] - .' = ' - .$associationMapping['joinColumns'][0]['name'] - ; + . ' = ' + . $associationMapping['joinColumns'][0]['name']; } private function getWhereClause(string $context, array $args): array @@ -149,21 +132,22 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte $metadataActivity = $this->em->getClassMetadata(Activity::class); $metadataPerson = $this->em->getClassMetadata(Person::class); $activityToPerson = $metadataActivity->getAssociationMapping('person')['joinColumns'][0]['name']; - $activityToScope = $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name']; + $activityToScope = $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name']; $personToCenter = $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name']; - // acls: $role = new Role(ActivityVoter::SEE); - $reachableCenters = $this->authorizationHelper->getReachableCenters($this->tokenStorage->getToken()->getUser(), - $role); + $reachableCenters = $this->authorizationHelper->getReachableCenters( + $this->tokenStorage->getToken()->getUser(), + $role + ); if (count($reachableCenters) === 0) { // insert a dummy condition return 'FALSE = TRUE'; } - if ($context === 'person') { + if ('person' === $context) { // we start with activities having the person_id linked to person $where .= sprintf('%s = ? AND ', $activityToPerson); $parameters[] = $person->getId(); @@ -172,21 +156,22 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte // we add acl (reachable center and scopes) $where .= '('; // first loop for the for centers $centersI = 0; // like centers#i + foreach ($reachableCenters as $center) { // we pass if not in centers - if (!\in_array($center, $args['centers'])) { + if (!in_array($center, $args['centers'])) { continue; } // we get all the reachable scopes for this center $reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), $role, $center); // we get the ids for those scopes $reachablesScopesId = array_map( - function(Scope $scope) { return $scope->getId(); }, + function (Scope $scope) { return $scope->getId(); }, $reachableScopes ); // if not the first center - if ($centersI > 0) { + if (0 < $centersI) { $where .= ') OR ('; } @@ -199,21 +184,20 @@ final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInte $scopesI = 0; //like scope#i foreach ($reachablesScopesId as $scopeId) { - if ($scopesI > 0) { + if (0 < $scopesI) { $where .= ' OR '; } $where .= sprintf(' %s.%s = ? ', $metadataActivity->getTableName(), $activityToScope); $parameters[] = $scopeId; - $scopesI ++; + ++$scopesI; } // close loop for scopes $where .= ') '; - $centersI++; + ++$centersI; } // close loop for centers $where .= ')'; return [$where, $parameters]; } - } diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php index 0b646f7c5..b09f62115 100644 --- a/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityACLAwareRepositoryInterface.php @@ -1,5 +1,12 @@ 'DESC'], ?int $limit = 100, ?int $offset = 0): array - { - $qb = $this->createQueryBuilder('a'); - $qb->select('a'); - - $qb - ->where($qb->expr()->in('a.scope', ':scopes')) - ->setParameter('scopes', $scopes) - ->andWhere( - $qb->expr()->orX( - $qb->expr()->eq('a.person', ':person'), - ':person MEMBER OF a.persons' - ) - ) - ->setParameter('person', $person); - - foreach ($orderBy as $k => $dir) { - $qb->addOrderBy('a.'.$k, $dir); - } - - $qb->setMaxResults($limit)->setFirstResult($offset); - - return $qb->getQuery()->getResult(); - } - /** * @return Activity[] */ @@ -81,7 +60,35 @@ class ActivityRepository extends ServiceEntityRepository ->setParameter('period', $period); foreach ($orderBy as $k => $dir) { - $qb->addOrderBy('a.'.$k, $dir); + $qb->addOrderBy('a.' . $k, $dir); + } + + $qb->setMaxResults($limit)->setFirstResult($offset); + + return $qb->getQuery()->getResult(); + } + + /** + * @return Activity[] + */ + public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = ['date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array + { + $qb = $this->createQueryBuilder('a'); + $qb->select('a'); + + $qb + ->where($qb->expr()->in('a.scope', ':scopes')) + ->setParameter('scopes', $scopes) + ->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('a.person', ':person'), + ':person MEMBER OF a.persons' + ) + ) + ->setParameter('person', $person); + + foreach ($orderBy as $k => $dir) { + $qb->addOrderBy('a.' . $k, $dir); } $qb->setMaxResults($limit)->setFirstResult($offset); diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityTypeCategoryRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeCategoryRepository.php index 62a6a9a0d..1714d14e3 100644 --- a/src/Bundle/ChillActivityBundle/Repository/ActivityTypeCategoryRepository.php +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeCategoryRepository.php @@ -1,5 +1,12 @@ - +
- -
+
    -
  • +
  • {{ p.text }} @@ -25,7 +24,7 @@ buttonTitle="activity.add_persons" modalTitle="activity.add_persons" v-bind:key="addPersons.key" - v-bind:options="addPersons.options" + v-bind:options="addPersonsOptions" @addNewPersons="addNewPersons" ref="addPersons"> @@ -55,38 +54,35 @@ export default { { key: 'personsAssociated', title: 'activity.bloc_persons_associated', persons: [], - included: false + included: window.activity ? window.activity.activityType.personsVisible !== 0 : true }, { key: 'personsNotAssociated', title: 'activity.bloc_persons_not_associated', persons: [], - included: false + included: window.activity ? window.activity.activityType.personsVisible !== 0 : true }, { key: 'thirdparty', title: 'activity.bloc_thirdparty', persons: [], - included: true + included: window.activity ? window.activity.activityType.thirdPartiesVisible !== 0 : true }, { key: 'users', title: 'activity.bloc_users', persons: [], - included: true + included: window.activity ? window.activity.activityType.usersVisible !== 0 : true }, ], addPersons: { - key: 'activity', - options: { - type: ['person', 'thirdparty', 'user'], - priority: null, - uniq: false, - button: { - size: 'btn-sm' - } - } + key: 'activity' } } }, computed: { + isComponentVisible() { + return window.activity + ? (window.activity.activityType.personsVisible !== 0 || window.activity.activityType.thirdPartiesVisible !== 0 || window.activity.activityType.usersVisible !== 0) + : true + }, ...mapState({ persons: state => state.activity.persons, thirdParties: state => state.activity.thirdParties, @@ -94,14 +90,38 @@ export default { accompanyingCourse: state => state.activity.accompanyingPeriod }), ...mapGetters([ - 'filterSuggestedPersons' + 'suggestedEntities' ]), getContext() { return (this.accompanyingCourse) ? "accompanyingCourse" : "person"; }, contextPersonsBlocs() { return this.personsBlocs.filter(bloc => bloc.included !== false); - } + }, + addPersonsOptions() { + let optionsType = []; + if (window.activity) { + if (window.activity.activityType.personsVisible !== 0) { + optionsType.push('person') + } + if (window.activity.activityType.thirdPartiesVisible !== 0) { + optionsType.push('thirdparty') + } + if (window.activity.activityType.usersVisible !== 0) { + optionsType.push('user') + } + } else { + optionsType = ['person', 'thirdparty', 'user']; + } + return { + type: optionsType, + priority: null, + uniq: false, + button: { + size: 'btn-sm' + } + } + }, }, mounted() { this.setPersonsInBloc(); @@ -171,7 +191,7 @@ export default { }, addNewPersons({ selected, modal }) { console.log('@@@ CLICK button addNewPersons', selected); - selected.forEach(function(item) { + selected.forEach((item) => { this.$store.dispatch('addPersonsInvolved', item); }, this ); @@ -179,7 +199,7 @@ export default { modal.showModal = false; this.setPersonsInBloc(); }, - addNewPerson(person) { + addSuggestedEntity(person) { this.$store.dispatch('addPersonsInvolved', { result: person, type: 'person' }); this.setPersonsInBloc(); }, diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue index c8d1472bd..5fa3360b7 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue @@ -55,16 +55,17 @@ export default { } }, mounted() { - this.getLocationsList(); + getLocations().then(response => new Promise(resolve => { + console.log('getLocations', response); + this.locations = response.results; + if (window.default_location_id) { + let location = this.locations.filter(l => l.id === window.default_location_id); + this.$store.dispatch('updateLocation', location); + } + resolve(); + })) }, methods: { - getLocationsList() { - getLocations().then(response => new Promise(resolve => { - console.log('getLocations', response); - this.locations = response.results; - resolve(); - })) - }, customLabel(value) { return `${value.locationType.title.fr} ${value.name ? value.name : ''}`; } diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js index 415c5a359..ef9cf3b1f 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js @@ -19,172 +19,294 @@ const removeIdFromValue = (string, id) => { }; const store = createStore({ - strict: debug, - state: { - activity: window.activity, - socialIssuesOther: [], - socialActionsList: [], - }, - getters: { - filterSuggestedPersons(state) { - if (typeof(state.activity.accompanyingPeriod) === 'undefined') { - return []; - } - let existingPersonIds = state.activity.persons.map(p => p.id); - return state.activity.accompanyingPeriod.participations.filter(p => p.endDate === null) - .map(p => p.person) - .filter(p => !existingPersonIds.includes(p.id)) - } - }, - mutations: { - // SocialIssueAcc - addIssueInList(state, issue) { - //console.log('add issue list', issue.id); - state.activity.accompanyingPeriod.socialIssues.push(issue); - }, - addIssueSelected(state, issue) { - //console.log('add issue selected', issue.id); - state.activity.socialIssues.push(issue); - }, - updateIssuesSelected(state, issues) { - //console.log('update issues selected', issues); - state.activity.socialIssues = issues; - }, - updateIssuesOther(state, payload) { - //console.log('update issues other'); - state.socialIssuesOther = payload; - }, - removeIssueInOther(state, issue) { - //console.log('remove issue other', issue.id); - state.socialIssuesOther = state.socialIssuesOther.filter(i => i.id !== issue.id); - }, - resetActionsList(state) { - //console.log('reset list actions'); - state.socialActionsList = []; - }, - addActionInList(state, action) { - //console.log('add action list', action.id); - state.socialActionsList.push(action); - }, - updateActionsSelected(state, actions) { - //console.log('update actions selected', actions); - state.activity.socialActions = actions; - }, - filterList(state, list) { - const filterList = (list) => { - // remove duplicates entries - list = list.filter((value, index) => list.findIndex(array => array.id === value.id) === index); - // alpha sort - list.sort((a,b) => (a.text > b.text) ? 1 : ((b.text > a.text) ? -1 : 0)); - return list; - }; - if (list === 'issues') { - state.activity.accompanyingPeriod.socialIssues = filterList(state.activity.accompanyingPeriod.socialIssues); - } - if (list === 'actions') { - state.socialActionsList = filterList(state.socialActionsList); - } + strict: debug, + state: { + activity: window.activity, + socialIssuesOther: [], + socialActionsList: [], }, + getters: { + suggestedEntities(state) { + console.log(state.activity); + if (typeof state.activity.accompanyingPeriod === "undefined") { + return []; + } + const allEntities = [ + ...store.getters.suggestedPersons, + ...store.getters.suggestedRequestor, + ...store.getters.suggestedUser, + ...store.getters.suggestedResources, + ]; + const uniqueIds = [ + ...new Set(allEntities.map((i) => `${i.type}-${i.id}`)), + ]; + return Array.from( + uniqueIds, + (id) => allEntities.filter((r) => `${r.type}-${r.id}` === id)[0] + ); + }, + suggestedPersons(state) { + const existingPersonIds = state.activity.persons.map((p) => p.id); + return state.activity.activityType.personsVisible === 0 + ? [] + : state.activity.accompanyingPeriod.participations + .filter((p) => p.endDate === null) + .map((p) => p.person) + .filter((p) => !existingPersonIds.includes(p.id)); + }, + suggestedRequestor(state) { + if (state.activity.accompanyingPeriod.requestor === null) { + return []; + } + const existingPersonIds = state.activity.persons.map((p) => p.id); + const existingThirdPartyIds = state.activity.thirdParties.map( + (p) => p.id + ); - // ConcernedGroups - addPersonsInvolved(state, payload) { - //console.log('### mutation addPersonsInvolved', payload.result.type); - switch (payload.result.type) { - case 'person': - state.activity.persons.push(payload.result); - break; - case 'thirdparty': - state.activity.thirdParties.push(payload.result); - break; - case 'user': - state.activity.users.push(payload.result); - break; - }; + return [state.activity.accompanyingPeriod.requestor].filter( + (r) => + (r.type === "person" && + !existingPersonIds.includes(r.id) && + state.activity.activityType.personsVisible !== 0) || + (r.type === "thirdparty" && + !existingThirdPartyIds.includes(r.id) && + state.activity.activityType.thirdPartiesVisible !== 0) + ); + }, + suggestedUser(state) { + const existingUserIds = state.activity.users.map((p) => p.id); + return state.activity.activityType.usersVisible === 0 + ? [] + : [state.activity.accompanyingPeriod.user].filter( + (u) => u !== null && !existingUserIds.includes(u.id) + ); + }, + suggestedResources(state) { + const resources = state.activity.accompanyingPeriod.resources; + const existingPersonIds = state.activity.persons.map((p) => p.id); + const existingThirdPartyIds = state.activity.thirdParties.map( + (p) => p.id + ); + return state.activity.accompanyingPeriod.resources + .map((r) => r.resource) + .filter( + (r) => + (r.type === "person" && + !existingPersonIds.includes(r.id) && + state.activity.activityType.personsVisible !== 0) || + (r.type === "thirdparty" && + !existingThirdPartyIds.includes(r.id) && + state.activity.activityType.thirdPartiesVisible !== 0) + ); + }, }, - removePersonInvolved(state, payload) { - //console.log('### mutation removePersonInvolved', payload.type); - switch (payload.type) { - case 'person': - state.activity.persons = state.activity.persons.filter(person => person !== payload); - break; - case 'thirdparty': - state.activity.thirdParties = state.activity.thirdParties.filter(thirdparty => thirdparty !== payload); - break; - case 'user': - state.activity.users = state.activity.users.filter(user => user !== payload); - break; - }; + mutations: { + // SocialIssueAcc + addIssueInList(state, issue) { + //console.log('add issue list', issue.id); + state.activity.accompanyingPeriod.socialIssues.push(issue); + }, + addIssueSelected(state, issue) { + //console.log('add issue selected', issue.id); + state.activity.socialIssues.push(issue); + }, + updateIssuesSelected(state, issues) { + //console.log('update issues selected', issues); + state.activity.socialIssues = issues; + }, + updateIssuesOther(state, payload) { + //console.log('update issues other'); + state.socialIssuesOther = payload; + }, + removeIssueInOther(state, issue) { + //console.log('remove issue other', issue.id); + state.socialIssuesOther = state.socialIssuesOther.filter( + (i) => i.id !== issue.id + ); + }, + resetActionsList(state) { + //console.log('reset list actions'); + state.socialActionsList = []; + }, + addActionInList(state, action) { + //console.log('add action list', action.id); + state.socialActionsList.push(action); + }, + updateActionsSelected(state, actions) { + //console.log('update actions selected', actions); + state.activity.socialActions = actions; + }, + filterList(state, list) { + const filterList = (list) => { + // remove duplicates entries + list = list.filter( + (value, index) => + list.findIndex((array) => array.id === value.id) === + index + ); + // alpha sort + list.sort((a, b) => + a.text > b.text ? 1 : b.text > a.text ? -1 : 0 + ); + return list; + }; + if (list === "issues") { + state.activity.accompanyingPeriod.socialIssues = filterList( + state.activity.accompanyingPeriod.socialIssues + ); + } + if (list === "actions") { + state.socialActionsList = filterList(state.socialActionsList); + } + }, + + // ConcernedGroups + addPersonsInvolved(state, payload) { + console.log("### mutation addPersonsInvolved", payload); + switch (payload.result.type) { + case "person": + state.activity.persons.push(payload.result); + break; + case "thirdparty": + state.activity.thirdParties.push(payload.result); + break; + case "user": + state.activity.users.push(payload.result); + break; + } + }, + removePersonInvolved(state, payload) { + //console.log('### mutation removePersonInvolved', payload.type); + switch (payload.type) { + case "person": + state.activity.persons = state.activity.persons.filter( + (person) => person !== payload + ); + break; + case "thirdparty": + state.activity.thirdParties = + state.activity.thirdParties.filter( + (thirdparty) => thirdparty !== payload + ); + break; + case "user": + state.activity.users = state.activity.users.filter( + (user) => user !== payload + ); + break; + } + }, + updateLocation(state, value) { + console.log("### mutation: updateLocation", value); + state.activity.location = value; + }, }, - updateLocation(state, value) { - console.log('### mutation: updateLocation', value); - state.activity.location = value; - } - }, - actions: { - addIssueSelected({ commit }, issue) { - let aSocialIssues = document.getElementById("chill_activitybundle_activity_socialIssues"); - aSocialIssues.value = addIdToValue(aSocialIssues.value, issue.id); - commit('addIssueSelected', issue); + actions: { + addIssueSelected({ commit }, issue) { + let aSocialIssues = document.getElementById( + "chill_activitybundle_activity_socialIssues" + ); + aSocialIssues.value = addIdToValue(aSocialIssues.value, issue.id); + commit("addIssueSelected", issue); + }, + updateIssuesSelected({ commit }, payload) { + let aSocialIssues = document.getElementById( + "chill_activitybundle_activity_socialIssues" + ); + aSocialIssues.value = ""; + payload.forEach((item) => { + aSocialIssues.value = addIdToValue( + aSocialIssues.value, + item.id + ); + }); + commit("updateIssuesSelected", payload); + }, + updateActionsSelected({ commit }, payload) { + let aSocialActions = document.getElementById( + "chill_activitybundle_activity_socialActions" + ); + aSocialActions.value = ""; + payload.forEach((item) => { + aSocialActions.value = addIdToValue( + aSocialActions.value, + item.id + ); + }); + commit("updateActionsSelected", payload); + }, + addPersonsInvolved({ commit }, payload) { + //console.log('### action addPersonsInvolved', payload.result.type); + switch (payload.result.type) { + case "person": + let aPersons = document.getElementById( + "chill_activitybundle_activity_persons" + ); + aPersons.value = addIdToValue( + aPersons.value, + payload.result.id + ); + break; + case "thirdparty": + let aThirdParties = document.getElementById( + "chill_activitybundle_activity_thirdParties" + ); + aThirdParties.value = addIdToValue( + aThirdParties.value, + payload.result.id + ); + break; + case "user": + let aUsers = document.getElementById( + "chill_activitybundle_activity_users" + ); + aUsers.value = addIdToValue( + aUsers.value, + payload.result.id + ); + break; + } + commit("addPersonsInvolved", payload); + }, + removePersonInvolved({ commit }, payload) { + //console.log('### action removePersonInvolved', payload); + switch (payload.type) { + case "person": + let aPersons = document.getElementById( + "chill_activitybundle_activity_persons" + ); + aPersons.value = removeIdFromValue( + aPersons.value, + payload.id + ); + break; + case "thirdparty": + let aThirdParties = document.getElementById( + "chill_activitybundle_activity_thirdParties" + ); + aThirdParties.value = removeIdFromValue( + aThirdParties.value, + payload.id + ); + break; + case "user": + let aUsers = document.getElementById( + "chill_activitybundle_activity_users" + ); + aUsers.value = removeIdFromValue(aUsers.value, payload.id); + break; + } + commit("removePersonInvolved", payload); + }, + updateLocation({ commit }, value) { + console.log("### action: updateLocation", value); + let hiddenLocation = document.getElementById( + "chill_activitybundle_activity_location" + ); + hiddenLocation.value = value.id; + commit("updateLocation", value); + }, }, - updateIssuesSelected({ commit }, payload) { - let aSocialIssues = document.getElementById("chill_activitybundle_activity_socialIssues"); - aSocialIssues.value = ''; - payload.forEach(item => { - aSocialIssues.value = addIdToValue(aSocialIssues.value, item.id); - }); - commit('updateIssuesSelected', payload); - }, - updateActionsSelected({ commit }, payload) { - let aSocialActions = document.getElementById("chill_activitybundle_activity_socialActions"); - aSocialActions.value = ''; - payload.forEach(item => { - aSocialActions.value = addIdToValue(aSocialActions.value, item.id); - }); - commit('updateActionsSelected', payload); - }, - addPersonsInvolved({ commit }, payload) { - //console.log('### action addPersonsInvolved', payload.result.type); - switch (payload.result.type) { - case 'person': - let aPersons = document.getElementById("chill_activitybundle_activity_persons"); - aPersons.value = addIdToValue(aPersons.value, payload.result.id); - break; - case 'thirdparty': - let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties"); - aThirdParties.value = addIdToValue(aThirdParties.value, payload.result.id); - break; - case 'user': - let aUsers = document.getElementById("chill_activitybundle_activity_users"); - aUsers.value = addIdToValue(aUsers.value, payload.result.id); - break; - }; - commit('addPersonsInvolved', payload); - }, - removePersonInvolved({ commit }, payload) { - //console.log('### action removePersonInvolved', payload); - switch (payload.type) { - case 'person': - let aPersons = document.getElementById("chill_activitybundle_activity_persons"); - aPersons.value = removeIdFromValue(aPersons.value, payload.id); - break; - case 'thirdparty': - let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties"); - aThirdParties.value = removeIdFromValue(aThirdParties.value, payload.id); - break; - case 'user': - let aUsers = document.getElementById("chill_activitybundle_activity_users"); - aUsers.value = removeIdFromValue(aUsers.value, payload.id); - break; - }; - commit('removePersonInvolved', payload); - }, - updateLocation({ commit }, value) { - console.log('### action: updateLocation', value); - let hiddenLocation = document.getElementById("chill_activitybundle_activity_location"); - hiddenLocation.value = value.id; - commit('updateLocation', value); - } - } }); export default store; 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..7f60a5a15 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/Resources/views/Activity/concernedGroups.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/concernedGroups.html.twig index 9e36f14f6..39c993dd3 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/concernedGroups.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/concernedGroups.html.twig @@ -12,12 +12,11 @@ }, { 'title': 'Third parties'|trans, 'items': entity.thirdParties, - 'path' : 'chill_3party_3party_show', - 'key' : 'thirdparty_id' + 'path' : 'chill_crud_3party_3party_view', + 'key' : 'id' }, { 'title': 'Users concerned'|trans, 'items': entity.users, - 'path' : 'admin_user_show', 'key' : 'id' }, ] %} @@ -35,8 +34,8 @@ }, { 'title': 'Third parties'|trans, 'items': entity.thirdParties, - 'path' : 'chill_3party_3party_show', - 'key' : 'thirdparty_id' + 'path' : 'chill_crud_3party_3party_view', + 'key' : 'id' }, { 'title': 'Users concerned'|trans, 'items': entity.users, diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig index 07e5d7a59..e043b4d53 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig @@ -34,16 +34,18 @@ {{ form_row(edit_form.reasons) }} {% endif %} -

    {{ 'Concerned groups'|trans }}

    +{%- if edit_form.persons is defined or edit_form.thirdParties is defined or edit_form.users is defined -%} +

    {{ 'Concerned groups'|trans }}

    -{%- if edit_form.persons is defined -%} - {{ form_widget(edit_form.persons) }} -{% endif %} -{%- if edit_form.thirdParties is defined -%} - {{ form_widget(edit_form.thirdParties) }} -{% endif %} -{%- if edit_form.users is defined -%} - {{ form_widget(edit_form.users) }} + {%- if edit_form.persons is defined -%} + {{ form_widget(edit_form.persons) }} + {% endif %} + {%- if edit_form.thirdParties is defined -%} + {{ form_widget(edit_form.thirdParties) }} + {% endif %} + {%- if edit_form.users is defined -%} + {{ form_widget(edit_form.users) }} + {% endif %} {% endif %}
    diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig index d1f9ec517..c5de72308 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig @@ -20,12 +20,14 @@ {% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'accompanyingCourse'} %} + {% if is_granted('CHILL_ACTIVITY_CREATE', accompanyingCourse) %} + {% endif %} {% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig index 101ad5502..d8f02a37d 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig @@ -22,6 +22,7 @@ '{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}'); }); window.activity = {{ activity_json|json_encode|raw }}; + window.default_location_id = {{ default_location_id }}; {{ encore_entry_script_tags('vue_activity') }} {% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php index 93d8117a9..7c850c67d 100644 --- a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php +++ b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php @@ -1,69 +1,54 @@ +/** + * 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; +use function in_array; -/** - * - * - * @author Julien Fastré - */ 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() + public function getRoles(): array { - return array(self::STATS, self::LISTS); + return $this->getAttributes(); + } + + public function getRolesWithHierarchy(): array + { + return ['Activity' => $this->getRoles()]; + } + + public function getRolesWithoutScope(): array + { + return $this->getAttributes(); } 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; + return [Center::class]; } protected function isGranted($attribute, $object, $user = null) @@ -71,22 +56,22 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar if (!$user instanceof \Symfony\Component\Security\Core\User\UserInterface) { return false; } - + return $this->helper->userHasAccess($user, $object, $attribute); } - public function getRoles() + protected function supports($attribute, $subject) { - return $this->getAttributes(); + if ($subject instanceof Center + && in_array($attribute, $this->getAttributes())) { + return true; + } + + return false; } - public function getRolesWithoutScope() + private function getAttributes() { - return $this->getAttributes(); - } - - public function getRolesWithHierarchy() - { - return [ 'Activity' => $this->getRoles() ]; + return [self::STATS, self::LISTS]; } } diff --git a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php index cc9cecf52..30e8f2c06 100644 --- a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php +++ b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php @@ -1,51 +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. */ +declare(strict_types=1); + namespace Chill\ActivityBundle\Security\Authorization; +use Chill\ActivityBundle\Entity\Activity; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface; use Chill\MainBundle\Security\Authorization\VoterHelperInterface; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Chill\PersonBundle\Security\Authorization\PersonVoter; +use RuntimeException; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - -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\Role\Role; use Symfony\Component\Security\Core\Security; +use function in_array; -/** - * Voter for Activity class - */ 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'; - const FULL = 'CHILL_ACTIVITY_FULL'; + /** + * allow to create an activity, which will either be associated to an + * accompanying course or person. + * + * It is safe for usage in template and controller + */ + public const CREATE = 'CHILL_ACTIVITY_CREATE'; + + /** + * role to allow to create an activity associated win an accompanying course. + * + * Before using this, check if @see{self::CREATE} is not sufficiant + * + * @internal + */ + public const CREATE_ACCOMPANYING_COURSE = 'CHILL_ACTIVITY_CREATE_ACCOMPANYING_COURSE'; + + /** + * role to allow to create an activity associated with a person. + * + * Before using this, check if @see{self::CREATE} is not sufficiant + * + * @internal + */ + public const CREATE_PERSON = 'CHILL_ACTIVITY_CREATE_PERSON'; + + public const DELETE = 'CHILL_ACTIVITY_DELETE'; + + public const FULL = 'CHILL_ACTIVITY_FULL'; + + public const SEE = 'CHILL_ACTIVITY_SEE'; + + public const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS'; + + public const UPDATE = 'CHILL_ACTIVITY_UPDATE'; private const ALL = [ self::CREATE, @@ -53,13 +70,13 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn self::UPDATE, self::DELETE, self::SEE_DETAILS, - self::FULL + self::FULL, ]; - protected VoterHelperInterface $voterHelper; - protected Security $security; + protected VoterHelperInterface $voterHelper; + public function __construct( Security $security, VoterHelperFactoryInterface $voterHelperFactory @@ -72,13 +89,33 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn ->build(); } + public function getRoles(): array + { + return [ + self::CREATE_PERSON, + self::CREATE_ACCOMPANYING_COURSE, + self::UPDATE, + self::DELETE, + self::FULL, + ]; + } - protected function supports($attribute, $subject) + public function getRolesWithHierarchy(): array + { + return ['Activity' => $this->getRoles()]; + } + + public function getRolesWithoutScope(): array + { + return []; + } + + protected function supports($attribute, $subject): bool { return $this->voterHelper->supports($attribute, $subject); } - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool { if (!$token->getUser() instanceof User) { return false; @@ -90,33 +127,43 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn if (!$this->security->isGranted(PersonVoter::SEE, $subject->getPerson())) { return false; } + + // change attribute CREATE + if (self::CREATE === $attribute) { + $attribute = self::CREATE_PERSON; + } } elseif ($subject->getAccompanyingPeriod() instanceof AccompanyingPeriod) { if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getAccompanyingPeriod())) { return false; } + + if (self::CREATE === $attribute) { + if (AccompanyingPeriod::STEP_CLOSED === $subject->getAccompanyingPeriod()->getStep()) { + return false; + } + $attribute = self::CREATE_ACCOMPANYING_COURSE; + } } else { - throw new \RuntimeException("could not determine context of activity"); + throw new RuntimeException('Could not determine context of activity.'); + } + } elseif ($subject instanceof AccompanyingPeriod) { + if (AccompanyingPeriod::STEP_CLOSED === $subject->getStep()) { + if (in_array($attribute, [self::UPDATE, self::CREATE, self::DELETE], true)) { + return false; + } + } + + // transform the attribute + if (self::CREATE === $attribute) { + $attribute = self::CREATE_ACCOMPANYING_COURSE; + } + } elseif ($subject instanceof Person) { + // transform the attribute + if (self::CREATE === $attribute) { + $attribute = self::CREATE_PERSON; } } return $this->voterHelper->voteOnAttribute($attribute, $subject, $token); } - - - public function getRoles() - { - return self::ALL; - } - - public function getRolesWithoutScope() - { - return []; - } - - - 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 6e2f6c897..f095e13e5 100644 --- a/src/Bundle/ChillActivityBundle/Templating/Entity/ActivityReasonRender.php +++ b/src/Bundle/ChillActivityBundle/Templating/Entity/ActivityReasonRender.php @@ -1,37 +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\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; @@ -41,34 +28,29 @@ class ActivityReasonRender extends AbstractChillEntityRender $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 { @@ -76,7 +58,8 @@ class ActivityReasonRender extends AbstractChillEntityRender if (null !== $entity->getCategory()) { $category = $this->translatableStringHelper->localize( - $entity->getCategory()->getName()). ' > '; + $entity->getCategory()->getName() + ) . ' > '; } return $category . 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 041978421..c0dab8abd 100644 --- a/src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php +++ b/src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php @@ -1,33 +1,45 @@ helper = $helper; $this->aclAwareRepository = $aclAwareRepository; - if (!$storage->getToken()->getUser() instanceof User) - { - throw new \RuntimeException('A user should be authenticated !'); + if (!$storage->getToken()->getUser() instanceof User) { + throw new RuntimeException('A user should be authenticated !'); } $this->user = $storage->getToken()->getUser(); } - /** - * - * {@inheritDoc} - */ public function fetchQuery($context, array $args) { if ('center' === $context) { @@ -59,80 +66,28 @@ class TimelineActivityProvider implements TimelineProviderInterface $metadataActivity = $this->em->getClassMetadata(Activity::class); - [$where, $parameters] = $this->getWhereClauseForPerson($args['person']); + [$where, $parameters] = $this->getWhereClauseForPerson($args['person']); return TimelineSingleQuery::fromArray([ - 'id' => $metadataActivity->getTableName() - .'.'.$metadataActivity->getColumnName('id'), - 'type' => 'activity', - 'date' => $metadataActivity->getTableName() - .'.'.$metadataActivity->getColumnName('date'), - 'FROM' => $this->getFromClausePerson(), - 'WHERE' => $where, - 'parameters' => $parameters - ]); - } - - private function getWhereClauseForPerson(Person $person) - { - $parameters = []; - $metadataActivity = $this->em->getClassMetadata(Activity::class); - $associationMapping = $metadataActivity->getAssociationMapping('person'); - $role = new Role('CHILL_ACTIVITY_SEE'); - $reachableScopes = $this->helper->getReachableScopes($this->user, $role->getRole(), $person->getCenter()); - $whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) '); - $scopes_ids = []; - - // first parameter: activity.person_id - $parameters[] = $person->getId(); - - // loop on reachable scopes - foreach ($reachableScopes as $scope) { - if (\in_array($scope->getId(), $scopes_ids)) { - continue; - } - $scopes_ids[] = '?'; - $parameters[] = $scope->getId(); - } - - return [ - \strtr( - $whereClause, - [ - '{activity.person_id}' => $associationMapping['joinColumns'][0]['name'], - '{activity.scope_id}' => $metadataActivity->getTableName().'.'. - $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], - '{scopes_ids}' => \implode(", ", $scopes_ids) -, - ] - ), - $parameters - ]; - } - - private function getFromClausePerson(): string - { - $metadataActivity = $this->em->getClassMetadata(Activity::class); - $metadataPerson = $this->em->getClassMetadata(Person::class); - $associationMapping = $metadataActivity->getAssociationMapping('person'); - - return sprintf( - "%s JOIN %s ON %s.%s = %s", - $metadataActivity->getTableName(), - $metadataPerson->getTableName(), - $metadataPerson->getTableName(), - $associationMapping['joinColumns'][0]['referencedColumnName'], - $associationMapping['joinColumns'][0]['name'] - ); + 'id' => $metadataActivity->getTableName() + . '.' . $metadataActivity->getColumnName('id'), + 'type' => 'activity', + 'date' => $metadataActivity->getTableName() + . '.' . $metadataActivity->getColumnName('date'), + 'FROM' => $this->getFromClausePerson(), + 'WHERE' => $where, + 'parameters' => $parameters, + ]); } public function getEntities(array $ids): array { $activities = $this->em->getRepository(Activity::class) - ->findBy(array('id' => $ids)); + ->findBy(['id' => $ids]); - $result = array(); - foreach($activities as $activity) { + $result = []; + + foreach ($activities as $activity) { $result[$activity->getId()] = $activity; } @@ -144,28 +99,28 @@ class TimelineActivityProvider implements TimelineProviderInterface $this->checkContext($context); return [ - 'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', - 'template_data' => [ - 'activity' => $entity, - 'context' => $context - ] + 'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', + 'template_data' => [ + 'activity' => $entity, + 'context' => $context, + ], ]; } public function supportsType($type): bool { - return $type === 'activity'; + return 'activity' === $type; } /** * Check if the context is supported. * - * @throws \LogicException if the context is not supported + * @throws LogicException if the context is not supported */ private function checkContext(string $context) { - if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) { - throw new \LogicException( + if (false === in_array($context, self::SUPPORTED_CONTEXTS)) { + throw new LogicException( sprintf( "The context '%s' is not supported. Currently only 'person' is supported", $context @@ -174,4 +129,55 @@ class TimelineActivityProvider implements TimelineProviderInterface } } + private function getFromClausePerson(): string + { + $metadataActivity = $this->em->getClassMetadata(Activity::class); + $metadataPerson = $this->em->getClassMetadata(Person::class); + $associationMapping = $metadataActivity->getAssociationMapping('person'); + + return sprintf( + '%s JOIN %s ON %s.%s = %s', + $metadataActivity->getTableName(), + $metadataPerson->getTableName(), + $metadataPerson->getTableName(), + $associationMapping['joinColumns'][0]['referencedColumnName'], + $associationMapping['joinColumns'][0]['name'] + ); + } + + private function getWhereClauseForPerson(Person $person) + { + $parameters = []; + $metadataActivity = $this->em->getClassMetadata(Activity::class); + $associationMapping = $metadataActivity->getAssociationMapping('person'); + $role = new Role('CHILL_ACTIVITY_SEE'); + $reachableScopes = $this->helper->getReachableScopes($this->user, $role->getRole(), $person->getCenter()); + $whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) '); + $scopes_ids = []; + + // first parameter: activity.person_id + $parameters[] = $person->getId(); + + // loop on reachable scopes + foreach ($reachableScopes as $scope) { + if (in_array($scope->getId(), $scopes_ids)) { + continue; + } + $scopes_ids[] = '?'; + $parameters[] = $scope->getId(); + } + + return [ + strtr( + $whereClause, + [ + '{activity.person_id}' => $associationMapping['joinColumns'][0]['name'], + '{activity.scope_id}' => $metadataActivity->getTableName() . '.' . + $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], + '{scopes_ids}' => implode(', ', $scopes_ids), + ] + ), + $parameters, + ]; + } } 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 5adf42e23..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/ChillActivityBundle/migrations/Version20210401090853.php b/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php index 283a4f077..cc75b418b 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php @@ -1,5 +1,12 @@ addSql('CREATE SEQUENCE activitytypecategory_id_seq INCREMENT BY 1 MINVALUE 1 START 1000'); - $this->addSql('CREATE TABLE activitytypecategory (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); - $this->addSql('INSERT INTO activitytypecategory VALUES(1, \'{"fr": "Défaut", "en": "Default"}\', true)'); - - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs $this->addSql('DROP SEQUENCE activitytypecategory_id_seq CASCADE'); $this->addSql('DROP TABLE activitytypecategory'); } + + 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('CREATE SEQUENCE activitytypecategory_id_seq INCREMENT BY 1 MINVALUE 1 START 1000'); + $this->addSql('CREATE TABLE activitytypecategory (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('INSERT INTO activitytypecategory VALUES(1, \'{"fr": "Défaut", "en": "Default"}\', true)'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php b/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php index c5f3f7d8d..8a32123e1 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activitytype ADD personVisible SMALLINT DEFAULT 2 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD personLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD userVisible SMALLINT DEFAULT 2 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD userLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD dateVisible SMALLINT DEFAULT 2 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD dateLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD placeVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD placeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD personsVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD personsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD thirdpartyVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD thirdpartyLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD durationTimeVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD durationTimeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD attendeeVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD attendeeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD reasonsVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD reasonsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD commentVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD commentLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD sentReceivedVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD sentReceivedLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD documentVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD documentLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD emergencyVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD emergencyLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD accompanyingPeriodVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD accompanyingPeriodLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD socialDataVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD socialDataLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ALTER name SET NOT NULL'); - $this->addSql('ALTER TABLE activitytype ALTER active DROP DEFAULT'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE activitytype DROP personVisible'); $this->addSql('ALTER TABLE activitytype DROP personLabel'); @@ -89,4 +55,45 @@ final class Version20210408122329 extends AbstractMigration $this->addSql('ALTER TABLE activitytype ALTER active SET DEFAULT \'true\''); $this->addSql('COMMENT ON COLUMN activitytype.name IS NULL'); } + + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE activitytype ADD personVisible SMALLINT DEFAULT 2 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD personLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD userVisible SMALLINT DEFAULT 2 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD userLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD dateVisible SMALLINT DEFAULT 2 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD dateLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD placeVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD placeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD personsVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD personsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD thirdpartyVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD thirdpartyLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD durationTimeVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD durationTimeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD attendeeVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD attendeeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD reasonsVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD reasonsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD commentVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD commentLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD sentReceivedVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD sentReceivedLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD emergencyVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD emergencyLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD accompanyingPeriodVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD accompanyingPeriodLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD socialDataVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD socialDataLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ALTER name SET NOT NULL'); + $this->addSql('ALTER TABLE activitytype ALTER active DROP DEFAULT'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210415113216.php b/src/Bundle/ChillActivityBundle/migrations/Version20210415113216.php index 6cf9c2923..f406d8ad1 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210415113216.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210415113216.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activitytype ADD thirdPartiesVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD thirdPartiesLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD documentsVisible SMALLINT DEFAULT 1 NOT NULL'); - $this->addSql('ALTER TABLE activitytype ADD documentsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); - $this->addSql('ALTER TABLE activitytype DROP thirdpartyvisible'); - $this->addSql('ALTER TABLE activitytype DROP thirdpartylabel'); - $this->addSql('ALTER TABLE activitytype DROP documentvisible'); - $this->addSql('ALTER TABLE activitytype DROP documentlabel'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE activitytype ADD thirdpartyvisible SMALLINT DEFAULT 1 NOT NULL'); $this->addSql('ALTER TABLE activitytype ADD thirdpartylabel VARCHAR(255) DEFAULT \'\' NOT NULL'); @@ -40,4 +30,21 @@ final class Version20210415113216 extends AbstractMigration $this->addSql('ALTER TABLE activitytype DROP documentsVisible'); $this->addSql('ALTER TABLE activitytype DROP documentsLabel'); } + + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE activitytype ADD thirdPartiesVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD thirdPartiesLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentsVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype DROP thirdpartyvisible'); + $this->addSql('ALTER TABLE activitytype DROP thirdpartylabel'); + $this->addSql('ALTER TABLE activitytype DROP documentvisible'); + $this->addSql('ALTER TABLE activitytype DROP documentlabel'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210422073711.php b/src/Bundle/ChillActivityBundle/migrations/Version20210422073711.php index 8d5dcfa84..dfb3a9cc7 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210422073711.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210422073711.php @@ -1,5 +1,12 @@ addSql('CREATE SEQUENCE activitytpresence_id_seq INCREMENT BY 1 MINVALUE 1 START 6'); - $this->addSql('CREATE TABLE activitytpresence (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); - - $list = [ - 'Usager pésent', "Absence de l''usager", - "Refus de visite ou d''entretien", 'Domicile non trouvé', - 'Domicile erronéee' - ]; - for ($i = 1; $i <= count($list); $i++) { - $this->addSql("INSERT INTO activitytpresence VALUES(".$i.", json_build_object('fr', '".$list[$i-1]."'), true)"); - } - - $this->addSql('ALTER TABLE activity ADD emergency BOOLEAN NOT NULL DEFAULT false'); - $this->addSql('ALTER TABLE activity ADD sentReceived VARCHAR(255) NOT NULL DEFAULT \'\' '); - $this->addSql('ALTER TABLE activity ALTER attendee TYPE INT USING CASE WHEN attendee is false THEN 2 WHEN attendee is true THEN 1 ELSE null END'); - $this->addSql('ALTER TABLE activity RENAME COLUMN attendee TO attendee_id'); - $this->addSql('ALTER TABLE activity ADD CONSTRAINT FK_AC74095ABCFD782A FOREIGN KEY (attendee_id) REFERENCES activitytpresence (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE activity DROP emergency'); $this->addSql('ALTER TABLE activity DROP CONSTRAINT FK_AC74095ABCFD782A'); @@ -49,4 +30,31 @@ final class Version20210422073711 extends AbstractMigration $this->addSql('DROP SEQUENCE activitytpresence_id_seq CASCADE'); $this->addSql('DROP TABLE activitytpresence'); } + + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE SEQUENCE activitytpresence_id_seq INCREMENT BY 1 MINVALUE 1 START 6'); + $this->addSql('CREATE TABLE activitytpresence (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); + + $list = [ + 'Usager pésent', "Absence de l''usager", + "Refus de visite ou d''entretien", 'Domicile non trouvé', + 'Domicile erronéee', + ]; + + for ($i = 1; count($list) >= $i; ++$i) { + $this->addSql('INSERT INTO activitytpresence VALUES(' . $i . ", json_build_object('fr', '" . $list[$i - 1] . "'), true)"); + } + + $this->addSql('ALTER TABLE activity ADD emergency BOOLEAN NOT NULL DEFAULT false'); + $this->addSql('ALTER TABLE activity ADD sentReceived VARCHAR(255) NOT NULL DEFAULT \'\' '); + $this->addSql('ALTER TABLE activity ALTER attendee TYPE INT USING CASE WHEN attendee is false THEN 2 WHEN attendee is true THEN 1 ELSE null END'); + $this->addSql('ALTER TABLE activity RENAME COLUMN attendee TO attendee_id'); + $this->addSql('ALTER TABLE activity ADD CONSTRAINT FK_AC74095ABCFD782A FOREIGN KEY (attendee_id) REFERENCES activitytpresence (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210422123846.php b/src/Bundle/ChillActivityBundle/migrations/Version20210422123846.php index 0fde71257..577d09c5e 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210422123846.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210422123846.php @@ -1,5 +1,12 @@ addSql('DROP TABLE activity_person'); + $this->addSql('DROP TABLE activity_thirdparty'); + $this->addSql('DROP TABLE activity_document'); + $this->addSql('DROP TABLE activity_user'); + + $this->addSql('ALTER TABLE activity DROP travelTime'); + + $this->addSql('ALTER TABLE activitytype DROP travelTimeVisible'); + $this->addSql('ALTER TABLE activitytype DROP travelTimeLabel'); + $this->addSql('ALTER TABLE activitytype DROP usersVisible'); + $this->addSql('ALTER TABLE activitytype DROP usersLabel'); + } + + public function getDescription(): string { return ''; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('CREATE TABLE activity_person (activity_id INT NOT NULL, person_id INT NOT NULL, PRIMARY KEY(activity_id, person_id))'); $this->addSql('CREATE INDEX IDX_66AA317681C06096 ON activity_person (activity_id)'); @@ -36,7 +58,7 @@ final class Version20210422123846 extends AbstractMigration $this->addSql('ALTER TABLE activity_thirdparty ADD CONSTRAINT FK_C6F0DE0381C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE activity_thirdparty ADD CONSTRAINT FK_C6F0DE03C7D3A8E6 FOREIGN KEY (thirdparty_id) REFERENCES chill_3party.third_party (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE activity_document ADD CONSTRAINT FK_78633A7881C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - #$this->addSql('ALTER TABLE activity_document ADD CONSTRAINT FK_78633A78C33F7837 FOREIGN KEY (document_id) REFERENCES Document (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + //$this->addSql('ALTER TABLE activity_document ADD CONSTRAINT FK_78633A78C33F7837 FOREIGN KEY (document_id) REFERENCES Document (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE activity_user ADD CONSTRAINT FK_8E570DDB81C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE activity_user ADD CONSTRAINT FK_8E570DDBA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); @@ -47,19 +69,4 @@ final class Version20210422123846 extends AbstractMigration $this->addSql('ALTER TABLE activitytype ADD usersVisible SMALLINT DEFAULT 1 NOT NULL'); $this->addSql('ALTER TABLE activitytype ADD usersLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); } - - public function down(Schema $schema) : void - { - $this->addSql('DROP TABLE activity_person'); - $this->addSql('DROP TABLE activity_thirdparty'); - $this->addSql('DROP TABLE activity_document'); - $this->addSql('DROP TABLE activity_user'); - - $this->addSql('ALTER TABLE activity DROP travelTime'); - - $this->addSql('ALTER TABLE activitytype DROP travelTimeVisible'); - $this->addSql('ALTER TABLE activitytype DROP travelTimeLabel'); - $this->addSql('ALTER TABLE activitytype DROP usersVisible'); - $this->addSql('ALTER TABLE activitytype DROP usersLabel'); - } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506071150.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506071150.php index 3a1a4e513..1b60bb219 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210506071150.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506071150.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activity ALTER durationTime SET NOT NULL'); + } + + 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('ALTER TABLE activity ALTER durationtime DROP NOT NULL'); } - - public function down(Schema $schema) : void - { - $this->addSql('ALTER TABLE activity ALTER durationTime SET NOT NULL'); - } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506090417.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506090417.php index b1e4e43fc..15f6a0158 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210506090417.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506090417.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activitytype ADD ordering DOUBLE PRECISION DEFAULT \'0.0\' NOT NULL'); - $this->addSql('ALTER TABLE activitytypecategory ADD ordering DOUBLE PRECISION DEFAULT \'0.0\' NOT NULL'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE activitytypecategory DROP ordering'); $this->addSql('ALTER TABLE activitytype DROP ordering'); } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE activitytype ADD ordering DOUBLE PRECISION DEFAULT \'0.0\' NOT NULL'); + $this->addSql('ALTER TABLE activitytypecategory ADD ordering DOUBLE PRECISION DEFAULT \'0.0\' NOT NULL'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506094520.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506094520.php index a31d23ae4..e29eb567a 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210506094520.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506094520.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activitytype DROP CONSTRAINT FK_B38CD05112469DE2'); + $this->addSql('ALTER TABLE activitytype DROP category_id'); + } + + public function getDescription(): string { return ''; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('ALTER TABLE activitytype ADD category_id INT DEFAULT 1'); $this->addSql('ALTER TABLE activitytype ADD CONSTRAINT FK_B38CD05112469DE2 FOREIGN KEY (category_id) REFERENCES activitytypecategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema) : void - { - $this->addSql('ALTER TABLE activitytype DROP CONSTRAINT FK_B38CD05112469DE2');; - $this->addSql('ALTER TABLE activitytype DROP category_id'); - } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506112500.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506112500.php index ca80d7720..2163a0b65 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210506112500.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506112500.php @@ -1,5 +1,12 @@ addSql('CREATE TABLE activity_storedobject (activity_id INT NOT NULL, storedobject_id INT NOT NULL, PRIMARY KEY(activity_id, storedobject_id))'); - $this->addSql('CREATE INDEX IDX_6F660E9381C06096 ON activity_storedobject (activity_id)'); - $this->addSql('CREATE INDEX IDX_6F660E93EE684399 ON activity_storedobject (storedobject_id)'); - $this->addSql('ALTER TABLE activity_storedobject ADD CONSTRAINT FK_6F660E9381C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE activity_storedobject ADD CONSTRAINT FK_6F660E93EE684399 FOREIGN KEY (storedobject_id) REFERENCES chill_doc.stored_object (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('DROP TABLE activity_document'); - - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs $this->addSql('CREATE SCHEMA public'); @@ -39,4 +29,20 @@ final class Version20210506112500 extends AbstractMigration $this->addSql('ALTER TABLE activity_document ADD CONSTRAINT fk_78633a7881c06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('DROP TABLE activity_storedobject'); } + + 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('CREATE TABLE activity_storedobject (activity_id INT NOT NULL, storedobject_id INT NOT NULL, PRIMARY KEY(activity_id, storedobject_id))'); + $this->addSql('CREATE INDEX IDX_6F660E9381C06096 ON activity_storedobject (activity_id)'); + $this->addSql('CREATE INDEX IDX_6F660E93EE684399 ON activity_storedobject (storedobject_id)'); + $this->addSql('ALTER TABLE activity_storedobject ADD CONSTRAINT FK_6F660E9381C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_storedobject ADD CONSTRAINT FK_6F660E93EE684399 FOREIGN KEY (storedobject_id) REFERENCES chill_doc.stored_object (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('DROP TABLE activity_document'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210520095626.php b/src/Bundle/ChillActivityBundle/migrations/Version20210520095626.php index f5a0abda6..1d6f42f6e 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210520095626.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210520095626.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activity DROP CONSTRAINT FK_AC74095AD7FA8EF0'); + $this->addSql('ALTER TABLE activity DROP accompanyingPeriod_id'); + } + public function getDescription(): string { return ''; @@ -22,10 +35,4 @@ final class Version20210520095626 extends AbstractMigration $this->addSql('ALTER TABLE activity ADD accompanyingPeriod_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE activity ADD CONSTRAINT FK_AC74095AD7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE activity DROP CONSTRAINT FK_AC74095AD7FA8EF0'); - $this->addSql('ALTER TABLE activity DROP accompanyingPeriod_id'); - } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210528161250.php b/src/Bundle/ChillActivityBundle/migrations/Version20210528161250.php index 8eaf7e1a4..1bc26298c 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210528161250.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210528161250.php @@ -1,5 +1,12 @@ addSql('DROP TABLE chill_activity_activity_chill_person_socialissue'); + $this->addSql('DROP TABLE chill_activity_activity_chill_person_socialaction'); + } + public function getDescription(): string { return 'Add socialIssues & socialActions fields to Activity'; @@ -30,10 +43,4 @@ final class Version20210528161250 extends AbstractMigration $this->addSql('ALTER TABLE chill_activity_activity_chill_person_socialaction ADD CONSTRAINT FK_548F1AD881C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_activity_activity_chill_person_socialaction ADD CONSTRAINT FK_548F1AD83DC32179 FOREIGN KEY (socialaction_id) REFERENCES chill_person_social_action (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP TABLE chill_activity_activity_chill_person_socialissue'); - $this->addSql('DROP TABLE chill_activity_activity_chill_person_socialaction'); - } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210602103243.php b/src/Bundle/ChillActivityBundle/migrations/Version20210602103243.php index 4c773c161..3122df777 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210602103243.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210602103243.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activitytype DROP socialIssuesVisible'); + $this->addSql('ALTER TABLE activitytype DROP socialIssuesLabel'); + $this->addSql('ALTER TABLE activitytype DROP socialActionsVisible'); + $this->addSql('ALTER TABLE activitytype DROP socialActionsLabel'); + } + public function getDescription(): string { return 'Add info for socialIssues & socialActions in ActivityType'; @@ -24,12 +39,4 @@ final class Version20210602103243 extends AbstractMigration $this->addSql('ALTER TABLE activitytype ADD socialActionsVisible SMALLINT DEFAULT 1 NOT NULL'); $this->addSql('ALTER TABLE activitytype ADD socialActionsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE activitytype DROP socialIssuesVisible'); - $this->addSql('ALTER TABLE activitytype DROP socialIssuesLabel'); - $this->addSql('ALTER TABLE activitytype DROP socialActionsVisible'); - $this->addSql('ALTER TABLE activitytype DROP socialActionsLabel'); - } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20211119173555.php b/src/Bundle/ChillActivityBundle/migrations/Version20211119173555.php index d39613455..66095af3d 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20211119173555.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20211119173555.php @@ -1,5 +1,12 @@ throwIrreversibleMigrationException(); + } + public function getDescription(): string { return 'remove comment on deprecated json_array type'; @@ -18,16 +30,11 @@ final class Version20211119173555 extends AbstractMigration { $columns = [ 'activitytype.name', - 'activitytypecategory.name' + 'activitytypecategory.name', ]; foreach ($columns as $col) { - $this->addSql("COMMENT ON COLUMN $col IS NULL"); + $this->addSql("COMMENT ON COLUMN {$col} IS NULL"); } } - - public function down(Schema $schema): void - { - $this->throwIrreversibleMigrationException(); - } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/ChillAsideActivityBundle.php b/src/Bundle/ChillAsideActivityBundle/src/ChillAsideActivityBundle.php index c9640d370..c87610fae 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/ChillAsideActivityBundle.php +++ b/src/Bundle/ChillAsideActivityBundle/src/ChillAsideActivityBundle.php @@ -1,5 +1,12 @@ categoryRepository = $categoryRepository; } + public function createEntity(string $action, Request $request): object + { + $asideActivity = new AsideActivity(); + + $duration = $request->query->get('duration', '300'); + $duration = DateTime::createFromFormat('U', $duration); + $asideActivity->setDuration($duration); + + $categoryId = $request->query->get('type', 7); + + if (null === $categoryId) { + return $this->createNotFoundException('You must give a valid category id'); + } + $category = $this->categoryRepository->find($categoryId); + $asideActivity->setType($category); + + $note = $request->query->get('note', null); + $asideActivity->setNote($note); + + return $asideActivity; + } + protected function buildQueryEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null) { $qb = parent::buildQueryEntities($action, $request); @@ -42,30 +70,9 @@ final class AsideActivityController extends CRUDController PaginatorInterface $paginator ) { if ('index' === $action) { - return $query->orderBy('e.date', 'DESC'); + return $query->orderBy('e.date', 'DESC'); } return parent::orderQuery($action, $query, $request, $paginator); } - - public function createEntity(string $action, Request $request): object - { - $asideActivity = new AsideActivity(); - - $duration = $request->query->get('duration', '300'); - $duration = \DateTime::createFromFormat('U', $duration); - $asideActivity->setDuration($duration); - - $categoryId = $request->query->get('type', 7); - if($categoryId === null){ - return $this->createNotFoundException('You must give a valid category id'); - } - $category = $this->categoryRepository->find($categoryId); - $asideActivity->setType($category); - - $note = $request->query->get('note', null); - $asideActivity->setNote($note); - - return $asideActivity; - } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivity.php index 2764db282..05a498c46 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivity.php @@ -1,13 +1,23 @@ userRepository->findOneBy(['username' => 'center a_social']); - for ($i = 0; $i < 50; $i++) { + for ($i = 0; 50 > $i; ++$i) { $activity = new AsideActivity(); $activity ->setAgent($user) - ->setCreatedAt(new \DateTimeImmutable('now')) + ->setCreatedAt(new DateTimeImmutable('now')) ->setCreatedBy($user) - ->setUpdatedAt(new \DateTimeImmutable('now')) + ->setUpdatedAt(new DateTimeImmutable('now')) ->setUpdatedBy($user) ->setType( $this->getReference('aside_activity_category_0') ) - ->setDate((new \DateTimeImmutable('today')) - ->sub(new \DateInterval('P'.\random_int(1, 100).'D'))) - ; + ->setDate((new DateTimeImmutable('today')) + ->sub(new DateInterval('P' . random_int(1, 100) . 'D'))); $manager->persist($activity); } diff --git a/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivityCategory.php b/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivityCategory.php index 497b260ad..d09652640 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivityCategory.php +++ b/src/Bundle/ChillAsideActivityBundle/src/DataFixtures/ORM/LoadAsideActivityCategory.php @@ -1,5 +1,12 @@ $label) { + 'Formation', + ] as $key => $label) { $category = new AsideActivityCategory(); $category->setTitle(['fr' => $label]); $manager->persist($category); - $this->setReference('aside_activity_category_'.$key, $category); + $this->setReference('aside_activity_category_' . $key, $category); } $manager->flush(); diff --git a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php index 5a63c2e7a..f40f18aa9 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php +++ b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/ChillAsideActivityExtension.php @@ -1,6 +1,8 @@ getConfiguration($configs, $container); $config = $this->processConfiguration($configuration, $configs); $container->setParameter('chill_aside_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/form.yaml'); $loader->load('services/menu.yaml'); @@ -40,18 +38,6 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte $this->prependCruds($container); } - protected function prependRoute(ContainerBuilder $container) - { - //declare routes for task bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillAsideActivityBundle/config/routes.yaml', - ) - ) - )); - } - protected function prependCruds(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ @@ -65,17 +51,17 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte 'actions' => [ 'index' => [ 'template' => '@ChillAsideActivity/asideActivityCategory/index.html.twig', - 'role' => 'ROLE_ADMIN' + 'role' => 'ROLE_ADMIN', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillAsideActivity/asideActivityCategory/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillAsideActivity/asideActivityCategory/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\AsideActivityBundle\Entity\AsideActivity::class, @@ -86,9 +72,9 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte 'actions' => [ 'index' => [ 'template' => '@ChillAsideActivity/asideActivity/index.html.twig', - 'role' => 'ROLE_USER' + 'role' => 'ROLE_USER', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_USER', 'template' => '@ChillAsideActivity/asideActivity/new.html.twig', ], @@ -96,17 +82,29 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte 'role' => 'ROLE_USER', 'template' => '@ChillAsideActivity/asideActivity/view.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_USER', 'template' => '@ChillAsideActivity/asideActivity/edit.html.twig', ], 'delete' => [ 'role' => 'ROLE_USER', 'template' => '@ChillAsideActivity/asideActivity/delete.html.twig', - ] - ] + ], + ], ], - ] + ], + ]); + } + + protected function prependRoute(ContainerBuilder $container) + { + //declare routes for task bundle + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillAsideActivityBundle/config/routes.yaml', + ], + ], ]); } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/Configuration.php b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/Configuration.php index 7268b92ae..bcfc0b9a4 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillAsideActivityBundle/src/DependencyInjection/Configuration.php @@ -1,5 +1,12 @@ getRootNode('chill_aside_activity') ->children() - ->arrayNode('form') - ->canBeEnabled() - ->children() - ->arrayNode('time_duration') - ->isRequired() - ->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], - [ 'label' => '2 hours 30', 'seconds' => 9000], - [ 'label' => '3 hours', 'seconds' => 10800], - [ 'label' => '3 hours 30', 'seconds' => 12600], - [ 'label' => '4 hours', 'seconds' => 14400], - [ 'label' => '4 hours 30', 'seconds' => 16200], - [ 'label' => '5 hours', 'seconds' => 18000], - [ 'label' => '5 hours 30', 'seconds' => 19800], - [ 'label' => '6 hours', 'seconds' => 21600], - [ 'label' => '6 hours 30', 'seconds' => 23400], - [ 'label' => '7 hours', 'seconds' => 25200], - [ 'label' => '7 hours 30', 'seconds' => 27000], - [ 'label' => '8 hours', 'seconds' => 28800], - [ 'label' => '8 hours 30', 'seconds' => 30600], - [ 'label' => '9 hours', 'seconds' => 32400], - [ 'label' => '9 hours 30', 'seconds' => 34200], - [ 'label' => '10 hours', 'seconds' => 36000], - [ 'label' => '1/2 day', 'seconds' => 14040], - [ 'label' => '1 day', 'seconds' => 28080], - [ 'label' => '1 1/2 days', 'seconds' => 42120], - [ 'label' => '2 days', 'seconds' => 56160], - [ 'label' => '2 1/2 days', 'seconds' => 70200], - [ 'label' => '3 days', 'seconds' => 84240], - [ 'label' => '3 1/2 days', 'seconds' => 98280], - [ 'label' => '4 days', 'seconds' => 112320], - [ 'label' => '4 1/2 days', 'seconds' => 126360], - [ 'label' => '5 days', 'seconds' => 140400], - [ 'label' => '5 1/2 days', 'seconds' => 154440], - [ 'label' => '6 days', 'seconds' => 168480], - [ 'label' => '6 1/2 days', 'seconds' => 182520], - [ 'label' => '7 days', 'seconds' => 196560], - [ 'label' => '7 1/2 days', 'seconds' => 210600], - [ 'label' => '8 days', 'seconds' => 224640], - [ 'label' => '8 1/2 days', 'seconds' => 238680], - [ 'label' => '9 days', 'seconds' => 252720], - [ 'label' => '9 1/2 days', 'seconds' => 266760], - [ 'label' => '10 days', 'seconds' => 280800], - [ 'label' => '10 1/2days', 'seconds' => 294840], - [ 'label' => '11 days', 'seconds' => 308880], - [ 'label' => '11 1/2 days', 'seconds' => 322920], - [ 'label' => '12 days', 'seconds' => 336960], - [ 'label' => '12 1/2 days', 'seconds' => 351000], - [ 'label' => '13 days', 'seconds' => 365040], - [ 'label' => '13 1/2 days', 'seconds' => 379080], - [ 'label' => '14 days', 'seconds' => 393120], - [ 'label' => '14 1/2 days', 'seconds' => 407160], - [ 'label' => '15 days', 'seconds' => 421200], - [ 'label' => '15 1/2 days', 'seconds' => 435240], - [ 'label' => '16 days', 'seconds' => 449280], - [ 'label' => '16 1/2 days', 'seconds' => 463320], - [ 'label' => '17 days', 'seconds' => 477360], - [ 'label' => '17 1/2 days', 'seconds' => 491400], - [ 'label' => '18 days', 'seconds' => 505440], - [ 'label' => '18 1/2 days', 'seconds' => 519480], - [ 'label' => '19 days', 'seconds' => 533520], - [ 'label' => '19 1/2 days', 'seconds' => 547560], - [ 'label' => '20 days', 'seconds' => 561600], - [ 'label' => '20 1/2 days', 'seconds' => 575640], - [ 'label' => '21 days', 'seconds' => 580680], - [ 'label' => '21 1/2 days', 'seconds' => 603720], - [ 'label' => '22 days', 'seconds' => 617760], - [ 'label' => '22 1/2 days', 'seconds' => 631800], - [ 'label' => '23 days', 'seconds' => 645840], - [ 'label' => '23 1/2 days', 'seconds' => 659880], - [ 'label' => '24 days', 'seconds' => 673920], - [ 'label' => '24 1/2 days', 'seconds' => 687960], - [ 'label' => '25 days', 'seconds' => 702000], - [ 'label' => '25 1/2 days', 'seconds' => 716040], - [ 'label' => '26 days', 'seconds' => 730080], - [ 'label' => '26 1/2 days', 'seconds' => 744120], - [ 'label' => '27 days', 'seconds' => 758160], - [ 'label' => '27 1/2 days', 'seconds' => 772200], - [ 'label' => '28 days', 'seconds' => 786240], - [ 'label' => '28 1/2 days', 'seconds' => 800280], - [ 'label' => '29 days', 'seconds' => 814320], - [ 'label' => '29 1/2 days', 'seconds' => 828360], - [ 'label' => '30 days', 'seconds' => 842400], - ] - ) - ->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() - ->end() - ->end() + ->arrayNode('form') + ->canBeEnabled() + ->children() + ->arrayNode('time_duration') + ->isRequired() + ->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], + ['label' => '2 hours 30', 'seconds' => 9000], + ['label' => '3 hours', 'seconds' => 10800], + ['label' => '3 hours 30', 'seconds' => 12600], + ['label' => '4 hours', 'seconds' => 14400], + ['label' => '4 hours 30', 'seconds' => 16200], + ['label' => '5 hours', 'seconds' => 18000], + ['label' => '5 hours 30', 'seconds' => 19800], + ['label' => '6 hours', 'seconds' => 21600], + ['label' => '6 hours 30', 'seconds' => 23400], + ['label' => '7 hours', 'seconds' => 25200], + ['label' => '7 hours 30', 'seconds' => 27000], + ['label' => '8 hours', 'seconds' => 28800], + ['label' => '8 hours 30', 'seconds' => 30600], + ['label' => '9 hours', 'seconds' => 32400], + ['label' => '9 hours 30', 'seconds' => 34200], + ['label' => '10 hours', 'seconds' => 36000], + ['label' => '1/2 day', 'seconds' => 14040], + ['label' => '1 day', 'seconds' => 28080], + ['label' => '1 1/2 days', 'seconds' => 42120], + ['label' => '2 days', 'seconds' => 56160], + ['label' => '2 1/2 days', 'seconds' => 70200], + ['label' => '3 days', 'seconds' => 84240], + ['label' => '3 1/2 days', 'seconds' => 98280], + ['label' => '4 days', 'seconds' => 112320], + ['label' => '4 1/2 days', 'seconds' => 126360], + ['label' => '5 days', 'seconds' => 140400], + ['label' => '5 1/2 days', 'seconds' => 154440], + ['label' => '6 days', 'seconds' => 168480], + ['label' => '6 1/2 days', 'seconds' => 182520], + ['label' => '7 days', 'seconds' => 196560], + ['label' => '7 1/2 days', 'seconds' => 210600], + ['label' => '8 days', 'seconds' => 224640], + ['label' => '8 1/2 days', 'seconds' => 238680], + ['label' => '9 days', 'seconds' => 252720], + ['label' => '9 1/2 days', 'seconds' => 266760], + ['label' => '10 days', 'seconds' => 280800], + ['label' => '10 1/2days', 'seconds' => 294840], + ['label' => '11 days', 'seconds' => 308880], + ['label' => '11 1/2 days', 'seconds' => 322920], + ['label' => '12 days', 'seconds' => 336960], + ['label' => '12 1/2 days', 'seconds' => 351000], + ['label' => '13 days', 'seconds' => 365040], + ['label' => '13 1/2 days', 'seconds' => 379080], + ['label' => '14 days', 'seconds' => 393120], + ['label' => '14 1/2 days', 'seconds' => 407160], + ['label' => '15 days', 'seconds' => 421200], + ['label' => '15 1/2 days', 'seconds' => 435240], + ['label' => '16 days', 'seconds' => 449280], + ['label' => '16 1/2 days', 'seconds' => 463320], + ['label' => '17 days', 'seconds' => 477360], + ['label' => '17 1/2 days', 'seconds' => 491400], + ['label' => '18 days', 'seconds' => 505440], + ['label' => '18 1/2 days', 'seconds' => 519480], + ['label' => '19 days', 'seconds' => 533520], + ['label' => '19 1/2 days', 'seconds' => 547560], + ['label' => '20 days', 'seconds' => 561600], + ['label' => '20 1/2 days', 'seconds' => 575640], + ['label' => '21 days', 'seconds' => 580680], + ['label' => '21 1/2 days', 'seconds' => 603720], + ['label' => '22 days', 'seconds' => 617760], + ['label' => '22 1/2 days', 'seconds' => 631800], + ['label' => '23 days', 'seconds' => 645840], + ['label' => '23 1/2 days', 'seconds' => 659880], + ['label' => '24 days', 'seconds' => 673920], + ['label' => '24 1/2 days', 'seconds' => 687960], + ['label' => '25 days', 'seconds' => 702000], + ['label' => '25 1/2 days', 'seconds' => 716040], + ['label' => '26 days', 'seconds' => 730080], + ['label' => '26 1/2 days', 'seconds' => 744120], + ['label' => '27 days', 'seconds' => 758160], + ['label' => '27 1/2 days', 'seconds' => 772200], + ['label' => '28 days', 'seconds' => 786240], + ['label' => '28 1/2 days', 'seconds' => 800280], + ['label' => '29 days', 'seconds' => 814320], + ['label' => '29 1/2 days', 'seconds' => 828360], + ['label' => '30 days', 'seconds' => 842400], + ] + ) + ->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() + ->end() + ->end() ->end(); - return $treeBuilder; + return $treeBuilder; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivity.php b/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivity.php index af4baa6d3..fc0eca9cd 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivity.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivity.php @@ -1,5 +1,12 @@ id; + return $this->agent; } - public function getType(): ?AsideActivityCategory + public function getCreatedAt(): ?DateTimeInterface { - return $this->type; - } - - public function setType(?AsideActivityCategory $type): self - { - $this->type = $type; - - return $this; + return $this->createdAt; } public function getCreatedBy(): ?User @@ -98,23 +100,39 @@ class AsideActivity implements TrackUpdateInterface, TrackCreationInterface return $this->createdBy; } - public function setCreatedBy(?User $createdBy): self + public function getDate(): ?DateTimeInterface { - $this->createdBy = $createdBy; - - return $this; + return $this->date; } - public function getCreatedAt(): ?\DateTimeInterface + public function getDuration(): ?DateTimeInterface { - return $this->createdAt; + return $this->duration; } - public function setCreatedAt(\DateTimeInterface $createdAt): self + public function getId(): ?int { - $this->createdAt = $createdAt; + return $this->id; + } - return $this; + public function getLocation(): ?string + { + return $this->location; + } + + public function getNote(): ?string + { + return $this->note; + } + + public function getType(): ?AsideActivityCategory + { + return $this->type; + } + + public function getUpdatedAt(): ?DateTimeInterface + { + return $this->updatedAt; } public function getUpdatedBy(): ?User @@ -122,30 +140,6 @@ class AsideActivity implements TrackUpdateInterface, TrackCreationInterface return $this->updatedBy; } - public function setUpdatedBy(?User $updatedBy): self - { - $this->updatedBy = $updatedBy; - - return $this; - } - - public function getUpdatedAt(): ?\DateTimeInterface - { - return $this->updatedAt; - } - - public function setUpdatedAt(\DateTimeInterface $updatedAt): self - { - $this->updatedAt = $updatedAt; - - return $this; - } - - public function getAgent(): ?User - { - return $this->agent; - } - public function setAgent(?User $agent): self { $this->agent = $agent; @@ -153,35 +147,34 @@ class AsideActivity implements TrackUpdateInterface, TrackCreationInterface return $this; } - public function getDate(): ?\DateTimeInterface + public function setCreatedAt(DateTimeInterface $createdAt): self { - return $this->date; + $this->createdAt = $createdAt; + + return $this; } - public function setDate(\DateTimeInterface $date): self + public function setCreatedBy(?User $createdBy): self + { + $this->createdBy = $createdBy; + + return $this; + } + + public function setDate(DateTimeInterface $date): self { $this->date = $date; return $this; } - public function getDuration(): ?\DateTimeInterface - { - return $this->duration; - } - - public function setDuration(?\DateTimeInterface $duration): self + public function setDuration(?DateTimeInterface $duration): self { $this->duration = $duration; return $this; } - public function getLocation(): ?string - { - return $this->location; - } - public function setLocation(?string $location): self { $this->location = $location; @@ -189,15 +182,31 @@ class AsideActivity implements TrackUpdateInterface, TrackCreationInterface return $this; } - public function getNote(): ?string - { - return $this->note; - } - public function setNote(?string $note): self { $this->note = $note; return $this; } + + public function setType(?AsideActivityCategory $type): self + { + $this->type = $type; + + return $this; + } + + public function setUpdatedAt(DateTimeInterface $updatedAt): self + { + $this->updatedAt = $updatedAt; + + return $this; + } + + public function setUpdatedBy(?User $updatedBy): self + { + $this->updatedBy = $updatedBy; + + return $this; + } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php b/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php index 6c00274ad..8ef9664c7 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php @@ -1,5 +1,12 @@ children = new ArrayCollection(); } + public function addChild(self $child): self + { + if (!$this->children->contains($child)) { + $this->children[] = $child; + $child->setParent($this); + } + + return $this; + } + + /** + * @return Collection|self[] + */ + public function getChildren(): Collection + { + return $this->children; + } + 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 getIsActive(): bool { return $this->isActive; } - public function setIsActive(bool $isActive): self + public function getOrdering(): float { - $this->isActive = $isActive; - - return $this; + return $this->ordering; } public function getParent(): ?self @@ -92,9 +102,20 @@ class AsideActivityCategory return $this->parent; } + public function getTitle(): ?array + { + return $this->title; + } + + public function hasParent(): bool + { + return null !== $this->parent; + } + /** + * @Assert\Callback * - * @Assert\Callback() + * @param mixed $payload */ public function preventRecursiveParent(ExecutionContextInterface $context, $payload) { @@ -108,43 +129,10 @@ class AsideActivityCategory $this->parent = $this->oldParent; $context->buildViolation('You must not add twice the same category in the parent tree (previous result returned)') ->atPath('parent') - ->addViolation() - ; + ->addViolation(); } } - public function hasParent(): bool - { - return $this->parent !== null; - } - - public function setParent(?self $parent): self - { - // cache the old result for changing it during validaiton - $this->oldParent = $this->parent; - $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)) { - $this->children[] = $child; - $child->setParent($this); - } - - return $this; - } - public function removeChild(self $child): self { if ($this->children->removeElement($child)) { @@ -157,14 +145,33 @@ class AsideActivityCategory return $this; } - public function getOrdering(): float + public function setIsActive(bool $isActive): self { - return $this->ordering; + $this->isActive = $isActive; + + return $this; } public function setOrdering(float $ordering): AsideActivityCategory { $this->ordering = $ordering; + + return $this; + } + + public function setParent(?self $parent): self + { + // cache the old result for changing it during validaiton + $this->oldParent = $this->parent; + $this->parent = $parent; + + return $this; + } + + public function setTitle(array $title): self + { + $this->title = $title; + return $this; } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityCategoryType.php b/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityCategoryType.php index e438998b0..314dbe551 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityCategoryType.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityCategoryType.php @@ -1,5 +1,12 @@ add('title', TranslatableStringFormType::class, - [ - 'label' => 'Nom', - ]) - ->add('parent', EntityType::class, [ - 'class' => AsideActivityCategory::class, - 'required' => false, - 'label' => 'Parent', - 'choice_label' => function (AsideActivityCategory $category){ - $options = []; - return $this->categoryRender->renderString($category, $options); - } - ]) - ->add('ordering', NumberType::class) - ->add('isActive', ChoiceType::class, - [ - 'choices' => [ - 'Yes' => true, - 'No' => false - ], - 'expanded' => true - ]); + $builder->add( + 'title', + TranslatableStringFormType::class, + [ + 'label' => 'Nom', + ] + ) + ->add('parent', EntityType::class, [ + 'class' => AsideActivityCategory::class, + 'required' => false, + 'label' => 'Parent', + 'choice_label' => function (AsideActivityCategory $category) { + $options = []; + + return $this->categoryRender->renderString($category, $options); + }, + ]) + ->add('ordering', NumberType::class) + ->add( + 'isActive', + ChoiceType::class, + [ + 'choices' => [ + 'Yes' => true, + 'No' => false, + ], + 'expanded' => true, + ] + ); } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityFormType.php b/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityFormType.php index f517279bb..efc368ecc 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityFormType.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Form/AsideActivityFormType.php @@ -1,5 +1,12 @@ timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration'); $this->storage = $storage; $this->categoryRender = $categoryRender; @@ -54,57 +63,65 @@ final class AsideActivityFormType extends AbstractType ]; $builder - ->add('agent', EntityType::class, - [ - 'label' => 'For agent', - 'required' => true, - 'class' => User::class, - 'data' => $this->storage->getToken()->getUser(), - 'query_builder' => function(EntityRepository $er){ - return $er->createQueryBuilder('u')->where('u.enabled = true'); - }, - 'attr' => array('class' => 'select2 '), - 'placeholder' => 'Choose the agent for whom this activity is created', - 'choice_label' => 'username' - ]) - ->add('date', ChillDateType::class, - [ - 'label' => 'date', - 'data' => new \DateTime(), - 'required' => true - ]) - ->add('type', EntityType::class, - [ - 'label' => 'Type', - 'required' => true, - 'class' => AsideActivityCategory::class, - 'placeholder' => 'Choose the activity category', - 'query_builder' => function(EntityRepository $er) { - $qb = $er->createQueryBuilder('ac'); - $qb->where($qb->expr()->eq('ac.isActive', 'TRUE')) - ->addOrderBy('ac.ordering', 'ASC') - ; + ->add( + 'agent', + EntityType::class, + [ + 'label' => 'For agent', + 'required' => true, + 'class' => User::class, + 'data' => $this->storage->getToken()->getUser(), + 'query_builder' => function (EntityRepository $er) { + return $er->createQueryBuilder('u')->where('u.enabled = true'); + }, + 'attr' => ['class' => 'select2 '], + 'placeholder' => 'Choose the agent for whom this activity is created', + 'choice_label' => 'username', + ] + ) + ->add( + 'date', + ChillDateType::class, + [ + 'label' => 'date', + 'data' => new DateTime(), + 'required' => true, + ] + ) + ->add( + 'type', + EntityType::class, + [ + 'label' => 'Type', + 'required' => true, + 'class' => AsideActivityCategory::class, + 'placeholder' => 'Choose the activity category', + 'query_builder' => function (EntityRepository $er) { + $qb = $er->createQueryBuilder('ac'); + $qb->where($qb->expr()->eq('ac.isActive', 'TRUE')) + ->addOrderBy('ac.ordering', 'ASC'); - return $qb; - }, - 'choice_label' => function (AsideActivityCategory $asideActivityCategory) { - $options = []; - return $this->categoryRender->renderString($asideActivityCategory, $options); - }, - ]) + return $qb; + }, + 'choice_label' => function (AsideActivityCategory $asideActivityCategory) { + $options = []; + + return $this->categoryRender->renderString($asideActivityCategory, $options); + }, + ] + ) ->add('duration', ChoiceType::class, $durationTimeOptions) ->add('note', ChillTextareaType::class, [ 'label' => 'Note', 'required' => false, ]); - foreach (['duration'] as $fieldName) - { - $builder->get($fieldName) + foreach (['duration'] as $fieldName) { + $builder->get($fieldName) ->addModelTransformer($durationTimeTransformer); $builder->get($fieldName) - ->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $formEvent) use ( + ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $formEvent) use ( $timeChoices, $builder, $durationTimeTransformer, @@ -113,14 +130,14 @@ final class AsideActivityFormType extends AbstractType ) { // 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'); + $timezoneUTC = new DateTimeZone('GMT'); /* @var $data \DateTimeImmutable */ - $data = $formEvent->getData() === NULL ? - \DateTime::createFromFormat('U', 300) : + $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')); + $data->add(new DateInterval('PT' . $seconds . 'S')); // test if the timestamp is in the choices. // If not, recreate the field with the new timestamp @@ -128,16 +145,17 @@ final class AsideActivityFormType extends AbstractType // the data are not in the possible values. add them $timeChoices[$data->format('H:i')] = $data->getTimestamp(); $form = $builder->create($fieldName, ChoiceType::class, array_merge( - $durationTimeOptions, [ + $durationTimeOptions, + [ 'choices' => $timeChoices, - 'auto_initialize' => false + 'auto_initialize' => false, ] )); $form->addModelTransformer($durationTimeTransformer); $formEvent->getForm()->getParent()->add($form->getForm()); } }); - } + } } public function configureOptions(OptionsResolver $resolver): void diff --git a/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php b/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php index 24fc89162..3ca65be28 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php @@ -1,5 +1,12 @@ security = $security; } - public static function getMenuIds(): array - { - return ['admin_index', 'admin_section', 'admin_aside_activity']; - } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { // all the entries below must have ROLE_ADMIN permissions @@ -28,21 +30,25 @@ final class AdminMenuBuilder implements \Chill\MainBundle\Routing\LocalMenuBuild if (in_array($menuId, ['admin_index', 'admin_section'])) { $menu->addChild('Aside activities', [ - 'route' => 'chill_crud_aside_activity_category_index' + 'route' => 'chill_crud_aside_activity_category_index', ]) ->setExtras([ 'order' => 900, - 'explain' => "Aside activity type configuration" + 'explain' => 'Aside activity type configuration', ]); } else { $menu ->addChild('Aside activity categories', [ - 'route' => 'chill_crud_aside_activity_category_index' + 'route' => 'chill_crud_aside_activity_category_index', ]) ->setExtras([ - 'order' => '50' + 'order' => '50', ]); } + } + public static function getMenuIds(): array + { + return ['admin_index', 'admin_section', 'admin_aside_activity']; } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Menu/SectionMenuBuilder.php b/src/Bundle/ChillAsideActivityBundle/src/Menu/SectionMenuBuilder.php index 8a8d65156..078ae8a76 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Menu/SectionMenuBuilder.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Menu/SectionMenuBuilder.php @@ -1,23 +1,28 @@ translator = $translator; @@ -26,38 +31,33 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface /** * @param $menuId - * @param MenuItem $menu - * @param array $parameters */ public function buildMenu($menuId, MenuItem $menu, array $parameters) { - if ($this->authorizationChecker->isGranted('ROLE_USER')){ + if ($this->authorizationChecker->isGranted('ROLE_USER')) { $menu->addChild($this->translator->trans('Create an aside activity'), [ - 'route' => 'chill_crud_aside_activity_new' - ]) + 'route' => 'chill_crud_aside_activity_new', + ]) ->setExtras([ 'order' => 11, - 'icons' => [ 'plus' ] + 'icons' => ['plus'], ]); $menu->addChild($this->translator->trans('Phonecall'), [ 'route' => 'chill_crud_aside_activity_new', 'routeParameters' => [ 'type' => 1, 'duration' => 900, - ] + ], ]) - ->setExtras([ - 'order' => 12, - 'icons' => ['plus'] - ]); + ->setExtras([ + 'order' => 12, + 'icons' => ['plus'], + ]); } } - /** - * @return array - */ public static function getMenuIds(): array { - return [ 'section' ]; + return ['section']; } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Menu/UserMenuBuilder.php b/src/Bundle/ChillAsideActivityBundle/src/Menu/UserMenuBuilder.php index 4858e6ee7..e7d6f5e67 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Menu/UserMenuBuilder.php @@ -1,41 +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\AsideActivityBundle\Menu; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; -use Knp\Menu\MenuItem; use Chill\TaskBundle\Templating\UI\CountNotificationTask; +use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Chill\MainBundle\Entity\User; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Translation\TranslatorInterface; - -/** - * - * - * @author Julien Fastré - */ class UserMenuBuilder implements LocalMenuBuilderInterface { + /** + * @var AuthorizationCheckerInterface + */ + public $authorizationChecker; /** - * * @var CountNotificationTask */ public $counter; @@ -46,17 +34,10 @@ class UserMenuBuilder implements LocalMenuBuilderInterface public $tokenStorage; /** - * * @var TranslatorInterface */ public $translator; - /** - * - * @var AuthorizationCheckerInterface - */ - public $authorizationChecker; - public function __construct( CountNotificationTask $counter, TokenStorageInterface $tokenStorage, @@ -69,24 +50,21 @@ class UserMenuBuilder implements LocalMenuBuilderInterface $this->authorizationChecker = $authorizationChecker; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { - if ($this->authorizationChecker->isGranted('ROLE_USER')){ - $menu->addChild("My aside activities", [ - 'route' => 'chill_crud_aside_activity_index' + if ($this->authorizationChecker->isGranted('ROLE_USER')) { + $menu->addChild('My aside activities', [ + 'route' => 'chill_crud_aside_activity_index', ]) - ->setExtras([ - 'order' => 10, - 'icon' => 'tasks' - ]); + ->setExtras([ + 'order' => 10, + 'icon' => 'tasks', + ]); } - } public static function getMenuIds(): array { - return [ 'user' ]; + return ['user']; } - } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php index bcae0ef2c..791bd0d5b 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityCategoryRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(AsideActivityCategory::class); } - public function find($id): ?AsideActivityCategory { return $this->repository->find($id); @@ -33,6 +39,9 @@ class AsideActivityCategoryRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return AsideActivityCategory[] */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array @@ -49,4 +58,4 @@ class AsideActivityCategoryRepository implements ObjectRepository { return AsideActivityCategory::class; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php index 054259b63..a318837f7 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Repository/AsideActivityRepository.php @@ -1,5 +1,12 @@ ' > ', + ]; public const SEPERATOR_KEY = 'default.separator'; - public const DEFAULT_ARGS = [ - self::SEPERATOR_KEY => ' > ' - ]; + + private EngineInterface $engine; + + private TranslatableStringHelper $translatableStringHelper; public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine) { @@ -23,6 +32,35 @@ final class CategoryRender implements ChillEntityRenderInterface $this->engine = $engine; } + public function buildParents(AsideActivityCategory $asideActivityCategory) + { + $parents = []; + + while ($asideActivityCategory->hasParent()) { + $asideActivityCategory = $parents[] = $asideActivityCategory->getParent(); + } + + return $parents; + } + + /** + * @param AsideActivityCategory $asideActivityCategory + */ + public function renderBox($asideActivityCategory, array $options): string + { + $options = array_merge(self::DEFAULT_ARGS, $options); + $parents = $this->buildParents($asideActivityCategory); + + return $this->engine->render( + '@ChillAsideActivity/Entity/asideActivityCategory.html.twig', + [ + 'asideActivityCategory' => $asideActivityCategory, + 'parents' => $parents, + 'options' => $options, + ] + ); + } + /** * @param AsideActivityCategory $asideActivityCategory */ @@ -42,7 +80,6 @@ final class CategoryRender implements ChillEntityRenderInterface $titles = array_reverse($titles); return implode($options[self::SEPERATOR_KEY], $titles); - } /** @@ -52,31 +89,4 @@ final class CategoryRender implements ChillEntityRenderInterface { return $asideActivityCategory instanceof AsideActivityCategory; } - - public function buildParents(AsideActivityCategory $asideActivityCategory) - { - $parents = []; - - while($asideActivityCategory->hasParent()) { - $asideActivityCategory = $parents[] = $asideActivityCategory->getParent(); - } - - return $parents; - } - - /** - * @param AsideActivityCategory $asideActivityCategory - */ - public function renderBox($asideActivityCategory, array $options): string - { - $options = array_merge(self::DEFAULT_ARGS, $options); - $parents = $this->buildParents($asideActivityCategory); - - return $this->engine->render('@ChillAsideActivity/Entity/asideActivityCategory.html.twig', - [ - 'asideActivityCategory' => $asideActivityCategory, - 'parents' => $parents, - 'options' => $options - ]); - } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/Tests/Controller/AsideActivityControllerTest.php b/src/Bundle/ChillAsideActivityBundle/src/Tests/Controller/AsideActivityControllerTest.php index 301da25e1..a0ad9828f 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Tests/Controller/AsideActivityControllerTest.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Tests/Controller/AsideActivityControllerTest.php @@ -1,13 +1,25 @@ client = $this->getClientAuthenticated(); } - public function testIndexWithoutUsers() - { - $this->client->request('GET', '/fr/asideactivity'); - - $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); - } - - public function testNewWithoutUsers() - { - $this->client->request('GET', '/fr/asideactivity/new'); - - $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); - } - - /** - * @dataProvider generateAsideActivityId - */ - - public function testEditWithoutUsers(int $asideActivityId) - { - $this->client->request('GET', "/fr/asideactivity/{$asideActivityId}/edit"); - - $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); - } - public function generateAsideActivityId() { self::bootKernel(); @@ -59,15 +46,38 @@ class AccompanyingCourseControllerTest extends WebTestCase ->setParameter('center_name', 'center a_social') ->setMaxResults(100) ->getQuery() - ->getResult() - ; + ->getResult(); - \shuffle($asideActivityIds); + shuffle($asideActivityIds); - yield [ \array_pop($asideActivityIds)['id'] ]; - yield [ \array_pop($asideActivityIds)['id'] ]; - yield [ \array_pop($asideActivityIds)['id'] ]; + yield [array_pop($asideActivityIds)['id']]; + + yield [array_pop($asideActivityIds)['id']]; + + yield [array_pop($asideActivityIds)['id']]; } + /** + * @dataProvider generateAsideActivityId + */ + public function testEditWithoutUsers(int $asideActivityId) + { + $this->client->request('GET', "/fr/asideactivity/{$asideActivityId}/edit"); -} \ No newline at end of file + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + } + + public function testIndexWithoutUsers() + { + $this->client->request('GET', '/fr/asideactivity'); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + } + + public function testNewWithoutUsers() + { + $this->client->request('GET', '/fr/asideactivity/new'); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + } +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210706124644.php b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210706124644.php index 13bee6404..f02b623d0 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210706124644.php +++ b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210706124644.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE AsideActivity DROP CONSTRAINT FK_E9FA2191C54C8C93'); + $this->addSql('DROP SEQUENCE AsideActivity_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE AsideActivityType_id_seq CASCADE'); + $this->addSql('DROP TABLE AsideActivity'); + $this->addSql('DROP TABLE AsideActivityType'); + } + public function getDescription(): string { return 'Aside activity category entity created'; @@ -16,7 +33,6 @@ final class Version20210706124644 extends AbstractMigration public function up(Schema $schema): void { - $this->addSql('CREATE SEQUENCE AsideActivity_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE SEQUENCE AsideActivityType_id_seq INCREMENT BY 1 MINVALUE 1 START 1000'); $this->addSql('CREATE TABLE AsideActivity (id INT NOT NULL, type_id INT NOT NULL, agent_id INT NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, duration TIME(0) WITHOUT TIME ZONE DEFAULT NULL, location VARCHAR(100) DEFAULT NULL, note TEXT DEFAULT NULL, createdBy_id INT NOT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))'); @@ -32,14 +48,4 @@ final class Version20210706124644 extends AbstractMigration $this->addSql('ALTER TABLE AsideActivity ADD CONSTRAINT FK_E9FA21913414710B FOREIGN KEY (agent_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); // this up() migration is auto-generated, please modify it to your needs } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE AsideActivity DROP CONSTRAINT FK_E9FA2191C54C8C93'); - $this->addSql('DROP SEQUENCE AsideActivity_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE AsideActivityType_id_seq CASCADE'); - $this->addSql('DROP TABLE AsideActivity'); - $this->addSql('DROP TABLE AsideActivityType'); - } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210804082249.php b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210804082249.php index 85b99c572..d14898422 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210804082249.php +++ b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210804082249.php @@ -1,5 +1,12 @@ addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP CONSTRAINT FK_A866DA0EC54C8C93'); + $this->addSql('DROP SEQUENCE chill_asideactivity.AsideActivity_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_asideactivity.AsideActivityCategory_id_seq CASCADE'); + $this->addSql('CREATE SEQUENCE asideactivity_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE SEQUENCE asideactivitytype_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE asideactivitytype (id INT NOT NULL, title VARCHAR(255) NOT NULL, isactive BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE TABLE asideactivity (id INT NOT NULL, type_id INT NOT NULL, agent_id INT NOT NULL, createdby_id INT NOT NULL, updatedby_id INT DEFAULT NULL, createdat TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedat TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, duration TIME(0) WITHOUT TIME ZONE DEFAULT NULL, location VARCHAR(100) DEFAULT NULL, note TEXT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX idx_e9fa21913174800f ON asideactivity (createdby_id)'); + $this->addSql('CREATE INDEX idx_e9fa2191c54c8c93 ON asideactivity (type_id)'); + $this->addSql('CREATE INDEX idx_e9fa219165ff1aec ON asideactivity (updatedby_id)'); + $this->addSql('CREATE INDEX idx_e9fa21913414710b ON asideactivity (agent_id)'); + $this->addSql('COMMENT ON COLUMN asideactivity.updatedat IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa2191c54c8c93 FOREIGN KEY (type_id) REFERENCES asideactivitytype (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913174800f FOREIGN KEY (createdby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa219165ff1aec FOREIGN KEY (updatedby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913414710b FOREIGN KEY (agent_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('DROP TABLE chill_asideactivity.AsideActivity'); + $this->addSql('DROP TABLE chill_asideactivity.AsideActivityCategory'); + $this->addSql('DROP SCHEMA chill_asideactivity'); + } + public function getDescription(): string { return 'Aside activity entity created'; @@ -39,29 +71,4 @@ final class Version20210804082249 extends AbstractMigration $this->addSql('DROP TABLE asideactivitytype'); $this->addSql('DROP TABLE asideactivity'); } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('CREATE SCHEMA public'); - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP CONSTRAINT FK_A866DA0EC54C8C93'); - $this->addSql('DROP SEQUENCE chill_asideactivity.AsideActivity_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_asideactivity.AsideActivityCategory_id_seq CASCADE'); - $this->addSql('CREATE SEQUENCE asideactivity_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE SEQUENCE asideactivitytype_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE TABLE asideactivitytype (id INT NOT NULL, title VARCHAR(255) NOT NULL, isactive BOOLEAN NOT NULL, PRIMARY KEY(id))'); - $this->addSql('CREATE TABLE asideactivity (id INT NOT NULL, type_id INT NOT NULL, agent_id INT NOT NULL, createdby_id INT NOT NULL, updatedby_id INT DEFAULT NULL, createdat TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedat TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, duration TIME(0) WITHOUT TIME ZONE DEFAULT NULL, location VARCHAR(100) DEFAULT NULL, note TEXT DEFAULT NULL, PRIMARY KEY(id))'); - $this->addSql('CREATE INDEX idx_e9fa21913174800f ON asideactivity (createdby_id)'); - $this->addSql('CREATE INDEX idx_e9fa2191c54c8c93 ON asideactivity (type_id)'); - $this->addSql('CREATE INDEX idx_e9fa219165ff1aec ON asideactivity (updatedby_id)'); - $this->addSql('CREATE INDEX idx_e9fa21913414710b ON asideactivity (agent_id)'); - $this->addSql('COMMENT ON COLUMN asideactivity.updatedat IS \'(DC2Type:datetime_immutable)\''); - $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa2191c54c8c93 FOREIGN KEY (type_id) REFERENCES asideactivitytype (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913174800f FOREIGN KEY (createdby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa219165ff1aec FOREIGN KEY (updatedby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913414710b FOREIGN KEY (agent_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('DROP TABLE chill_asideactivity.AsideActivity'); - $this->addSql('DROP TABLE chill_asideactivity.AsideActivityCategory'); - $this->addSql('DROP SCHEMA chill_asideactivity'); - } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140343.php b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140343.php index 75c7b81b2..889c7f177 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140343.php +++ b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140343.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD duration INT DEFAULT NULL'); + } + public function getDescription(): string { return 'Duration changed to type integer'; @@ -19,10 +32,4 @@ final class Version20210806140343 extends AbstractMigration // this up() migration is auto-generated, please modify it to your needs $this->addSql('ALTER TABLE chill_asideactivity.asideactivity DROP duration'); } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD duration INT DEFAULT NULL'); - } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140710.php b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140710.php index 5c572e650..62fe73244 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140710.php +++ b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210806140710.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP duration'); + } + public function getDescription(): string { return 'Duration changed back to timestamp'; @@ -19,11 +32,4 @@ final class Version20210806140710 extends AbstractMigration // this up() migration is auto-generated, please modify it to your needs $this->addSql('ALTER TABLE chill_asideactivity.asideactivity ADD duration TIME(0) WITHOUT TIME ZONE DEFAULT NULL'); } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP duration'); - - } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210810084456.php b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210810084456.php index 2984108c2..d6d4deef4 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210810084456.php +++ b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210810084456.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER createdAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER createdAt DROP DEFAULT'); + $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER updatedAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER updatedAt DROP DEFAULT'); + $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER date TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER date DROP DEFAULT'); + $this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.createdat IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.updatedat IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.date IS \'(DC2Type:datetime_immutable)\''); + } + public function getDescription(): string { return 'createdat, updatedat and date given a type timestamp'; @@ -27,19 +48,4 @@ final class Version20210810084456 extends AbstractMigration $this->addSql('COMMENT ON COLUMN chill_asideactivity.asideactivity.updatedAt IS NULL'); $this->addSql('COMMENT ON COLUMN chill_asideactivity.asideactivity.date IS NULL'); } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER createdAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER createdAt DROP DEFAULT'); - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER updatedAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER updatedAt DROP DEFAULT'); - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER date TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER date DROP DEFAULT'); - $this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.createdat IS \'(DC2Type:datetime_immutable)\''); - $this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.updatedat IS \'(DC2Type:datetime_immutable)\''); - $this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.date IS \'(DC2Type:datetime_immutable)\''); - - } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210922182907.php b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210922182907.php index 13ba8749c..67a1db139 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210922182907.php +++ b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20210922182907.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_asideactivity.AsideActivityCategory DROP parent'); + } + public function getDescription(): string { return 'Parent and children added to aside activity category entity'; @@ -18,11 +30,6 @@ final class Version20210922182907 extends AbstractMigration { $this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory ADD parent_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory ADD CONSTRAINT FK_7BF90DBE727ACA70 FOREIGN KEY (parent_id) REFERENCES chill_asideactivity.AsideActivityCategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE INDEX IDX_7BF90DBE727ACA70 ON chill_asideactivity.asideactivitycategory (parent_id)'); - } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_asideactivity.AsideActivityCategory DROP parent'); + $this->addSql('CREATE INDEX IDX_7BF90DBE727ACA70 ON chill_asideactivity.asideactivitycategory (parent_id)'); } } diff --git a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20211004134012.php b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20211004134012.php index 42763638e..cfa5f3ce5 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20211004134012.php +++ b/src/Bundle/ChillAsideActivityBundle/src/migrations/Version20211004134012.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_asideactivity.asideactivitycategory DROP ordering'); + } + public function getDescription(): string { return 'allow to add an ordering to aside activity categories'; @@ -21,9 +33,4 @@ final class Version20211004134012 extends AbstractMigration { $this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory ADD ordering DOUBLE PRECISION NOT NULL DEFAULT 0.00'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory DROP ordering'); - } } 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..2057aadde 100644 --- a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php +++ b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php @@ -1,67 +1,71 @@ - */ +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..ee0fc30d0 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/ElementController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/ElementController.php @@ -1,46 +1,49 @@ 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 6d0b9c7b6..f64283b5a 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ChargeType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ChargeType.php @@ -1,19 +1,28 @@ 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', ]); } @@ -60,15 +69,35 @@ class ChargeType extends AbstractType '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', ]); } } + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Charge::class, + 'show_start_date' => true, + 'show_end_date' => true, + 'show_help' => true, + ]); + + $resolver + ->setAllowedTypes('show_start_date', 'boolean') + ->setAllowedTypes('show_end_date', 'boolean') + ->setAllowedTypes('show_help', 'boolean'); + } + + public function getBlockPrefix() + { + return 'chill_amli_budgetbundle_charge'; + } + private function getTypes() { $charges = $this->configRepository @@ -79,28 +108,8 @@ class ChargeType extends AbstractType $charges[$key] = $this->translatableStringHelper->localize($labels); } - \asort($charges); + asort($charges); - return \array_flip($charges); - } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults(array( - 'data_class' => Charge::class, - 'show_start_date' => true, - 'show_end_date' => true, - 'show_help' => true - )); - - $resolver - ->setAllowedTypes('show_start_date', 'boolean') - ->setAllowedTypes('show_end_date', 'boolean') - ->setAllowedTypes('show_help', 'boolean'); - } - - public function getBlockPrefix() - { - return 'chill_amli_budgetbundle_charge'; + return array_flip($charges); } } diff --git a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php index 2df9ee6d7..ddb4dd777 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php @@ -1,19 +1,27 @@ 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', ]); } } 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') @@ -86,6 +94,6 @@ class ResourceType extends AbstractType asort($resources); - return \array_flip($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..3c2a41226 100644 --- a/src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php +++ b/src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php @@ -1,79 +1,80 @@ + * 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 ]; - } - - public function getRolesWithoutScope() + public function getRoles(): array { return self::ROLES; } + public function getRolesWithHierarchy(): array + { + return ['Budget elements' => self::ROLES]; + } + + public function getRolesWithoutScope(): array + { + 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/ChillCalendarBundle/ChillCalendarBundle.php b/src/Bundle/ChillCalendarBundle/ChillCalendarBundle.php index cfbfa5b38..a42c0eca1 100644 --- a/src/Bundle/ChillCalendarBundle/ChillCalendarBundle.php +++ b/src/Bundle/ChillCalendarBundle/ChillCalendarBundle.php @@ -1,5 +1,12 @@ getMethod()) { - case Request::METHOD_GET: - return [ 'groups' => [ 'calendar:read' ] ]; - } - } - return parent::getContextForSerialization($action, $request, $_format, $entity); - } - protected function customizeQuery(string $action, Request $request, $qb): void { if ($request->query->has('main_user')) { - $qb->where('e.mainUser = :main_user') - ->setParameter('main_user', $request->query->get('main_user')); + ->setParameter('main_user', $request->query->get('main_user')); } } + protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array + { + switch ($action) { + case '_index': + switch ($request->getMethod()) { + case Request::METHOD_GET: + return ['groups' => ['calendar:read']]; + } + } + + return parent::getContextForSerialization($action, $request, $_format, $entity); + } } diff --git a/src/Bundle/ChillCalendarBundle/Controller/CalendarController.php b/src/Bundle/ChillCalendarBundle/Controller/CalendarController.php index c6f435ea6..0165142f7 100644 --- a/src/Bundle/ChillCalendarBundle/Controller/CalendarController.php +++ b/src/Bundle/ChillCalendarBundle/Controller/CalendarController.php @@ -1,43 +1,49 @@ calendarRepository = $calendarRepository; } + /** + * Delete a calendar item. + * + * @Route("/{_locale}/calendar/{id}/delete", name="chill_calendar_calendar_delete") + */ + public function deleteAction(Request $request, int $id) + { + $view = null; + $em = $this->getDoctrine()->getManager(); + + [$user, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = '@ChillCalendar/Calendar/confirm_deleteByAccompanyingCourse.html.twig'; + } elseif ($user instanceof User) { + $view = '@ChillCalendar/Calendar/confirm_deleteByUser.html.twig'; + } + + /* @var $entity Calendar */ + $entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Calendar entity.'); + } + + $form = $this->createDeleteForm($id, $user, $accompanyingPeriod); + + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); + + if ($form->isValid()) { + $this->logger->notice('A calendar event has been removed', [ + 'by_user' => $this->getUser()->getUsername(), + 'calendar_id' => $entity->getId(), + ]); + + $em->remove($entity); + $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The calendar item has been successfully removed.')); + + $params = $this->buildParamsToUrl($user, $accompanyingPeriod); + + return $this->redirectToRoute('chill_calendar_calendar_list', $params); + } + } + + if (null === $view) { + throw $this->createNotFoundException('Template not found'); + } + + return $this->render($view, [ + 'calendar' => $entity, + 'delete_form' => $form->createView(), + 'accompanyingCourse' => $accompanyingPeriod, + ]); + } + + /** + * Edit a calendar item. + * + * @Route("/{_locale}/calendar/calendar/{id}/edit", name="chill_calendar_calendar_edit") + */ + public function editAction(int $id, Request $request): Response + { + $view = null; + $em = $this->getDoctrine()->getManager(); + + [$user, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = '@ChillCalendar/Calendar/editByAccompanyingCourse.html.twig'; + } elseif ($user instanceof User) { + $view = '@ChillCalendar/Calendar/editByUser.html.twig'; + } + + $entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Calendar entity.'); + } + + $form = $this->createForm(CalendarType::class, $entity, [ + 'accompanyingPeriod' => $accompanyingPeriod, + ])->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $em->persist($entity); + $em->flush(); + + $this->addFlash('success', $this->get('translator')->trans('Success : calendar item updated!')); + + $params = $this->buildParamsToUrl($user, $accompanyingPeriod); + + return $this->redirectToRoute('chill_calendar_calendar_list', $params); + } + + if ($form->isSubmitted() and !$form->isValid()) { + $this->addFlash('error', $this->get('translator')->trans('This form contains errors')); + } + + $deleteForm = $this->createDeleteForm($id, $user, $accompanyingPeriod); + + if (null === $view) { + throw $this->createNotFoundException('Template not found'); + } + + $entity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); + + return $this->render($view, [ + 'entity' => $entity, + 'form' => $form->createView(), + 'delete_form' => $deleteForm->createView(), + 'accompanyingCourse' => $accompanyingPeriod, + 'user' => $user, + 'entity_json' => $entity_array, + ]); + } + /** * Lists all Calendar entities. + * * @Route("/{_locale}/calendar/calendar/", name="chill_calendar_calendar_list") */ public function listAction(Request $request): Response @@ -67,14 +194,13 @@ class CalendarController extends AbstractController [$user, $accompanyingPeriod] = $this->getEntity($request); if ($user instanceof User) { - $calendarItems = $this->calendarRepository->findByUser($user); $view = '@ChillCalendar/Calendar/listByUser.html.twig'; return $this->render($view, [ 'calendarItems' => $calendarItems, - 'user' => $user + 'user' => $user, ]); } @@ -93,15 +219,16 @@ class CalendarController extends AbstractController return $this->render($view, [ 'calendarItems' => $calendarItems, 'accompanyingCourse' => $accompanyingPeriod, - 'paginator' => $paginator + 'paginator' => $paginator, ]); } - throw new \Exception('Unable to list actions.'); + throw new Exception('Unable to list actions.'); } /** - * Create a new calendar item + * Create a new calendar item. + * * @Route("/{_locale}/calendar/calendar/new", name="chill_calendar_calendar_new") */ public function newAction(Request $request): Response @@ -149,7 +276,7 @@ class CalendarController extends AbstractController $this->addFlash('error', $this->get('translator')->trans('This form contains errors')); } - if ($view === null) { + if (null === $view) { throw $this->createNotFoundException('Template not found'); } @@ -160,15 +287,16 @@ class CalendarController extends AbstractController 'accompanyingCourse' => $accompanyingPeriod, 'entity' => $entity, 'form' => $form->createView(), - 'entity_json' => $entity_array + 'entity_json' => $entity_array, ]); } /** - * Show a calendar item + * Show a calendar item. + * * @Route("/{_locale}/calendar/calendar/{id}/show", name="chill_calendar_calendar_show") */ - public function showAction(Request $request, $id): Response + public function showAction(Request $request, int $id): Response { $view = null; $em = $this->getDoctrine()->getManager(); @@ -177,12 +305,11 @@ class CalendarController extends AbstractController if ($accompanyingPeriod instanceof AccompanyingPeriod) { $view = '@ChillCalendar/Calendar/showByAccompanyingCourse.html.twig'; - } - elseif ($user instanceof User) { + } elseif ($user instanceof User) { $view = '@ChillCalendar/Calendar/showByUser.html.twig'; } - if ($view === null) { + if (null === $view) { throw $this->createNotFoundException('Template not found'); } @@ -214,7 +341,7 @@ class CalendarController extends AbstractController ); $durationTime = $entity->getEndDate()->diff($entity->getStartDate()); - $durationTimeInMinutes = $durationTime->days*1440 + $durationTime->h*60 + $durationTime->i; + $durationTimeInMinutes = $durationTime->days * 1440 + $durationTime->h * 60 + $durationTime->i; $activityData = [ 'calendarId' => $id, @@ -230,131 +357,24 @@ class CalendarController extends AbstractController 'accompanyingCourse' => $accompanyingPeriod, 'entity' => $entity, 'user' => $user, - 'activityData' => $activityData + 'activityData' => $activityData, //'delete_form' => $deleteForm->createView(), ]); } - - - /** - * Edit a calendar item - * @Route("/{_locale}/calendar/calendar/{id}/edit", name="chill_calendar_calendar_edit") - */ - public function editAction($id, Request $request): Response + private function buildParamsToUrl(?User $user, ?AccompanyingPeriod $accompanyingPeriod): array { - $view = null; - $em = $this->getDoctrine()->getManager(); + $params = []; - [$user, $accompanyingPeriod] = $this->getEntity($request); - - if ($accompanyingPeriod instanceof AccompanyingPeriod) { - $view = '@ChillCalendar/Calendar/editByAccompanyingCourse.html.twig'; - } - elseif ($user instanceof User) { - $view = '@ChillCalendar/Calendar/editByUser.html.twig'; + if (null !== $user) { + $params['user_id'] = $user->getId(); } - $entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Calendar entity.'); + if (null !== $accompanyingPeriod) { + $params['accompanying_period_id'] = $accompanyingPeriod->getId(); } - $form = $this->createForm(CalendarType::class, $entity, [ - 'accompanyingPeriod' => $accompanyingPeriod, - ])->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $em->persist($entity); - $em->flush(); - - $this->addFlash('success', $this->get('translator')->trans('Success : calendar item updated!')); - - $params = $this->buildParamsToUrl($user, $accompanyingPeriod); - - return $this->redirectToRoute('chill_calendar_calendar_list', $params); - } - - if ($form->isSubmitted() and !$form->isValid()) { - $this->addFlash('error', $this->get('translator')->trans('This form contains errors')); - } - - $deleteForm = $this->createDeleteForm($id, $user, $accompanyingPeriod); - - if ($view === null) { - throw $this->createNotFoundException('Template not found'); - } - - $entity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); - - return $this->render($view, [ - 'entity' => $entity, - 'form' => $form->createView(), - 'delete_form' => $deleteForm->createView(), - 'accompanyingCourse' => $accompanyingPeriod, - 'user' => $user, - 'entity_json' => $entity_array - ]); - } - - /** - * Delete a calendar item - * @Route("/{_locale}/calendar/{id}/delete", name="chill_calendar_calendar_delete") - */ - public function deleteAction(Request $request, $id) - { - $view = null; - $em = $this->getDoctrine()->getManager(); - - [$user, $accompanyingPeriod] = $this->getEntity($request); - - if ($accompanyingPeriod instanceof AccompanyingPeriod) { - $view = '@ChillCalendar/Calendar/confirm_deleteByAccompanyingCourse.html.twig'; - } - elseif ($user instanceof User) { - $view = '@ChillCalendar/Calendar/confirm_deleteByUser.html.twig'; - } - - /* @var $entity Calendar */ - $entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Calendar entity.'); - } - - $form = $this->createDeleteForm($id, $user, $accompanyingPeriod); - - if ($request->getMethod() === Request::METHOD_DELETE) { - $form->handleRequest($request); - - if ($form->isValid()) { - - $this->logger->notice("A calendar event has been removed", [ - 'by_user' => $this->getUser()->getUsername(), - 'calendar_id' => $entity->getId() - ]); - - $em->remove($entity); - $em->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans("The calendar item has been successfully removed.")); - - $params = $this->buildParamsToUrl($user, $accompanyingPeriod); - return $this->redirectToRoute('chill_calendar_calendar_list', $params); - } - } - - if ($view === null) { - throw $this->createNotFoundException('Template not found'); - } - - return $this->render($view, [ - 'calendar' => $entity, - 'delete_form' => $form->createView(), - 'accompanyingCourse' => $accompanyingPeriod, - ]); + return $params; } /** @@ -369,8 +389,7 @@ class CalendarController extends AbstractController ->setAction($this->generateUrl('chill_calendar_calendar_delete', $params)) ->setMethod('DELETE') ->add('submit', SubmitType::class, ['label' => 'Delete']) - ->getForm() - ; + ->getForm(); } private function getEntity(Request $request): array @@ -382,7 +401,7 @@ class CalendarController extends AbstractController $user_id = $request->get('user_id'); $user = $em->getRepository(User::class)->find($user_id); - if ($user === null) { + if (null === $user) { throw $this->createNotFoundException('User not found'); } @@ -392,32 +411,18 @@ class CalendarController extends AbstractController $accompanying_period_id = $request->get('accompanying_period_id'); $accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id); - if ($accompanyingPeriod === null) { + if (null === $accompanyingPeriod) { throw $this->createNotFoundException('Accompanying Period not found'); } // TODO Add permission // $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); } else { - throw $this->createNotFoundException("Person or Accompanying Period not found"); + throw $this->createNotFoundException('Person or Accompanying Period not found'); } return [ - $user, $accompanyingPeriod + $user, $accompanyingPeriod, ]; } - - private function buildParamsToUrl(?User $user, ?AccompanyingPeriod $accompanyingPeriod): array { - $params = []; - - if (null !== $user) { - $params['user_id'] = $user->getId(); - } - - if (null !== $accompanyingPeriod) { - $params['accompanying_period_id'] = $accompanyingPeriod->getId(); - } - - return $params; - } } diff --git a/src/Bundle/ChillCalendarBundle/Controller/CalendarRangeAPIController.php b/src/Bundle/ChillCalendarBundle/Controller/CalendarRangeAPIController.php index 672e9527c..4334667dd 100644 --- a/src/Bundle/ChillCalendarBundle/Controller/CalendarRangeAPIController.php +++ b/src/Bundle/ChillCalendarBundle/Controller/CalendarRangeAPIController.php @@ -1,18 +1,22 @@ getResult(); - return $this->json(['count' => count($results), 'results' => $results], Response::HTTP_OK, [], [ 'groups' => [ 'read' ]]); + return $this->json(['count' => count($results), 'results' => $results], Response::HTTP_OK, [], ['groups' => ['read']]); //TODO use also the paginator, eg return $this->serializeCollection('get', $request, $_format, $paginator, $results); } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php index 42218da03..e708672a9 100644 --- a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php +++ b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCalendarRange.php @@ -1,12 +1,17 @@ userRepository = $userRepository; } - public function getOrder(): int - { - return 40003; - } - public static function getGroups(): array { return ['calendar']; } + public function getOrder(): int + { + return 40003; + } + public function load(ObjectManager $manager): void { $arr = range(-50, 50); - print "Creating calendar range ('plage de disponibilités')\n"; + echo "Creating calendar range ('plage de disponibilités')\n"; $users = $this->userRepository->findAll(); @@ -60,25 +64,23 @@ class LoadCalendarRange extends Fixture implements FixtureGroupInterface, Ordere '10:00:00', '11:30:00', '13:30:00', - '15:00:00' + '15:00:00', ]; foreach ($users as $u) { foreach ($days as $d) { - foreach ($hours as $h){ - $event = $d.' '.$h; + foreach ($hours as $h) { + $event = $d . ' ' . $h; $startEvent = new DateTimeImmutable($event); - $endEvent = new DateTimeImmutable($event.' + 1 hours'); - $calendarRange= (new CalendarRange()) + $endEvent = new DateTimeImmutable($event . ' + 1 hours'); + $calendarRange = (new CalendarRange()) ->setUser($u) ->setStartDate($startEvent) ->setEndDate($endEvent); $manager->persist($calendarRange); } - } - } $manager->flush(); } diff --git a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCancelReason.php b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCancelReason.php index 370b08f07..508195081 100644 --- a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCancelReason.php +++ b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadCancelReason.php @@ -1,5 +1,12 @@ setCanceledBy($a['name']) ->setActive(true); $manager->persist($cancelReason); - $reference = 'CancelReason_'.$a['name']; + $reference = 'CancelReason_' . $a['name']; $this->addReference($reference, $cancelReason); static::$references[] = $reference; } diff --git a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadInvite.php b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadInvite.php index 9c265b3ac..926797899 100644 --- a/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadInvite.php +++ b/src/Bundle/ChillCalendarBundle/DataFixtures/ORM/LoadInvite.php @@ -1,5 +1,12 @@ setStatus($a['name']); $manager->persist($invite); - $reference = 'Invite_'.$a['name']['fr']; + $reference = 'Invite_' . $a['name']['fr']; $this->addReference($reference, $invite); static::$references[] = $reference; } diff --git a/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php b/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php index eaa8a1416..3ac0b54ad 100644 --- a/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php +++ b/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php @@ -1,30 +1,34 @@ processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.yml'); $loader->load('services/controller.yml'); $loader->load('services/fixtures.yml'); @@ -37,22 +41,7 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf $this->preprendRoutes($container); $this->prependCruds($container); } - - protected function preprendRoutes(ContainerBuilder $container) - { - $container->prependExtensionConfig('chill_main', [ - 'routing' => [ - 'resources' => [ - '@ChillCalendarBundle/Resources/config/routing.yml' - ] - ] - ]); - } - - /** - * @param ContainerBuilder $container - */ protected function prependCruds(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ @@ -77,9 +66,9 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf Request::METHOD_POST => true, Request::METHOD_PATCH => true, Request::METHOD_DELETE => true, - ] + ], ], - ] + ], ], [ 'controller' => \Chill\CalendarBundle\Controller\CalendarAPIController::class, @@ -91,20 +80,29 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true - ] + Request::METHOD_HEAD => true, + ], ], - ] - ] - ] + ], + ], + ], ]); } - + protected function preprendRoutes(ContainerBuilder $container) + { + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillCalendarBundle/Resources/config/routing.yml', + ], + ], + ]); + } } diff --git a/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php index 40524b53e..0d1c32d3f 100644 --- a/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php @@ -1,5 +1,12 @@ invites = new ArrayCollection(); } - - public function getId(): ?int - { - return $this->id; - } - - public function getSendSMS(): ?bool - { - return $this->sendSMS; - } - - public function setSendSMS(?bool $sendSMS): self - { - $this->sendSMS = $sendSMS; - - return $this; - } - - public function getComment(): CommentEmbeddable - { - return $this->comment; - } - - public function setComment(CommentEmbeddable $comment): self - { - $this->comment = $comment; - - return $this; - } - - public function getStartDate(): ?\DateTimeImmutable - { - return $this->startDate; - } - - public function setStartDate(\DateTimeImmutable $startDate): self - { - $this->startDate = $startDate; - - return $this; - } - - public function getEndDate(): ?\DateTimeImmutable - { - return $this->endDate; - } - - public function setEndDate(\DateTimeImmutable $endDate): self - { - $this->endDate = $endDate; - - return $this; - } - - public function getStatus(): ?string - { - return $this->status; - } - - public function setStatus(string $status): self - { - $this->status = $status; - - return $this; - } - - public function getUser(): ?User - { - return $this->user; - } - - public function setUser(?User $user): self - { - $this->user = $user; - - return $this; - } - - public function getAccompanyingPeriod(): ?AccompanyingPeriod - { - return $this->accompanyingPeriod; - } - - public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self - { - $this->accompanyingPeriod = $accompanyingPeriod; - - return $this; - } - - public function getMainUser(): ?User - { - return $this->mainUser; - } - - public function setMainUser(?User $mainUser): self - { - $this->mainUser = $mainUser; - - return $this; - } - - /** - * @return Collection|Person[] - */ - public function getPersons(): Collection - { - return $this->persons; - } - - public function addPerson(?Person $person): self - { - if (null !== $person) { - $this->persons[] = $person; - } - - return $this; - } - - public function removePerson(Person $person): self - { - $this->persons->removeElement($person); - - return $this; - } - - /** - * @return Collection|ThirdParty[] - */ - public function getProfessionals(): Collection - { - return $this->professionals; - } - - public function addProfessional(?ThirdParty $professional): self - { - if (null !== $professional) { - $this->professionals[] = $professional; - } - - return $this; - } - - public function removeProfessional(ThirdParty $professional): self - { - $this->professionals->removeElement($professional); - - return $this; - } - - /** - * @return Collection|Invite[] - */ - public function getInvites(): Collection - { - return $this->invites; - } - public function addInvite(?Invite $invite): self { if (null !== $invite) { @@ -319,35 +161,27 @@ class Calendar return $this; } - public function removeInvite(Invite $invite): self + public function addPerson(?Person $person): self { - $this->invites->removeElement($invite); + if (null !== $person) { + $this->persons[] = $person; + } return $this; } - public function getCancelReason(): ?CancelReason + public function addProfessional(?ThirdParty $professional): self { - return $this->cancelReason; - } - - public function setCancelReason(?CancelReason $cancelReason): self - { - $this->cancelReason = $cancelReason; + if (null !== $professional) { + $this->professionals[] = $professional; + } return $this; } - public function getCalendarRange(): ?CalendarRange + public function getAccompanyingPeriod(): ?AccompanyingPeriod { - return $this->calendarRange; - } - - public function setCalendarRange(?CalendarRange $calendarRange): self - { - $this->calendarRange = $calendarRange; - - return $this; + return $this->accompanyingPeriod; } public function getActivity(): ?Activity @@ -355,24 +189,71 @@ class Calendar return $this->activity; } - public function setActivity(?Activity $activity): self + public function getCalendarRange(): ?CalendarRange { - $this->activity = $activity; + return $this->calendarRange; + } - return $this; + public function getCancelReason(): ?CancelReason + { + return $this->cancelReason; + } + + public function getComment(): CommentEmbeddable + { + return $this->comment; + } + + public function getEndDate(): ?DateTimeImmutable + { + return $this->endDate; + } + + public function getId(): ?int + { + return $this->id; + } + + /** + * @return Collection|Invite[] + */ + public function getInvites(): Collection + { + return $this->invites; + } + + public function getLocation(): ?Location + { + return $this->location; + } + + public function getMainUser(): ?User + { + return $this->mainUser; + } + + /** + * @return Collection|Person[] + */ + public function getPersons(): Collection + { + return $this->persons; } public function getPersonsAssociated(): array { if (null !== $this->accompanyingPeriod) { $personsAssociated = []; + foreach ($this->accompanyingPeriod->getParticipations() as $participation) { if ($this->persons->contains($participation->getPerson())) { $personsAssociated[] = $participation->getPerson(); } } + return $personsAssociated; } + return []; } @@ -380,22 +261,52 @@ class Calendar { if (null !== $this->accompanyingPeriod) { $personsNotAssociated = []; + foreach ($this->persons as $person) { if (!in_array($person, $this->getPersonsAssociated())) { - $personsNotAssociated[] = $person; + $personsNotAssociated[] = $person; } } + return $personsNotAssociated; } + return []; } + /** + * @return Collection|ThirdParty[] + */ + public function getProfessionals(): Collection + { + return $this->professionals; + } + + public function getSendSMS(): ?bool + { + return $this->sendSMS; + } + + public function getStartDate(): ?DateTimeImmutable + { + return $this->startDate; + } + + public function getStatus(): ?string + { + return $this->status; + } public function getThirdParties(): Collection { return $this->getProfessionals(); } + public function getUser(): ?User + { + return $this->user; + } + public function getusers(): Collection { return $this->getInvites(); //TODO get users of the invite @@ -415,22 +326,108 @@ class Calendar ])); } - /** - * @return Location|null - */ - public function getLocation(): ?Location + public function removeInvite(Invite $invite): self { - return $this->location; - } + $this->invites->removeElement($invite); - /** - * @param Location|null $location - * @return Calendar - */ - public function setLocation(?Location $location): Calendar - { - $this->location = $location; return $this; } + public function removePerson(Person $person): self + { + $this->persons->removeElement($person); + + return $this; + } + + public function removeProfessional(ThirdParty $professional): self + { + $this->professionals->removeElement($professional); + + return $this; + } + + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + { + $this->accompanyingPeriod = $accompanyingPeriod; + + return $this; + } + + public function setActivity(?Activity $activity): self + { + $this->activity = $activity; + + return $this; + } + + public function setCalendarRange(?CalendarRange $calendarRange): self + { + $this->calendarRange = $calendarRange; + + return $this; + } + + public function setCancelReason(?CancelReason $cancelReason): self + { + $this->cancelReason = $cancelReason; + + return $this; + } + + public function setComment(CommentEmbeddable $comment): self + { + $this->comment = $comment; + + return $this; + } + + public function setEndDate(DateTimeImmutable $endDate): self + { + $this->endDate = $endDate; + + return $this; + } + + public function setLocation(?Location $location): Calendar + { + $this->location = $location; + + return $this; + } + + public function setMainUser(?User $mainUser): self + { + $this->mainUser = $mainUser; + + return $this; + } + + public function setSendSMS(?bool $sendSMS): self + { + $this->sendSMS = $sendSMS; + + return $this; + } + + public function setStartDate(DateTimeImmutable $startDate): self + { + $this->startDate = $startDate; + + return $this; + } + + public function setStatus(string $status): self + { + $this->status = $status; + + return $this; + } + + public function setUser(?User $user): self + { + $this->user = $user; + + return $this; + } } diff --git a/src/Bundle/ChillCalendarBundle/Entity/CalendarRange.php b/src/Bundle/ChillCalendarBundle/Entity/CalendarRange.php index 312e4bb41..0a749c0ba 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/CalendarRange.php +++ b/src/Bundle/ChillCalendarBundle/Entity/CalendarRange.php @@ -1,9 +1,17 @@ calendars = new ArrayCollection(); } + public function getEndDate(): ?DateTimeImmutable + { + return $this->endDate; + } + public function getId(): ?int { return $this->id; } - public function getStartDate(): ?\DateTimeImmutable + public function getStartDate(): ?DateTimeImmutable { return $this->startDate; } - public function setStartDate(\DateTimeImmutable $startDate): self + public function getUser(): ?User { - $this->startDate = $startDate; - - return $this; + return $this->user; } - public function getEndDate(): ?\DateTimeImmutable - { - return $this->endDate; - } - - public function setEndDate(\DateTimeImmutable $endDate): self + public function setEndDate(DateTimeImmutable $endDate): self { $this->endDate = $endDate; return $this; } - public function getUser(): ?User + public function setStartDate(DateTimeImmutable $startDate): self { - return $this->user; + $this->startDate = $startDate; + + return $this; } public function setUser(?User $user): self @@ -94,6 +102,4 @@ class CalendarRange return $this; } - - } diff --git a/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php b/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php index bca569a49..4d8236c9a 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php +++ b/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php @@ -1,5 +1,12 @@ active; + } + + public function getCanceledBy(): ?string + { + return $this->canceledBy; + } + public function getId(): ?int { return $this->id; } - public function getActive(): ?bool + public function getName(): ?array { - return $this->active; + return $this->name; } public function setActive(bool $active): self @@ -55,11 +73,6 @@ class CancelReason return $this; } - public function getCanceledBy(): ?string - { - return $this->canceledBy; - } - public function setCanceledBy(string $canceledBy): self { $this->canceledBy = $canceledBy; @@ -67,11 +80,6 @@ class CancelReason return $this; } - public function getName(): ?array - { - return $this->name; - } - public function setName(array $name): self { $this->name = $name; diff --git a/src/Bundle/ChillCalendarBundle/Entity/Invite.php b/src/Bundle/ChillCalendarBundle/Entity/Invite.php index c1e7f8b57..7204f8067 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/Invite.php +++ b/src/Bundle/ChillCalendarBundle/Entity/Invite.php @@ -1,5 +1,12 @@ id; @@ -39,6 +46,11 @@ class Invite return $this->status; } + public function getUser(): ?User + { + return $this->user; + } + public function setStatus(array $status): self { $this->status = $status; @@ -46,11 +58,6 @@ class Invite return $this; } - public function getUser(): ?User - { - return $this->user; - } - public function setUser(?User $user): self { $this->user = $user; diff --git a/src/Bundle/ChillCalendarBundle/Event/ListenToActivityCreate.php b/src/Bundle/ChillCalendarBundle/Event/ListenToActivityCreate.php index d7073597a..ab06ac71f 100644 --- a/src/Bundle/ChillCalendarBundle/Event/ListenToActivityCreate.php +++ b/src/Bundle/ChillCalendarBundle/Event/ListenToActivityCreate.php @@ -1,5 +1,12 @@ query->has('activityData')) { $activityData = $request->query->get('activityData'); + if (array_key_exists('calendarId', $activityData)) { $calendarId = $activityData['calendarId']; @@ -40,8 +47,5 @@ class ListenToActivityCreate $em->flush(); } } - - - } } diff --git a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php index 753eb3728..1ed91894e 100644 --- a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php +++ b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php @@ -1,53 +1,54 @@ translatableStringHelper = $translatableStringHelper; $this->om = $om; } - /** - * {@inheritdoc} - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('comment', CommentType::class, [ - 'required' => false + 'required' => false, ]) // ->add('cancelReason', EntityType::class, [ // 'required' => false, @@ -60,124 +61,126 @@ class CalendarType extends AbstractType 'required' => false, 'choices' => [ 'Oui' => true, - 'Non' => false + 'Non' => false, ], - 'expanded' => true - ]) - ; - + 'expanded' => true, + ]); $builder->add('mainUser', HiddenType::class); $builder->get('mainUser') ->addModelTransformer(new CallbackTransformer( function (?User $user): int { - if (NULL !== $user) { + if (null !== $user) { $res = $user->getId(); } else { $res = -1; //TODO cannot be null in any ways... } + return $res; }, function (?int $userId): User { return $this->om->getRepository(user::class)->findOneBy(['id' => (int) $userId]); } - )) - ; + )); $builder->add('startDate', HiddenType::class); $builder->get('startDate') ->addModelTransformer(new CallbackTransformer( function (?DateTimeImmutable $dateTimeImmutable): string { - if (NULL !== $dateTimeImmutable) { + if (null !== $dateTimeImmutable) { $res = date_format($dateTimeImmutable, 'Y-m-d H:i:s'); } else { $res = ''; } + return $res; }, function (?string $dateAsString): DateTimeImmutable { dump($dateAsString); + return new DateTimeImmutable($dateAsString); } - )) - ; + )); $builder->add('endDate', HiddenType::class); $builder->get('endDate') ->addModelTransformer(new CallbackTransformer( function (?DateTimeImmutable $dateTimeImmutable): string { - if (NULL !== $dateTimeImmutable) { + if (null !== $dateTimeImmutable) { $res = date_format($dateTimeImmutable, 'Y-m-d H:i:s'); } else { $res = ''; } + return $res; }, function (?string $dateAsString): DateTimeImmutable { return new DateTimeImmutable($dateAsString); } - )) - ; + )); $builder->add('persons', HiddenType::class); $builder->get('persons') ->addModelTransformer(new CallbackTransformer( function (iterable $personsAsIterable): string { $personIds = []; + foreach ($personsAsIterable as $value) { $personIds[] = $value->getId(); } + return implode(',', $personIds); }, function (?string $personsAsString): array { return array_map( - fn(string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]), + fn (string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]), explode(',', $personsAsString) ); } - )) - ; + )); $builder->add('professionals', HiddenType::class); $builder->get('professionals') ->addModelTransformer(new CallbackTransformer( function (iterable $thirdpartyAsIterable): string { $thirdpartyIds = []; + foreach ($thirdpartyAsIterable as $value) { $thirdpartyIds[] = $value->getId(); } + return implode(',', $thirdpartyIds); }, function (?string $thirdpartyAsString): array { return array_map( - fn(string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]), + fn (string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]), explode(',', $thirdpartyAsString) ); } - )) - ; + )); $builder->add('calendarRange', HiddenType::class); $builder->get('calendarRange') ->addModelTransformer(new CallbackTransformer( function (?CalendarRange $calendarRange): ?int { - if (NULL !== $calendarRange) { + if (null !== $calendarRange) { $res = $calendarRange->getId(); } else { $res = -1; } + return $res; }, function (?string $calendarRangeId): ?CalendarRange { - if (NULL !== $calendarRangeId) { + if (null !== $calendarRangeId) { $res = $this->om->getRepository(CalendarRange::class)->findOneBy(['id' => (int) $calendarRangeId]); } else { - $res = NULL; + $res = null; } + return $res; } - )) - ; + )); $builder->add('location', HiddenType::class) ->get('location') @@ -186,58 +189,48 @@ class CalendarType extends AbstractType if (null === $location) { return ''; } + return $location->getId(); }, function (?string $id): ?Location { return $this->om->getRepository(Location::class)->findOneBy(['id' => (int) $id]); } - )) - ; + )); - // $builder->add('invites', HiddenType::class); - // $builder->get('invites') - // ->addModelTransformer(new CallbackTransformer( - // function (iterable $usersAsIterable): string { - // $userIds = []; - // foreach ($usersAsIterable as $value) { - // $userIds[] = $value->getId(); - // } - // return implode(',', $userIds); - // }, - // function (?string $usersAsString): array { - // return array_map( - // fn(string $id): ?Invite => $this->om->getRepository(Invite::class)->findOneBy(['id' => (int) $id]), - // explode(',', $usersAsString) - // ); - // } - // )) - // ; + $builder->add('invites', HiddenType::class); + $builder->get('invites') + ->addModelTransformer(new CallbackTransformer( + function (iterable $usersAsIterable): string { + $userIds = []; + foreach ($usersAsIterable as $value) { + $userIds[] = $value->getId(); + } + + return implode(',', $userIds); + }, + function (?string $usersAsString): array { + return array_map( + fn (string $id): ?Invite => $this->om->getRepository(Invite::class)->findOneBy(['id' => (int) $id]), + explode(',', $usersAsString) + ); + } + )); + } - }/** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ - 'data_class' => Calendar::class + 'data_class' => Calendar::class, ]); $resolver ->setRequired(['accompanyingPeriod']) - ->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']) - ; + ->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']); } - /** - * {@inheritdoc} - */ public function getBlockPrefix() { return 'chill_calendarbundle_calendar'; } - - } - - diff --git a/src/Bundle/ChillCalendarBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillCalendarBundle/Menu/AccompanyingCourseMenuBuilder.php index 4f0cf7b30..451dee836 100644 --- a/src/Bundle/ChillCalendarBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillCalendarBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -1,5 +1,12 @@ authorizationHelper = $authorizationHelper; $this->tokenStorage = $tokenStorage; } - public static function getMenuIds(): array - { - return ['accompanyingCourse']; - } public function buildMenu($menuId, MenuItem $menu, array $parameters) { @@ -40,8 +43,13 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface 'route' => 'chill_calendar_calendar_list', 'routeParameters' => [ 'accompanying_period_id' => $period->getId(), - ]]) + ], ]) ->setExtras(['order' => 35]); } } + + public static function getMenuIds(): array + { + return ['accompanyingCourse']; + } } diff --git a/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php b/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php index 9a3c8ce56..6561808fc 100644 --- a/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php @@ -1,40 +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\CalendarBundle\Menu; - -use Chill\MainBundle\Entity\User; -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 Symfony\Component\Translation\TranslatorInterface; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; - /** + * Chill is a software for social workers * - * @author Champs-Libres + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\CalendarBundle\Menu; + +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +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; @@ -45,17 +34,10 @@ class UserMenuBuilder implements LocalMenuBuilderInterface public $tokenStorage; /** - * * @var TranslatorInterface */ public $translator; - /** - * - * @var AuthorizationCheckerInterface - */ - public $authorizationChecker; - public function __construct( CountNotificationTask $counter, TokenStorageInterface $tokenStorage, @@ -68,25 +50,23 @@ class UserMenuBuilder implements LocalMenuBuilderInterface $this->authorizationChecker = $authorizationChecker; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { $user = $this->tokenStorage->getToken()->getUser(); - if ($this->authorizationChecker->isGranted('ROLE_USER')){ - $menu->addChild("My calendar list", [ - 'route' => 'chill_calendar_calendar_list' + if ($this->authorizationChecker->isGranted('ROLE_USER')) { + $menu->addChild('My calendar list', [ + 'route' => 'chill_calendar_calendar_list', ]) - ->setExtras([ - 'order' => 9, - 'icon' => 'tasks' - ]); + ->setExtras([ + 'order' => 9, + 'icon' => 'tasks', + ]); } } public static function getMenuIds(): array { - return [ 'user' ]; + return ['user']; } - } diff --git a/src/Bundle/ChillCalendarBundle/Repository/CalendarRangeRepository.php b/src/Bundle/ChillCalendarBundle/Repository/CalendarRangeRepository.php index 152c0f097..aaa5a2a23 100644 --- a/src/Bundle/ChillCalendarBundle/Repository/CalendarRangeRepository.php +++ b/src/Bundle/ChillCalendarBundle/Repository/CalendarRangeRepository.php @@ -1,5 +1,12 @@ getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?CalendarRange @@ -46,5 +53,5 @@ class CalendarRangeRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php b/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php index b87f4f525..2789d83b9 100644 --- a/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php +++ b/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php @@ -1,9 +1,15 @@ repository = $entityManager->getRepository(AccompanyingPeriodWork::class); + // $this->repository = $entityManager->getRepository(AccompanyingPeriodWork::class); } // /** @@ -40,7 +45,7 @@ class CalendarRepository extends ServiceEntityRepository ->getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?Calendar @@ -52,5 +57,5 @@ class CalendarRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillCalendarBundle/Repository/CancelReasonRepository.php b/src/Bundle/ChillCalendarBundle/Repository/CancelReasonRepository.php index 5bd07fbd9..20e01304a 100644 --- a/src/Bundle/ChillCalendarBundle/Repository/CancelReasonRepository.php +++ b/src/Bundle/ChillCalendarBundle/Repository/CancelReasonRepository.php @@ -1,5 +1,12 @@ getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?CancelReason @@ -46,5 +53,5 @@ class CancelReasonRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillCalendarBundle/Repository/InviteRepository.php b/src/Bundle/ChillCalendarBundle/Repository/InviteRepository.php index ece11269f..73f7c1299 100644 --- a/src/Bundle/ChillCalendarBundle/Repository/InviteRepository.php +++ b/src/Bundle/ChillCalendarBundle/Repository/InviteRepository.php @@ -1,5 +1,12 @@ getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?Invite @@ -46,5 +53,5 @@ class InviteRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/Calendar/store.js b/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/Calendar/store.js index b4578ea2b..457d31799 100644 --- a/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/Calendar/store.js +++ b/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/Calendar/store.js @@ -28,9 +28,59 @@ const mapEntity = (entity) => { const store = createStore({ strict: debug, state: { - activity: mapEntity(window.entity), + activity: mapEntity(window.entity), // activity is the calendar entity actually currentEvent: null }, + getters: { + suggestedEntities(state) { + console.log(state.activity) + if (typeof(state.activity.accompanyingPeriod) === 'undefined') { + return []; + } + const allEntities = [ + ...store.getters.suggestedPersons, + ...store.getters.suggestedRequestor, + ...store.getters.suggestedUser, + ...store.getters.suggestedResources + ]; + const uniqueIds = [...new Set(allEntities.map(i => `${i.type}-${i.id}`))]; + return Array.from(uniqueIds, id => allEntities.filter(r => `${r.type}-${r.id}` === id)[0]); + }, + suggestedPersons(state) { + const existingPersonIds = state.activity.persons.map(p => p.id); + return state.activity.accompanyingPeriod.participations + .filter(p => p.endDate === null) + .map(p => p.person) + .filter(p => !existingPersonIds.includes(p.id)) + }, + suggestedRequestor(state) { + const existingPersonIds = state.activity.persons.map(p => p.id); + const existingThirdPartyIds = state.activity.thirdParties.map(p => p.id); + return [state.activity.accompanyingPeriod.requestor] + .filter(r => + (r.type === 'person' && !existingPersonIds.includes(r.id)) || + (r.type === 'thirdparty' && !existingThirdPartyIds.includes(r.id)) + ); + }, + suggestedUser(state) { + const existingUserIds = state.activity.users.map(p => p.id); + return [state.activity.accompanyingPeriod.user] + .filter( + u => !existingUserIds.includes(u.id) + ); + }, + suggestedResources(state) { + const resources = state.activity.accompanyingPeriod.resources; + const existingPersonIds = state.activity.persons.map(p => p.id); + const existingThirdPartyIds = state.activity.thirdParties.map(p => p.id); + return state.activity.accompanyingPeriod.resources + .map(r => r.resource) + .filter(r => + (r.type === 'person' && !existingPersonIds.includes(r.id)) || + (r.type === 'thirdparty' && !existingThirdPartyIds.includes(r.id)) + ); + } + }, mutations: { // ConcernedGroups diff --git a/src/Bundle/ChillCalendarBundle/Tests/Controller/CalendarControllerTest.php b/src/Bundle/ChillCalendarBundle/Tests/Controller/CalendarControllerTest.php index 00fca668a..2ec95df65 100644 --- a/src/Bundle/ChillCalendarBundle/Tests/Controller/CalendarControllerTest.php +++ b/src/Bundle/ChillCalendarBundle/Tests/Controller/CalendarControllerTest.php @@ -1,47 +1,56 @@ 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', + ]); } public function provideAccompanyingPeriod(): iterable { static::bootKernel(); - $em= static::$container->get(EntityManagerInterface::class); + $em = static::$container->get(EntityManagerInterface::class); $nb = $em->createQueryBuilder() ->from(AccompanyingPeriod::class, 'ac') ->select('COUNT(ac) AS nb') ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); - yield [ $em->createQueryBuilder() + yield [$em->createQueryBuilder() ->from(AccompanyingPeriod::class, 'ac') ->select('ac.id') - ->setFirstResult(\random_int(0, $nb)) + ->setFirstResult(random_int(0, $nb)) ->setMaxResults(1) ->getQuery() - ->getSingleScalarResult() + ->getSingleScalarResult(), ]; } diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php b/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php index 0d2dd2f2e..20d21f499 100644 --- a/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_calendar.calendar_to_persons DROP CONSTRAINT FK_AEE94715A40A2C8'); + $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals DROP CONSTRAINT FK_FADF2C77A40A2C8'); + $this->addSql('ALTER TABLE chill_calendar.calendar_to_thirdparties DROP CONSTRAINT FK_2BAB7EFDA40A2C8'); + $this->addSql('ALTER TABLE chill_calendar.calendar_to_invites DROP CONSTRAINT FK_FCBEAAAA40A2C8'); + $this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315ACC5CB285D'); + $this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315ACE980772F'); + $this->addSql('ALTER TABLE chill_calendar.calendar_to_invites DROP CONSTRAINT FK_FCBEAAAEA417747'); + $this->addSql('DROP SEQUENCE chill_calendar.calendar_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_calendar.calendar_range_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_calendar.cancel_reason_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_calendar.invite_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_calendar.calendar'); + $this->addSql('DROP TABLE chill_calendar.calendar_to_persons'); + $this->addSql('DROP TABLE chill_calendar.calendar_to_non_professionals'); + $this->addSql('DROP TABLE chill_calendar.calendar_to_thirdparties'); + $this->addSql('DROP TABLE chill_calendar.calendar_to_invites'); + $this->addSql('DROP TABLE chill_calendar.calendar_range'); + $this->addSql('DROP TABLE chill_calendar.cancel_reason'); + $this->addSql('DROP TABLE chill_calendar.invite'); + $this->addSql('DROP SCHEMA chill_calendar'); + } + public function getDescription(): string { return 'Create the schema chill_calendar and several calendar entities'; @@ -69,28 +100,4 @@ final class Version20210715141731 extends AbstractMigration $this->addSql('ALTER TABLE chill_calendar.calendar_range ADD CONSTRAINT FK_38D57D05A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_calendar.invite ADD CONSTRAINT FK_F517FFA7A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_calendar.calendar_to_persons DROP CONSTRAINT FK_AEE94715A40A2C8'); - $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals DROP CONSTRAINT FK_FADF2C77A40A2C8'); - $this->addSql('ALTER TABLE chill_calendar.calendar_to_thirdparties DROP CONSTRAINT FK_2BAB7EFDA40A2C8'); - $this->addSql('ALTER TABLE chill_calendar.calendar_to_invites DROP CONSTRAINT FK_FCBEAAAA40A2C8'); - $this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315ACC5CB285D'); - $this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315ACE980772F'); - $this->addSql('ALTER TABLE chill_calendar.calendar_to_invites DROP CONSTRAINT FK_FCBEAAAEA417747'); - $this->addSql('DROP SEQUENCE chill_calendar.calendar_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_calendar.calendar_range_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_calendar.cancel_reason_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_calendar.invite_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_calendar.calendar'); - $this->addSql('DROP TABLE chill_calendar.calendar_to_persons'); - $this->addSql('DROP TABLE chill_calendar.calendar_to_non_professionals'); - $this->addSql('DROP TABLE chill_calendar.calendar_to_thirdparties'); - $this->addSql('DROP TABLE chill_calendar.calendar_to_invites'); - $this->addSql('DROP TABLE chill_calendar.calendar_range'); - $this->addSql('DROP TABLE chill_calendar.cancel_reason'); - $this->addSql('DROP TABLE chill_calendar.invite'); - $this->addSql('DROP SCHEMA chill_calendar'); - } } diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php b/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php index b90c4b1b5..ecafff926 100644 --- a/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php @@ -1,5 +1,12 @@ addSql('CREATE TABLE chill_calendar.calendar_to_non_professionals (calendar_id INT NOT NULL, person_id INT NOT NULL, PRIMARY KEY(calendar_id, person_id))'); + $this->addSql('CREATE INDEX idx_fadf2c77217bbb47 ON chill_calendar.calendar_to_non_professionals (person_id)'); + $this->addSql('CREATE INDEX idx_fadf2c77a40a2c8 ON chill_calendar.calendar_to_non_professionals (calendar_id)'); + $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals ADD CONSTRAINT fk_fadf2c77a40a2c8 FOREIGN KEY (calendar_id) REFERENCES chill_calendar.calendar (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals ADD CONSTRAINT fk_fadf2c77217bbb47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy TYPE JSON'); + $this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy DROP DEFAULT'); + } + public function getDescription(): string { return 'Adapt calendar entities'; @@ -24,15 +42,4 @@ final class Version20210723074557 extends AbstractMigration $this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledby DROP DEFAULT'); $this->addSql('COMMENT ON COLUMN chill_calendar.cancel_reason.canceledBy IS NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('CREATE TABLE chill_calendar.calendar_to_non_professionals (calendar_id INT NOT NULL, person_id INT NOT NULL, PRIMARY KEY(calendar_id, person_id))'); - $this->addSql('CREATE INDEX idx_fadf2c77217bbb47 ON chill_calendar.calendar_to_non_professionals (person_id)'); - $this->addSql('CREATE INDEX idx_fadf2c77a40a2c8 ON chill_calendar.calendar_to_non_professionals (calendar_id)'); - $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals ADD CONSTRAINT fk_fadf2c77a40a2c8 FOREIGN KEY (calendar_id) REFERENCES chill_calendar.calendar (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals ADD CONSTRAINT fk_fadf2c77217bbb47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy TYPE JSON'); - $this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy DROP DEFAULT'); - } } diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20210723142003.php b/src/Bundle/ChillCalendarBundle/migrations/Version20210723142003.php index 0af4fb1b8..f3a7e1928 100644 --- a/src/Bundle/ChillCalendarBundle/migrations/Version20210723142003.php +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20210723142003.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_calendar.calendar ALTER startDate TYPE DATE'); + $this->addSql('ALTER TABLE chill_calendar.calendar ALTER startDate DROP DEFAULT'); + $this->addSql('ALTER TABLE chill_calendar.calendar ALTER endDate TYPE DATE'); + $this->addSql('ALTER TABLE chill_calendar.calendar ALTER endDate DROP DEFAULT'); + $this->addSql('COMMENT ON COLUMN chill_calendar.calendar.startdate IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_calendar.calendar.enddate IS \'(DC2Type:date_immutable)\''); + } + public function getDescription(): string { return 'Alter startDate and endDate to datetimetz_immutable'; @@ -26,14 +43,4 @@ final class Version20210723142003 extends AbstractMigration $this->addSql('COMMENT ON COLUMN chill_calendar.calendar.startDate IS \'(DC2Type:datetimetz_immutable)\''); $this->addSql('COMMENT ON COLUMN chill_calendar.calendar.endDate IS \'(DC2Type:datetimetz_immutable)\''); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_calendar.calendar ALTER startDate TYPE DATE'); - $this->addSql('ALTER TABLE chill_calendar.calendar ALTER startDate DROP DEFAULT'); - $this->addSql('ALTER TABLE chill_calendar.calendar ALTER endDate TYPE DATE'); - $this->addSql('ALTER TABLE chill_calendar.calendar ALTER endDate DROP DEFAULT'); - $this->addSql('COMMENT ON COLUMN chill_calendar.calendar.startdate IS \'(DC2Type:date_immutable)\''); - $this->addSql('COMMENT ON COLUMN chill_calendar.calendar.enddate IS \'(DC2Type:date_immutable)\''); - } } diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20210723142842.php b/src/Bundle/ChillCalendarBundle/migrations/Version20210723142842.php index 5b77338c3..eb055a27e 100644 --- a/src/Bundle/ChillCalendarBundle/migrations/Version20210723142842.php +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20210723142842.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_calendar.calendar_range ALTER startDate TYPE DATE'); + $this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER startDate DROP DEFAULT'); + $this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER endDate TYPE DATE'); + $this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER endDate DROP DEFAULT'); + $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.startdate IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.enddate IS \'(DC2Type:date_immutable)\''); + } + public function getDescription(): string { return 'Alter startDate and endDate to datetimetz_immutable on calendarRange'; @@ -26,14 +43,4 @@ final class Version20210723142842 extends AbstractMigration $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.startDate IS \'(DC2Type:datetimetz_immutable)\''); $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.endDate IS \'(DC2Type:datetimetz_immutable)\''); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER startDate TYPE DATE'); - $this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER startDate DROP DEFAULT'); - $this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER endDate TYPE DATE'); - $this->addSql('ALTER TABLE chill_calendar.calendar_range ALTER endDate DROP DEFAULT'); - $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.startdate IS \'(DC2Type:date_immutable)\''); - $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.enddate IS \'(DC2Type:date_immutable)\''); - } } diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20211119173557.php b/src/Bundle/ChillCalendarBundle/migrations/Version20211119173557.php index 002bfd1ae..2567557e8 100644 --- a/src/Bundle/ChillCalendarBundle/migrations/Version20211119173557.php +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20211119173557.php @@ -1,5 +1,12 @@ throwIrreversibleMigrationException(); + } + public function getDescription(): string { return 'remove comment on deprecated json_array type'; @@ -22,12 +34,7 @@ final class Version20211119173557 extends AbstractMigration ]; foreach ($columns as $col) { - $this->addSql("COMMENT ON COLUMN $col IS NULL"); + $this->addSql("COMMENT ON COLUMN {$col} IS NULL"); } } - - public function down(Schema $schema): void - { - $this->throwIrreversibleMigrationException(); - } } 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 */ @@ -61,15 +53,9 @@ class CreateFieldsOnGroupCommand extends Command */ private $validator; - private $availableLanguages; - private $customizablesEntities; - /** * CreateFieldsOnGroupCommand constructor. * - * @param CustomFieldProvider $customFieldProvider - * @param EntityManager $entityManager - * @param ValidatorInterface $validator * @param $availableLanguages * @param $customizablesEntities */ @@ -92,14 +78,21 @@ class CreateFieldsOnGroupCommand extends Command { $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 */ @@ -113,9 +106,7 @@ class CreateFieldsOnGroupCommand extends Command } /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int|null|void + * @return int|void|null */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -139,108 +130,62 @@ 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 CustomFieldsGroup'); + + 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])) ? @@ -250,14 +195,64 @@ class CreateFieldsOnGroupCommand extends Command 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..856ac8ae9 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php @@ -1,57 +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 . + * 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; +use function LogicException; -/** - * - * - * @author Julien Fastré - * @author Marc Ducobu - */ 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 +46,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 +101,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 +119,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 +163,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 +353,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 +375,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..10842c43b 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'); + 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 85eba7071..233b11ed0 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php @@ -1,28 +1,36 @@ 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' => static fn (Option $key): ?int => $key === null ? null : $key->getId(), + 'choice_value' => static fn (Option $key): ?int => null === $key ? null : $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()); } return $translatableStringHelper->localize($option->getText()); }, - 'label' => $translatableStringHelper->localize($customField->getName()) - )); + 'label' => $translatableStringHelper->localize($customField->getName()), + ]); $builder ->get($customField->getSlug()) @@ -70,25 +81,24 @@ class CustomFieldLongChoice extends AbstractCustomField { //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); } @@ -97,32 +107,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..e66a512d9 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php @@ -1,69 +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\CustomFieldsBundle\CustomFields; -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; +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; /** * 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 +59,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 +106,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 +122,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..8e2e9a80f 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,55 @@ 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 +98,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 44af7a6fe..f8cf11e8e 100644 --- a/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/ChillCustomFieldsExtension.php +++ b/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/ChillCustomFieldsExtension.php @@ -1,29 +1,33 @@ 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'); @@ -34,15 +38,19 @@ class ChillCustomFieldsExtension extends Extension implements PrependExtensionIn // && $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() - */ + /* (non-PHPdoc) + * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() + */ public function prepend(ContainerBuilder $container) { // add form layout to twig resources @@ -54,12 +62,12 @@ class ChillCustomFieldsExtension extends Extension implements PrependExtensionIn $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 8472896eb..74d8270cd 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,16 +12,36 @@ 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") @@ -41,6 +49,34 @@ class CustomField */ private $id; + /** + * @var array + * + * @ORM\Column(type="json") + */ + private $name; + + /** + * @var array + * + * @ORM\Column(type="json") + */ + private $options = []; + + /** + * @var float + * + * @ORM\Column(type="float") + */ + private $ordering; + + /** + * @var bool + * + * @ORM\Column(type="boolean") + */ + private $required = false; + /** * @var string * @@ -56,57 +92,19 @@ class CustomField private $type; /** - * @var boolean + * Get customFieldGroup. * - * @ORM\Column(type="boolean") + * @return CustomFieldsGroup */ - private $active = true; + public function getCustomFieldsGroup() + { + return $this->customFieldGroup; + } /** - * @var array + * Get id. * - * @ORM\Column(type="json") - */ - private $options = array(); - - /** - * @var array - * - * @ORM\Column(type="json") - */ - private $name; - - /** - * @var float - * - * @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() { @@ -114,36 +112,69 @@ class CustomField } /** - * @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 + * Get order. * - * @param string $type - * @return CustomField + * @return float */ - public function setType($type) + public function getOrdering() { - $this->type = $type; - - return $this; + return $this->ordering; } /** - * Get type + * 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; } + /** + * Returns true if the custom field is active. + * + * @return bool + */ + public function isActive() + { + return $this->active; + } /** - * Set 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,57 +246,8 @@ class CustomField } /** - * Get name + * Set options. * - * @return array - */ - 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 order - * - * @param float $order - * @return CustomField - */ - public function setOrdering($order) - { - $this->ordering = $order; - - return $this; - } - - /** - * Get order - * - * @return float - */ - public function getOrdering() - { - return $this->ordering; - } - - /** - * Set options - * - * @param array $options * @return CustomField */ public function setOptions(array $options) @@ -274,39 +258,49 @@ class CustomField } /** - * @param $slug - * @return $this + * Set order. + * + * @param float $order + * + * @return CustomField */ - public function setSlug($slug) + public function setOrdering($order) { - $this->slug = $slug; + $this->ordering = $order; + 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) { $this->required = $required; + return $this; } + /** + * @param $slug + * + * @return $this + */ + public function setSlug($slug) + { + $this->slug = $slug; + + return $this; + } + + /** + * Set type. + * + * @param string $type + * + * @return CustomField + */ + public function setType($type) + { + $this->type = $type; + + return $this; + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php index ee3eae24f..fbcfb644a 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,15 +14,27 @@ 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") @@ -40,6 +42,12 @@ class Option */ private $id; + /** + * @var string + * @ORM\Column(type="string", length=50, name="internal_key") + */ + private $internalKey = ''; + /** * @var string * @ORM\Column(type="string", length=15) @@ -47,7 +55,16 @@ class Option private $key; /** - * A json representation of text (multilingual) + * @var Option + * @ORM\ManyToOne( + * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option", + * inversedBy="children") + * @ORM\JoinColumn(nullable=true) + */ + private $parent; + + /** + * A json representation of text (multilingual). * * @var array * @ORM\Column(type="json") @@ -55,33 +72,20 @@ class Option private $text; /** - * @var Collection - * @ORM\OneToMany( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option", - * mappedBy="parent") + * @return bool */ - private $children; + public function getActive() + { + return $this->isActive(); + } /** - * @var Option - * @ORM\ManyToOne( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option", - * inversedBy="children") - * @ORM\JoinColumn(nullable=true) + * @return Collection */ - private $parent; - - /** - * @var string - * @ORM\Column(type="string", length=50, name="internal_key") - */ - private $internalKey = ''; - - /** - * @var boolean - * @ORM\Column(type="boolean") - */ - private $active = true; + public function getChildren() + { + return $this->children; + } /** * @return int @@ -91,6 +95,14 @@ class Option return $this->id; } + /** + * @return string + */ + public function getInternalKey() + { + return $this->internalKey; + } + /** * @return string */ @@ -99,22 +111,6 @@ class Option return $this->key; } - /** - * @return array - */ - public function getText() - { - return $this->text; - } - - /** - * @return Collection - */ - public function getChildren() - { - return $this->children; - } - /** * @return Option */ @@ -124,51 +120,19 @@ class Option } /** - * @param $key - * @return $this + * @return array */ - public function setKey($key) + public function getText() { - $this->key = $key; - return $this; + return $this->text; } /** - * @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 + * @return bool */ public function hasParent() { - return $this->parent === NULL ? false : true; - } - - /** - * @return string - */ - public function getInternalKey() - { - return $this->internalKey; + return null === $this->parent ? false : true; } /** @@ -179,32 +143,60 @@ class Option return $this->active; } - /** - * @return bool - */ - public function getActive() - { - return $this->isActive(); - } - - /** - * @param $internal_key - * @return $this - */ - public function setInternalKey($internal_key) - { - $this->internalKey = $internal_key; - return $this; - } - /** * @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 db484b9de..3c61a70f1 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,41 +65,12 @@ 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") */ - 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); } } @@ -144,9 +113,27 @@ class CustomFieldsGroup } /** - * 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 ''; + return ''; + } - } else { - return $this->name; - } + 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; + $this->name = $name; + + return $this; } /** - * get options array + * set options array. * - * @return array - */ - public function getOptions() - { - return $this->options; - } - - /** - * set options array - * - * @param array $options * @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 138254fbc..3055e64d2 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php @@ -1,22 +1,26 @@ 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) { + function (FormEvent $event) use ($customizableEntities, $builder) { $form = $event->getForm(); $group = $event->getData(); //stop the function if entity is not set - if ($group->getEntity() === NULL) { + if ($group->getEntity() === null) { return; } $optionBuilder = null; + if (count($customizableEntities[$group->getEntity()]['options']) > 0) { $optionBuilder = $builder ->getFormFactory() @@ -75,11 +75,11 @@ class CustomFieldsGroupType extends AbstractType [ 'compound' => true, 'auto_initialize' => false, - 'required' => false + 'required' => false, ] ); - foreach($customizableEntities[$group->getEntity()]['options'] as $key => $option) { + foreach ($customizableEntities[$group->getEntity()]['options'] as $key => $option) { $optionBuilder->add($key, $option['form_type'], $option['form_options']); } } @@ -87,7 +87,8 @@ class CustomFieldsGroupType extends AbstractType if ((null !== $optionBuilder) && $optionBuilder->count() > 0) { $form->add($optionBuilder->getForm()); } - }); + } + ); } public function configureOptions(OptionsResolver $resolver) 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 31708b582..0600264f5 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) { @@ -61,7 +44,7 @@ class CustomFieldsGroupToIdTransformer implements DataTransformerInterface 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' @@ -70,8 +53,7 @@ class CustomFieldsGroupToIdTransformer implements DataTransformerInterface } $customFieldsGroup = $this->om - ->getRepository(CustomFieldsGroup::class)->find($id) - ; + ->getRepository(CustomFieldsGroup::class)->find($id); if (null === $customFieldsGroup) { throw new TransformationFailedException( @@ -84,4 +66,31 @@ class CustomFieldsGroupToIdTransformer implements DataTransformerInterface return $customFieldsGroup; } + + /** + * 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 2d04c036d..b41586c99 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/JsonCustomFieldToArrayTransformer.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/JsonCustomFieldToArrayTransformer.php @@ -1,18 +1,26 @@ om = $om; @@ -23,56 +31,15 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface { // @TODO: in the array_map callback, CustomField::getLabel() does not exist. What do we do here? $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) { - $customFieldsArray = []; - } else { - $customFieldsArray = json_decode($customFieldsJSON, true, 512, JSON_THROW_ON_ERROR); - } - - $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) { /* @@ -86,23 +53,25 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface { 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) { + if (strpos($type, 'ManyToOnePersist') === 0) { // PEUT ETRE A FAIRE SI SEULEMENT $value->getId() ne renvoie rien... // // @@ -123,14 +92,57 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface { } } - if(! $traited) { + if (!$traited) { $customFieldsArrayRet[$key] = $value; } - } //echo json_encode($customFieldsArrayRet); return json_encode($customFieldsArrayRet); } + + public function transform($customFieldsJSON) + { + echo $customFieldsJSON; + + if (null === $customFieldsJSON) { + $customFieldsArray = []; + } else { + $customFieldsArray = json_decode($customFieldsJSON, true, 512, JSON_THROW_ON_ERROR); + } + + $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..a005af73c 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesListType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesListType.php @@ -1,35 +1,42 @@ 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 +45,9 @@ class ChoicesListType extends AbstractType $data['slug'] = $formData['slug']; $event->setData($data); } - }) - ; + }); } - /* * * @see \Symfony\Component\Form\FormTypeInterface::getName() @@ -51,5 +56,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/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php b/src/Bundle/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php index 350290b08..9e3570708 100644 --- a/src/Bundle/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php +++ b/src/Bundle/ChillDocGeneratorBundle/ChillDocGeneratorBundle.php @@ -1,5 +1,12 @@ [], + 'cloneRowAndSetValues' => [], + ]; + + $persons = $entity->getAccompanyingPeriodWork()->getPersons(); + + if (sizeof($persons) > 0) { + $firstPerson = $persons[0]; + + $datas['setValues'][] = [ + 'firstPersonFirstName' => $firstPerson->getFirstName(), + 'firstPersonLastName' => $firstPerson->getLastName(), ]; + } + + if (get_class($entity) == AccompanyingPeriodWorkEvaluation::class) { + $values = []; + + foreach ($entity->getAccompanyingPeriodWork()->getPersons() as $person) { + $i = 1; + $values[] = [ + 'personRowId' => $i, + 'personFirstName' => $person->getFirstName(), + 'personLastName' => $person->getLastName(), + ]; + } + + $datas['cloneRowAndSetValues'][] = [ + 'personRowId', $values, ]; + } + + return $datas; } /** - * Generate the form that display + * Generate the form that display. + * + * @param mixed $entity */ - public function getForm($entity) { - throw new \Exception("No implemented yet", 1); - + public function getForm($entity) + { + throw new Exception('No implemented yet', 1); $choices = []; - if(get_class($entity) == AccompanyingPeriodWorkEvaluation::class) { + + if (get_class($entity) == AccompanyingPeriodWorkEvaluation::class) { foreach ($entity->getAccompanyingPeriodWork()->getPersons() as $person) { $choices[$person->getId()] = $person->getName(); } @@ -34,56 +79,27 @@ class HouseholdMemberSelectionContext implements DocGeneratorContextInterface $builder->add('members', ChoiceType::class, [ 'choices' => $choices, 'placeholder' => 'Choose a person', - 'label' => 'Person to add' + 'label' => 'Person to add', ]); return $builder; } /** - * True of false which entity supports + * has form. */ - public function supports(string $entityClass): bool { - return - ($entityClass == AccompanyingPeriod::class) || - ($entityClass == SocialAction::class); + public function hasForm(): bool + { + return true; } /** - * Get the data that will be injected to the generated document + * True of false which entity supports. */ - public function getData($entity): array { - $datas = array( - 'setValues' => array(), - 'cloneRowAndSetValues' => array() - ); - - $persons = $entity->getAccompanyingPeriodWork()->getPersons(); - - if(sizeof($persons) > 0) { - $firstPerson = $persons[0]; - - $datas['setValues'][] = array( - 'firstPersonFirstName' => $firstPerson->getFirstName(), - 'firstPersonLastName' => $firstPerson->getLastName(),); - } - - - if(get_class($entity) == AccompanyingPeriodWorkEvaluation::class) { - $values = array(); - foreach($entity->getAccompanyingPeriodWork()->getPersons() as $person) { - $i = 1; - $values[] = array( - 'personRowId' => $i, - 'personFirstName' => $person->getFirstName(), - 'personLastName' => $person->getLastName(), - ); - } - - $datas['cloneRowAndSetValues'][] = array( - 'personRowId', $values); - } - - return $datas; + public function supports(string $entityClass): bool + { + return + (AccompanyingPeriod::class == $entityClass) + || (SocialAction::class == $entityClass); } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php b/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php index 0b870a34e..c7ac94744 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php +++ b/src/Bundle/ChillDocGeneratorBundle/Controller/AdminDocGeneratorTemplateController.php @@ -1,5 +1,12 @@ setContent('Test'); - } - - /** - * @Route( - * "{_locale}/doc/gen/test", - * name="chill_docgenerator_test" - * ) - * - * @param Request $request - * @return \Symfony\Component\HttpFoundation\Response - */ - public function getDoc(Request $request, TempUrlOpenstackGenerator $tempUrlGenerator) + public function getDoc(Request $request, TempUrlOpenstackGenerator $tempUrlGenerator): Response { $p = $tempUrlGenerator->generate( - 'GET', - 'FORMULAIRE_AEB.docx', - $request->query->has('expires_delay') ? $request->query->getInt('expires_delay', 0) : null - ); + 'GET', + 'FORMULAIRE_AEB.docx', + $request->query->has('expires_delay') ? $request->query->getInt('expires_delay', 0) : null + ); $tmpfname = tempnam(sys_get_temp_dir(), 'DOC_TEMPLATE'); - file_put_contents($tmpfname, file_get_contents($p->{"url"})); + file_put_contents($tmpfname, file_get_contents($p->url)); $templateProcessor = new TemplateProcessor($tmpfname); - $templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe')); + $templateProcessor->setValues(['firstname' => 'John', 'lastname' => 'Doe']); $tmpfname2 = tempnam(sys_get_temp_dir(), 'DOC_GENERATED'); $templateProcessor->saveAs($tmpfname2); @@ -73,4 +60,15 @@ class DocGeneratorController extends AbstractController return $response; } + + /** + * @Route( + * "{_locale}/doc/gen/test", + * name="chill_docgenerator_test" + * ) + */ + public function testAction(): Response + { + return (new Response())->setContent('Test'); + } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php index d82d8a0a7..dd9d8e635 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php +++ b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php @@ -1,58 +1,36 @@ findByEntity($entityClassName); - - $ret = array(); - - foreach ($entities as $entity) { - $ret[] = array( - 'id' => $entity->getId(), - 'name' => $entity->getName(), - 'description' => $entity->getDescription() - ); - } - - return new JsonResponse(["results" => $ret]); - } - /** * @Route( * "{_locale}/doc/gen/generate/from/{template}/for/{entityClassName}/{entityId}", @@ -60,7 +38,7 @@ class DocGeneratorTemplateController extends AbstractController * ) */ public function generateDocFromTemplateAction( - \ChampsLibres\AsyncUploaderBundle\TempUrl\TempUrlGeneratorInterface $tempUrlGenerator, + TempUrlGeneratorInterface $tempUrlGenerator, DocGeneratorTemplate $template, string $entityClassName, int $entityId, @@ -68,10 +46,11 @@ class DocGeneratorTemplateController extends AbstractController ): Response { $getUrlGen = $tempUrlGenerator->generate( 'GET', - $template->getFile()); + $template->getFile() + ); $tmpfname = tempnam(sys_get_temp_dir(), 'DOC_TEMPLATE'); - file_put_contents($tmpfname, file_get_contents($getUrlGen->{"url"})); + file_put_contents($tmpfname, file_get_contents($getUrlGen->url)); $entity = $this->getDoctrine()->getRepository($entityClassName)->find($entityId); @@ -79,7 +58,7 @@ class DocGeneratorTemplateController extends AbstractController $context = new HouseholdMemberSelectionContext(); $datas = $context->getData($entity); } else { - throw new \Exception("Not implemented", 1); + throw new Exception('Not implemented', 1); } $templateProcessor = new TemplateProcessor($tmpfname); @@ -103,15 +82,16 @@ class DocGeneratorTemplateController extends AbstractController $getUrlGen = $tempUrlGenerator->generate( 'PUT', - $genDocName); + $genDocName + ); unlink($tmpfname2); $client = new Client(); try { - $putResponse = $client->request('PUT', $getUrlGen->{'url'}, [ - 'body' => $fileContent + $putResponse = $client->request('PUT', $getUrlGen->url, [ + 'body' => $fileContent, ]); if ($putResponse->getStatusCode() == 201) { @@ -129,8 +109,7 @@ class DocGeneratorTemplateController extends AbstractController $doc = new AccompanyingPeriodWorkEvaluationDocument(); $doc ->setStoredObject($storedObject) - ->setTemplate($template) - ; + ->setTemplate($template); $entity->addDocument($doc); $em->persist($doc); } @@ -139,13 +118,38 @@ class DocGeneratorTemplateController extends AbstractController return $this->redirectToRoute('chill_wopi_file_edit', [ 'fileId' => $storedObject->getUuid(), - 'returnPath' => $request->query->get('returnPath', "/") + 'returnPath' => $request->query->get('returnPath', '/'), ]); } } catch (TransferException $e) { throw $e; } - throw new \Exception('Unable to generate document.'); + throw new Exception('Unable to generate document.'); + } + + /** + * @Route( + * "{_locale}/doc/gen/templates/for/{entityClassName}", + * name="chill_docgenerator_templates_for_entity_api" + * ) + */ + public function listTemplateApiAction( + string $entityClassName, + DocGeneratorTemplateRepository $templateRepository + ): Response { + $entities = $templateRepository->findByEntity($entityClassName); + + $ret = []; + + foreach ($entities as $entity) { + $ret[] = [ + 'id' => $entity->getId(), + 'name' => $entity->getName(), + 'description' => $entity->getDescription(), + ]; + } + + return new JsonResponse(['results' => $ret]); } } diff --git a/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php b/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php index 06d26a446..32ba194b3 100644 --- a/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php +++ b/src/Bundle/ChillDocGeneratorBundle/DataFixtures/ORM/LoadDocGeneratorTemplate.php @@ -1,23 +1,25 @@ setName($template['name']) ->setDescription($template['desc']) ->setFile($template['file']) ->setContext($template['context']) - ->setEntities($template['entities']) - ; + ->setEntities($template['entities']); $manager->persist($newTemplate); diff --git a/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/ChillDocGeneratorExtension.php b/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/ChillDocGeneratorExtension.php index dfa604d9e..70640b73d 100644 --- a/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/ChillDocGeneratorExtension.php +++ b/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/ChillDocGeneratorExtension.php @@ -1,26 +1,30 @@ load('services.yaml'); $loader->load('services/controller.yaml'); $loader->load('services/fixtures.yaml'); @@ -33,20 +37,6 @@ class ChillDocGeneratorExtension extends Extension implements PrependExtensionIn $this->prependCruds($container); } - protected function preprendRoutes(ContainerBuilder $container) - { - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillDocGeneratorBundle/config/routes.yaml' - ) - ) - )); - } - - /** - * @param ContainerBuilder $container - */ protected function prependCruds(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ @@ -60,19 +50,30 @@ class ChillDocGeneratorExtension extends Extension implements PrependExtensionIn 'actions' => [ 'index' => [ 'template' => '@ChillDocGenerator/Admin/DocGeneratorTemplate/index.html.twig', - 'role' => 'ROLE_ADMIN' + 'role' => 'ROLE_ADMIN', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillDocGenerator/Admin/DocGeneratorTemplate/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillDocGenerator/Admin/DocGeneratorTemplate/edit.html.twig', - ] - ] - ] - ] + ], + ], + ], + ], + ]); + } + + protected function preprendRoutes(ContainerBuilder $container) + { + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillDocGeneratorBundle/config/routes.yaml', + ], + ], ]); } } diff --git a/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/Configuration.php index def8043a4..4d8e46464 100644 --- a/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillDocGeneratorBundle/DependencyInjection/Configuration.php @@ -1,5 +1,12 @@ context; + } + public function getDescription(): ?string + { + return $this->description; + } - /** - * @ORM\Column(type="simple_array") - * - * Class name of the entities for which this template can be used - * - * so if $entities = ['Chill\PersonBundle\Entity\AccompanyingPeriod', 'Chill\PersonBundle\Entity\SocialWork\SocialAction'] - * this template can be selected for an AccompanyingPeriod or a SocialAction - */ - private array $entities = []; + public function getEntities(): ?array + { + return $this->entities; + } - - /** - * @ORM\Column(type="string", length=255) - * - * Class name of the context to use - * - * so if $context = '' - * this template will use '' as context - */ - private string $context; - - /** - * @ORM\Column(type="string", length=255) - */ - private string $file; + public function getFile(): ?string + { + return $this->file; + } public function getId(): ?int { @@ -68,18 +92,13 @@ class DocGeneratorTemplate return $this->name; } - public function setName(array $name): self + public function setContext(string $context): self { - $this->name = $name; + $this->context = $context; return $this; } - public function getDescription(): ?string - { - return $this->description; - } - public function setDescription(?string $description): self { $this->description = $description; @@ -87,9 +106,11 @@ class DocGeneratorTemplate return $this; } - public function getFile(): ?string + public function setEntities(array $entities): self { - return $this->file; + $this->entities = $entities; + + return $this; } public function setFile(string $file): self @@ -99,26 +120,9 @@ class DocGeneratorTemplate return $this; } - public function getEntities(): ?array + public function setName(array $name): self { - return $this->entities; - } - - public function setEntities(array $entities): self - { - $this->entities = $entities; - - return $this; - } - - public function getContext(): ?string - { - return $this->context; - } - - public function setContext(string $context): self - { - $this->context = $context; + $this->name = $name; return $this; } diff --git a/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php b/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php index a0f36da0a..4735dbe3c 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php +++ b/src/Bundle/ChillDocGeneratorBundle/Form/DocGeneratorTemplateType.php @@ -1,38 +1,35 @@ add('name', TranslatableStringFormType::class, [ - 'label' => 'Nom' + 'label' => 'Nom', ]) ->add('description') - ->add('file') - ; + ->add('file'); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { $resolver - ->setDefault('class', DocGeneratorTemplate::class) - ; + ->setDefault('class', DocGeneratorTemplate::class); } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php b/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php index 1dc4f41f1..df0e0bd3d 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php +++ b/src/Bundle/ChillDocGeneratorBundle/Repository/DocGeneratorTemplateRepository.php @@ -1,13 +1,20 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?DocGeneratorTemplate - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return DocGeneratorTemplate[] */ @@ -37,26 +39,34 @@ final class DocGeneratorTemplateRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return DocGeneratorTemplate[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function findByEntity($entity) { - + public function findByEntity($entity) + { $builder = $this->repository->createQueryBuilder('t'); $builder ->where('t.entities LIKE :entity') - ->setParameter('entity', '%'.addslashes($entity).'%') - ; + ->setParameter('entity', '%' . addslashes($entity) . '%'); return $builder->getQuery()->execute(); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?DocGeneratorTemplate + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return DocGeneratorTemplate::class; } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Serializer/Encoder/DocGenEncoder.php b/src/Bundle/ChillDocGeneratorBundle/Serializer/Encoder/DocGenEncoder.php index da98504ae..c30155955 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Serializer/Encoder/DocGenEncoder.php +++ b/src/Bundle/ChillDocGeneratorBundle/Serializer/Encoder/DocGenEncoder.php @@ -1,19 +1,24 @@ isAssociative($data)) { - throw new UnexpectedValueException("Only associative arrays are allowed; lists are not allowed"); + throw new UnexpectedValueException('Only associative arrays are allowed; lists are not allowed'); } $result = []; @@ -22,11 +27,28 @@ class DocGenEncoder implements \Symfony\Component\Serializer\Encoder\EncoderInte return $result; } + public function supportsEncoding(string $format) + { + return 'docgen' === $format; + } + + private function canonicalizeKey(string $path, string $key): string + { + return '' === $path ? $key : $path . '_' . $key; + } + + private function isAssociative(array $data) + { + $keys = array_keys($data); + + return array_keys($keys) !== $keys; + } + private function recusiveEncoding(array $data, array &$result, $path) { if ($this->isAssociative($data)) { foreach ($data as $key => $value) { - if (\is_array($value)) { + if (is_array($value)) { $this->recusiveEncoding($value, $result, $this->canonicalizeKey($path, $key)); } else { $result[$this->canonicalizeKey($path, $key)] = $value; @@ -34,9 +56,8 @@ class DocGenEncoder implements \Symfony\Component\Serializer\Encoder\EncoderInte } } else { foreach ($data as $elem) { - if (!$this->isAssociative($elem)) { - throw new UnexpectedValueException(sprintf("Embedded loops are not allowed. See data under %s path", $path)); + throw new UnexpectedValueException(sprintf('Embedded loops are not allowed. See data under %s path', $path)); } $sub = []; @@ -45,25 +66,4 @@ class DocGenEncoder implements \Symfony\Component\Serializer\Encoder\EncoderInte } } } - - private function canonicalizeKey(string $path, string $key): string - { - return $path === '' ? $key : $path.'_'.$key; - } - - private function isAssociative(array $data) - { - $keys = \array_keys($data); - - return $keys !== \array_keys($keys); - } - - - /** - * @inheritDoc - */ - public function supportsEncoding(string $format) - { - return $format === 'docgen'; - } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php b/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php index be5e971d7..a55ee4b06 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php +++ b/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php @@ -1,8 +1,16 @@ normalizer->normalize(null, $format, \array_merge( + $data[$key] = $this->normalizer->normalize(null, $format, array_merge( $context, ['docgen:expects' => $class] )); + break; } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php index 08e2c63d9..81ddd97ca 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php +++ b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php @@ -1,8 +1,16 @@ propertyAccess = PropertyAccess::createPropertyAccessor(); } - /** - * @inheritDoc - */ - public function normalize($object, string $format = null, array $context = []) + public function normalize($object, ?string $format = null, array $context = []) { $classMetadataKey = $object ?? $context['docgen:expects']; if (!$this->classMetadataFactory->hasMetadataFor($classMetadataKey)) { - throw new LogicException(sprintf("This object does not have metadata: %s. Add groups on this entity to allow to serialize with the format %s and groups %s", is_object($object) ? get_class($object) : $context['docgen:expects'], $format, \implode(', ', $context['groups']))); + throw new LogicException(sprintf('This object does not have metadata: %s. Add groups on this entity to allow to serialize with the format %s and groups %s', is_object($object) ? get_class($object) : $context['docgen:expects'], $format, implode(', ', $context['groups']))); } $metadata = $this->classMetadataFactory->getMetadataFor($classMetadataKey); - $expectedGroups = \array_key_exists(AbstractNormalizer::GROUPS, $context) ? - \is_array($context[AbstractNormalizer::GROUPS]) ? $context[AbstractNormalizer::GROUPS] : [$context[AbstractNormalizer::GROUPS]] + $expectedGroups = array_key_exists(AbstractNormalizer::GROUPS, $context) ? + is_array($context[AbstractNormalizer::GROUPS]) ? $context[AbstractNormalizer::GROUPS] : [$context[AbstractNormalizer::GROUPS]] : []; - $attributes = \array_filter( + $attributes = array_filter( $metadata->getAttributesMetadata(), function (AttributeMetadata $a) use ($expectedGroups) { foreach ($a->getGroups() as $g) { - if (\in_array($g, $expectedGroups, true)) { + if (in_array($g, $expectedGroups, true)) { return true; } } return false; - }); + } + ); if (null === $object) { return $this->normalizeNullData($format, $context, $metadata, $attributes); @@ -62,11 +75,36 @@ class DocGenObjectNormalizer implements NormalizerInterface, NormalizerAwareInte return $this->normalizeObject($object, $format, $context, $expectedGroups, $metadata, $attributes); } + public function supportsNormalization($data, ?string $format = null): bool + { + return 'docgen' === $format && (is_object($data) || null === $data); + } + + private function getExpectedType(AttributeMetadata $attribute, ReflectionClass $reflection): string + { + // we have to get the expected content + if ($reflection->hasProperty($attribute->getName())) { + $type = $reflection->getProperty($attribute->getName())->getType(); + } elseif ($reflection->hasMethod($attribute->getName())) { + $type = $reflection->getMethod($attribute->getName())->getReturnType(); + } else { + throw new \LogicException(sprintf( + 'Could not determine how the content is determined for the attribute %s. Add attribute property only on property or method', + $attribute->getName() + )); + } + + if (null === $type) { + throw new \LogicException(sprintf( + 'Could not determine the type for this attribute: %s. Add a return type to the method or property declaration', + $attribute->getName() + )); + } + + return $type->getName(); + } + /** - * @param string $format - * @param array $context - * @param array $expectedGroups - * @param ClassMetadata $metadata * @param array|AttributeMetadata[] $attributes */ private function normalizeNullData(string $format, array $context, ClassMetadata $metadata, array $attributes): array @@ -83,15 +121,43 @@ class DocGenObjectNormalizer implements NormalizerInterface, NormalizerAwareInte return $normalizer->normalize($keys, $format, $context); } + /** + * @param mixed $format + */ + private function normalizeNullOutputValue($format, array $context, AttributeMetadata $attribute, ReflectionClass $reflection) + { + $type = $this->getExpectedType($attribute, $reflection); + + switch ($type) { + case 'array': + case 'bool': + case 'double': + case 'float': + case 'int': + case 'resource': + case 'string': + return ''; + + default: + return $this->normalizer->normalize( + null, + $format, + array_merge( + $context, + ['docgen:expects' => $type] + ) + ); + } + } + /** * @param $object * @param $format - * @param array $context - * @param array $expectedGroups - * @param ClassMetadata $metadata * @param array|AttributeMetadata[] $attributes - * @return array + * * @throws ExceptionInterface + * + * @return array */ private function normalizeObject($object, $format, array $context, array $expectedGroups, ClassMetadata $metadata, array $attributes) { @@ -105,8 +171,9 @@ class DocGenObjectNormalizer implements NormalizerInterface, NormalizerAwareInte if (is_object($value)) { $data[$key] = - $this->normalizer->normalize($value, $format, \array_merge( - $context, $attribute->getNormalizationContextForGroups($expectedGroups) + $this->normalizer->normalize($value, $format, array_merge( + $context, + $attribute->getNormalizationContextForGroups($expectedGroups) )); } elseif (null === $value) { $data[$key] = $this->normalizeNullOutputValue($format, $context, $attribute, $reflection); @@ -117,61 +184,4 @@ class DocGenObjectNormalizer implements NormalizerInterface, NormalizerAwareInte return $data; } - - private function getExpectedType(AttributeMetadata $attribute, \ReflectionClass $reflection): string - { - // we have to get the expected content - if ($reflection->hasProperty($attribute->getName())) { - $type = $reflection->getProperty($attribute->getName())->getType(); - } elseif ($reflection->hasMethod($attribute->getName())) { - $type = $reflection->getMethod($attribute->getName())->getReturnType(); - } else { - throw new \LogicException(sprintf( - "Could not determine how the content is determined for the attribute %s. Add attribute property only on property or method", $attribute->getName() - )); - } - - if (null === $type) { - throw new \LogicException(sprintf( - "Could not determine the type for this attribute: %s. Add a return type to the method or property declaration", $attribute->getName() - )); - } - - return $type->getName(); - } - - /** - */ - private function normalizeNullOutputValue($format, array $context, AttributeMetadata $attribute, \ReflectionClass $reflection) - { - $type = $this->getExpectedType($attribute, $reflection); - - switch ($type) { - case 'array': - case 'bool': - case 'double': - case 'float': - case 'int': - case 'resource': - case 'string': - return ''; - default: - return $this->normalizer->normalize( - null, - $format, - \array_merge( - $context, - ['docgen:expects' => $type] - ) - ); - } - } - - /** - * @inheritDoc - */ - public function supportsNormalization($data, string $format = null): bool - { - return $format === 'docgen' && (is_object($data) || null === $data); - } } diff --git a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210805162522.php b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210805162522.php index 26a6c3d56..b11112bad 100644 --- a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210805162522.php +++ b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210805162522.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_docgen_template_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_docgen_template'); + } + public function getDescription(): string { return 'Creation of table for storing DocGenTemplate'; @@ -22,10 +35,4 @@ final class Version20210805162522 extends AbstractMigration $this->addSql('CREATE SEQUENCE chill_docgen_template_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE chill_docgen_template (id INT NOT NULL, name JSON NOT NULL, description TEXT DEFAULT NULL, file VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP SEQUENCE chill_docgen_template_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_docgen_template'); - } } diff --git a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php index 363c94938..c6a7223e4 100644 --- a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php +++ b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_docgen_template DROP entities'); + $this->addSql('ALTER TABLE chill_docgen_template DROP context'); + $this->addSql('COMMENT ON COLUMN chill_docgen_template.name IS NULL'); + } + public function getDescription(): string { return 'Add entities and context fields to DocGenTemplate'; @@ -23,11 +37,4 @@ final class Version20210812214310 extends AbstractMigration $this->addSql('ALTER TABLE chill_docgen_template ADD context VARCHAR(255)'); $this->addSql('COMMENT ON COLUMN chill_docgen_template.entities IS \'(DC2Type:simple_array)\''); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_docgen_template DROP entities'); - $this->addSql('ALTER TABLE chill_docgen_template DROP context'); - $this->addSql('COMMENT ON COLUMN chill_docgen_template.name IS NULL'); - } } diff --git a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211119173556.php b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211119173556.php index 947628ef8..17deb2352 100644 --- a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211119173556.php +++ b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20211119173556.php @@ -1,5 +1,12 @@ throwIrreversibleMigrationException(); + } + public function getDescription(): string { return 'remove comment on deprecated json_array type'; @@ -17,16 +29,11 @@ final class Version20211119173556 extends AbstractMigration public function up(Schema $schema): void { $columns = [ - 'chill_docgen_template.name' + 'chill_docgen_template.name', ]; foreach ($columns as $col) { - $this->addSql("COMMENT ON COLUMN $col IS NULL"); + $this->addSql("COMMENT ON COLUMN {$col} IS NULL"); } } - - public function down(Schema $schema): void - { - $this->throwIrreversibleMigrationException(); - } } diff --git a/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Encoder/DocGenEncoderTest.php b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Encoder/DocGenEncoderTest.php index a6267e489..9ccf2a002 100644 --- a/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Encoder/DocGenEncoderTest.php +++ b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Encoder/DocGenEncoderTest.php @@ -1,12 +1,22 @@ encoder = new DocGenEncoder(); } - /** - * @dataProvider generateEncodeData - */ - public function testEncode($expected, $data, string $msg) - { - $generated = $this->encoder->encode($data, 'docgen'); - $this->assertEquals($expected, $generated, $msg); - } - - public function testEmbeddedLoopsThrowsException() - { - $this->expectException(UnexpectedValueException::class); - - $data = [ - 'data' => [ - ['item' => 'one'], - [ - 'embedded' => [ - [ - ['subitem' => 'two'], - ['subitem' => 'three'] - ] - ] - ], - ] - ]; - - $this->encoder->encode($data, 'docgen'); - } - public function generateEncodeData() { - yield [ ['tests' => 'ok'], ['tests' => 'ok'], "A simple test with a simple array"]; - - yield [ - // expected: - ['item_subitem' => 'value'], - // data: - ['item' => ['subitem' => 'value']], - "A test with multidimensional array" - ]; - - yield [ - // expected: - [ 'data' => [['item' => 'one'], ['item' => 'two']] ], - // data: - [ 'data' => [['item' => 'one'], ['item' => 'two']] ], - "a list of items" - ]; + yield [['tests' => 'ok'], ['tests' => 'ok'], 'A simple test with a simple array']; yield [ // expected: - [ 'data' => [['item_subitem' => 'alpha'], ['item' => 'two']] ], + ['item_subitem' => 'value'], // data: - [ 'data' => [['item' => ['subitem' => 'alpha']], ['item' => 'two'] ] ], - "a list of items with multidimensional array inside item" + ['item' => ['subitem' => 'value']], + 'A test with multidimensional array', + ]; + + yield [ + // expected: + ['data' => [['item' => 'one'], ['item' => 'two']]], + // data: + ['data' => [['item' => 'one'], ['item' => 'two']]], + 'a list of items', + ]; + + yield [ + // expected: + ['data' => [['item_subitem' => 'alpha'], ['item' => 'two']]], + // data: + ['data' => [['item' => ['subitem' => 'alpha']], ['item' => 'two']]], + 'a list of items with multidimensional array inside item', ]; yield [ @@ -88,9 +68,9 @@ class DocGenEncoderTest extends TestCase 'father_firstname' => 'Marcel', 'father_lastname' => 'Dupont', 'father_dateOfBirth_long' => '10 novembre 1953', - 'father_dateOfBirth_short' => '10/11/1953' + 'father_dateOfBirth_short' => '10/11/1953', ], - ] + ], ], // data: [ @@ -98,16 +78,49 @@ class DocGenEncoderTest extends TestCase [ 'firstname' => 'Jonathan', 'lastname' => 'Dupont', - 'dateOfBirth' => [ 'long' => '16 juin 1981', 'short' => '16/06/1981'], + 'dateOfBirth' => ['long' => '16 juin 1981', 'short' => '16/06/1981'], 'father' => [ 'firstname' => 'Marcel', 'lastname' => 'Dupont', - 'dateOfBirth' => ['long' => '10 novembre 1953', 'short' => '10/11/1953'] - ] + 'dateOfBirth' => ['long' => '10 novembre 1953', 'short' => '10/11/1953'], + ], ], - ] + ], ], - "a longer list, with near real data inside and embedded associative arrays" + 'a longer list, with near real data inside and embedded associative arrays', ]; } + + public function testEmbeddedLoopsThrowsException() + { + $this->expectException(UnexpectedValueException::class); + + $data = [ + 'data' => [ + ['item' => 'one'], + [ + 'embedded' => [ + [ + ['subitem' => 'two'], + ['subitem' => 'three'], + ], + ], + ], + ], + ]; + + $this->encoder->encode($data, 'docgen'); + } + + /** + * @dataProvider generateEncodeData + * + * @param mixed $expected + * @param mixed $data + */ + public function testEncode($expected, $data, string $msg) + { + $generated = $this->encoder->encode($data, 'docgen'); + $this->assertEquals($expected, $generated, $msg); + } } diff --git a/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php index 4d0031f55..b54e67c89 100644 --- a/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php +++ b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php @@ -1,5 +1,12 @@ setMainCenter($center = new Center()); $center->setName('test'); - $normalized = $this->normalizer->normalize($user, 'docgen', [ AbstractNormalizer::GROUPS => ['docgen:read']]); + $normalized = $this->normalizer->normalize($user, 'docgen', [AbstractNormalizer::GROUPS => ['docgen:read']]); $expected = [ 'label' => 'User Test', 'email' => '', 'mainCenter' => [ - 'name' => 'test' - ] + 'name' => 'test', + ], ]; - $this->assertEquals($expected, $normalized, "test normalization fo an user"); - } - - public function testNormalizeWithNullValueEmbedded() - { - $user = new User(); - $user->setUsername('User Test'); - - $normalized = $this->normalizer->normalize($user, 'docgen', [ AbstractNormalizer::GROUPS => ['docgen:read']]); - $expected = [ - 'label' => 'User Test', - 'email' => '', - 'mainCenter' => [ - 'name' => '' - ] - ]; - - $this->assertEquals($expected, $normalized, "test normalization fo an user with null center"); + $this->assertEquals($expected, $normalized, 'test normalization fo an user'); } public function testNormalizeNullObjectWithObjectEmbedded() @@ -68,13 +61,27 @@ class DocGenObjectNormalizerTest extends KernelTestCase 'label' => '', 'email' => '', 'mainCenter' => [ - 'name' => '' - ] + 'name' => '', + ], ]; - $this->assertEquals($expected, $normalized, "test normalization for a null user"); - + $this->assertEquals($expected, $normalized, 'test normalization for a null user'); } + public function testNormalizeWithNullValueEmbedded() + { + $user = new User(); + $user->setUsername('User Test'); + $normalized = $this->normalizer->normalize($user, 'docgen', [AbstractNormalizer::GROUPS => ['docgen:read']]); + $expected = [ + 'label' => 'User Test', + 'email' => '', + 'mainCenter' => [ + 'name' => '', + ], + ]; + + $this->assertEquals($expected, $normalized, 'test normalization fo an user with null center'); + } } 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/DocumentAccompanyingCourseController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php index e0bcceef1..c355c9e97 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseController.php @@ -1,5 +1,12 @@ authorizationHelper = $authorizationHelper; } + /** + * @Route("/{id}", name="accompanying_course_document_delete", methods="DELETE") + */ + public function delete(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response + { + $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::DELETE, $document); + + if ($this->isCsrfTokenValid('delete' . $document->getId(), $request->request->get('_token'))) { + $em = $this->getDoctrine()->getManager(); + $em->remove($document); + $em->flush(); + } + + return $this->redirectToRoute( + 'accompanying_course_document_index', + ['accompanyingCourse' => $course->getId()] + ); + } + + /** + * @Route("/{id}/edit", name="accompanying_course_document_edit", methods="GET|POST") + */ + public function edit(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response + { + $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::UPDATE, $document); + + $document->setUser($this->getUser()); + $document->setDate(new DateTime('Now')); + + $form = $this->createForm( + AccompanyingCourseDocumentType::class, + $document + ); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->getDoctrine()->getManager()->flush(); + + $this->addFlash('success', $this->translator->trans('The document is successfully updated')); + + return $this->redirectToRoute( + 'accompanying_course_document_edit', + ['id' => $document->getId(), 'course' => $course->getId()] + ); + } + + if ($form->isSubmitted() and !$form->isValid()) { + $this->addFlash('error', $this->translator->trans('This form contains errors')); + } + + return $this->render( + 'ChillDocStoreBundle:AccompanyingCourseDocument:edit.html.twig', + [ + 'document' => $document, + 'form' => $form->createView(), + 'accompanyingCourse' => $course, + ] + ); + } + /** * @Route("/", name="accompanying_course_document_index", methods="GET") */ @@ -62,14 +122,14 @@ class DocumentAccompanyingCourseController extends AbstractController { $em = $this->getDoctrine()->getManager(); - if ($course === NULL) { + if (null === $course) { throw $this->createNotFoundException('Accompanying period not found'); } $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::SEE, $course); $documents = $em - ->getRepository("ChillDocStoreBundle:AccompanyingCourseDocument") + ->getRepository('ChillDocStoreBundle:AccompanyingCourseDocument') ->findBy( ['course' => $course], ['date' => 'DESC'] @@ -79,8 +139,9 @@ class DocumentAccompanyingCourseController extends AbstractController 'ChillDocStoreBundle:AccompanyingCourseDocument:index.html.twig', [ 'documents' => $documents, - 'accompanyingCourse' => $course - ]); + 'accompanyingCourse' => $course, + ] + ); } /** @@ -88,14 +149,14 @@ class DocumentAccompanyingCourseController extends AbstractController */ public function new(Request $request, AccompanyingPeriod $course): Response { - if ($course === NULL) { + if (null === $course) { throw $this->createNotFoundException('Accompanying period not found'); } $document = new AccompanyingCourseDocument(); $document->setUser($this->getUser()); $document->setCourse($course); - $document->setDate(new \DateTime('Now')); + $document->setDate(new DateTime('Now')); $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::CREATE, $document); @@ -104,18 +165,22 @@ class DocumentAccompanyingCourseController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { $this->denyAccessUnlessGranted( - 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', $document, - 'creation of this activity not allowed'); + 'CHILL_ACCOMPANYING_COURSE_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('accompanying_course_document_index', ['course' => $course->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:AccompanyingCourseDocument:new.html.twig', [ @@ -134,59 +199,7 @@ class DocumentAccompanyingCourseController extends AbstractController return $this->render( 'ChillDocStoreBundle:AccompanyingCourseDocument:show.html.twig', - ['document' => $document, 'accompanyingCourse' => $course]); - } - - /** - * @Route("/{id}/edit", name="accompanying_course_document_edit", methods="GET|POST") - */ - public function edit(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response - { - $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::UPDATE, $document); - - $document->setUser($this->getUser()); - $document->setDate(new \DateTime('Now')); - - $form = $this->createForm( - AccompanyingCourseDocumentType::class, $document); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->getDoctrine()->getManager()->flush(); - - $this->addFlash('success', $this->translator->trans("The document is successfully updated")); - - return $this->redirectToRoute( - 'accompanying_course_document_edit', - ['id' => $document->getId(), 'course' => $course->getId()]); - - } elseif ($form->isSubmitted() and !$form->isValid()) { - $this->addFlash('error', $this->translator->trans("This form contains errors")); - } - - return $this->render( - 'ChillDocStoreBundle:AccompanyingCourseDocument:edit.html.twig', - [ - 'document' => $document, - 'form' => $form->createView(), - 'accompanyingCourse' => $course, - ]); - } - - /** - * @Route("/{id}", name="accompanying_course_document_delete", methods="DELETE") - */ - public function delete(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response - { - $this->denyAccessUnlessGranted(AccompanyingCourseDocumentVoter::DELETE, $document); - - if ($this->isCsrfTokenValid('delete'.$document->getId(), $request->request->get('_token'))) { - $em = $this->getDoctrine()->getManager(); - $em->remove($document); - $em->flush(); - } - - return $this->redirectToRoute( - 'accompanying_course_document_index', ['accompanyingCourse' => $course->getId()]); + ['document' => $document, 'accompanyingCourse' => $course] + ); } } diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php index 301487fd7..a6147c4cd 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php @@ -1,9 +1,17 @@ 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(); + $em = $this->getDoctrine()->getManager(); $categories = $em->getRepository(DocumentCategory::class)->findAll(); return $this->render( @@ -68,64 +130,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 ec1773640..cda071963 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'), true)) { + if (in_array($scope->getName()['en'], ['administrative', 'social'], true)) { 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 " + printf( + 'Adding Person report acl to %s ' . "permission group, scope '%s' \n", - $permissionsGroup->getName(), $scope->getName()['en']); + $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 eac97b86e..51cd60636 100644 --- a/src/Bundle/ChillDocStoreBundle/DependencyInjection/ChillDocStoreExtension.php +++ b/src/Bundle/ChillDocStoreBundle/DependencyInjection/ChillDocStoreExtension.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.yaml'); $loader->load('services/media.yaml'); $loader->load('services/controller.yaml'); @@ -41,40 +45,40 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $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], + AccompanyingCourseDocumentVoter::UPDATE => [AccompanyingCourseDocumentVoter::SEE_DETAILS], + AccompanyingCourseDocumentVoter::CREATE => [AccompanyingCourseDocumentVoter::SEE_DETAILS], + AccompanyingCourseDocumentVoter::DELETE => [AccompanyingCourseDocumentVoter::SEE_DETAILS], + AccompanyingCourseDocumentVoter::SEE_DETAILS => [AccompanyingCourseDocumentVoter::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' - ) - ) - )); - } - - 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], - AccompanyingCourseDocumentVoter::UPDATE => [AccompanyingCourseDocumentVoter::SEE_DETAILS], - AccompanyingCourseDocumentVoter::CREATE => [AccompanyingCourseDocumentVoter::SEE_DETAILS], - AccompanyingCourseDocumentVoter::DELETE => [AccompanyingCourseDocumentVoter::SEE_DETAILS], - AccompanyingCourseDocumentVoter::SEE_DETAILS => [AccompanyingCourseDocumentVoter::SEE], - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillDocStoreBundle/config/routes.yaml', + '@ChampsLibresAsyncUploaderBundle/config/routes.yaml', + ], + ], + ]); } 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 35853fcd9..ffd08d80a 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php @@ -1,9 +1,14 @@ 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 c6376b805..251a7513d 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php @@ -1,36 +1,48 @@ creationDate = new \DateTime(); + $this->creationDate = new DateTime(); $this->uuid = Uuid::uuid4(); } - public function getId() - { - return $this->id; - } - - 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; + return $this->id; } - public function setType($type) + public function getIv() { - $this->type = $type; - - return $this; + return $this->iv; } - public function setDatas(array $datas) + public function getKeyInfos() { - $this->datas = $datas; - - return $this; + return $this->keyInfos; } /** @@ -141,28 +125,9 @@ class StoredObject implements AsyncFileInterface, Document return $this->getFilename(); } - public function getKeyInfos() + public function getType() { - return $this->keyInfos; - } - - public function getIv() - { - return $this->iv; - } - - public function setKeyInfos($keyInfos) - { - $this->keyInfos = $keyInfos; - - return $this; - } - - public function setIv($iv) - { - $this->iv = $iv; - - return $this; + return $this->type; } public function getUuid(): UuidInterface @@ -174,4 +139,46 @@ class StoredObject implements AsyncFileInterface, Document { return (string) $this->uuid; } + + 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/AccompanyingCourseDocumentRepository.php b/src/Bundle/ChillDocStoreBundle/EntityRepository/AccompanyingCourseDocumentRepository.php index 7b7f1c1b1..dfbd533d9 100644 --- a/src/Bundle/ChillDocStoreBundle/EntityRepository/AccompanyingCourseDocumentRepository.php +++ b/src/Bundle/ChillDocStoreBundle/EntityRepository/AccompanyingCourseDocumentRepository.php @@ -1,5 +1,12 @@ getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?AccompanyingCourseDocument @@ -48,5 +55,5 @@ class AccompanyingCourseDocumentRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillDocStoreBundle/EntityRepository/DocumentCategoryRepository.php b/src/Bundle/ChillDocStoreBundle/EntityRepository/DocumentCategoryRepository.php index 72c068d18..18370b470 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,7 +20,8 @@ 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 reset($array_res); diff --git a/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php b/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php index b1a113a0a..aae7c5435 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/AccompanyingCourseDocumentType.php @@ -1,73 +1,72 @@ 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('date', ChillDateType::class) //TODO : adapt to using AccompanyingCourseDocument categories. Currently there are none... - ->add('category', EntityType::class, array( + ->add('category', EntityType::class, [ 'placeholder' => 'Choose a document category', 'class' => 'ChillDocStoreBundle:DocumentCategory', 'query_builder' => function (EntityRepository $er) { @@ -78,9 +77,7 @@ class AccompanyingCourseDocumentType extends AbstractType 'choice_label' => function ($entity = null) { return $entity ? $this->translatableStringHelper->localize($entity->getName()) : ''; }, - )) - ; - + ]); } public function configureOptions(OptionsResolver $resolver) @@ -88,7 +85,7 @@ class AccompanyingCourseDocumentType 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 ]) 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..03d83c181 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php @@ -1,108 +1,115 @@ 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 4040fdc09..a26e1467f 100644 --- a/src/Bundle/ChillDocStoreBundle/Menu/MenuBuilder.php +++ b/src/Bundle/ChillDocStoreBundle/Menu/MenuBuilder.php @@ -1,19 +1,27 @@ translator = $translator; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { - switch($menuId) { + switch ($menuId) { case 'accompanyingCourse': $this->buildMenuAccompanyingCourse($menu, $parameters); + break; + 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"); } } - protected function buildMenuPerson(MenuItem $menu, array $parameters) + public static function getMenuIds(): array { - /* @var $person \Chill\PersonBundle\Entity\Person */ - $person = $parameters['person']; - - if ($this->security->isGranted(PersonDocumentVoter::SEE, $person)) { - $menu->addChild($this->translator->trans('Documents'), [ - 'route' => 'person_document_index', - 'routeParameters' => [ - 'person' => $person->getId() - ] - ]) - ->setExtras([ - 'order'=> 350 - ]); - } + return ['person', 'accompanyingCourse']; } - protected function buildMenuAccompanyingCourse(MenuItem $menu, array $parameters){ + private function buildMenuAccompanyingCourse(MenuItem $menu, array $parameters) + { $course = $parameters['accompanyingCourse']; if ($this->security->isGranted(AccompanyingCourseDocumentVoter::SEE, $course)) { $menu->addChild($this->translator->trans('Documents'), [ 'route' => 'accompanying_course_document_index', 'routeParameters' => [ - 'course' => $course->getId() - ] + 'course' => $course->getId(), + ], ]) ->setExtras([ - 'order' => 400 + 'order' => 400, ]); } } - public static function getMenuIds(): array + private function buildMenuPerson(MenuItem $menu, array $parameters) { - return [ 'person', 'accompanyingCourse' ]; + /* @var $person \Chill\PersonBundle\Entity\Person */ + $person = $parameters['person']; + + if ($this->security->isGranted(PersonDocumentVoter::SEE, $person)) { + $menu->addChild($this->translator->trans('Documents'), [ + 'route' => 'person_document_index', + 'routeParameters' => [ + 'person' => $person->getId(), + ], + ]) + ->setExtras([ + 'order' => 350, + ]); + } } } 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/Repository/StoredObjectRepository.php b/src/Bundle/ChillDocStoreBundle/Repository/StoredObjectRepository.php index 4da7b4ca9..118998a9c 100644 --- a/src/Bundle/ChillDocStoreBundle/Repository/StoredObjectRepository.php +++ b/src/Bundle/ChillDocStoreBundle/Repository/StoredObjectRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(StoredObject::class); } + public function find($id, $lockMode = null, $lockVersion = null): ?StoredObject + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + /** * @return array */ @@ -27,6 +39,9 @@ final class StoredObjectRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return array */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array @@ -43,9 +58,4 @@ final class StoredObjectRepository implements ObjectRepository { return StoredObject::class; } - - public function find($id, $lockMode = null, $lockVersion = null): ?StoredObject - { - return $this->repository->find($id, $lockMode, $lockVersion); - } } diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig index fbea1229a..dd0c9cc62 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/AccompanyingCourseDocument/index.html.twig @@ -62,7 +62,7 @@ diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentVoter.php index 53507d573..18377211c 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentVoter.php @@ -1,38 +1,47 @@ build(); } - public function getRoles() + public function getRoles(): array { return [ self::CREATE, self::SEE, self::SEE_DETAILS, self::UPDATE, - self::DELETE + self::DELETE, ]; } + public function getRolesWithHierarchy(): array + { + return ['accompanyingCourseDocument' => $this->getRoles()]; + } + + public function getRolesWithoutScope(): array + { + return []; + } + protected function supports($attribute, $subject) { return $this->voterHelper->supports($attribute, $subject); @@ -65,27 +84,29 @@ class AccompanyingCourseDocumentVoter extends AbstractChillVoter implements Prov 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; } - if ($subject instanceof AccompanyingCourseDocument - && !$this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getCourse())) { - return false; + if ($subject instanceof AccompanyingPeriod) { + if (AccompanyingPeriod::STEP_CLOSED === $subject->getStep()) { + if (self::CREATE === $attribute) { + return false; + } + } + } elseif ($subject instanceof AccompanyingCourseDocument) { + if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getCourse())) { + return false; + } + + if (AccompanyingPeriod::STEP_CLOSED === $subject->getCourse()->getStep() + && in_array($attribute, [self::CREATE, self::DELETE, self::UPDATE], true)) { + return false; + } } return $this->voterHelper->voteOnAttribute($attribute, $subject, $token); } - - public function getRolesWithoutScope() - { - return array(); - } - - public function getRolesWithHierarchy() - { - return ['accompanyingCourseDocument' => $this->getRoles() ]; - } } diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php index 73254278b..c1f945990 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php @@ -1,29 +1,42 @@ build(); } - public function getRoles() + public function getRoles(): array { return [ self::CREATE, self::SEE, self::SEE_DETAILS, self::UPDATE, - self::DELETE + self::DELETE, ]; } + public function getRolesWithHierarchy(): array + { + return ['PersonDocument' => $this->getRoles()]; + } + + public function getRolesWithoutScope(): array + { + return []; + } + protected function supports($attribute, $subject) { return $this->voterHelper->supports($attribute, $subject); } /** - * * @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; @@ -78,15 +100,4 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera return $this->voterHelper->voteOnAttribute($attribute, $subject, $token); } - - 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 97d971c6c..30e008d1f 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\'.'); @@ -27,12 +43,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 b0fae40fb..5a3034280 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\'.'); @@ -21,15 +41,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/ChillDocStoreBundle/migrations/Version20210903091534.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20210903091534.php index fa4182142..caf412f2d 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20210903091534.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20210903091534.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_doc.accompanyingcourse_document_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_doc.accompanyingcourse_document'); + } + public function getDescription(): string { return ''; @@ -24,10 +37,4 @@ final class Version20210903091534 extends AbstractMigration $this->addSql('CREATE INDEX IDX_A45098F6591CC992 ON chill_doc.accompanyingcourse_document (course_id)'); $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F6591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP SEQUENCE chill_doc.accompanyingcourse_document_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_doc.accompanyingcourse_document'); - } } diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20210903123835.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20210903123835.php index c91c7e173..d24474bde 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20210903123835.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20210903123835.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6369A0BE36EF62EFC'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6232D562B'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6682B5931'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6A76ED395'); + $this->addSql('DROP INDEX IDX_A45098F6369A0BE36EF62EFC'); + $this->addSql('DROP INDEX IDX_A45098F6232D562B'); + $this->addSql('DROP INDEX IDX_A45098F6682B5931'); + $this->addSql('DROP INDEX IDX_A45098F6A76ED395'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP category_bundle_id'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP category_id_inside_bundle'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP object_id'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP scope_id'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP user_id'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP title'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP description'); + $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP date'); + } + public function getDescription(): string { return ''; @@ -36,24 +63,4 @@ final class Version20210903123835 extends AbstractMigration $this->addSql('CREATE INDEX IDX_A45098F6682B5931 ON chill_doc.accompanyingcourse_document (scope_id)'); $this->addSql('CREATE INDEX IDX_A45098F6A76ED395 ON chill_doc.accompanyingcourse_document (user_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6369A0BE36EF62EFC'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6232D562B'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6682B5931'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6A76ED395'); - $this->addSql('DROP INDEX IDX_A45098F6369A0BE36EF62EFC'); - $this->addSql('DROP INDEX IDX_A45098F6232D562B'); - $this->addSql('DROP INDEX IDX_A45098F6682B5931'); - $this->addSql('DROP INDEX IDX_A45098F6A76ED395'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP category_bundle_id'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP category_id_inside_bundle'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP object_id'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP scope_id'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP user_id'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP title'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP description'); - $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP date'); - } } diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20210928182542.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20210928182542.php index 20d45ca37..cbafadc02 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20210928182542.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20210928182542.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_doc.stored_object DROP uuid'); + } + public function getDescription(): string { return 'Create UUID column on StoredObject table.'; @@ -22,9 +34,4 @@ final class Version20210928182542 extends AbstractMigration $this->addSql('ALTER TABLE chill_doc.stored_object ALTER uuid SET NOT NULL'); $this->addSql('CREATE UNIQUE INDEX UNIQ_49604E36D17F50A6 ON chill_doc.stored_object (uuid)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_doc.stored_object DROP uuid'); - } } diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20211119173558.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20211119173558.php index a66ddd52e..7d0b5e3e2 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20211119173558.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20211119173558.php @@ -1,4 +1,12 @@ throwIrreversibleMigrationException(); + } + public function getDescription(): string { return 'remove comment on deprecated json_array type'; @@ -23,12 +36,7 @@ final class Version20211119173558 extends AbstractMigration ]; foreach ($columns as $col) { - $this->addSql("COMMENT ON COLUMN $col IS NULL"); + $this->addSql("COMMENT ON COLUMN {$col} IS NULL"); } } - - public function down(Schema $schema): void - { - $this->throwIrreversibleMigrationException(); - } } 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..f9af30d8f 100644 --- a/src/Bundle/ChillEventBundle/Controller/EventTypeController.php +++ b/src/Bundle/ChillEventBundle/Controller/EventTypeController.php @@ -1,39 +1,28 @@ 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 +35,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 +72,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 +212,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 df69f5afa..fc0abada1 100644 --- a/src/Bundle/ChillEventBundle/Controller/ParticipationController.php +++ b/src/Bundle/ChillEventBundle/Controller/ParticipationController.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\EventBundle\Controller; use ArrayIterator; use Chill\EventBundle\Entity\Event; +use Chill\EventBundle\Entity\Participation; +use Chill\EventBundle\Form\ParticipationType; +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\Form\FormInterface; 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 Symfony\Component\Form\Extension\Core\Type\CollectionType; /** - * Class ParticipationController - * - * @package Chill\EventBundle\Controller - * @author Julien Fastré + * Class ParticipationController. */ class ParticipationController extends AbstractController { - /** * @var \Psr\Log\LoggerInterface */ @@ -48,8 +36,6 @@ class ParticipationController extends AbstractController /** * ParticipationController constructor. - * - * @param LoggerInterface $logger */ public function __construct(LoggerInterface $logger) { @@ -57,207 +43,14 @@ class ParticipationController extends AbstractController } /** - * 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); - $ignoredParticipations = $newParticipations = []; - - foreach ($participations as $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 ([] === $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) - )); - } - - 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, - ] - ); - } - - /** - * @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()) @@ -269,292 +62,77 @@ class ParticipationController extends AbstractController $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. - * - * @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, - bool $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 null $return_path */ public function createCreateForm(Participation $participation, $return_path = null): FormInterface { - - $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() - )) - )); + 'person_id' => $participation->getPerson()->getId(), + ]), + ]); - $form->add('submit', SubmitType::class, array( - 'label' => 'Create' - )); + $form->add('submit', SubmitType::class, [ + 'label' => 'Create', + ]); return $form; } public function createCreateFormMultiple(array $participations): FormInterface { - $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( + 'participations', + CollectionType::class, + [ + 'entry_type' => ParticipationType::class, + 'entry_options' => [ + 'event_type' => current($participations)->getEvent()->getType(), + ], + ] ); - $form->add('submit', SubmitType::class, array( - 'label' => 'Create' - )); + $form->add('submit', SubmitType::class, [ + 'label' => 'Create', + ]); return $form; } - /** - * Show an edit form for the participation with the given 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 - */ - public function editAction(int $participation_id): Response - { - /* @var $participation Participation */ - $participation = $this->getDoctrine()->getManager() - ->getRepository(Participation::class) - ->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', [ - 'form' => $form->createView(), - 'participation' => $participation, - ]); - } - - public function updateAction(int $participation_id, Request $request): Response - { - /* @var $participation Participation */ - $participation = $this->getDoctrine()->getManager() - ->getRepository(Participation::class) - ->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', [ - 'event_id' => $participation->getEvent()->getId(), - ]); - - } - - return $this->render('ChillEventBundle:Participation:edit.html.twig', [ - 'form' => $form->createView(), - 'participation' => $participation, - ]); - } - public function createEditForm(Participation $participation): FormInterface { $form = $this->createForm( @@ -573,7 +151,8 @@ class ParticipationController extends AbstractController $form->add( 'submit', - SubmitType::class, [ + SubmitType::class, + [ 'label' => 'Edit', ] ); @@ -582,136 +161,102 @@ class ParticipationController extends AbstractController } /** - * show a form to edit multiple participation for the same event. - * - * @param int $event_id - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse */ - public function editMultipleAction($event_id) + public function createMultiple(Request $request) { - $event = $this->getDoctrine()->getRepository('ChillEventBundle:Event') - ->find($event_id); + $participations = $this->handleRequest($request, new Participation(), true); - if ($event === null) { - throw $this->createNotFoundException("The event with id $event_id is not found"); + foreach ($participations as $participation) { + $this->denyAccessUnlessGranted( + ParticipationVoter::CREATE, + $participation, + 'The user is not allowed to create this participation' + ); } - // 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', - 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 = $this->createCreateFormMultiple($participations); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $this->getDoctrine()->getManager()->flush(); + $em = $this->getDoctrine()->getManager(); + $data = $form->getData(); - $this->addFlash('success', $this->get('translator')->trans("The participations " - . "have been successfully updated.")); + foreach ($data['participations'] as $participation) { + $em->persist($participation); + } - return $this->redirectToRoute('chill_event__event_show', - array('event_id' => $event->getId())); + $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:edit-multiple.html.twig', array( - 'event' => $event, - 'participations' => $event->getParticipations(), - 'form' => $form->createView() - )); + return $this->render('ChillEventBundle:Participation:new.html.twig', [ + 'form' => $form->createView(), + 'participation' => $participation, + ]); } /** - * @param ArrayIterator $participations - * @param Event $event - * @return \Symfony\Component\Form\FormInterface + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse */ - protected function createEditFormMultiple(ArrayIterator $participations, Event $event) + public function createSingle(Request $request) { - $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() - )) - )); + $participation = $this->handleRequest($request, new Participation(), false); - $form->add('participations', CollectionType::class, array( - 'entry_type' => ParticipationType::class, - 'entry_options' => array( - 'event_type' => $event->getType() - ), - ) + $this->denyAccessUnlessGranted( + ParticipationVoter::CREATE, + $participation, + 'The user is not allowed to create this participation' ); - $form->add('submit', SubmitType::class, array( - 'label' => 'Update' - )); + $form = $this->createCreateForm($participation); + $form->handleRequest($request); - return $form; + 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 integer $participation_id - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response + * @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.'); } @@ -724,40 +269,513 @@ class ParticipationController extends AbstractController $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. + * + * @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(int $participation_id): Response + { + /* @var $participation Participation */ + $participation = $this->getDoctrine()->getManager() + ->getRepository(Participation::class) + ->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"); + } + + public function updateAction(int $participation_id, Request $request): Response + { + /* @var $participation Participation */ + $participation = $this->getDoctrine()->getManager() + ->getRepository(Participation::class) + ->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. + * + * @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, + bool $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); + $ignoredParticipations = $newParticipations = []; + + foreach ($participations as $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 ([] === $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..63ff27dbb 100644 --- a/src/Bundle/ChillEventBundle/Controller/StatusController.php +++ b/src/Bundle/ChillEventBundle/Controller/StatusController.php @@ -1,39 +1,28 @@ 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 +35,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 +69,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 +206,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 be95880e8..a9b437cba 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,37 +39,43 @@ 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'), true)) { + if (in_array($scope->getName()['en'], ['administrative', 'social'], true)) { 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 " + 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']); + $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); @@ -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 c8b6b63c0..d028c6c55 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,42 @@ 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; + } + + public function getRoles() + { + return $this->roles; + } + + /** + * Get statuses. * * @return Collection */ @@ -202,4 +136,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..fb8ffeaed 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,190 @@ 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 +319,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 1f1bb93ad..3c7b50135 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 1f073fd7d..a4914b552 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,17 +12,22 @@ 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") @@ -48,25 +41,28 @@ class Status */ 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..4d9d41a22 100644 --- a/src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php +++ b/src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php @@ -1,29 +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\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 +25,99 @@ 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 +125,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..11d9dbef3 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,31 @@ 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))) { + 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..bbd93228e 100644 --- a/src/Bundle/ChillEventBundle/Security/Authorization/EventVoter.php +++ b/src/Bundle/ChillEventBundle/Security/Authorization/EventVoter.php @@ -1,149 +1,131 @@ + +/** + * 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 getRoles(): array + { + return self::ROLES; + } + + public function getRolesWithHierarchy(): array + { + return [ + 'Event' => self::ROLES, + ]; + } + + public function getRolesWithoutScope(): array + { + 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 && $attribute === self::SEE ) - ; + || ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE])) + || (null === $subject && self::SEE === $attribute); } - + /** - * * @param string $attribute * @param Event $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; } - + 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 ($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 ); - } - - - public function getRoles() - { - return self::ROLES; - } - - public function getRolesWithHierarchy() - { - return [ - 'Event' => self::ROLES - ]; - } - - public function getRolesWithoutScope() - { - return []; - } - } diff --git a/src/Bundle/ChillEventBundle/Security/Authorization/ParticipationVoter.php b/src/Bundle/ChillEventBundle/Security/Authorization/ParticipationVoter.php index 50e05e279..aff66dbdb 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,33 +57,45 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar AccessDecisionManagerInterface $accessDecisionManager, AuthorizationHelper $authorizationHelper, LoggerInterface $logger - ) - { + ) { $this->accessDecisionManager = $accessDecisionManager; $this->authorizationHelper = $authorizationHelper; $this->logger = $logger; } + public function getRoles(): array + { + return self::ROLES; + } + + public function getRolesWithHierarchy(): array + { + return [ + 'Event' => self::ROLES, + ]; + } + + public function getRolesWithoutScope(): array + { + 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 && $attribute === self::SEE ) - ; + || ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE])) + || (null === $subject && self::SEE === $attribute); } /** - * * @param string $attribute * @param Participation $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; @@ -102,19 +103,18 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar 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 ($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; } @@ -124,24 +124,5 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar $subject, $attribute ); - } - - public function getRoles() - { - return self::ROLES; - } - - public function getRolesWithHierarchy() - { - return [ - 'Event' => self::ROLES - ]; - } - - public function getRolesWithoutScope() - { - return []; - } - } 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 ffb068d70..c2169d5a9 100644 --- a/src/Bundle/ChillEventBundle/Timeline/TimelineEventProvider.php +++ b/src/Bundle/ChillEventBundle/Timeline/TimelineEventProvider.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\EventBundle\Timeline; use Chill\EventBundle\Entity\Event; use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\MainBundle\Timeline\TimelineSingleQuery; +use Chill\PersonBundle\Entity\Person; use Doctrine\ORM\EntityManager; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +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 { @@ -44,23 +32,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, @@ -69,44 +53,104 @@ 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 = TimelineSingleQuery::fromArray([ - 'id' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('id'), + + return TimelineSingleQuery::fromArray([ + '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']), - 'parameters' => [] + 'parameters' => [], ]); - - return $query; } - + + /** + * @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, @@ -115,30 +159,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, @@ -147,20 +186,23 @@ 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(); }, @@ -176,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 - ) - ); - } - } 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 1e25915ac..51dd0cd73 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php +++ b/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php @@ -1,31 +1,38 @@ denyAccessUnlessGranted(FamilyMemberVoter::DELETE, $familyMember, 'You are not ' + . 'allowed to delete this family membership'); + + $form = $this->createDeleteForm(); + + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); + + if ($form->isValid()) { + $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(), + ]); + + $this->em->remove($familyMember); + $this->em->flush(); + + $this->addFlash('success', $this->translator + ->trans('The family member has been successfully removed.')); + + return $this->redirectToRoute('chill_family_members_family_members_index', [ + 'id' => $familyMember->getPerson()->getId(), + ]); + } + } + + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:confirm_delete.html.twig', [ + 'familyMember' => $familyMember, + 'delete_form' => $form->createView(), + ]); + } + + /** + * @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() && $form->isValid()) { + $this->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) @@ -55,14 +136,14 @@ class FamilyMemberController extends AbstractController return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', [ 'person' => $person, - 'familyMembers' => $familyMembers + 'familyMembers' => $familyMembers, ]); } /** * @Route( - * "{_locale}/family-members/family-members/by-person/{id}/new", - * name="chill_family_members_family_members_new" + * "{_locale}/family-members/family-members/by-person/{id}/new", + * name="chill_family_members_family_members_new" * ) */ public function newAction(Person $person, Request $request) @@ -83,96 +164,20 @@ class FamilyMemberController extends AbstractController $this->addFlash('success', $this->translator->trans('Family member created')); return $this->redirectToRoute('chill_family_members_family_members_index', [ - 'id' => $person->getId() + 'id' => $person->getId(), ]); } return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:new.html.twig', [ 'form' => $form->createView(), - 'person' => $person + '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() && $form->isValid()) { - $this->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/{id}/delete", - * name="chill_family_members_family_members_delete" - * ) - */ - public function deleteAction(FamilyMember $familyMember, Request $request): Response - { - $this->denyAccessUnlessGranted(FamilyMemberVoter::DELETE, $familyMember, 'You are not ' - . 'allowed to delete this family membership'); - - $form = $this->createDeleteForm(); - - if ($request->getMethod() === Request::METHOD_DELETE) { - $form->handleRequest($request); - - if ($form->isValid()) { - $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() - ]); - - $this->em->remove($familyMember); - $this->em->flush(); - - $this->addFlash('success', $this->translator - ->trans("The family member has been successfully removed.")); - - return $this->redirectToRoute('chill_family_members_family_members_index', [ - 'id' => $familyMember->getPerson()->getId() - ]); - } - } - - - 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}/view", + * name="chill_family_members_family_members_view" * ) */ public function viewAction(FamilyMember $familyMember) @@ -180,7 +185,7 @@ class FamilyMemberController extends AbstractController $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $familyMember); return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', [ - 'familyMember' => $familyMember + 'familyMember' => $familyMember, ]); } @@ -193,8 +198,6 @@ class FamilyMemberController extends AbstractController ->createFormBuilder() ->setMethod(Request::METHOD_DELETE) ->add('submit', SubmitType::class, ['label' => 'Delete']) - ->getForm() - ; + ->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 a6754981b..571e94161 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php +++ b/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php @@ -1,5 +1,12 @@ 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..fba5e0c37 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php +++ b/src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php @@ -1,79 +1,80 @@ + * 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 ]; - } - - public function getRolesWithoutScope() + public function getRoles(): array { return self::ROLES; } + public function getRolesWithHierarchy(): array + { + return ['Family Members' => self::ROLES]; + } + + public function getRolesWithoutScope(): array + { + 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 11b3c34fd..e3ee53897 100644 --- a/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php +++ b/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.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 . - */ -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; -use Symfony\Component\DependencyInjection\Alias; /** - * + * 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\Alias; +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) @@ -45,15 +31,15 @@ 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'; // create config parameter in container - $param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name']; + $param = 'chill_main_' . $apiOrCrud . '_config_' . $crudEntry['name']; $container->setParameter($param, $crudEntry); if ($container->hasDefinition($controllerClass)) { @@ -63,8 +49,7 @@ class CRUDControllerCompilerPass implements CompilerPassInterface // add the "addMethodCall" $container->getDefinition($controllerClass) - ->addMethodCall('setCrudConfig', ['%'.$param.'%']); - + ->addMethodCall('setCrudConfig', ['%' . $param . '%']); } else { $controller = new Definition($controllerClass); @@ -72,10 +57,9 @@ class CRUDControllerCompilerPass implements CompilerPassInterface $controller->setAutoconfigured(true); $controller->setPublic(true); - $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 f88982070..cd458e222 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php @@ -1,96 +1,63 @@ getDoctrine() - ->getRepository($this->getEntityClass()) - ->find($id); + return array_merge( + parent::getSubscribedServices(), + [ + 'chill_main.paginator_factory' => PaginatorFactory::class, - if (null === $e) { - throw $this->createNotFoundException(sprintf("The object %s for id %s is not found", $this->getEntityClass(), $id)); - } - - return $e; - } - - protected function createEntity(string $action, Request $request): object - { - $class = $this->getEntityClass(); - - return new $class; + 'translator' => TranslatorInterface::class, + AuthorizationHelper::class => AuthorizationHelper::class, + EventDispatcherInterface::class => EventDispatcherInterface::class, + Resolver::class => Resolver::class, + SerializerInterface::class => SerializerInterface::class, + 'validator' => ValidatorInterface::class, + ] + ); } /** - * Count the number of entities + * Set the crud configuration. * - * By default, count all entities. You can customize the query by - * using the method `customizeQuery`. + * Used by the container to inject configuration for this crud. */ - protected function countEntities(string $action, Request $request, $_format): int + public function setCrudConfig(array $config): void { - 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; + $this->crudConfig = $config; } /** @@ -117,16 +84,157 @@ abstract class AbstractCRUDController extends AbstractController return $qb; } - protected function customizeQuery(string $action, Request $request, $query): void {} + /** + * 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) + { + // @TODO: Implements abstract getRoleFor method or do it in the interface. + $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 createEntity(string $action, Request $request): object + { + $class = $this->getEntityClass(); + + return new $class(); + } + + 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. + * + * @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found + * + * @param mixed $action + */ + protected function getEntity($action, string $id, Request $request): object + { + $e = $this + ->getDoctrine() + ->getRepository($this->getEntityClass()) + ->find($id); + + if (null === $e) { + throw $this->createNotFoundException(sprintf('The object %s for id %s is not found', $this->getEntityClass(), $id)); + } + + return $e; + } + + /** + * Get the FQDN of the class. + * + * @return class-string The FQDN of the class + */ + protected function getEntityClass(): string + { + return $this->crudConfig['class']; + } + + protected function getPaginatorFactory(): PaginatorFactory + { + return $this->container->get('chill_main.paginator_factory'); + } /** * 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(); } + protected function getValidator(): ValidatorInterface + { + return $this->get('validator'); + } + + /** + * Called on post check ACL. + * + * @param mixed $entity + */ + protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response + { + return null; + } + + /** + * Called on post fetch entity. + * + * @param mixed $entity + * @param mixed $_format + */ + protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response + { + return null; + } + + /** + * Method used by indexAction. + * + * @param mixed $query + */ + protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response + { + 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; @@ -141,111 +249,33 @@ abstract class AbstractCRUDController extends AbstractController } /** - * 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 FQDN of the class. + * Add ordering fields in the query build by self::queryEntities. * - * @return class-string The FQDN of the class + * @param mixed $query + * @param mixed $_format */ - protected function getEntityClass(): string + protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format) { - return $this->crudConfig['class']; + return $query; } /** - * Called on post fetch entity. - */ - protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response - { - return null; - } - - /** - * Called on post check ACL. - */ - protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response - { - return null; - } - - /** - * check the acl. Called by every action. + * Query the entity. * - * By default, check the role given by `getRoleFor` for the value given in - * $entity. + * By default, get all entities. You can customize the query by using the + * method `customizeQuery`. * - * Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException - * if not accessible. + * The method `orderEntity` is called internally to order entities. * - * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException + * It returns, by default, a query builder. */ - protected function checkACL(string $action, Request $request, string $_format, $entity = null) + protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator) { - // @TODO: Implements abstract getRoleFor method or do it in the interface. - $this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity); - } + $query = $this->buildQueryEntities($action, $request) + ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) + ->setMaxResults($paginator->getItemsPerPage()); - /** - * @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 - * - * Used by the container to inject configuration for this crud. - */ - public function setCrudConfig(array $config): void - { - $this->crudConfig = $config; - } - - protected function getPaginatorFactory(): PaginatorFactory - { - return $this->container->get('chill_main.paginator_factory'); - } - - protected function getValidator(): ValidatorInterface - { - return $this->get('validator'); - } - - public static function getSubscribedServices(): array - { - return \array_merge( - parent::getSubscribedServices(), - [ - 'chill_main.paginator_factory' => PaginatorFactory::class, - - 'translator' => TranslatorInterface::class, - AuthorizationHelper::class => AuthorizationHelper::class, - EventDispatcherInterface::class => EventDispatcherInterface::class, - Resolver::class => Resolver::class, - SerializerInterface::class => SerializerInterface::class, - 'validator' => ValidatorInterface::class, - ] - ); + // 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 3a390a286..15d8dbcc3 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php @@ -1,80 +1,38 @@ getEntity($action, $id, $request); - - $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); - - if ($postFetch instanceof Response) { - return $postFetch; - } - - $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 + * @param mixed $id + * @param mixed $_format * * @return void */ @@ -84,163 +42,45 @@ class ApiController extends AbstractCRUDController case Request::METHOD_GET: case Request::METHOD_HEAD: return $this->entityGet('_entity', $request, $id, $_format); + case Request::METHOD_PUT: case Request::METHOD_PATCH: return $this->entityPut('_entity', $request, $id, $_format); + case Request::METHOD_POST: return $this->entityPostAction('_entity', $request, $id); + case Request::METHOD_DELETE: return $this->entityDelete('_entity', $request, $id, $_format); + default: - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented"); - } - } - public function entityPost(Request $request, $_format): Response - { - switch($request->getMethod()) { - case Request::METHOD_POST: - return $this->entityPostAction('_entity', $request, $_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'); } } - protected function entityPostAction($action, Request $request, string $_format): Response - { - $entity = $this->createEntity($action, $request); - - try { - $entity = $this->deserialize($action, $request, $_format, $entity); - } catch (NotEncodableValueException $e) { - throw new BadRequestException("invalid json", 400, $e); - } - - $errors = $this->validate($action, $request, $_format, $entity); - - $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors); - if ($response instanceof Response) { - return $response; - } - - if ($errors->count() > 0) { - $response = $this->json($errors); - $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY); - - return $response; - } - - $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; - } - - $this->getDoctrine()->getManager()->persist($entity); - $this->getDoctrine()->getManager()->flush(); - - $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors); - if ($response instanceof Response) { - return $response; - } - $response = $this->onBeforeSerialize($action, $request, $_format, $entity); - if ($response instanceof Response) { - return $response; - } - - return $this->json( - $entity, - Response::HTTP_OK, - [], - $this->getContextForSerializationPostAlter($action, $request, $_format, $entity) - ); - } - public function entityPut($action, Request $request, $id, string $_format): Response - { - $entity = $this->getEntity($action, $id, $request); - - $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; - } - - try { - $entity = $this->deserialize($action, $request, $_format, $entity); - } catch (NotEncodableValueException $e) { - throw new BadRequestException("invalid json", 400, $e); - } - - $errors = $this->validate($action, $request, $_format, $entity); - - $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors); - if ($response instanceof Response) { - return $response; - } - - if ($errors->count() > 0) { - $response = $this->json($errors); - $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY); - - return $response; - } - - $this->getDoctrine()->getManager()->flush(); - - $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors); - if ($response instanceof Response) { - return $response; - } - - return $this->json( - $entity, - Response::HTTP_OK, - [], - $this->getContextForSerializationPostAlter($action, $request, $_format, $entity) - ); - } public function entityDelete($action, Request $request, $id, string $_format): 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)); + 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; } @@ -248,6 +88,7 @@ class ApiController extends AbstractCRUDController $errors = $this->validate($action, $request, $_format, $entity); $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors); + if ($response instanceof Response) { return $response; } @@ -263,6 +104,7 @@ class ApiController extends AbstractCRUDController $this->getDoctrine()->getManager()->flush(); $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors); + if ($response instanceof Response) { return $response; } @@ -270,51 +112,89 @@ class ApiController extends AbstractCRUDController return $this->json(Response::HTTP_OK); } - protected function onAfterValidation(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response + public function entityPost(Request $request, $_format): Response { - return null; + switch ($request->getMethod()) { + case Request::METHOD_POST: + return $this->entityPostAction('_entity', $request, $_format); + + default: + throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This method is not implemented'); + } } - - protected function onAfterFlush(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response + public function entityPut($action, Request $request, $id, string $_format): Response { - return null; - } + $entity = $this->getEntity($action, $id, $request); - protected function getValidationGroups(string $action, Request $request, string $_format, $entity): ?array - { - return null; - } + $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); - protected function validate(string $action, Request $request, string $_format, $entity, array $more = []): ConstraintViolationListInterface - { - $validationGroups = $this->getValidationGroups($action, $request, $_format, $entity); - - return $this->getValidator()->validate($entity, null, $validationGroups); - } - - /** - * Deserialize the content of the request into the class associated with the curd - */ - protected function deserialize(string $action, Request $request, string $_format, $entity = null): object - { - $default = []; - - if (NULL !== $entity) { - $default[AbstractNormalizer::OBJECT_TO_POPULATE] = $entity; + if ($postFetch instanceof Response) { + return $postFetch; } - $context = \array_merge( - $default, - $this->getContextForSerialization($action, $request, $_format, $entity) - ); + if (null === $entity) { + throw $this->createNotFoundException(sprintf('The %s with id %s ' + . 'is not found', $this->getCrudName(), $id)); + } - return $this->getSerializer()->deserialize($request->getContent(), $this->getEntityClass(), $_format, $context); + $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; + } + + try { + $entity = $this->deserialize($action, $request, $_format, $entity); + } catch (NotEncodableValueException $e) { + throw new BadRequestException('invalid json', 400, $e); + } + + $errors = $this->validate($action, $request, $_format, $entity); + + $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors); + + if ($response instanceof Response) { + return $response; + } + + if ($errors->count() > 0) { + $response = $this->json($errors); + $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY); + + return $response; + } + + $this->getDoctrine()->getManager()->flush(); + + $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors); + + if ($response instanceof Response) { + return $response; + } + + return $this->json( + $entity, + Response::HTTP_OK, + [], + $this->getContextForSerializationPostAlter($action, $request, $_format, $entity) + ); } - /** - * Base action for indexing entities + * Base action for indexing entities. */ public function indexApi(Request $request, string $_format) { @@ -322,82 +202,15 @@ 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'); } } - /** - * 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. Serialize the entities in a Collection, using `SerializeCollection` - * - * @param string $action - * @param Request $request - */ - protected function indexApiAction($action, Request $request, $_format) + public function onBeforeSerialize(string $action, Request $request, $_format, $entity): ?Response { - $this->onPreIndex($action, $request, $_format); - - $response = $this->checkACL($action, $request, $_format); - if ($response instanceof Response) { - return $response; - } - - $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 - ); - - if ($response instanceof Response) { - return $response; - } - - $query = $this->queryEntities($action, $request, $_format, $paginator); - - $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); - - if ($response instanceof Response) { - return $response; - } - - return $this->serializeCollection($action, $request, $_format, $paginator, $entities); + return null; } /** @@ -420,36 +233,38 @@ class ApiController extends AbstractCRUDController * * @param string action * @param mixed id - * @param Request $request - * @param string $_format * @param string $property the name of the property. This will be used to make a `add+$property` and `remove+$property` method * @param string $postedDataType the type of the posted data (the content) * @param string $postedDataContext a context to deserialize posted data (the content) * @param bool $forcePersist force to persist the created element (only for POST request) + * @param mixed $id * @throw BadRequestException if unable to deserialize the posted data * @throw BadRequestException if the method is not POST or DELETE - * */ protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, array $postedDataContext = [], bool $forcePersist = false): Response { $entity = $this->getEntity($action, $id, $request); $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); + if ($postFetch instanceof Response) { return $postFetch; } $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; } @@ -457,25 +272,30 @@ class ApiController extends AbstractCRUDController try { $postedData = $this->getSerializer()->deserialize($request->getContent(), $postedDataType, $_format, $postedDataContext); } catch (\Symfony\Component\Serializer\Exception\UnexpectedValueException $e) { - throw new BadRequestException(sprintf("Unable to deserialize posted ". - "data: %s", $e->getMessage()), 0, $e); + throw new BadRequestException(sprintf('Unable to deserialize posted ' . + 'data: %s', $e->getMessage()), 0, $e); } switch ($request->getMethod()) { case Request::METHOD_DELETE: // oups... how to use property accessor to remove element ? - $entity->{'remove'.\ucfirst($property)}($postedData); + $entity->{'remove' . ucfirst($property)}($postedData); + break; + case Request::METHOD_POST: - $entity->{'add'.\ucfirst($property)}($postedData); + $entity->{'add' . ucfirst($property)}($postedData); + break; + default: - throw new BadRequestException("this method is not supported"); + throw new BadRequestException('this method is not supported'); } $errors = $this->validate($action, $request, $_format, $entity, [$postedData]); $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors, [$postedData]); + if ($response instanceof Response) { return $response; } @@ -491,8 +311,8 @@ class ApiController extends AbstractCRUDController $this->getDoctrine()->getManager()->flush(); - $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors, [$postedData]); + if ($response instanceof Response) { return $response; } @@ -500,6 +320,7 @@ class ApiController extends AbstractCRUDController switch ($request->getMethod()) { case Request::METHOD_DELETE: return $this->json('', Response::HTTP_OK); + case Request::METHOD_POST: return $this->json( $postedData, @@ -509,12 +330,308 @@ class ApiController extends AbstractCRUDController ); } - throw new \Exception('Unable to handle such request method.'); + throw new Exception('Unable to handle such request method.'); } /** - * Serialize collections + * Deserialize the content of the request into the class associated with the curd. * + * @param mixed|null $entity + */ + protected function deserialize(string $action, Request $request, string $_format, $entity = null): object + { + $default = []; + + if (null !== $entity) { + $default[AbstractNormalizer::OBJECT_TO_POPULATE] = $entity; + } + + $context = array_merge( + $default, + $this->getContextForSerialization($action, $request, $_format, $entity) + ); + + return $this->getSerializer()->deserialize($request->getContent(), $this->getEntityClass(), $_format, $context); + } + + /** + * 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); + + $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); + + if ($postFetch instanceof Response) { + return $postFetch; + } + + $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 entityPostAction($action, Request $request, string $_format): Response + { + $entity = $this->createEntity($action, $request); + + try { + $entity = $this->deserialize($action, $request, $_format, $entity); + } catch (NotEncodableValueException $e) { + throw new BadRequestException('invalid json', 400, $e); + } + + $errors = $this->validate($action, $request, $_format, $entity); + + $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors); + + if ($response instanceof Response) { + return $response; + } + + if ($errors->count() > 0) { + $response = $this->json($errors); + $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY); + + return $response; + } + + $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; + } + + $this->getDoctrine()->getManager()->persist($entity); + $this->getDoctrine()->getManager()->flush(); + + $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors); + + if ($response instanceof Response) { + return $response; + } + $response = $this->onBeforeSerialize($action, $request, $_format, $entity); + + if ($response instanceof Response) { + return $response; + } + + return $this->json( + $entity, + Response::HTTP_OK, + [], + $this->getContextForSerializationPostAlter($action, $request, $_format, $entity) + ); + } + + protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array + { + switch ($request->getMethod()) { + case Request::METHOD_GET: + return ['groups' => ['read']]; + + case Request::METHOD_PUT: + case Request::METHOD_PATCH: + case Request::METHOD_POST: + return ['groups' => ['write']]; + + default: + throw new LogicException('get context for serialization is not implemented for this method'); + } + } + + /** + * Get the context for serialization post alter query (in case of + * PATCH, PUT, or POST method). + * + * This is called **after** the entity was altered. + * + * @param mixed $entity + */ + protected function getContextForSerializationPostAlter(string $action, Request $request, string $_format, $entity, array $more = []): array + { + return ['groups' => ['read']]; + } + + /** + * 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'); + } + + protected function getValidationGroups(string $action, Request $request, string $_format, $entity): ?array + { + return null; + } + + /** + * 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. Serialize the entities in a Collection, using `SerializeCollection` + * + * @param string $action + * @param mixed $_format + */ + protected function indexApiAction($action, Request $request, $_format) + { + $this->onPreIndex($action, $request, $_format); + + $response = $this->checkACL($action, $request, $_format); + + if ($response instanceof Response) { + return $response; + } + + $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 + ); + + if ($response instanceof Response) { + return $response; + } + + $query = $this->queryEntities($action, $request, $_format, $paginator); + + $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 + ); + + if ($response instanceof Response) { + return $response; + } + + return $this->serializeCollection($action, $request, $_format, $paginator, $entities); + } + + protected function onAfterFlush(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response + { + return null; + } + + protected function onAfterValidation(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response + { + return null; + } + + /** + * Serialize collections. + * + * @param mixed $entities */ protected function serializeCollection(string $action, Request $request, string $_format, PaginatorInterface $paginator, $entities): Response { @@ -525,55 +642,10 @@ class ApiController extends AbstractCRUDController return $this->json($model, Response::HTTP_OK, [], $context); } - - protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array + protected function validate(string $action, Request $request, string $_format, $entity, array $more = []): ConstraintViolationListInterface { - switch ($request->getMethod()) { - case Request::METHOD_GET: - return [ 'groups' => [ 'read' ]]; - case Request::METHOD_PUT: - case Request::METHOD_PATCH: - case Request::METHOD_POST: - return [ 'groups' => [ 'write' ]]; - default: - throw new \LogicException("get context for serialization is not implemented for this method"); - } - } + $validationGroups = $this->getValidationGroups($action, $request, $_format, $entity); - /** - * Get the context for serialization post alter query (in case of - * PATCH, PUT, or POST method) - * - * This is called **after** the entity was altered. - */ - protected function getContextForSerializationPostAlter(string $action, Request $request, string $_format, $entity, array $more = []): array - { - return [ 'groups' => [ 'read' ]]; - } - - /** - * 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'); + return $this->getValidator()->validate($entity, null, $validationGroups); } } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php index 94479e233..fc6580f61 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php @@ -1,38 +1,43 @@ crudConfig = $config; - } - public function CRUD(?string $parameter): Response { return new Response($parameter); @@ -46,6 +51,201 @@ class CRUDController extends AbstractController return $this->deleteAction('delete', $request, $id); } + /** + * BAse method for edit action. + * + * IMplemented by the method formEditAction, with action as 'edit' + * + * @param mixed $id + */ + public function edit(Request $request, $id): Response + { + return $this->formEditAction('edit', $request, $id); + } + + /** + * Get the context for the serialization. + * + * @param mixed $entity + */ + public function getContextForSerialization(string $action, Request $request, $entity, string $_format): array + { + return []; + } + + public static function getSubscribedServices(): array + { + return array_merge( + parent::getSubscribedServices(), + [ + 'chill_main.paginator_factory' => PaginatorFactory::class, + 'translator' => TranslatorInterface::class, + AuthorizationHelper::class => AuthorizationHelper::class, + EventDispatcherInterface::class => EventDispatcherInterface::class, + Resolver::class => Resolver::class, + SerializerInterface::class => SerializerInterface::class, + FilterOrderHelperFactoryInterface::class => FilterOrderHelperFactoryInterface::class, + ] + ); + } + + /** + * 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): void + { + $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 + ); + } + + protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper + { + return null; + } + + /** + * 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) + { + $query = $this + ->getDoctrine() + ->getManager() + ->createQueryBuilder() + ->select('e') + ->from($this->getEntityClass(), 'e'); + + $this->customizeQuery($action, $request, $query); + + return $query; + } + + /** + * 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, ?FilterOrderHelper $filterOrder = null): 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) + { + } + + protected function customizeQuery(string $action, Request $request, $query): void + { + } + /** * @param $id * @param null $formClass @@ -62,7 +262,7 @@ class CRUDController extends AbstractController return $postFetch; } - if (NULL === $entity) { + if (null === $entity) { throw $this->createNotFoundException( sprintf( 'The %s with id %s is not found', @@ -73,11 +273,13 @@ class CRUDController extends AbstractController } $response = $this->checkACL($action, $entity); + if ($response instanceof Response) { return $response; } $response = $this->onPostCheckACL($action, $request, $entity); + if ($response instanceof Response) { return $response; } @@ -106,8 +308,7 @@ class CRUDController extends AbstractController return $result; } - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]); - + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', ['id' => $entity->getId()]); } if ($form->isSubmitted()) { @@ -117,514 +318,29 @@ class CRUDController extends AbstractController $defaultTemplateParameters = [ 'form' => $form->createView(), 'entity' => $entity, - 'crud_name' => $this->getCrudName() + '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. + * Duplicate an entity. * - * @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` - * 2. check acl. If it does return a response instance, return it - * 3. launch `onPostCheckACL`. If it does return a response instance, return it - * 4. count the items, using `countEntities` - * 5. build a paginator element from the the number of entities ; - * 6. Launch `onPreIndexQuery`. If it does return a response instance, return it - * 7. fetch the results, using `getQueryResult` - * - * Internally, this build a query, using `queryEntities` - * - * 8. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it - * 9. create default parameters: - * - * The default parameters are: - * - * * entities: the list en entities ; - * * crud_name: the name of the crud ; - * * paginator: a paginator element ; - * 10. Launch rendering, the parameter is fetch using `getTemplateFor` - * The parameters may be personnalized using `generateTemplateParameter`. - * - * @param string $action - * @param Request $request - */ - protected function indexEntityAction($action, Request $request) - { - $this->onPreIndex($action, $request); - - $response = $this->checkACL($action, null); - if ($response instanceof Response) { - return $response; - } - - $entity = ''; - - $response = $this->onPostCheckACL($action, $request, $entity); - if ($response instanceof Response) { - return $response; - } - - $filterOrder = $this->buildFilterOrderHelper($action, $request); - $totalItems = $this->countEntities($action, $request, $filterOrder); - $paginator = $this->getPaginatorFactory()->create($totalItems); - - $response = $this->onPreIndexBuildQuery($action, $request, $totalItems, - $paginator); - - if ($response instanceof Response) { - return $response; - } - - $entities = $this->getQueryResult($action, $request, $totalItems, $paginator, $filterOrder); - - $response = $this->onPostIndexFetchQuery($action, $request, $totalItems, - $paginator, $entities); - - if ($response instanceof Response) { - return $response; - } - - $defaultTemplateParameters = [ - 'entities' => $entities, - 'crud_name' => $this->getCrudName(), - 'paginator' => $paginator, - 'filter_order' => $filterOrder - ]; - - return $this->render( - $this->getTemplateFor($action, $entities, $request), - $this->generateTemplateParameter($action, $entities, $request, $defaultTemplateParameters) - ); - } - - protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper - { - return null; - } - - /** - * @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) - { - $query = $this - ->getDoctrine() - ->getManager() - ->createQueryBuilder() - ->select('e') - ->from($this->getEntityClass(), 'e'); - - $this->customizeQuery($action, $request, $query); - - return $query; - } - - protected function customizeQuery(string $action, Request $request, $query): void {} - - /** - * 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, ?FilterOrderHelper $filterOrder = null) - { - $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 * @return mixed */ - protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, - ?FilterOrderHelper $filterOrder = null) + protected function duplicateEntity(string $action, Request $request) { - $query = $this->queryEntities($action, $request, $paginator, $filterOrder); + $id = $request->query->get('duplicate_id', 0); + $originalEntity = $this->getEntity($action, $id, $request); - return $query->getQuery()->getResult(); - } + $this->getDoctrine()->getManager() + ->detach($originalEntity); - /** - * Count the number of entities - * - * @param string $action - * @param Request $request - * @return int - */ - protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int - { - return $this->buildQueryEntities($action, $request) - ->select('COUNT(e)') - ->getQuery() - ->getSingleScalarResult() - ; - } - - /** - * 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 - */ - 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($action, $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) - ); + return $originalEntity; } /** @@ -665,10 +381,7 @@ class CRUDController extends AbstractController * 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 { @@ -679,11 +392,13 @@ class CRUDController extends AbstractController } $response = $this->checkACL($action, $entity); + if ($response instanceof Response) { return $response; } $response = $this->onPostCheckACL($action, $request, $entity); + if ($response instanceof Response) { return $response; } @@ -712,189 +427,135 @@ class CRUDController extends AbstractController return $result; } - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]); + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', ['id' => $entity->getId()]); + } - } elseif ($form->isSubmitted()) { + if ($form->isSubmitted()) { $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); } $defaultTemplateParameters = [ 'form' => $form->createView(), 'entity' => $entity, - 'crud_name' => $this->getCrudName() + '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 + * The edit action. * - * @param string $id - * @return object - */ - protected function getEntity($action, $id, Request $request): ?object - { - return $this->getDoctrine() - ->getRepository($this->getEntityClass()) - ->find($id); - } - - /** - * Duplicate an entity + * Some steps may be overriden during this process of rendering: * - * @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; - } - - /** + * This method: * - * @return string the complete fqdn of the class - */ - protected function getEntityClass(): string - { - return $this->crudConfig['class']; - } - - /** + * 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; * - * @return string the crud name - */ - protected function getCrudName(): string - { - return $this->crudConfig['name']; - } - - /** - * check the acl. Called by every action. + * If the form is valid, the entity is stored and flushed, and a redirection + * is returned. * - * By default, check the role given by `getRoleFor` for the value given in - * $entity. + * In this case, those hooks are available: * - * Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException - * if not accessible. + * * onFormValid + * * onPreFlush + * * onPostFlush + * * onBeforeRedirectAfterSubmission. If this method return an instance of + * Response, this response is returned. * - * @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. + * 5. generate default template parameters: * - * @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. + * * `entity`: the fetched entity ; + * * `crud_name`: the crud name ; + * * `form`: the formview instance. * - * This method should not be overriden. Override `getRoleFor` instead. + * 6. Launch rendering, the parameter is fetch using `getTemplateFor` + * The parameters may be personnalized using `generateTemplateParameter`. * - * @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 mixed $id * @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 + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ - protected function customizeForm(string $action, FormInterface $form) + 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($action, $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 - * - * @param string $action - * @param FormInterface $form - * @return string */ protected function generateFormErrorMessage(string $action, FormInterface $form): string { @@ -904,26 +565,31 @@ class CRUDController extends AbstractController } /** - * Generate a success message when a form could be flushed successfully + * 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"; + $msg = 'crud.edit.success'; + break; + case 'new': - $msg = "crud.new.success"; + $msg = 'crud.new.success'; + break; + case 'delete': - $msg = "crud.delete.success"; + $msg = 'crud.delete.success'; + break; + default: - $msg = "crud.default.success"; + $msg = 'crud.default.success'; } return $this->getTranslator()->trans($msg); @@ -932,10 +598,8 @@ class CRUDController extends AbstractController /** * Customize template parameters. * - * @param string $action * @param mixed $entity - * @param Request $request - * @param array $defaultTemplateParameters + * * @return array */ protected function generateTemplateParameter( @@ -948,17 +612,137 @@ class CRUDController extends AbstractController } /** - * Create an entity. + * 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 * - * @param string $action - * @param Request $request * @return object */ - protected function createEntity(string $action, Request $request): object + protected function getEntity($action, $id, Request $request): ?object { - $type = $this->getEntityClass(); + return $this->getDoctrine() + ->getRepository($this->getEntityClass()) + ->find($id); + } - return new $type; + /** + * @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); + } + + protected function getFilterOrderHelperFactory(): FilterOrderHelperFactoryInterface + { + return $this->get(FilterOrderHelperFactoryInterface::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']; + } + + /** + * @todo (check how to do this with dependency injection and make changes...) + */ + protected function getPaginatorFactory(): PaginatorFactory + { + return $this->container->get('chill_main.paginator_factory'); + } + + /** + * Get the result of the query. + * + * @return mixed + */ + protected function getQueryResult( + string $action, + Request $request, + int $totalItems, + PaginatorInterface $paginator, + ?FilterOrderHelper $filterOrder = null + ) { + $query = $this->queryEntities($action, $request, $paginator, $filterOrder); + + 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); } /** @@ -970,9 +754,10 @@ class CRUDController extends AbstractController * * @param string $action * @param mixed $entity the entity for the current request, or an array of entities - * @param Request $request + * + * @throws LogicException if no template are available + * * @return string the path to the template - * @throws \LogicException if no template are available */ protected function getTemplateFor($action, $entity, Request $request) { @@ -983,26 +768,34 @@ class CRUDController extends AbstractController 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"); + 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 - * @param Request $request - * @return bool */ protected function hasCustomTemplate($action, $entity, Request $request): bool { @@ -1010,69 +803,93 @@ class CRUDController extends AbstractController } /** + * Build an index page. + * + * Some steps may be overriden during this process of rendering. + * + * This method: + * + * 1. Launch `onPreIndex` + * 2. check acl. If it does return a response instance, return it + * 3. launch `onPostCheckACL`. If it does return a response instance, return it + * 4. count the items, using `countEntities` + * 5. build a paginator element from the the number of entities ; + * 6. Launch `onPreIndexQuery`. If it does return a response instance, return it + * 7. fetch the results, using `getQueryResult` + * + * Internally, this build a query, using `queryEntities` + * + * 8. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it + * 9. create default parameters: + * + * The default parameters are: + * + * * entities: the list en entities ; + * * crud_name: the name of the crud ; + * * paginator: a paginator element ; + * 10. Launch rendering, the parameter is fetch using `getTemplateFor` + * The parameters may be personnalized using `generateTemplateParameter`. + * * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request */ - protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request) + protected function indexEntityAction($action, Request $request) { - } + $this->onPreIndex($action, $request); - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPostFlush(string $action, $entity, FormInterface $form, Request $request) - { - } + $response = $this->checkACL($action, null); - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request) - { - } + if ($response instanceof Response) { + return $response; + } - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPostPersist(string $action, $entity, FormInterface $form, Request $request) - { - } + $entity = ''; - /** - * @param $action - * @param Request $request - * @param $entity - * @return null|Response - */ - protected function onPostFetchEntity($action, Request $request, $entity): ?Response - { - return null; - } + $response = $this->onPostCheckACL($action, $request, $entity); - /** - * @param $action - * @param Request $request - * @param $entity - * @return null|Response - */ - protected function onPostCheckACL($action, Request $request, $entity): ?Response - { - return null; - } + if ($response instanceof Response) { + return $response; + } - protected function onFormValid(string $action, object $entity, FormInterface $form, Request $request) - { + $filterOrder = $this->buildFilterOrderHelper($action, $request); + $totalItems = $this->countEntities($action, $request, $filterOrder); + $paginator = $this->getPaginatorFactory()->create($totalItems); + + $response = $this->onPreIndexBuildQuery( + $action, + $request, + $totalItems, + $paginator + ); + + if ($response instanceof Response) { + return $response; + } + + $entities = $this->getQueryResult($action, $request, $totalItems, $paginator, $filterOrder); + + $response = $this->onPostIndexFetchQuery( + $action, + $request, + $totalItems, + $paginator, + $entities + ); + + if ($response instanceof Response) { + return $response; + } + + $defaultTemplateParameters = [ + 'entities' => $entities, + 'crud_name' => $this->getCrudName(), + 'paginator' => $paginator, + 'filter_order' => $filterOrder, + ]; + + return $this->render( + $this->getTemplateFor($action, $entities, $request), + $this->generateTemplateParameter($action, $entities, $request, $defaultTemplateParameters) + ); } /** @@ -1084,113 +901,242 @@ class CRUDController extends AbstractController * * 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"); + $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()); + 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() - ]); + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', [ + 'id' => $entity->getId(), + ]); } } + protected function onFormValid(string $action, object $entity, FormInterface $form, Request $request) + { + } + /** - * Include services + * @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 string $action - * @return mixed + * @param mixed $query */ - protected function getActionConfig(string $action) + protected function onPostIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query) { - return $this->crudConfig['actions'][$action]; } /** - * @todo (check how to do this with dependency injection and make changes...) - * @return PaginatorFactory + * method used by indexAction. + * + * @param mixed $entities */ - protected function getPaginatorFactory(): PaginatorFactory + protected function onPostIndexFetchQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $entities) { - return $this->container->get('chill_main.paginator_factory'); } /** - * @return TranslatorInterface + * @param $entity */ - protected function getTranslator(): TranslatorInterface + protected function onPostPersist(string $action, $entity, FormInterface $form, Request $request) { - return $this->container->get('translator'); } /** - * @return AuthorizationHelper + * @param $entity */ - protected function getAuthorizationHelper(): AuthorizationHelper + protected function onPostRemove(string $action, $entity, FormInterface $form, Request $request) + { + } + + protected function onPreDelete(string $action, Request $request) { - return $this->container->get(AuthorizationHelper::class); } /** - * @param Role $role - * @param Scope|null $scope - * @return \Chill\MainBundle\Entity\Center[] + * @param $entity */ - protected function getReachableCenters(Role $role, Scope $scope = null) + protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request) + { + } + + protected function onPreIndex(string $action, Request $request) { - return $this->getAuthorizationHelper() - ->getReachableCenters($this->getUser(), $role, $scope) - ; } /** - * @return EventDispatcherInterface + * method used by indexAction. */ - protected function getEventDispatcher(): EventDispatcherInterface + protected function onPreIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator) { - return $this->get(EventDispatcherInterface::class); } /** - * @return Resolver + * @param $entity */ - protected function getCrudResolver(): Resolver + protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request) { - return $this->get(Resolver::class); - } - - protected function getFilterOrderHelperFactory(): FilterOrderHelperFactoryInterface - { - return $this->get(FilterOrderHelperFactoryInterface::class); } /** - * @return array + * @param $entity */ - public static function getSubscribedServices(): array + protected function onPreRemove(string $action, $entity, FormInterface $form, Request $request) { - return \array_merge( - parent::getSubscribedServices(), - [ - 'chill_main.paginator_factory' => PaginatorFactory::class, - 'translator' => TranslatorInterface::class, - AuthorizationHelper::class => AuthorizationHelper::class, - EventDispatcherInterface::class => EventDispatcherInterface::class, - Resolver::class => Resolver::class, - SerializerInterface::class => SerializerInterface::class, - FilterOrderHelperFactoryInterface::class => FilterOrderHelperFactoryInterface::class, - ] - ); + } + + /** + * 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, ?FilterOrderHelper $filterOrder = null) + { + $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..0ac1da9ff 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php +++ b/src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php @@ -1,122 +1,114 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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 85ef4c66c..8a6d316e5 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php +++ b/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php @@ -1,32 +1,42 @@ isLoaded) { - throw new \RuntimeException('Do not add the "CRUD" loader twice'); + throw new RuntimeException('Do not add the "CRUD" loader twice'); } $collection = new RouteCollection(); @@ -60,6 +63,7 @@ class CRUDRoutesLoader extends Loader foreach ($this->crudConfig as $crudConfig) { $collection->addCollection($this->loadCrudConfig($crudConfig)); } + foreach ($this->apiCrudConfig as $crudConfig) { $collection->addCollection($this->loadApi($crudConfig)); } @@ -68,56 +72,30 @@ class CRUDRoutesLoader extends Loader } /** - * Load routes for CRUD (without api) + * @param mixed $resource + * @param null $type * - * @param $crudConfig - * @return RouteCollection + * @return bool */ - protected function loadCrudConfig($crudConfig): RouteCollection + public function supports($resource, $type = null) { - $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; + 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; } @@ -126,46 +104,61 @@ 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 + )); if (count($methods) === 0) { - throw new \RuntimeException("The api configuration named \"{$crudConfig['name']}\", action \"{$name}\", ". - "does not have any allowed methods. You should remove this action from the config ". - "or allow, at least, one method"); + throw new RuntimeException("The api configuration named \"{$crudConfig['name']}\", action \"{$name}\", " . + 'does not have any allowed methods. You should remove this action from the config ' . + 'or allow, at least, one method'); } - if ('_entity' === $name && \in_array(Request::METHOD_POST, $methods)) { - unset($methods[\array_search(Request::METHOD_POST, $methods)]); - $entityPostRoute = $this->createEntityPostRoute($name, $crudConfig, $action, - $controller); - $collection->add("chill_api_single_{$crudConfig['name']}_{$name}_create", - $entityPostRoute); + if ('_entity' === $name && in_array(Request::METHOD_POST, $methods)) { + unset($methods[array_search(Request::METHOD_POST, $methods)]); + $entityPostRoute = $this->createEntityPostRoute( + $name, + $crudConfig, + $action, + $controller + ); + $collection->add( + "chill_api_single_{$crudConfig['name']}_{$name}_create", + $entityPostRoute + ); } if (count($methods) === 0) { @@ -177,7 +170,43 @@ class CRUDRoutesLoader extends Loader $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; @@ -185,14 +214,14 @@ class CRUDRoutesLoader extends Loader private function createEntityPostRoute(string $name, $crudConfig, array $action, $controller): Route { - $localPath = $action['path'].'.{_format}'; + $localPath = $action['path'] . '.{_format}'; $defaults = [ - '_controller' => $controller.':'.($action['controller_action'] ?? 'entityPost') + '_controller' => $controller . ':' . ($action['controller_action'] ?? 'entityPost'), ]; - $path = $crudConfig['base_path'].$localPath; + $path = $crudConfig['base_path'] . $localPath; $requirements = $action['requirements'] ?? []; $route = new Route($path, $defaults, $requirements); - $route->setMethods([ Request::METHOD_POST ]); + $route->setMethods([Request::METHOD_POST]); return $route; } 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 @@ 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 @@ -82,6 +119,99 @@ class ChillImportUsersCommand extends Command ->addOption('csv-dump', null, InputOption::VALUE_REQUIRED, 'A path to dump a summary of the created file'); } + 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([ + '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) { + return true; + } + + if ($this->userRepository->countByUsernameOrEmail($data['email']) > 0) { + return true; + } + + return false; + } + protected function execute(InputInterface $input, OutputInterface $output) { $this->tempOutput = $output; @@ -99,221 +229,11 @@ class ChillImportUsersCommand extends Command try { $this->loadUsers(); - } - catch(\Exception $e) { + } 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; - } - - $user = $this->createUser($line, $r); - $this->appendUserToFile($user); - } - } - - protected function doesUserExists($data) - { - if ($this->userRepository->countByUsernameOrEmail($data['username']) > 0) { - return true; - } - - 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); - } - } - } - - - 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 getPermissionGroup($alias) - { - if (\array_key_exists($alias, $this->permissionGroups)) { - return $this->permissionGroups[$alias]; - } - - $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->writeln('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 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. * @@ -326,14 +246,15 @@ class ChillImportUsersCommand extends Command * 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); + $name = trim($name); - if (\array_key_exists($name, $this->centers)) { + if (array_key_exists($name, $this->centers)) { return $this->centers[$name]; } @@ -351,23 +272,23 @@ class ChillImportUsersCommand extends Command $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); @@ -378,16 +299,115 @@ class ChillImportUsersCommand extends Command 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->writeln('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..0a78f8c59 100644 --- a/src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php +++ b/src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php @@ -1,88 +1,92 @@ logger = $logger; $this->em = $em; $this->recoverPasswordHelper = $recoverPasswordHelper; $this->eventDispatcher = $eventDispatcher; - + parent::__construct(); } - - protected function configure() { $this @@ -91,113 +95,114 @@ 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 443f4b52f..9ef4f70ff 100644 --- a/src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php +++ b/src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php @@ -1,74 +1,41 @@ entityManager=$entityManager; - $this->availableLanguages=$availableLanguages; + $this->entityManager = $entityManager; + $this->availableLanguages = $availableLanguages; parent::__construct(); } - /* - * (non-PHPdoc) - * @see \Symfony\Component\Console\Command\Command::configure() - */ - protected function configure() - { - $this->setName('chill:main:countries:populate') - ->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() - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $countries = static::prepareCountryList($this->availableLanguages); - $em = $this->entityManager; - - foreach($countries as $country) { - $countryStored = $em->getRepository('ChillMainBundle:Country') - ->findOneBy(array('countryCode' => $country->getCountryCode())); - - if (NULL === $countryStored) { - $em->persist($country); - } else { - $countryStored->setName($country->getName()); - } - } - - $em->flush(); - } - public static function prepareCountryList($languages) { $regionBundle = Intl::getRegionBundle(); @@ -78,10 +45,10 @@ class LoadCountriesCommand extends Command $countries[$language] = $regionBundle->getCountryNames($language); } - $countryEntities = array(); + $countryEntities = []; foreach ($countries[$languages[0]] as $countryCode => $name) { - $names = array(); + $names = []; foreach ($languages as $language) { $names[$language] = $countries[$language][$countryCode]; @@ -94,4 +61,38 @@ class LoadCountriesCommand extends Command return $countryEntities; } + + /* + * (non-PHPdoc) + * @see \Symfony\Component\Console\Command\Command::configure() + */ + protected function configure() + { + $this->setName('chill:main:countries:populate') + ->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() + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $countries = static::prepareCountryList($this->availableLanguages); + $em = $this->entityManager; + + foreach ($countries as $country) { + $countryStored = $em->getRepository('ChillMainBundle:Country') + ->findOneBy(['countryCode' => $country->getCountryCode()]); + + if (null === $countryStored) { + $em->persist($country); + } else { + $countryStored->setName($country->getName()); + } + } + + $em->flush(); + } } diff --git a/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php b/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php index 248419d7f..e99a47673 100644 --- a/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php +++ b/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php @@ -1,20 +1,28 @@ 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." - . "Optionally, the csv file can have the following " - . "columns after the country code: reference code, latitude, longitude, source. " - . "The latitude and longitude columns are supposed to be in WGS84 and expressed in decimal degrees. " - . "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.' + . 'Optionally, the csv file can have the following ' + . 'columns after the country code: reference code, latitude, longitude, source. ' + . 'The latitude and longitude columns are supposed to be in WGS84 and expressed in decimal degrees. ' + . '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) @@ -79,90 +87,77 @@ class LoadPostalCodesCommand extends Command $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 !'); - } - - 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."); - } - - $resource = fopen($filename, 'r'); - - if ($resource == FALSE) { - throw new \RuntimeException("The file '$filename' could not be opened."); - } - - return $resource; + $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]); + $output->writeln('handling row: ' . $row[0] . ' | ' . $row[1] . ' | ' . $row[2]); } $em = $this->entityManager; $country = $em - ->getRepository(Country::class) - ->findOneBy(array('countryCode' => $row[2])); + ->getRepository(Country::class) + ->findOneBy(['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])); + 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(PostalCode::class) - ->findBy(array('code' => $row[0], 'name' => $row[1])); + ->getRepository(PostalCode::class) + ->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])); + 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) - ; + ->setCode($row[0]) + ->setName($row[1]) + ->setCountry($country); - if (NULL != $row[3]){ + if (null != $row[3]) { $postalCode->setRefPostalCodeId($row[3]); } - if (NULL != $row[4] & NULL != $row[5]){ + if (null != $row[4] & null != $row[5]) { $postalCode->setCenter(Point::fromLonLat((float) $row[5], (float) $row[4])); } - if (NULL != $row[6]){ + if (null != $row[6]) { $postalCode->setPostalCodeSource($row[6]); } @@ -171,35 +166,53 @@ class LoadPostalCodesCommand extends Command if ($errors->count() == 0) { $em->persist($postalCode); } else { - $msg = ""; + $msg = ''; + foreach ($errors as $error) { - $msg .= " ".$error->getMessage(); + $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())); + $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.'); + } + + $resource = fopen($filename, 'r'); + + if (false == $resource) { + throw new RuntimeException("The file '{$filename}' could not be opened."); + } + + return $resource; + } } - -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/AddressApiController.php b/src/Bundle/ChillMainBundle/Controller/AddressApiController.php index 5c90cc9a7..9a5f9cc62 100644 --- a/src/Bundle/ChillMainBundle/Controller/AddressApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/AddressApiController.php @@ -1,5 +1,12 @@ flush(); return $this->json($new, Response::HTTP_OK, [], [ - AbstractNormalizer::GROUPS => ['read'] + AbstractNormalizer::GROUPS => ['read'], ]); - } - } diff --git a/src/Bundle/ChillMainBundle/Controller/AddressReferenceAPIController.php b/src/Bundle/ChillMainBundle/Controller/AddressReferenceAPIController.php index 3ec690677..6f6836730 100644 --- a/src/Bundle/ChillMainBundle/Controller/AddressReferenceAPIController.php +++ b/src/Bundle/ChillMainBundle/Controller/AddressReferenceAPIController.php @@ -1,5 +1,12 @@ query->has('postal_code')) { - $qb->where('e.postcode = :postal_code') - ->setParameter('postal_code', $request->query->get('postal_code')); - + ->setParameter('postal_code', $request->query->get('postal_code')); } - } protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format) @@ -33,5 +33,4 @@ class AddressReferenceAPIController extends ApiController return $query; } - } diff --git a/src/Bundle/ChillMainBundle/Controller/AdminController.php b/src/Bundle/ChillMainBundle/Controller/AdminController.php index 1fe10ef08..be6cc4e21 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; @@ -27,7 +15,6 @@ use Symfony\Component\Routing\Annotation\Route; class AdminController extends AbstractController { - /** * @Route("/{_locale}/admin", name="chill_main_admin_central") */ @@ -36,14 +23,13 @@ class AdminController extends AbstractController return $this->render('@ChillMain/Admin/index.html.twig'); } - public function indexPermissionsAction() - { - return $this->render('@ChillMain/Admin/layout_permissions.html.twig'); - } - public function indexLocationsAction() { return $this->render('@ChillMain/Admin/layout_location.html.twig'); } + public function indexPermissionsAction() + { + return $this->render('@ChillMain/Admin/layout_permissions.html.twig'); + } } diff --git a/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php b/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php index 3be418698..a0447a1c7 100644 --- a/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php +++ b/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php @@ -1,5 +1,12 @@ 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 +35,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 +60,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 +136,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..eab491c52 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -1,86 +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\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 +78,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 +142,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 +162,7 @@ class ExportController extends AbstractController * * @param string $request * @param Request $alias + * * @return \Symfony\Component\HttpFoundation\Response */ public function newAction(Request $request, $alias) @@ -137,7 +171,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 +180,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 +270,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 +283,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 +321,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 +346,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 +377,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 +388,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 +411,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 +444,119 @@ 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/LocationApiController.php b/src/Bundle/ChillMainBundle/Controller/LocationApiController.php index c21eaaf26..52b6f1e81 100644 --- a/src/Bundle/ChillMainBundle/Controller/LocationApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/LocationApiController.php @@ -1,15 +1,21 @@ expr()->neq('e.name', ':emptyString'), ) )) - ->setParameters([ - 'user' => $this->getUser(), - 'dateBefore' => (new \DateTime())->sub(new \DateInterval('P6M')), - 'emptyString' => '', - ]); + ->setParameters([ + 'user' => $this->getUser(), + 'dateBefore' => (new DateTime())->sub(new DateInterval('P6M')), + 'emptyString' => '', + ]); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillMainBundle/Controller/LocationController.php b/src/Bundle/ChillMainBundle/Controller/LocationController.php index fb1c1c61a..ca740bcb5 100644 --- a/src/Bundle/ChillMainBundle/Controller/LocationController.php +++ b/src/Bundle/ChillMainBundle/Controller/LocationController.php @@ -1,5 +1,12 @@ where('e.availableForUsers = true'); //TODO not working - } - protected function createEntity(string $action, Request $request): object { $entity = parent::createEntity($action, $request); @@ -20,4 +22,9 @@ class LocationController extends CRUDController return $entity; } + + protected function customizeQuery(string $action, Request $request, $query): void + { + $query->where('e.availableForUsers = true'); //TODO not working + } } diff --git a/src/Bundle/ChillMainBundle/Controller/LocationTypeApiController.php b/src/Bundle/ChillMainBundle/Controller/LocationTypeApiController.php index 2a3a6cc59..2ee0bc41b 100644 --- a/src/Bundle/ChillMainBundle/Controller/LocationTypeApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/LocationTypeApiController.php @@ -1,15 +1,19 @@ 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/NotificationController.php b/src/Bundle/ChillMainBundle/Controller/NotificationController.php index c76e19d9e..58be0a33a 100644 --- a/src/Bundle/ChillMainBundle/Controller/NotificationController.php +++ b/src/Bundle/ChillMainBundle/Controller/NotificationController.php @@ -1,14 +1,20 @@ security = $security; } - /** * @Route("/show", name="chill_main_notification_show") */ public function showAction( - NotificationRepository $notificationRepository, NotificationRenderer $notificationRenderer, - PaginatorFactory $paginatorFactory) - { + NotificationRepository $notificationRepository, + NotificationRenderer $notificationRenderer, + PaginatorFactory $paginatorFactory + ) { $currentUser = $this->security->getUser(); $notificationsNbr = $notificationRepository->countAllForAttendee(($currentUser)); @@ -37,15 +43,17 @@ class NotificationController extends AbstractController $notifications = $notificationRepository->findAllForAttendee( $currentUser, - $limit=$paginator->getItemsPerPage(), - $offset= $paginator->getCurrentPage()->getFirstItemNumber()); + $limit = $paginator->getItemsPerPage(), + $offset = $paginator->getCurrentPage()->getFirstItemNumber() + ); + + $templateData = []; - $templateData = array(); foreach ($notifications as $notification) { $data = [ 'template' => $notificationRenderer->getTemplate($notification), 'template_data' => $notificationRenderer->getTemplateData($notification), - 'notification' => $notification + 'notification' => $notification, ]; $templateData[] = $data; } 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..393849776 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,63 @@ 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/PostalCodeAPIController.php b/src/Bundle/ChillMainBundle/Controller/PostalCodeAPIController.php index 026784208..fc11a30d6 100644 --- a/src/Bundle/ChillMainBundle/Controller/PostalCodeAPIController.php +++ b/src/Bundle/ChillMainBundle/Controller/PostalCodeAPIController.php @@ -1,27 +1,27 @@ query->has('country')) { - $qb->where('e.country = :country') - ->setParameter('country', $request->query->get('country')); - + ->setParameter('country', $request->query->get('country')); } } - } diff --git a/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php b/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php index fb88e0763..04ac9332e 100644 --- a/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php +++ b/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php @@ -1,90 +1,76 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public 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 4ecc215f7..7d1a08f46 100644 --- a/src/Bundle/ChillMainBundle/Controller/SearchController.php +++ b/src/Bundle/ChillMainBundle/Controller/SearchController.php @@ -1,62 +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\MainBundle\Controller; +use Chill\MainBundle\Pagination\PaginatorFactory; +use Chill\MainBundle\Search\ParsingException; +use Chill\MainBundle\Search\SearchApi; use Chill\MainBundle\Search\SearchApiNoQueryException; -use Chill\MainBundle\Serializer\Model\Collection; -use GuzzleHttp\Psr7\Response; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; +use Chill\MainBundle\Search\SearchInterface; +use Chill\MainBundle\Search\SearchProvider; use Chill\MainBundle\Search\UnknowSearchDomainException; use Chill\MainBundle\Search\UnknowSearchNameException; -use Chill\MainBundle\Search\ParsingException; -use Chill\MainBundle\Search\SearchInterface; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; +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\Exception\BadRequestException; use Symfony\Component\HttpFoundation\JsonResponse; -use Chill\MainBundle\Search\SearchProvider; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Contracts\Translation\TranslatorInterface; -use Chill\MainBundle\Pagination\PaginatorFactory; -use Chill\MainBundle\Search\SearchApi; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; +use function key; +use function reset; /** - * Class SearchController - * - * @package Chill\MainBundle\Controller + * Class SearchController. */ class SearchController extends AbstractController { - protected SearchProvider $searchProvider; - - protected TranslatorInterface $translator; - protected PaginatorFactory $paginatorFactory; protected SearchApi $searchApi; - function __construct( + protected SearchProvider $searchProvider; + + protected TranslatorInterface $translator; + + public function __construct( SearchProvider $searchProvider, TranslatorInterface $translator, PaginatorFactory $paginatorFactory, @@ -68,127 +53,6 @@ class SearchController extends AbstractController $this->searchApi = $searchApi; } - - 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 searchApi(Request $request, $_format): JsonResponse - { - //TODO this is an incomplete implementation - $query = $request->query->get('q', ''); - $types = $request->query->get('type', []); - - if (count($types) === 0) { - throw new BadRequestException("The request must contains at " - ." one type"); - } - - try { - $collection = $this->searchApi->getResults($query, $types, []); - } catch (SearchApiNoQueryException $e) { - throw new BadRequestHttpException($e->getMessage(), $e); - } - - return $this->json($collection, \Symfony\Component\HttpFoundation\Response::HTTP_OK, [], [ "groups" => ["read"]]); - } - - 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 { @@ -196,16 +60,16 @@ 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 ?? []); @@ -219,17 +83,146 @@ class SearchController extends AbstractController ->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] + ); + } + + public function searchApi(Request $request, $_format): JsonResponse + { + //TODO this is an incomplete implementation + $query = $request->query->get('q', ''); + $types = $request->query->get('type', []); + + if (count($types) === 0) { + throw new BadRequestException('The request must contains at ' + . ' one type'); + } + + try { + $collection = $this->searchApi->getResults($query, $types, []); + } catch (SearchApiNoQueryException $e) { + throw new BadRequestHttpException($e->getMessage(), $e); + } + + return $this->json($collection, \Symfony\Component\HttpFoundation\Response::HTTP_OK, [], ['groups' => ['read']]); } protected function createAdvancedSearchForm($name, array $data = []) @@ -240,19 +233,17 @@ class SearchController extends AbstractController null, FormType::class, $data, - [ 'method' => Request::METHOD_POST ] + ['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/TimelineCenterController.php b/src/Bundle/ChillMainBundle/Controller/TimelineCenterController.php index af17993ed..55b809265 100644 --- a/src/Bundle/ChillMainBundle/Controller/TimelineCenterController.php +++ b/src/Bundle/ChillMainBundle/Controller/TimelineCenterController.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\MainBundle\Controller; -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; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\Role\Role; +use Chill\MainBundle\Timeline\TimelineBuilder; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Security; class TimelineCenterController extends AbstractController { - - protected TimelineBuilder $timelineBuilder; - protected PaginatorFactory $paginatorFactory; + protected TimelineBuilder $timelineBuilder; + private Security $security; - + public function __construct( TimelineBuilder $timelineBuilder, PaginatorFactory $paginatorFactory, @@ -52,15 +36,16 @@ class TimelineCenterController extends AbstractController /** * @Route("/{_locale}/center/timeline", - * name="chill_center_timeline", - * methods={"GET"} - * ) - */ + * name="chill_center_timeline", + * methods={"GET"} + * ) + */ public function centerAction(Request $request) { // collect reachable center for each group $user = $this->security->getUser(); $centers = []; + foreach ($user->getGroupCenters() as $group) { $centers[] = $group->getCenter(); } @@ -68,24 +53,26 @@ class TimelineCenterController extends AbstractController if (0 === count($centers)) { throw $this->createNotFoundException(); } - - $nbItems = $this->timelineBuilder->countItems('center', - [ 'centers' => $centers ] - ); - + + $nbItems = $this->timelineBuilder->countItems( + 'center', + ['centers' => $centers] + ); + $paginator = $this->paginatorFactory->create($nbItems); - - return $this->render('@ChillMain/Timeline/index.html.twig', array - ( + + return $this->render( + '@ChillMain/Timeline/index.html.twig', + [ 'timeline' => $this->timelineBuilder->getTimelineHTML( - 'center', - [ 'centers' => $centers ], + 'center', + ['centers' => $centers], $paginator->getCurrentPage()->getFirstItemNumber(), $paginator->getItemsPerPage() - ), + ), 'nb_items' => $nbItems, - 'paginator' => $paginator - ) + 'paginator' => $paginator, + ] ); } } 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/UserApiController.php b/src/Bundle/ChillMainBundle/Controller/UserApiController.php index 3742a7ded..46ba35155 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserApiController.php +++ b/src/Bundle/ChillMainBundle/Controller/UserApiController.php @@ -1,9 +1,15 @@ json($this->getUser(), JsonResponse::HTTP_OK, [], - [ "groups" => [ "read" ] ]); + return $this->json( + $this->getUser(), + JsonResponse::HTTP_OK, + [], + ['groups' => ['read']] + ); } - } diff --git a/src/Bundle/ChillMainBundle/Controller/UserController.php b/src/Bundle/ChillMainBundle/Controller/UserController.php index bd2ad89d7..4167bb173 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserController.php +++ b/src/Bundle/ChillMainBundle/Controller/UserController.php @@ -1,41 +1,46 @@ passwordEncoder = $passwordEncoder; } - protected function createFormFor(string $action, $entity, string $formClass = null, array $formOptions = []): FormInterface + /** + * @Route("/{_locale}/admin/main/user/{uid}/add_link_groupcenter", + * name="admin_user_add_groupcenter") + * + * @param mixed $uid + */ + public function addLinkGroupCenterAction(Request $request, $uid): Response + { + $em = $this->getDoctrine()->getManager(); + + $user = $em->getRepository('ChillMainBundle:User')->find($uid); + + if (!$user) { + throw $this->createNotFoundException('Unable to find User entity.'); + } + + $form = $this->createAddLinkGroupCenterForm($user, $request); + $form->handleRequest($request); + + if ($form->isValid()) { + $groupCenter = $this->getPersistedGroupCenter( + $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 ' + . 'permissions have been successfully added to the user')); + + $returnPathParams = $request->query->has('returnPath') ? + ['returnPath' => $request->query->get('returnPath')] : []; + + return $this->redirect($this->generateUrl( + 'chill_crud_admin_user_edit', + \array_merge(['id' => $uid], $returnPathParams) + )); + } + + foreach ($this->validator->validate($user) as $error) { + $this->addFlash('error', $error->getMessage()); + } + } + + return $this->render('@ChillMain/User/edit.html.twig', [ + 'entity' => $user, + 'edit_form' => $this->createEditForm($user)->createView(), + 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user, $request)->createView(), + 'delete_groupcenter_form' => array_map( + static fn (Form $form) => $form->createView(), + iterator_to_array($this->getDeleteLinkGroupCenterByUser($user, $request), true) + ), + ]); + } + + /** + * @Route("/{_locale}/admin/main/user/{uid}/delete_link_groupcenter/{gcid}", + * name="admin_user_delete_groupcenter") + * + * @param mixed $uid + * @param mixed $gcid + */ + public function deleteLinkGroupCenterAction($uid, $gcid, Request $request): RedirectResponse + { + $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('chill_crud_admin_user_edit', ['id' => $uid])); + } + + $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The permissions where removed.')); + + return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', ['id' => $uid])); + } + + /** + * Displays a form to edit the user current location. + * + * @Route("/{_locale}/main/user/current-location/edit", name="chill_main_user_currentlocation_edit") + */ + public function editCurrentLocationAction(Request $request) + { + $user = $this->getUser(); + $form = $this->createForm(UserCurrentLocationType::class, $user) + ->add('submit', SubmitType::class, ['label' => 'Save']) + ->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $currentLocation = $form->get('currentLocation')->getData(); + + $user->setCurrentLocation($currentLocation); + + $this->getDoctrine()->getManager()->flush(); + $this->addFlash('success', $this->get('translator')->trans('Current location successfully updated')); + + return $this->redirect( + $request->query->has('returnPath') ? $request->query->get('returnPath') : + $this->generateUrl('chill_main_homepage') + ); + } + + return $this->render('@ChillMain/User/edit_current_location.html.twig', [ + 'entity' => $user, + 'edit_form' => $form->createView(), + ]); + } + + /** + * Displays a form to edit the user password. + * + * @Route("/{_locale}/admin/user/{id}/edit_password", name="admin_user_edit_password") + */ + public function editPasswordAction(User $user, Request $request) + { + $editForm = $this->createEditPasswordForm($user); + $editForm->handleRequest($request); + + if ($editForm->isSubmitted() && $editForm->isValid()) { + $password = $editForm->get('new_password')->getData(); + + // logging for prod + $this->logger->info('update password for an user', [ + 'by' => $this->getUser()->getUsername(), + 'user' => $user->getUsername(), + ]); + + $user->setPassword($this->passwordEncoder->encodePassword($user, $password)); + + $this->getDoctrine()->getManager()->flush(); + $this->addFlash('success', $this->get('translator')->trans('Password successfully updated!')); + + return $this->redirect( + $request->query->has('returnPath') ? $request->query->get('returnPath') : + $this->generateUrl('chill_crud_admin_user_edit', ['id' => $user->getId()]) + ); + } + + return $this->render('@ChillMain/User/edit_password.html.twig', [ + 'entity' => $user, + 'edit_form' => $editForm->createView(), + ]); + } + + protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface { // for "new", add special config if ('new' === $action) { - return $this->createForm(UserType::class, $entity, array( - 'is_creation' => true - )); + return $this->createForm(UserType::class, $entity, [ + 'is_creation' => true, + ]); } // default behaviour return parent::createFormFor($action, $entity, $formClass, $formOptions); } + protected function generateTemplateParameter(string $action, $entity, Request $request, array $defaultTemplateParameters = []) + { + // add mini-forms for edit action + if ('edit' === $action) { + return array_merge( + $defaultTemplateParameters, + [ + 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($entity, $request)->createView(), + 'delete_groupcenter_form' => array_map( + function (Form $form) { + return $form->createView(); + }, + iterator_to_array($this->getDeleteLinkGroupCenterByUser($entity, $request), true) + ), + ] + ); + } + + // default behaviour + return parent::generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters); + } + protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request) { // for "new", encode the password @@ -78,202 +269,6 @@ class UserController extends CRUDController return parent::orderQuery($action, $query, $request, $paginator); } - protected function generateTemplateParameter(string $action, $entity, Request $request, array $defaultTemplateParameters = []) - { - // add mini-forms for edit action - if ("edit" === $action) { - return array_merge( - $defaultTemplateParameters, - [ - 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($entity, $request)->createView(), - 'delete_groupcenter_form' => array_map( - function(\Symfony\Component\Form\Form $form) { - return $form->createView(); - }, - iterator_to_array($this->getDeleteLinkGroupCenterByUser($entity, $request), true) - ) - ] - ); - } - - // default behaviour - return parent::generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters); - } - - /** - * Displays a form to edit the user password. - * - * @Route("/{_locale}/admin/user/{id}/edit_password", name="admin_user_edit_password") - */ - public function editPasswordAction(User $user, Request $request) - { - $editForm = $this->createEditPasswordForm($user); - $editForm->handleRequest($request); - - if ($editForm->isSubmitted() && $editForm->isValid()) { - $password = $editForm->get('new_password')->getData(); - - // logging for prod - $this->logger->info('update password for an user', [ - 'by' => $this->getUser()->getUsername(), - 'user' => $user->getUsername() - ]); - - $user->setPassword($this->passwordEncoder->encodePassword($user, $password)); - - $this->getDoctrine()->getManager()->flush(); - $this->addFlash('success', $this->get('translator')->trans('Password successfully updated!')); - - return $this->redirect( - $request->query->has('returnPath') ? $request->query->get('returnPath') : - $this->generateUrl('chill_crud_admin_user_edit', ['id' => $user->getId()]) - ); - } - - return $this->render('@ChillMain/User/edit_password.html.twig', [ - 'entity' => $user, - 'edit_form' => $editForm->createView() - ]); - } - - private function createEditPasswordForm(User $user): FormInterface - { - return $this->createForm( - UserPasswordType::class, - null, - [ - 'user' => $user - ] - ) - ->add('submit', SubmitType::class, array('label' => 'Change password')) - ->remove('actual_password'); - } - - /** - * @Route("/{_locale}/admin/main/user/{uid}/delete_link_groupcenter/{gcid}", - * name="admin_user_delete_groupcenter") - */ - public function deleteLinkGroupCenterAction($uid, $gcid, Request $request): RedirectResponse - { - $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('chill_crud_admin_user_edit', array('id' => $uid))); - } - - $em->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans('The permissions where removed.')); - - return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', array('id' => $uid))); - - } - - /** - * @Route("/{_locale}/admin/main/user/{uid}/add_link_groupcenter", - * name="admin_user_add_groupcenter") - */ - public function addLinkGroupCenterAction(Request $request, $uid): Response - { - $em = $this->getDoctrine()->getManager(); - - $user = $em->getRepository('ChillMainBundle:User')->find($uid); - - if (!$user) { - throw $this->createNotFoundException('Unable to find User entity.'); - } - - $form = $this->createAddLinkGroupCenterForm($user, $request); - $form->handleRequest($request); - - if ($form->isValid()) { - $groupCenter = $this->getPersistedGroupCenter( - $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 ' - . 'permissions have been successfully added to the user')); - - $returnPathParams = $request->query->has('returnPath') ? - ['returnPath' => $request->query->get('returnPath')] : []; - - return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', - \array_merge(['id' => $uid], $returnPathParams))); - - } - - foreach($this->validator->validate($user) as $error) { - $this->addFlash('error', $error->getMessage()); - } - } - - return $this->render('@ChillMain/User/edit.html.twig', [ - 'entity' => $user, - 'edit_form' => $this->createEditForm($user)->createView(), - 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user, $request)->createView(), - 'delete_groupcenter_form' => array_map( - static fn(Form $form) => $form->createView(), - iterator_to_array($this->getDeleteLinkGroupCenterByUser($user, $request), 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; - } - - /** - * Creates a form to delete a link to a GroupCenter - * - * @param mixed $permissionsGroup The entity id - */ - private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request): FormInterface - { - $returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : []; - - return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_user_delete_groupcenter', - array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()]))) - ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm(); - } - /** * Create a form to add a link to a groupcenter. */ @@ -282,18 +277,71 @@ class UserController extends CRUDController $returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : []; return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_user_add_groupcenter', - array_merge($returnPathParams, ['uid' => $user->getId()]))) + ->setAction($this->generateUrl( + 'admin_user_add_groupcenter', + array_merge($returnPathParams, ['uid' => $user->getId()]) + )) ->setMethod('POST') ->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class) - ->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter')) + ->add('submit', SubmitType::class, ['label' => 'Add a new groupCenter']) ->getForm(); } + /** + * Creates a form to delete a link to a GroupCenter. + * + * @param mixed $request + */ + private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request): FormInterface + { + $returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : []; + + return $this->createFormBuilder() + ->setAction($this->generateUrl( + 'admin_user_delete_groupcenter', + array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()]) + )) + ->setMethod('DELETE') + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); + } + + private function createEditPasswordForm(User $user): FormInterface + { + return $this->createForm( + UserPasswordType::class, + null, + [ + 'user' => $user, + ] + ) + ->add('submit', SubmitType::class, ['label' => 'Change password']) + ->remove('actual_password'); + } + private function getDeleteLinkGroupCenterByUser(User $user, Request $request) { foreach ($user->getGroupCenters() as $groupCenter) { yield $groupCenter->getId() => $this->createDeleteLinkGroupCenterForm($user, $groupCenter, $request); } } + + 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/LoadAbstractNotificationsTrait.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadAbstractNotificationsTrait.php index 629b6657e..a5ff75ec4 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadAbstractNotificationsTrait.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadAbstractNotificationsTrait.php @@ -1,34 +1,39 @@ notifs as $notif) { $entityId = $this->getReference($notif['entityRef'])->getId(); - print('Adding notification for '.$notif['entityClass'].'(entity id:'.$entityId.")\n"); + echo 'Adding notification for ' . $notif['entityClass'] . '(entity id:' . $entityId . ")\n"; $newNotif = (new Notification()) ->setMessage($notif['message']) ->setSender($this->getReference($notif['sender'])) ->setRelatedEntityClass($notif['entityClass']) ->setRelatedEntityId($entityId) - ->setDate(new \DateTimeImmutable('now')) - ->setRead([]) - ; + ->setDate(new DateTimeImmutable('now')) + ->setRead([]); foreach ($notif['addressees'] as $addressee) { $newNotif->addAddressee($this->getReference($addressee)); 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 a3c01fdf6..adcfe484e 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'], $center); static::$refs[] = $new['ref']; } - + $manager->flush(); } } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php index b26b5b991..84a2ba181 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php @@ -1,5 +1,12 @@ ['fr' => "Monsieur" ], 'abbrev' => ['fr' => 'M.']], - ['name' => ['fr' => "Madame" ], 'abbrev' => ['fr' => 'Mme']], - ['name' => ['fr' => "Docteur" ], 'abbrev' => ['fr' => 'Dr']], - ['name' => ['fr' => "Professeur" ], 'abbrev' => ['fr' => 'Pr']], - ['name' => ['fr' => "Madame la Directrice" ], 'abbrev' => ['fr' => 'Mme']], - ['name' => ['fr' => "Monsieur le Directeur" ], 'abbrev' => ['fr' => 'M.']], - ['name' => ['fr' => "Madame la Maire" ]], - ['name' => ['fr' => "Monsieur le Maire" ]], - ['name' => ['fr' => "Maître" ], 'abbrev' => ['fr' => 'Me']], + ['name' => ['fr' => 'Monsieur'], 'abbrev' => ['fr' => 'M.']], + ['name' => ['fr' => 'Madame'], 'abbrev' => ['fr' => 'Mme']], + ['name' => ['fr' => 'Docteur'], 'abbrev' => ['fr' => 'Dr']], + ['name' => ['fr' => 'Professeur'], 'abbrev' => ['fr' => 'Pr']], + ['name' => ['fr' => 'Madame la Directrice'], 'abbrev' => ['fr' => 'Mme']], + ['name' => ['fr' => 'Monsieur le Directeur'], 'abbrev' => ['fr' => 'M.']], + ['name' => ['fr' => 'Madame la Maire']], + ['name' => ['fr' => 'Monsieur le Maire']], + ['name' => ['fr' => 'Maître'], 'abbrev' => ['fr' => 'Me']], ]; - foreach ( $civilities as $val) { + foreach ($civilities as $val) { $civility = (new Civility()) ->setName($val['name']) ->setAbbreviation($val['abbrev'] ?? []) 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 e9e679392..cfa149411 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php @@ -1,60 +1,57 @@ + * 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) - { - $this->container = $container; - } + // 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() { + 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); } } @@ -62,12 +59,18 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface, $manager->flush(); } + public function setContainer(?ContainerInterface $container = null) + { + $this->container = $container; + } + /** * Prepare names for languages. * * @return string[] languages name indexed by available language code */ - private function prepareName(string $languageCode): array { + private function prepareName(string $languageCode): array + { $names = []; foreach ($this->container->getParameter('chill_main.available_languages') as $lang) { @@ -76,6 +79,4 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface, return $names; } - - } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLocationType.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLocationType.php index 4e103cc8e..72d1c05e5 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLocationType.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLocationType.php @@ -1,57 +1,56 @@ container = $container; - } - - public function getOrder() { return 52; } - public function load(ObjectManager $manager): void { - + public function load(ObjectManager $manager): void + { echo "loading some location type... \n"; $arr = [ [ 'name' => ['fr' => 'Mairie'], - 'address_required' => LocationType::STATUS_OPTIONAL + 'address_required' => LocationType::STATUS_OPTIONAL, ], [ 'name' => ['fr' => 'Guichet d\'accueil'], - 'address_required' => LocationType::STATUS_OPTIONAL + 'address_required' => LocationType::STATUS_OPTIONAL, ], [ 'name' => ['fr' => 'Domicile de l\'usager'], - 'address_required' => LocationType::STATUS_REQUIRED + 'address_required' => LocationType::STATUS_REQUIRED, ], [ 'name' => ['fr' => 'Centre d\'aide sociale'], - 'address_required' => LocationType::STATUS_OPTIONAL + 'address_required' => LocationType::STATUS_OPTIONAL, ], ]; @@ -66,4 +65,9 @@ class LoadLocationType extends AbstractFixture implements ContainerAwareInterfac $manager->flush(); } -} \ No newline at end of file + + public function setContainer(?ContainerInterface $container = null) + { + $this->container = $container; + } +} 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 947243f55..17728d14d 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPostalCodes.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPostalCodes.php @@ -1,48 +1,334 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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\Doctrine\Model\Point; use Chill\MainBundle\Entity\Country; +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 $postalCodeBelgium = <<<'EOF' + 1000,BRUXELLES,BE + 1020,BRUXELLES,BE + 1030,SCHAERBEEK,BE + 1040,ETTERBEEK,BE + 1050,IXELLES,BE + 1060,SAINT-GILLES,BE + 1070,ANDERLECHT,BE + 1080,MOLENBEEK-SAINT-JEAN,BE + 1081,KOEKELBERG,BE + 1082,BERCHEM-SAINTE-AGATHE,BE + 1083,GANSHOREN,BE + 1090,JETTE,BE + 1120,BRUXELLES,BE + 1130,BRUXELLES,BE + 1140,EVERE,BE + 1150,WOLUWE-SAINT-PIERRE,BE + 1160,AUDERGHEM,BE + 1170,WATERMAEL-BOITSFORT,BE + 1180,UCCLE,BE + 1190,FOREST,BE + 1200,WOLUWE-SAINT-LAMBERT,BE + 1210,SAINT-JOSSE-TEN-NOODE,BE + 1300,WAVRE,BE + 1300,WAVRE,BE + 1301,WAVRE,BE + 1310,LA HULPE,BE + 1315,INCOURT,BE + 1315,INCOURT,BE + 1315,INCOURT,BE + 1315,INCOURT,BE + 1315,INCOURT,BE + 1320,BEAUVECHAIN,BE + EOF; + + private static $postalCodeFrance = <<<'EOF' + 85000,LA ROCHE SUR YON,FR,85191,46.6675261644,-1.4077954093,INSEE + 85000,MOUILLERON LE CAPTIF,FR,85155,46.7104764993,-1.46129661418,INSEE + 85100,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE + 85110,STE CECILE,FR,85202,46.7309688326,-1.12107316048,INSEE + 85110,LA JAUDONNIERE,FR,85115,46.6488761831,-0.962477574588,INSEE + 85110,ST GERMAIN DE PRINCAY,FR,85220,46.7356314659,-1.04299885081,INSEE + 85110,MONSIREIGNE,FR,85145,46.7383480028,-0.931953130855,INSEE + 85110,ST VINCENT STERLANGES,FR,85276,46.7397220689,-1.08371759277,INSEE + 85110,SIGOURNAIS,FR,85282,46.7140097406,-0.98747730882,INSEE + 85110,CHANTONNAY,FR,85051,46.6690167793,-1.04372588019,INSEE + 85110,ST PROUANT,FR,85266,46.7502017421,-0.974504061491,INSEE + 85120,LA CHAPELLE AUX LYS,FR,85053,46.6221916887,-0.642706103195,INSEE + 85120,VOUVANT,FR,85305,46.5626835135,-0.764380170382,INSEE + 85120,ANTIGNY,FR,85005,46.6191770822,-0.767030058653,INSEE + 85120,ST MAURICE DES NOUES,FR,85251,46.5955876221,-0.724327725888,INSEE + 85120,LOGE FOUGEREUSE,FR,85125,46.6180854641,-0.6899276733,INSEE + 85120,LA TARDIERE,FR,85289,46.663737434,-0.727562430214,INSEE + 85120,LA CHATAIGNERAIE,FR,85059,46.6416143401,-0.739561966419,INSEE + 85120,ST HILAIRE DE VOUST,FR,85229,46.5914988312,-0.651486245674,INSEE + 85120,BREUIL BARRET,FR,85037,46.6503266235,-0.671948654426,INSEE + 85120,ST PIERRE DU CHEMIN,FR,85264,46.6957771744,-0.701777715154,INSEE + 85130,LA GAUBRETIERE,FR,85097,46.9345007303,-1.05578200702,INSEE + 85130,ST MARTIN DES TILLEULS,FR,85247,46.9711539531,-1.06282621567,INSEE + 85130,TIFFAUGES,FR,85293,47.0020573556,-1.09858009203,INSEE + 85130,CHANVERRIE,FR,85302,46.9634774521,-0.985340006089,INSEE + 85130,BAZOGES EN PAILLERS,FR,85013,46.9213757643,-1.14415666313,INSEE + 85130,LES LANDES GENUSSON,FR,85119,46.9663828627,-1.12900644447,INSEE + 85130,ST AUBIN DES ORMEAUX,FR,85198,46.9958175597,-1.04216568722,INSEE + 85140,ESSARTS EN BOCAGE,FR,85084,46.7806739038,-1.22925967851,INSEE + 85140,LA MERLATIERE,FR,85142,46.7557703112,-1.29794577,INSEE + 85140,ST MARTIN DES NOYERS,FR,85246,46.7239461187,-1.20379080965,INSEE + 85140,CHAUCHE,FR,85064,46.8282791899,-1.27090860656,INSEE + 85150,ST MATHURIN,FR,85250,46.5686332748,-1.70787622288,INSEE + 85150,MARTINET,FR,85138,46.6620680463,-1.6772013304,INSEE + 85150,STE FLAIVE DES LOUPS,FR,85211,46.611019489,-1.58031627863,INSEE + 85150,STE FOY,FR,85214,46.5327600427,-1.69243074733,INSEE + 85150,ST JULIEN DES LANDES,FR,85236,46.6395925444,-1.7159724914,INSEE + 85150,ST GEORGES DE POINTINDOUX,FR,85218,46.6423470977,-1.62881823574,INSEE + 85150,LE GIROUARD,FR,85099,46.5726064909,-1.58872487716,INSEE + 85150,LANDERONDE,FR,85118,46.6549237031,-1.57351777893,INSEE + 85150,LES ACHARDS,FR,85152,46.6163645636,-1.65038156849,INSEE + 85150,VAIRE,FR,85298,46.6055340621,-1.74863672042,INSEE + 85160,ST JEAN DE MONTS,FR,85234,46.8021968737,-2.04839789308,INSEE + 85170,BELLEVIGNY,FR,85019,46.7756383534,-1.43313700054,INSEE + 85170,LE POIRE SUR VIE,FR,85178,46.769919754,-1.50488626452,INSEE + 85170,BEAUFOU,FR,85015,46.8191122027,-1.52479250801,INSEE + 85170,DOMPIERRE SUR YON,FR,85081,46.7599858068,-1.37275519417,INSEE + 85170,LES LUCS SUR BOULOGNE,FR,85129,46.8527299002,-1.48398928084,INSEE + 85170,ST DENIS LA CHEVASSE,FR,85208,46.8325959261,-1.3830312677,INSEE + 85180,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE + 85190,AIZENAY,FR,85003,46.7384516809,-1.62702889721,INSEE + 85190,VENANSAULT,FR,85300,46.685677363,-1.54112129191,INSEE + 85190,MACHE,FR,85130,46.771364944,-1.69526445062,INSEE + 85190,BEAULIEU SOUS LA ROCHE,FR,85016,46.6872087211,-1.62355064963,INSEE + 85190,LA GENETOUZE,FR,85098,46.7244524541,-1.50410719693,INSEE + 85200,PISSOTTE,FR,85176,46.5010870694,-0.808352236192,INSEE + 85200,AUCHAY SUR VENDEE,FR,85009,46.4474386161,-0.876574265149,INSEE + 85200,FONTENAY LE COMTE,FR,85092,46.4563186117,-0.793449510859,INSEE + 85200,MERVENT,FR,85143,46.5325327351,-0.748519927998,INSEE + 85200,DOIX LES FONTAINES,FR,85080,46.3849492327,-0.806840287485,INSEE + 85200,LONGEVES,FR,85126,46.4722105292,-0.858917690239,INSEE + 85200,ST MARTIN DE FRAIGNEAU,FR,85244,46.4289052087,-0.758948963227,INSEE + 85200,SERIGNE,FR,85281,46.5054321828,-0.848819460581,INSEE + 85200,BOURNEAU,FR,85033,46.5476882922,-0.813838020265,INSEE + 85200,ST MICHEL LE CLOUCQ,FR,85256,46.4861591475,-0.743056336646,INSEE + 85200,MONTREUIL,FR,85148,46.3973419593,-0.840846860992,INSEE + 85200,L ORBRIE,FR,85167,46.4997145725,-0.77427886573,INSEE + 85210,ST JEAN DE BEUGNE,FR,85233,46.5196817523,-1.10826075013,INSEE + 85210,ST MARTIN LARS EN STE HERMINE,FR,85248,46.5970244335,-0.976384286709,INSEE + 85210,LA REORTHE,FR,85188,46.6113748938,-1.04881036553,INSEE + 85210,ST AUBIN LA PLAINE,FR,85199,46.5040293195,-1.06506577005,INSEE + 85210,ST JUIRE CHAMPGILLON,FR,85235,46.5882648491,-1.00959676911,INSEE + 85210,LA CHAPELLE THEMER,FR,85056,46.5639307793,-0.960376685588,INSEE + 85210,ST ETIENNE DE BRILLOUET,FR,85209,46.5138850327,-1.01157660374,INSEE + 85210,STE HERMINE,FR,85223,46.5572659953,-1.07210861039,INSEE + 85210,THIRE,FR,85290,46.5433098199,-1.00699777534,INSEE + 85220,ST MAIXENT SUR VIE,FR,85239,46.7329496925,-1.82595152879,INSEE + 85220,LA CHAIZE GIRAUD,FR,85045,46.6476375058,-1.81865076161,INSEE + 85220,LANDEVIEILLE,FR,85120,46.6444349925,-1.7854367847,INSEE + 85220,L AIGUILLON SUR VIE,FR,85002,46.6706426618,-1.82599992318,INSEE + 85220,COEX,FR,85070,46.7078707764,-1.75788339462,INSEE + 85220,ST REVEREND,FR,85268,46.7057741864,-1.83155480996,INSEE + 85220,APREMONT,FR,85006,46.7572682339,-1.74841313647,INSEE + 85220,LA CHAPELLE HERMIER,FR,85054,46.6826679204,-1.72083372442,INSEE + 85220,COMMEQUIERS,FR,85071,46.7674752232,-1.82534079642,INSEE + 85230,BEAUVOIR SUR MER,FR,85018,46.9086155426,-2.06349351302,INSEE + 85230,BOUIN,FR,85029,46.9815930867,-2.00423808381,INSEE + 85230,ST URBAIN,FR,85273,46.8818371328,-2.01607828912,INSEE + 85230,ST GERVAIS,FR,85221,46.9285711589,-1.98059327519,INSEE + 85240,MARILLET,FR,85136,46.5667525381,-0.634287713939,INSEE + 85240,ST HILAIRE DES LOGES,FR,85227,46.4747117878,-0.650611151998,INSEE + 85240,FAYMOREAU,FR,85087,46.5427361252,-0.624271378946,INSEE + 85240,XANTON CHASSENON,FR,85306,46.4519408659,-0.706316598666,INSEE + 85240,FOUSSAIS PAYRE,FR,85094,46.5230750581,-0.687135962627,INSEE + 85240,RIVES D AUTISE,FR,85162,46.424726987,-0.665995249042,INSEE + 85240,PUY DE SERRE,FR,85184,46.5650384637,-0.680144631346,INSEE + 85250,ST ANDRE GOULE D OIE,FR,85196,46.8410224478,-1.19644211396,INSEE + 85250,LA RABATELIERE,FR,85186,46.8584147661,-1.2569733759,INSEE + 85250,CHAVAGNES EN PAILLERS,FR,85065,46.8951394423,-1.24054768713,INSEE + 85250,ST FULGENT,FR,85215,46.8705618525,-1.16246465678,INSEE + 85250,VENDRENNES,FR,85301,46.8226741756,-1.11650982164,INSEE + 85260,LA COPECHAGNIERE,FR,85072,46.8523980181,-1.34349746898,INSEE + 85260,L HERBERGEMENT,FR,85108,46.9166207979,-1.37033557148,INSEE + 85260,MONTREVERD,FR,85197,46.9277672307,-1.4126154924,INSEE + 85260,LES BROUZILS,FR,85038,46.8854235235,-1.33186892233,INSEE + 85270,NOTRE DAME DE RIEZ,FR,85189,46.7532179022,-1.8935292542,INSEE + 85270,ST HILAIRE DE RIEZ,FR,85226,46.7432732188,-1.96439228965,INSEE + 85280,LA FERRIERE,FR,85089,46.7215872927,-1.33469332327,INSEE + 85290,MORTAGNE SUR SEVRE,FR,85151,46.9910941319,-0.946500033344,INSEE + 85290,ST LAURENT SUR SEVRE,FR,85238,46.9506837971,-0.901123752328,INSEE + 85300,CHALLANS,FR,85047,46.8354416653,-1.84036683139,INSEE + 85300,FROIDFOND,FR,85095,46.8789464367,-1.75511438567,INSEE + 85300,SOULLANS,FR,85284,46.7951288466,-1.91392699457,INSEE + 85300,LE PERRIER,FR,85172,46.8196487652,-1.97926629071,INSEE + 85300,SALLERTAINE,FR,85280,46.8659054157,-1.94894081389,INSEE + 85310,LA CHAIZE LE VICOMTE,FR,85046,46.6729533879,-1.29188591019,INSEE + 85310,NESMY,FR,85160,46.5921936479,-1.40947698594,INSEE + 85310,RIVES DE L YON,FR,85213,46.605637391,-1.3354497172,INSEE + 85310,LE TABLIER,FR,85285,46.5596307281,-1.32788759657,INSEE + 85320,CHATEAU GUIBERT,FR,85061,46.5741109302,-1.25524886228,INSEE + 85320,LES PINEAUX,FR,85175,46.599225902,-1.17865799724,INSEE + 85320,ROSNAY,FR,85193,46.5324344973,-1.3007139449,INSEE + 85320,BESSAY,FR,85023,46.5397253861,-1.17028433093,INSEE + 85320,LA BRETONNIERE LA CLAYE,FR,85036,46.4879459421,-1.26773426545,INSEE + 85320,CORPE,FR,85073,46.5050234767,-1.17034425311,INSEE + 85320,MAREUIL SUR LAY DISSAIS,FR,85135,46.5335825488,-1.22688907859,INSEE + 85320,PEAULT,FR,85171,46.502029199,-1.22708559855,INSEE + 85320,LA COUTURE,FR,85074,46.523938732,-1.26493227292,INSEE + 85320,MOUTIERS SUR LE LAY,FR,85157,46.5651677306,-1.16826489836,INSEE + 85320,STE PEXINE,FR,85261,46.5596018797,-1.12406235901,INSEE + 85330,NOIRMOUTIER EN L ILE,FR,85163,47.0086655085,-2.26243620205,INSEE + 85340,L ILE D OLONNE,FR,85112,46.570163703,-1.7737502368,INSEE + 85340,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE + 85350,L ILE D YEU,FR,85113,46.7093514816,-2.34712702345,INSEE + 85360,LA TRANCHE SUR MER,FR,85294,46.3564601605,-1.43136322126,INSEE + 85370,MOUZEUIL ST MARTIN,FR,85158,46.4591118412,-0.984449849889,INSEE + 85370,NALLIERS,FR,85159,46.4658962703,-1.03958611312,INSEE + 85370,LE LANGON,FR,85121,46.4393119039,-0.947017086151,INSEE + 85390,BAZOGES EN PAREDS,FR,85014,46.6602005512,-0.914053446792,INSEE + 85390,ST MAURICE LE GIRARD,FR,85252,46.6398624578,-0.810875649028,INSEE + 85390,TALLUD STE GEMME,FR,85287,46.6949386862,-0.886169517112,INSEE + 85390,CHAVAGNES LES REDOUX,FR,85066,46.7101499475,-0.915900131393,INSEE + 85390,CHEFFOIS,FR,85067,46.6786935635,-0.782949851125,INSEE + 85390,MOUILLERON ST GERMAIN,FR,85154,46.6612700667,-0.846784201071,INSEE + 85400,STE GEMME LA PLAINE,FR,85216,46.4732196212,-1.11103084694,INSEE + 85400,LAIROUX,FR,85117,46.4496842668,-1.27114022202,INSEE + 85400,LUCON,FR,85128,46.4510564854,-1.16449285012,INSEE + 85400,LES MAGNILS REIGNIERS,FR,85131,46.4635045649,-1.210635375,INSEE + 85400,CHASNAIS,FR,85058,46.4459908481,-1.2385924923,INSEE + 85410,ST LAURENT DE LA SALLE,FR,85237,46.5854041653,-0.922177315485,INSEE + 85410,LA CAILLERE ST HILAIRE,FR,85040,46.6293907412,-0.933153931505,INSEE + 85410,ST CYR DES GATS,FR,85205,46.572397925,-0.86344873853,INSEE + 85410,THOUARSAIS BOUILDROUX,FR,85292,46.6062740621,-0.873461023865,INSEE + 85410,CEZAIS,FR,85041,46.5917363748,-0.802618133558,INSEE + 85410,ST SULPICE EN PAREDS,FR,85271,46.6130038733,-0.8310839288,INSEE + 85420,LE MAZEAU,FR,85139,46.3298580373,-0.672957405035,INSEE + 85420,LIEZ,FR,85123,46.3698532376,-0.70502476758,INSEE + 85420,BOUILLE COURDAULT,FR,85028,46.3847932448,-0.684917815779,INSEE + 85420,DAMVIX,FR,85078,46.32063079,-0.743504259797,INSEE + 85420,MAILLE,FR,85132,46.3417503082,-0.787487297301,INSEE + 85420,ST PIERRE LE VIEUX,FR,85265,46.4009643491,-0.742816267425,INSEE + 85420,ST SIGISMOND,FR,85269,46.3368577973,-0.707293731101,INSEE + 85420,MAILLEZAIS,FR,85133,46.3642178261,-0.750260780443,INSEE + 85420,RIVES D AUTISE,FR,85162,46.424726987,-0.665995249042,INSEE + 85430,AUBIGNY LES CLOUZEAUX,FR,85008,46.6028241769,-1.46743549114,INSEE + 85430,NIEUL LE DOLENT,FR,85161,46.5676509922,-1.51560194548,INSEE + 85430,LA BOISSIERE DES LANDES,FR,85026,46.5581861734,-1.44371985689,INSEE + 85440,ST HILAIRE LA FORET,FR,85231,46.4551155186,-1.53048160541,INSEE + 85440,TALMONT ST HILAIRE,FR,85288,46.475786445,-1.62751498166,INSEE + 85440,POIROUX,FR,85179,46.5107890457,-1.53929317556,INSEE + 85440,GROSBREUIL,FR,85103,46.5390090882,-1.6072005484,INSEE + 85440,AVRILLE,FR,85010,46.4744272125,-1.49524360118,INSEE + 85450,CHAMPAGNE LES MARAIS,FR,85049,46.3735020647,-1.13380723653,INSEE + 85450,LA TAILLEE,FR,85286,46.3852513569,-0.941017792066,INSEE + 85450,CHAILLE LES MARAIS,FR,85042,46.3853555319,-1.01044079362,INSEE + 85450,VOUILLE LES MARAIS,FR,85304,46.3891941167,-0.968106001439,INSEE + 85450,MOREILLES,FR,85149,46.4218721314,-1.09404530407,INSEE + 85450,PUYRAVAULT,FR,85185,46.3653834101,-1.09115660367,INSEE + 85450,STE RADEGONDE DES NOYERS,FR,85267,46.3694246909,-1.06671995264,INSEE + 85460,LA FAUTE SUR MER,FR,85307,46.3199919131,-1.31487049579,INSEE + 85460,L AIGUILLON SUR MER,FR,85001,46.304138479,-1.2623239198,INSEE + 85470,BRETIGNOLLES SUR MER,FR,85035,46.6374826705,-1.86324200464,INSEE + 85470,BREM SUR MER,FR,85243,46.6118566989,-1.81003917923,INSEE + 85480,BOURNEZEAU,FR,85034,46.6296975315,-1.14101742229,INSEE + 85480,FOUGERE,FR,85093,46.6617881911,-1.23612691916,INSEE + 85480,ST HILAIRE LE VOUHIS,FR,85232,46.6859198669,-1.15222590884,INSEE + 85480,THORIGNY,FR,85291,46.6179795025,-1.24888057642,INSEE + 85490,BENET,FR,85020,46.368873213,-0.613959918706,INSEE + 85500,BEAUREPAIRE,FR,85017,46.9050210355,-1.10144867013,INSEE + 85500,ST PAUL EN PAREDS,FR,85259,46.8303789022,-0.964515191283,INSEE + 85500,LES HERBIERS,FR,85109,46.8666125813,-1.02216086186,INSEE + 85500,MESNARD LA BAROTIERE,FR,85144,46.851716793,-1.10954466033,INSEE + 85500,CHANVERRIE,FR,85302,46.9634774521,-0.985340006089,INSEE + 85510,ROCHETREJOUX,FR,85192,46.7852546732,-0.996743019108,INSEE + 85510,LE BOUPERE,FR,85031,46.7877960262,-0.930897406714,INSEE + 85520,JARD SUR MER,FR,85114,46.4246376808,-1.60014921643,INSEE + 85520,ST VINCENT SUR JARD,FR,85278,46.4297504489,-1.54956205778,INSEE + 85530,LA BRUFFIERE,FR,85039,47.0148006973,-1.18329758318,INSEE + 85540,LE CHAMP ST PERE,FR,85050,46.5157210212,-1.33946630196,INSEE + 85540,LE GIVRE,FR,85101,46.4729146043,-1.40256149118,INSEE + 85540,MOUTIERS LES MAUXFAITS,FR,85156,46.489279204,-1.43622387207,INSEE + 85540,ST VINCENT SUR GRAON,FR,85277,46.5034756656,-1.382954206,INSEE + 85540,LA JONCHERE,FR,85116,46.4358647401,-1.38517843312,INSEE + 85540,ST BENOIST SUR MER,FR,85201,46.4266286403,-1.3399129604,INSEE + 85540,CURZON,FR,85077,46.4512376923,-1.30138059216,INSEE + 85540,ST AVAUGOURD DES LANDES,FR,85200,46.5136722903,-1.47528120789,INSEE + 85540,ST CYR EN TALMONDAIS,FR,85206,46.4597334032,-1.33722144355,INSEE + 85550,LA BARRE DE MONTS,FR,85012,46.8722784154,-2.09984018879,INSEE + 85560,LE BERNARD,FR,85022,46.44832528,-1.43979865314,INSEE + 85560,LONGEVILLE SUR MER,FR,85127,46.4091029013,-1.47711855345,INSEE + 85570,POUILLE,FR,85181,46.5022256779,-0.955223380119,INSEE + 85570,ST VALERIEN,FR,85274,46.5348508899,-0.944470507825,INSEE + 85570,L HERMENAULT,FR,85110,46.5156262822,-0.898430664265,INSEE + 85570,PETOSSE,FR,85174,46.4796848965,-0.911734176662,INSEE + 85570,ST MARTIN DES FONTAINES,FR,85245,46.5464637508,-0.907394581139,INSEE + 85570,MARSAIS STE RADEGONDE,FR,85137,46.5380790745,-0.868868309437,INSEE + 85580,ST DENIS DU PAYRE,FR,85207,46.4118936776,-1.27222282402,INSEE + 85580,ST MICHEL EN L HERM,FR,85255,46.3366903175,-1.2483968538,INSEE + 85580,TRIAIZE,FR,85297,46.3792685111,-1.19928351422,INSEE + 85580,GRUES,FR,85104,46.3813091348,-1.32364519268,INSEE + 85590,TREIZE VENTS,FR,85296,46.9168130123,-0.845959158017,INSEE + 85590,LES EPESSES,FR,85082,46.8917166066,-0.903422756546,INSEE + 85590,MALLIEVRE,FR,85134,46.9112847287,-0.864977836096,INSEE + 85590,ST MALO DU BOIS,FR,85240,46.9248120291,-0.914182961099,INSEE + 85590,ST MARS LA REORTHE,FR,85242,46.8597253005,-0.925777900202,INSEE + 85600,LA BOISSIERE DE MONTAIGU,FR,85025,46.9451858636,-1.1916392484,INSEE + 85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE + 85600,TREIZE SEPTIERS,FR,85295,46.9975586143,-1.23193361154,INSEE + 85610,CUGAND,FR,85076,47.0602388146,-1.25289811103,INSEE + 85610,LA BERNARDIERE,FR,85021,47.0361828072,-1.27390355206,INSEE + 85620,ROCHESERVIERE,FR,85190,46.9274273036,-1.50132208111,INSEE + 85630,BARBATRE,FR,85011,46.9335754783,-2.16743559847,INSEE + 85640,MOUCHAMPS,FR,85153,46.7870550926,-1.05454102867,INSEE + 85660,ST PHILBERT DE BOUAINE,FR,85262,46.9927907526,-1.5073882242,INSEE + 85670,LA CHAPELLE PALLUAU,FR,85055,46.7873638997,-1.62492863273,INSEE + 85670,FALLERON,FR,85086,46.8623928354,-1.70108938038,INSEE + 85670,ST ETIENNE DU BOIS,FR,85210,46.8418481774,-1.59617737479,INSEE + 85670,ST PAUL MONT PENIT,FR,85260,46.8070059547,-1.66964833149,INSEE + 85670,ST CHRISTOPHE DU LIGNERON,FR,85204,46.8151386519,-1.74035413493,INSEE + 85670,GRAND LANDES,FR,85102,46.8483283063,-1.64453002578,INSEE + 85670,PALLUAU,FR,85169,46.8063002019,-1.60225256402,INSEE + 85680,LA GUERINIERE,FR,85106,46.9669962053,-2.2302799245,INSEE + 85690,NOTRE DAME DE MONTS,FR,85164,46.8424284611,-2.10928732775,INSEE + 85700,SEVREMONT,FR,85090,46.8211105864,-0.854584153953,INSEE + 85700,LA MEILLERAIE TILLAY,FR,85140,46.742582825,-0.85478763606,INSEE + 85700,MONTOURNAIS,FR,85147,46.7502937556,-0.770013941158,INSEE + 85700,POUZAUGES,FR,85182,46.7812581702,-0.828778359084,INSEE + 85700,REAUMUR,FR,85187,46.7145137269,-0.816742537248,INSEE + 85700,MENOMBLET,FR,85141,46.7301338667,-0.728654955878,INSEE + 85700,ST MESMIN,FR,85254,46.8005779435,-0.748892533741,INSEE + 85710,BOIS DE CENE,FR,85024,46.9479643351,-1.89668693466,INSEE + 85710,CHATEAUNEUF,FR,85062,46.916944435,-1.9261131832,INSEE + 85710,LA GARNACHE,FR,85096,46.8977541296,-1.82443040539,INSEE + 85740,L EPINE,FR,85083,46.9843405667,-2.26449527608,INSEE + 85750,ANGLES,FR,85004,46.3870511077,-1.40049386944,INSEE + 85770,LES VELLUIRE SUR VENDEE,FR,85177,46.4190919441,-0.910475769222,INSEE + 85770,VIX,FR,85303,46.3543018169,-0.856628326667,INSEE + 85770,LE GUE DE VELLUIRE,FR,85105,46.3675950645,-0.905432724485,INSEE + 85770,L ILE D ELLE,FR,85111,46.3334258655,-0.919100677098,INSEE + 85800,ST GILLES CROIX DE VIE,FR,85222,46.6904708814,-1.91946363327,INSEE + 85800,LE FENOUILLER,FR,85088,46.7161264566,-1.89206667498,INSEE + 85800,GIVRAND,FR,85100,46.6822701061,-1.8787272243,INSEE + EOF; + public function getOrder() { return 50; } - - public static $refs = []; public function load(ObjectManager $manager) { @@ -51,342 +337,40 @@ class LoadPostalCodes extends AbstractFixture implements OrderedFixtureInterface $this->loadPostalCodeCSV($manager, self::$postalCodeFrance, 'FR'); } - private function loadPostalCodeCSV(ObjectManager $manager, string $csv, string $countryCode) { - + private function loadPostalCodeCSV(ObjectManager $manager, string $csv, string $countryCode) + { $lines = str_getcsv($csv, "\n"); $country = $manager->getRepository(Country::class) - ->findOneBy(['countryCode' => $countryCode]); - - foreach($lines as $line) { - $code = str_getcsv($line); + ->findOneBy(['countryCode' => $countryCode]); + + foreach ($lines as $line) { + $code = str_getcsv($line); $c = new PostalCode(); $c->setCountry($country) - ->setCode($code[0]) - ->setName(\ucwords(\strtolower($code[1]))) - ; + ->setCode($code[0]) + ->setName(ucwords(strtolower($code[1]))); - if (NULL != $code[3]){ + if (null != $code[3]) { $c->setRefPostalCodeId($code[3]); } - if (NULL != $code[4] & NULL != $code[5]){ + if (null != $code[4] & null != $code[5]) { $c->setCenter(Point::fromLonLat((float) $code[5], (float) $code[4])); } - if (NULL != $code[6]){ + if (null != $code[6]) { $c->setPostalCodeSource($code[6]); } $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 $postalCodeBelgium = << - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public 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 02f1bfd18..70c6fe1dc 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUsers.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUsers.php @@ -1,30 +1,59 @@ */ 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; @@ -34,58 +63,31 @@ class LoadUsers extends AbstractFixture implements OrderedFixtureInterface, Cont 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 +95,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 da53ba3af..4fc4fb752 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.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; @@ -23,60 +13,64 @@ use Chill\MainBundle\Controller\AddressApiController; use Chill\MainBundle\Controller\LocationController; use Chill\MainBundle\Controller\LocationTypeController; use Chill\MainBundle\Controller\UserController; -use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength; -use Chill\MainBundle\Doctrine\DQL\STContains; -use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\UserJob; -use Chill\MainBundle\Form\UserJobType; -use Chill\MainBundle\Form\UserType; -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\JsonbArrayLength; use Chill\MainBundle\Doctrine\DQL\JsonbExistsInArray; -use Chill\MainBundle\Doctrine\DQL\Similarity; use Chill\MainBundle\Doctrine\DQL\OverlapsI; use Chill\MainBundle\Doctrine\DQL\Replace; +use Chill\MainBundle\Doctrine\DQL\Similarity; +use Chill\MainBundle\Doctrine\DQL\STContains; +use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS; +use Chill\MainBundle\Doctrine\DQL\Unaccent; use Chill\MainBundle\Doctrine\ORM\Hydration\FlatHierarchyEntityHydrator; use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType; use Chill\MainBundle\Doctrine\Type\PointType; use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\LocationType; -use Chill\MainBundle\Form\LocationTypeType; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Entity\UserJob; use Chill\MainBundle\Form\LocationFormType; +use Chill\MainBundle\Form\LocationTypeType; +use Chill\MainBundle\Form\UserJobType; +use Chill\MainBundle\Form\UserType; +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 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[] */ @@ -86,10 +80,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) { @@ -101,38 +92,55 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, $container->setParameter('chill_main', $config); // legacy config - $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.available_countries', - $config['available_countries']); + $container->setParameter( + 'chill_main.available_countries', + $config['available_countries'] + ); - $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'); @@ -159,33 +167,20 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, $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) @@ -215,7 +210,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, ], ], ], - ); + ); //add dbal types (default entity_manager) $container @@ -231,45 +226,43 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, ], 'types' => [ 'dateinterval' => [ - 'class' => NativeDateIntervalType::class + 'class' => NativeDateIntervalType::class, ], 'point' => [ - 'class' => PointType::class - ] - ] - ] + 'class' => 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'], + ]); //add crud api $this->prependCruds($container); } /** - * 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; } @@ -282,10 +275,6 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, // Note: the controller are loaded inside compiler pass } - - /** - * @param ContainerBuilder $container - */ protected function prependCruds(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ @@ -302,11 +291,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, 'template' => '@ChillMain/UserJob/index.html.twig', ], 'new' => [ - 'role' => 'ROLE_ADMIN' + 'role' => 'ROLE_ADMIN', ], 'edit' => [ - 'role' => 'ROLE_ADMIN' - ] + 'role' => 'ROLE_ADMIN', + ], ], ], [ @@ -319,17 +308,17 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, 'actions' => [ 'index' => [ 'role' => 'ROLE_ADMIN', - 'template' => '@ChillMain/User/index.html.twig' + 'template' => '@ChillMain/User/index.html.twig', ], 'new' => [ 'role' => 'ROLE_ADMIN', - 'template' => '@ChillMain/User/new.html.twig' + 'template' => '@ChillMain/User/new.html.twig', ], 'edit' => [ 'role' => 'ROLE_ADMIN', - 'template' => '@ChillMain/User/edit.html.twig' - ] - ] + 'template' => '@ChillMain/User/edit.html.twig', + ], + ], ], [ 'class' => Location::class, @@ -343,15 +332,15 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, 'role' => 'ROLE_ADMIN', 'template' => '@ChillMain/Location/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillMain/Location/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillMain/Location/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => LocationType::class, @@ -365,15 +354,15 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, 'role' => 'ROLE_ADMIN', 'template' => '@ChillMain/LocationType/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillMain/LocationType/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillMain/LocationType/edit.html.twig', - ] - ] + ], + ], ], ], 'apis' => [ @@ -387,7 +376,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ @@ -395,10 +384,10 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, Request::METHOD_GET => true, Request::METHOD_POST => true, Request::METHOD_HEAD => true, - Request::METHOD_PATCH => true - ] + Request::METHOD_PATCH => true, + ], ], - ] + ], ], [ 'controller' => \Chill\MainBundle\Controller\AddressReferenceAPIController::class, @@ -410,16 +399,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true - ] + Request::METHOD_HEAD => true, + ], ], - ] + ], ], [ 'controller' => \Chill\MainBundle\Controller\PostalCodeAPIController::class, @@ -431,7 +420,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ @@ -439,9 +428,9 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, Request::METHOD_GET => true, Request::METHOD_HEAD => true, Request::METHOD_POST => true, - ] + ], ], - ] + ], ], [ 'class' => \Chill\MainBundle\Entity\Country::class, @@ -452,16 +441,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true - ] + Request::METHOD_HEAD => true, + ], ], - ] + ], ], [ 'class' => \Chill\MainBundle\Entity\User::class, @@ -473,16 +462,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - ] + ], ], - ] + ], ], [ 'class' => \Chill\MainBundle\Entity\Scope::class, @@ -493,16 +482,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - ] + ], ], - ] + ], ], [ 'class' => \Chill\MainBundle\Entity\Location::class, @@ -514,7 +503,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ @@ -522,10 +511,9 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, Request::METHOD_GET => true, Request::METHOD_HEAD => true, Request::METHOD_POST => true, - ] + ], ], - - ] + ], ], [ 'class' => \Chill\MainBundle\Entity\LocationType::class, @@ -537,19 +525,18 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - ] + ], ], - - ] - ] - ] + ], + ], + ], ]); } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php index 91dff76ad..b8b3b4d85 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php @@ -1,14 +1,21 @@ 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 LogicException(sprintf( - "This tag 'scope' is not implemented: %s, on service with id %s", $tag['scope'], $id) - ); + throw new LogicException( + 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 7cf3aed50..85d0150ba 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php @@ -1,38 +1,37 @@ setWidgetFactories($widgetFactories); $this->containerBuilder = $containerBuilder; } - /** - * {@inheritDoc} - */ public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder('chill_main'); @@ -40,225 +39,220 @@ 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('available_countries') - ->defaultValue(array('FR')) - ->prototype('scalar')->end() - ->end() // end of array 'available_countries' - ->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('acl') - ->addDefaultsIfNotSet() - ->children() - ->booleanNode('form_show_scopes') - ->defaultTrue() - ->end() - ->booleanNode('form_show_centers') - ->defaultTrue() - ->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('available_countries') + ->defaultValue(['FR']) + ->prototype('scalar')->end() + ->end() // end of array 'available_countries' + ->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('acl') + ->addDefaultsIfNotSet() + ->children() + ->booleanNode('form_show_scopes') + ->defaultTrue() + ->end() + ->booleanNode('form_show_centers') + ->defaultTrue() + ->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() - ->booleanNode(Request::METHOD_PATCH)->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() - ->scalarNode(Request::METHOD_PATCH)->defaultNull()->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - - ->end() - ->end() // end of root/children + ->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() + ->booleanNode(Request::METHOD_PATCH)->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() + ->scalarNode(Request::METHOD_PATCH)->defaultNull()->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->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 e0dffdb21..b8eebc3be 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php @@ -1,32 +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\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. @@ -57,37 +49,30 @@ use Chill\MainBundle\DependencyInjection\Widget\HasWidgetFactoriesExtensionInter * } * } * ``` - * - * */ 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'; - - /** - * the value of the `name` key in service definitions's tag - * - * @var string - */ - const WIDGET_SERVICE_TAG_NAME = 'chill_widget'; + public const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget'; /** * the key used to collect the alias in the service definition's tag. @@ -96,34 +81,46 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface * * @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'; + public const WIDGET_SERVICE_TAG_NAME = 'chill_widget'; /** - * 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'; - - - /** - * process the configuration and the container to add the widget available + * 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 ContainerBuilder $container * @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 */ public function doProcess( ContainerBuilder $container, @@ -131,8 +128,8 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface $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); @@ -142,15 +139,16 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface $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 @@ -160,23 +158,22 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface $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", + 'The widget with alias %s is not allowed at place %s', $alias, $place - )); + )); } // get the order, eventually corrected @@ -189,64 +186,145 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface $factory = $this->widgetServices[$alias]; // get the config (under the key which equals to widget_alias $config = isset($param[$factory->getWidgetAlias()]) ? - $param[$factory->getWidgetAlias()] : array(); + $param[$factory->getWidgetAlias()] : []; // register the service into the container - $serviceId =$this->registerServiceIntoContainer($container, - $factory, $place, $order, $config); + $serviceId = $this->registerServiceIntoContainer( + $container, + $factory, + $place, + $order, + $config + ); - $managerDefinition->addMethodCall(self::WIDGET_MANAGER_METHOD_REGISTER, - array( - $place, - $order, - new Reference($serviceId), - $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 + ] + ); } } } } + /** + * This method collect all service tagged with `self::WIDGET_SERVICE_TAG`, and + * 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. + * + * @throws InvalidConfigurationException + * @throws InvalidArgumentException + */ + protected function collectTaggedServices(ContainerBuilder $container) + { + // 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); + } + + // 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', + 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]); + } + + // 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) { + /* @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) + )); + } + + // 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 ' . + 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()'); + } + + // 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); + } + + // register the factory as available + $this->widgetServices[$factory->getWidgetAlias()] = $factory; + } + } + /** * 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, + ContainerBuilder $container, + WidgetFactoryInterface $factory, + $place, + $order, + array $config + ) { + $serviceId = $factory->getServiceId($container, $place, $order, $config); + $definition = $factory->createDefinition( + $container, $place, $order, - array $config - ) { - $serviceId = $factory->getServiceId($container, $place, $order, $config); - $definition = $factory->createDefinition($container, $place, - $order, $config); + $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 @@ -256,44 +334,46 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface * * @param string $place * @param float $ordering + * * @return float */ - private function cacheAndGetOrdering($place, $ordering) { + 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(); + $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); - } else { - // cache the ordering - $this->cacheOrdering[$place][] = $ordering; - - return $ordering; } + // cache the ordering + $this->cacheOrdering[$place][] = $ordering; + + return $ordering; } /** - * get the places where the service is allowed + * get the places where the service is allowed. + * + * @param mixed $place + * @param mixed $widgetAlias * - * @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())) { + ->getAllowedPlaces())) { return true; } - } else { $definition = $container->findDefinition($this->widgetServices[$widgetAlias]); - foreach($definition->getTag(self::WIDGET_SERVICE_TAG_NAME) as $attrs) { + foreach ($definition->getTag(self::WIDGET_SERVICE_TAG_NAME) as $attrs) { $placeValue = $attrs[self::WIDGET_SERVICE_TAG_PLACES]; if ($placeValue === $place) { @@ -304,86 +384,4 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface return false; } - - /** - * This method collect all service tagged with `self::WIDGET_SERVICE_TAG`, and - * 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 - */ - protected function collectTaggedServices(ContainerBuilder $container) - { - // 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); - } - - // 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", - 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]); - } - - // 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) { - /* @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))); - } - - // 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 ". - 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()'); - } - - // 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); - } - - // register the factory as available - $this->widgetServices[$factory->getWidgetAlias()] = $factory; - - } - } - - } 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/JsonbArrayLength.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonbArrayLength.php index 39049748c..31b1504db 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonbArrayLength.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonbArrayLength.php @@ -1,8 +1,12 @@ - */ class JsonbExistsInArray extends FunctionNode { private $expr1; + private $expr2; public function getSql(SqlWalker $sqlWalker): string diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php index 083567960..52b39e97f 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php @@ -1,5 +1,12 @@ dispatch($sqlWalker), - $part->dispatch($sqlWalker), - $p - ); - } - - return sprintf( - "CASE WHEN %s::date IS NOT NULL THEN %s::date ELSE '%s'::date END", - $part->dispatch($sqlWalker), - $part->dispatch($sqlWalker), - $p - ); - } - public function parse(Parser $parser): void { $parser->match(Lexer::T_IDENTIFIER); @@ -92,4 +70,38 @@ class OverlapsI extends FunctionNode $parser->match(Lexer::T_CLOSE_PARENTHESIS); } + + protected function makeCase($sqlWalker, $part, string $position): string + { + switch ($position) { + case 'start': + $p = '-infinity'; + + break; + + case 'end': + $p = 'infinity'; + + break; + + default: + throw new Exception('Unexpected position value.'); + } + + if ($part instanceof PathExpression) { + return sprintf( + "CASE WHEN %s IS NOT NULL THEN %s ELSE '%s'::date END", + $part->dispatch($sqlWalker), + $part->dispatch($sqlWalker), + $p + ); + } + + return sprintf( + "CASE WHEN %s::date IS NOT NULL THEN %s::date ELSE '%s'::date END", + $part->dispatch($sqlWalker), + $part->dispatch($sqlWalker), + $p + ); + } } 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/STContains.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/STContains.php index 5235d51bb..9a28b6132 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/STContains.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/STContains.php @@ -1,28 +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\MainBundle\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\Lexer; /** - * Geometry function 'ST_CONTAINS', added by postgis + * Geometry function 'ST_CONTAINS', added by postgis. */ class STContains extends FunctionNode { @@ -32,8 +23,8 @@ class STContains extends FunctionNode public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { - return 'ST_CONTAINS('.$this->firstPart->dispatch($sqlWalker). - ', ' . $this->secondPart->dispatch($sqlWalker) .")"; + return 'ST_CONTAINS(' . $this->firstPart->dispatch($sqlWalker) . + ', ' . $this->secondPart->dispatch($sqlWalker) . ')'; } public function parse(\Doctrine\ORM\Query\Parser $parser) diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php index 1875f978c..0ef7d8b2f 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php @@ -1,21 +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\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; @@ -29,8 +20,8 @@ class Similarity extends FunctionNode 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) diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/StrictWordSimilarityOPS.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/StrictWordSimilarityOPS.php index 22dcda879..6606c2298 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/StrictWordSimilarityOPS.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/StrictWordSimilarityOPS.php @@ -1,5 +1,12 @@ firstPart->dispatch($sqlWalker). + return $this->firstPart->dispatch($sqlWalker) . ' <<% ' . $this->secondPart->dispatch($sqlWalker); } - public function parse(\Doctrine\ORM\Query\Parser $parser) + public function parse(Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_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/Event/TrackCreateUpdateSubscriber.php b/src/Bundle/ChillMainBundle/Doctrine/Event/TrackCreateUpdateSubscriber.php index 3926e2062..4c91f9679 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Event/TrackCreateUpdateSubscriber.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Event/TrackCreateUpdateSubscriber.php @@ -1,36 +1,37 @@ security = $security; } - - /** - * {@inheritDoc} - */ + public function getSubscribedEvents() { return [ Events::prePersist, - Events::preUpdate + Events::preUpdate, ]; } @@ -41,7 +42,7 @@ class TrackCreateUpdateSubscriber implements EventSubscriber if ($object instanceof TrackCreationInterface && $this->security->getUser() instanceof User) { $object->setCreatedBy($this->security->getUser()); - $object->setCreatedAt(new \DateTimeImmutable('now')); + $object->setCreatedAt(new DateTimeImmutable('now')); } $this->onUpdate($object); @@ -56,10 +57,10 @@ class TrackCreateUpdateSubscriber implements EventSubscriber protected function onUpdate(object $object): void { - if ($object instanceof TrackUpdateInterface + if ($object instanceof TrackUpdateInterface && $this->security->getUser() instanceof User) { $object->setUpdatedBy($this->security->getUser()); - $object->setUpdatedAt(new \DateTimeImmutable('now')); + $object->setUpdatedAt(new DateTimeImmutable('now')); } } } 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 20b59fbb7..423e23e04 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Model/Point.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Model/Point.php @@ -1,25 +1,79 @@ lat = $lat; $this->lon = $lon; } - public function toGeoJson(): string + public static function fromArrayGeoJson(array $array): self { - $array = $this->toArrayGeoJson(); + if ('Point' === $array['type'] && isset($array['coordinates'])) { + return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]); + } - return \json_encode($array); + throw new Exception('Unable to build a point from input data.'); + } + + public static function fromGeoJson(string $geojson): self + { + $a = json_decode($geojson); + + if (null === $a) { + throw PointException::badJsonString($geojson); + } + + if (null === $a->type || null === $a->coordinates) { + throw PointException::badJsonString($geojson); + } + + if ('Point' !== $a->type) { + throw PointException::badGeoType(); + } + + [$lon, $lat] = $a->coordinates; + + return Point::fromLonLat($lon, $lat); + } + + public static function fromLonLat(float $lon, float $lat): self + { + if ((-180 < $lon && 180 > $lon) && (-90 < $lat && 90 > $lat)) { + return new Point($lon, $lat); + } + + throw PointException::badCoordinates($lon, $lat); + } + + public function getLat(): float + { + return $this->lat; + } + + public function getLon(): float + { + return $this->lon; } public function jsonSerialize(): array @@ -35,59 +89,15 @@ class Point implements JsonSerializable { ]; } + public function toGeoJson(): string + { + $array = $this->toArrayGeoJson(); + + return json_encode($array); + } + public function toWKT(): string { - return sprintf("SRID=%s;POINT(%s %s)", self::$SRID, $this->lon, $this->lat); - } - - public static function fromGeoJson(string $geojson): self - { - $a = json_decode($geojson); - - if (null === $a) { - throw PointException::badJsonString($geojson); - } - - if (null === $a->type || null === $a->coordinates) { - throw PointException::badJsonString($geojson); - } - - if ($a->type !== 'Point'){ - throw PointException::badGeoType(); - } - - [$lon, $lat] = $a->coordinates; - - return Point::fromLonLat($lon, $lat); - } - - public static function fromLonLat(float $lon, float $lat): self - { - if (($lon > -180 && $lon < 180) && ($lat > -90 && $lat < 90)) { - return new Point($lon, $lat); - } - - throw PointException::badCoordinates($lon, $lat); - } - - public static function fromArrayGeoJson(array $array): self - { - if ($array['type'] === 'Point' && isset($array['coordinates'])) { - return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]); - } - - throw new \Exception('Unable to build a point from input data.'); - } - - public function getLat(): float - { - return $this->lat; - } - - public function getLon(): float - { - return $this->lon; + return sprintf('SRID=%s;POINT(%s %s)', self::$SRID, $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 @@ flatListGenerator($this->buildChildrenHashmap(parent::hydrateAllData())))); } - private function flatListGenerator(array $hashMap, ?object $parent = null): Generator - { - $parent = null === $parent ? null : spl_object_id($parent); - $hashMap += [$parent => []]; - - foreach ($hashMap[$parent] as $node) { - yield spl_object_id($node) => $node; - yield from $this->flatListGenerator($hashMap, $node); - } - } - private function buildChildrenHashmap(array $nodes): array { return array_reduce( @@ -44,4 +40,15 @@ final class FlatHierarchyEntityHydrator extends ObjectHydrator ); } + private function flatListGenerator(array $hashMap, ?object $parent = null): Generator + { + $parent = null === $parent ? null : spl_object_id($parent); + $hashMap += [$parent => []]; + + foreach ($hashMap[$parent] as $node) { + yield spl_object_id($node) => $node; + + yield from $this->flatListGenerator($hashMap, $node); + } + } } diff --git a/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php b/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php index 3f95f7b6e..1d90fe382 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php @@ -1,20 +1,68 @@ + * 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 { @@ -26,86 +74,52 @@ 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 9e42048f7..1d44b2358 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php @@ -1,69 +1,76 @@ toWKT(); + } + + public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) + { + return $sqlExpr; } /** + * @param mixed $value + * * @return ?Point */ public function convertToPHPValue($value, AbstractPlatform $platform) { - if ($value === NULL){ - return NULL; + if (null === $value) { + return null; } return Point::fromGeoJson($value); } + public function convertToPHPValueSQL($sqlExpr, $platform) + { + return 'ST_AsGeoJSON(' . $sqlExpr . ') '; + } + public function getName() { return self::POINT; } - public function convertToDatabaseValue($value, AbstractPlatform $platform) + /** + * @return string + */ + public function getSQLDeclaration(array $column, AbstractPlatform $platform) { - if ($value === NULL){ - return NULL; - } - - 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 06839ec99..9fabe8674 100644 --- a/src/Bundle/ChillMainBundle/Entity/Address.php +++ b/src/Bundle/ChillMainBundle/Entity/Address.php @@ -1,79 +1,36 @@ validFrom = new \DateTime(); + $this->validFrom = new DateTime(); } - /** - * Get id - * - * @return integer - */ - public function getId() - { - return $this->id; - } - - /** - * Set streetAddress1 (legacy function) - * - * @param string $streetAddress1 - * - * @return Address - */ - public function setStreetAddress1($streetAddress1) - { - $this->street = $streetAddress1 === NULL ? '' : $streetAddress1; - - return $this; - } - - /** - * Get streetAddress1 (legacy function) - * - * @return string - */ - public function getStreetAddress1() - { - return $this->street; - } - - /** - * Set streetAddress2 (legacy function) - * - * @param string $streetAddress2 - * - * @return Address - */ - public function setStreetAddress2($streetAddress2) - { - $this->streetNumber = $streetAddress2 === NULL ? '' : $streetAddress2; - - return $this; - } - - /** - * Get streetAddress2 (legacy function) - * - * @return string - */ - public function getStreetAddress2() - { - return $this->streetNumber; - } - - /** - * Set postcode - * - * @param PostalCode $postcode - * - * @return Address - */ - public function setPostcode(PostalCode $postcode = null) - { - $this->postcode = $postcode; - - return $this; - } - - /** - * Get postcode - * - * @return PostalCode - */ - public function getPostcode() - { - return $this->postcode; - } - - /** - * @return \DateTime - */ - public function getValidFrom() - { - return $this->validFrom; - } - - /** - * @param \DateTime $validFrom - * @return Address - */ - public function setValidFrom(\DateTime $validFrom) - { - $this->validFrom = $validFrom; - return $this; - } - - /** - * 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): self - { - $this->isNoAddress = $isNoAddress; - return $this; - } - - /** - * Get customs 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 - { - $this->customs = $customs; - - return $this; - } - - /** - * Validate the address. - * - * Check that: - * - * * if the address is not home address: - * * the postal code is present - * * 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) { - $context - ->buildViolation("address.date-should-be-set") - ->atPath('validFrom') - ->addViolation(); - } - - if ($this->isNoAddress()) { - return; - } - - if (empty($this->getStreetAddress1())) { - $context - ->buildViolation("address.street1-should-be-set") - ->atPath('streetAddress1') - ->addViolation(); - } - - if (!$this->getPostcode() instanceof PostalCode) { - $context - ->buildViolation("address.postcode-should-be-set") - ->atPath('postCode') - ->addViolation(); - } - } - - /** - * @param Address $original - * @return Address - */ - public static function createFromAddress(Address $original) : Address + public static function createFromAddress(Address $original): Address { return (new Address()) ->setAddressReference($original->getAddressReference()) @@ -398,8 +202,7 @@ class Address ->setStreet($original->getStreet()) ->setStreetNumber($original->getStreetNumber()) ->setValidFrom($original->getValidFrom()) - ->setValidTo($original->getValidTo()) - ; + ->setValidTo($original->getValidTo()); } public static function createFromAddressReference(AddressReference $original): Address @@ -409,44 +212,17 @@ class Address ->setPostcode($original->getPostcode()) ->setStreet($original->getStreet()) ->setStreetNumber($original->getStreetNumber()) - ->setAddressReference($original) - ; + ->setAddressReference($original); } - public function getStreet(): ?string + public function getAddressReference(): ?AddressReference { - return $this->street; + return $this->addressReference; } - public function setStreet(string $street): self + public function getBuildingName(): ?string { - $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; + return $this->buildingName; } public function getCorridor(): ?string @@ -454,11 +230,72 @@ class Address return $this->corridor; } - public function setCorridor(?string $corridor): self + /** + * Get customs informations in the address. + */ + public function getCustoms(): array { - $this->corridor = $corridor; + return $this->customs; + } - return $this; + 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 int + */ + public function getId() + { + return $this->id; + } + + /** + * Get IsNoAddress. + * + * Indicate true if the address is a fake address (homeless, ...) + */ + public function getIsNoAddress(): bool + { + return $this->isNoAddress; + } + + public function getLinkedToThirdParty() + { + return $this->linkedToThirdParty; + } + + public function getPoint(): ?Point + { + return $this->point; + } + + /** + * Get postcode. + * + * @return PostalCode + */ + public function getPostcode() + { + return $this->postcode; } public function getSteps(): ?string @@ -466,16 +303,59 @@ class Address return $this->steps; } - public function setSteps(?string $steps): self + public function getStreet(): ?string { - $this->steps = $steps; - - return $this; + return $this->street; } - public function getBuildingName(): ?string + /** + * Get streetAddress1 (legacy function). + * + * @return string + */ + public function getStreetAddress1() { - return $this->buildingName; + return $this->street; + } + + /** + * Get streetAddress2 (legacy function). + * + * @return string + */ + public function getStreetAddress2() + { + return $this->streetNumber; + } + + public function getStreetNumber(): ?string + { + return $this->streetNumber; + } + + /** + * @return DateTime + */ + public function getValidFrom() + { + return $this->validFrom; + } + + public function getValidTo(): ?DateTimeInterface + { + return $this->validTo; + } + + public function isNoAddress(): bool + { + return $this->getIsNoAddress(); + } + + public function setAddressReference(?AddressReference $addressReference = null): Address + { + $this->addressReference = $addressReference; + + return $this; } public function setBuildingName(?string $buildingName): self @@ -485,21 +365,23 @@ class Address return $this; } - public function getFlat(): ?string + public function setCorridor(?string $corridor): self { - return $this->flat; - } - - public function setFlat(?string $flat): self - { - $this->flat = $flat; + $this->corridor = $corridor; return $this; } - public function getDistribution(): ?string + /** + * Store custom informations in the address. + * + * @return $this + */ + public function setCustoms(array $customs): self { - return $this->distribution; + $this->customs = $customs; + + return $this; } public function setDistribution(?string $distribution): self @@ -509,11 +391,6 @@ class Address return $this; } - public function getExtra(): ?string - { - return $this->extra; - } - public function setExtra(?string $extra): self { $this->extra = $extra; @@ -521,33 +398,32 @@ class Address return $this; } - public function getValidTo(): ?\DateTimeInterface + public function setFlat(?string $flat): self { - return $this->validTo; - } - - public function setValidTo(?\DateTimeInterface $validTo = null): self - { - $this->validTo = $validTo; + $this->flat = $flat; return $this; } - public function getPoint(): ?Point + public function setFloor(?string $floor): self { - return $this->point; - } - - public function setPoint(?Point $point): self - { - $this->point = $point; + $this->floor = $floor; return $this; } - public function getLinkedToThirdParty() + /** + * Set IsNoAddress. + * + * Indicate true if the address is a fake address (homeless, ...) + * + * @return $this + */ + public function setIsNoAddress(bool $isNoAddress): self { - return $this->linkedToThirdParty; + $this->isNoAddress = $isNoAddress; + + return $this; } public function setLinkedToThirdParty($linkedToThirdParty): self @@ -557,22 +433,130 @@ class Address return $this; } - /** - * @return AddressReference|null - */ - public function getAddressReference(): ?AddressReference + public function setPoint(?Point $point): self { - return $this->addressReference; - } + $this->point = $point; - /** - * @param AddressReference|null $addressReference - * @return Address - */ - public function setAddressReference(?AddressReference $addressReference = null): Address - { - $this->addressReference = $addressReference; 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 = null): self + { + $this->validTo = $validTo; + + return $this; + } + + /** + * Validate the address. + * + * Check that: + * + * * if the address is not home address: + * * the postal code is present + * * the valid from is not null + * * the address street 1 is greater than 2 + * + * @param array $payload + */ + public function validate(ExecutionContextInterface $context, $payload) + { + if (!$this->getValidFrom() instanceof DateTime) { + $context + ->buildViolation('address.date-should-be-set') + ->atPath('validFrom') + ->addViolation(); + } + + if ($this->isNoAddress()) { + return; + } + + if (empty($this->getStreetAddress1())) { + $context + ->buildViolation('address.street1-should-be-set') + ->atPath('streetAddress1') + ->addViolation(); + } + + if (!$this->getPostcode() instanceof PostalCode) { + $context + ->buildViolation('address.postcode-should-be-set') + ->atPath('postCode') + ->addViolation(); + } + } +} diff --git a/src/Bundle/ChillMainBundle/Entity/AddressReference.php b/src/Bundle/ChillMainBundle/Entity/AddressReference.php index 2a50932f4..02d600272 100644 --- a/src/Bundle/ChillMainBundle/Entity/AddressReference.php +++ b/src/Bundle/ChillMainBundle/Entity/AddressReference.php @@ -1,15 +1,22 @@ 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 */ @@ -135,9 +101,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 @@ -147,9 +128,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 @@ -159,14 +163,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 a0c540a06..b76f2fed2 100644 --- a/src/Bundle/ChillMainBundle/Entity/Center.php +++ b/src/Bundle/ChillMainBundle/Entity/Center.php @@ -1,28 +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\MainBundle\Entity; -use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation as Serializer; /** @@ -31,24 +20,6 @@ use Symfony\Component\Serializer\Annotation as Serializer; */ class Center implements HasCenterInterface { - - /** - * @var integer - * - * @ORM\Id - * @ORM\Column(name="id", type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; - - /** - * @var string - * - * @ORM\Column(type="string", length=255) - * @Serializer\Groups({"docgen:read"}) - */ - private string $name = ''; - /** * @var Collection * @@ -59,6 +30,20 @@ class Center implements HasCenterInterface */ private $groupCenters; + /** + * @var int + * + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @ORM\Column(type="string", length=255) + * @Serializer\Groups({"docgen:read"}) + */ + private string $name = ''; /** * Center constructor. @@ -71,27 +56,27 @@ class Center implements HasCenterInterface /** * @return string */ - public function getName() + public function __toString() { - return $this->name; + return $this->getName(); } /** - * @param $name * @return $this */ - public function setName($name) + public function addGroupCenter(GroupCenter $groupCenter) { - $this->name = $name; + $this->groupCenters->add($groupCenter); + return $this; } /** - * @return int + * @return $this|Center */ - public function getId() + public function getCenter() { - return $this->id; + return $this; } /** @@ -103,29 +88,30 @@ class Center implements HasCenterInterface } /** - * @param GroupCenter $groupCenter - * @return $this + * @return int */ - public function addGroupCenter(GroupCenter $groupCenter) + public function getId() { - $this->groupCenters->add($groupCenter); - return $this; + return $this->id; } /** * @return string */ - public function __toString() + public function getName() { - return $this->getName(); + return $this->name; } /** - * @return $this|Center + * @param $name + * + * @return $this */ - public function getCenter() + public function setName($name) { + $this->name = $name; + return $this; } - } diff --git a/src/Bundle/ChillMainBundle/Entity/Civility.php b/src/Bundle/ChillMainBundle/Entity/Civility.php index 32f5396cd..2ab66ebb8 100644 --- a/src/Bundle/ChillMainBundle/Entity/Civility.php +++ b/src/Bundle/ChillMainBundle/Entity/Civility.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\Entity; @@ -31,6 +18,17 @@ use Symfony\Component\Serializer\Annotation as Serializer; */ class Civility { + /** + * @ORM\Column(type="json") + * @Serializer\Groups({"read"}) + */ + private array $abbreviation = []; + + /** + * @ORM\Column(type="boolean") + */ + private bool $active = true; + /** * @ORM\Id * @ORM\GeneratedValue @@ -45,16 +43,15 @@ class Civility */ private array $name = []; - /** - * @ORM\Column(type="json") - * @Serializer\Groups({"read"}) - */ - private array $abbreviation = []; + public function getAbbreviation(): array + { + return $this->abbreviation; + } - /** - * @ORM\Column(type="boolean") - */ - private bool $active = true; + public function getActive(): ?bool + { + return $this->active; + } public function getId(): ?int { @@ -66,18 +63,16 @@ class Civility return $this->name; } - public function setName(array $name): self + /** + * @return Civility + */ + public function setAbbreviation(array $abbreviation): self { - $this->name = $name; + $this->abbreviation = $abbreviation; return $this; } - public function getActive(): ?bool - { - return $this->active; - } - public function setActive(bool $active): self { $this->active = $active; @@ -85,21 +80,10 @@ class Civility return $this; } - /** - * @return array - */ - public function getAbbreviation(): array + public function setName(array $name): self { - return $this->abbreviation; - } + $this->name = $name; - /** - * @param array $abbreviation - * @return Civility - */ - public function setAbbreviation(array $abbreviation): self - { - $this->abbreviation = $abbreviation; return $this; } } diff --git a/src/Bundle/ChillMainBundle/Entity/Country.php b/src/Bundle/ChillMainBundle/Entity/Country.php index df3f676b9..a199c5a7b 100644 --- a/src/Bundle/ChillMainBundle/Entity/Country.php +++ b/src/Bundle/ChillMainBundle/Entity/Country.php @@ -1,22 +1,37 @@ 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 */ @@ -85,7 +57,6 @@ class Country } /** - * * @return the string */ public function getCountryCode() @@ -94,13 +65,46 @@ class Country } /** + * Get id. * + * @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 9c99c98b4..4a4977632 100644 --- a/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php +++ b/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php @@ -1,12 +1,19 @@ comment; } + /** + * @return DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * @return interger $userId + */ + public function getUserId() + { + return $this->userId; + } + public function isEmpty() { return empty($this->getComment()); @@ -51,34 +75,18 @@ class CommentEmbeddable } /** - * @return interger $userId + * @param DateTime $date */ - public function getUserId() + public function setDate(?DateTime $date) { - return $this->userId; + $this->date = $date; } /** - * @param integer $userId + * @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 a7700001f..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\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/HasCentersInterface.php b/src/Bundle/ChillMainBundle/Entity/HasCentersInterface.php index 921cbba41..f3bb80201 100644 --- a/src/Bundle/ChillMainBundle/Entity/HasCentersInterface.php +++ b/src/Bundle/ChillMainBundle/Entity/HasCentersInterface.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\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/HasScopesInterface.php b/src/Bundle/ChillMainBundle/Entity/HasScopesInterface.php index 911dea563..b88618ee7 100644 --- a/src/Bundle/ChillMainBundle/Entity/HasScopesInterface.php +++ b/src/Bundle/ChillMainBundle/Entity/HasScopesInterface.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\MainBundle\Entity; @@ -23,19 +12,19 @@ namespace Chill\MainBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Language + * Language. * * @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,7 +37,7 @@ class Language private $name; /** - * Get id + * Get id. * * @return string */ @@ -58,21 +47,34 @@ 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) @@ -81,14 +83,4 @@ class Language return $this; } - - /** - * Get name - * - * @return string array - */ - public function getName() - { - return $this->name; - } } diff --git a/src/Bundle/ChillMainBundle/Entity/Location.php b/src/Bundle/ChillMainBundle/Entity/Location.php index 06e5ccca5..036673ec9 100644 --- a/src/Bundle/ChillMainBundle/Entity/Location.php +++ b/src/Bundle/ChillMainBundle/Entity/Location.php @@ -1,25 +1,71 @@ active; + } + public function getAddress(): ?Address + { + return $this->address; + } + public function getAvailableForUsers(): ?bool + { + return $this->availableForUsers; + } + public function getCreatedAt(): ?DateTimeImmutable + { + return $this->createdAt; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; + } + + public function getEmail(): ?string + { + return $this->email; + } public function getId(): ?int { @@ -119,88 +155,29 @@ class Location implements TrackCreationInterface, TrackUpdateInterface return $this->locationType; } - public function setLocationType(?LocationType $locationType): self - { - $this->locationType = $locationType; - - return $this; - } - - public function getAddress(): ?Address - { - return $this->address; - } - - public function setAddress(Address $address): self - { - $this->address = $address; - - return $this; - } - public function getName(): ?string { return $this->name; } - public function setName(?string $name): self - { - $this->name = $name; - - return $this; - } - public function getPhonenumber1(): ?string { return $this->phonenumber1; } - public function setPhonenumber1(?string $phonenumber1): self - { - $this->phonenumber1 = $phonenumber1; - - return $this; - } - public function getPhonenumber2(): ?string { return $this->phonenumber2; } - public function setPhonenumber2(?string $phonenumber2): self + public function getUpdatedAt(): ?DateTimeImmutable { - $this->phonenumber2 = $phonenumber2; - - return $this; + return $this->updatedAt; } - public function getEmail(): ?string + public function getUpdatedBy(): ?User { - return $this->email; - } - - public function setEmail(?string $email): self - { - $this->email = $email; - - return $this; - } - - public function getAvailableForUsers(): ?bool - { - return $this->availableForUsers; - } - - public function setAvailableForUsers(bool $availableForUsers): self - { - $this->availableForUsers = $availableForUsers; - - return $this; - } - - public function getActive(): ?bool - { - return $this->active; + return $this->updatedBy; } public function setActive(bool $active): self @@ -210,9 +187,25 @@ class Location implements TrackCreationInterface, TrackUpdateInterface return $this; } - public function getCreatedBy(): ?User + public function setAddress(Address $address): self { - return $this->createdBy; + $this->address = $address; + + return $this; + } + + public function setAvailableForUsers(bool $availableForUsers): self + { + $this->availableForUsers = $availableForUsers; + + return $this; + } + + public function setCreatedAt(?DateTimeInterface $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; } public function setCreatedBy(?User $createdBy): self @@ -222,21 +215,46 @@ class Location implements TrackCreationInterface, TrackUpdateInterface return $this; } - public function getCreatedAt(): ?\DateTimeImmutable + public function setEmail(?string $email): self { - return $this->createdAt; - } - - public function setCreatedAt(?\DateTimeInterface $createdAt): self - { - $this->createdAt = $createdAt; + $this->email = $email; return $this; } - public function getUpdatedBy(): ?User + public function setLocationType(?LocationType $locationType): self { - return $this->updatedBy; + $this->locationType = $locationType; + + return $this; + } + + public function setName(?string $name): self + { + $this->name = $name; + + return $this; + } + + public function setPhonenumber1(?string $phonenumber1): self + { + $this->phonenumber1 = $phonenumber1; + + return $this; + } + + public function setPhonenumber2(?string $phonenumber2): self + { + $this->phonenumber2 = $phonenumber2; + + return $this; + } + + public function setUpdatedAt(?DateTimeInterface $updatedAt): self + { + $this->updatedAt = $updatedAt; + + return $this; } public function setUpdatedBy(?User $updatedBy): self @@ -245,16 +263,4 @@ class Location implements TrackCreationInterface, TrackUpdateInterface return $this; } - - public function getUpdatedAt(): ?\DateTimeImmutable - { - return $this->updatedAt; - } - - public function setUpdatedAt(?\DateTimeInterface $updatedAt): self - { - $this->updatedAt = $updatedAt; - - return $this; - } } diff --git a/src/Bundle/ChillMainBundle/Entity/LocationType.php b/src/Bundle/ChillMainBundle/Entity/LocationType.php index 026fc727d..8b171eb0f 100644 --- a/src/Bundle/ChillMainBundle/Entity/LocationType.php +++ b/src/Bundle/ChillMainBundle/Entity/LocationType.php @@ -1,5 +1,12 @@ active; + } - /** - * @ORM\Column(type="boolean", nullable=true) - * @Serializer\Groups({"read"}) - */ - private bool $active = true; + public function getAddressRequired(): ?string + { + return $this->addressRequired; + } - /** - * @ORM\Column(type="string", length=32, options={"default"="optional"}) - * @Serializer\Groups({"read"}) - */ - private string $addressRequired = self::STATUS_OPTIONAL; - - /** - * @ORM\Column(type="string", length=32, options={"default"="optional"}) - * @Serializer\Groups({"read"}) - */ - private string $contactData = self::STATUS_OPTIONAL; + public function getAvailableForUsers(): ?bool + { + return $this->availableForUsers; + } + public function getContactData(): ?string + { + return $this->contactData; + } public function getId(): ?int { @@ -69,18 +97,6 @@ class LocationType return $this->title; } - public function setTitle(array $title): self - { - $this->title = $title; - - return $this; - } - - public function getActive(): ?bool - { - return $this->active; - } - public function setActive(bool $active): self { $this->active = $active; @@ -88,23 +104,6 @@ class LocationType return $this; } - public function getAvailableForUsers(): ?bool - { - return $this->availableForUsers; - } - - public function setAvailableForUsers(bool $availableForUsers): self - { - $this->availableForUsers = $availableForUsers; - - return $this; - } - - public function getAddressRequired(): ?string - { - return $this->addressRequired; - } - public function setAddressRequired(string $addressRequired): self { $this->addressRequired = $addressRequired; @@ -112,9 +111,11 @@ class LocationType return $this; } - public function getContactData(): ?string + public function setAvailableForUsers(bool $availableForUsers): self { - return $this->contactData; + $this->availableForUsers = $availableForUsers; + + return $this; } public function setContactData(string $contactData): self @@ -123,4 +124,11 @@ class LocationType return $this; } + + public function setTitle(array $title): self + { + $this->title = $title; + + return $this; + } } diff --git a/src/Bundle/ChillMainBundle/Entity/Notification.php b/src/Bundle/ChillMainBundle/Entity/Notification.php index 092445c9b..bdf2529ca 100644 --- a/src/Bundle/ChillMainBundle/Entity/Notification.php +++ b/src/Bundle/ChillMainBundle/Entity/Notification.php @@ -1,25 +1,15 @@ +/** + * 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; -use Chill\MainBundle\Entity\User; +use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; @@ -27,14 +17,25 @@ use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table( - * name="chill_main_notification", - * uniqueConstraints={ - * @ORM\UniqueConstraint(columns={"relatedEntityClass", "relatedEntityId"}) - * } + * name="chill_main_notification", + * uniqueConstraints={ + * @ORM\UniqueConstraint(columns={"relatedEntityClass", "relatedEntityId"}) + * } * ) */ class Notification { + /** + * @ORM\ManyToMany(targetEntity=User::class) + * @ORM\JoinTable(name="chill_main_notification_addresses_user") + */ + private Collection $addressees; + + /** + * @ORM\Column(type="datetime_immutable") + */ + private DateTimeImmutable $date; + /** * @ORM\Id * @ORM\GeneratedValue @@ -48,21 +49,9 @@ class Notification private string $message; /** - * @ORM\Column(type="datetime_immutable") + * @ORM\Column(type="json") */ - private \DateTimeImmutable $date; - - /** - * @ORM\ManyToOne(targetEntity=User::class) - * @ORM\JoinColumn(nullable=false) - */ - private User $sender; - - /** - * @ORM\ManyToMany(targetEntity=User::class) - * @ORM\JoinTable(name="chill_main_notification_addresses_user") - */ - private Collection $addressees; + private array $read; /** * @ORM\Column(type="string", length=255) @@ -75,52 +64,21 @@ class Notification private int $relatedEntityId; /** - * @ORM\Column(type="json") + * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\JoinColumn(nullable=false) */ - private array $read; + private User $sender; public function __construct() { $this->addressees = new ArrayCollection(); } - public function getId(): ?int + public function addAddressee(User $addressee): self { - return $this->id; - } - - public function getMessage(): ?string - { - return $this->message; - } - - public function setMessage(string $message): self - { - $this->message = $message; - - return $this; - } - - public function getDate(): ?\DateTimeImmutable - { - return $this->date; - } - - public function setDate(\DateTimeImmutable $date): self - { - $this->date = $date; - - return $this; - } - - public function getSender(): ?User - { - return $this->sender; - } - - public function setSender(?User $sender): self - { - $this->sender = $sender; + if (!$this->addressees->contains($addressee)) { + $this->addressees[] = $addressee; + } return $this; } @@ -133,13 +91,39 @@ class Notification return $this->addressees; } - public function addAddressee(User $addressee): self + public function getDate(): ?DateTimeImmutable { - if (!$this->addressees->contains($addressee)) { - $this->addressees[] = $addressee; - } + return $this->date; + } - return $this; + public function getId(): ?int + { + return $this->id; + } + + public function getMessage(): ?string + { + return $this->message; + } + + public function getRead(): array + { + return $this->read; + } + + public function getRelatedEntityClass(): ?string + { + return $this->relatedEntityClass; + } + + public function getRelatedEntityId(): ?int + { + return $this->relatedEntityId; + } + + public function getSender(): ?User + { + return $this->sender; } public function removeAddressee(User $addressee): self @@ -149,9 +133,25 @@ class Notification return $this; } - public function getRelatedEntityClass(): ?string + public function setDate(DateTimeImmutable $date): self { - return $this->relatedEntityClass; + $this->date = $date; + + return $this; + } + + public function setMessage(string $message): self + { + $this->message = $message; + + return $this; + } + + public function setRead(array $read): self + { + $this->read = $read; + + return $this; } public function setRelatedEntityClass(string $relatedEntityClass): self @@ -161,11 +161,6 @@ class Notification return $this; } - public function getRelatedEntityId(): ?int - { - return $this->relatedEntityId; - } - public function setRelatedEntityId(int $relatedEntityId): self { $this->relatedEntityId = $relatedEntityId; @@ -173,14 +168,9 @@ class Notification return $this; } - public function getRead(): array + public function setSender(?User $sender): self { - return $this->read; - } - - public function setRead(array $read): self - { - $this->read = $read; + $this->sender = $sender; return $this; } diff --git a/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php b/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php index 456ee29e3..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\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 91ce46e17..11a5d10c9 100644 --- a/src/Bundle/ChillMainBundle/Entity/PostalCode.php +++ b/src/Bundle/ChillMainBundle/Entity/PostalCode.php @@ -1,5 +1,12 @@ center; + } /** - * @var Point + * Get code. * - * @ORM\Column(type="point", nullable=true) - * @groups({"read"}) + * @return string */ - private $center; + public function getCode() + { + return $this->code; + } /** - * Get id + * Get country. * - * @return integer + * @return Country + */ + public function getCountry() + { + return $this->country; + } + + /** + * Get id. + * + * @return int */ public function getId() { return $this->id; } - /** - * Set origin - * - * @param int $origin - * - * @return PostalCode - */ - public function setOrigin($origin) - { - $this->origin = $origin; - - return $this; - } - - /** - * Get origin - * - * @return int - */ - public function getOrigin() - { - return $this->origin; - } - - - /** - * Set name - * - * @param string $name - * - * @return PostalCode - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name + * Get name. * * @return string */ @@ -148,7 +139,34 @@ class PostalCode } /** - * Set code + * Get origin. + * + * @return int + */ + public function getOrigin() + { + return $this->origin; + } + + public function getPostalCodeSource(): ?string + { + return $this->postalCodeSource; + } + + public function getRefPostalCodeId(): ?string + { + return $this->refPostalCodeId; + } + + public function setCenter(?Point $center): self + { + $this->center = $center; + + return $this; + } + + /** + * Set code. * * @param string $code * @@ -162,23 +180,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; @@ -186,30 +194,31 @@ class PostalCode } /** - * Get country + * Set name. * - * @return Country + * @param string $name + * + * @return PostalCode */ - public function getCountry() + public function setName($name) { - return $this->country; - } - - public function getRefPostalCodeId(): ?string - { - return $this->refPostalCodeId; - } - - public function setRefPostalCodeId(?string $refPostalCodeId): self - { - $this->refPostalCodeId = $refPostalCodeId; + $this->name = $name; return $this; } - public function getPostalCodeSource(): ?string + /** + * Set origin. + * + * @param int $origin + * + * @return PostalCode + */ + public function setOrigin($origin) { - return $this->postalCodeSource; + $this->origin = $origin; + + return $this; } public function setPostalCodeSource(?string $postalCodeSource): self @@ -219,16 +228,10 @@ class PostalCode return $this; } - public function getCenter(): ?Point + public function setRefPostalCodeId(?string $refPostalCodeId): self { - return $this->center; - } - - public function setCenter(?Point $center): self - { - $this->center = $center; + $this->refPostalCodeId = $refPostalCodeId; return $this; } } - diff --git a/src/Bundle/ChillMainBundle/Entity/RoleScope.php b/src/Bundle/ChillMainBundle/Entity/RoleScope.php index a92184917..a9a65799d 100644 --- a/src/Bundle/ChillMainBundle/Entity/RoleScope.php +++ b/src/Bundle/ChillMainBundle/Entity/RoleScope.php @@ -1,12 +1,19 @@ permissionsGroups = new ArrayCollection(); } diff --git a/src/Bundle/ChillMainBundle/Entity/Scope.php b/src/Bundle/ChillMainBundle/Entity/Scope.php index acd92099c..adac7ce40 100644 --- a/src/Bundle/ChillMainBundle/Entity/Scope.php +++ b/src/Bundle/ChillMainBundle/Entity/Scope.php @@ -1,44 +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\Entity; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; -use Chill\MainBundle\Entity\RoleScope; -use Symfony\Component\Serializer\Annotation\Groups; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Symfony\Component\Serializer\Annotation\Groups; /** * @ORM\Entity * @ORM\Table(name="scopes") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * @DiscriminatorMap(typeProperty="type", mapping={ - * "scope"=Scope::class + * "scope": Scope::class * }) */ class Scope { /** - * @var integer + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -48,7 +36,7 @@ class Scope private $id; /** - * translatable names + * translatable names. * * @var array * @@ -62,12 +50,11 @@ class Scope * * @ORM\OneToMany( * targetEntity="Chill\MainBundle\Entity\RoleScope", - * mappedBy="scope") + * mappedBy="scope") * @ORM\Cache(usage="NONSTRICT_READ_WRITE") */ private $roleScopes; - /** * Scope constructor. */ @@ -76,6 +63,11 @@ class Scope $this->roleScopes = new ArrayCollection(); } + public function addRoleScope(RoleScope $roleScope) + { + $this->roleScopes->add($roleScope); + } + /** * @return int */ @@ -92,16 +84,6 @@ class Scope return $this->name; } - /** - * @param $name - * @return $this - */ - public function setName($name) - { - $this->name = $name; - return $this; - } - /** * @return Collection */ @@ -111,10 +93,14 @@ class Scope } /** - * @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 2d8636e5f..d0ff644c1 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -1,29 +1,36 @@ id; - } - - /** - * Set username - * - * @param string $name - * @return Agent - */ - public function setUsername($name) - { - $this->username = $name; - - if (empty($this->getLabel())) { - $this->setLabel($name); - } + $this->groupCenters->add($groupCenter); return $this; } - /** - * @return string - */ - public function getUsername() + public function eraseCredentials() { - return $this->username; } /** - */ - public function eraseCredentials() {} - - /** + * Get attributes. + * * @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() + public function getCurrentLocation(): ?Location { - 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 $this->currentLocation; } /** @@ -250,17 +211,6 @@ class User implements AdvancedUserInterface { return $this->email; } - /** - * @param $emailCanonical - * @return $this - */ - public function setEmailCanonical($emailCanonical) - { - $this->emailCanonical = $emailCanonical; - - return $this; - } - /** * @return string */ @@ -270,14 +220,36 @@ class User implements AdvancedUserInterface { } /** - * @param $password - * @return $this + * @return GroupCenter */ - function setPassword($password) + public function getGroupCenters() { - $this->password = $password; + return $this->groupCenters; + } - return $this; + /** + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + public function getLabel(): string + { + return $this->label; + } + + public function getMainCenter(): ?Center + { + return $this->mainCenter; + } + + public function getMainScope(): ?Scope + { + return $this->mainScope; } /** @@ -288,14 +260,38 @@ class User implements AdvancedUserInterface { return $this->password; } - /** - * @param $salt - * @return $this - */ - function setSalt($salt) + public function getRoles(): array { - $this->salt = $salt; - return $this; + return ['ROLE_USER']; + } + + /** + * @return string|null + */ + public function getSalt() + { + return $this->salt; + } + + public function getUserJob(): ?UserJob + { + return $this->userJob; + } + + /** + * @return string + */ + public function getUsername() + { + return $this->username; + } + + /** + * @return string + */ + public function getUsernameCanonical() + { + return $this->usernameCanonical; } /** @@ -330,46 +326,6 @@ 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 * use this function to avoid a user to be associated to the same groupCenter @@ -377,12 +333,12 @@ class User implements AdvancedUserInterface { */ 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(); } @@ -390,7 +346,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 * @@ -403,89 +372,126 @@ class User implements AdvancedUserInterface { return $this; } + public function setCurrentLocation(?Location $currentLocation): User + { + $this->currentLocation = $currentLocation; + + return $this; + } + /** - * 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; } /** - * @return string + * @param $emailCanonical + * + * @return $this */ - public function getLabel(): string + public function setEmailCanonical($emailCanonical) { - return $this->label; + $this->emailCanonical = $emailCanonical; + + return $this; } /** - * @param string $label - * @return User + * @param bool $enabled */ + public function setEnabled($enabled) + { + $this->enabled = $enabled; + + return $this; + } + public function setLabel(string $label): User { $this->label = $label; + return $this; } - /** - * @return Center|null - */ - public function getMainCenter(): ?Center - { - return $this->mainCenter; - } - - /** - * @param Center|null $mainCenter - * @return User - */ public function setMainCenter(?Center $mainCenter): User { $this->mainCenter = $mainCenter; + return $this; } - /** - * @return Scope|null - */ - public function getMainScope(): ?Scope - { - return $this->mainScope; - } - - /** - * @param Scope|null $mainScope - * @return User - */ public function setMainScope(?Scope $mainScope): User { $this->mainScope = $mainScope; + return $this; } /** - * @return UserJob|null + * @param $password + * + * @return $this */ - public function getUserJob(): ?UserJob + public function setPassword($password) { - return $this->userJob; + $this->password = $password; + + return $this; } /** - * @param UserJob|null $userJob - * @return User + * @param $salt + * + * @return $this */ + public function setSalt($salt) + { + $this->salt = $salt; + + return $this; + } + public function setUserJob(?UserJob $userJob): User { $this->userJob = $userJob; + + return $this; + } + + /** + * Set username. + * + * @param string $name + * + * @return Agent + */ + public function setUsername($name) + { + $this->username = $name; + + if (empty($this->getLabel())) { + $this->setLabel($name); + } + + return $this; + } + + /** + * @param $usernameCanonical + * + * @return $this + */ + public function setUsernameCanonical($usernameCanonical) + { + $this->usernameCanonical = $usernameCanonical; + return $this; } } diff --git a/src/Bundle/ChillMainBundle/Entity/UserJob.php b/src/Bundle/ChillMainBundle/Entity/UserJob.php index 411d5c40f..dfc48d16b 100644 --- a/src/Bundle/ChillMainBundle/Entity/UserJob.php +++ b/src/Bundle/ChillMainBundle/Entity/UserJob.php @@ -1,5 +1,12 @@ id; @@ -52,31 +54,25 @@ class UserJob return $this->label; } - /** - * @param array|string[] $label - * @return UserJob - */ - public function setLabel(array $label): UserJob - { - $this->label = $label; - return $this; - } - - /** - * @return bool - */ public function isActive(): bool { return $this->active; } - /** - * @param bool $active - * @return UserJob - */ public function setActive(bool $active): UserJob { $this->active = $active; + + return $this; + } + + /** + * @param array|string[] $label + */ + public function setLabel(array $label): UserJob + { + $this->label = $label; + return $this; } } diff --git a/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php b/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php index db65600bd..19de762d5 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..bfe6ee0bc 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..e80dd154c 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportManager.php +++ b/src/Bundle/ChillMainBundle/Export/ExportManager.php @@ -1,154 +1,166 @@ +/** + * 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 +168,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 +192,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 +390,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 +409,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 +478,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 d64de7ae6..c1404d2b8 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php @@ -1,68 +1,69 @@ translator = $translator; $this->exportManager = $manager; } - public function getType() - { - return 'tabular'; - } - - public function getName() - { - return 'Comma separated values (CSV)'; - } - /** * @uses appendAggregatorForm + * + * @param mixed $exportAlias */ public function buildForm(FormBuilderInterface $builder, $exportAlias, array $aggregatorAliases) { @@ -70,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(); @@ -137,38 +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. - * - */ - protected function orderingHeaders(array $formatterData) + public function getType() { - $this->formatterData = $formatterData; - uasort( - $this->formatterData, - static fn(array $a, array $b): int => ($a['order'] <= $b['order'] ? -1 : 1) + return 'tabular'; + } + + protected function gatherLabels() + { + return array_merge( + $this->gatherLabelsFromAggregators(), + $this->gatherLabelsFromExport() ); } - private function findColumnPosition(&$columnHeaders, $columnToFind): int + protected function gatherLabelsFromAggregators() { - $i = 0; - foreach($columnHeaders as $set) { - if ($set === $columnToFind) { - return $i; + $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] + ); } - $i++; } - //we didn't find it, adding the column - $columnHeaders[] = $columnToFind; + return $labels; + } - return $i++; + 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() @@ -179,25 +217,25 @@ 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 = []; // create a file pointer connected to the output stream $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) { @@ -220,41 +258,42 @@ class CSVFormatter implements FormatterInterface $columnPosition = $this->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'] : ''; } @@ -262,10 +301,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); } @@ -275,10 +315,82 @@ 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. + */ + protected function orderingHeaders(array $formatterData) + { + $this->formatterData = $formatterData; + uasort( + $this->formatterData, + static fn (array $a, array $b): int => ($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 findColumnPosition(&$columnHeaders, $columnToFind): int + { + $i = 0; + + foreach ($columnHeaders as $set) { + if ($set === $columnToFind) { + return $i; + } + ++$i; + } + + //we didn't find it, adding the column + $columnHeaders[] = $columnToFind; + + return $i++; + } private function getOrderedResults() { - $r = array(); + $r = []; $results = $this->result; $labels = $this->labels; $rowKeys = $this->getRowHeaders(); @@ -287,9 +399,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]); } @@ -306,31 +418,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]; @@ -342,95 +445,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..193cc0feb 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php @@ -1,68 +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\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 +60,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 +192,39 @@ 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..ccdfcb97a 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php @@ -1,126 +1,106 @@ +/** + * 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 +108,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 +180,33 @@ 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 aed10a29f..71119205e 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php @@ -1,96 +1,38 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public 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 +41,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 +78,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 +101,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 +128,7 @@ class SpreadSheetFormatter implements FormatterInterface /** * Whethe `cacheDisplayableResult` is initialized or not. * - * @var boolean + * @var bool */ private $cacheDisplayableResultIsInitialized = false; @@ -147,58 +138,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 +189,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 +323,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 +503,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 +532,6 @@ class SpreadSheetFormatter implements FormatterInterface * array( 5, 6, 4 ) * ) * ``` - * */ protected function sortResult() { @@ -386,198 +539,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..e4fb8cf19 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php @@ -1,163 +1,157 @@ +/** + * 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 +159,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 +254,37 @@ 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..9c7b7d414 100644 --- a/src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php +++ b/src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php @@ -1,82 +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\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 +70,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/Event/CustomizeFormEvent.php b/src/Bundle/ChillMainBundle/Form/Event/CustomizeFormEvent.php index 43fab6f62..2c8c5d348 100644 --- a/src/Bundle/ChillMainBundle/Form/Event/CustomizeFormEvent.php +++ b/src/Bundle/ChillMainBundle/Form/Event/CustomizeFormEvent.php @@ -1,36 +1,37 @@ type = $type; $this->builder = $builder; } - /** - * @return string - */ - public function getType(): string - { - return $this->type; - } - - /** - * @return FormBuilderInterface - */ public function getBuilder(): FormBuilderInterface { return $this->builder; } + + public function getType(): string + { + return $this->type; + } } diff --git a/src/Bundle/ChillMainBundle/Form/LocationFormType.php b/src/Bundle/ChillMainBundle/Form/LocationFormType.php index 83d1c4242..22d3d1702 100644 --- a/src/Bundle/ChillMainBundle/Form/LocationFormType.php +++ b/src/Bundle/ChillMainBundle/Form/LocationFormType.php @@ -1,5 +1,12 @@ translatableStringHelper = $translatableStringHelper; - // } + public function __construct(TranslatableStringHelper $translatableStringHelper) + { + $this->translatableStringHelper = $translatableStringHelper; + } public function buildForm(FormBuilderInterface $builder, array $options) { - $builder ->add('locationType', EntityType::class, [ 'class' => EntityLocationType::class, @@ -38,8 +40,7 @@ final class LocationFormType extends AbstractType ]; }, 'choice_label' => function (EntityLocationType $entity) { - //return $this->translatableStringHelper->localize($entity->getTitle()); //TODO not working. Cannot pass smthg in the constructor - return $entity->getTitle()['fr']; + return $this->translatableStringHelper->localize($entity->getTitle()); }, ]) ->add('name', TextType::class) @@ -53,25 +54,27 @@ final class LocationFormType extends AbstractType 'use_valid_to' => false, 'mapped' => false, ]) - ->add('active', ChoiceType::class, - [ - 'choices' => [ - 'Yes' => true, - 'No' => false - ], - 'expanded' => true - ]); + ->add( + 'active', + ChoiceType::class, + [ + 'choices' => [ + 'Yes' => true, + 'No' => false, + ], + 'expanded' => true, + ] + ); } - /** * @param OptionsResolverInterface $resolver */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\MainBundle\Entity\Location' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\MainBundle\Entity\Location', + ]); } /** @@ -81,5 +84,4 @@ final class LocationFormType extends AbstractType { return 'chill_mainbundle_location'; } - } diff --git a/src/Bundle/ChillMainBundle/Form/LocationTypeType.php b/src/Bundle/ChillMainBundle/Form/LocationTypeType.php index dded13327..1e4776f8f 100644 --- a/src/Bundle/ChillMainBundle/Form/LocationTypeType.php +++ b/src/Bundle/ChillMainBundle/Form/LocationTypeType.php @@ -1,5 +1,12 @@ add('title', TranslatableStringFormType::class, - [ - 'label' => 'Name', - ]) - ->add('availableForUsers', ChoiceType::class, - [ - 'choices' => [ - 'Yes' => true, - 'No' => false - ], - 'expanded' => true - ]) - ->add('addressRequired', ChoiceType::class, - [ - 'choices' => [ - 'optional' => LocationType::STATUS_OPTIONAL, - 'required' => LocationType::STATUS_REQUIRED, - 'never' => LocationType::STATUS_NEVER, - ], - 'expanded' => true - ]) - ->add('contactData', ChoiceType::class, - [ - 'choices' => [ - 'optional' => LocationType::STATUS_OPTIONAL, - 'required' => LocationType::STATUS_REQUIRED, - 'never' => LocationType::STATUS_NEVER, - ], - 'expanded' => true - ]) - ->add('active', ChoiceType::class, - [ - 'choices' => [ - 'Yes' => true, - 'No' => false - ], - 'expanded' => true - ]); + $builder->add( + 'title', + TranslatableStringFormType::class, + [ + 'label' => 'Name', + ] + ) + ->add( + 'availableForUsers', + ChoiceType::class, + [ + 'choices' => [ + 'Yes' => true, + 'No' => false, + ], + 'expanded' => true, + ] + ) + ->add( + 'addressRequired', + ChoiceType::class, + [ + 'choices' => [ + 'optional' => LocationType::STATUS_OPTIONAL, + 'required' => LocationType::STATUS_REQUIRED, + 'never' => LocationType::STATUS_NEVER, + ], + 'expanded' => true, + ] + ) + ->add( + 'contactData', + ChoiceType::class, + [ + 'choices' => [ + 'optional' => LocationType::STATUS_OPTIONAL, + 'required' => LocationType::STATUS_REQUIRED, + 'never' => LocationType::STATUS_NEVER, + ], + 'expanded' => true, + ] + ) + ->add( + 'active', + ChoiceType::class, + [ + 'choices' => [ + 'Yes' => true, + 'No' => false, + ], + 'expanded' => true, + ] + ); } } diff --git a/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php b/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php index d9b4ab730..1fb0426b4 100644 --- a/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php +++ b/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php @@ -1,75 +1,63 @@ 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 +67,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 f17721881..80bde17fd 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/AddressType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/AddressType.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\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 Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Form\Type\PostalCodeType; -use Chill\MainBundle\Form\Type\ChillDateType; 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\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,25 +33,27 @@ 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', ChillDateType::class, array( - 'required' => true, - ) - ); + ->add( + 'validFrom', + ChillDateType::class, + [ + 'required' => true, + ] + ); } if ($options['has_no_address']) { @@ -72,13 +62,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()); } } @@ -95,7 +85,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/ChillCollectionType.php b/src/Bundle/ChillMainBundle/Form/Type/ChillCollectionType.php index 2b20dbd98..a50a66340 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ChillCollectionType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ChillCollectionType.php @@ -1,40 +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\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. * - `empty_collection_explain` - * - * */ class ChillCollectionType extends AbstractType { + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['button_add_label'] = $options['button_add_label']; + $view->vars['button_remove_label'] = $options['button_remove_label']; + $view->vars['allow_delete'] = (int) $options['allow_delete']; + $view->vars['allow_add'] = (int) $options['allow_add']; + $view->vars['identifier'] = $options['identifier']; + $view->vars['empty_collection_explain'] = $options['empty_collection_explain']; + } + public function configureOptions(OptionsResolver $resolver) { $resolver @@ -46,16 +46,6 @@ class ChillCollectionType extends AbstractType ]); } - public function buildView(FormView $view, FormInterface $form, array $options) - { - $view->vars['button_add_label'] = $options['button_add_label']; - $view->vars['button_remove_label'] = $options['button_remove_label']; - $view->vars['allow_delete'] = (int) $options['allow_delete']; - $view->vars['allow_add'] = (int) $options['allow_add']; - $view->vars['identifier'] = $options['identifier']; - $view->vars['empty_collection_explain'] = $options['empty_collection_explain']; - } - 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 8502febbb..7679b5f72 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,10 +25,9 @@ class ChillDateType extends AbstractType { $resolver ->setDefault('widget', 'single_text') - ->setDefault('html5', true) - ; + ->setDefault('html5', true); } - + 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 3d3f2e9d8..e05b6bc96 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; @@ -47,15 +38,14 @@ class CommentType extends AbstractType ->add('comment', ChillTextareaType::class, [ 'disable_editor' => $options['disable_editor'], 'label' => $options['label'], - ]) - ; + ]); $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $data = $event->getForm()->getData(); $comment = $event->getData() ?? ['comment' => '']; if (null !== $data && $data->getComment() !== $comment['comment']) { - $data->setDate(new \DateTime()); + $data->setDate(new DateTime()); $data->setUserId($this->user->getId()); $event->getForm()->setData($data); } @@ -65,7 +55,8 @@ class CommentType extends AbstractType public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace( - $view->vars, [ + $view->vars, + [ 'hideLabel' => true, ] ); @@ -78,7 +69,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..f7b19f453 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ComposedGroupCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ComposedGroupCenterType.php @@ -1,54 +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\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 Chill\MainBundle\Entity\PermissionsGroup; 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\Component\OptionsResolver\OptionsResolver; -/** - * - * - * @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 +43,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..bafdf627e 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ComposedRoleScopeType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ComposedRoleScopeType.php @@ -1,71 +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 . + * 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 +62,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/AddressToIdDataTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/AddressToIdDataTransformer.php index 1931ded47..32b4890a1 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/AddressToIdDataTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/AddressToIdDataTransformer.php @@ -1,5 +1,12 @@ addressRepository->find($value); - if (NULL === $address) { - $failure = new TransformationFailedException(sprintf("Address with id %s does not exists", $value)); + if (null === $address) { + $failure = new TransformationFailedException(sprintf('Address with id %s does not exists', $value)); $failure - ->setInvalidMessage("The given {{ value }} is not a valid address id", [ '{{ value }}' => $value]); + ->setInvalidMessage('The given {{ value }} is not a valid address id', ['{{ value }}' => $value]); throw $failure; } @@ -36,7 +43,7 @@ final class AddressToIdDataTransformer implements DataTransformerInterface public function transform($value) { - if (NULL === $value) { + if (null === $value) { return ''; } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php index 581a40bcc..a7deab29c 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.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\Form\Type\DataTransformer; @@ -22,15 +12,15 @@ namespace Chill\MainBundle\Form\Type\DataTransformer; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Repository\CenterRepository; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\Common\Collections\Collection; -use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Traversable; class CenterTransformer implements DataTransformerInterface { private CenterRepository $centerRepository; + private bool $multiple = false; public function __construct( @@ -43,12 +33,12 @@ class CenterTransformer implements DataTransformerInterface public function reverseTransform($id) { - if ($id === NULL) { + if (null === $id) { if ($this->multiple) { return new ArrayCollection(); - } else { - return NULL; } + + return null; } $ids = []; @@ -61,11 +51,13 @@ class CenterTransformer implements DataTransformerInterface $centers = $this ->centerRepository - ->findBy(['id' => $ids ]); + ->findBy(['id' => $ids]); if ([] === $centers || count($ids) > count($centers)) { throw new TransformationFailedException(sprintf( - 'No center found for one of those ids: %s', implode(',', $ids))); + 'No center found for one of those ids: %s', + implode(',', $ids) + )); } if ($this->multiple) { @@ -77,25 +69,27 @@ class CenterTransformer implements DataTransformerInterface public function transform($center) { - if ($center === NULL) { + if (null === $center) { return ''; } if ($this->multiple) { if (!is_iterable($center)) { - throw new UnexpectedTypeException($center, \Traversable::class); + throw new UnexpectedTypeException($center, Traversable::class); } $ids = []; + foreach ($center as $c) { $ids[] = $c->getId(); } return implode(',', $ids); - } else { - if (!$center instanceof Center) { - throw new UnexpectedTypeException($center, Center::class); - } - return (string) $center->getId(); } + + if (!$center instanceof Center) { + throw new UnexpectedTypeException($center, Center::class); + } + + return (string) $center->getId(); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php index 4d4e2d79d..f41223d17 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php @@ -1,70 +1,35 @@ d > 0) { - // we check for weeks (weeks are converted to 7 days) - if ($value->d % 7 === 0) { - return [ - 'n' => $value->d / 7, - 'unit' => 'W' - ]; - } - - return [ - 'n' => $value->d, - 'unit' => 'D' - ]; - } - - if ($value->m > 0) { - return [ - 'n' => $value->m, - 'unit' => 'M' - ]; - } - - if ($value->y > 0) { - 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) || empty($value['n'])) { return null; } - $string = 'P'.$value['n'].$value['unit']; + $string = 'P' . $value['n'] . $value['unit']; try { - return new \DateInterval($string); - } catch (\Exception $e) { + return new DateInterval($string); + } catch (Exception $e) { throw new TransformationFailedException( 'Could not transform value into DateInterval', 1542, @@ -72,4 +37,48 @@ class DateIntervalTransformer implements DataTransformerInterface ); } } + + public function transform($value) + { + if (empty($value)) { + return null; + } + + if (!$value instanceof DateInterval) { + throw new UnexpectedTypeException($value, DateInterval::class); + } + + 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', + ]; + } + + return [ + '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.' + ); + } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php index 00ee26fff..ca5bfafef 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php @@ -1,37 +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\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\ORM\EntityManagerInterface; +use Symfony\Component\Form\DataTransformerInterface; class MultipleObjectsToIdTransformer implements DataTransformerInterface { - private EntityManagerInterface $em; - private ?string $class; + private EntityManagerInterface $em; + public function __construct(EntityManagerInterface $em, ?string $class = null) { $this->em = $em; @@ -39,28 +26,12 @@ class MultipleObjectsToIdTransformer implements DataTransformerInterface } /** - * 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(); @@ -72,6 +43,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 82cdf6c21..844754a98 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.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\Form\Type\DataTransformer; @@ -23,14 +12,13 @@ namespace Chill\MainBundle\Form\Type\DataTransformer; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; -use Doctrine\Persistence\ObjectManager; class ObjectToIdTransformer implements DataTransformerInterface { - private EntityManagerInterface $em; - private ?string $class; + private EntityManagerInterface $em; + public function __construct(EntityManagerInterface $em, ?string $class = null) { $this->em = $em; @@ -38,26 +26,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) { @@ -67,13 +42,28 @@ class ObjectToIdTransformer implements DataTransformerInterface $object = $this->em ->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 bd1185333..32957afc4 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php @@ -1,30 +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\MainBundle\Form\Type\DataTransformer; use Chill\MainBundle\Entity\Scope; -use Symfony\Component\Form\DataTransformerInterface; -use Doctrine\Persistence\ObjectManager; -use Symfony\Component\Form\Exception\TransformationFailedException; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; class ScopeTransformer implements DataTransformerInterface { @@ -35,19 +23,10 @@ class ScopeTransformer implements DataTransformerInterface $this->em = $em; } - 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 @@ -55,12 +34,20 @@ class ScopeTransformer implements DataTransformerInterface ->getRepository(Scope::class) ->find($id); - if ($scope === NULL) { - throw new TransformationFailedException(sprintf("The scope with 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..442d82608 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DateIntervalType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DateIntervalType.php @@ -1,40 +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 . - */ -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 +37,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 +49,6 @@ use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; * ] * )); * ``` - * */ class DateIntervalType extends AbstractType { @@ -66,18 +59,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 +78,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..3bedc9a3d 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php @@ -1,182 +1,175 @@ +/** + * 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..9f6374109 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php @@ -1,36 +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\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - 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; /** - * Choose a formatter amongst the available formatters - * - * - * @author Julien Fastré + * Choose a formatter amongst the available formatters. */ class PickFormatterType extends AbstractType { @@ -45,26 +32,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/Listing/FilterOrderType.php b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php index 564b08596..ff8820f4d 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php @@ -1,5 +1,12 @@ hasSearchBox()) { $builder->add('q', SearchType::class, [ 'label' => false, - 'required' => false + 'required' => false, ]); } - $checkboxesBuilder = $builder->create('checkboxes', null, [ 'compound' => true ]); - foreach ($helper->getCheckboxes() as $name => $c) { + $checkboxesBuilder = $builder->create('checkboxes', null, ['compound' => true]); - $choices = \array_combine( - \array_map(function($c, $t) { - if ($t !== NULL) { return $t; } - else { return $c; } + foreach ($helper->getCheckboxes() as $name => $c) { + $choices = array_combine( + array_map(function ($c, $t) { + if (null !== $t) { + return $t; + } + + return $c; }, $c['choices'], $c['trans']), $c['choices'] ); @@ -55,19 +67,23 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType } foreach ($this->requestStack->getCurrentRequest()->query->getIterator() as $key => $value) { - switch($key) { + switch ($key) { case 'q': - case 'checkboxes'.$key: + case 'checkboxes' . $key: break; + case 'page': $builder->add($key, HiddenType::class, [ - 'data' => 1 + 'data' => 1, ]); + break; + default: $builder->add($key, HiddenType::class, [ - 'data' => $value + 'data' => $value, ]); + break; } } @@ -79,14 +95,15 @@ final class FilterOrderType extends \Symfony\Component\Form\AbstractType $helper = $options['helper']; $view->vars['has_search_box'] = $helper->hasSearchBox(); $view->vars['checkboxes'] = []; + foreach ($helper->getCheckboxes() as $name => $c) { - $view->vars['checkboxes'][$name] = []; + $view->vars['checkboxes'][$name] = []; } } public function configureOptions(\Symfony\Component\OptionsResolver\OptionsResolver $resolver) { - $resolver->setRequired('helper') - ->setAllowedTypes('helper', FilterOrderHelper::class); + $resolver->setRequired('helper') + ->setAllowedTypes('helper', FilterOrderHelper::class); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickAddressType.php b/src/Bundle/ChillMainBundle/Form/Type/PickAddressType.php index e613fdf65..686fc83da 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/PickAddressType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PickAddressType.php @@ -1,5 +1,12 @@ vars['uniqid'] = $view->vars['attr']['data-input-address'] =\uniqid('input_address_'); + $view->vars['uniqid'] = $view->vars['attr']['data-input-address'] = uniqid('input_address_'); $view->vars['attr']['data-use-valid-from'] = (int) $options['use_valid_from']; $view->vars['attr']['data-use-valid-to'] = (int) $options['use_valid_to']; $view->vars['attr']['data-button-text-create'] = $this->translator->trans($options['button_text_create']); diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickCenterType.php b/src/Bundle/ChillMainBundle/Form/Type/PickCenterType.php index 07c3d5c67..9a5be7bc6 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/PickCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PickCenterType.php @@ -1,56 +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; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer; use Chill\MainBundle\Repository\CenterRepository; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; +use RuntimeException; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; 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 Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Security\Core\Security; +use function array_merge; +use function array_values; /** - * Pick a center + * Pick a center. * * For a given role and, eventually, scopes, show a dropdown (if more than * one reachable center) or a HiddenType (if one or zero center). - * - * */ class PickCenterType extends AbstractType { protected AuthorizationHelperInterface $authorizationHelper; - protected Security $security; - protected CenterRepository $centerRepository; + protected Security $security; + public function __construct( AuthorizationHelperInterface $authorizationHelper, Security $security, @@ -61,13 +50,64 @@ class PickCenterType extends AbstractType $this->centerRepository = $centerRepository; } + /** + * add a data transformer if user can reach only one center. + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $centers = $this->getReachableCenters($options['role'], $options['scopes']); + + if (count($centers) <= 1) { + $multiple = $options['choice_options']['multiple'] ?? false; + $builder->add('center', HiddenType::class); + $builder->get('center')->addModelTransformer( + new CenterTransformer($this->centerRepository, $multiple) + ); + } else { + $builder->add( + 'center', + EntityType::class, + array_merge( + $options['choice_options'], + [ + 'class' => Center::class, + 'choices' => $centers, + ] + ) + ); + } + + $builder + ->addModelTransformer(new CallbackTransformer( + function ($data) { + if (null === $data) { + return ['center' => null]; + } + + return ['center' => $data]; + }, + function ($data) { + return $data['center']; + } + )); + } + + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['is_hidden'] = count($this->getReachableCenters( + $options['role'], + $options['scopes'] + )) <= 1; + } + /** * return a 'hidden' field if only one center is available. * * Return a 'choice' field if more than one center is available. * + * @throws RuntimeException if the user is not associated with any center + * * @return string - * @throws \RuntimeException if the user is not associated with any center */ /* public function getParent() @@ -80,71 +120,26 @@ class PickCenterType extends AbstractType return EntityType::class; } } - */ + */ /** * configure default options, i.e. add choices if user can reach multiple * centers. - * - * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver) { $resolver ->setDefault('class', Center::class) ->setRequired('role') - ->setAllowedTypes('role', [ 'string' ]) + ->setAllowedTypes('role', ['string']) ->setDefault('scopes', []) ->setAllowedTypes('scopes', ['iterable']) - ->setDefault('choice_options', []) - ; + ->setDefault('choice_options', []); /* ->setDefault('choices', $this->reachableCenters) ->setDefault('placeholder', 'Pick a center') ; - */ - } - - /** - * add a data transformer if user can reach only one center - * - * @param FormBuilderInterface $builder - * @param array $options - */ - public function buildForm(FormBuilderInterface $builder, array $options) - { - $centers = $this->getReachableCenters($options['role'], $options['scopes']); - - if (count($centers) <= 1) { - $multiple = $options['choice_options']['multiple'] ?? false; - $builder->add('center', HiddenType::class); - $builder->get('center')->addModelTransformer( - new CenterTransformer($this->centerRepository, $multiple) - ); - } else { - $builder->add('center', EntityType::class, - \array_merge( - $options['choice_options'], - [ - 'class' => Center::class, - 'choices' => $centers - ] - ) - ); - } - - $builder - ->addModelTransformer(new CallbackTransformer( - function($data) { - if (NULL === $data) { - return ['center' => null]; - } - return ['center' => $data]; - }, - function($data) { - return $data['center']; - } - )); + */ } private function getReachableCenters(string $role, iterable $scopes): array @@ -152,23 +147,17 @@ class PickCenterType extends AbstractType if (0 < count($scopes)) { $centers = []; - foreach($scopes as $scope) { + foreach ($scopes as $scope) { foreach ($this->authorizationHelper - ->getReachableCenters($this->security->getUser(), $role, $scope) as $center) { + ->getReachableCenters($this->security->getUser(), $role, $scope) as $center) { $centers[spl_object_hash($center)] = $center; } } - return \array_values($centers); - } else { - return $this->authorizationHelper - ->getReachableCenters($this->security->getUser(), $role); + return array_values($centers); } - } - public function buildView(FormView $view, FormInterface $form, array $options) - { - $view->vars['is_hidden'] = count($this->getReachableCenters($options['role'], - $options['scopes'])) <= 1; + return $this->authorizationHelper + ->getReachableCenters($this->security->getUser(), $role); } } 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 2785365cf..95c262575 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; @@ -23,11 +14,8 @@ use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\DataMapper\ScopePickerDataMapper; use Chill\MainBundle\Repository\ScopeRepository; -use Chill\MainBundle\Repository\UserACLAwareRepositoryInterface; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; 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\Extension\Core\Type\HiddenType; @@ -39,6 +27,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Security; +use function array_map; /** * Allow to pick amongst available scope for the current @@ -48,29 +37,28 @@ use Symfony\Component\Security\Core\Security; * * - `center`: the center of the entity * - `role` : the role of the user - * */ class ScopePickerType extends AbstractType { protected AuthorizationHelperInterface $authorizationHelper; + /** + * @var ScopeRepository + */ + protected $scopeRepository; + + protected Security $security; + /** * @var TokenStorageInterface */ protected $tokenStorage; - /** - * @var ScopeRepository - */ - protected $scopeRepository; - /** * @var TranslatableStringHelper */ protected $translatableStringHelper; - protected Security $security; - public function __construct( AuthorizationHelperInterface $authorizationHelper, TokenStorageInterface $tokenStorage, @@ -87,8 +75,11 @@ class ScopePickerType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { - $items = $this->authorizationHelper->getReachableScopes($this->security->getUser(), - $options['role'], $options['center']); + $items = $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + $options['role'], + $options['center'] + ); if (1 !== count($items)) { $builder->add('scope', EntityType::class, [ @@ -111,7 +102,8 @@ class ScopePickerType extends AbstractType public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace( - $view->vars, [ + $view->vars, + [ 'hideLabel' => true, ] ); @@ -129,15 +121,16 @@ class ScopePickerType extends AbstractType } /** - * @param Center|array|Center[] $center + * @param array|Center|Center[] $center * @param string $role + * * @return \Doctrine\ORM\QueryBuilder */ protected function buildAccessibleScopeQuery($center, $role) { $roles = $this->authorizationHelper->getParentRoles($role); $roles[] = $role; - $centers = $center instanceof Center ? [$center]: $center; + $centers = $center instanceof Center ? [$center] : $center; $qb = $this->scopeRepository->createQueryBuilder('s'); $qb @@ -147,13 +140,13 @@ class ScopePickerType extends AbstractType ->join('pg.groupCenters', 'gc') // add center constraint ->where($qb->expr()->in('IDENTITY(gc.center)', ':centers')) - ->setParameter('centers', \array_map(fn(Center $c) => $c->getId(), $centers)) + ->setParameter('centers', array_map(fn (Center $c) => $c->getId(), $centers)) // role constraints ->andWhere($qb->expr()->in('rs.role', ':roles')) ->setParameter('roles', $roles) // 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 c8288d69d..e0fa0374c 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php @@ -1,80 +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\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\DependencyInjection\ParameterBag\ParameterBagInterface; +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 { - private RequestStack $requestStack; - - private ObjectManager $em; + protected ParameterBagInterface $parameterBag; protected TranslatableStringHelper $translatableStringHelper; - protected ParameterBagInterface $parameterBag; + private ObjectManager $em; + + private RequestStack $requestStack; public function __construct( RequestStack $requestStack, ObjectManager $em, TranslatableStringHelper $translatableStringHelper, ParameterBagInterface $parameterBag - ) - { + ) { $this->requestStack = $requestStack; $this->em = $em; $this->translatableStringHelper = $translatableStringHelper; $this->parameterBag = $parameterBag; } - 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) { $countries = $this->em->getRepository('Chill\MainBundle\Entity\Country')->findAll(); @@ -96,10 +70,20 @@ 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)), - 'preferred_choices' => array_combine(array_values($preferredChoices), array_keys($preferredChoices)) - )); + $resolver->setDefaults([ + 'class' => 'Chill\MainBundle\Entity\Country', + 'choices' => array_combine(array_values($choices), array_keys($choices)), + 'preferred_choices' => array_combine(array_values($preferredChoices), array_keys($preferredChoices)), + ]); + } + + 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 a50569967..a74454172 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php @@ -1,77 +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\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\DependencyInjection\ParameterBag\ParameterBagInterface; +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 { - private RequestStack $requestStack; - - private ObjectManager $em; + protected ParameterBagInterface $parameterBag; protected TranslatableStringHelper $translatableStringHelper; - protected ParameterBagInterface $parameterBag; + private ObjectManager $em; + + private RequestStack $requestStack; public function __construct( RequestStack $requestStack, ObjectManager $em, TranslatableStringHelper $translatableStringHelper, ParameterBagInterface $parameterBag - ) - { + ) { $this->requestStack = $requestStack; $this->em = $em; $this->translatableStringHelper = $translatableStringHelper; $this->parameterBag = $parameterBag; } - 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) { $languages = $this->em->getRepository('Chill\MainBundle\Entity\Language')->findAll(); @@ -82,16 +59,27 @@ class Select2LanguageType extends AbstractType foreach ($languages as $l) { $choices[$l->getId()] = $this->translatableStringHelper->localize($l->getName()); } + foreach ($preferredLanguages as $l) { $preferredChoices[$l] = $choices[$l]; } asort($choices, SORT_STRING | SORT_FLAG_CASE); - $resolver->setDefaults(array( - 'class' => 'Chill\MainBundle\Entity\Language', - 'choices' => array_combine(array_values($choices), array_keys($choices)), - 'preferred_choices' => array_combine(array_values($preferredChoices), array_keys($preferredChoices)) - )); + $resolver->setDefaults([ + 'class' => 'Chill\MainBundle\Entity\Language', + 'choices' => array_combine(array_values($choices), array_keys($choices)), + 'preferred_choices' => array_combine(array_values($preferredChoices), array_keys($preferredChoices)), + ]); + } + + 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 2558f4a4f..57106da07 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php @@ -1,37 +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\Form\Type; use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Repository\UserACLAwareRepositoryInterface; -use Symfony\Component\Form\AbstractType; +use Chill\MainBundle\Repository\UserRepository; 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 Chill\MainBundle\Repository\UserRepository; -use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Security\Core\Role\Role; - /** * Pick a user available for the given role and center. * @@ -39,27 +28,23 @@ 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; - protected UserRepository $userRepository; - protected UserACLAwareRepositoryInterface $userACLAwareRepository; + protected UserRepository $userRepository; + public function __construct( AuthorizationHelper $authorizationHelper, TokenStorageInterface $tokenStorage, @@ -72,42 +57,37 @@ class UserPickerType extends AbstractType $this->userACLAwareRepository = $userACLAwareRepository; } - public function configureOptions(OptionsResolver $resolver) { $resolver // create `center` option ->setRequired('center') - ->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class, 'null', 'array' ]) + ->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class, 'null', 'array']) // 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(); }) ->setDefault('scope', null) ->setAllowedTypes('scope', [Scope::class, 'array', 'null']) - ->setNormalizer('choices', function(Options $options) { - + ->setNormalizer('choices', function (Options $options) { $users = $this->userACLAwareRepository ->findUsersByReachedACL($options['role'], $options['center'], $options['scope'], true); - 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/UserCurrentLocationType.php b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php new file mode 100644 index 000000000..a6bc6ef8a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php @@ -0,0 +1,46 @@ +translatableStringHelper = $translatableStringHelper; + $this->locationRepository = $locationRepository; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('currentLocation', EntityType::class, [ + 'class' => Location::class, + 'choices' => $this->locationRepository->findByPublicLocations(), + 'choice_label' => function (Location $entity) { + return $entity->getName() ? + $entity->getName() . ' (' . $this->translatableStringHelper->localize($entity->getLocationType()->getTitle()) . ')' : + $this->translatableStringHelper->localize($entity->getLocationType()->getTitle()); + }, + 'placeholder' => 'Pick a location', + 'required' => false, + ]); + } +} diff --git a/src/Bundle/ChillMainBundle/Form/UserJobType.php b/src/Bundle/ChillMainBundle/Form/UserJobType.php index eec718261..3938ef731 100644 --- a/src/Bundle/ChillMainBundle/Form/UserJobType.php +++ b/src/Bundle/ChillMainBundle/Form/UserJobType.php @@ -1,5 +1,12 @@ add('label', TranslatableStringFormType::class, [ 'label' => 'Label', - 'required' => true + 'required' => true, ]) ->add('active', ChoiceType::class, [ 'choices' => [ 'Active' => true, - 'Inactive' => false - ] - ]) - ; + 'Inactive' => false, + ], + ]); } - } 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 bf056cec5..cf062f1ab 100644 --- a/src/Bundle/ChillMainBundle/Form/UserType.php +++ b/src/Bundle/ChillMainBundle/Form/UserType.php @@ -1,5 +1,12 @@ translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('username') ->add('email', EmailType::class, [ - 'required' => true + 'required' => true, ]) ->add('label', TextType::class) ->add('mainCenter', EntityType::class, [ @@ -56,7 +54,7 @@ class UserType extends AbstractType $qb->addOrderBy('c.name'); return $qb; - } + }, ]) ->add('mainScope', EntityType::class, [ 'label' => 'Main scope', @@ -75,47 +73,47 @@ class UserType extends AbstractType 'choice_label' => function (UserJob $c) { return $this->translatableStringHelper->localize($c->getLabel()); }, - ]) - ; + ]); + 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, - )) - ); + ]) + ); } } @@ -124,14 +122,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 +84,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 +125,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/Notification/NotificationRenderer.php b/src/Bundle/ChillMainBundle/Notification/NotificationRenderer.php index d6f383b73..1a8c68ca2 100644 --- a/src/Bundle/ChillMainBundle/Notification/NotificationRenderer.php +++ b/src/Bundle/ChillMainBundle/Notification/NotificationRenderer.php @@ -1,10 +1,18 @@ renderers[] = $activityNotificationRenderer; } - private function getRenderer(Notification $notification) - { - foreach ($this->renderers as $renderer) { - if($renderer->supports($notification)) { - return $renderer; - } - } - - throw new \Exception('No renderer for '. $notification); - } - public function getTemplate(Notification $notification) { return $this->getRenderer($notification)->getTemplate(); @@ -41,4 +38,15 @@ final class NotificationRenderer { return $this->getRenderer($notification)->getTemplateData($notification); } + + private function getRenderer(Notification $notification) + { + foreach ($this->renderers as $renderer) { + if ($renderer->supports($notification)) { + return $renderer; + } + } + + throw new Exception('No renderer for ' . $notification); + } } diff --git a/src/Bundle/ChillMainBundle/Pagination/ChillItemsPerPageTwig.php b/src/Bundle/ChillMainBundle/Pagination/ChillItemsPerPageTwig.php index 2cfb45d4a..b94a75645 100644 --- a/src/Bundle/ChillMainBundle/Pagination/ChillItemsPerPageTwig.php +++ b/src/Bundle/ChillMainBundle/Pagination/ChillItemsPerPageTwig.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,41 +14,37 @@ use Twig\Extension\AbstractExtension; use Twig\TwigFunction; /** - * add twig function to render pagination - * - * @author Mathieu Jaumotte - * @author Champs Libres + * add twig function to render pagination. */ class ChillItemsPerPageTwig extends AbstractExtension { + public function getFunctions() + { + return [ + new TwigFunction( + 'chill_items_per_page', + [$this, 'paginationRender'], + [ + 'needs_environment' => true, + 'is_safe' => ['html'], + ] + ), + ]; + } + public function getName() { return 'chill_items_per_page'; } - public function getFunctions() - { - return array( - new TwigFunction( - 'chill_items_per_page', - array($this, 'paginationRender'), - array( - 'needs_environment' => true, - 'is_safe' => ['html'] - ) - ) - ); - } - public function paginationRender( - Environment $env, - PaginatorInterface $paginator, - $template = '@ChillMain/Pagination/items_per_page.html.twig' + Environment $env, + PaginatorInterface $paginator, + $template = '@ChillMain/Pagination/items_per_page.html.twig' ) { - - return $env->render($template, array( - 'paginator' => $paginator, - 'current' => $paginator->getItemsPerPage() - )); + return $env->render($template, [ + 'paginator' => $paginator, + 'current' => $paginator->getItemsPerPage(), + ]); } } 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 93c481a2e..d7da19708 100644 --- a/src/Bundle/ChillMainBundle/Pagination/PageGenerator.php +++ b/src/Bundle/ChillMainBundle/Pagination/PageGenerator.php @@ -1,21 +1,30 @@ paginator = $paginator;; + $this->paginator = $paginator; } public function current() @@ -30,7 +39,7 @@ class PageGenerator implements \Iterator public function next() { - $this->current++; + ++$this->current; } public function rewind() @@ -40,7 +49,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 c386a9757..f453ba7e8 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 = 20 + RequestStack $requestStack, + RouterInterface $router, + $itemPerPage = 20 ) { $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(), + $this->router->getContext()->getParameters(), // get the route parameters $this->requestStack - ->getCurrentRequest() - ->attributes->get('_route_params'), + ->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..f6c62dff1 100644 --- a/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php +++ b/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php @@ -1,28 +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\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 +26,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 +55,18 @@ 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 +74,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 +215,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 51f2d2c6d..7ed0bece5 100644 --- a/src/Bundle/ChillMainBundle/Redis/RedisConnectionFactory.php +++ b/src/Bundle/ChillMainBundle/Redis/RedisConnectionFactory.php @@ -1,78 +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 . - */ -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 $host; - + protected $port; - - protected $timeout; - + /** - * * @var Redis */ protected $redis; - + + protected $timeout; + public function __construct($parameters) { $this->host = $parameters['host']; $this->port = $parameters['port']; $this->timeout = $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 cf488f411..4344964af 100644 --- a/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(AddressReference::class); } + public function countAll(): int + { + $qb = $this->repository->createQueryBuilder('ar'); + $qb->select('count(ar.id)'); + + return $qb->getQuery()->getSingleScalarResult(); + } + public function find($id, $lockMode = null, $lockVersion = null): ?AddressReference { return $this->repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?AddressReference - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return AddressReference[] */ @@ -36,23 +46,24 @@ final class AddressReferenceRepository implements ObjectRepository return $this->repository->findAll(); } - public function countAll(): int - { - $qb = $this->repository->createQueryBuilder('ar'); - $qb->select('count(ar.id)'); - - return $qb->getQuery()->getSingleScalarResult(); - } - /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return AddressReference[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?AddressReference + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return AddressReference::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/AddressRepository.php b/src/Bundle/ChillMainBundle/Repository/AddressRepository.php index 08e2da708..a6d739de4 100644 --- a/src/Bundle/ChillMainBundle/Repository/AddressRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/AddressRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(Address::class); } + public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder + { + return $this->repository->createQueryBuilder($alias, $indexBy); + } + public function find($id, $lockMode = null, $lockVersion = null): ?Address { return $this->repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?Address - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return Address[] */ @@ -38,19 +45,23 @@ final class AddressRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return Address[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { - return Address::class; + public function findOneBy(array $criteria, ?array $orderBy = null): ?Address + { + return $this->repository->findOneBy($criteria, $orderBy); } - public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder + public function getClassName() { - return $this->repository->createQueryBuilder($alias, $indexBy); + return Address::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php index 3cf8cf38b..554f39880 100644 --- a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?Center - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return Center[] */ @@ -37,14 +39,23 @@ final class CenterRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return Center[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?Center + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return Center::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/CivilityRepository.php b/src/Bundle/ChillMainBundle/Repository/CivilityRepository.php index 2702784f0..9e3f8928a 100644 --- a/src/Bundle/ChillMainBundle/Repository/CivilityRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/CivilityRepository.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\Repository; @@ -38,5 +25,4 @@ class CivilityRepository extends ServiceEntityRepository { parent::__construct($registry, Civility::class); } - } diff --git a/src/Bundle/ChillMainBundle/Repository/CountryRepository.php b/src/Bundle/ChillMainBundle/Repository/CountryRepository.php index 336768948..81bea648d 100644 --- a/src/Bundle/ChillMainBundle/Repository/CountryRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/CountryRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?Country - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return Country[] */ @@ -37,14 +39,23 @@ final class CountryRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return Country[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?Country + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return Country::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/GroupCenterRepository.php b/src/Bundle/ChillMainBundle/Repository/GroupCenterRepository.php index 6faed8e47..f8b11ceac 100644 --- a/src/Bundle/ChillMainBundle/Repository/GroupCenterRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/GroupCenterRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?GroupCenter - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return GroupCenter[] */ @@ -37,14 +39,23 @@ final class GroupCenterRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return GroupCenter[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?GroupCenter + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return GroupCenter::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/LanguageRepository.php b/src/Bundle/ChillMainBundle/Repository/LanguageRepository.php index f6a7ec284..88e00a6c4 100644 --- a/src/Bundle/ChillMainBundle/Repository/LanguageRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/LanguageRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?Language - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return Language[] */ @@ -37,14 +39,23 @@ final class LanguageRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return Language[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?Language + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return Language::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/LocationRepository.php b/src/Bundle/ChillMainBundle/Repository/LocationRepository.php index 8e67fecea..44484c91c 100644 --- a/src/Bundle/ChillMainBundle/Repository/LocationRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/LocationRepository.php @@ -1,5 +1,12 @@ findBy(['active' => true, 'availableForUsers' => true]); + } } diff --git a/src/Bundle/ChillMainBundle/Repository/LocationTypeRepository.php b/src/Bundle/ChillMainBundle/Repository/LocationTypeRepository.php index 80e2d020d..be47fe74c 100644 --- a/src/Bundle/ChillMainBundle/Repository/LocationTypeRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/LocationTypeRepository.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\Repository; use Chill\MainBundle\Entity\Notification; +use Chill\MainBundle\Entity\User; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; -use Doctrine\Persistence\ObjectRepository; -use Chill\MainBundle\Entity\User; use Doctrine\ORM\Query; +use Doctrine\Persistence\ObjectRepository; final class NotificationRepository implements ObjectRepository { @@ -35,16 +25,18 @@ final class NotificationRepository implements ObjectRepository $this->repository = $entityManager->getRepository(Notification::class); } + public function countAllForAttendee(User $addressee): int // TODO passer à attendees avec S + { + $query = $this->queryAllForAttendee($addressee, $countQuery = true); + + return $query->getSingleScalarResult(); + } + public function find($id, $lockMode = null, $lockVersion = null): ?Notification { return $this->repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?Notification - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return Notification[] */ @@ -54,19 +46,54 @@ final class NotificationRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return Notification[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findAllForAttendee(User $addressee, $limit = null, $offset = null): array // TODO passer à attendees avec S + { + $query = $this->queryAllForAttendee($addressee); + + if ($limit) { + $query = $query->setMaxResults($limit); + } + + if ($offset) { + $query = $query->setFirstResult($offset); + } + + return $query->getResult(); + } + + /** + * @param mixed|null $limit + * @param mixed|null $offset + * + * @return Notification[] + */ + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - private function queryAllForAttendee(User $addressee, bool $countQuery=False): Query + public function findOneBy(array $criteria, ?array $orderBy = null): ?Notification + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { + return Notification::class; + } + + private function queryAllForAttendee(User $addressee, bool $countQuery = false): Query { $qb = $this->repository->createQueryBuilder('n'); $select = 'n'; - if($countQuery) { + + if ($countQuery) { $select = 'count(n)'; } @@ -78,37 +105,4 @@ final class NotificationRepository implements ObjectRepository return $qb->getQuery(); } - - /** - * @return int - */ - public function countAllForAttendee(User $addressee): int // TODO passer à attendees avec S - { - $query = $this->queryAllForAttendee($addressee, $countQuery=True); - - return $query->getSingleScalarResult(); - } - - - /** - * @return Notification[] - */ - public function findAllForAttendee(User $addressee, $limit = null, $offset = null): array // TODO passer à attendees avec S - { - $query = $this->queryAllForAttendee($addressee); - - if($limit) { - $query = $query->setMaxResults($limit); - } - - if($offset) { - $query = $query->setFirstResult($offset); - } - - return $query->getResult(); - } - - public function getClassName() { - return Notification::class; - } } diff --git a/src/Bundle/ChillMainBundle/Repository/PermissionsGroupRepository.php b/src/Bundle/ChillMainBundle/Repository/PermissionsGroupRepository.php index 0bb4c7bfd..18f8ff777 100644 --- a/src/Bundle/ChillMainBundle/Repository/PermissionsGroupRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/PermissionsGroupRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?PermissionsGroup - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return PermissionsGroup[] */ @@ -37,14 +39,23 @@ final class PermissionsGroupRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return PermissionsGroup[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?PermissionsGroup + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return PermissionsGroup::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php b/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php index 0087c9aa9..697c8f90d 100644 --- a/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?PostalCode - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return PostalCode[] */ @@ -37,14 +39,23 @@ final class PostalCodeRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return PostalCode[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?PostalCode + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return PostalCode::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/RoleScopeRepository.php b/src/Bundle/ChillMainBundle/Repository/RoleScopeRepository.php index 6996f384c..2475f9497 100644 --- a/src/Bundle/ChillMainBundle/Repository/RoleScopeRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/RoleScopeRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?RoleScope - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return RoleScope[] */ @@ -37,14 +39,23 @@ final class RoleScopeRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return RoleScope[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?RoleScope + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return RoleScope::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/ScopeRepository.php b/src/Bundle/ChillMainBundle/Repository/ScopeRepository.php index e100000c4..5b3efe658 100644 --- a/src/Bundle/ChillMainBundle/Repository/ScopeRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/ScopeRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(Scope::class); } + public function createQueryBuilder($alias, $indexBy = null) + { + return $this->repository->createQueryBuilder($alias, $indexBy); + } + public function find($id, $lockMode = null, $lockVersion = null): ?Scope { return $this->repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?Scope - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return Scope[] */ @@ -37,19 +44,23 @@ final class ScopeRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return Scope[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - - public function createQueryBuilder($alias, $indexBy = null) + + public function findOneBy(array $criteria, ?array $orderBy = null): ?Scope { - return $this->repository->createQueryBuilder($alias, $indexBy); + return $this->repository->findOneBy($criteria, $orderBy); } - public function getClassName() { + public function getClassName() + { return Scope::class; } } diff --git a/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepository.php b/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepository.php index de0ded2c2..9eb8c859d 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepository.php @@ -1,19 +1,26 @@ parentRoleHelper = $parentRoleHelper; @@ -33,30 +40,26 @@ class UserACLAwareRepository implements UserACLAwareRepositoryInterface ->join('u.groupCenters', 'gc') ->join('gc.permissionsGroup', 'pg') ->join('pg.roleScopes', 'rs') - ->where($qb->expr()->in('rs.role', $parents)) - ; + ->where($qb->expr()->in('rs.role', $parents)); if ($onlyEnabled) { $qb->andWhere($qb->expr()->eq('u.enabled', "'TRUE'")); } - if (NULL !== $center) { + if (null !== $center) { $centers = $center instanceof Center ? [$center] : $center; $qb ->andWhere($qb->expr()->in('gc.center', ':centers')) - ->setParameter('centers', $centers) - ; + ->setParameter('centers', $centers); } - if (NULL !== $scope) { + if (null !== $scope) { $scopes = $scope instanceof Scope ? [$scope] : $scope; $qb ->andWhere($qb->expr()->in('rs.scope', ':scopes')) - ->setParameter('scopes', $scopes) - ; + ->setParameter('scopes', $scopes); } return $qb->getQuery()->getResult(); } - } diff --git a/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepositoryInterface.php index eb249911b..d55797fd5 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillMainBundle/Repository/UserACLAwareRepositoryInterface.php @@ -1,5 +1,12 @@ entityManager = $entityManager; $this->repository = $entityManager->getRepository(User::class); } - public function find($id, $lockMode = null, $lockVersion = null): ?User - { - return $this->repository->find($id, $lockMode, $lockVersion); - } - - public function findOneBy(array $criteria, array $orderBy = null): ?User - { - return $this->repository->findOneBy($criteria, $orderBy); - } - - /** - * @return User[] - */ - public function findAll(): array - { - return $this->repository->findAll(); - } - - /** - * @return User[] - */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array - { - return $this->repository->findBy($criteria, $orderBy, $limit, $offset); - } - public function countBy(array $criteria): int { return $this->repository->count($criteria); @@ -59,18 +40,6 @@ final class UserRepository implements ObjectRepository return $this->countBy(['enabled' => true]); } - /** - * @return User[]|array - */ - public function findByActive(array $orderBy = null, int $limit = null, int $offset = null): array - { - return $this->findBy(['enabled' => true], $orderBy, $limit, $offset); - } - - public function getClassName() { - return User::class; - } - public function countByUsernameOrEmail(string $pattern): int { $qb = $this->queryByUsernameOrEmail($pattern); @@ -80,6 +49,38 @@ final class UserRepository implements ObjectRepository return (int) $qb->getQuery()->getSingleScalarResult(); } + public function find($id, $lockMode = null, $lockVersion = null): ?User + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + /** + * @return User[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @param mixed|null $limit + * @param mixed|null $offset + * + * @return User[] + */ + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + /** + * @return array|User[] + */ + public function findByActive(?array $orderBy = null, ?int $limit = null, ?int $offset = null): array + { + return $this->findBy(['enabled' => true], $orderBy, $limit, $offset); + } + public function findByUsernameOrEmail(string $pattern) { $qb = $this->queryByUsernameOrEmail($pattern); @@ -87,6 +88,11 @@ final class UserRepository implements ObjectRepository return $qb->getQuery()->getResult(); } + public function findOneBy(array $criteria, ?array $orderBy = null): ?User + { + return $this->repository->findOneBy($criteria, $orderBy); + } + public function findOneByUsernameOrEmail(string $pattern) { $qb = $this->queryByUsernameOrEmail($pattern); @@ -95,28 +101,29 @@ final class UserRepository implements ObjectRepository } /** - * Get the users having a specific flags + * 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, array $amongstUsers = []): array { $gcs = $this ->entityManager ->createQuery( - "SELECT DISTINCT gc " . - "FROM ".GroupCenter::class." gc " . - "JOIN gc.permissionsGroup pg " . - "WHERE " . - "JSONB_EXISTS_IN_ARRAY(pg.flags, :flag) = :true " + '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(); @@ -132,14 +139,14 @@ final class UserRepository implements ObjectRepository $orx = $qb->expr()->orX(); - foreach($gcs as $i => $gc) { + foreach ($gcs as $i => $gc) { $orx->add(':gc_' . $i . ' MEMBER OF u.groupCenters'); $qb->setParameter('gc_' . $i, $gc); } $qb->andWhere($orx); - if ($amongstUsers !== []) { + if ([] !== $amongstUsers) { $qb ->andWhere($qb->expr()->in('u', ':amongstUsers')) ->setParameter('amongstUsers', $amongstUsers); @@ -148,7 +155,12 @@ final class UserRepository implements ObjectRepository return $qb->getQuery()->getResult(); } - protected function queryByUsernameOrEmail(string $pattern): QueryBuilder + public function getClassName() + { + return User::class; + } + + private function queryByUsernameOrEmail(string $pattern): QueryBuilder { $qb = $this->entityManager->createQueryBuilder('u'); 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 @@ +

    {{ 'Edit my current location'|trans }}

    + + {{ form_start(edit_form) }} + {{ form_row(edit_form.currentLocation) }} + +
      +
    • + {{ form_widget(edit_form.submit, { 'attr': { 'class': 'btn btn-edit' } } ) }} +
    • +
    + + {{ form_end(edit_form) }} + +
+{% endblock %} diff --git a/src/Bundle/ChillMainBundle/Routing/Loader/ChillRoutesLoader.php b/src/Bundle/ChillMainBundle/Routing/Loader/ChillRoutesLoader.php index e9b084e6d..bc16929b7 100644 --- a/src/Bundle/ChillMainBundle/Routing/Loader/ChillRoutesLoader.php +++ b/src/Bundle/ChillMainBundle/Routing/Loader/ChillRoutesLoader.php @@ -1,5 +1,12 @@ routes as $routeResource) { $collection->addCollection( - $this->import($routeResource, NULL) + $this->import($routeResource, null) ); } @@ -41,5 +48,4 @@ class ChillRoutesLoader extends Loader { 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 7f41dbf67..b76fbe4f2 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminSectionMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminSectionMenuBuilder.php @@ -1,35 +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\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; @@ -47,26 +33,26 @@ class AdminSectionMenuBuilder implements LocalMenuBuilderInterface } $menu->addChild('Users and permissions', [ - 'route' => 'chill_main_admin_permissions' - ]) + 'route' => 'chill_main_admin_permissions', + ]) ->setExtras([ 'icons' => ['key'], 'order' => 200, - 'explain' => "Configure permissions for users" + 'explain' => 'Configure permissions for users', ]); $menu->addChild('Location and location type', [ - 'route' => 'chill_main_admin_locations' - ]) + 'route' => 'chill_main_admin_locations', + ]) ->setExtras([ 'icons' => ['key'], 'order' => 205, - 'explain' => "Configure location and location type" + 'explain' => 'Configure location and location type', ]); } public static function getMenuIds(): array { - return [ 'admin_section', 'admin_index' ]; + return ['admin_section', 'admin_index']; } } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/LocationMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/LocationMenuBuilder.php index 890c1b2ef..a304275d3 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/LocationMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/LocationMenuBuilder.php @@ -1,28 +1,31 @@ addChild('Location type list', [ - 'route' => 'chill_crud_main_location_type_index' + 'route' => 'chill_crud_main_location_type_index', ])->setExtras(['order' => 205]); $menu->addChild('Location list', [ - 'route' => 'chill_crud_main_location_index' + 'route' => 'chill_crud_main_location_index', ])->setExtras(['order' => 206]); } + + public static function getMenuIds(): array + { + return ['admin_location']; + } } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/PermissionMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/PermissionMenuBuilder.php index 470930820..116aa0498 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/PermissionMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/PermissionMenuBuilder.php @@ -1,43 +1,45 @@ addChild('Permissions group list', [ - 'route' => 'admin_permissionsgroup' + 'route' => 'admin_permissionsgroup', ])->setExtras([ - 'order' => 300 - ]); + 'order' => 300, + ]); $menu->addChild('crud.admin_user.index.title', [ - 'route' => 'chill_crud_admin_user_index' + 'route' => 'chill_crud_admin_user_index', ])->setExtras(['order' => 400]); $menu->addChild('List circles', [ - 'route' => 'admin_scope' + 'route' => 'admin_scope', ])->setExtras(['order' => 200]); $menu->addChild('Center list', [ - 'route' => 'admin_center' + 'route' => 'admin_center', ])->setExtras(['order' => 100]); $menu->addChild('User jobs', [ - 'route' => 'chill_crud_admin_user_job_index' + 'route' => 'chill_crud_admin_user_job_index', ])->setExtras(['order' => 150]); + } + public static function getMenuIds(): array + { + return ['admin_permissions']; } } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php index b8619750c..b1d5abcfd 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,62 +24,56 @@ 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, ]); $menu->addChild($this->translator->trans('Global timeline'), [ 'route' => 'chill_center_timeline', ]) - ->setExtras([ - 'order' => 10 - ] - ); - + ->setExtras( + [ + 'order' => 10, + ] + ); + 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..bdff818ef 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php @@ -1,71 +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 . - */ -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\Security; + class UserMenuBuilder implements LocalMenuBuilderInterface { - /** - * - * @var TokenStorageInterface - */ - protected $tokenStorage; - - public function __construct(TokenStorageInterface $tokenStorage) + private Security $security; + + public function __construct(Security $security) { - $this->tokenStorage = $tokenStorage; + $this->security = $security; } - + public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters) { - if ($this->tokenStorage->getToken()->getUser() instanceof User) { + $user = $this->security->getUser(); + + if ($user instanceof User) { + if (null !== $user->getCurrentLocation()) { + $locationTextMenu = $user->getCurrentLocation()->getName(); + } else { + $locationTextMenu = 'Set a location'; + } + + $menu + ->addChild( + $locationTextMenu, + ['route' => 'chill_main_user_currentlocation_edit'] + ) + ->setExtras([ + 'order' => -9999999, + 'icon' => 'map-marker', + ]); $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 b1883c61d..94a6970c8 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuComposer.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuComposer.php @@ -1,38 +1,43 @@ 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]; @@ -89,54 +117,29 @@ class MenuComposer return $routes; } - public function getMenuFor($menuId, array $parameters = array()) + /** + * 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 + */ + public function hasLocalMenuBuilder($menuId): bool { - $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 \array_key_exists($menuId, $this->localMenuBuilders); } /** - * 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 + * 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). */ - private function resolveOrder($routes, $order) + public function setRouteCollection(RouteCollection $routeCollection) { - if (isset($routes[$order])) { - return $this->resolveOrder($routes, $order + 1); - } else { - return $order; - } + $this->routeCollection = $routeCollection; } private function reorderMenu(ItemInterface $menu) @@ -147,8 +150,8 @@ class MenuComposer foreach ($menu->getChildren() as $name => $item) { $order = $item->getExtra('order'); - if ($order !== null) { - $ordered[$this->resolveOrder($ordered, $order)] = $name; + if (null !== $order) { + $ordered[$this->resolveOrder($ordered, $order)] = $name; } else { $unordered = $name; } @@ -156,29 +159,26 @@ class MenuComposer ksort($ordered); - $menus = \array_merge(\array_values($ordered), $unordered); + $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. + * 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. * - * 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 array $routes the routes previously added + * @param int $order * - * @param string $menuId - * @return bool + * @return int */ - public function hasLocalMenuBuilder($menuId): bool + private function resolveOrder($routes, $order) { - return \array_key_exists($menuId, $this->localMenuBuilders); - } + 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 1f32d3d16..3577c1300 100644 --- a/src/Bundle/ChillMainBundle/Search/AbstractSearch.php +++ b/src/Bundle/ChillMainBundle/Search/AbstractSearch.php @@ -1,98 +1,85 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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 .= (mb_stristr(' ', $terms[$term]) === FALSE) ? $terms[$term] : '('.$terms[$term].')'; + $recomposed .= (mb_stristr(' ', $terms[$term]) === false) ? $terms[$term] : '(' . $terms[$term] . ')'; + if ($containsSpace) { $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); } diff --git a/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php b/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php index 6b8139419..18e98a0e7 100644 --- a/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php +++ b/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php @@ -1,59 +1,65 @@ userRepository = $userRepository; } - public function provideQuery(string $pattern, array $parameters): SearchApiQuery - { - $query = new SearchApiQuery(); - $query - ->setSelectKey("user") - ->setSelectJsonbMetadata("jsonb_build_object('id', u.id)") - ->setSelectPertinence("GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical), - SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical))", [ $pattern, $pattern ]) - ->setFromClause("users AS u") - ->setWhereClauses("SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15 - OR - SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical) > 0.15 - ", [ $pattern, $pattern ]); - - return $query; - } - - public function supportsTypes(string $pattern, array $types, array $parameters): bool - { - return \in_array('user', $types); - } - - public function prepare(array $metadatas): void - { - $ids = \array_map(fn($m) => $m['id'], $metadatas); - - $this->userRepository->findBy([ 'id' => $ids ]); - } - - public function supportsResult(string $key, array $metadatas): bool - { - return $key === 'user'; - } - public function getResult(string $key, array $metadata, float $pertinence) { return $this->userRepository->find($metadata['id']); } + + public function prepare(array $metadatas): void + { + $ids = array_map(fn ($m) => $m['id'], $metadatas); + + $this->userRepository->findBy(['id' => $ids]); + } + + public function provideQuery(string $pattern, array $parameters): SearchApiQuery + { + $query = new SearchApiQuery(); + $query + ->setSelectKey('user') + ->setSelectJsonbMetadata("jsonb_build_object('id', u.id)") + ->setSelectPertinence('GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical), + SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical))', [$pattern, $pattern]) + ->setFromClause('users AS u') + ->setWhereClauses('SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15 + OR + SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical) > 0.15 + ', [$pattern, $pattern]); + + return $query; + } + + public function supportsResult(string $key, array $metadatas): bool + { + return 'user' === $key; + } + + public function supportsTypes(string $pattern, array $types, array $parameters): bool + { + return in_array('user', $types); + } } 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/Model/Result.php b/src/Bundle/ChillMainBundle/Search/Model/Result.php index a88c2f55f..ca6960fc5 100644 --- a/src/Bundle/ChillMainBundle/Search/Model/Result.php +++ b/src/Bundle/ChillMainBundle/Search/Model/Result.php @@ -1,5 +1,12 @@ result; } - - - } 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 @@ $p->provideQuery($pattern, $parameters), - $this->findProviders($pattern, $types, $parameters), - ); - } - - private function findProviders(string $pattern, array $types, array $parameters): array - { - $providers = []; - - foreach ($this->providers as $provider) { - if ($provider->supportsTypes($pattern, $types, $parameters)) { - $providers[] = $provider; - } - } - - return $providers; - } - - private function countItems($providers, $types, $parameters): int - { - list($countQuery, $parameters) = $this->buildCountQuery($providers, $types, $parameters); - $rsmCount = new ResultSetMappingBuilder($this->em); - $rsmCount->addScalarResult('count', 'count'); - $countNq = $this->em->createNativeQuery($countQuery, $rsmCount); - $countNq->setParameters($parameters); - - return (int) $countNq->getSingleScalarResult(); - } - private function buildCountQuery(array $queries, $types, $parameters) { - $query = "SELECT SUM(c) AS count FROM ({union_unordered}) AS sq"; + $query = 'SELECT SUM(c) AS count FROM ({union_unordered}) AS sq'; $unions = []; $parameters = []; foreach ($queries as $q) { $unions[] = $q->buildQuery(true); - $parameters = \array_merge($parameters, $q->buildParameters(true)); + $parameters = array_merge($parameters, $q->buildParameters(true)); } - $unionUnordered = \implode(" UNION ", $unions); + $unionUnordered = implode(' UNION ', $unions); return [ - \strtr($query, [ '{union_unordered}' => $unionUnordered ]), - $parameters + strtr($query, ['{union_unordered}' => $unionUnordered]), + $parameters, ]; } - private function buildUnionQuery(array $queries, $types, $parameters) - { - $query = "{unions} ORDER BY pertinence DESC"; - $unions = []; - $parameters = []; - - foreach ($queries as $q) { - $unions[] = $q->buildQuery(); - $parameters = \array_merge($parameters, $q->buildParameters()); - } - - $union = \implode(" UNION ", $unions); - - return [ - \strtr($query, [ '{unions}' => $union]), - $parameters - ]; - } - - private function fetchRawResult($queries, $types, $parameters, $paginator): array - { - list($union, $parameters) = $this->buildUnionQuery($queries, $types, $parameters); - $rsm = new ResultSetMappingBuilder($this->em); - $rsm->addScalarResult('key', 'key', Types::STRING) - ->addScalarResult('metadata', 'metadata', Types::JSON) - ->addScalarResult('pertinence', 'pertinence', Types::FLOAT) - ; - - $nq = $this->em->createNativeQuery($union, $rsm); - $nq->setParameters($parameters); - - return $nq->getResult(); - } - - private function prepareProviders(array $rawResults) - { - $metadatas = []; - $providers = []; - - foreach ($rawResults as $r) { - foreach ($this->providers as $k => $p) { - if ($p->supportsResult($r['key'], $r['metadata'])) { - $metadatas[$k][] = $r['metadata']; - $providers[$k] = $p; - break; - } - } - } - - foreach ($metadatas as $k => $m) { - $providers[$k]->prepare($m); - } - } - private function buildResults(array $rawResults): array { $items = []; @@ -170,6 +91,7 @@ class SearchApi ->setResult( $p->getResult($r['key'], $r['metadata'], $r['pertinence']) ); + break; } } @@ -177,4 +99,90 @@ class SearchApi return $items; } + + private function buildUnionQuery(array $queries, $types, $parameters) + { + $query = '{unions} ORDER BY pertinence DESC'; + $unions = []; + $parameters = []; + + foreach ($queries as $q) { + $unions[] = $q->buildQuery(); + $parameters = array_merge($parameters, $q->buildParameters()); + } + + $union = implode(' UNION ', $unions); + + return [ + strtr($query, ['{unions}' => $union]), + $parameters, + ]; + } + + private function countItems($providers, $types, $parameters): int + { + [$countQuery, $parameters] = $this->buildCountQuery($providers, $types, $parameters); + $rsmCount = new ResultSetMappingBuilder($this->em); + $rsmCount->addScalarResult('count', 'count'); + $countNq = $this->em->createNativeQuery($countQuery, $rsmCount); + $countNq->setParameters($parameters); + + return (int) $countNq->getSingleScalarResult(); + } + + private function fetchRawResult($queries, $types, $parameters, $paginator): array + { + [$union, $parameters] = $this->buildUnionQuery($queries, $types, $parameters); + $rsm = new ResultSetMappingBuilder($this->em); + $rsm->addScalarResult('key', 'key', Types::STRING) + ->addScalarResult('metadata', 'metadata', Types::JSON) + ->addScalarResult('pertinence', 'pertinence', Types::FLOAT); + + $nq = $this->em->createNativeQuery($union, $rsm); + $nq->setParameters($parameters); + + return $nq->getResult(); + } + + private function findProviders(string $pattern, array $types, array $parameters): array + { + $providers = []; + + foreach ($this->providers as $provider) { + if ($provider->supportsTypes($pattern, $types, $parameters)) { + $providers[] = $provider; + } + } + + return $providers; + } + + private function findQueries($pattern, array $types, array $parameters): array + { + return array_map( + fn ($p) => $p->provideQuery($pattern, $parameters), + $this->findProviders($pattern, $types, $parameters), + ); + } + + private function prepareProviders(array $rawResults) + { + $metadatas = []; + $providers = []; + + foreach ($rawResults as $r) { + foreach ($this->providers as $k => $p) { + if ($p->supportsResult($r['key'], $r['metadata'])) { + $metadatas[$k][] = $r['metadata']; + $providers[$k] = $p; + + break; + } + } + } + + foreach ($metadatas as $k => $m) { + $providers[$k]->prepare($m); + } + } } diff --git a/src/Bundle/ChillMainBundle/Search/SearchApiInterface.php b/src/Bundle/ChillMainBundle/Search/SearchApiInterface.php index 54269c946..0c0e42ac3 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchApiInterface.php +++ b/src/Bundle/ChillMainBundle/Search/SearchApiInterface.php @@ -1,18 +1,23 @@ pattern = $pattern; $this->types = $types; diff --git a/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php b/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php index 8d656aa7c..a8a623573 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php +++ b/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php @@ -1,20 +1,42 @@ whereClauses[] = $whereClause; + array_push($this->whereClausesParams, ...$params); + + return $this; + } + + public function buildParameters(bool $countOnly = false): array + { + if (!$countOnly) { + return [ + ...$this->buildSelectParams($countOnly), + ...$this->fromClauseParams, + ...$this->whereClausesParams, + ]; + } + + return [ + ...$this->fromClauseParams, + ...$this->whereClausesParams, + ]; + } + + public function buildQuery(bool $countOnly = false): string + { + $isMultiple = count($this->whereClauses); + $where = + ($isMultiple ? '(' : '') . + implode( + ($isMultiple ? ')' : '') . ' AND ' . ($isMultiple ? '(' : ''), + $this->whereClauses + ) . + ($isMultiple ? ')' : ''); + + $select = $this->buildSelectClause($countOnly); + + return strtr('SELECT + {select} + FROM {from} + WHERE {where} + ', [ + '{select}' => $select, + '{from}' => $this->fromClause, + '{where}' => $where, + ]); + } + + public function getFromClause(): string + { + return $this->fromClause; + } + + public function getFromParams(): array + { + return $this->fromClauseParams; + } + + public function getSelectClauses(): array + { + return $this->select; + } + + public function getSelectParams(): array + { + return $this->selectParams; + } + public function resetSelectClause(): self { $this->select = []; @@ -39,20 +136,10 @@ class SearchApiQuery return $this; } - public function getSelectClauses(): array + public function setFromClause(string $fromClause, array $params = []): self { - return $this->select; - } - - public function getSelectParams(): array - { - return $this->selectParams; - } - - public function setSelectKey(string $selectKey, array $params = []): self - { - $this->selectKey = $selectKey; - $this->selectKeyParams = $params; + $this->fromClause = $fromClause; + $this->fromClauseParams = $params; return $this; } @@ -65,6 +152,14 @@ class SearchApiQuery return $this; } + public function setSelectKey(string $selectKey, array $params = []): self + { + $this->selectKey = $selectKey; + $this->selectKeyParams = $params; + + return $this; + } + public function setSelectPertinence(string $pertinence, array $params = []): self { $this->pertinence = $pertinence; @@ -73,27 +168,8 @@ class SearchApiQuery return $this; } - public function setFromClause(string $fromClause, array $params = []): self - { - $this->fromClause = $fromClause; - $this->fromClauseParams = $params; - - return $this; - } - - public function getFromClause(): string - { - return $this->fromClause; - } - - public function getFromParams(): array - { - return $this->fromClauseParams; - } - /** * Set the where clause and replace all existing ones. - * */ public function setWhereClauses(string $whereClause, array $params = []): self { @@ -103,21 +179,27 @@ class SearchApiQuery return $this; } - /** - * Add a where clause. - * - * This will add to previous where clauses with and `AND` join - * - * @param string $whereClause - * @param array $params - * @return $this - */ - public function andWhereClause(string $whereClause, array $params = []): self + private function buildSelectClause(bool $countOnly = false): string { - $this->whereClauses[] = $whereClause; - \array_push($this->whereClausesParams, ...$params); + if ($countOnly) { + return 'count(*) AS c'; + } - return $this; + $selects = $this->getSelectClauses(); + + if (null !== $this->selectKey) { + $selects[] = strtr("'{key}' AS key", ['{key}' => $this->selectKey]); + } + + if (null !== $this->jsonbMetadata) { + $selects[] = strtr('{metadata} AS metadata', ['{metadata}' => $this->jsonbMetadata]); + } + + if (null !== $this->pertinence) { + $selects[] = strtr('{pertinence} AS pertinence', ['{pertinence}' => $this->pertinence]); + } + + return implode(', ', $selects); } private function buildSelectParams(bool $count = false): array @@ -131,76 +213,15 @@ class SearchApiQuery if (null !== $this->selectKey) { $args = [...$args, ...$this->selectKeyParams]; } + if (null !== $this->jsonbMetadata) { $args = [...$args, ...$this->jsonbMetadataParams]; } + if (null !== $this->pertinence) { $args = [...$args, ...$this->pertinenceParams]; } return $args; } - - private function buildSelectClause(bool $countOnly = false): string - { - if ($countOnly) { - return 'count(*) AS c'; - } - - $selects = $this->getSelectClauses(); - - if (null !== $this->selectKey) { - $selects[] = \strtr("'{key}' AS key", [ '{key}' => $this->selectKey ]); - } - if (null !== $this->jsonbMetadata) { - $selects[] = \strtr('{metadata} AS metadata', [ '{metadata}' => $this->jsonbMetadata]); - } - if (null !== $this->pertinence) { - $selects[] = \strtr('{pertinence} AS pertinence', [ '{pertinence}' => $this->pertinence]); - } - - return \implode(', ', $selects); - } - - public function buildQuery(bool $countOnly = false): string - { - $isMultiple = count($this->whereClauses); - $where = - ($isMultiple ? '(' : ''). - \implode( - ($isMultiple ? ')' : '').' AND '.($isMultiple ? '(' : '') - , $this->whereClauses). - ($isMultiple ? ')' : '') - ; - - $select = $this->buildSelectClause($countOnly); - - - return \strtr("SELECT - {select} - FROM {from} - WHERE {where} - ", [ - '{select}' => $select, - '{from}' => $this->fromClause, - '{where}' => $where, - ]); - } - - - public function buildParameters(bool $countOnly = false): array - { - if (!$countOnly) { - return [ - ...$this->buildSelectParams($countOnly), - ...$this->fromClauseParams, - ...$this->whereClausesParams, - ]; - } else { - return [ - ...$this->fromClauseParams, - ...$this->whereClausesParams, - ]; - } - } } diff --git a/src/Bundle/ChillMainBundle/Search/SearchApiResult.php b/src/Bundle/ChillMainBundle/Search/SearchApiResult.php index c44db3339..ac47de087 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchApiResult.php +++ b/src/Bundle/ChillMainBundle/Search/SearchApiResult.php @@ -1,5 +1,12 @@ relevance = $relevance; } - public function setResult($result): self + /** + * @Serializer\Groups({"read"}) + */ + public function getRelevance(): float { - $this->result = $result; - - return $this; + return $this->relevance; } /** @@ -34,11 +42,10 @@ class SearchApiResult return $this->result; } - /** - * @Serializer\Groups({"read"}) - */ - public function getRelevance(): float + public function setResult($result): self { - return $this->relevance; + $this->result = $result; + + return $this; } } diff --git a/src/Bundle/ChillMainBundle/Search/SearchInterface.php b/src/Bundle/ChillMainBundle/Search/SearchInterface.php index 958ce9ddd..6df5cbae7 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchInterface.php +++ b/src/Bundle/ChillMainBundle/Search/SearchInterface.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\Search; @@ -25,76 +13,75 @@ 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é - * */ interface SearchInterface { - const SEARCH_PREVIEW_OPTION = '_search_preview'; + /** + * Supplementary parameters to the query string. + */ + public const REQUEST_QUERY_KEY_ADD_PARAMETERS = 'add_q'; /** - * Request parameters contained inside the `add_q` parameters + * Request parameters contained inside the `add_q` parameters. */ - const REQUEST_QUERY_PARAMETERS = '_search_parameters'; + public const REQUEST_QUERY_PARAMETERS = '_search_parameters'; + + public const SEARCH_PREVIEW_OPTION = '_search_preview'; /** - * Supplementary parameters to the query string + * the order in which the results will appears in the global view. + * + * (this may be eventually defined in config.yml) + * + * @return int */ - const REQUEST_QUERY_KEY_ADD_PARAMETERS = 'add_q'; + public function getOrder(); - /** - * 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'); + /** + * 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(); - /** - * 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(); - - /** - * indicate if the implementation supports the given domain - * - * @return boolean - */ - public function supports($domain, $format); + /** + * 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 3d02579bb..ccf013f2a 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchProvider.php +++ b/src/Bundle/ChillMainBundle/Search/SearchProvider.php @@ -1,15 +1,21 @@ get('chill_main.search_provider') + * $container->get('chill_main.search_provider'). * * the syntax for search string is : * - domain, which begin with `@`. Example: `@person`. Restrict the search to some @@ -19,22 +25,53 @@ use Chill\MainBundle\Search\HasAdvancedSearchFormInterface; * - 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 @@ -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 + * 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 - * @return string + * * @throws ParsingException + * + * @return string */ private function extractDomain(&$subject) { @@ -115,12 +260,12 @@ 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 = []; $matches = []; preg_match_all('/([a-z\-]+):(([^"][\S\-]+)|"[^"]*")/', $subject, $matches); @@ -128,8 +273,8 @@ class SearchProvider //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; @@ -138,128 +283,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. * @@ -268,191 +291,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 @@ -501,5 +527,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/Search/Utils/ExtractDateFromPattern.php b/src/Bundle/ChillMainBundle/Search/Utils/ExtractDateFromPattern.php index 84540a708..79a61a062 100644 --- a/src/Bundle/ChillMainBundle/Search/Utils/ExtractDateFromPattern.php +++ b/src/Bundle/ChillMainBundle/Search/Utils/ExtractDateFromPattern.php @@ -1,15 +1,25 @@ ""])); + $filteredSubject = trim(strtr($filteredSubject, [$match => ''])); } } } diff --git a/src/Bundle/ChillMainBundle/Search/Utils/ExtractPhonenumberFromPattern.php b/src/Bundle/ChillMainBundle/Search/Utils/ExtractPhonenumberFromPattern.php index b4601a5f7..9f88ca588 100644 --- a/src/Bundle/ChillMainBundle/Search/Utils/ExtractPhonenumberFromPattern.php +++ b/src/Bundle/ChillMainBundle/Search/Utils/ExtractPhonenumberFromPattern.php @@ -1,28 +1,47 @@ $char) { + foreach (str_split(trim($matches[0])) as $key => $char) { switch ($char) { case '0': $length++; - if ($key === 0) { $phonenumber[] = '+32'; } - else { $phonenumber[] = $char; } + + if (0 === $key) { + $phonenumber[] = '+32'; + } else { + $phonenumber[] = $char; + } + break; + case '1': case '2': case '3': @@ -34,18 +53,21 @@ class ExtractPhonenumberFromPattern case '9': $length++; $phonenumber[] = $char; + break; + case ' ': break; + default: - throw new \LogicException("should not match not alnum character"); + throw new LogicException('should not match not alnum character'); } } - if ($length > 5) { - $filtered = \trim(\strtr($subject, [$matches[0] => ''])); + if (5 < $length) { + $filtered = trim(strtr($subject, [$matches[0] => ''])); - return new SearchExtractionResult($filtered, [\implode('', $phonenumber)] ); + return new SearchExtractionResult($filtered, [implode('', $phonenumber)]); } } diff --git a/src/Bundle/ChillMainBundle/Search/Utils/SearchExtractionResult.php b/src/Bundle/ChillMainBundle/Search/Utils/SearchExtractionResult.php index e9ca2a691..6caf12a54 100644 --- a/src/Bundle/ChillMainBundle/Search/Utils/SearchExtractionResult.php +++ b/src/Bundle/ChillMainBundle/Search/Utils/SearchExtractionResult.php @@ -1,10 +1,18 @@ found = $found; } + public function getFilteredSubject(): string + { + return $this->filteredSubject; + } + public function getFound(): array { return $this->found; @@ -22,9 +35,4 @@ class SearchExtractionResult { return [] !== $this->found; } - - public function getFilteredSubject(): string - { - return $this->filteredSubject; - } } diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php index fec4da627..ad58b058a 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php @@ -1,12 +1,20 @@ 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) diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php b/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php index b90556b69..ab8506891 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php @@ -1,29 +1,29 @@ userCanReachCenter($user, $c)) { - return true; - } - } - return false; - } - - if ($center instanceof Center) { - foreach ($user->getGroupCenters() as $groupCenter) { - if ($center->getId() === $groupCenter->getCenter()->getId()) { - return true; - } - } - - return false; - } - - throw new \UnexpectedValueException( - sprintf( - 'The entity given is not an instance of %s, %s given', - Center::class, - get_class($center) - ) - ); - } - - /** - * 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 mixed $entity the entity may also implement HasScopeInterface - * @param string|Role $attribute - * @return boolean true if the user has access - */ - public function userHasAccess(User $user, $entity, $attribute) - { - $center = $this->centerResolverDispatcher->resolveCenter($entity); - - if (is_iterable($center)) { - foreach ($center as $c) { - if ($this->userHasAccessForCenter($user, $c, $entity, $attribute)) { - return true; - } - } - - return false; - } elseif ($center instanceof Center) { - return $this->userHasAccessForCenter($user, $center, $entity, $attribute); - } elseif (NULL === $center) { - return false; - } else { - throw new \UnexpectedValueException("could not resolver a center"); - } - } - - private function userHasAccessForCenter(User $user, Center $center, $entity, $attribute): bool - { - if (!$this->userCanReachCenter($user, $center)) { - $this->logger->debug("user cannot reach center of entity", [ - 'center_name' => $center->getName(), - 'user' => $user->getUsername() - ]); - return false; - } - - foreach ($user->getGroupCenters() as $groupCenter){ - //filter on center - if ($groupCenter->getCenter() === $center) { - $permissionGroup = $groupCenter->getPermissionsGroup(); - //iterate on roleScopes - foreach($permissionGroup->getRoleScopes() as $roleScope) { - //check that the role allow to reach the required role - if ($this->isRoleReached($attribute, $roleScope->getRole())) { - //if yes, we have a right on something... - // perform check on scope if necessary - if ($this->scopeResolverDispatcher->isConcerned($entity)) { - $scope = $this->scopeResolverDispatcher->resolveScope($entity); - - if (NULL === $scope) { - return true; - } - - if (is_iterable($scope)) { - foreach ($scope as $s) { - if ($s === $roleScope->getScope()) { - return true; - } - } - } else { - if ($scope === $roleScope->getScope()) { - return true; - } - } - } else { - return true; - } - } - } - } - } - - $this->logger->debug("user can reach center entity, but not role", [ - 'username' => $user->getUsername(), - 'center' => $center->getName() - ]); - - return false; - } - - /** - * Get reachable Centers for the given user, role, - * and optionally Scope - * - * @return Center[]|array - */ - public function getReachableCenters(UserInterface $user, string $role, ?Scope $scope = null): array - { - if ($role instanceof Role) { - $role = $role->getRole(); - } - $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, $roleScope->getRole())) { - if ($scope === null) { - $centers[] = $groupCenter->getCenter(); - break 1; - } - - if ($scope->getId() == $roleScope->getScope()->getId()){ - $centers[] = $groupCenter->getCenter(); - break 1; - } - } - } - - } - - return $centers; - } - - /** - * Filter an array of centers, return only center which are reachable + * Filter an array of centers, return only center which are reachable. * * @param User $user The user * @param array $centers a list of centers which are going to be filtered - * @param string|Center $role + * @param Center|string $role */ public function filterReachableCenters(User $user, array $centers, $role): array { @@ -238,27 +81,75 @@ class AuthorizationHelper implements AuthorizationHelperInterface } /** - * Return all reachable scope for a given user, center and role + * @deprecated use UserACLAwareRepositoryInterface::findUsersByReachedACL instead * - * @deprecated Use getReachableCircles + * @param array|Center|Center[] $center + * @param array|Scope|Scope[]|null $scope * - * @param Center|Center[] $center - * @return Scope[]|array + * @return User[] */ - public function getReachableScopes(UserInterface $user, string $role, $center): array + public function findUsersReaching(string $role, $center, $scope = null, bool $onlyEnabled = true): array + { + return $this->userACLAwareRepository + ->findUsersByReachedACL($role, $center, $scope, $onlyEnabled); + } + + /** + * Return all the role which give access to the given role. Only the role + * which are registered into Chill are taken into account. + * + * @return string[] the role which give access to the given $role + */ + public function getParentRoles(string $role): array + { + trigger_deprecation('Chill\MainBundle', '2.0', 'use ParentRoleHelper::getParentRoles instead'); + + return $this->parentRoleHelper->getParentRoles($role); + } + + /** + * Get reachable Centers for the given user, role, + * and optionally Scope. + * + * @return array|Center[] + */ + public function getReachableCenters(UserInterface $user, string $role, ?Scope $scope = null): array { if ($role instanceof Role) { $role = $role->getRole(); } + $centers = []; - return $this->getReachableCircles($user, $role, $center); + 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, $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 all reachable circle for a given user, center and role. * - * @param string|Role $role + * @param Role|string $role * @param Center|Center[] $center + * * @return Scope[] */ public function getReachableCircles(UserInterface $user, $role, $center) @@ -267,7 +158,7 @@ class AuthorizationHelper implements AuthorizationHelperInterface if (is_iterable($center)) { foreach ($center as $c) { - $scopes = \array_merge($scopes, $this->getReachableCircles($user, $role, $c)); + $scopes = array_merge($scopes, $this->getReachableCircles($user, $role, $c)); } return $scopes; @@ -277,12 +168,12 @@ class AuthorizationHelper implements AuthorizationHelperInterface $role = $role->getRole(); } - foreach ($user->getGroupCenters() as $groupCenter){ + 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) { + foreach ($permissionGroup->getRoleScopes() as $roleScope) { //check that the role is in the reachable roles if ($this->isRoleReached($role, $roleScope->getRole())) { $scopes[] = $roleScope->getScope(); @@ -295,41 +186,160 @@ class AuthorizationHelper implements AuthorizationHelperInterface } /** + * Return all reachable scope for a given user, center and role. * - * @deprecated use UserACLAwareRepositoryInterface::findUsersByReachedACL instead - * @param Center|Center[]|array $center - * @param Scope|Scope[]|array|null $scope - * @param bool $onlyActive true if get only active users - * @return User[] + * @deprecated Use getReachableCircles + * + * @param Center|Center[] $center + * + * @return array|Scope[] */ - public function findUsersReaching(string $role, $center, $scope = null, bool $onlyEnabled = true): array + public function getReachableScopes(UserInterface $user, string $role, $center): array { - return $this->userACLAwareRepository - ->findUsersByReachedACL($role, $center, $scope, $onlyEnabled); + if ($role instanceof Role) { + $role = $role->getRole(); + } + + return $this->getReachableCircles($user, $role, $center); } /** - * Test if a parent role may give access to a given child role + * Determines if a user is active on this center. + * + * @param Center|Center[] $center May be an array of center + */ + public function userCanReachCenter(User $user, $center): bool + { + if ($center instanceof Traversable) { + foreach ($center as $c) { + if ($c->userCanReachCenter($user, $c)) { + return true; + } + } + + return false; + } + + if ($center instanceof Center) { + foreach ($user->getGroupCenters() as $groupCenter) { + if ($center->getId() === $groupCenter->getCenter()->getId()) { + return true; + } + } + + return false; + } + + throw new UnexpectedValueException( + sprintf( + 'The entity given is not an instance of %s, %s given', + Center::class, + get_class($center) + ) + ); + } + + /** + * 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 mixed $entity the entity may also implement HasScopeInterface + * @param Role|string $attribute + * + * @return bool true if the user has access + */ + public function userHasAccess(User $user, $entity, $attribute) + { + $center = $this->centerResolverDispatcher->resolveCenter($entity); + + if (is_iterable($center)) { + foreach ($center as $c) { + if ($this->userHasAccessForCenter($user, $c, $entity, $attribute)) { + return true; + } + } + + return false; + } + + if ($center instanceof Center) { + return $this->userHasAccessForCenter($user, $center, $entity, $attribute); + } + + if (null === $center) { + return false; + } + + throw new UnexpectedValueException('could not resolver a center'); + } + + /** + * Test if a parent role may give access to a given child role. * * @param string $childRole The role we want to test if he is reachable * @param string $parentRole The role which should give access to $childRole - * @return boolean true if the child role is granted by parent role + * + * @return bool true if the child role is granted by parent role */ private function isRoleReached(string $childRole, string $parentRole) { return $this->parentRoleHelper->isRoleReached($childRole, $parentRole); } - /** - * Return all the role which give access to the given role. Only the role - * which are registered into Chill are taken into account. - * - * @param string $role - * @return string[] the role which give access to the given $role - */ - public function getParentRoles(string $role): array + private function userHasAccessForCenter(User $user, Center $center, $entity, $attribute): bool { - trigger_deprecation('Chill\MainBundle', '2.0', 'use ParentRoleHelper::getParentRoles instead'); - return $this->parentRoleHelper->getParentRoles($role); + if (!$this->userCanReachCenter($user, $center)) { + $this->logger->debug('user cannot reach center of entity', [ + 'center_name' => $center->getName(), + 'user' => $user->getUsername(), + ]); + + return false; + } + + foreach ($user->getGroupCenters() as $groupCenter) { + //filter on center + if ($groupCenter->getCenter() === $center) { + $permissionGroup = $groupCenter->getPermissionsGroup(); + //iterate on roleScopes + foreach ($permissionGroup->getRoleScopes() as $roleScope) { + //check that the role allow to reach the required role + if ($this->isRoleReached($attribute, $roleScope->getRole())) { + //if yes, we have a right on something... + // perform check on scope if necessary + if ($this->scopeResolverDispatcher->isConcerned($entity)) { + $scope = $this->scopeResolverDispatcher->resolveScope($entity); + + if (null === $scope) { + return true; + } + + if (is_iterable($scope)) { + foreach ($scope as $s) { + if ($roleScope->getScope() === $s) { + return true; + } + } + } else { + if ($roleScope->getScope() === $scope) { + return true; + } + } + } else { + return true; + } + } + } + } + } + + $this->logger->debug('user can reach center entity, but not role', [ + 'username' => $user->getUsername(), + 'center' => $center->getName(), + ]); + + return false; } } diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelperInterface.php b/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelperInterface.php index 2ad30f8f3..9304dab77 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelperInterface.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelperInterface.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\Security\Authorization; /** * Provides methods for compiling voter and build admin role fields. - * - * @author Julien Fastré */ interface ChillVoterInterface { - } diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelper.php b/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelper.php index ef1d319ac..95f070b3b 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelper.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelper.php @@ -1,26 +1,31 @@ authorizationHelper = $authorizationHelper; @@ -30,13 +35,13 @@ final class DefaultVoterHelper implements VoterHelperInterface public function supports($attribute, $subject): bool { - foreach ($this->configuration as list($attributes, $subj)) { - if ($subj === null) { - if ($subject === null && \in_array($attribute, $attributes)) { + foreach ($this->configuration as [$attributes, $subj]) { + if (null === $subj) { + if (null === $subject && in_array($attribute, $attributes, true)) { return true; } } elseif ($subject instanceof $subj) { - return \in_array($attribute, $attributes); + return in_array($attribute, $attributes, true); } } @@ -49,8 +54,8 @@ final class DefaultVoterHelper implements VoterHelperInterface return false; } - if (NULL === $subject) { - return 0 < count($this->authorizationHelper->getReachableCenters($token->getUser(), $attribute, null)); + if (null === $subject) { + return [] !== $this->authorizationHelper->getReachableCenters($token->getUser(), $attribute, null); } return $this->authorizationHelper->userHasAccess( diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperFactory.php b/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperFactory.php index 9349eaed2..f95e93c2b 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperFactory.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperFactory.php @@ -1,17 +1,27 @@ authorizationHelper = $authorizationHelper; $this->centerResolverDispatcher = $centerResolverDispatcher; diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperGenerator.php b/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperGenerator.php index c8300e45a..64d40ad15 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperGenerator.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/DefaultVoterHelperGenerator.php @@ -1,18 +1,29 @@ authorizationHelper = $authorizationHelper; $this->centerResolverDispatcher = $centerResolverDispatcher; @@ -20,9 +31,9 @@ final class DefaultVoterHelperGenerator implements VoterGeneratorInterface public function addCheckFor(?string $subject, array $attributes): self { - $this->configuration[] = [$attributes, $subject]; + $this->configuration[] = [$attributes, $subject]; - return $this; + return $this; } public function build(): VoterHelperInterface diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/VoterGeneratorInterface.php b/src/Bundle/ChillMainBundle/Security/Authorization/VoterGeneratorInterface.php index 70e517536..1dec1d053 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/VoterGeneratorInterface.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/VoterGeneratorInterface.php @@ -1,5 +1,12 @@ roleHierarchy = $roleHierarchy; - $this->hierarchy = $parameterBag->get('security.role_hierarchy.roles'); + $this->hierarchy = $parameterBag->get('security.role_hierarchy.roles'); } /** @@ -35,14 +43,13 @@ class ParentRoleHelper * * The array contains always the current $role (which give access to himself) * - * @param string $role * @return string[] the role which give access to the given $role */ public function getParentRoles(string $role): array { $parentRoles = [$role]; // transform the roles from role hierarchy from string to Role - $roles = \array_keys($this->hierarchy); + $roles = array_keys($this->hierarchy); foreach ($roles as $r) { $childRoles = $this->roleHierarchy->getReachableRoleNames([$r]); @@ -56,10 +63,11 @@ class ParentRoleHelper } /** - * Test if a parent role may give access to a given child role + * Test if a parent role may give access to a given child role. * * @param string $childRole The role we want to test if he is reachable * @param string $parentRole The role which should give access to $childRole + * * @return bool true if the child role is granted by parent role */ public function isRoleReached($childRole, $parentRole): bool @@ -69,5 +77,4 @@ class ParentRoleHelper return in_array($childRole, $reachableRoles); } - } 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 b6ba03621..01f091b73 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; - } return false; diff --git a/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php b/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php index 969f774a6..4baa682c7 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php @@ -1,59 +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 . - */ -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 +49,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..9a60c1da0 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php @@ -1,103 +1,99 @@ + +/** + * 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..5a7d73eae 100644 --- a/src/Bundle/ChillMainBundle/Security/ProvideRoleHierarchyInterface.php +++ b/src/Bundle/ChillMainBundle/Security/ProvideRoleHierarchyInterface.php @@ -1,42 +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. */ + +declare(strict_types=1); + 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' ] ]` + * + * @return array> Where keys are the hierarchy, and values an array of roles: `[ 'title' => [ 'CHILL_FOO_SEE', 'CHILL_FOO_UPDATE' ] ]` */ - public function getRolesWithHierarchy(); + public function getRolesWithHierarchy(): array; } diff --git a/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php b/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php index 08a48181a..b6680946c 100644 --- a/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php +++ b/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php @@ -1,53 +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. */ +declare(strict_types=1); + 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(); - + public function getRoles(): array; + /** - * return roles which doesn't need - * + * Return roles which doesn't need. + * * @return string[] array of roles without scopes */ - public function getRolesWithoutScope(); + public function getRolesWithoutScope(): array; } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php index e6cdd8b0c..e2fafbf7f 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php @@ -1,15 +1,17 @@ resolvers = $resolvers; } - /** - * @param object $entity - * @return null|Center|Center[] - */ public function resolveCenter($entity, ?array $options = []) { trigger_deprecation( @@ -37,7 +35,7 @@ final class CenterResolverDispatcher ' ); - foreach($this->resolvers as $resolver) { + foreach ($this->resolvers as $resolver) { if ($resolver->supports($entity, $options)) { return $resolver->resolveCenter($entity, $options); } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcherInterface.php b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcherInterface.php new file mode 100644 index 000000000..95bd03e20 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcherInterface.php @@ -0,0 +1,27 @@ +resolvers as $resolver) { + foreach ($this->resolvers as $resolver) { if ($resolver->supports($entity, $options)) { $resolved = $resolver->resolveCenter($entity, $options); + if (null === $resolved) { return []; - } elseif ($resolved instanceof Center) { + } + + if ($resolved instanceof Center) { return [$resolved]; - } elseif (\is_array($resolved)) { + } + + if (is_array($resolved)) { return $resolved; } - throw new \UnexpectedValueException(sprintf("the return type of a %s should be an instance of %s, an array or null. Resolver is %s", - CenterResolverInterface::class, Center::class, get_class($resolver))); + throw new UnexpectedValueException(sprintf( + 'the return type of a %s should be an instance of %s, an array or null. Resolver is %s', + CenterResolverInterface::class, + Center::class, + get_class($resolver) + )); } } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManagerInterface.php b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManagerInterface.php index 1ca145b99..34de9ecb6 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManagerInterface.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManagerInterface.php @@ -1,5 +1,12 @@ getCenter(); - } elseif ($entity instanceof HasCentersInterface) { - return $entity->getCenters(); - } else { - throw new \UnexpectedValueException("should be an instanceof"); } + + if ($entity instanceof HasCentersInterface) { + return $entity->getCenters(); + } + + throw new UnexpectedValueException('should be an instanceof'); } - public static function getDefaultPriority(): int + public function supports($entity, ?array $options = []): bool { - return -256; + return $entity instanceof HasCenterInterface || $entity instanceof HasCentersInterface; } } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/DefaultScopeResolver.php b/src/Bundle/ChillMainBundle/Security/Resolver/DefaultScopeResolver.php index caf052764..e4b9021f4 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/DefaultScopeResolver.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/DefaultScopeResolver.php @@ -1,33 +1,23 @@ getScope(); - } elseif ($entity instanceof HasScopesInterface) { - return $entity->getScopes(); - } else { - throw new \UnexpectedValueException("should be an instanceof %s or %s", - HasScopesInterface::class, HasScopeInterface::class); - } + return -256; } public function isConcerned($entity, ?array $options = []): bool @@ -35,8 +25,28 @@ class DefaultScopeResolver implements ScopeResolverInterface return $entity instanceof HasScopeInterface || $entity instanceof HasScopesInterface; } - public static function getDefaultPriority(): int + /** + * @param HasScopeInterface|HasScopesInterface $entity + */ + public function resolveScope($entity, ?array $options = []) { - return -256; + if ($entity instanceof HasScopeInterface) { + return $entity->getScope(); + } + + if ($entity instanceof HasScopesInterface) { + return $entity->getScopes(); + } + + throw new UnexpectedValueException( + 'should be an instanceof %s or %s', + HasScopesInterface::class, + HasScopeInterface::class + ); + } + + public function supports($entity, ?array $options = []): bool + { + return $entity instanceof HasScopeInterface || $entity instanceof HasScopesInterface; } } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php b/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php index 9555d2a06..6bd4cddc2 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/ResolverTwigExtension.php @@ -1,5 +1,12 @@ scopeResolverDispatcher->isConcerned($entity, $options); + } + /** * @param mixed $entity - * @param array|null $options + * * @return Center|Center[]|null */ public function resolveCenter($entity, ?array $options = []) @@ -36,17 +54,7 @@ final class ResolverTwigExtension extends \Twig\Extension\AbstractExtension /** * @param $entity - * @param array|null $options - * @return bool - */ - public function isScopeConcerned($entity, ?array $options = []) - { - return $this->scopeResolverDispatcher->isConcerned($entity, $options); - } - - /** - * @param $entity - * @param array|null $options + * * @return array|\Chill\MainBundle\Entity\Scope|\Chill\MainBundle\Entity\Scope[] */ public function resolveScope($entity, ?array $options = []) diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php b/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php index cc3f11560..96321de6a 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverDispatcher.php @@ -1,5 +1,12 @@ resolvers = $resolvers; } + public function isConcerned($entity, ?array $options = []): bool + { + foreach ($this->resolvers as $resolver) { + if ($resolver->supports($entity, $options)) { + return $resolver->isConcerned($entity, $options); + } + } + + return false; + } + /** * @param $entity - * @return Scope|Scope[]|iterable + * + * @return iterable|Scope|Scope[] */ public function resolveScope($entity, ?array $options = []) { @@ -30,15 +49,4 @@ final class ScopeResolverDispatcher return null; } - - public function isConcerned($entity, ?array $options = []): bool - { - foreach ($this->resolvers as $resolver) { - if ($resolver->supports($entity, $options)) { - return $resolver->isConcerned($entity, $options); - } - } - - return false; - } } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverInterface.php b/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverInterface.php index 04e949a59..1e4319ad9 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverInterface.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/ScopeResolverInterface.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\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() + + public function getRoles(): array { - $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() + + public function getRolesWithoutScopes(): array { - $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 b2e09775b..db9e4c2de 100644 --- a/src/Bundle/ChillMainBundle/Security/UserProvider/UserProvider.php +++ b/src/Bundle/ChillMainBundle/Security/UserProvider/UserProvider.php @@ -1,16 +1,23 @@ 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 (NoResultException $e) { @@ -46,12 +54,12 @@ class UserProvider implements UserProviderInterface 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())); } @@ -60,6 +68,6 @@ class UserProvider implements UserProviderInterface 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/AddressNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php index cd37ea989..f9a73cd07 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php @@ -1,5 +1,12 @@ $address->getId(), - 'text' => $address->isNoAddress() ? '' : $address->getStreetNumber().', '.$address->getStreet(), + 'text' => $address->isNoAddress() ? '' : $address->getStreetNumber() . ', ' . $address->getStreet(), 'street' => $address->getStreet(), 'streetNumber' => $address->getStreetNumber(), 'postcode' => [ @@ -49,14 +56,10 @@ class AddressNormalizer implements NormalizerAwareInterface, NormalizerInterface [AbstractNormalizer::GROUPS => ['read']] ), ]; - - return $data; } - public function supportsNormalization($data, string $format = null) + public function supportsNormalization($data, ?string $format = null) { return $data instanceof Address; } - - } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php index aeb437336..c5211e5a2 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php @@ -1,69 +1,42 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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 Chill\MainBundle\Entity\Center; use Chill\MainBundle\Repository\CenterRepository; -use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\UnexpectedValueException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use function array_key_exists; -/** - * - * - */ class CenterNormalizer implements NormalizerInterface, DenormalizerInterface { private CenterRepository $repository; - public function __construct(CenterRepository $repository) { $this->repository = $repository; } - public function normalize($center, string $format = null, array $context = array()) + public function denormalize($data, string $type, ?string $format = null, array $context = []) { - /** @var Center $center */ - return [ - 'id' => $center->getId(), - 'type' => 'center', - 'name' => $center->getName() - ]; - } - - public function supportsNormalization($data, string $format = null): bool - { - return $data instanceof Center && $format === 'json'; - } - - public function denormalize($data, string $type, string $format = null, array $context = []) - { - if (FALSE === \array_key_exists('type', $data)) { + if (false === array_key_exists('type', $data)) { throw new InvalidArgumentException('missing "type" key in data'); } + if ('center' !== $data['type']) { throw new InvalidArgumentException('type should be equal to "center"'); } - if (FALSE === \array_key_exists('id', $data)) { + + if (false === array_key_exists('id', $data)) { throw new InvalidArgumentException('missing "id" key in data'); } @@ -76,8 +49,23 @@ class CenterNormalizer implements NormalizerInterface, DenormalizerInterface return $center; } - public function supportsDenormalization($data, string $type, string $format = null) + public function normalize($center, ?string $format = null, array $context = []) { - return $type === Center::class; + /** @var Center $center */ + return [ + 'id' => $center->getId(), + 'type' => 'center', + 'name' => $center->getName(), + ]; + } + + public function supportsDenormalization($data, string $type, ?string $format = null) + { + return Center::class === $type; + } + + public function supportsNormalization($data, ?string $format = null): bool + { + return $data instanceof Center && 'json' === $format; } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php index a763a5675..ce2a36f09 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php @@ -1,11 +1,18 @@ getPaginator(); @@ -31,7 +38,7 @@ class CollectionNormalizer implements NormalizerInterface, NormalizerAwareInterf ]; } - public function supportsNormalization($data, string $format = null): bool + 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 288a6865d..4813203d7 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php @@ -1,115 +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\MainBundle\Serializer\Normalizer; +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; +use IntlDateFormatter; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; -use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use function is_array; class DateNormalizer implements ContextAwareNormalizerInterface, DenormalizerInterface { - private RequestStack $requestStack; private ParameterBagInterface $parameterBag; + private RequestStack $requestStack; + public function __construct(RequestStack $requestStack, ParameterBagInterface $parameterBag) { $this->requestStack = $requestStack; $this->parameterBag = $parameterBag; } - public function normalize($date, string $format = null, array $context = array()) + public function denormalize($data, string $type, ?string $format = null, array $context = []) { - /** @var \DateTimeInterface $date */ - switch($format) { + switch ($type) { + case DateTime::class: + return DateTime::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']); + + case DateTimeInterface::class: + case DateTimeImmutable::class: + default: + return DateTimeImmutable::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']); + } + } + + public function normalize($date, ?string $format = null, array $context = []) + { + /** @var DateTimeInterface $date */ + switch ($format) { case 'json': return [ - 'datetime' => $date->format(\DateTimeInterface::ISO8601) + 'datetime' => $date->format(DateTimeInterface::ISO8601), ]; - case 'docgen': + case 'docgen': if (null === $date) { return [ - 'long' => '', 'short' => '' + 'long' => '', 'short' => '', ]; } - $hasTime = $date->format('His') !== "000000"; + $hasTime = $date->format('His') !== '000000'; $request = $this->requestStack->getCurrentRequest(); $locale = null !== $request ? $request->getLocale() : $this->parameterBag->get('kernel.default_locale'); - $formatterLong = \IntlDateFormatter::create( + $formatterLong = IntlDateFormatter::create( $locale, - \IntlDateFormatter::LONG, - $hasTime ? \IntlDateFormatter::SHORT: \IntlDateFormatter::NONE + IntlDateFormatter::LONG, + $hasTime ? IntlDateFormatter::SHORT : IntlDateFormatter::NONE ); - $formatterShort = \IntlDateFormatter::create( + $formatterShort = IntlDateFormatter::create( $locale, - \IntlDateFormatter::SHORT, - $hasTime ? \IntlDateFormatter::SHORT: \IntlDateFormatter::NONE + IntlDateFormatter::SHORT, + $hasTime ? IntlDateFormatter::SHORT : IntlDateFormatter::NONE ); return [ 'short' => $formatterShort->format($date), - 'long' => $formatterLong->format($date) + 'long' => $formatterLong->format($date), ]; } } - public function supportsNormalization($data, string $format = null, array $context = []): bool + public function supportsDenormalization($data, string $type, ?string $format = null): bool { - if ($format === 'json') { - return $data instanceof \DateTimeInterface; - } elseif ($format === 'docgen') { - return $data instanceof \DateTimeInterface || ( - $data === null + return DateTimeInterface::class === $type + || DateTime::class === $type + || DateTimeImmutable::class === $type + || (is_array($data) && array_key_exists('datetime', $data)); + } + + public function supportsNormalization($data, ?string $format = null, array $context = []): bool + { + if ('json' === $format) { + return $data instanceof DateTimeInterface; + } + + if ('docgen' === $format) { + return $data instanceof DateTimeInterface || ( + null === $data && \array_key_exists('docgen:expects', $context) && ( - $context['docgen:expects'] === \DateTimeInterface::class - || $context['docgen:expects'] === \DateTime::class - || $context['docgen:expects'] === \DateTimeImmutable::class + DateTimeInterface::class === $context['docgen:expects'] + || DateTime::class === $context['docgen:expects'] + || DateTimeImmutable::class === $context['docgen:expects'] ) ); } return false; } - - public function denormalize($data, string $type, string $format = null, array $context = []) - { - switch ($type) { - case \DateTime::class: - return \DateTime::createFromFormat(\DateTimeInterface::ISO8601, $data['datetime']); - case \DateTimeInterface::class: - case \DateTimeImmutable::class: - default: - return \DateTimeImmutable::createFromFormat(\DateTimeInterface::ISO8601, $data['datetime']); - } - } - - public function supportsDenormalization($data, string $type, string $format = null): bool - { - return $type === \DateTimeInterface::class || - $type === \DateTime::class || - $type === \DateTimeImmutable::class || - (\is_array($data) && array_key_exists('datetime', $data)); - } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DiscriminatedObjectDenormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DiscriminatedObjectDenormalizer.php index 25b2c5017..018f99b46 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DiscriminatedObjectDenormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DiscriminatedObjectDenormalizer.php @@ -1,62 +1,64 @@ denormalizer->supportsDenormalization($data, $localType, $format)) { try { - return $this->denormalizer->denormalize($data, $localType, $format, $context); } catch (RuntimeException $e) { + return $this->denormalizer->denormalize($data, $localType, $format, $context); + } catch (RuntimeException $e) { $lastException = $e; } } } - throw new RuntimeException(sprintf("Could not find any denormalizer for those ". - "ALLOWED_TYPES: %s", \implode(", ", $context[self::ALLOWED_TYPES]))); + throw new RuntimeException(sprintf('Could not find any denormalizer for those ' . + 'ALLOWED_TYPES: %s', implode(', ', $context[self::ALLOWED_TYPES]))); } - /** - * {@inheritDoc} - */ - public function supportsDenormalization($data, string $type, string $format = null, array $context = []) + public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []) { if (self::TYPE !== $type) { return false; } if (0 === count($context[self::ALLOWED_TYPES] ?? [])) { - throw new \LogicException("The context should contains a list of - allowed types"); + throw new LogicException('The context should contains a list of + allowed types'); } foreach ($context[self::ALLOWED_TYPES] as $localType) { @@ -67,5 +69,4 @@ class DiscriminatedObjectDenormalizer implements ContextAwareDenormalizerInterfa return false; } - } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DoctrineExistingEntityNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DoctrineExistingEntityNormalizer.php index cb2635802..f33241cc7 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DoctrineExistingEntityNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DoctrineExistingEntityNormalizer.php @@ -1,14 +1,21 @@ em = $em; $this->serializerMetadataFactory = $serializerMetadataFactory; } - public function denormalize($data, string $type, string $format = null, array $context = []) + public function denormalize($data, string $type, ?string $format = null, array $context = []) { - if (\array_key_exists(AbstractNormalizer::OBJECT_TO_POPULATE, $context)) { + if (array_key_exists(AbstractNormalizer::OBJECT_TO_POPULATE, $context)) { return $context[AbstractNormalizer::OBJECT_TO_POPULATE]; } @@ -33,23 +39,22 @@ class DoctrineExistingEntityNormalizer implements DenormalizerInterface ->find($data['id']); } - public function supportsDenormalization($data, string $type, string $format = null) + public function supportsDenormalization($data, string $type, ?string $format = null) { - if (FALSE === \is_array($data)) { + if (false === is_array($data)) { return false; } - if (FALSE === \array_key_exists('id', $data)) { + if (false === array_key_exists('id', $data)) { return false; - } + } - if (FALSE === $this->em->getClassMetadata($type) instanceof ClassMetadata) { - return false; + if (false === $this->em->getClassMetadata($type) instanceof ClassMetadata) { + return false; } // does have serializer metadata, and class discriminator ? if ($this->serializerMetadataFactory->hasMetadataFor($type)) { - $classDiscriminator = $this->serializerMetadataFactory ->getMetadataFor($type)->getClassDiscriminatorMapping(); @@ -58,14 +63,14 @@ class DoctrineExistingEntityNormalizer implements DenormalizerInterface // check that only 2 keys // that the second key is property - // and that the type match the class for given type property + // and that the type match the class for given type property return count($data) === 2 - && \array_key_exists($typeProperty, $data) - && $type === $classDiscriminator->getClassForType($data[$typeProperty]); + && array_key_exists($typeProperty, $data) + && $classDiscriminator->getClassForType($data[$typeProperty]) === $type; } } // we do not have any class discriminator. Check that the id is the only one key return count($data) === 1; } -} +} diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/PointNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/PointNormalizer.php index 210e85fb7..e4c8a1737 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/PointNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/PointNormalizer.php @@ -1,34 +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\Serializer\Normalizer; @@ -28,6 +18,7 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class UserNormalizer implements NormalizerInterface, NormalizerAwareInterface { use NormalizerAwareTrait; + private UserRender $userRender; public function __construct(UserRender $userRender) @@ -35,7 +26,7 @@ class UserNormalizer implements NormalizerInterface, NormalizerAwareInterface $this->userRender = $userRender; } - public function normalize($user, string $format = null, array $context = array()) + public function normalize($user, ?string $format = null, array $context = []) { /** @var User $user */ return [ @@ -50,8 +41,8 @@ class UserNormalizer implements NormalizerInterface, NormalizerAwareInterface ]; } - public function supportsNormalization($data, string $format = null): bool + public function supportsNormalization($data, ?string $format = null): bool { - return $format === 'json' && $data instanceof User; + return 'json' === $format && $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 29d189155..c0da5c6eb 100644 --- a/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php +++ b/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php @@ -1,29 +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 Parsedown; /** - * Render markdown + * 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 Parsedown; +use Twig\Extension\AbstractExtension; + +use Twig\TwigFilter; + +/** + * Render markdown. */ final class ChillMarkdownRenderExtension extends AbstractExtension { @@ -42,8 +34,8 @@ final class ChillMarkdownRenderExtension extends AbstractExtension { return [ new TwigFilter('chill_markdown_to_html', [$this, 'renderMarkdownToHtml'], [ - 'is_safe' => [ 'html' ] - ]) + 'is_safe' => ['html'], + ]), ]; } diff --git a/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php b/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php index b6b267386..9b9e5815a 100644 --- a/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php @@ -1,32 +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\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 +22,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 +76,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 c9b06a883..1ddd272c9 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/AddressRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php index 788fd43c1..2e3a80219 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php @@ -1,14 +1,21 @@ false, 'with_valid_to' => false, @@ -16,57 +23,60 @@ class AddressRender implements ChillEntityRenderInterface 'with_delimiter' => false, 'has_no_address' => false, 'multiline' => true, - 'extended_infos' => false + 'extended_infos' => false, ]; + private EngineInterface $templating; + public function __construct(EngineInterface $templating) { $this->templating = $templating; } - /** - * {@inheritDoc} - */ - public function supports($entity, array $options): bool - { - return $entity instanceof Address; - } - /** * @param Address addr - */ - public function renderString($addr, array $options): string - { - $lines = []; - if (!empty($addr->getStreet())) { - $lines[0] = $addr->getStreet(); - } - if (!empty($addr->getStreetNumber())) { - $lines[0] .= ", ".$addr->getStreetNumber(); - } - if (!empty($addr->getPostcode())) { - $lines[1] = \strtr("{postcode} {label}", [ - '{postcode}' => $addr->getPostcode()->getCode(), - '{label}' => $addr->getPostcode()->getName() - ]); - } - - return implode(" - ", $lines); - } - - /** - * {@inheritDoc} - * @param Address addr + * @param mixed $addr */ public function renderBox($addr, array $options): string { - $options = \array_merge(self::DEFAULT_OPTIONS, $options); + $options = array_merge(self::DEFAULT_OPTIONS, $options); return $this->templating ->render('@ChillMain/Entity/address.html.twig', [ 'address' => $addr, 'render' => $options['render'] ?? 'bloc', - 'options' => $options + 'options' => $options, ]); } + + /** + * @param Address addr + * @param mixed $addr + */ + public function renderString($addr, array $options): string + { + $lines = []; + + if (!empty($addr->getStreet())) { + $lines[0] = $addr->getStreet(); + } + + if (!empty($addr->getStreetNumber())) { + $lines[0] .= ', ' . $addr->getStreetNumber(); + } + + if (!empty($addr->getPostcode())) { + $lines[1] = strtr('{postcode} {label}', [ + '{postcode}' => $addr->getPostcode()->getCode(), + '{label}' => $addr->getPostcode()->getName(), + ]); + } + + return implode(' - ', $lines); + } + + public function supports($entity, array $options): bool + { + return $entity instanceof Address; + } } 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..5e5f24eb3 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.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\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 +36,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/Entity/UserRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php index 121b94ead..a91b9bb69 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php @@ -1,20 +1,29 @@ true, + 'user_job' => true, + ]; + private EngineInterface $engine; - const DEFAULT_OPTIONS = [ - 'main_scope' => true, - 'user_job' => true - ]; + private TranslatableStringHelper $translatableStringHelper; public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine) { @@ -22,45 +31,40 @@ class UserRender implements ChillEntityRenderInterface $this->engine = $engine; } - /** - * @inheritDoc - */ - public function supports($entity, array $options): bool + public function renderBox($entity, array $options): string { - return $entity instanceof User; + $opts = array_merge(self::DEFAULT_OPTIONS, $options); + + return $this->engine->render('@ChillMain/Entity/user.html.twig', [ + 'user' => $entity, + 'opts' => $opts, + ]); } /** - * @inheritDoc * @param User $entity */ public function renderString($entity, array $options): string { - $opts = \array_merge(self::DEFAULT_OPTIONS, $options); + $opts = array_merge(self::DEFAULT_OPTIONS, $options); $str = $entity->getLabel(); - if (NULL !== $entity->getUserJob() && $opts['user_job']) { - $str .= ' ('.$this->translatableStringHelper - ->localize($entity->getUserJob()->getLabel()).')'; + + if (null !== $entity->getUserJob() && $opts['user_job']) { + $str .= ' (' . $this->translatableStringHelper + ->localize($entity->getUserJob()->getLabel()) . ')'; } - if (NULL !== $entity->getMainScope() && $opts['main_scope']) { - $str .= ' ('.$this->translatableStringHelper - ->localize($entity->getMainScope()->getName()).')'; + + if (null !== $entity->getMainScope() && $opts['main_scope']) { + $str .= ' (' . $this->translatableStringHelper + ->localize($entity->getMainScope()->getName()) . ')'; } return $str; } - /** - * @inheritDoc - */ - public function renderBox($entity, array $options): string + public function supports($entity, array $options): bool { - $opts = \array_merge(self::DEFAULT_OPTIONS, $options); - - return $this->engine->render('@ChillMain/Entity/user.html.twig', [ - 'user' => $entity, - 'opts' => $opts - ]); + return $entity instanceof User; } } 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/Listing/FilterOrderHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php index 8f349da4b..66ad3aa39 100644 --- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php @@ -1,23 +1,37 @@ requestStack = $requestStack; } - public function setSearchBox($searchBoxFields = null): self - { - $this->searchBoxFields = $searchBoxFields; - - return $this; - } - public function addCheckbox(string $name, array $choices, ?array $default = [], ?array $trans = []): self { $missing = count($choices) - count($trans) - 1; $this->checkboxes[$name] = [ 'choices' => $choices, 'default' => $default, - 'trans' => - \array_merge( - $trans, - 0 < $missing ? + 'trans' => array_merge( + $trans, + 0 < $missing ? array_fill(0, $missing, null) : [] - ) + ), ]; return $this; } + public function buildForm(): FormInterface + { + return $this->formFactory + ->createNamed($this->formName, $this->formType, $this->getDefaultData(), array_merge([ + 'helper' => $this, + 'method' => 'GET', + 'csrf_protection' => false, + ], $this->formOptions)) + ->handleRequest($this->requestStack->getCurrentRequest()); + } + public function getCheckboxData(string $name): array { return $this->getFormData()['checkboxes'][$name]; @@ -60,28 +77,31 @@ class FilterOrderHelper return $this->checkboxes; } - public function hasSearchBox(): bool + public function getQueryString(): ?string { - return $this->searchBoxFields !== null; + return $this->getFormData()['q']; } - private function getFormData(): array + public function hasSearchBox(): bool { - if (NULL === $this->submitted) { - $this->submitted = $this->buildForm() - ->getData(); - } + return null !== $this->searchBoxFields; + } - return $this->submitted; + public function setSearchBox($searchBoxFields = null): self + { + $this->searchBoxFields = $searchBoxFields; + + return $this; } private function getDefaultData(): array { - $r = []; + $r = []; + + if ($this->hasSearchBox()) { + $r['q'] = ''; + } - if ($this->hasSearchBox()) { - $r['q'] = ''; - } foreach ($this->checkboxes as $name => $c) { $r['checkboxes'][$name] = $c['default']; } @@ -89,19 +109,13 @@ class FilterOrderHelper return $r; } - public function getQueryString(): ?string + private function getFormData(): array { - return $this->getFormData()['q']; - } + if (null === $this->submitted) { + $this->submitted = $this->buildForm() + ->getData(); + } - public function buildForm(): FormInterface - { - return $this->formFactory - ->createNamed($this->formName, $this->formType, $this->getDefaultData(), \array_merge([ - 'helper' => $this, - 'method' => 'GET', - 'csrf_protection' => false, - ], $this->formOptions)) - ->handleRequest($this->requestStack->getCurrentRequest()); + return $this->submitted; } } diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php index a1791f89f..9ce2c41cd 100644 --- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php @@ -1,5 +1,12 @@ requestStack = $requestStack; } - public function addSearchBox(?array $fields = [], ?array $options = []): self + public function addCheckbox(string $name, array $choices, ?array $default = [], ?array $trans = []): self { - $this->searchBoxFields = $fields; + $this->checkboxes[$name] = ['choices' => $choices, 'default' => $default, 'trans' => $trans]; return $this; } - public function addCheckbox(string $name, array $choices, ?array $default = [], ?array $trans = []): self + public function addSearchBox(?array $fields = [], ?array $options = []): self { - $this->checkboxes[$name] = [ 'choices' => $choices, 'default' => $default, 'trans' => $trans]; + $this->searchBoxFields = $fields; return $this; } @@ -42,12 +52,13 @@ class FilterOrderHelperBuilder ); $helper->setSearchBox($this->searchBoxFields); + foreach ($this->checkboxes as $name => [ 'choices' => $choices, 'default' => $default, - 'trans' => $trans + 'trans' => $trans, ]) { - $helper->addCheckbox($name, $choices, $default, $trans); + $helper->addCheckbox($name, $choices, $default, $trans); } return $helper; diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php index 1b1c4c983..72fed8ae6 100644 --- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php @@ -1,14 +1,21 @@ true, 'is_safe' => ['html'], - ]) - ]; - } - - public function renderFilterOrderHelper( - Environment $environment, - FilterOrderHelper $helper, - ?string $template = '@ChillMain/FilterOrder/base.html.twig', - ?array $options = [] - ) { - return $environment->render($template, [ - 'helper' => $helper, - 'form' => $helper->buildForm()->createView(), - 'options' => $options - ]); - } + ]), + ]; + } + public function renderFilterOrderHelper( + Environment $environment, + FilterOrderHelper $helper, + ?string $template = '@ChillMain/FilterOrder/base.html.twig', + ?array $options = [] + ) { + return $environment->render($template, [ + 'helper' => $helper, + 'form' => $helper->buildForm()->createView(), + 'options' => $options, + ]); + } } diff --git a/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php index cbeb9514e..1673ce386 100644 --- a/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.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\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 fcf82fca9..72db44dac 100644 --- a/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php +++ b/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php @@ -1,28 +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\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. @@ -30,41 +24,35 @@ use Symfony\Component\HttpFoundation\Request; * 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; + public function dataProviderGetQueryKeys() + { + foreach ($this->getFormData() as $data) { + yield [$data]; + } + } /** - * Create an instance of the report to test - * - * @return \Chill\MainBundle\Export\ExportInterface an instance of the export to test + * create data for `ìnitiateQuery` method. */ - public abstract function getExport(); + public function dataProviderInitiateQuery() + { + $acl = $this->getAcl(); + + foreach ($this->getModifiersCombination() as $modifiers) { + foreach ($this->getFormData() as $data) { + yield [$modifiers, $acl, $data]; + } + } + } /** - * 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 + * Return an array usable as ACL. * * If this method is overridden, the returned result must be an array * with this form : @@ -77,11 +65,10 @@ abstract class AbstractExportTest extends WebTestCase * ) * ); * ``` - * */ public function getACL() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } @@ -94,169 +81,103 @@ abstract class AbstractExportTest extends WebTestCase ->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 ?"); + throw new RuntimeException('No center found. Did you forget to ' + . 'run `doctrine:fixtures:load` command before ?'); } - return array([ + 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 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 - */ - public function dataProviderInitiateQuery() - { - $acl = $this->getAcl(); - - foreach($this->getModifiersCombination() as $modifiers) { - - foreach($this->getFormData() as $data) { - - yield array($modifiers, $acl, $data); - } - } - } - - public function dataProviderGetQueryKeys() - { - foreach($this->getFormData() as $data) { - yield array($data); - } + $circles, + ], ]]; } /** + * Create an instance of the report to test. * - * 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 \Chill\MainBundle\Export\ExportInterface an instance of the export to test */ - 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"); - } - } + abstract public function getExport(); /** - * Test that supportsModifier return : + * Create possible combinaison of data (produced by the form). * - * - an array of string, if the query is a QueryBuilder ; - * - nothing, if the query is a native SQL + * This data will be used to generate data providers using this data. * - * @dataProvider dataProviderInitiateQuery + * @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 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"); - } - } + abstract public function getFormData(); /** - * Test required role is an instance of Role + * 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'), ...)` */ - 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 getModifiersCombination(); /** - * Test the formatters type are string + * 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 + * 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. * - * @param array $data * @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 ; @@ -266,7 +187,6 @@ abstract class AbstractExportTest extends WebTestCase * * @param string[] $modifiers * @param array $acl - * @param array $data * * @dataProvider dataProviderInitiateQuery */ @@ -276,7 +196,7 @@ abstract class AbstractExportTest extends WebTestCase // 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) @@ -284,33 +204,45 @@ abstract class AbstractExportTest extends WebTestCase $query->setMaxResults(1); } - $results = $this->getExport()->getResult($query, $data); + $results = $this->getExport()->getResult($query, $data); - $this->assertInternalType('array', $results, - "assert that the returned result is an array"); + $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"); + $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`"); + $this->assertContains( + $key, + $queryKeys, + 'test that each key is present in `getQueryKeys`' + ); - $closure = $this->getExport()->getLabels($key, array($value), $data); + $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( + 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 @@ -318,24 +250,85 @@ abstract class AbstractExportTest extends WebTestCase && !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 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 + * 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 @@ -343,16 +336,68 @@ abstract class AbstractExportTest extends WebTestCase $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 4440f2eef..799b9e617 100644 --- a/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php +++ b/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php @@ -1,27 +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\Test; +use LogicException; use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Prepare a client authenticated with a user + * Prepare a client authenticated with a user. */ trait PrepareClientTrait { @@ -30,20 +23,21 @@ trait PrepareClientTrait * * @param string $username the username (default 'center a_social') * @param string $password the password (default 'password') - * @throws \LogicException + * + * @throws LogicException */ public function getClientAuthenticated( $username = 'center a_social', $password = 'password' ): KernelBrowser { 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/Authorization/ParentRoleHelperTest.php b/src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php index 5f98879b4..1dc2fedcf 100644 --- a/src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php @@ -1,11 +1,22 @@ client = $this->getClientAuthenticated(); } - /** - * @dataProvider generateAddressIds - * @param int $addressId - */ - public function testDuplicate(int $addressId) - { - $this->client->request('POST', "/api/1.0/main/address/$addressId/duplicate.json"); - - $this->assertResponseIsSuccessful('test that duplicate is successful'); - } - public function generateAddressIds() { self::bootKernel(); @@ -43,7 +42,17 @@ class AddressControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTest ->getResult(); foreach ($addresses as $a) { - yield [ $a->getId() ]; + yield [$a->getId()]; } } + + /** + * @dataProvider generateAddressIds + */ + public function testDuplicate(int $addressId) + { + $this->client->request('POST', "/api/1.0/main/address/{$addressId}/duplicate.json"); + + $this->assertResponseIsSuccessful('test that duplicate is successful'); + } } 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/SearchApiControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/SearchApiControllerTest.php index 1c76d8975..17ef616b0 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/SearchApiControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/SearchApiControllerTest.php @@ -1,15 +1,37 @@ request( Request::METHOD_GET, '/api/1.0/search.json', - [ 'q' => $pattern, 'type' => $types ] + ['q' => $pattern, 'type' => $types] ); $this->assertResponseIsSuccessful(); } - - public function generateSearchData() - { - yield ['per', ['person', 'thirdparty'] ]; - yield ['per', ['thirdparty'] ]; - yield ['per', ['person'] ]; - yield ['fjklmeqjfkdqjklrmefdqjklm', ['person', 'thirdparty'] ]; - } } 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/UserApiControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/UserApiControllerTest.php index 85d9895fc..333ab2e19 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/UserApiControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/UserApiControllerTest.php @@ -1,15 +1,42 @@ getClientAuthenticated(); + + $client->request(Request::METHOD_GET, '/api/1.0/main/user/' . $existingUser['id'] . '.json'); + + $this->assertResponseIsSuccessful(); + } + public function testIndex() { $client = $this->getClientAuthenticated(); @@ -18,26 +45,14 @@ class UserApiControllerTest extends WebTestCase $this->assertResponseIsSuccessful(); - $data = \json_decode($client->getResponse()->getContent(), true); - $this->assertTrue(\array_key_exists('count', $data)); + $data = json_decode($client->getResponse()->getContent(), true); + $this->assertTrue(array_key_exists('count', $data)); $this->assertGreaterThan(0, $data['count']); - $this->assertTrue(\array_key_exists('results', $data)); + $this->assertTrue(array_key_exists('results', $data)); return $data['results'][0]; } - /** - * @depends testIndex - */ - public function testEntity($existingUser) - { - $client = $this->getClientAuthenticated(); - - $client->request(Request::METHOD_GET, '/api/1.0/main/user/'.$existingUser['id'].'.json'); - - $this->assertResponseIsSuccessful(); - } - public function testWhoami() { $client = $this->getClientAuthenticated(); diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php index 0017fbb4e..e3ac7337e 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php @@ -1,5 +1,12 @@ client = static::createClient(array(), array( - '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/main/user'); - $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), - "Unexpected HTTP status code for GET /admin/main/user"); - } - - public function testNew() - { - $crawler = $this->client->request('GET', '/fr/admin/main/user/new'); - - $username = 'Test_user'. uniqid(); - $password = 'Password1234!'; - // Fill in the form and submit it - $form = $crawler->selectButton('Créer')->form(array( - 'chill_mainbundle_user[username]' => $username, - 'chill_mainbundle_user[plainPassword][first]' => $password, - 'chill_mainbundle_user[plainPassword][second]' => $password, - 'chill_mainbundle_user[email]' => $username.'@gmail.com', - 'chill_mainbundle_user[label]' => $username, - - )); - - $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")'); - - //test the auth of the new client - $this->isPasswordValid($username, $password); - } - - protected function isPasswordValid($username, $password) - { - /* @var $passwordEncoder \Symfony\Component\Security\Core\Encoder\UserPasswordEncoder */ - $passwordEncoder = self::$container - ->get(UserPasswordEncoderInterface::class); - - $user = self::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:User') - ->findOneBy(array('username' => $username)); - - $this->assertTrue($passwordEncoder->isPasswordValid($user, $password)); - } - - /** - * - * @dataProvider dataGenerateUserId - */ - public function testUpdate(int $userId, string $username) - { - $crawler = $this->client->request('GET', "/fr/admin/main/user/$userId/edit"); - - $username = 'Foo bar '.uniqid(); - $form = $crawler->selectButton('Enregistrer & fermer')->form(array( - '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('[data-username="'.$username.'"]')->count(), - 'Missing element [data-username="Foo bar"]'); - } - - /** - * - * @dataProvider dataGenerateUserId - */ - public function testUpdatePassword(int $userId, $username) - { - $crawler = $this->client->request('GET', "/fr/admin/user/$userId/edit_password"); - $newPassword = '1234Password!'; - - $form = $crawler->selectButton('Changer le mot de passe')->form(array( - '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->isPasswordValid($username, $newPassword); + $this->client = static::createClient([], [ + 'PHP_AUTH_USER' => 'admin', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); } protected function tearDown() @@ -120,7 +40,7 @@ class UserControllerTest extends WebTestCase self::bootKernel(); $em = self::$container->get(EntityManagerInterface::class); - foreach ($this->toDelete as list($class, $id)) { + foreach ($this->toDelete as [$class, $id]) { $obj = $em->getRepository($class)->find($id); $em->remove($obj); } @@ -134,15 +54,118 @@ class UserControllerTest extends WebTestCase $em = self::$container->get(EntityManagerInterface::class); $user = new User(); - $user->setUsername('Test_user '.uniqid()); - $user->setPassword(self::$container->get(UserPasswordEncoderInterface::class)->encodePassword($user, - 'password')); + $user->setUsername('Test_user ' . uniqid()); + $user->setPassword(self::$container->get(UserPasswordEncoderInterface::class)->encodePassword( + $user, + 'password' + )); $em->persist($user); $em->flush(); $this->toDelete[] = [User::class, $user->getId()]; - yield [ $user->getId(), $user->getUsername() ]; + yield [$user->getId(), $user->getUsername()]; + } + + public function testList() + { + // get the list + $crawler = $this->client->request('GET', '/fr/admin/main/user'); + $this->assertEquals( + 200, + $this->client->getResponse()->getStatusCode(), + 'Unexpected HTTP status code for GET /admin/main/user' + ); + } + + public function testNew() + { + $crawler = $this->client->request('GET', '/fr/admin/main/user/new'); + + $username = 'Test_user' . uniqid(); + $password = 'Password1234!'; + // Fill in the form and submit it + $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[email]' => $username . '@gmail.com', + 'chill_mainbundle_user[label]' => $username, + ]); + + $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")' + ); + + //test the auth of the new client + $this->isPasswordValid($username, $password); + } + + /** + * @dataProvider dataGenerateUserId + */ + public function testUpdate(int $userId, string $username) + { + $crawler = $this->client->request('GET', "/fr/admin/main/user/{$userId}/edit"); + + $username = 'Foo bar ' . uniqid(); + $form = $crawler->selectButton('Enregistrer & fermer')->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('[data-username="' . $username . '"]')->count(), + 'Missing element [data-username="Foo bar"]' + ); + } + + /** + * @dataProvider dataGenerateUserId + * + * @param mixed $username + */ + public function testUpdatePassword(int $userId, $username) + { + $crawler = $this->client->request('GET', "/fr/admin/user/{$userId}/edit_password"); + $newPassword = '1234Password!'; + + $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->isPasswordValid($username, $newPassword); + } + + protected function isPasswordValid($username, $password) + { + /* @var $passwordEncoder \Symfony\Component\Security\Core\Encoder\UserPasswordEncoder */ + $passwordEncoder = self::$container + ->get(UserPasswordEncoderInterface::class); + + $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/PickCenterTypeTest.php b/src/Bundle/ChillMainBundle/Tests/Form/Type/PickCenterTypeTest.php index a72360301..12a940d98 100644 --- a/src/Bundle/ChillMainBundle/Tests/Form/Type/PickCenterTypeTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Form/Type/PickCenterTypeTest.php @@ -1,83 +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\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() - { - $this->markTestSkipped(); - //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() - { - $this->markTestSkipped(); - //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 * make CenterType render as "entity" type. @@ -89,15 +32,12 @@ 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); @@ -105,15 +45,57 @@ class CenterTypeTest extends TypeTestCase } /** - * 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() + { + $this->markTestSkipped(); + //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() + { + $this->markTestSkipped(); + //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 */ private function prepareCenter($id, $name) { - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $prophecyCenter = $prophet->prophesize(); $prophecyCenter->willExtend('\Chill\MainBundle\Entity\Center'); @@ -123,36 +105,35 @@ class CenterTypeTest extends TypeTestCase 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/SearchApiQueryTest.php b/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php index 8e05f528f..5adcb0965 100644 --- a/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php @@ -1,12 +1,39 @@ addSelectClause('bada', ['one', 'two']) + ->addSelectClause('boum', ['three', 'four']) + ->setWhereClauses('mywhere', ['six', 'seven']); + + $params = $q->buildParameters(); + + $this->assertEquals(['six', 'seven'], $q->buildParameters(true)); + $this->assertEquals(['one', 'two', 'three', 'four', 'six', 'seven'], $q->buildParameters()); + } + public function testMultipleWhereClauses() { $q = new SearchApiQuery(); @@ -14,9 +41,8 @@ class SearchApiQueryTest extends TestCase ->setSelectKey('bim') ->setSelectPertinence('?', ['gamma']) ->setFromClause('badaboum') - ->andWhereClause('foo', [ 'alpha' ]) - ->andWhereClause('bar', [ 'beta' ]) - ; + ->andWhereClause('foo', ['alpha']) + ->andWhereClause('bar', ['beta']); $query = $q->buildQuery(); @@ -35,27 +61,9 @@ class SearchApiQueryTest extends TestCase $q->setSelectJsonbMetadata('boum') ->setSelectKey('bim') ->setSelectPertinence('1') - ->setFromClause('badaboum') - ; + ->setFromClause('badaboum'); - $this->assertTrue(\is_string($q->buildQuery())); + $this->assertTrue(is_string($q->buildQuery())); $this->assertEquals([], $q->buildParameters()); } - - public function testBuildParams() - { - $q = new SearchApiQuery(); - - $q - ->addSelectClause('bada', [ 'one', 'two' ]) - ->addSelectClause('boum', ['three', 'four']) - ->setWhereClauses('mywhere', [ 'six', 'seven']) - ; - - $params = $q->buildParameters(); - - $this->assertEquals(['six', 'seven'], $q->buildParameters(true)); - $this->assertEquals(['one', 'two', 'three', 'four', 'six', 'seven'], $q->buildParameters()); - } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php b/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php index 99e5baed3..b2b64c904 100644 --- a/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php @@ -1,34 +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\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 */ private $search; @@ -39,85 +30,14 @@ class SearchProviderTest extends TestCase //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' - ); - } - - /** - * @expectedException \Chill\MainBundle\Search\UnknowSearchNameException - */ - public function testInvalidSearchName() - { - $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 - */ - public function testMultipleDomainError() - { - $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); + $this->createNonDefaultDomainSearchService('I am domain bar', 20, false), + 'bar' + ); } public function testAccentued() @@ -126,10 +46,10 @@ class SearchProviderTest extends TestCase $terms = $this->p('manço bélier aztèque à saloù ê'); - $this->assertEquals(array( - '_domain' => NULL, - '_default' => 'manco belier azteque a salou e' - ), $terms); + $this->assertEquals([ + '_domain' => null, + '_default' => 'manco belier azteque a salou e', + ], $terms); } public function testAccentuedCapitals() @@ -138,47 +58,65 @@ class SearchProviderTest extends TestCase $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); + $this->assertEquals([ + '_domain' => null, + '_default' => 'manea ou li a', + ], $terms); } public function testArgumentNameWithTrait() { $terms = $this->p('date-from:2016-05-04'); - $this->assertEquals(array( + $this->assertEquals([ '_domain' => null, 'date-from' => '2016-05-04', - '_default' => '' - ), $terms); + '_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'); + } + + /** + * @expectedException \Chill\MainBundle\Search\ParsingException + */ + public function testMultipleDomainError() + { + $term = $this->p('@person @report'); } /** * Test the behaviour when no domain is provided in the search pattern : - * the default search should be enabled + * the default search should be enabled. */ public function testSearchResultDefault() { @@ -186,9 +124,24 @@ class SearchProviderTest extends TestCase //$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); } /** @@ -199,35 +152,19 @@ 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); - } /** @@ -236,52 +173,94 @@ class SearchProviderTest extends TestCase public function testSearchWithinSpecificSearchNameInConflictWithSupport() { $response = $this->search->getResultByName('@foo default search', 'bar'); - } - /** - * shortcut for executing parse method - * - * @param unknown $pattern - * @return string[] - */ - private function p($pattern) + public function testSimplePattern() { - return $this->search->parse($pattern); + $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); } /** - * Add a search service to the chill.main.search_provider + * 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) + private function addSearchService(SearchInterface $search, $name) { $this->search - ->addSearchService($search, $name); + ->addSearchService($search, $name); } private function createDefaultSearchService($result, $order) { $mock = $this - ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); + ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); //set the mock as default $mock->expects($this->any()) - ->method('isActiveByDefault') - ->will($this->returnValue(TRUE)); + ->method('isActiveByDefault') + ->will($this->returnValue(true)); $mock->expects($this->any()) - ->method('getOrder') - ->will($this->returnValue($order)); + ->method('getOrder') + ->will($this->returnValue($order)); //set the return value $mock->expects($this->any()) - ->method('renderResult') - ->will($this->returnValue($result)); + ->method('renderResult') + ->will($this->returnValue($result)); return $mock; } @@ -289,26 +268,38 @@ class SearchProviderTest extends TestCase private function createNonDefaultDomainSearchService($result, $order, $domain) { $mock = $this - ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); + ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); //set the mock as default $mock->expects($this->any()) - ->method('isActiveByDefault') - ->will($this->returnValue(FALSE)); + ->method('isActiveByDefault') + ->will($this->returnValue(false)); $mock->expects($this->any()) - ->method('getOrder') - ->will($this->returnValue($order)); + ->method('getOrder') + ->will($this->returnValue($order)); $mock->expects($this->any()) - ->method('supports') - ->will($this->returnValue($domain)); + ->method('supports') + ->will($this->returnValue($domain)); //set the return value $mock->expects($this->any()) - ->method('renderResult') - ->will($this->returnValue($result)); + ->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); + } } diff --git a/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractDateFromPatternTest.php b/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractDateFromPatternTest.php index 428996b8e..1fe8b7c01 100644 --- a/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractDateFromPatternTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractDateFromPatternTest.php @@ -1,12 +1,41 @@ assertCount($count, $result->getFound()); $this->assertEquals($filtered, $result->getFilteredSubject()); - $this->assertContainsOnlyInstancesOf(\DateTimeImmutable::class, $result->getFound()); + $this->assertContainsOnlyInstancesOf(DateTimeImmutable::class, $result->getFound()); - $dates = \array_map( - function (\DateTimeImmutable $d) { + $dates = array_map( + function (DateTimeImmutable $d) { return $d->format('Y-m-d'); - }, $result->getFound() + }, + $result->getFound() ); foreach ($datesSearched as $date) { $this->assertContains($date, $dates); } } - - public function provideSubjects() - { - yield ["15/06/1981", "", 1, '1981-06-15']; - yield ["15/06/1981 30/12/1987", "", 2, '1981-06-15', '1987-12-30']; - yield ["diallo 15/06/1981", "diallo", 1, '1981-06-15']; - yield ["diallo 31/03/1981", "diallo", 1, '1981-03-31']; - yield ["diallo 15-06-1981", "diallo", 1, '1981-06-15']; - yield ["diallo 1981-12-08", "diallo", 1, '1981-12-08']; - yield ["diallo", "diallo", 0]; - } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractPhonenumberFromPatternTest.php b/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractPhonenumberFromPatternTest.php index 5c88efa7e..fedd43f5b 100644 --- a/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractPhonenumberFromPatternTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Search/Utils/ExtractPhonenumberFromPatternTest.php @@ -1,14 +1,46 @@ assertEquals($filteredSubject, $result->getFilteredSubject()); $this->assertEquals($expected, $result->getFound()); } - - public function provideData() - { - yield ['Diallo', 0, [], 'Diallo', "no phonenumber"]; - yield ['Diallo 15/06/2021', 0, [], 'Diallo 15/06/2021', "no phonenumber and a date"]; - yield ['Diallo 0486 123 456', 1, ['+32486123456'], 'Diallo', "a phonenumber and a name"]; - yield ['Diallo 123 456', 1, ['123456'], 'Diallo', "a number and a name, without leadiing 0"]; - yield ['123 456', 1, ['123456'], '', "only phonenumber"]; - yield ['0123 456', 1, ['+32123456'], '', "only phonenumber with a leading 0"]; - } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php index 764d6c429..80a7af66a 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php @@ -1,388 +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\Tests\Security\Authorization; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasCentersInterface; use Chill\MainBundle\Entity\HasScopeInterface; use Chill\MainBundle\Entity\HasScopesInterface; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\MainBundle\Test\PrepareUserTrait; +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; + 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(HasCenterInterface::class); - $entity->willImplement(HasScopeInterface::class); - $entity->getCenter()->willReturn($center); - $entity->getScope()->willReturn($scopeA); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - public function testUserHasAccess_MultiCenter_EntityWithoutScope() - { - $center = $this->prepareCenter(1, 'center'); - $centerB = $this->prepareCenter(1, 'centerB'); - $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(HasCentersInterface::class); - $entity->getCenters()->willReturn([$center, $centerB]); - - $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - public function testUserHasNoAccess_MultiCenter_EntityWithoutScope() - { - $center = $this->prepareCenter(1, 'center'); - $centerB = $this->prepareCenter(1, 'centerB'); - $centerC = $this->prepareCenter(1, 'centerC'); - $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(HasCentersInterface::class); - $entity->getCenters()->willReturn([$centerB, $centerC]); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - public function testUserHasNoAccess_EntityMultiScope() - { - $centerA = $this->prepareCenter(1, 'center'); - $centerB = $this->prepareCenter(1, 'centerB'); - $scopeA = $this->prepareScope(2, 'other'); //the user will be granted this scope - $scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope - $scopeC = $this->prepareScope(2, 'other'); //the user will be granted this scope - $user = $this->prepareUser(array( - array( - 'center' => $centerA, 'permissionsGroup' => array( - ['scope' => $scopeA, 'role' => 'CHILL_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement(HasCentersInterface::class); - $entity->willImplement(HasScopesInterface::class); - $entity->getCenters()->willReturn([$centerA, $centerB]); - $entity->getScopes()->willReturn([$scopeB, $scopeC]); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - public function testUserHasAccess_EntityMultiScope() - { - $centerA = $this->prepareCenter(1, 'center'); - $centerB = $this->prepareCenter(1, 'centerB'); - $scopeA = $this->prepareScope(2, 'other'); //the user will be granted this scope - $scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope - $user = $this->prepareUser(array( - array( - 'center' => $centerA, 'permissionsGroup' => array( - ['scope' => $scopeA, 'role' => 'CHILL_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement(HasCentersInterface::class); - $entity->willImplement(HasScopesInterface::class); - $entity->getCenters()->willReturn([$centerA, $centerB]); - $entity->getScopes()->willReturn([$scopeA, $scopeB]); - - $this->assertTrue($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(); @@ -392,93 +49,92 @@ class AuthorizationHelperTest extends KernelTestCase $scopeB = $this->prepareScope(2, 'scope B'); $scopeC = $this->prepareScope(3, 'scope C'); - $userA = $this->prepareUser(array( - array( + $userA = $this->prepareUser([ + [ 'center' => $centerA, - 'permissionsGroup' => array( + '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( + 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 ' - ), - array( + 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 ' - ), - array( + 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 ' - ), - array( + 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 - array( + 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 ' - ), - array( + 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 ' - ), - array( + 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); + in_array($centerB, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_2'), + $scopeA + )), + 'center B should be available for userA, with role 2, scopeA ', + ], + ]; } public function dataProvider_getReachableScopes() @@ -489,61 +145,51 @@ class AuthorizationHelperTest extends KernelTestCase $scopeB = $this->prepareScope(2, 'scope B'); $scopeC = $this->prepareScope(3, 'scope C'); - $userA = $this->prepareUser(array( - array( + $userA = $this->prepareUser([ + [ 'center' => $centerA, - 'permissionsGroup' => array( + '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'] - ) - ) + ['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 array( - array( + 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" - ) - ); - } - - public function testGetParentRoles() - { - $parentRoles = $this->getAuthorizationHelper() - ->getParentRoles('CHILL_INHERITED_ROLE_1'); - - $this->assertContains('CHILL_MASTER_ROLE', $parentRoles, - "Assert that `CHILL_MASTER_ROLE` is a parent of `CHILL_INHERITED_ROLE_1`"); + 'Assert that a scope not reachable is not found within accessible scopes.' + . ' Trying on filter centering', + ], + ]; } public function testFindUsersReaching() @@ -554,12 +200,383 @@ class AuthorizationHelperTest extends KernelTestCase ->findOneByName('Center A'); $users = $this->getAuthorizationHelper() - ->findUsersReaching(new Role('CHILL_PERSON_SEE'), - $centerA); + ->findUsersReaching( + new Role('CHILL_PERSON_SEE'), + $centerA + ); - $usernames = \array_map(function(User $u) { return $u->getUsername(); }, $users); + $usernames = array_map(function (User $u) { return $u->getUsername(); }, $users); $this->assertContains('center a_social', $usernames); } + public function testGetParentRoles() + { + $parentRoles = $this->getAuthorizationHelper() + ->getParentRoles('CHILL_INHERITED_ROLE_1'); + + $this->assertContains( + 'CHILL_MASTER_ROLE', + $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 testUserHasAccessEntityMultiScope() + { + $centerA = $this->prepareCenter(1, 'center'); + $centerB = $this->prepareCenter(1, 'centerB'); + $scopeA = $this->prepareScope(2, 'other'); //the user will be granted this scope + $scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope + $user = $this->prepareUser([ + [ + 'center' => $centerA, 'permissionsGroup' => [ + ['scope' => $scopeA, 'role' => 'CHILL_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement(HasCentersInterface::class); + $entity->willImplement(HasScopesInterface::class); + $entity->getCenters()->willReturn([$centerA, $centerB]); + $entity->getScopes()->willReturn([$scopeA, $scopeB]); + + $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + public function testUserHasAccessMultiCenterEntityWithoutScope() + { + $center = $this->prepareCenter(1, 'center'); + $centerB = $this->prepareCenter(1, 'centerB'); + $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(HasCentersInterface::class); + $entity->getCenters()->willReturn([$center, $centerB]); + + $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + 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(HasCenterInterface::class); + $entity->willImplement(HasScopeInterface::class); + $entity->getCenter()->willReturn($center); + $entity->getScope()->willReturn($scopeA); + + $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + public function testUserHasNoAccessEntityMultiScope() + { + $centerA = $this->prepareCenter(1, 'center'); + $centerB = $this->prepareCenter(1, 'centerB'); + $scopeA = $this->prepareScope(2, 'other'); //the user will be granted this scope + $scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope + $scopeC = $this->prepareScope(2, 'other'); //the user will be granted this scope + $user = $this->prepareUser([ + [ + 'center' => $centerA, 'permissionsGroup' => [ + ['scope' => $scopeA, 'role' => 'CHILL_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement(HasCentersInterface::class); + $entity->willImplement(HasScopesInterface::class); + $entity->getCenters()->willReturn([$centerA, $centerB]); + $entity->getScopes()->willReturn([$scopeB, $scopeC]); + + $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + public function testUserHasNoAccessMultiCenterEntityWithoutScope() + { + $center = $this->prepareCenter(1, 'center'); + $centerB = $this->prepareCenter(1, 'centerB'); + $centerC = $this->prepareCenter(1, 'centerC'); + $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(HasCentersInterface::class); + $entity->getCenters()->willReturn([$centerB, $centerC]); + + $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/Security/Resolver/CenterResolverDispatcherTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/CenterResolverDispatcherTest.php index 851183e3d..2e020ab9a 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/CenterResolverDispatcherTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/CenterResolverDispatcherTest.php @@ -1,14 +1,28 @@ dispatcher->resolveCenter($center); + $resolved = $this->dispatcher->resolveCenter($center); - $this->assertSame($center, $resolved); + $this->assertSame($center, $resolved); } } diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php index de6d19b5a..d7063815a 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/DefaultScopeResolverTest.php @@ -1,5 +1,12 @@ scope = $scope; } @@ -30,7 +41,6 @@ class DefaultScopeResolverTest extends TestCase { return $this->scope; } - }; $this->assertTrue($this->scopeResolver->supports($entity)); @@ -41,8 +51,8 @@ class DefaultScopeResolverTest extends TestCase public function testHasScopesInterface() { $entity = new class($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { - - public function __construct(Scope $scopeA, Scope $scopeB) { + public function __construct(Scope $scopeA, Scope $scopeB) + { $this->scopes = [$scopeA, $scopeB]; } @@ -58,5 +68,4 @@ class DefaultScopeResolverTest extends TestCase $this->assertSame($scopeA, $this->scopeResolver->resolveScope($entity)[0]); $this->assertSame($scopeB, $this->scopeResolver->resolveScope($entity)[1]); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php index 2a36fd365..570138aea 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Resolver/ScopeResolverDispatcherTest.php @@ -1,5 +1,12 @@ scope = $scope; } @@ -31,7 +42,6 @@ class DefaultScopeResolverDispatcherTest extends TestCase { return $this->scope; } - }; $this->assertTrue($this->scopeResolverDispatcher->isConcerned($entity)); @@ -41,8 +51,8 @@ class DefaultScopeResolverDispatcherTest extends TestCase public function testHasScopesInterface() { $entity = new class($scopeA = new Scope(), $scopeB = new Scope()) implements HasScopesInterface { - - public function __construct(Scope $scopeA, Scope $scopeB) { + public function __construct(Scope $scopeA, Scope $scopeB) + { $this->scopes = [$scopeA, $scopeB]; } diff --git a/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DateNormalizerTest.php b/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DateNormalizerTest.php index 03e3015e8..4fa58b782 100644 --- a/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DateNormalizerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DateNormalizerTest.php @@ -1,14 +1,29 @@ prophet = new Prophet(); } - public function testSupports() + public function generateDataNormalize() { - $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'json')); - $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTimeImmutable(), 'json')); - $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'docgen')); - $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTimeImmutable(), 'docgen')); - $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTimeImmutable::class])); - $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTimeInterface::class])); - $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTime::class])); - $this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new \stdClass(), 'docgen')); - $this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'xml')); + $datetime = DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 15:05:01+02:00'); + $date = DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 00:00:00+02:00'); + + yield [ + ['datetime' => '2021-06-05T15:05:01+0200'], + $datetime, 'json', null, 'simple normalization to json', + ]; + + yield [ + ['long' => '5 juin 2021', 'short' => '05/06/2021'], + $date, 'docgen', 'fr', 'normalization to docgen for a date, with current request', + ]; + + yield [ + ['long' => '5 juin 2021', 'short' => '05/06/2021'], + $date, 'docgen', null, 'normalization to docgen for a date, without current request', + ]; + + yield [ + ['long' => '5 juin 2021 à 15:05', 'short' => '05/06/2021 15:05'], + $datetime, 'docgen', null, 'normalization to docgen for a datetime, without current request', + ]; + + yield [ + ['long' => '', 'short' => ''], + null, 'docgen', null, 'normalization to docgen for a null datetime', + ]; } /** * @dataProvider generateDataNormalize + * + * @param mixed $expected + * @param mixed $date + * @param mixed $format + * @param mixed $locale + * @param mixed $msg */ public function testNormalize($expected, $date, $format, $locale, $msg) { $this->assertEquals($expected, $this->buildDateNormalizer($locale)->normalize($date, $format, []), $msg); } - private function buildDateNormalizer(string $locale = null): DateNormalizer + public function testSupports() + { + $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new DateTime(), 'json')); + $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new DateTimeImmutable(), 'json')); + $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new DateTime(), 'docgen')); + $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new DateTimeImmutable(), 'docgen')); + $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => DateTimeImmutable::class])); + $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => DateTimeInterface::class])); + $this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => DateTime::class])); + $this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new stdClass(), 'docgen')); + $this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new DateTime(), 'xml')); + } + + private function buildDateNormalizer(?string $locale = null): DateNormalizer { $requestStack = $this->prophet->prophesize(RequestStack::class); $parameterBag = new ParameterBag(); $parameterBag->set('kernel.default_locale', 'fr'); - if ($locale === null) { + if (null === $locale) { $requestStack->getCurrentRequest()->willReturn(null); } else { $request = $this->prophet->prophesize(Request::class); @@ -55,34 +107,4 @@ class DateNormalizerTest extends KernelTestCase return new DateNormalizer($requestStack->reveal(), $parameterBag); } - - public function generateDataNormalize() - { - $datetime = \DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 15:05:01+02:00'); - $date = \DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 00:00:00+02:00'); - yield [ - ['datetime' => '2021-06-05T15:05:01+0200'], - $datetime, 'json', null, 'simple normalization to json' - ]; - - yield [ - ['long' => '5 juin 2021', 'short' => '05/06/2021'], - $date, 'docgen', 'fr', 'normalization to docgen for a date, with current request' - ]; - - yield [ - ['long' => '5 juin 2021', 'short' => '05/06/2021'], - $date, 'docgen', null, 'normalization to docgen for a date, without current request' - ]; - - yield [ - ['long' => '5 juin 2021 à 15:05', 'short' => '05/06/2021 15:05'], - $datetime, 'docgen', null, 'normalization to docgen for a datetime, without current request' - ]; - - yield [ - ['long' => '', 'short' => ''], - null, 'docgen', null, 'normalization to docgen for a null datetime' - ]; - } } diff --git a/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DoctrineExistingEntityNormalizerTest.php b/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DoctrineExistingEntityNormalizerTest.php index c4f4bc13d..57b4d44b7 100644 --- a/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DoctrineExistingEntityNormalizerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Serializer/Normalizer/DoctrineExistingEntityNormalizerTest.php @@ -1,14 +1,24 @@ get(EntityManagerInterface::class); + $em = self::$container->get(EntityManagerInterface::class); $serializerFactory = self::$container->get(ClassMetadataFactoryInterface::class); $this->normalizer = new DoctrineExistingEntityNormalizer($em, $serializerFactory); } - /** - * @dataProvider dataProviderUserId - */ - public function testGetMappedClass($userId) - { - $data = [ 'type' => 'user', 'id' => $userId]; - $supports = $this->normalizer->supportsDenormalization($data, User::class); - - $this->assertTrue($supports); - } - public function dataProviderUserId() { self::bootKernel(); @@ -43,9 +42,21 @@ class DoctrineExistingEntityNormalizerTest extends KernelTestCase ->select('u.id') ->setMaxResults(1) ->getQuery() - ->getResult() - ; + ->getResult(); - yield [ $userIds[0]['id'] ]; + yield [$userIds[0]['id']]; + } + + /** + * @dataProvider dataProviderUserId + * + * @param mixed $userId + */ + public function testGetMappedClass($userId) + { + $data = ['type' => 'user', 'id' => $userId]; + $supports = $this->normalizer->supportsDenormalization($data, User::class); + + $this->assertTrue($supports); } } 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/Templating/Entity/AddressRenderTest.php b/src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php index 79551d23c..2873c04e3 100644 --- a/src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php @@ -1,22 +1,51 @@ setName(['fr' => 'Pays']) + ->setCountryCode('BE'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + yield [$addr, 'Rue ABC, 5 - 012345 Locality']; + } + /** * @dataProvider addressDataProvider */ @@ -26,30 +55,8 @@ class AddressRenderTest extends KernelTestCase $renderer = new AddressRender($engine); $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + return; $this->assertIsString($renderer->renderBox($addr, [])); - } - - - public function addressDataProvider(): \Iterator - { - $addr = new Address(); - $country = (new Country()) - ->setName([ "fr" => "Pays" ]) - ->setCountryCode("BE") - ; - $postCode = new PostalCode(); - $postCode->setName("Locality") - ->setCode("012345") - ->setCountry($country) - ; - - $addr->setStreet("Rue ABC") - ->setStreetNumber("5") - ->setPostcode($postCode) - ; - - yield[ $addr, "Rue ABC, 5 - 012345 Locality"]; } - } 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/Util/DateRangeCoveringTest.php b/src/Bundle/ChillMainBundle/Tests/Util/DateRangeCoveringTest.php index 18af61849..b02e2ea3e 100644 --- a/src/Bundle/ChillMainBundle/Tests/Util/DateRangeCoveringTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Util/DateRangeCoveringTest.php @@ -1,35 +1,47 @@ add(new \DateTime('2010-01-01'), new \DateTime('2010-12-01'), 1) - ->add(new \DateTime('2010-06-01'), new \DateTime('2011-06-01'), 2) - ->add(new \DateTime('2019-06-01'), new \DateTime('2019-06-01'), 3) - ->compute() - ; + ->add(new DateTime('2010-01-01'), new DateTime('2010-12-01'), 1) + ->add(new DateTime('2010-06-01'), new DateTime('2011-06-01'), 2) + ->add(new DateTime('2019-06-01'), new DateTime('2019-06-01'), 3) + ->compute(); $this->assertTrue($cover->hasIntersections()); $this->assertIsArray($cover->getIntersections()); $this->assertCount(1, $cover->getIntersections()); $this->assertEquals( - new \DateTime('2010-06-01'), + new DateTime('2010-06-01'), $cover->getIntersections()[0][0], - "assert date start are the intersection" + 'assert date start are the intersection' ); $this->assertEquals( - new \DateTime('2010-12-01'), + new DateTime('2010-12-01'), $cover->getIntersections()[0][1], - "assert date end are the intersection" + 'assert date end are the intersection' ); $this->assertIsArray($cover->getIntersections()[0][2]); $this->assertContains(1, $cover->getIntersections()[0][2]); @@ -37,28 +49,26 @@ class DateRangeCoveringTest extends TestCase $this->assertNotContains(3, $cover->getIntersections()[0][2]); } - public function testCoveringWithMinCover1_NoCoveringWithNullDates() + public function testCoveringWithMinCover1NoCoveringWithNullDates() { - $cover = new DateRangeCovering(1, new \DateTimeZone('Europe/Brussels')); + $cover = new DateRangeCovering(1, new DateTimeZone('Europe/Brussels')); $cover - ->add(new \DateTime('2021-10-05'), new \DateTime('2021-10-18'), 521) - ->add(new \DateTime('2021-10-26'), null, 663) - ->compute() - ; + ->add(new DateTime('2021-10-05'), new DateTime('2021-10-18'), 521) + ->add(new DateTime('2021-10-26'), null, 663) + ->compute(); $this->assertFalse($cover->hasIntersections()); } public function testCoveringWithMinCover1WithTwoIntersections() { - $cover = new DateRangeCovering(1, new \DateTimeZone('Europe/Brussels')); + $cover = new DateRangeCovering(1, new DateTimeZone('Europe/Brussels')); $cover - ->add(new \DateTime('2010-01-01'), new \DateTime('2010-12-01'), 1) - ->add(new \DateTime('2010-06-01'), new \DateTime('2011-06-01'), 2) - ->add(new \DateTime('2019-01-01'), new \DateTime('2019-12-01'), 3) - ->add(new \DateTime('2019-06-01'), new \DateTime('2020-06-01'), 4) - ->compute() - ; + ->add(new DateTime('2010-01-01'), new DateTime('2010-12-01'), 1) + ->add(new DateTime('2010-06-01'), new DateTime('2011-06-01'), 2) + ->add(new DateTime('2019-01-01'), new DateTime('2019-12-01'), 3) + ->add(new DateTime('2019-06-01'), new DateTime('2020-06-01'), 4) + ->compute(); $this->assertTrue($cover->hasIntersections()); $this->assertIsArray($cover->getIntersections()); @@ -67,7 +77,7 @@ class DateRangeCoveringTest extends TestCase $intersections = $cover->getIntersections(); // sort the intersections to compare them in expected order - \usort($intersections, function($a, $b) { + usort($intersections, function ($a, $b) { if ($a[0] === $b[0]) { return $a[1] <=> $b[1]; } @@ -77,14 +87,14 @@ class DateRangeCoveringTest extends TestCase // first intersection $this->assertEquals( - new \DateTime('2010-06-01'), + new DateTime('2010-06-01'), $intersections[0][0], - "assert date start are the intersection" + 'assert date start are the intersection' ); $this->assertEquals( - new \DateTime('2010-12-01'), + new DateTime('2010-12-01'), $intersections[0][1], - "assert date end are the intersection" + 'assert date end are the intersection' ); $this->assertIsArray($intersections[0][2]); $this->assertContains(1, $intersections[0][2]); @@ -94,14 +104,14 @@ class DateRangeCoveringTest extends TestCase // second intersection $this->assertEquals( - new \DateTime('2019-06-01'), + new DateTime('2019-06-01'), $intersections[1][0], - "assert date start are the intersection" + 'assert date start are the intersection' ); $this->assertEquals( - new \DateTime('2019-12-01'), + new DateTime('2019-12-01'), $intersections[1][1], - "assert date end are the intersection" + 'assert date end are the intersection' ); $this->assertIsArray($intersections[1][2]); $this->assertContains(3, $intersections[1][2]); @@ -112,28 +122,27 @@ class DateRangeCoveringTest extends TestCase public function testCoveringWithMinCover2() { - $cover = new DateRangeCovering(2, new \DateTimeZone('Europe/Brussels')); + $cover = new DateRangeCovering(2, new DateTimeZone('Europe/Brussels')); $cover - ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), 1) - ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), 2) - ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), 3) - ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), 4) - ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), 5) - ->compute() - ; + ->add(new DateTime('2010-01-01'), new DateTime('2010-10-01'), 1) + ->add(new DateTime('2010-06-01'), new DateTime('2010-09-01'), 2) + ->add(new DateTime('2010-04-01'), new DateTime('2010-12-01'), 3) + ->add(new DateTime('2019-01-01'), new DateTime('2019-10-01'), 4) + ->add(new DateTime('2019-06-01'), new DateTime('2019-09-01'), 5) + ->compute(); $this->assertTrue($cover->hasIntersections()); $this->assertIsArray($cover->getIntersections()); $this->assertCount(1, $cover->getIntersections()); $this->assertEquals( - new \DateTime('2010-06-01'), + new DateTime('2010-06-01'), $cover->getIntersections()[0][0], - "assert date start are the intersection" + 'assert date start are the intersection' ); $this->assertEquals( - new \DateTime('2010-09-01'), + new DateTime('2010-09-01'), $cover->getIntersections()[0][1], - "assert date end are the intersection" + 'assert date end are the intersection' ); $this->assertIsArray($cover->getIntersections()[0][2]); $this->assertContains(1, $cover->getIntersections()[0][2]); @@ -145,30 +154,29 @@ class DateRangeCoveringTest extends TestCase public function testCoveringWithMinCover2AndThreePeriodsCovering() { - $cover = new DateRangeCovering(2, new \DateTimeZone('Europe/Brussels')); + $cover = new DateRangeCovering(2, new DateTimeZone('Europe/Brussels')); $cover - ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), 1) - ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), 2) - ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), 3) - ->add(new \DateTime('2009-01-01'), new \DateTime('2010-09-15'), 4) - ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), 5) - ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), 6) - ->compute() - ; + ->add(new DateTime('2010-01-01'), new DateTime('2010-10-01'), 1) + ->add(new DateTime('2010-06-01'), new DateTime('2010-09-01'), 2) + ->add(new DateTime('2010-04-01'), new DateTime('2010-12-01'), 3) + ->add(new DateTime('2009-01-01'), new DateTime('2010-09-15'), 4) + ->add(new DateTime('2019-01-01'), new DateTime('2019-10-01'), 5) + ->add(new DateTime('2019-06-01'), new DateTime('2019-09-01'), 6) + ->compute(); $this->assertTrue($cover->hasIntersections()); $this->assertIsArray($cover->getIntersections()); $this->assertCount(1, $cover->getIntersections()); $this->assertEquals( - new \DateTime('2010-04-01'), + new DateTime('2010-04-01'), $cover->getIntersections()[0][0], - "assert date start are the intersection" + 'assert date start are the intersection' ); $this->assertEquals( - new \DateTime('2010-09-15'), + new DateTime('2010-09-15'), $cover->getIntersections()[0][1], - "assert date end are the intersection" + 'assert date end are the intersection' ); $this->assertIsArray($cover->getIntersections()[0][2]); $this->assertContains(1, $cover->getIntersections()[0][2]); @@ -181,46 +189,43 @@ class DateRangeCoveringTest extends TestCase public function testCoveringWithMinCover2AndThreePeriodsCoveringWithNullMetadata() { - $cover = new DateRangeCovering(2, new \DateTimeZone('Europe/Brussels')); + $cover = new DateRangeCovering(2, new DateTimeZone('Europe/Brussels')); $cover - ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), null) - ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), null) - ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), null) - ->add(new \DateTime('2009-01-01'), new \DateTime('2010-09-15'), null) - ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), null) - ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), null) - ->compute() - ; + ->add(new DateTime('2010-01-01'), new DateTime('2010-10-01'), null) + ->add(new DateTime('2010-06-01'), new DateTime('2010-09-01'), null) + ->add(new DateTime('2010-04-01'), new DateTime('2010-12-01'), null) + ->add(new DateTime('2009-01-01'), new DateTime('2010-09-15'), null) + ->add(new DateTime('2019-01-01'), new DateTime('2019-10-01'), null) + ->add(new DateTime('2019-06-01'), new DateTime('2019-09-01'), null) + ->compute(); $this->assertTrue($cover->hasIntersections()); $this->assertIsArray($cover->getIntersections()); $this->assertCount(1, $cover->getIntersections()); $this->assertEquals( - new \DateTime('2010-04-01'), + new DateTime('2010-04-01'), $cover->getIntersections()[0][0], - "assert date start are the intersection" + 'assert date start are the intersection' ); $this->assertEquals( - new \DateTime('2010-09-15'), + new DateTime('2010-09-15'), $cover->getIntersections()[0][1], - "assert date end are the intersection" + 'assert date end are the intersection' ); $this->assertIsArray($cover->getIntersections()[0][2]); } - public function testCoveringWithMinCover3Absent() { - $cover = new DateRangeCovering(3, new \DateTimeZone('Europe/Brussels')); + $cover = new DateRangeCovering(3, new DateTimeZone('Europe/Brussels')); $cover - ->add(new \DateTime('2010-01-01'), new \DateTime('2010-10-01'), 1) - ->add(new \DateTime('2010-06-01'), new \DateTime('2010-09-01'), 2) - ->add(new \DateTime('2010-04-01'), new \DateTime('2010-12-01'), 3) - ->add(new \DateTime('2019-01-01'), new \DateTime('2019-10-01'), 4) - ->add(new \DateTime('2019-06-01'), new \DateTime('2019-09-01'), 5) - ->compute() - ; + ->add(new DateTime('2010-01-01'), new DateTime('2010-10-01'), 1) + ->add(new DateTime('2010-06-01'), new DateTime('2010-09-01'), 2) + ->add(new DateTime('2010-04-01'), new DateTime('2010-12-01'), 3) + ->add(new DateTime('2019-01-01'), new DateTime('2019-10-01'), 4) + ->add(new DateTime('2019-06-01'), new DateTime('2019-09-01'), 5) + ->compute(); $this->assertFalse($cover->hasIntersections()); $this->assertIsArray($cover->getIntersections()); $this->assertCount(0, $cover->getIntersections()); 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\Types; use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Doctrine\ORM\Query; -use Doctrine\ORM\NativeQuery; +use Doctrine\ORM\Query\ResultSetMapping; +use LogicException; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; /** - * Build timeline + * 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 ]` * @@ -50,7 +39,7 @@ class TimelineBuilder implements ContainerAwareInterface private $providers = []; /** - * Record provider and their context + * Record provider and their context. * * This array has the structure `[ 'context' => [ 'service id' ] ]` * @@ -64,58 +53,7 @@ class TimelineBuilder implements ContainerAwareInterface } /** - * 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) - { - list($union, $parameters) = $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, $parameters); - $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) - { - $rsm = (new ResultSetMapping()) - ->addScalarResult('total', 'total', Types::INTEGER); - - list($select, $parameters) = $this->buildUnionQuery($context, $args); - - // embed the union query inside a count query - $countQuery = sprintf('SELECT COUNT(sq.id) AS total FROM (%s) as sq', $select); - - $nq = $this->em->createNativeQuery($countQuery, $rsm); - $nq->setParameters($parameters); - - return $nq->getSingleScalarResult(); - } - - /** - * add a provider id + * add a provider id. * * @internal This function is called by the TimelineCompilerClass * @@ -129,22 +67,46 @@ class TimelineBuilder implements ContainerAwareInterface } /** - * 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) + { + $rsm = (new ResultSetMapping()) + ->addScalarResult('total', 'total', Types::INTEGER); + + [$select, $parameters] = $this->buildUnionQuery($context, $args); + + // embed the union query inside a count query + $countQuery = sprintf('SELECT COUNT(sq.id) AS total FROM (%s) as sq', $select); + + $nq = $this->em->createNativeQuery($countQuery, $rsm); + $nq->setParameters($parameters); + + return $nq->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]; } @@ -152,11 +114,93 @@ class TimelineBuilder implements ContainerAwareInterface } /** - * build the UNION query with all providers + * 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, $parameters] = $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, $parameters); + $entitiesByKey = $this->getEntities($fetched, $context); + + return $this->render($fetched, $entitiesByKey, $context, $args); + } + + /** + * Hack to replace the arbitrary "AS" statement in DQL + * into proper SQL query + * TODO remove + * private function replaceASInDQL(string $dql): string + * { + * $pattern = '/^(SELECT\s+[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s{0,},\s{0,}[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s{0,},\s{0,}[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s+FROM.*)/'; + * $replacements = '${1} AS id ${3} AS type ${5} AS date ${7}';. + * + * $s = \preg_replace($pattern, $replacements, $dql, 1); + * + * if (NULL === $s) { + * throw new \RuntimeException('Could not replace the "AS" statement produced by '. + * 'DQL with normal SQL AS: '.$dql); + * } + * + * return $s; + * } + * + * @param mixed $data + */ + + /** + * return the SQL SELECT query as a string,. + * + * @return array: first parameter is the sql string, second an array with parameters + */ + private function buildSelectQuery($data): array + { + return [$data->buildSql(), $data->getParameters()]; + // dead code + $parameters = []; + + $sql = sprintf( + 'SELECT %s AS id, ' + . '%s AS "date", ' + . "'%s' AS type " + . 'FROM %s ' + . 'WHERE %s', + $data['id'], + $data['date'], + $data['type'], + $data['FROM'], + is_string($data['WHERE']) ? $data['WHERE'] : $data['WHERE'][0] + ); + + return [$sql, $data['WHERE'][1]]; + } + + /** + * build the UNION query with all providers. * * @uses self::buildSelectQuery to build individual SELECT queries * - * @throws \LogicException if no builder have been defined for this context + * @throws LogicException if no builder have been defined for this context + * * @return array, where first element is the query, the second one an array with the parameters */ private function buildUnionQuery(string $context, array $args): array @@ -165,10 +209,10 @@ class TimelineBuilder implements ContainerAwareInterface $union = ''; $parameters = []; - foreach($this->getProvidersByContext($context) as $provider) { + foreach ($this->getProvidersByContext($context) as $provider) { $data = $provider->fetchQuery($context, $args); - list($select, $selectParameters) = $this->buildSelectQuery($data); - $append = empty($union) ? $select : ' UNION '.$select; + [$select, $selectParameters] = $this->buildSelectQuery($data); + $append = empty($union) ? $select : ' UNION ' . $select; $union .= $append; $parameters = array_merge($parameters, $selectParameters); } @@ -177,93 +221,28 @@ class TimelineBuilder implements ContainerAwareInterface } /** - * Hack to replace the arbitrary "AS" statement in DQL - * into proper SQL query - * TODO remove - private function replaceASInDQL(string $dql): string - { - $pattern = '/^(SELECT\s+[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s{0,},\s{0,}[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s{0,},\s{0,}[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s+FROM.*)/'; - $replacements = '${1} AS id ${3} AS type ${5} AS date ${7}'; - - $s = \preg_replace($pattern, $replacements, $dql, 1); - - if (NULL === $s) { - throw new \RuntimeException('Could not replace the "AS" statement produced by '. - 'DQL with normal SQL AS: '.$dql); - } - - return $s; - } - */ - - /** - * return the SQL SELECT query as a string, - * - * @return array: first parameter is the sql string, second an array with parameters - */ - private function buildSelectQuery($data): array - { - return [$data->buildSql(), $data->getParameters()]; - - // dead code - $parameters = []; - - $sql = sprintf( - 'SELECT %s AS id, ' - . '%s AS "date", ' - . "'%s' AS type " - . 'FROM %s ' - . 'WHERE %s', - $data['id'], - $data['date'], - $data['type'], - $data['FROM'], - is_string($data['WHERE']) ? $data['WHERE'] : $data['WHERE'][0] - ); - - return [$sql, $data['WHERE'][1]]; - - } - - /** - * run the UNION query and return result as an array - * - * @return array an array with the results - */ - private function runUnionQuery(string $query, array $parameters): array - { - $resultSetMapping = (new ResultSetMapping()) - ->addScalarResult('id', 'id') - ->addScalarResult('type', 'type') - ->addScalarResult('date', 'date'); - - return $this->em->createNativeQuery($query, $resultSetMapping) - ->setParameters($parameters) - ->getArrayResult(); - } - - /** - * - * @param array $queriedIds * @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(); + $idsByType = []; - foreach($queriedIds as $result) { + 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 } } @@ -272,40 +251,6 @@ class TimelineBuilder implements ContainerAwareInterface 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); - - $timelineEntries[] = [ - 'date' => new \DateTime($result['date']), - 'template' => $data['template'], - 'template_data' => $data['template_data'] - ]; - } - - return $this->container->get('templating') - ->render('@ChillMain/Timeline/chain_timelines.html.twig', array( - 'results' => $timelineEntries - )); - - } - /** * get the template data from the provider for the given entity, by type. * @@ -313,14 +258,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 + ); + + $timelineEntries[] = [ + 'date' => new DateTime($result['date']), + 'template' => $data['template'], + 'template_data' => $data['template_data'], + ]; + } + + return $this->container->get('templating') + ->render('@ChillMain/Timeline/chain_timelines.html.twig', [ + 'results' => $timelineEntries, + ]); + } + + /** + * run the UNION query and return result as an array. + * + * @return array an array with the results + */ + private function runUnionQuery(string $query, array $parameters): array + { + $resultSetMapping = (new ResultSetMapping()) + ->addScalarResult('id', 'id') + ->addScalarResult('type', 'type') + ->addScalarResult('date', 'date'); + + return $this->em->createNativeQuery($query, $resultSetMapping) + ->setParameters($parameters) + ->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/Timeline/TimelineSingleQuery.php b/src/Bundle/ChillMainBundle/Timeline/TimelineSingleQuery.php index e7e456a80..42f8cd192 100644 --- a/src/Bundle/ChillMainBundle/Timeline/TimelineSingleQuery.php +++ b/src/Bundle/ChillMainBundle/Timeline/TimelineSingleQuery.php @@ -1,30 +1,38 @@ id = $id; @@ -35,6 +43,27 @@ class TimelineSingleQuery $this->parameters = $parameters; } + public function buildSql(): string + { + $parameters = []; + + return strtr( + 'SELECT {distinct} {id} AS id, ' + . '{date} AS "date", ' + . "'{key}' AS type " + . 'FROM {from} ' + . 'WHERE {where}', + [ + '{distinct}' => $this->distinct ? 'DISTINCT' : '', + '{id}' => $this->getId(), + '{date}' => $this->getDate(), + '{key}' => $this->getKey(), + '{from}' => $this->getFrom(), + '{where}' => $this->getWhere(), + ] + ); + } + public static function fromArray(array $a) { return new TimelineSingleQuery( @@ -43,78 +72,49 @@ class TimelineSingleQuery $a['type'] ?? $a['key'] ?? null, $a['FROM'] ?? $a['from'] ?? null, $a['WHERE'] ?? $a['where'] ?? null, - $a['parameters'] ?? null); - } - - public function getId(): string - { - return $this->id; - } - - public function setId(string $id): self - { - $this->id = $id; - - return $this; + $a['parameters'] ?? null + ); } public function getDate(): string { return $this->date; } - - public function setDate(string $date): self + + public function getFrom(): string { - $this->date = $date; - - return $this; + return $this->from; + } + + public function getId(): string + { + return $this->id; } public function getKey(): string { return $this->key; } - - public function setKey(string $key): self - { - $this->key = $key; - - return $this; - } - public function getFrom(): string + public function getParameters(): array { - return $this->from; - } - - public function setFrom(string $from): self - { - $this->from = $from; - - return $this; + return $this->parameters; } public function getWhere(): string { return $this->where; } - - public function setWhere(string $where): self + + public function isDistinct(): bool { - $this->where = $where; - - return $this; + return $this->distinct; } - public function getParameters(): array + public function setDate(string $date): self { - return $this->parameters; - } - - public function setParameters(array $parameters): self - { - $this->parameters = $parameters; - + $this->date = $date; + return $this; } @@ -125,31 +125,38 @@ class TimelineSingleQuery return $this; } - public function isDistinct(): bool + public function setFrom(string $from): self { - return $this->distinct; + $this->from = $from; + + return $this; } - public function buildSql(): string + public function setId(string $id): self { - $parameters = []; + $this->id = $id; - $sql = \strtr( - 'SELECT {distinct} {id} AS id, ' - . '{date} AS "date", ' - . "'{key}' AS type " - . 'FROM {from} ' - . 'WHERE {where}', - [ - '{distinct}' => $this->distinct ? 'DISTINCT' : '', - '{id}' => $this->getId(), - '{date}' => $this->getDate(), - '{key}' => $this->getKey(), - '{from}' => $this->getFrom(), - '{where}' => $this->getWhere(), - ] - ); + return $this; + } - return $sql; + public function setKey(string $key): self + { + $this->key = $key; + + return $this; + } + + public function setParameters(array $parameters): self + { + $this->parameters = $parameters; + + return $this; + } + + public function setWhere(string $where): self + { + $this->where = $where; + + return $this; } } 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 @@ $minCover) { + throw new LogicException('argument minCover cannot be lower than 0'); } $this->minCover = $minCover; $this->tz = $tz; } - public function add(\DateTimeInterface $start, \DateTimeInterface $end = null, $metadata = null): self + public function add(DateTimeInterface $start, ?DateTimeInterface $end = null, $metadata = null): self { if ($this->computed) { - throw new \LogicException("You cannot add intervals to a computed instance"); + throw new LogicException('You cannot add intervals to a computed instance'); } $k = $this->uniqueKeyCounter++; @@ -72,29 +92,17 @@ class DateRangeCovering $this->addToSequence($start->getTimestamp(), $k, null); $this->addToSequence( - NULL === $end ? PHP_INT_MAX : $end->getTimestamp(), null, $k + null === $end ? PHP_INT_MAX : $end->getTimestamp(), + null, + $k ); return $this; } - private function addToSequence($timestamp, int $start = null, int $end = null) - { - if (!\array_key_exists($timestamp, $this->sequence)) { - $this->sequence[$timestamp] = [ 's' => [], 'e' => [] ]; - } - - if (NULL !== $start) { - $this->sequence[$timestamp]['s'][] = $start; - } - if (NULL !== $end) { - $this->sequence[$timestamp]['e'][] = $end; - } - } - public function compute(): self { - \ksort($this->sequence); + ksort($this->sequence); $currentPeriod = []; $currents = []; @@ -102,8 +110,8 @@ class DateRangeCovering $overs = []; foreach ($this->sequence as $ts => $moves) { - $currents = \array_merge($currents, $moves['s']); - $currents = \array_diff($currents, $moves['e']); + $currents = array_merge($currents, $moves['s']); + $currents = array_diff($currents, $moves['e']); if (count($currents) > $this->minCover && !$isOpen) { $currentPeriod[0] = $ts; @@ -115,23 +123,23 @@ class DateRangeCovering $currentPeriod = []; $isOpen = false; } elseif ($isOpen) { - $currentPeriod[2] = \array_merge($currentPeriod[2], $currents); + $currentPeriod[2] = array_merge($currentPeriod[2], $currents); } } // process metadata - foreach ($overs as list($start, $end, $metadata)) { + foreach ($overs as [$start, $end, $metadata]) { $this->intersections[] = [ - (new \DateTimeImmutable('@'.$start)) + (new DateTimeImmutable('@' . $start)) ->setTimezone($this->tz), - $end === PHP_INT_MAX ? null : (new \DateTimeImmutable('@'.$end)) + PHP_INT_MAX === $end ? null : (new DateTimeImmutable('@' . $end)) ->setTimezone($this->tz), - \array_values( - \array_intersect_key( + array_values( + array_intersect_key( $this->metadatas, - \array_flip(\array_unique($metadata)) + array_flip(array_unique($metadata)) ) - ) + ), ]; } @@ -140,24 +148,38 @@ class DateRangeCovering return $this; } - public function hasIntersections(): bool - { - if (!$this->computed) { - throw new \LogicException(sprintf("You cannot call the method %s before ". - "'process'", __METHOD__)); - } - - return count($this->intersections) > 0; - } - public function getIntersections(): array { if (!$this->computed) { - throw new \LogicException(sprintf("You cannot call the method %s before ". + throw new LogicException(sprintf('You cannot call the method %s before ' . "'process'", __METHOD__)); } return $this->intersections; } + public function hasIntersections(): bool + { + if (!$this->computed) { + throw new LogicException(sprintf('You cannot call the method %s before ' . + "'process'", __METHOD__)); + } + + return count($this->intersections) > 0; + } + + private function addToSequence($timestamp, ?int $start = null, ?int $end = null) + { + if (!array_key_exists($timestamp, $this->sequence)) { + $this->sequence[$timestamp] = ['s' => [], 'e' => []]; + } + + if (null !== $start) { + $this->sequence[$timestamp]['s'][] = $start; + } + + if (null !== $end) { + $this->sequence[$timestamp]['e'][] = $end; + } + } } diff --git a/src/Bundle/ChillMainBundle/Validation/Constraint/PhonenumberConstraint.php b/src/Bundle/ChillMainBundle/Validation/Constraint/PhonenumberConstraint.php index cf4479456..86a53412c 100644 --- a/src/Bundle/ChillMainBundle/Validation/Constraint/PhonenumberConstraint.php +++ b/src/Bundle/ChillMainBundle/Validation/Constraint/PhonenumberConstraint.php @@ -1,43 +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\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..09c03f3ef 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 + && $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()) - ) - { + && !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 { $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..3c8652fed 100644 --- a/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistencyValidator.php +++ b/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistencyValidator.php @@ -1,66 +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\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/chill.api.specs.yaml b/src/Bundle/ChillMainBundle/chill.api.specs.yaml index 8252502ba..110547201 100644 --- a/src/Bundle/ChillMainBundle/chill.api.specs.yaml +++ b/src/Bundle/ChillMainBundle/chill.api.specs.yaml @@ -1,625 +1,626 @@ --- openapi: "3.0.0" info: - version: "1.0.0" - title: "Chill api" - description: "Api documentation for chill. Currently, work in progress" + version: "1.0.0" + title: "Chill api" + description: "Api documentation for chill. Currently, work in progress" servers: - - url: "/api" - description: "Your current dev server" + - url: "/api" + description: "Your current dev server" components: - schemas: - User: - type: object - properties: - id: - type: integer - type: - type: string - enum: - - user - username: - type: string - text: - type: string - Center: - type: object - properties: - id: - type: integer - name: - type: string - Address: - type: object - properties: - address_id: - type: integer - text: - type: string - postcode: - type: object - properties: - name: - type: string - - Country: - type: object - properties: - id: - type: integer - name: - type: object - countryCode: - type: string - - PostalCode: - type: object - properties: - id: - type: integer - name: - type: string - code: - type: string - country: - type: object - properties: - id: - type: integer - name: - type: object - countryCode: - type: string - - AddressReference: - type: object - properties: - id: - type: integer - refId: - type: string - street: - type: string - streetNumber: - type: string - postcode: - type: object - properties: - id: - type: integer - name: - type: string - code: - type: string - country: - type: object - properties: + schemas: + User: + type: object + properties: id: - type: integer + type: integer + type: + type: string + enum: + - user + username: + type: string + text: + type: string + Center: + type: object + properties: + id: + type: integer name: - type: object + type: string + Address: + type: object + properties: + address_id: + type: integer + text: + type: string + postcode: + type: object + properties: + name: + type: string + + Country: + type: object + properties: + id: + type: integer + name: + type: object countryCode: - type: string - municipalityCode: - type: string - source: - type: string - point: - type: object - properties: - type: - type: string - coordinates: - type: array - items: - type: number - minItems: 2 - maxItems: 2 + type: string + + PostalCode: + type: object + properties: + id: + type: integer + name: + type: string + code: + type: string + country: + type: object + properties: + id: + type: integer + name: + type: object + countryCode: + type: string + + AddressReference: + type: object + properties: + id: + type: integer + refId: + type: string + street: + type: string + streetNumber: + type: string + postcode: + type: object + properties: + id: + type: integer + name: + type: string + code: + type: string + country: + type: object + properties: + id: + type: integer + name: + type: object + countryCode: + type: string + municipalityCode: + type: string + source: + type: string + point: + type: object + properties: + type: + type: string + coordinates: + type: array + items: + type: number + minItems: 2 + maxItems: 2 paths: - /1.0/search.json: - get: - summary: perform a search across multiple entities - tags: - - search - - person - - thirdparty - description: > - The search is performed across multiple entities. The entities must be listed into - `type` parameters. - - The results are ordered by relevance, from the most to the lowest relevant. - - parameters: - - name: q - in: query - required: true - description: the pattern to search - schema: - type: string - - name: type[] - in: query - required: true - description: the type entities amongst the search is performed - schema: - type: array - items: - type: string - enum: + /1.0/search.json: + get: + summary: perform a search across multiple entities + tags: + - search - person - thirdparty + description: > + The search is performed across multiple entities. The entities must be listed into + `type` parameters. + + The results are ordered by relevance, from the most to the lowest relevant. + + parameters: + - name: q + in: query + required: true + description: the pattern to search + schema: + type: string + - name: type[] + in: query + required: true + description: the type entities amongst the search is performed + schema: + type: array + items: + type: string + enum: + - person + - thirdparty + - user + responses: + 200: + description: "OK" + /1.0/main/address.json: + get: + tags: + - address + summary: Return a list of all Chill addresses + responses: + 200: + description: "ok" + post: + tags: + - address + summary: create a new address + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + buildingName: + type: string + corridor: + type: string + distribution: + type: string + extra: + type: string + flat: + type: string + floor: + type: string + isNoAddress: + type: boolean + point: + type: array + items: + type: number + minItems: 2 + maxItems: 2 + postcode: + $ref: '#/components/schemas/PostalCode' + steps: + type: string + street: + type: string + streetNumber: + type: string + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + 422: + description: "Unprocessable entity (validation errors)" + 400: + description: "transition cannot be applyed" + patch: + tags: + - address + summary: patch an address + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + buildingName: + type: string + corridor: + type: string + distribution: + type: string + extra: + type: string + flat: + type: string + floor: + type: string + isNoAddress: + type: boolean + point: + type: array + items: + type: number + minItems: 2 + maxItems: 2 + postcode: + $ref: '#/components/schemas/PostalCode' + steps: + type: string + street: + type: string + streetNumber: + type: string + validFrom: + type: string + validTo: + type: string + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + 422: + description: "Unprocessable entity (validation errors)" + 400: + description: "transition cannot be applyed" + + /1.0/main/address/{id}.json: + get: + tags: + - address + summary: Return an address by id + parameters: + - name: id + in: path + required: true + description: The address id + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/Address' + 404: + description: "not found" + 401: + description: "Unauthorized" + + /1.0/main/address/{id}/duplicate.json: + post: + tags: + - address + summary: Duplicate an existing address + parameters: + - name: id + in: path + required: true + description: The address id that will be duplicated + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/Address' + 404: + description: "not found" + 401: + description: "Unauthorized" + + /1.0/main/address-reference.json: + get: + tags: + - address + summary: Return a list of all reference addresses + parameters: + - in: query + name: postal_code + required: false + schema: + type: integer + description: The id of a postal code to filter the reference addresses + responses: + 200: + description: "ok" + /1.0/main/address-reference/{id}.json: + get: + tags: + - address + summary: Return a reference address by id + parameters: + - name: id + in: path + required: true + description: The reference address id + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/AddressReference' + 404: + description: "not found" + 401: + description: "Unauthorized" + + /1.0/main/postal-code.json: + get: + tags: + - address + summary: Return a list of all postal-code + parameters: + - in: query + name: country + required: false + schema: + type: integer + description: The id of a country to filter the postal code + responses: + 200: + description: "ok" + post: + tags: + - address + summary: create a new PostalCode + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + code: + type: string + country: + $ref: '#/components/schemas/Country' + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + 422: + description: "Unprocessable entity (validation errors)" + 400: + description: "transition cannot be applyed" + + /1.0/main/postal-code/{id}.json: + get: + tags: + - address + summary: Return a postal code by id + parameters: + - name: id + in: path + required: true + description: The postal code id + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/PostalCode' + 404: + description: "not found" + 401: + description: "Unauthorized" + + /1.0/main/country.json: + get: + tags: + - address + summary: Return a list of all countries + responses: + 200: + description: "ok" + /1.0/main/country/{id}.json: + get: + tags: + - address + summary: Return a country by id + parameters: + - name: id + in: path + required: true + description: The country id + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/Country' + 404: + description: "not found" + 401: + description: "Unauthorized" + + + /1.0/main/user.json: + get: + tags: - user - responses: - 200: - description: "OK" - /1.0/main/address.json: - get: - tags: - - address - summary: Return a list of all Chill addresses - responses: - 200: - description: "ok" - post: - tags: - - address - summary: create a new address - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - buildingName: - type: string - corridor: - type: string - distribution: - type: string - extra: - type: string - flat: - type: string - floor: - type: string - isNoAddress: - type: boolean - point: - type: array - items: - type: number - minItems: 2 - maxItems: 2 - postcode: - $ref: '#/components/schemas/PostalCode' - steps: - type: string - street: - type: string - streetNumber: - type: string - responses: - 401: - description: "Unauthorized" - 404: - description: "Not found" - 200: - description: "OK" - 422: - description: "Unprocessable entity (validation errors)" - 400: - description: "transition cannot be applyed" - patch: - tags: - - address - summary: patch an address - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - buildingName: - type: string - corridor: - type: string - distribution: - type: string - extra: - type: string - flat: - type: string - floor: - type: string - isNoAddress: - type: boolean - point: - type: array - items: - type: number - minItems: 2 - maxItems: 2 - postcode: - $ref: '#/components/schemas/PostalCode' - steps: - type: string - street: - type: string - streetNumber: - type: string - validFrom: - type: string - validTo: - type: string - responses: - 401: - description: "Unauthorized" - 404: - description: "Not found" - 200: - description: "OK" - 422: - description: "Unprocessable entity (validation errors)" - 400: - description: "transition cannot be applyed" + summary: Return a list of all user + responses: + 200: + description: "ok" + /1.0/main/whoami.json: + get: + tags: + - user + summary: Return the currently authenticated user + responses: + 200: + description: "ok" + /1.0/main/user/{id}.json: + get: + tags: + - user + summary: Return a user by id + parameters: + - name: id + in: path + required: true + description: The user id + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/User' + 404: + description: "not found" + 401: + description: "Unauthorized" - /1.0/main/address/{id}.json: - get: - tags: - - address - summary: Return an address by id - parameters: - - name: id - in: path - required: true - description: The address id - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - content: - application/json: - schema: - $ref: '#/components/schemas/Address' - 404: - description: "not found" - 401: - description: "Unauthorized" + /1.0/main/scope.json: + get: + tags: + - scope + summary: return a list of scopes + responses: + 200: + description: "ok" + 401: + description: "Unauthorized" - /1.0/main/address/{id}/duplicate.json: - post: - tags: - - address - summary: Duplicate an existing address - parameters: - - name: id - in: path - required: true - description: The address id that will be duplicated - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - content: - application/json: - schema: - $ref: '#/components/schemas/Address' - 404: - description: "not found" - 401: - description: "Unauthorized" + /1.0/main/scope/{id}.json: + get: + tags: + - scope + summary: return a list of scopes + parameters: + - name: id + in: path + required: true + description: The scope id + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + 401: + description: "Unauthorized" - /1.0/main/address-reference.json: - get: - tags: - - address - summary: Return a list of all reference addresses - parameters: - - in: query - name: postal_code - required: false - schema: - type: integer - description: The id of a postal code to filter the reference addresses - responses: - 200: - description: "ok" - /1.0/main/address-reference/{id}.json: - get: - tags: - - address - summary: Return a reference address by id - parameters: - - name: id - in: path - required: true - description: The reference address id - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - content: - application/json: - schema: - $ref: '#/components/schemas/AddressReference' - 404: - description: "not found" - 401: - description: "Unauthorized" + /1.0/main/location.json: + get: + tags: + - location + summary: Return a list of locations + responses: + 200: + description: "ok" + 401: + description: "Unauthorized" + post: + tags: + - location + summary: create a new location + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + type: + type: string + name: + type: string + phonenumber1: + type: string + phonenumber2: + type: string + email: + type: string + address: + type: object + properties: + id: + type: integer + locationType: + type: object + properties: + id: + type: integer + type: + type: string + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + 422: + description: "Unprocessable entity (validation errors)" + 400: + description: "transition cannot be applyed" - /1.0/main/postal-code.json: - get: - tags: - - address - summary: Return a list of all postal-code - parameters: - - in: query - name: country - required: false - schema: - type: integer - description: The id of a country to filter the postal code - responses: - 200: - description: "ok" - post: - tags: - - address - summary: create a new PostalCode - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - code: - type: string - country: - $ref: '#/components/schemas/Country' - responses: - 401: - description: "Unauthorized" - 404: - description: "Not found" - 200: - description: "OK" - 422: - description: "Unprocessable entity (validation errors)" - 400: - description: "transition cannot be applyed" + /1.0/main/location/{id}.json: + get: + tags: + - location + summary: Return the given location + parameters: + - name: id + in: path + required: true + description: The location id + schema: + type: integer + format: integer + minimum: 1 + responses: + 200: + description: "ok" + 401: + description: "Unauthorized" - /1.0/main/postal-code/{id}.json: - get: - tags: - - address - summary: Return a postal code by id - parameters: - - name: id - in: path - required: true - description: The postal code id - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - content: - application/json: - schema: - $ref: '#/components/schemas/PostalCode' - 404: - description: "not found" - 401: - description: "Unauthorized" + /1.0/main/location-type.json: + get: + tags: + - location + summary: Return a list of location types + responses: + 200: + description: "ok" + 401: + description: "Unauthorized" - /1.0/main/country.json: - get: - tags: - - address - summary: Return a list of all countries - responses: - 200: - description: "ok" - /1.0/main/country/{id}.json: - get: - tags: - - address - summary: Return a country by id - parameters: - - name: id - in: path - required: true - description: The country id - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - content: - application/json: - schema: - $ref: '#/components/schemas/Country' - 404: - description: "not found" - 401: - description: "Unauthorized" - - - /1.0/main/user.json: - get: - tags: - - user - summary: Return a list of all user - responses: - 200: - description: "ok" - /1.0/main/whoami.json: - get: - tags: - - user - summary: Return the currently authenticated user - responses: - 200: - description: "ok" - /1.0/main/user/{id}.json: - get: - tags: - - user - summary: Return a user by id - parameters: - - name: id - in: path - required: true - description: The user id - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - content: - application/json: - schema: - $ref: '#/components/schemas/User' - 404: - description: "not found" - 401: - description: "Unauthorized" - - /1.0/main/scope.json: - get: - tags: - - scope - summary: return a list of scopes - responses: - 200: - description: "ok" - 401: - description: "Unauthorized" - - /1.0/main/scope/{id}.json: - get: - tags: - - scope - summary: return a list of scopes - parameters: - - name: id - in: path - required: true - description: The scope id - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - 401: - description: "Unauthorized" - - /1.0/main/location.json: - get: - tags: - - location - summary: Return a list of locations - responses: - 200: - description: "ok" - 401: - description: "Unauthorized" - post: - tags: - - location - summary: create a new location - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - type: - type: string - name: - type: string - phonenumber1: - type: string - phonenumber2: - type: string - email: - type: string - address: - type: object - properties: - id: - type: integer - locationType: - type: object - properties: - id: - type: integer - type: - type: string - responses: - 401: - description: "Unauthorized" - 404: - description: "Not found" - 200: - description: "OK" - 422: - description: "Unprocessable entity (validation errors)" - 400: - description: "transition cannot be applyed" - - /1.0/main/location/{id}.json: - get: - tags: - - location - summary: Return the given location - parameters: - - name: id - in: path - required: true - description: The location id - schema: - type: integer - format: integer - minimum: 1 - responses: - 200: - description: "ok" - 401: - description: "Unauthorized" - - /1.0/main/location-type.json: - get: - tags: - - location - summary: Return a list of location types - responses: - 200: - description: "ok" - 401: - description: "Unauthorized" diff --git a/src/Bundle/ChillMainBundle/config/services.yaml b/src/Bundle/ChillMainBundle/config/services.yaml index dd098c75d..8ee24d7b7 100644 --- a/src/Bundle/ChillMainBundle/config/services.yaml +++ b/src/Bundle/ChillMainBundle/config/services.yaml @@ -70,3 +70,4 @@ services: - "@chill.main.security.authorization.helper" - "@security.token_storage" + Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface: '@Chill\MainBundle\Security\Resolver\CenterResolverDispatcher' diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml index 003fce783..0d0a17201 100644 --- a/src/Bundle/ChillMainBundle/config/services/form.yaml +++ b/src/Bundle/ChillMainBundle/config/services/form.yaml @@ -128,4 +128,16 @@ services: Chill\MainBundle\Form\DataTransform\AddressToIdDataTransformer: ~ + Chill\MainBundle\Form\DataTransform\AddressToIdDataTransformer: + autoconfigure: true + autowire: true + + Chill\MainBundle\Form\LocationFormType: + autowire: true + autoconfigure: true + + Chill\MainBundle\Form\UserCurrentLocationType: + autowire: true + autoconfigure: true + Chill\MainBundle\Form\Type\LocationFormType: ~ diff --git a/src/Bundle/ChillMainBundle/config/services/menu.yaml b/src/Bundle/ChillMainBundle/config/services/menu.yaml index a41e90345..97a1d5e89 100644 --- a/src/Bundle/ChillMainBundle/config/services/menu.yaml +++ b/src/Bundle/ChillMainBundle/config/services/menu.yaml @@ -7,8 +7,8 @@ services: resource: '../../Routing/MenuBuilder' Chill\MainBundle\Routing\MenuBuilder\UserMenuBuilder: - arguments: - $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' + autowire: true + autoconfigure: true tags: - { name: 'chill.menu_builder' } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20100000000000.php b/src/Bundle/ChillMainBundle/migrations/Version20100000000000.php new file mode 100644 index 000000000..89454c356 --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20100000000000.php @@ -0,0 +1,28 @@ +addSql('CREATE EXTENSION IF NOT EXISTS unaccent'); + $this->addSql('CREATE EXTENSION IF NOT EXISTS pg_trgm'); + } +} 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 159de82f6..5f15147e4 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'); } - - 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/ChillMainBundle/migrations/Version20210525144016.php b/src/Bundle/ChillMainBundle/migrations/Version20210525144016.php index 3be8d9ea1..f917a5bf1 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210525144016.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210525144016.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_address DROP CONSTRAINT fk_165051f6114b8dd9'); + $this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT fk_165051f6114b8dd9 FOREIGN KEY (linkedtothirdparty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + public function getDescription(): string { return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables'; @@ -22,10 +35,4 @@ final class Version20210525144016 extends AbstractMigration $this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F6114B8DD9'); $this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT FK_165051F6114B8DD9 FOREIGN KEY (linkedToThirdParty_id) REFERENCES chill_3party.third_party (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT fk_165051f6114b8dd9'); - $this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT fk_165051f6114b8dd9 FOREIGN KEY (linkedtothirdparty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210528090000.php b/src/Bundle/ChillMainBundle/migrations/Version20210528090000.php index d2a33230f..09a0a52fd 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210528090000.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210528090000.php @@ -1,5 +1,12 @@ addSql('DROP EXTENSION btree_gist'); + } + public function getDescription(): string { return 'add extension btree_gist'; @@ -21,9 +33,4 @@ final class Version20210528090000 extends AbstractMigration { $this->addSql('CREATE EXTENSION IF NOT EXISTS btree_gist'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP EXTENSION btree_gist'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210610140248.php b/src/Bundle/ChillMainBundle/migrations/Version20210610140248.php index d54ff4634..54160273e 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210610140248.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210610140248.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_notification_addresses_user DROP CONSTRAINT FK_E52C5D2BEF1A9D84'); + $this->addSql('DROP SEQUENCE chill_main_notification_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_main_notification'); + $this->addSql('DROP TABLE chill_main_notification_addresses_user'); + } + public function getDescription(): string { return 'Add table for ChillMain/Notification'; @@ -31,12 +46,4 @@ final class Version20210610140248 extends AbstractMigration $this->addSql('ALTER TABLE chill_main_notification_addresses_user ADD CONSTRAINT FK_E52C5D2BEF1A9D84 FOREIGN KEY (notification_id) REFERENCES chill_main_notification (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_main_notification_addresses_user ADD CONSTRAINT FK_E52C5D2BA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_notification_addresses_user DROP CONSTRAINT FK_E52C5D2BEF1A9D84'); - $this->addSql('DROP SEQUENCE chill_main_notification_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_main_notification'); - $this->addSql('DROP TABLE chill_main_notification_addresses_user'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210616134328.php b/src/Bundle/ChillMainBundle/migrations/Version20210616134328.php index c54f0a183..ed4603b17 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210616134328.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210616134328.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_postal_code DROP origin'); + } + public function getDescription(): string { return ''; @@ -21,9 +33,4 @@ final class Version20210616134328 extends AbstractMigration { $this->addSql('ALTER TABLE chill_main_postal_code ADD origin INT DEFAULT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_postal_code DROP origin'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210903144853.php b/src/Bundle/ChillMainBundle/migrations/Version20210903144853.php index 7fe6b8e72..cfd449dd0 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210903144853.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210903144853.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E964B65C5B'); + $this->addSql('DROP SEQUENCE chill_main_user_job_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_main_user_job'); + $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E92C2125C1'); + $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E9115E73F3'); + $this->addSql('ALTER TABLE users DROP label'); + $this->addSql('ALTER TABLE users DROP mainCenter_id'); + $this->addSql('ALTER TABLE users DROP mainScope_id'); + $this->addSql('ALTER TABLE users DROP userJob_id'); + $this->addSql('ALTER TABLE users ALTER usernameCanonical DROP NOT NULL'); + } + public function getDescription(): string { return 'Add metadata on users'; @@ -35,18 +56,4 @@ final class Version20210903144853 extends AbstractMigration $this->addSql('CREATE INDEX IDX_1483A5E9115E73F3 ON users (mainScope_id)'); $this->addSql('CREATE INDEX IDX_1483A5E964B65C5B ON users (userJob_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E964B65C5B'); - $this->addSql('DROP SEQUENCE chill_main_user_job_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_main_user_job'); - $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E92C2125C1'); - $this->addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E9115E73F3'); - $this->addSql('ALTER TABLE users DROP label'); - $this->addSql('ALTER TABLE users DROP mainCenter_id'); - $this->addSql('ALTER TABLE users DROP mainScope_id'); - $this->addSql('ALTER TABLE users DROP userJob_id'); - $this->addSql('ALTER TABLE users ALTER usernameCanonical DROP NOT NULL'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210929192242.php b/src/Bundle/ChillMainBundle/migrations/Version20210929192242.php index a2fbefa69..5e22201c3 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210929192242.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210929192242.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_address DROP addressReference_id'); + } + public function getDescription(): string { return 'Add a link between address and address reference'; @@ -23,9 +35,4 @@ final class Version20210929192242 extends AbstractMigration $this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT FK_165051F647069464 FOREIGN KEY (addressReference_id) REFERENCES chill_main_address_reference (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_165051F647069464 ON chill_main_address (addressReference_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_address DROP addressReference_id'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211006151653.php b/src/Bundle/ChillMainBundle/migrations/Version20211006151653.php index 9f4508ba8..c564c30eb 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211006151653.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211006151653.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_postal_code DROP refPostalCodeId'); + $this->addSql('ALTER TABLE chill_main_postal_code DROP postalCodeSource'); + $this->addSql('ALTER TABLE chill_main_postal_code DROP center'); + } + public function getDescription(): string { return 'Add some fields to PostalCode'; @@ -23,11 +37,4 @@ final class Version20211006151653 extends AbstractMigration $this->addSql('ALTER TABLE chill_main_postal_code ADD postalCodeSource VARCHAR(255) DEFAULT NULL'); $this->addSql('ALTER TABLE chill_main_postal_code ADD center geometry(POINT,4326) DEFAULT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_postal_code DROP refPostalCodeId'); - $this->addSql('ALTER TABLE chill_main_postal_code DROP postalCodeSource'); - $this->addSql('ALTER TABLE chill_main_postal_code DROP center'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211007150019.php b/src/Bundle/ChillMainBundle/migrations/Version20211007150019.php index b81c7f74e..33cb2fd42 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211007150019.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211007150019.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_main_civility_id_seq'); + $this->addSql('DROP TABLE chill_main_civility'); + } + public function getDescription(): string { return 'create civility table'; @@ -22,10 +35,4 @@ final class Version20211007150019 extends AbstractMigration $this->addSql('CREATE SEQUENCE chill_main_civility_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE chill_main_civility (id INT NOT NULL, name JSON NOT NULL, abbreviation JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP SEQUENCE chill_main_civility_id_seq'); - $this->addSql('DROP TABLE chill_main_civility'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211012141336.php b/src/Bundle/ChillMainBundle/migrations/Version20211012141336.php index 4ed8da1dc..4d1050b94 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211012141336.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211012141336.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activity DROP CONSTRAINT FK_AC74095A64D218E'); + $this->addSql('ALTER TABLE activity DROP location_id'); + + $this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315AC64D218E'); + $this->addSql('ALTER TABLE chill_calendar.calendar DROP location_id'); + + $this->addSql('ALTER TABLE chill_main_location DROP CONSTRAINT FK_90E4736AB8B0DA8E'); + + $this->addSql('DROP SEQUENCE chill_main_location_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_main_location_type_id_seq CASCADE'); + + $this->addSql('DROP TABLE chill_main_location'); + $this->addSql('DROP TABLE chill_main_location_type'); + } + public function getDescription(): string { return 'Add Location and LocationType Entities (for activity and calendar)'; @@ -45,22 +69,4 @@ final class Version20211012141336 extends AbstractMigration $this->addSql('ALTER TABLE chill_calendar.calendar ADD CONSTRAINT FK_712315AC64D218E FOREIGN KEY (location_id) REFERENCES chill_main_location (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_712315AC64D218E ON chill_calendar.calendar (location_id)'); } - - public function down(Schema $schema): void - { - - $this->addSql('ALTER TABLE activity DROP CONSTRAINT FK_AC74095A64D218E'); - $this->addSql('ALTER TABLE activity DROP location_id'); - - $this->addSql('ALTER TABLE chill_calendar.calendar DROP CONSTRAINT FK_712315AC64D218E'); - $this->addSql('ALTER TABLE chill_calendar.calendar DROP location_id'); - - $this->addSql('ALTER TABLE chill_main_location DROP CONSTRAINT FK_90E4736AB8B0DA8E'); - - $this->addSql('DROP SEQUENCE chill_main_location_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_main_location_type_id_seq CASCADE'); - - $this->addSql('DROP TABLE chill_main_location'); - $this->addSql('DROP TABLE chill_main_location_type'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211013124455.php b/src/Bundle/ChillMainBundle/migrations/Version20211013124455.php index 0d30cece5..c40446834 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211013124455.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211013124455.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activitytype DROP locationVisible'); + $this->addSql('ALTER TABLE activitytype DROP locationLabel'); + + // fix old migration !? + $this->addSql('ALTER TABLE activitytype ALTER category_id SET DEFAULT 1'); + } + public function getDescription(): string { return 'add location visible admin option'; @@ -21,16 +37,5 @@ final class Version20211013124455 extends AbstractMigration // fix old migration !? $this->addSql('ALTER TABLE activitytype ALTER category_id DROP DEFAULT'); - - } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE activitytype DROP locationVisible'); - $this->addSql('ALTER TABLE activitytype DROP locationLabel'); - - // fix old migration !? - $this->addSql('ALTER TABLE activitytype ALTER category_id SET DEFAULT 1'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211015084653.php b/src/Bundle/ChillMainBundle/migrations/Version20211015084653.php index 12b230f10..52cf53aac 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211015084653.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211015084653.php @@ -1,5 +1,12 @@ addSql('DROP INDEX IDX_90E4736AF5B7AF75'); + $this->addSql('CREATE UNIQUE INDEX uniq_90e4736af5b7af75 ON chill_main_location (address_id)'); + } + public function getDescription(): string { return 'Location entity: change Address to ManyToOne'; @@ -16,13 +29,7 @@ final class Version20211015084653 extends AbstractMigration public function up(Schema $schema): void { - $this->addSql('DROP INDEX uniq_90e4736af5b7af75'); - $this->addSql('CREATE INDEX IDX_90E4736AF5B7AF75 ON chill_main_location (address_id)'); - } - - public function down(Schema $schema): void - { - $this->addSql('DROP INDEX IDX_90E4736AF5B7AF75'); - $this->addSql('CREATE UNIQUE INDEX uniq_90e4736af5b7af75 ON chill_main_location (address_id)'); + $this->addSql('DROP INDEX uniq_90e4736af5b7af75'); + $this->addSql('CREATE INDEX IDX_90E4736AF5B7AF75 ON chill_main_location (address_id)'); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211022094429.php b/src/Bundle/ChillMainBundle/migrations/Version20211022094429.php index 1bc4f68d0..f11dbf42b 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211022094429.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211022094429.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_location_type DROP active'); + $this->addSql('ALTER TABLE chill_main_location DROP active'); + } + public function getDescription(): string { return 'Add active on Location and LocationType'; @@ -22,10 +35,4 @@ final class Version20211022094429 extends AbstractMigration $this->addSql('ALTER TABLE chill_main_location ADD active BOOLEAN DEFAULT TRUE;'); $this->addSql('ALTER TABLE chill_main_location_type ADD active BOOLEAN DEFAULT TRUE;'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_location_type DROP active'); - $this->addSql('ALTER TABLE chill_main_location DROP active'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php b/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php new file mode 100644 index 000000000..d9011049f --- /dev/null +++ b/src/Bundle/ChillMainBundle/migrations/Version20211116162847.php @@ -0,0 +1,40 @@ +addSql('ALTER TABLE users DROP CONSTRAINT FK_1483A5E93C219753'); + $this->addSql('DROP INDEX IDX_1483A5E93C219753'); + $this->addSql('ALTER TABLE users DROP currentLocation_id'); + } + + public function getDescription(): string + { + return 'Add current location to User entity'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE users ADD currentLocation_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE users ADD CONSTRAINT FK_1483A5E93C219753 FOREIGN KEY (currentLocation_id) REFERENCES chill_main_location (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_1483A5E93C219753 ON users (currentLocation_id)'); + } +} diff --git a/src/Bundle/ChillMainBundle/migrations/Version20211119173554.php b/src/Bundle/ChillMainBundle/migrations/Version20211119173554.php index d8f705f39..9494337fd 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20211119173554.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20211119173554.php @@ -1,5 +1,12 @@ throwIrreversibleMigrationException(); + } + public function getDescription(): string { return 'remove comment on deprecated json_array type'; @@ -20,16 +32,11 @@ final class Version20211119173554 extends AbstractMigration public function up(Schema $schema): void { $columns = [ - 'users.attributes' + 'users.attributes', ]; foreach ($columns as $col) { - $this->addSql("COMMENT ON COLUMN $col IS NULL"); + $this->addSql("COMMENT ON COLUMN {$col} IS NULL"); } } - - public function down(Schema $schema): void - { - $this->throwIrreversibleMigrationException(); - } } diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 9b9ceb204..210227fbe 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -180,6 +180,13 @@ Flags: Drapeaux # admin section for users jobs User jobs: Métiers +# user page for current location +Current location: Localisation actuelle +Edit my current location: Éditer ma localisation actuelle +Change current location: Changer ma localisation actuelle +Set a location: Indiquer une localisation +Current location successfully updated: Localisation actuelle mise à jour +Pick a location: Choisir un lieu #admin section for circles (old: scopes) List circles: Cercles @@ -204,8 +211,7 @@ Location list: Liste des localisations Location type: Type de localisation Phonenumber1: Numéro de téléphone Phonenumber2: Autre numéro de téléphone -Configure location: Configuration des localisations -Configure location type: Configuration des types de localisations +Configure location and location type: Configuration des localisations # circles / scopes Choose the circle: Choisir le cercle diff --git a/src/Bundle/ChillPersonBundle/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodLinkedWithSocialIssuesEntityInterface.php b/src/Bundle/ChillPersonBundle/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodLinkedWithSocialIssuesEntityInterface.php index 0f1922435..c281ff087 100644 --- a/src/Bundle/ChillPersonBundle/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodLinkedWithSocialIssuesEntityInterface.php +++ b/src/Bundle/ChillPersonBundle/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodLinkedWithSocialIssuesEntityInterface.php @@ -1,13 +1,20 @@ ensureConsistencyEntity($entity); } - public function preUpdate(AccompanyingPeriodLinkedWithSocialIssuesEntityInterface $entity, LifecycleEventArgs $eventArgs) - { - $this->ensureConsistencyEntity($entity); - } - public function prePersistAccompanyingPeriod(AccompanyingPeriod $period, LifecycleEventArgs $eventArgs) { $this->ensureConsistencyAccompanyingPeriod($period); } - public function preUpdateAccompanyingPeriod(AccompanyingPeriod $period, LifecycleEventArgs $eventArgs) + public function preUpdate(AccompanyingPeriodLinkedWithSocialIssuesEntityInterface $entity, LifecycleEventArgs $eventArgs) { - $this->ensureConsistencyAccompanyingPeriod($period); + $this->ensureConsistencyEntity($entity); } - private function ensureConsistencyEntity(AccompanyingPeriodLinkedWithSocialIssuesEntityInterface $entity): void + public function preUpdateAccompanyingPeriod(AccompanyingPeriod $period, LifecycleEventArgs $eventArgs) { - if (NULL === $period = $entity->getAccompanyingPeriod()) { - return; - } - // remove issues parents on the entity itself - $ancestors = SocialIssue::findAncestorSocialIssues($entity->getSocialIssues()); - foreach ($ancestors as $ancestor) { - $entity->removeSocialIssue($ancestor); - } - - foreach ($entity->getSocialIssues() as $issue) { - // the entity itself test if the social issue is already associated, or not - $period->addSocialIssue($issue); - } - $this->ensureConsistencyAccompanyingPeriod($period); } @@ -64,4 +52,24 @@ final class AccompanyingPeriodSocialIssueConsistencyEntityListener $period->removeSocialIssue($ancestor); } } + + private function ensureConsistencyEntity(AccompanyingPeriodLinkedWithSocialIssuesEntityInterface $entity): void + { + if (null === $period = $entity->getAccompanyingPeriod()) { + return; + } + // remove issues parents on the entity itself + $ancestors = SocialIssue::findAncestorSocialIssues($entity->getSocialIssues()); + + foreach ($ancestors as $ancestor) { + $entity->removeSocialIssue($ancestor); + } + + foreach ($entity->getSocialIssues() as $issue) { + // the entity itself test if the social issue is already associated, or not + $period->addSocialIssue($issue); + } + + $this->ensureConsistencyAccompanyingPeriod($period); + } } diff --git a/src/Bundle/ChillPersonBundle/AccompanyingPeriod/Suggestion/ReferralsSuggestion.php b/src/Bundle/ChillPersonBundle/AccompanyingPeriod/Suggestion/ReferralsSuggestion.php index b28dcce79..7f484d807 100644 --- a/src/Bundle/ChillPersonBundle/AccompanyingPeriod/Suggestion/ReferralsSuggestion.php +++ b/src/Bundle/ChillPersonBundle/AccompanyingPeriod/Suggestion/ReferralsSuggestion.php @@ -1,12 +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\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..afd844610 100644 --- a/src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php +++ b/src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php @@ -1,54 +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\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 +47,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..d3c9669e0 100644 --- a/src/Bundle/ChillPersonBundle/CRUD/Controller/EntityPersonCRUDController.php +++ b/src/Bundle/ChillPersonBundle/CRUD/Controller/EntityPersonCRUDController.php @@ -1,113 +1,125 @@ + +/** + * 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 +127,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 7a1379434..684f78d61 100644 --- a/src/Bundle/ChillPersonBundle/CRUD/Controller/OneToOneEntityPersonCRUDController.php +++ b/src/Bundle/ChillPersonBundle/CRUD/Controller/OneToOneEntityPersonCRUDController.php @@ -1,44 +1,37 @@ 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 implemented 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() @@ -51,23 +44,40 @@ class OneToOneEntityPersonCRUDController extends CRUDController return $entity; } - protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request) + protected function getTemplateFor($action, $entity, Request $request) { - $this->getDoctrine()->getManager()->persist($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'); + } } protected function onPostFetchEntity($action, Request $request, $entity): ?Response { - if (FALSE === $this->getDoctrine()->getManager()->contains($entity)) { + if (false === $this->getDoctrine()->getManager()->contains($entity)) { return new RedirectResponse($this->generateRedirectOnCreateRoute($action, $request, $entity)); } return null; } - protected function generateRedirectOnCreateRoute($action, Request $request, $entity) + protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request) { - throw new BadMethodCallException('Not implemented yet.'); + $this->getDoctrine()->getManager()->persist($entity); } - } 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 b68997ed6..d45522871 100644 --- a/src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php +++ b/src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php @@ -1,24 +1,32 @@ 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); } @@ -97,25 +105,28 @@ final class ChillPersonMoveCommand extends Command } $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) + protected function interact(InputInterface $input, OutputInterface $output) { - $ctxt = [ - 'from' => $from->getId(), - 'to' => $to->getId() - ]; + if (false === $input->hasOption('dump-sql') && false === $input->hasOption('force')) { + $msg = 'You must use "--dump-sql" or "--force"'; - foreach ($deleteEntities as $key => $de) { - $ctxt['delete_entity_'.$key] = $de; - } - foreach ($sqls as $key => $sql) { - $ctxt['sql_'.$key] = $sql; + throw new RuntimeException($msg); } - return $ctxt; + 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 9b73fa817..e0ba03194 100644 --- a/src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php +++ b/src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php @@ -1,57 +1,56 @@ 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) @@ -229,122 +143,242 @@ EOF return $this; } - /** - * @param InputInterface $input - * @param OutputInterface $output - */ - protected function interact(InputInterface $input, OutputInterface $output) + protected function configure() { - // preparing the basic - $this->input = $input; - $this->output = $output; - $this->logger = new ConsoleLogger($output); + $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. - $csv = $this->openCSV(); + 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 - // getting the first row - if (($row = fgetcsv( - $csv, - $input->getOption('length'), - $input->getOption('delimiter'), - $input->getOption('enclosure'), - $input->getOption('escape'))) !== false) { + 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' + ); - try { - $this->matchColumnToCustomField($row); - } finally { - $this->logger->debug('closing csv', array('method' => __METHOD__)); - fclose($csv); - } + // mapping columns + foreach (self::$mapping as $m) { + $this->addOptionShortcut($m[0], $m[1], $m[2]); } - // 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); - } - } + // 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 $headers the processed header : an array as prepared by self::processingHeaders * + * @throws Exception */ + protected function createPerson(array $row, array $headers): Person + { + // trying to get the opening date + $openingDateString = trim($row[array_search('opening_date', $headers)]); + $openingDate = $this->processDate($openingDateString, $this->input->getOption('opening_date_format')); + + // @TODO: Fix the constructor parameter, $openingDate does not exists. + $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(); @@ -355,10 +389,9 @@ EOF } /** - * @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) { @@ -366,7 +399,7 @@ EOF $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 @@ -376,14 +409,16 @@ EOF $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); @@ -407,16 +442,16 @@ EOF $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) { @@ -424,7 +459,7 @@ EOF $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(); @@ -432,156 +467,7 @@ EOF } /** - * - * @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; - } - - /** - * @return array where keys are column number, and value is information mapped - */ - protected function processingHeaders(array $firstRow): array - { - $availableOptions = array_map( - static fn (array $m) => $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; - } - - /** - * @param array $headers the processed header : an array as prepared by self::processingHeaders - * @throws \Exception - */ - protected function createPerson(array $row, array $headers): Person - { - // trying to get the opening date - $openingDateString = trim($row[array_search('opening_date', $headers)]); - $openingDate = $this->processDate($openingDateString, $this->input->getOption('opening_date_format')); - - // @TODO: Fix the constructor parameter, $openingDate does not exists. - $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; - } - - /** - * @return Center|mixed|null|object + * @return Center|mixed|object|null */ protected function getCenter(array $row, array $headers) { @@ -607,27 +493,27 @@ EOF /** * @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)) { @@ -636,31 +522,32 @@ EOF } $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; + 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) - ; + ->setName($centerName); - if ($this->input->getOption('force') === TRUE) { + if ($this->input->getOption('force') === true) { $this->em->persist($center); $this->em->flush(); } @@ -679,31 +566,32 @@ EOF /** * @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 @@ -717,7 +605,7 @@ EOF } $postalCodeByName = []; - $names = \array_map(function(PostalCode $pc) use (&$postalCodeByName) { + $names = \array_map(function (PostalCode $pc) use (&$postalCodeByName) { $n = $pc->getName(); $postalCodeByName[$n] = $pc; @@ -726,15 +614,21 @@ EOF $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; } @@ -746,22 +640,160 @@ EOF 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; } + if (empty($value)) { + return; + } $date = $this->processDate($value, $this->input->getOption('birthdate_format')); - if ($date instanceof \DateTime) { + 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')); + if ($date > new DateTime('yesterday')) { + $date = $date->sub(new DateInterval('P100Y')); } $person->setBirthdate($date); @@ -771,120 +803,12 @@ EOF // 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)); - + '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); - } - - } - - $person->setCFData($cfData); - } - - /** - * 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. * @@ -892,17 +816,16 @@ 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']); @@ -910,102 +833,294 @@ EOF // 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() - ); + "The question '%s' with slug '%s' does not count any answer.", + $this->helper->localize($cf->getName()), + $cf->getSlug() + ); - $this->logger->error($message, array( + $this->logger->error($message, [ 'method' => __METHOD__, 'slug' => $cf->getSlug(), - 'question' => $this->helper->localize($cf->getName()) - )); + 'question' => $this->helper->localize($cf->getName()), + ]); - throw new \RuntimeException($message); + 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->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])); + 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; $matchingTableRowAnswer = []; - 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( + $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->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); + } + + /** + * @return array where keys are column number, and value is information mapped + */ + protected function processingHeaders(array $firstRow): array + { + $availableOptions = array_map( + static fn (array $m) => $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; } @@ -1014,69 +1129,32 @@ EOF * 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/Command/ImportSocialWorkMetadata.php b/src/Bundle/ChillPersonBundle/Command/ImportSocialWorkMetadata.php index e42f0ef26..b04cff13a 100644 --- a/src/Bundle/ChillPersonBundle/Command/ImportSocialWorkMetadata.php +++ b/src/Bundle/ChillPersonBundle/Command/ImportSocialWorkMetadata.php @@ -1,26 +1,30 @@ setDelimiter(';'); return true === $this->importer->import($csv) ? - 0: + 0 : 1; } } 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 0941dd7d4..7c19864bd 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -1,41 +1,53 @@ referralAvailable = $referralAvailable; } + public function commentApi($id, Request $request, string $_format): Response + { + return $this->addRemoveSomething('comment', $id, $request, $_format, 'comment', Comment::class); + } + public function confirmApi($id, Request $request, $_format): Response { /** @var AccompanyingPeriod $accompanyingPeriod */ @@ -58,10 +75,11 @@ final class AccompanyingCourseApiController extends ApiController $this->checkACL('confirm', $request, $_format, $accompanyingPeriod); $workflow = $this->registry->get($accompanyingPeriod); - if (FALSE === $workflow->can($accompanyingPeriod, 'confirm')) { + if (false === $workflow->can($accompanyingPeriod, 'confirm')) { // throw new BadRequestException('It is not possible to confirm this period'); $errors = $this->validator->validate($accompanyingPeriod, null, [$accompanyingPeriod::STEP_CONFIRMED]); - if( count($errors) > 0 ){ + + if (count($errors) > 0) { return $this->json($errors, 422); } } @@ -71,10 +89,26 @@ final class AccompanyingCourseApiController extends ApiController $this->getDoctrine()->getManager()->flush(); return $this->json($accompanyingPeriod, Response::HTTP_OK, [], [ - 'groups' => [ 'read' ] + 'groups' => ['read'], ]); } + /** + * @ParamConverter("person", options={"id": "person_id"}) + */ + public function getAccompanyingPeriodsByPerson(Person $person) + { + $accompanyingPeriods = $person->getCurrentAccompanyingPeriods(); + $accompanyingPeriodsChecked = array_filter( + $accompanyingPeriods, + function (AccompanyingPeriod $period) { + return $this->isGranted(AccompanyingPeriodVoter::SEE, $period); + } + ); + + return $this->json(array_values($accompanyingPeriodsChecked), Response::HTTP_OK, [], ['groups' => ['read']]); + } + public function participationApi($id, Request $request, $_format) { /** @var AccompanyingPeriod $accompanyingPeriod */ @@ -82,7 +116,7 @@ final class AccompanyingCourseApiController extends ApiController $person = $this->getSerializer() ->deserialize($request->getContent(), Person::class, $_format, []); - if (NULL === $person) { + if (null === $person) { throw new BadRequestException('person id not found'); } @@ -93,12 +127,16 @@ final class AccompanyingCourseApiController extends ApiController switch ($request->getMethod()) { case Request::METHOD_POST: $participation = $accompanyingPeriod->createParticipationFor($person); + break; + case Request::METHOD_DELETE: $participation = $accompanyingPeriod->closeParticipationFor($person); + break; + default: - throw new BadRequestException("This method is not supported"); + throw new BadRequestException('This method is not supported'); } $errors = $this->validator->validate($accompanyingPeriod); @@ -110,48 +148,7 @@ final class AccompanyingCourseApiController extends ApiController $this->getDoctrine()->getManager()->flush(); - return $this->json($participation, 200, [], ['groups' => [ 'read' ]]); - } - - public function resourceApi($id, Request $request, string $_format): Response - { - $accompanyingPeriod = $this->getEntity('resource', $id, $request); - $errors = $this->validator->validate($accompanyingPeriod); - - if ($errors->count() > 0) { - return $this->json($errors, 422); - } - - return $this->addRemoveSomething('resource', $id, $request, $_format, 'resource', Resource::class); - } - - public function scopeApi($id, Request $request, string $_format): Response - { - return $this->addRemoveSomething('scope', $id, $request, $_format, 'scope', Scope::class, [ 'groups' => [ 'read' ] ]); - } - - public function commentApi($id, Request $request, string $_format): Response - { - return $this->addRemoveSomething('comment', $id, $request, $_format, 'comment', Comment::class); - } - - public function socialIssueApi($id, Request $request, string $_format): Response - { - return $this->addRemoveSomething('socialissue', $id, $request, $_format, 'socialIssue', SocialIssue::class, [ 'groups' => [ 'read' ] ]); - } - - public function workApi($id, Request $request, string $_format): Response - { - return $this->addRemoveSomething( - 'work', - $id, - $request, - $_format, - 'work', - AccompanyingPeriodWork::class, - [ 'groups' => [ 'accompanying_period_work:create' ] ], - true // force persist - ); + return $this->json($participation, 200, [], ['groups' => ['read']]); } public function requestorApi($id, Request $request, string $_format): Response @@ -165,10 +162,11 @@ final class AccompanyingCourseApiController extends ApiController $this->onPostCheckACL($action, $request, $_format, $accompanyingPeriod); if (Request::METHOD_DELETE === $request->getMethod()) { - $accompanyingPeriod->setRequestor(NULL); + $accompanyingPeriod->setRequestor(null); } elseif (Request::METHOD_POST === $request->getMethod()) { $requestor = null; $exceptions = []; + foreach ([Person::class, ThirdParty::class] as $class) { try { $requestor = $this->getSerializer() @@ -177,7 +175,8 @@ final class AccompanyingCourseApiController extends ApiController $exceptions[] = $e; } } - if ($requestor === null) { + + if (null === $requestor) { throw new BadRequestException('Could not find any person or requestor', 0, $exceptions[0]); } @@ -195,40 +194,35 @@ final class AccompanyingCourseApiController extends ApiController $this->getDoctrine()->getManager()->flush(); - return $this->json($accompanyingPeriod->getRequestor(), 200, [], ['groups' => [ 'read']]); + return $this->json($accompanyingPeriod->getRequestor(), 200, [], ['groups' => ['read']]); } - protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response + public function resourceApi($id, Request $request, string $_format): Response { - $this->eventDispatcher->dispatch( - AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT, - new AccompanyingPeriodPrivacyEvent($entity, [ - 'action' => $action, - 'request' => $request->getMethod() - ]) - ); + $accompanyingPeriod = $this->getEntity('resource', $id, $request); + $errors = $this->validator->validate($accompanyingPeriod); - return null; + if ($errors->count() > 0) { + return $this->json($errors, 422); + } + + return $this->addRemoveSomething('resource', $id, $request, $_format, 'resource', Resource::class); } - /** - * @ParamConverter("person", options={"id" = "person_id"}) - */ - public function getAccompanyingPeriodsByPerson(Person $person){ - $accompanyingPeriods = $person->getCurrentAccompanyingPeriods(); - $accompanyingPeriodsChecked = array_filter($accompanyingPeriods, - function(AccompanyingPeriod $period){ - return $this->isGranted(AccompanyingPeriodVoter::SEE, $period); - }); - return $this->json(\array_values($accompanyingPeriodsChecked), Response::HTTP_OK, [], ['groups' => [ 'read']]); + public function scopeApi($id, Request $request, string $_format): Response + { + return $this->addRemoveSomething('scope', $id, $request, $_format, 'scope', Scope::class, ['groups' => ['read']]); + } + + public function socialIssueApi($id, Request $request, string $_format): Response + { + return $this->addRemoveSomething('socialissue', $id, $request, $_format, 'socialIssue', SocialIssue::class, ['groups' => ['read']]); } /** * @Route("/api/1.0/person/accompanying-course/{id}/referrers-suggested.{_format}", - * requirements={ "_format"="json"}, - * name="chill_api_person_accompanying_period_referrers_suggested") - * @param AccompanyingPeriod $period - * @return JsonResponse + * requirements={ "_format": "json"}, + * name="chill_api_person_accompanying_period_referrers_suggested") */ public function suggestReferrals(AccompanyingPeriod $period, string $_format = 'json'): JsonResponse { @@ -238,13 +232,47 @@ final class AccompanyingCourseApiController extends ApiController $paginator = $this->getPaginatorFactory()->create($total); if (0 < $total) { - $users = $this->referralAvailable->findReferralSuggested($period, $paginator->getItemsPerPage(), - $paginator->getCurrentPageFirstItemNumber()); + $users = $this->referralAvailable->findReferralSuggested( + $period, + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); } else { $users = []; } - return $this->json(new Collection($users, $paginator), Response::HTTP_OK, - [], [ AbstractNormalizer::GROUPS => [ 'read' ]]); + return $this->json( + new Collection($users, $paginator), + Response::HTTP_OK, + [], + [AbstractNormalizer::GROUPS => ['read']] + ); + } + + public function workApi($id, Request $request, string $_format): Response + { + return $this->addRemoveSomething( + 'work', + $id, + $request, + $_format, + 'work', + AccompanyingPeriodWork::class, + ['groups' => ['accompanying_period_work:create']], + true // force persist + ); + } + + protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response + { + $this->eventDispatcher->dispatch( + AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT, + new AccompanyingPeriodPrivacyEvent($entity, [ + 'action' => $action, + 'request' => $request->getMethod(), + ]) + ); + + return null; } } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php index 5c11f4802..7af13ccd4 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php @@ -1,91 +1,148 @@ serializer = $serializer; $this->dispatcher = $dispatcher; $this->validator = $validator; $this->workRepository = $workRepository; + $this->registry = $registry; + $this->translator = $translator; } /** - * @Route("/{_locale}/person/parcours/new", name="chill_person_accompanying_course_new") + * @Route("/{_locale}/parcours/{accompanying_period_id}/close", name="chill_person_accompanying_course_close") + * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) */ - public function newAction(Request $request): Response + public function closeAction(AccompanyingPeriod $accompanyingCourse, Request $request): Response { - $period = new AccompanyingPeriod(); - $em = $this->getDoctrine()->getManager(); + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $accompanyingCourse); - if ($request->query->has('person_id')) { - $personIds = $request->query->get('person_id'); + $form = $this->createForm(AccompanyingCourseType::class, $accompanyingCourse, [ + 'validation_groups' => [AccompanyingPeriod::STEP_CLOSED], + ]); - if (FALSE === \is_array($personIds)) { - throw new BadRequestException("person_id parameter should be an array"); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + + $workflow = $this->registry->get($accompanyingCourse); + + if ($workflow->can($accompanyingCourse, 'close')) { + $workflow->apply($accompanyingCourse, 'close'); + + $em->flush(); + + return $this->redirectToRoute('chill_person_accompanying_course_index', [ + 'accompanying_period_id' => $accompanyingCourse->getId(), + ]); } + /** @var ConstraintViolationListInterface $errors */ + $errors = $this->validator->validate($accompanyingCourse, null, [$accompanyingCourse::STEP_CLOSED]); + $this->addFlash('error', $this->translator->trans('It is not possible to close this course')); - foreach ($personIds as $personId) { - $person = $em->getRepository(Person::class)->find($personId); - if (NULL !== $person) { - $period->addPerson($person); - } + foreach ($errors as $e) { + /** @var ConstraintViolationInterface $e */ + $this->addFlash('error', $e->getMessage()); } } - $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::CREATE, $period); - - $em->persist($period); - $em->flush(); - - return $this->redirectToRoute('chill_person_accompanying_course_edit', [ - 'accompanying_period_id' => $period->getId() + return $this->render('@ChillPerson/AccompanyingCourse/close.html.twig', [ + 'form' => $form->createView(), + 'accompanyingCourse' => $accompanyingCourse, ]); - } /** - * Homepage of Accompanying Course section + * Edit page of Accompanying Course section. + * + * the page edit all blocks managed by vuejs component + * + * @Route("/{_locale}/parcours/{accompanying_period_id}/edit", name="chill_person_accompanying_course_edit") + * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) + */ + public function editAction(AccompanyingPeriod $accompanyingCourse): Response + { + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse); + + return $this->render('@ChillPerson/AccompanyingCourse/edit.html.twig', [ + 'accompanyingCourse' => $accompanyingCourse, + ]); + } + + /** + * History page of Accompanying Course section. + * + * the page show anti chronologic history with all actions, title of page is 'Accompanying Course History' + * + * @Route("/{_locale}/parcours/{accompanying_period_id}/history", name="chill_person_accompanying_course_history") + * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) + */ + public function historyAction(AccompanyingPeriod $accompanyingCourse): Response + { + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse); + + return $this->render('@ChillPerson/AccompanyingCourse/history.html.twig', [ + 'accompanyingCourse' => $accompanyingCourse, + ]); + } + + /** + * Homepage of Accompanying Course section. * * @Route("/{_locale}/parcours/{accompanying_period_id}", name="chill_person_accompanying_course_index") * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) @@ -97,9 +154,9 @@ class AccompanyingCourseController extends Controller // compute some warnings // get persons without household $withoutHousehold = []; - foreach ($accompanyingCourse->getParticipations() as - $p) { - if (FALSE === $p->getPerson()->isSharingHousehold()) { + + foreach ($accompanyingCourse->getParticipations() as $p) { + if (false === $p->getPerson()->isSharingHousehold()) { $withoutHousehold[] = $p->getPerson(); } } @@ -120,42 +177,41 @@ class AccompanyingCourseController extends Controller 'withoutHousehold' => $withoutHousehold, 'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(), 'works' => $works, - 'activities' => $activities + 'activities' => $activities, ]); } /** - * Edit page of Accompanying Course section - * - * the page edit all blocks managed by vuejs component - * - * @Route("/{_locale}/parcours/{accompanying_period_id}/edit", name="chill_person_accompanying_course_edit") - * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) + * @Route("/{_locale}/person/parcours/new", name="chill_person_accompanying_course_new") */ - public function editAction(AccompanyingPeriod $accompanyingCourse): Response + public function newAction(Request $request): Response { - $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse); + $period = new AccompanyingPeriod(); + $em = $this->getDoctrine()->getManager(); - return $this->render('@ChillPerson/AccompanyingCourse/edit.html.twig', [ - 'accompanyingCourse' => $accompanyingCourse + if ($request->query->has('person_id')) { + $personIds = $request->query->get('person_id'); + + if (false === is_array($personIds)) { + throw new BadRequestException('person_id parameter should be an array'); + } + + foreach ($personIds as $personId) { + $person = $em->getRepository(Person::class)->find($personId); + + if (null !== $person) { + $period->addPerson($person); + } + } + } + + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::CREATE, $period); + + $em->persist($period); + $em->flush(); + + return $this->redirectToRoute('chill_person_accompanying_course_edit', [ + 'accompanying_period_id' => $period->getId(), ]); } - - /** - * History page of Accompanying Course section - * - * the page show anti chronologic history with all actions, title of page is 'Accompanying Course History' - * - * @Route("/{_locale}/parcours/{accompanying_period_id}/history", name="chill_person_accompanying_course_history") - * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) - */ - public function historyAction(AccompanyingPeriod $accompanyingCourse): Response - { - $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $accompanyingCourse); - - return $this->render('@ChillPerson/AccompanyingCourse/history.html.twig', [ - 'accompanyingCourse' => $accompanyingCourse - ]); - } - } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkApiController.php index 6263736b0..5383305ce 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkApiController.php @@ -1,5 +1,12 @@ getMethod()) { case Request::METHOD_PUT: - return [ 'groups' => [ 'accompanying_period_work:edit' ] ]; + return ['groups' => ['accompanying_period_work:edit']]; } } return parent::getContextForSerialization($action, $request, $_format, $entity); } - } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php index cf935b7c3..bb85036a9 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseWorkController.php @@ -1,29 +1,40 @@ getSocialIssues()->count() === 0) { - $this->addFlash('error', $this->trans->trans( - "accompanying_work.You must add at least ". - "one social issue on accompanying period") + $this->addFlash( + 'error', + $this->trans->trans( + 'accompanying_work.You must add at least ' . + 'one social issue on accompanying period' + ) ); return $this->redirectToRoute('chill_person_accompanying_course_index', [ - 'accompanying_period_id' => $period->getId() + 'accompanying_period_id' => $period->getId(), ]); } - $json = $this->serializer->normalize($period, 'json', [ "groups" => [ "read" ]]); + $json = $this->serializer->normalize($period, 'json', ['groups' => ['read']]); return $this->render('@ChillPerson/AccompanyingCourseWork/create.html.twig', [ 'accompanyingCourse' => $period, - 'json' => $json + 'json' => $json, ]); } /** * @Route( - * "{_locale}/person/accompanying-period/work/{id}/edit", - * name="chill_person_accompanying_period_work_edit", - * methods={"GET"} - * ) + * "{_locale}/person/accompanying-period/work/{id}/delete", + * name="chill_person_accompanying_period_work_delete", + * methods={"GET", "POST", "DELETE"} + * ) + */ + public function deleteWork(AccompanyingPeriodWork $work, Request $request): Response + { + // TODO ACL + $em = $this->getDoctrine()->getManager(); + + $form = $this->createDeleteForm($work->getId()); + + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); + + if ($form->isValid()) { + $this->chillLogger->notice('An accompanying period work has been removed', [ + 'by_user' => $this->getUser()->getUsername(), + 'work_id' => $work->getId(), + 'accompanying_period_id' => $work->getAccompanyingPeriod()->getId(), + ]); + + $em->remove($work); + $em->flush(); + + $this->addFlash( + 'success', + $this->trans->trans('The accompanying period work has been successfully removed.') + ); + + return $this->redirectToRoute('chill_person_accompanying_period_work_list', [ + 'id' => $work->getAccompanyingPeriod()->getId(), + ]); + } + } + + return $this->render('@ChillPerson/AccompanyingCourseWork/delete.html.twig', [ + 'accompanyingCourse' => $work->getAccompanyingPeriod(), + 'work' => $work, + 'delete_form' => $form->createView(), + ]); + } + + /** + * @Route( + * "{_locale}/person/accompanying-period/work/{id}/edit", + * name="chill_person_accompanying_period_work_edit", + * methods={"GET"} + * ) */ public function editWork(AccompanyingPeriodWork $work): Response { // TODO ACL - $json = $this->serializer->normalize($work, 'json', [ "groups" => [ "read" ] ]); + $json = $this->serializer->normalize($work, 'json', ['groups' => ['read']]); + return $this->render('@ChillPerson/AccompanyingCourseWork/edit.html.twig', [ 'accompanyingCourse' => $work->getAccompanyingPeriod(), 'work' => $work, - 'json' => $json + 'json' => $json, ]); } /** * @Route( - * "{_locale}/person/accompanying-period/{id}/work", - * name="chill_person_accompanying_period_work_list", - * methods={"GET"} - * ) + * "{_locale}/person/accompanying-period/{id}/work", + * name="chill_person_accompanying_period_work_list", + * methods={"GET"} + * ) */ public function listWorkByAccompanyingPeriod(AccompanyingPeriod $period): Response { @@ -109,54 +169,7 @@ class AccompanyingCourseWorkController extends AbstractController return $this->render('@ChillPerson/AccompanyingCourseWork/index.html.twig', [ 'accompanyingCourse' => $period, 'works' => $works, - 'paginator' => $paginator - ]); - } - - - /** - * @Route( - * "{_locale}/person/accompanying-period/work/{id}/delete", - * name="chill_person_accompanying_period_work_delete", - * methods={"GET", "POST", "DELETE"} - * ) - */ - public function deleteWork(AccompanyingPeriodWork $work, Request $request): Response - { - // TODO ACL - $em = $this->getDoctrine()->getManager(); - - $form = $this->createDeleteForm($work->getId()); - - if ($request->getMethod() === Request::METHOD_DELETE) { - $form->handleRequest($request); - - if ($form->isValid()) { - - $this->chillLogger->notice("An accompanying period work has been removed", [ - 'by_user' => $this->getUser()->getUsername(), - 'work_id' => $work->getId(), - 'accompanying_period_id' => $work->getAccompanyingPeriod()->getId() - ]); - - $em->remove($work); - $em->flush(); - - $this->addFlash( - 'success', - $this->trans->trans("The accompanying period work has been successfully removed.") - ); - - return $this->redirectToRoute('chill_person_accompanying_period_work_list', [ - 'id' => $work->getAccompanyingPeriod()->getId() - ]); - } - } - - return $this->render('@ChillPerson/AccompanyingCourseWork/delete.html.twig', [ - 'accompanyingCourse' => $work->getAccompanyingPeriod(), - 'work' => $work, - 'delete_form' => $form->createView() + 'paginator' => $paginator, ]); } @@ -169,9 +182,6 @@ class AccompanyingCourseWorkController extends AbstractController ->setAction($this->generateUrl('chill_person_accompanying_period_work_delete', $params)) ->setMethod('DELETE') ->add('submit', SubmitType::class, ['label' => 'Delete']) - ->getForm() - ; + ->getForm(); } - - } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php index 255c6d9ba..893dda03c 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php @@ -1,51 +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\Controller; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Form\AccompanyingPeriodType; use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use DateTime; use Doctrine\DBAL\Exception; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Form\AccompanyingPeriodType; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Doctrine\Common\Collections\Criteria; -use Chill\PersonBundle\Security\Authorization\PersonVoter; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\ConstraintViolationListInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; +use function array_filter; /** - * Class AccompanyingPeriodController - * - * @package Chill\PersonBundle\Controller + * Class AccompanyingPeriodController. */ class AccompanyingPeriodController extends AbstractController { + protected AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository; + /** * @var EventDispatcherInterface */ @@ -56,8 +44,6 @@ class AccompanyingPeriodController extends AbstractController */ protected $validator; - protected AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository; - public function __construct( AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository, EventDispatcherInterface $eventDispatcher, @@ -68,218 +54,71 @@ class AccompanyingPeriodController extends AbstractController $this->validator = $validator; } - /** - * @ParamConverter("person", options={"id"="person_id"}) - */ - public function listAction(Person $person): Response - { - $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $person); - - $event = new PrivacyEvent($person, [ - 'element_class' => AccompanyingPeriod::class, - 'action' => 'list' - ]); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - $accompanyingPeriods = $this->accompanyingPeriodACLAwareRepository - ->findByPerson($person, AccompanyingPeriodVoter::SEE); - - return $this->render('@ChillPerson/AccompanyingPeriod/list.html.twig', [ - 'accompanying_periods' => $accompanyingPeriods, - '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') ); @@ -294,57 +133,131 @@ 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 + public function createAction(int $person_id, Request $request): Response { - $errors = $this->validator->validate($person, null, - ['Default']); + $person = $this->_getPerson($person_id); - // Can be disabled with config - if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) { + $this->denyAccessUnlessGranted( + PersonVoter::UPDATE, + $person, + 'You are not allowed to update this person' + ); - $errors_accompanying_period = $this->validator->validate($person, null, - ['accompanying_period_consistent']); + $accompanyingPeriod = new AccompanyingPeriod(new DateTime('now')); + $accompanyingPeriod->setClosingDate(new DateTime('now')); - foreach($errors_accompanying_period as $error ) { - $errors->add($error); + $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, + ]); + } + + /** + * @ParamConverter("person", options={"id": "person_id"}) + */ + public function listAction(Person $person): Response + { + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $person); + + $event = new PrivacyEvent($person, [ + 'element_class' => AccompanyingPeriod::class, + 'action' => 'list', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + $accompanyingPeriods = $this->accompanyingPeriodACLAwareRepository + ->findByPerson($person, AccompanyingPeriodVoter::SEE); + + return $this->render('@ChillPerson/AccompanyingPeriod/list.html.twig', [ + 'accompanying_periods' => $accompanyingPeriods, + '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); @@ -357,40 +270,41 @@ 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, ]); } @@ -400,20 +314,20 @@ class AccompanyingPeriodController extends AbstractController $person = $this->_getPerson($person_id); /* @var $period AccompanyingPeriod */ - $period = \array_filter( + $period = array_filter( $person->getAccompanyingPeriods(), function (AccompanyingPeriod $p) use ($period_id) { return $p->getId() === ($period_id); } - )[0] ?? NULL; + )[0] ?? null; - 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); @@ -421,40 +335,141 @@ 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 @@ householdACLAwareRepository = $householdACLAwareRepository; } - public function householdAddressApi($id, Request $request, string $_format): Response - { - return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, [ 'groups' => [ 'read' ] ]); - } - /** - * Find Household of people participating to the same AccompanyingPeriod + * @Route("/api/1.0/person/household/by-address-reference/{id}.json", + * name="chill_api_person_household_by_address_reference") * - * @ParamConverter("person", options={"id" = "person_id"}) + * @return \Symfony\Component\HttpFoundation\JsonResponse */ - public function suggestHouseholdByAccompanyingPeriodParticipationApi(Person $person, string $_format) + public function getHouseholdByAddressReference(AddressReference $addressReference): Response { - // TODO add acl + // TODO ACL + $this->denyAccessUnlessGranted('ROLE_USER'); - $count = $this->householdRepository->countByAccompanyingPeriodParticipation($person); - $paginator = $this->getPaginatorFactory()->create($count); - - $households = []; - if ($count !== 0) { - $allHouseholds = $this->householdRepository->findByAccompanyingPeriodParticipation($person, - $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); - $currentHouseholdPerson = $person->getCurrentHousehold(); - - foreach ($allHouseholds as $h) { - if ($h !== $currentHouseholdPerson) { - array_push($households, $h); - } - } - if (null !== $currentHouseholdPerson) { - $count = $count - 1; - $paginator = $this->getPaginatorFactory()->create($count); - } - } + $total = $this->householdACLAwareRepository->countByAddressReference($addressReference); + $paginator = $this->getPaginatorFactory()->create($total); + $households = $this->householdACLAwareRepository->findByAddressReference( + $addressReference, + $paginator->getCurrentPageFirstItemNumber(), + $paginator->getItemsPerPage() + ); $collection = new Collection($households, $paginator); - return $this->json($collection, Response::HTTP_OK, [], - [ "groups" => ["read"]]); + return $this->json($collection, Response::HTTP_OK, [], [ + AbstractNormalizer::GROUPS => ['read'], + ]); + } + + public function householdAddressApi($id, Request $request, string $_format): Response + { + return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, ['groups' => ['read']]); } /** * @Route("/api/1.0/person/address/suggest/by-household/{household_id}.{_format}", - * name="chill_person_address_suggest_by_household", - * requirements={ - * "_format"="json" + * name="chill_person_address_suggest_by_household", + * requirements={ + * "_format": "json" * } - * ) - * @ParamConverter("household", options={"id" = "household_id"}) + * ) + * @ParamConverter("household", options={"id": "household_id"}) */ public function suggestAddressByHousehold(Household $household, string $_format) { @@ -90,9 +90,11 @@ class HouseholdApiController extends ApiController $a = $participation->getAccompanyingPeriod()->getAddressLocation(); $addresses[$a->getId()] = $a; } + if (null !== $personLocation = $participation ->getAccompanyingPeriod()->getPersonLocation()) { $a = $personLocation->getCurrentHouseholdAddress(); + if (null !== $a) { $addresses[$a->getId()] = $a; } @@ -102,34 +104,59 @@ class HouseholdApiController extends ApiController // remove the actual address $actual = $household->getCurrentAddress(); + if (null !== $actual) { - $addresses = \array_filter($addresses, fn($a) => $a !== $actual); + $addresses = array_filter($addresses, fn ($a) => $a !== $actual); } - return $this->json(\array_values($addresses), Response::HTTP_OK, [], - [ 'groups' => [ 'read' ] ]); + return $this->json( + array_values($addresses), + Response::HTTP_OK, + [], + ['groups' => ['read']] + ); } /** + * Find Household of people participating to the same AccompanyingPeriod. * - * @Route("/api/1.0/person/household/by-address-reference/{id}.json", - * name="chill_api_person_household_by_address_reference") - * @param AddressReference $addressReference - * @return \Symfony\Component\HttpFoundation\JsonResponse + * @ParamConverter("person", options={"id": "person_id"}) */ - public function getHouseholdByAddressReference(AddressReference $addressReference): Response + public function suggestHouseholdByAccompanyingPeriodParticipationApi(Person $person, string $_format) { - // TODO ACL - $this->denyAccessUnlessGranted('ROLE_USER'); + // TODO add acl - $total = $this->householdACLAwareRepository->countByAddressReference($addressReference); - $paginator = $this->getPaginatorFactory()->create($total); - $households = $this->householdACLAwareRepository->findByAddressReference($addressReference, - $paginator->getCurrentPageFirstItemNumber(), $paginator->getItemsPerPage()); + $count = $this->householdRepository->countByAccompanyingPeriodParticipation($person); + $paginator = $this->getPaginatorFactory()->create($count); + + $households = []; + + if (0 !== $count) { + $allHouseholds = $this->householdRepository->findByAccompanyingPeriodParticipation( + $person, + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); + $currentHouseholdPerson = $person->getCurrentHousehold(); + + foreach ($allHouseholds as $h) { + if ($h !== $currentHouseholdPerson) { + array_push($households, $h); + } + } + + if (null !== $currentHouseholdPerson) { + $count = $count - 1; + $paginator = $this->getPaginatorFactory()->create($count); + } + } $collection = new Collection($households, $paginator); - return $this->json($collection, Response::HTTP_OK, [], [ - AbstractNormalizer::GROUPS => ['read'] - ]); + return $this->json( + $collection, + Response::HTTP_OK, + [], + ['groups' => ['read']] + ); } } diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php index cd9e0fd79..6bba9223d 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php @@ -1,36 +1,41 @@ positionRepository - ->findByActiveOrdered() - ; - - // little performance improvement: - // initialize members collection, which will avoid - // some queries - $household->getMembers()->initialize(); - - if ($request->query->has('edit')) { - $form = $this->createMetadataForm($household); - } else { - $form = null; - } - - return $this->render('@ChillPerson/Household/summary.html.twig', - [ - 'household' => $household, - 'positions' => $positions, - 'form' => NULL !== $form ? $form->createView() : null, - ] - ); - } - - /** - * @Route( - * "/{household_id}/accompanying-period", - * name="chill_person_household_accompanying_period", - * methods={"GET", "HEAD"} - * ) - * @ParamConverter("household", options={"id" = "household_id"}) + * "/{household_id}/accompanying-period", + * name="chill_person_household_accompanying_period", + * methods={"GET", "HEAD"} + * ) + * @ParamConverter("household", options={"id": "household_id"}) */ public function accompanyingPeriod(Request $request, Household $household) { - $currentMembers = $household->getCurrentPersons(); $accompanyingPeriods = []; @@ -100,9 +68,8 @@ class HouseholdController extends AbstractController foreach ($accompanyingPeriodsMember as $accompanyingPeriod) { if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $accompanyingPeriod)) { continue; - } else { - $accompanyingPeriods[$accompanyingPeriod->getId()] = $accompanyingPeriod; } + $accompanyingPeriods[$accompanyingPeriod->getId()] = $accompanyingPeriod; } } @@ -115,93 +82,44 @@ class HouseholdController extends AbstractController foreach ($accompanyingPeriodsOldMember as $accompanyingPeriod) { if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $accompanyingPeriod)) { continue; - } else { - $id = $accompanyingPeriod->getId(); + } + $id = $accompanyingPeriod->getId(); - if (!array_key_exists($id, $accompanyingPeriodsOld) && !array_key_exists($id, $accompanyingPeriods)) { - $accompanyingPeriodsOld[$id] = $accompanyingPeriod; - } + if (!array_key_exists($id, $accompanyingPeriodsOld) && !array_key_exists($id, $accompanyingPeriods)) { + $accompanyingPeriodsOld[$id] = $accompanyingPeriod; } } } - return $this->render('@ChillPerson/Household/accompanying_period.html.twig', + return $this->render( + '@ChillPerson/Household/accompanying_period.html.twig', [ 'household' => $household, 'accompanying_periods' => $accompanyingPeriods, - 'accompanying_periods_old' => $accompanyingPeriodsOld + 'accompanying_periods_old' => $accompanyingPeriodsOld, ] ); } /** * @Route( - * "/{household_id}/addresses", - * name="chill_person_household_addresses", - * methods={"GET", "HEAD"} - * ) - * @ParamConverter("household", options={"id" = "household_id"}) - */ - public function addresses(Request $request, Household $household) - { - // TODO ACL - - //TODO put these lines into a validator constraint on household->getAddress - $addresses = $household->getAddresses(); - $cond = True; - for ($i=0; $i < count($addresses) - 1; $i++) { - if ($addresses[$i]->getValidFrom() != $addresses[$i + 1]->getValidTo()) { - $cond = False; - } - } - - return $this->render('@ChillPerson/Household/addresses.html.twig', - [ - 'household' => $household - ] - ); - } - - - /** - * @Route( - * "/{household_id}/address/move", - * name="chill_person_household_address_move", - * methods={"GET", "HEAD", "POST"} - * ) - * @ParamConverter("household", options={"id" = "household_id"}) - */ - public function addressMove(Request $request, Household $household) - { - // TODO ACL - - return $this->render('@ChillPerson/Household/address_move.html.twig', - [ - 'household' => $household - ] - ); - } - - /** - * @Route( - * "/{household_id}/address/edit", - * name="chill_person_household_address_edit", - * methods={"GET", "HEAD", "POST"} - * ) - * @ParamConverter("household", options={"id" = "household_id"}) + * "/{household_id}/address/edit", + * name="chill_person_household_address_edit", + * methods={"GET", "HEAD", "POST"} + * ) + * @ParamConverter("household", options={"id": "household_id"}) */ public function addressEdit(Request $request, Household $household) { - // TODO ACL $address_id = $request->query->get('address_id'); $address = $this->getDoctrine()->getManager() ->getRepository(Address::class) - ->find($address_id) - ; + ->find($address_id); - return $this->render('@ChillPerson/Household/address_edit.html.twig', + return $this->render( + '@ChillPerson/Household/address_edit.html.twig', [ 'household' => $household, 'address' => $address, @@ -211,32 +129,61 @@ class HouseholdController extends AbstractController /** * @Route( - * "/{household_id}/relationship", - * name="chill_person_household_relationship", - * methods={"GET", "HEAD"} - * ) - * @ParamConverter("household", options={"id" = "household_id"}) + * "/{household_id}/addresses", + * name="chill_person_household_addresses", + * methods={"GET", "HEAD"} + * ) + * @ParamConverter("household", options={"id": "household_id"}) */ - public function showRelationship(Request $request, Household $household) + public function addresses(Request $request, Household $household) { - $jsonString = $this->serializer->serialize($household->getCurrentPersons(), - 'json', [ AbstractNormalizer::GROUPS => ['read']]); + // TODO ACL - return $this->render('@ChillPerson/Household/relationship.html.twig', + //TODO put these lines into a validator constraint on household->getAddress + $addresses = $household->getAddresses(); + $cond = true; + + for ($i = 0; count($addresses) - 1 > $i; ++$i) { + if ($addresses[$i]->getValidFrom() != $addresses[$i + 1]->getValidTo()) { + $cond = false; + } + } + + return $this->render( + '@ChillPerson/Household/addresses.html.twig', [ 'household' => $household, - 'persons' => $jsonString ] ); } /** * @Route( - * "/{household_id}/members/metadata/edit", - * name="chill_person_household_members_metadata_edit", - * methods={"GET", "POST"} - * ) - * @ParamConverter("household", options={"id" = "household_id"}) + * "/{household_id}/address/move", + * name="chill_person_household_address_move", + * methods={"GET", "HEAD", "POST"} + * ) + * @ParamConverter("household", options={"id": "household_id"}) + */ + public function addressMove(Request $request, Household $household) + { + // TODO ACL + + return $this->render( + '@ChillPerson/Household/address_move.html.twig', + [ + 'household' => $household, + ] + ); + } + + /** + * @Route( + * "/{household_id}/members/metadata/edit", + * name="chill_person_household_members_metadata_edit", + * methods={"GET", "POST"} + * ) + * @ParamConverter("household", options={"id": "household_id"}) */ public function editHouseholdMetadata(Request $request, Household $household) { @@ -251,32 +198,90 @@ class HouseholdController extends AbstractController $this->addFlash('success', $this->translator->trans('household.data_saved')); return $this->redirectToRoute('chill_person_household_summary', [ - 'household_id' => $household->getId() + 'household_id' => $household->getId(), ]); } return $this->render('@ChillPerson/Household/edit_member_metadata.html.twig', [ 'household' => $household, - 'form' => $form->createView() + 'form' => $form->createView(), ]); } + /** + * @Route( + * "/{household_id}/relationship", + * name="chill_person_household_relationship", + * methods={"GET", "HEAD"} + * ) + * @ParamConverter("household", options={"id": "household_id"}) + */ + public function showRelationship(Request $request, Household $household) + { + $jsonString = $this->serializer->serialize( + $household->getCurrentPersons(), + 'json', + [AbstractNormalizer::GROUPS => ['read']] + ); + + return $this->render( + '@ChillPerson/Household/relationship.html.twig', + [ + 'household' => $household, + 'persons' => $jsonString, + ] + ); + } + + /** + * @Route( + * "/{household_id}/summary", + * name="chill_person_household_summary", + * methods={"GET", "HEAD"} + * ) + * @ParamConverter("household", options={"id": "household_id"}) + */ + public function summary(Request $request, Household $household) + { + // TODO ACL + + $positions = $this->positionRepository + ->findByActiveOrdered(); + + // little performance improvement: + // initialize members collection, which will avoid + // some queries + $household->getMembers()->initialize(); + + if ($request->query->has('edit')) { + $form = $this->createMetadataForm($household); + } else { + $form = null; + } + + return $this->render( + '@ChillPerson/Household/summary.html.twig', + [ + 'household' => $household, + 'positions' => $positions, + 'form' => null !== $form ? $form->createView() : null, + ] + ); + } + private function createMetadataForm(Household $household): FormInterface { - $form = $this->createForm( + return $this->createForm( HouseholdType::class, $household, [ 'action' => $this->generateUrl( 'chill_person_household_members_metadata_edit', [ - 'household_id' => $household->getId() + 'household_id' => $household->getId(), ] - ) + ), ] ); - - return $form; } - } diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php index 2d6f70f85..01f72ceb1 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdMemberController.php @@ -1,39 +1,44 @@ generator = $generator; $this->translator = $translator; $this->periodRepository = $periodRepository; @@ -41,16 +46,143 @@ class HouseholdMemberController extends ApiController /** * @Route( - * "/api/1.0/person/household/members/move.{_format}", - * name="chill_api_person_household_members_move" - * ) + * "/{_locale}/person/household/member/{id}/edit", + * name="chill_person_household_member_edit" + * ) + */ + public function editMembership(Request $request, HouseholdMember $member): Response + { + // TODO ACL + + $form = $this->createForm(HouseholdMemberType::class, $member, [ + 'validation_groups' => ['household_memberships'], + ]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->getDoctrine()->getManager()->flush(); + + $this->addFlash('success', $this->translator + ->trans('household.successfully saved member')); + + return $this->redirect( + $request->get('returnPath', null) ?? + $this->generator->generate('chill_person_household_summary', ['household_id' => $member->getHousehold()->getId()]) + ); + } + + return $this->render('@ChillPerson/Household/Member/edit.html.twig', [ + 'household' => $member->getHousehold(), + 'member' => $member, + 'form' => $form->createView(), + ]); + } + + /** + * Route for showing an editor to leave a household. + * + * Possibles arguments are: + * + * * persons[]: an id of the person to add to the form + * * household: the id of the destination household + * * allow_leave_without_household: if present, the editor will allow + * to leave household without joining another + * + * @Route( + * "/{_locale}/person/household/members/editor", + * name="chill_person_household_members_editor" + * ) + */ + public function editor(Request $request) + { + $em = $this->getDoctrine()->getManager(); + + if ($request->query->has('persons')) { + $ids = $request->query->get('persons', []); + + if (0 === count($ids)) { + throw new BadRequestException('parameters persons in query ' . + 'is not an array or empty'); + } + + $persons = $em->getRepository(Person::class) + ->findById($ids); + + foreach ($persons as $person) { + $this->denyAccessUnlessGranted( + PersonVoter::SEE, + $person, + "You are not allowed to see person with id {$person->getId()}" + ); + } + } + + if ($householdId = $request->query->get('household', false)) { + $household = $em->getRepository(Household::class) + ->find($householdId); + $allowHouseholdCreate = false; + $allowHouseholdSearch = false; + $allowLeaveWithoutHousehold = false; + + if (null === $household) { + throw $this->createNotFoundException('household not found'); + } + // TODO ACL on household + } + + $positions = $this->getDoctrine()->getManager() + ->getRepository(Position::class) + ->findAll(); + + $data = [ + 'persons' => $persons ?? false ? + $this->getSerializer()->normalize($persons, 'json', ['groups' => ['read']]) : [], + 'household' => $household ?? false ? + $this->getSerializer()->normalize($household, 'json', ['groups' => ['read']]) : null, + 'positions' => $this->getSerializer()->normalize($positions, 'json', ['groups' => ['read']]), + 'allowHouseholdCreate' => $allowHouseholdCreate ?? true, + 'allowHouseholdSearch' => $allowHouseholdSearch ?? true, + 'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'), + ]; + + // context + if ($request->query->has('accompanying_period_id')) { + $period = $this->periodRepository->find( + $request->query->getInt('accompanying_period_id') + ); + + if (null === $period) { + throw $this->createNotFoundException('period not found'); + } + + // TODO add acl on accompanying Course + } + + return $this->render('@ChillPerson/Household/members_editor.html.twig', [ + 'data' => $data, + 'expandSuggestions' => (int) $request->query->getBoolean('expand_suggestions', false), + 'accompanyingCourse' => $period ?? null, + ]); + } + + /** + * @Route( + * "/api/1.0/person/household/members/move.{_format}", + * name="chill_api_person_household_members_move" + * ) + * + * @param mixed $_format */ public function move(Request $request, $_format): Response { try { $editor = $this->getSerializer() - ->deserialize($request->getContent(), MembersEditor::class, - $_format, ['groups' => [ "read" ]]); + ->deserialize( + $request->getContent(), + MembersEditor::class, + $_format, + ['groups' => ['read']] + ); } catch (Exception\InvalidArgumentException | Exception\UnexpectedValueException $e) { throw new BadRequestException("Deserialization error: {$e->getMessage()}", 45896, $e); } @@ -68,143 +200,16 @@ class HouseholdMemberController extends ApiController // if new household, persist it if ( $editor->hasHousehold() - && - FALSE === $em->contains($editor->getHousehold()) + && false === $em->contains($editor->getHousehold()) ) { $em->persist($editor->getHousehold()); } foreach ($editor->getPersistable() as $el) { - $em->persist($el); + $em->persist($el); } $em->flush(); - return $this->json($editor->getHousehold(), Response::HTTP_OK, [], ["groups" => ["read"]]); - } - - /** - * Route for showing an editor to leave a household. - * - * Possibles arguments are: - * - * * persons[]: an id of the person to add to the form - * * household: the id of the destination household - * * allow_leave_without_household: if present, the editor will allow - * to leave household without joining another - * - * @Route( - * "/{_locale}/person/household/members/editor", - * name="chill_person_household_members_editor" - * ) - */ - public function editor(Request $request) - { - $em = $this->getDoctrine()->getManager(); - - if ($request->query->has('persons')) { - $ids = $request->query->get('persons', []); - - if (0 === count($ids)) { - throw new BadRequestException("parameters persons in query ". - "is not an array or empty"); - } - - $persons = $em->getRepository(Person::class) - ->findById($ids) - ; - - foreach ($persons as $person) { - $this->denyAccessUnlessGranted(PersonVoter::SEE, $person, - "You are not allowed to see person with id {$person->getId()}" - ); - } - } - - if ($householdId = $request->query->get('household', false)) { - $household = $em->getRepository(Household::class) - ->find($householdId) - ; - $allowHouseholdCreate = false; - $allowHouseholdSearch = false; - $allowLeaveWithoutHousehold = false; - - if (NULL === $household) { - throw $this->createNotFoundException('household not found'); - } - // TODO ACL on household - } - - $positions = $this->getDoctrine()->getManager() - ->getRepository(Position::class) - ->findAll() - ; - - $data = [ - 'persons' => $persons ?? false ? - $this->getSerializer()->normalize($persons, 'json', [ 'groups' => [ 'read' ]]) : [], - 'household' => $household ?? false ? - $this->getSerializer()->normalize($household, 'json', [ 'groups' => [ 'read' ]]) : null, - 'positions' => - $this->getSerializer()->normalize($positions, 'json', [ 'groups' => [ 'read' ]]), - 'allowHouseholdCreate' => $allowHouseholdCreate ?? true, - 'allowHouseholdSearch' => $allowHouseholdSearch ?? true, - 'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'), - ]; - - // context - if ($request->query->has('accompanying_period_id')) { - $period = $this->periodRepository->find( - $request->query->getInt('accompanying_period_id') - ); - - if ($period === null) { - throw $this->createNotFoundException('period not found'); - } - - // TODO add acl on accompanying Course - } - - return $this->render('@ChillPerson/Household/members_editor.html.twig', [ - 'data' => $data, - 'expandSuggestions' => (int) $request->query->getBoolean('expand_suggestions', false), - 'accompanyingCourse' => $period ?? null, - ]); - } - - /** - * @Route( - * "/{_locale}/person/household/member/{id}/edit", - * name="chill_person_household_member_edit" - * ) - */ - public function editMembership(Request $request, HouseholdMember $member): Response - { - // TODO ACL - - $form = $this->createForm(HouseholdMemberType::class, $member, [ - 'validation_groups' => [ 'household_memberships' ] - ]); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->getDoctrine()->getManager()->flush(); - - $this->addFlash('success', $this->translator - ->trans('household.successfully saved member')) - ; - - return $this->redirect( - $request->get('returnPath', null) ?? - $this->generator->generate('chill_person_household_summary', [ 'household_id' => - $member->getHousehold()->getId() ]) - ); - } - - return $this->render('@ChillPerson/Household/Member/edit.html.twig', [ - 'household' => $member->getHousehold(), - 'member' => $member, - 'form' => $form->createView() - ]); - + return $this->json($editor->getHousehold(), Response::HTTP_OK, [], ['groups' => ['read']]); } } 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 4ec1b6218..684a04b0d 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php @@ -1,43 +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\PersonBundle\Controller; +use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Form\Type\AddressType; +use Chill\PersonBundle\Entity\Person; 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 { @@ -48,78 +30,27 @@ class PersonAddressController extends AbstractController /** * 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 +68,6 @@ class PersonAddressController extends AbstractController $this->addFlash('error', $error->getMessage()); } } elseif ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); $em->flush(); @@ -146,47 +76,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 +174,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,90 +199,84 @@ 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) { $address = $this->getDoctrine()->getManager() ->getRepository(Address::class) - ->find($address_id) - ; + ->find($address_id); if (!$person->getAddresses()->contains($address)) { - throw $this->createAccessDeniedException("Not allowed to see this address"); + throw $this->createAccessDeniedException('Not allowed to see this address'); } return $address; @@ -311,16 +284,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/PersonApiController.php b/src/Bundle/ChillPersonBundle/Controller/PersonApiController.php index ab39c13bb..61da76c18 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonApiController.php @@ -1,70 +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\PersonBundle\Controller; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\Role\Role; use Chill\MainBundle\CRUD\Controller\ApiController; +use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Chill\MainBundle\Entity\Address; use Symfony\Component\Routing\Annotation\Route; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; +use Symfony\Component\Security\Core\Role\Role; +use function array_filter; +use function array_values; class PersonApiController extends ApiController { private AuthorizationHelper $authorizationHelper; - /** - * @param AuthorizationHelper $authorizationHelper - */ public function __construct(AuthorizationHelper $authorizationHelper) { $this->authorizationHelper = $authorizationHelper; } - protected function createEntity(string $action, Request $request): object - { - $person = parent::createEntity($action, $request); - - // TODO temporary hack to allow creation of person with fake center - /* $centers = $this->authorizationHelper->getReachableCenters($this->getUser(), - new Role(PersonVoter::CREATE)); - $person->setCenter($centers[0]); */ - - return $person; - } - public function personAddressApi($id, Request $request, string $_format): Response { - return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, [ 'groups' => [ 'read' ] ]); + return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, ['groups' => ['read']]); } /** * @Route("/api/1.0/person/address/suggest/by-person/{person_id}.{_format}", - * name="chill_person_address_suggest_by_person", - * requirements={ - * "_format"="json" + * name="chill_person_address_suggest_by_person", + * requirements={ + * "_format": "json" * } - * ) - * @ParamConverter("person", options={"id" = "person_id"}) + * ) + * @ParamConverter("person", options={"id": "person_id"}) */ public function suggestAddress(Person $person, Request $request, string $_format): Response { @@ -81,10 +60,20 @@ class PersonApiController extends ApiController // remove the actual address $actual = $person->getCurrentHouseholdAddress(); + if (null !== $actual) { - $addresses = \array_filter($addresses, fn($a) => $a !== $actual); + $addresses = array_filter($addresses, fn ($a) => $a !== $actual); } - return $this->json(\array_values($addresses), Response::HTTP_OK, [], [ 'groups' => [ 'read' ]]); + return $this->json(array_values($addresses), Response::HTTP_OK, [], ['groups' => ['read']]); + } + + protected function createEntity(string $action, Request $request): object + { + return parent::createEntity($action, $request); + // TODO temporary hack to allow creation of person with fake center + /* $centers = $this->authorizationHelper->getReachableCenters($this->getUser(), + new Role(PersonVoter::CREATE)); + $person->setCenter($centers[0]); */ } } diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonController.php b/src/Bundle/ChillPersonBundle/Controller/PersonController.php index 596d2bbdf..82ab0a30f 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonController.php @@ -1,65 +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\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 Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Form\Extension\Core\Type\ButtonType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Form; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; -use Symfony\Component\Security\Core\Role\Role; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Chill\PersonBundle\Search\SimilarPersonMatcher; +use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Security; use Symfony\Component\Translation\TranslatorInterface; -use Chill\MainBundle\Search\SearchProvider; -use Chill\PersonBundle\Repository\PersonRepository; -use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper; -use Chill\PersonBundle\Repository\PersonNotDuplicateRepository; use Symfony\Component\Validator\Validator\ValidatorInterface; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Routing\Annotation\Route; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; +use function hash; +use function implode; +use function in_array; +use function is_array; final class PersonController extends AbstractController { /** - * @var SimilarPersonMatcher + * @var ConfigPersonAltNamesHelper */ - protected $similarPersonMatcher; - - /** - * @var TranslatorInterface - */ - protected $translator; + protected $configPersonAltNameHelper; /** * @var EventDispatcherInterface @@ -72,9 +53,14 @@ final class PersonController extends AbstractController protected $personRepository; /** - * @var ConfigPersonAltNamesHelper + * @var SimilarPersonMatcher */ - protected $configPersonAltNameHelper; + protected $similarPersonMatcher; + + /** + * @var TranslatorInterface + */ + protected $translator; /** * @var EntityManagerInterface @@ -111,60 +97,28 @@ final class PersonController extends AbstractController $this->validator = $validator; $this->em = $em; $this->security = $security; - } - - 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) - { - $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_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', - array( - "person" => $person, - "cFGroup" => $this->getCFGroup(), - "alt_names" => $this->configPersonAltNameHelper->getChoices(), - )); } public function editAction($person_id, Request $request) { $person = $this->_getPerson($person_id); - if ($person === null) { + if (null === $person) { throw $this->createNotFoundException(); } - $this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person, - 'You are not allowed to edit this person'); + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_UPDATE', + $person, + 'You are not allowed to edit this person' + ); - $form = $this->createForm(PersonType::class, $person, - array( - "cFGroup" => $this->getCFGroup() - ) + $form = $this->createForm( + PersonType::class, + $person, + [ + 'cFGroup' => $this->getCFGroup(), + ] ); $form->handleRequest($request); @@ -172,28 +126,71 @@ final class PersonController extends AbstractController if ($form->isSubmitted() && !$form->isValid()) { $this->get('session') ->getFlashBag()->add('error', $this->translator - ->trans('This form contains errors')); + ->trans('This form contains errors')); } elseif ($form->isSubmitted() && $form->isValid()) { $this->get('session')->getFlashBag() - ->add('success', + ->add( + 'success', $this->get('translator') ->trans('The person data has been updated') ); $this->em->flush(); - return $this->redirectToRoute('chill_person_view', [ - 'person_id' => $person->getId() + return $this->redirectToRoute('chill_person_view', [ + 'person_id' => $person->getId(), ]); } + return $this->render( + 'ChillPersonBundle:Person:edit.html.twig', + ['person' => $person, 'form' => $form->createView()] + ); + } - return $this->render('ChillPersonBundle:Person:edit.html.twig', - array('person' => $person, 'form' => $form->createView())); + public function getCFGroup() + { + $cFGroup = null; + + $cFDefaultGroup = $this->em->getRepository('ChillCustomFieldsBundle:CustomFieldsDefaultGroup') + ->findOneByEntity('Chill\\PersonBundle\\Entity\\Person'); + + if ($cFDefaultGroup) { + $cFGroup = $cFDefaultGroup->getCustomFieldsGroup(); + } + + return $cFGroup; } /** - * Method for creating a new person + * @Route( + * "/{_locale}/person/household/{person_id}/history", + * name="chill_person_household_person_history", + * methods={"GET", "POST"} + * ) + * @ParamConverter("person", options={"id": "person_id"}) + */ + public function householdHistoryByPerson(Request $request, Person $person): Response + { + $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( + '@ChillPerson/Person/household_history.html.twig', + [ + 'person' => $person, + ] + ); + } + + /** + * Method for creating a new person. * *The controller register data from a previous post on the form, and * register it in the session. @@ -201,15 +198,14 @@ final class PersonController extends AbstractController * The next post compare the data with previous one and, if yes, show a * review page if there are "alternate persons". * - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse */ public function newAction(Request $request) { $person = new Person(); if (1 === count($this->security->getUser() - ->getGroupCenters())) { + ->getGroupCenters())) { $person->setCenter( $this->security->getUser() ->getGroupCenters()[0] @@ -218,13 +214,13 @@ final class PersonController extends AbstractController } $form = $this->createForm(CreationPersonType::class, $person, [ - 'validation_groups' => ['create'] + 'validation_groups' => ['create'], ])->add('editPerson', SubmitType::class, [ - 'label' => 'Add the person' + 'label' => 'Add the person', ])->add('createPeriod', SubmitType::class, [ - 'label' => 'Add the person and create an accompanying period' + 'label' => 'Add the person and create an accompanying period', ])->add('createHousehold', SubmitType::class, [ - 'label' => 'Add the person and create an household' + 'label' => 'Add the person and create an household', ]); // TODO createHousehold form action $form->handleRequest($request); @@ -233,14 +229,12 @@ final class PersonController extends AbstractController $this->lastPostDataReset(); } elseif ($request->getMethod() === Request::METHOD_POST && $form->isValid()) { - $alternatePersons = $this->similarPersonMatcher ->matchPerson($person); if ( - FALSE === $this->isLastPostDataChanges($form, $request, true) - || - count($alternatePersons) === 0 + false === $this->isLastPostDataChanges($form, $request, true) + || count($alternatePersons) === 0 ) { $this->em->persist($person); @@ -249,84 +243,75 @@ final class PersonController extends AbstractController if ($form->get('createPeriod')->isClicked()) { return $this->redirectToRoute('chill_person_accompanying_course_new', [ - 'person_id' => [ $person->getId() ] + 'person_id' => [$person->getId()], ]); } - return $this->redirectToRoute('chill_person_general_edit', - ['person_id' => $person->getId()]); + return $this->redirectToRoute( + 'chill_person_general_edit', + ['person_id' => $person->getId()] + ); } } elseif ($request->getMethod() === Request::METHOD_POST && !$form->isValid()) { $this->addFlash('error', $this->translator->trans('This form contains errors')); } - return $this->render('@ChillPerson/Person/create.html.twig', + return $this->render( + '@ChillPerson/Person/create.html.twig', [ 'form' => $form->createView(), - 'alternatePersons' => $alternatePersons ?? [] + 'alternatePersons' => $alternatePersons ?? [], ] ); } - private function isLastPostDataChanges(Form $form, Request $request, bool $replace = false): bool + public function viewAction($person_id) { - /** @var SessionInterface $session */ - $session = $this->get('session'); - if (!$session->has('last_person_data')) { - return true; + $person = $this->_getPerson($person_id); + + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found on this server'); } - $newPost = $this->lastPostDataBuildHash($form, $request); + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_SEE', + $person, + 'You are not allowed to see this person.' + ); - $isChanged = $newPost !== $session->get('last_person_data'); + $event = new PrivacyEvent($person); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - if ($replace) { - $session->set('last_person_data', $newPost); - } - - return $isChanged ; - } - - private function lastPostDataReset(): void - { - $this->get('session')->set('last_person_data', ""); + return $this->render( + 'ChillPersonBundle:Person:view.html.twig', + [ + 'person' => $person, + 'cFGroup' => $this->getCFGroup(), + 'alt_names' => $this->configPersonAltNameHelper->getChoices(), + ] + ); } /** - * build the hash for posted data + * easy getting a person by his id. * - * For privacy reasons, the data are hashed using sha512 + * @param mixed $id * - * @param Form $form - * @param Request $request - * @return string + * @return \Chill\PersonBundle\Entity\Person */ - private function lastPostDataBuildHash(Form $form, Request $request): string + private function _getPerson($id) { - $fields = []; - $ignoredFields = ['form_status', '_token']; - - foreach ($request->request->all()[$form->getName()] as $field => $value) { - if (\in_array($field, $ignoredFields)) { - continue; - } - $fields[$field] = \is_array($value) ? - \implode(",", $value) : $value; - } - ksort($fields); - - return \hash('sha512', \implode("&", $fields)); + return $this->personRepository->find($id); } /** - * - * @param \Chill\PersonBundle\Entity\Person $person * @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(); @@ -336,7 +321,7 @@ final class PersonController extends AbstractController ->validate($period); //group errors : - foreach($period_errors as $error) { + foreach ($period_errors as $error) { $errors->add($error); } } @@ -344,39 +329,50 @@ final class PersonController extends AbstractController return $errors; } - /** - * easy getting a person by his id - * @return \Chill\PersonBundle\Entity\Person - */ - private function _getPerson($id) + private function isLastPostDataChanges(Form $form, Request $request, bool $replace = false): bool { - $person = $this->personRepository->find($id); + /** @var SessionInterface $session */ + $session = $this->get('session'); - return $person; + if (!$session->has('last_person_data')) { + return true; + } + + $newPost = $this->lastPostDataBuildHash($form, $request); + + $isChanged = $session->get('last_person_data') !== $newPost; + + if ($replace) { + $session->set('last_person_data', $newPost); + } + + return $isChanged; } /** + * build the hash for posted data. * - * @Route( - * "/{_locale}/person/household/{person_id}/history", - * name="chill_person_household_person_history", - * methods={"GET", "POST"} - * ) - * @ParamConverter("person", options={"id" = "person_id"}) + * For privacy reasons, the data are hashed using sha512 */ - public function householdHistoryByPerson(Request $request, Person $person): Response + private function lastPostDataBuildHash(Form $form, Request $request): string { - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person, - "You are not allowed to see this person."); + $fields = []; + $ignoredFields = ['form_status', '_token']; - $event = new PrivacyEvent($person); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + foreach ($request->request->all()[$form->getName()] as $field => $value) { + if (in_array($field, $ignoredFields)) { + continue; + } + $fields[$field] = is_array($value) ? + implode(',', $value) : $value; + } + ksort($fields); - return $this->render( - '@ChillPerson/Person/household_history.html.twig', - [ - 'person' => $person - ] - ); + return hash('sha512', implode('&', $fields)); + } + + private function lastPostDataReset(): void + { + $this->get('session')->set('last_person_data', ''); } } diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php index d30ddebae..d1d9338aa 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php @@ -1,29 +1,50 @@ similarPersonMatcher = $similarPersonMatcher; $this->translator = $translator; @@ -63,29 +69,6 @@ class PersonDuplicateController extends Controller $this->eventDispatcher = $eventDispatcher; } - public function viewAction($person_id, PersonNotDuplicateRepository $personNotDuplicateRepository) - { - $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, $personNotDuplicateRepository, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL); - - $notDuplicatePersons = $personNotDuplicateRepository->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) { @@ -98,17 +81,20 @@ 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 +102,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 +114,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 +130,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 +210,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 +227,56 @@ 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, PersonNotDuplicateRepository $personNotDuplicateRepository) { $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, $personNotDuplicateRepository, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL); - $form->handleRequest($request); + $notDuplicatePersons = $personNotDuplicateRepository->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/RelationshipApiController.php b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php index b396cdf36..72e92ac92 100644 --- a/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/RelationshipApiController.php @@ -1,4 +1,12 @@ validator = $validator; @@ -22,13 +32,13 @@ class RelationshipApiController extends ApiController } /** - * @ParamConverter("person", options={"id" = "person_id"}) + * @ParamConverter("person", options={"id": "person_id"}) */ public function getRelationshipsByPerson(Person $person) { //TODO: add permissions? (voter?) $relationships = $this->repository->findByPerson($person); - return $this->json(\array_values($relationships), Response::HTTP_OK, [], ['groups' => [ 'read']]); + return $this->json(array_values($relationships), Response::HTTP_OK, [], ['groups' => ['read']]); } } diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php index c1d251efb..398d352d7 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialIssueApiController.php @@ -1,5 +1,12 @@ orderBy("GET_JSON_FIELD_BY_KEY(e.title, :locale)", 'ASC') + ->orderBy('GET_JSON_FIELD_BY_KEY(e.title, :locale)', 'ASC') ->setParameter(':locale', $request->getLocale()); return null; diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminEvaluationController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminEvaluationController.php index 134cedc74..272ef02e4 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminEvaluationController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminEvaluationController.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\Controller\SocialWork; @@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController; /** * Class AdminSocialIssueController - * Controller for social issues - * - * @package Chill\PersonBundle\Controller + * Controller for social issues. */ class AdminEvaluationController extends CRUDController { diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminGoalController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminGoalController.php index 18e1c9f3b..14225f812 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminGoalController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminGoalController.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\Controller\SocialWork; @@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController; /** * Class AdminSocialIssueController - * Controller for social issues - * - * @package Chill\PersonBundle\Controller + * Controller for social issues. */ class AdminGoalController extends CRUDController { diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminResultController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminResultController.php index 80d552282..2500d87cd 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminResultController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminResultController.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\Controller\SocialWork; @@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController; /** * Class AdminSocialIssueController - * Controller for social issues - * - * @package Chill\PersonBundle\Controller + * Controller for social issues. */ class AdminResultController extends CRUDController { diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialActionController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialActionController.php index 695ec75a1..d83fe2c1f 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialActionController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialActionController.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\Controller\SocialWork; @@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController; /** * Class AdminSocialIssueController - * Controller for social issues - * - * @package Chill\PersonBundle\Controller + * Controller for social issues. */ class AdminSocialActionController extends CRUDController { diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialIssueController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialIssueController.php index 35b0df4a2..b07c95c95 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialIssueController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWork/AdminSocialIssueController.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\Controller\SocialWork; @@ -24,9 +13,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController; /** * Class AdminSocialIssueController - * Controller for social issues - * - * @package Chill\PersonBundle\Controller + * Controller for social issues. */ class AdminSocialIssueController extends CRUDController { diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWorkEvaluationApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWorkEvaluationApiController.php index 24b919978..019dff4d7 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWorkEvaluationApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWorkEvaluationApiController.php @@ -1,22 +1,26 @@ paginatorFactory = $paginatorFactory; @@ -26,21 +30,21 @@ class SocialWorkEvaluationApiController extends AbstractController * @Route("/api/1.0/person/social-work/evaluation/by-social-action/{action_id}.json", * name="chill_person_evaluation_index_by_social_action", * requirements={ - * "_format": "json" + * "_format": "json" * } * ) * @ParamConverter("action", options={"id": "action_id"}) - * @param SocialAction $action - * @return Response */ public function listEvaluationBySocialAction(SocialAction $action): Response { $pagination = $this->paginatorFactory->create($action->getEvaluations()->count()); - $evaluations = $action->getEvaluations()->slice($pagination->getCurrentPageFirstItemNumber(), - $pagination->getItemsPerPage()); + $evaluations = $action->getEvaluations()->slice( + $pagination->getCurrentPageFirstItemNumber(), + $pagination->getItemsPerPage() + ); $collection = new Collection($evaluations, $pagination); - return $this->json($collection, Response::HTTP_OK, [], [ 'groups' => [ 'read' ]]); + return $this->json($collection, Response::HTTP_OK, [], ['groups' => ['read']]); } } diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWorkGoalApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWorkGoalApiController.php index 2e678a0d0..575d493ee 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWorkGoalApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWorkGoalApiController.php @@ -1,13 +1,19 @@ goalRepository = $goalRepository; @@ -28,13 +33,16 @@ class SocialWorkGoalApiController extends ApiController { $totalItems = $this->goalRepository->countBySocialActionWithDescendants($action); $paginator = $this->getPaginatorFactory()->create($totalItems); - - $entities = $this->goalRepository->findBySocialActionWithDescendants($action, ["id" => "ASC"], - $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); - + + $entities = $this->goalRepository->findBySocialActionWithDescendants( + $action, + ['id' => 'ASC'], + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); + $model = new Collection($entities, $paginator); - return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]); + return $this->json($model, Response::HTTP_OK, [], ['groups' => ['read']]); } - } diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWorkResultApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWorkResultApiController.php index 24902a163..17d7181c5 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWorkResultApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWorkResultApiController.php @@ -1,12 +1,19 @@ resultRepository = $resultRepository; } + public function listByGoal(Request $request, Goal $goal): Response + { + $totalItems = $this->resultRepository->countByGoal($goal); + $paginator = $this->getPaginatorFactory()->create($totalItems); + + $entities = $this->resultRepository->findByGoal( + $goal, + ['id' => 'ASC'], + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); + + $model = new Collection($entities, $paginator); + + return $this->json($model, Response::HTTP_OK, [], ['groups' => ['read']]); + } + public function listBySocialAction(Request $request, SocialAction $action): Response { $totalItems = $this->resultRepository->countBySocialActionWithDescendants($action); $paginator = $this->getPaginatorFactory()->create($totalItems); - - $entities = $this->resultRepository->findBySocialActionWithDescendants($action, ["id" => "ASC"], - $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); - + + $entities = $this->resultRepository->findBySocialActionWithDescendants( + $action, + ['id' => 'ASC'], + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); + $model = new Collection($entities, $paginator); - return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]); - } - - public function listByGoal(Request $request, Goal $goal): Response - { - $totalItems = $this->resultRepository->countByGoal($goal); - $paginator = $this->getPaginatorFactory()->create($totalItems); - - $entities = $this->resultRepository->findByGoal($goal, ["id" => "ASC"], - $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); - - $model = new Collection($entities, $paginator); - - return $this->json($model, Response::HTTP_OK, [], [ "groups" => [ "read" ]]); + return $this->json($model, Response::HTTP_OK, [], ['groups' => ['read']]); } } diff --git a/src/Bundle/ChillPersonBundle/Controller/SocialWorkSocialActionApiController.php b/src/Bundle/ChillPersonBundle/Controller/SocialWorkSocialActionApiController.php index de87b380a..8a607f111 100644 --- a/src/Bundle/ChillPersonBundle/Controller/SocialWorkSocialActionApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/SocialWorkSocialActionApiController.php @@ -1,36 +1,40 @@ socialIssueRepository = $socialIssueRepository; $this->paginator = $paginator; } - + public function listBySocialIssueApi($id, Request $request) { $socialIssue = $this->socialIssueRepository ->find($id); - if (NULL === $socialIssue) { - throw $this->createNotFoundException("socialIssue not found"); + if (null === $socialIssue) { + throw $this->createNotFoundException('socialIssue not found'); } $socialActions = $socialIssue->getRecursiveSocialActions(); @@ -39,9 +43,7 @@ class SocialWorkSocialActionApiController extends ApiController $pagination->setItemsPerPage(count($socialActions)); $collection = new Collection($socialActions, $pagination); - - - return $this->json($collection, JsonResponse::HTTP_OK, [], [ "groups" => [ "read" ]]); - } + return $this->json($collection, JsonResponse::HTTP_OK, [], ['groups' => ['read']]); + } } diff --git a/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php b/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php index 389c723ce..7402698d9 100644 --- a/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php +++ b/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php @@ -1,27 +1,33 @@ getDoctrine() - ->getRepository(Person::class) - ->find($person_id); + ->getRepository(Person::class) + ->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], $paginator->getCurrentPage()->getFirstItemNumber(), $paginator->getItemsPerPage() - ), + ), 'person' => $person, 'nb_items' => $nbItems, - 'paginator' => $paginator - ) + 'paginator' => $paginator, + ] ); } - } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php index 0f7068751..d3872a64b 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/PersonRandomHelper.php @@ -1,25 +1,35 @@ countPersons) { $qb = $em->createQueryBuilder(); $this->countPersons = $qb->select('count(p)') ->from(Person::class, 'p') ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); } if ([] === $this->randPersons) { @@ -28,13 +38,11 @@ trait PersonRandomHelper ->select('p') ->from(Person::class, 'p') ->getQuery() - ->setFirstResult(\random_int(0, $this->countPersons - $fetchBy)) + ->setFirstResult(random_int(0, $this->countPersons - $fetchBy)) ->setMaxResults($fetchBy) - ->getResult() - ; + ->getResult(); } - return \array_pop($this->randPersons); + return array_pop($this->randPersons); } - } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php index c6cef7aa0..b0a337374 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/Helper/RandomPersonHelperTrait.php @@ -1,9 +1,17 @@ createQueryBuilder(); $qb - ->from(Person::class, 'p') - ; + ->from(Person::class, 'p'); if (null === $this->nbOfPersons) { $this->nbOfPersons = $qb ->select('COUNT(p)') ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); } return $qb ->select('p') ->setMaxResults(1) - ->setFirstResult(\random_int(0, $this->nbOfPersons)) + ->setFirstResult(random_int(0, $this->nbOfPersons)) ->getQuery() - ->getSingleResult() - ; + ->getSingleResult(); } } 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/LoadAccompanyingPeriodNotifications.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodNotifications.php index e96bf44e6..3db1c264f 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodNotifications.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodNotifications.php @@ -1,14 +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\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 9000; } - 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/LoadAccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodWork.php index 82e232e8d..6b98ff574 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodWork.php @@ -1,5 +1,12 @@ evaluationRepository = $evaluationRepository; } - /** - * @inheritDoc - */ public function getDependencies() { return [ - LoadPeople::class + LoadPeople::class, ]; } + public function load(ObjectManager $manager) + { + // load all the period which are confirmed + $periods = $this->periodRepository + ->findBy(['step' => AccompanyingPeriod::STEP_CONFIRMED]); + + $i = 0; + + while (null !== $period = array_pop($periods)) { + /** @var AccompanyingPeriod $period */ + ++$i; + + if (0 === $i % 15) { + $manager->flush(); + } + + if (0 === $period->getSocialIssues()->count()) { + continue; + } + $work = new AccompanyingPeriod\AccompanyingPeriodWork(); + $action = $this->getRandomAction($period->getSocialIssues()->first()); + + if (null !== $action) { + $work + ->setAccompanyingPeriod($period) + ->setSocialAction($action) + ->setStartDate(new DateTimeImmutable('today')) + ->addPerson($period->getPersons()->first()) + ->setCreatedAt(new DateTimeImmutable()) + ->setCreatedBy($this->getReference('center a_social')) + ->setUpdatedAt(new DateTimeImmutable()) + ->setUpdatedBy($this->getReference('center a_social')); + $manager->persist($work); + + if ($action->getEvaluations()->count() > 0) { + $ev = $action->getEvaluations()->first(); + $evaluation = new AccompanyingPeriod\AccompanyingPeriodWorkEvaluation(); + $evaluation->setAccompanyingPeriodWork($work) + ->setEvaluation($ev); + $manager->persist($evaluation); + } + } + + // 1 of 10, force an evaluation + if (0 === $i % 10) { + $evaluation = $this->getRandomEvaluation(); + $action = $evaluation->getSocialAction(); + $issue = $action->getIssue(); + + $period->addSocialIssue($issue); + $work + ->setAccompanyingPeriod($period) + ->setSocialAction($action) + ->setStartDate(new DateTimeImmutable('today')) + ->addPerson($period->getPersons()->first()) + ->setCreatedAt(new DateTimeImmutable()) + ->setCreatedBy($this->getReference('center a_social')) + ->setUpdatedAt(new DateTimeImmutable()) + ->setUpdatedBy($this->getReference('center a_social')); + $manager->persist($work); + $ev = new AccompanyingPeriod\AccompanyingPeriodWorkEvaluation(); + $ev->setAccompanyingPeriodWork($work) + ->setEvaluation($evaluation); + $manager->persist($ev); + } + } + + $manager->flush(); + } + private function getRandomAction(SocialIssue $socialIssue): ?SocialAction { $actions = $socialIssue->getRecursiveSocialActions()->toArray(); @@ -52,89 +124,16 @@ class LoadAccompanyingPeriodWork extends \Doctrine\Bundle\FixturesBundle\Fixture return null; } - return $actions[\array_rand($actions)]; + return $actions[array_rand($actions)]; } private function getRandomEvaluation(): Evaluation { - if (0 === count($this->cacheEvaluations)) { - $this->cacheEvaluations = $this->evaluationRepository - ->findAll(); - } - - return $this->cacheEvaluations[\array_rand($this->cacheEvaluations)]; - } - - /** - * @inheritDoc - */ - public function load(ObjectManager $manager) - { - // load all the period which are confirmed - $periods = $this->periodRepository - ->findBy(['step' => AccompanyingPeriod::STEP_CONFIRMED]) - ; - - $i = 0; - while (null !== $period = \array_pop($periods)) { - /** @var AccompanyingPeriod $period */ - $i++; - if (0 === $i % 15) { - $manager->flush(); - } - if (0 === $period->getSocialIssues()->count()) { - continue; - } - $work = new AccompanyingPeriod\AccompanyingPeriodWork(); - $action = $this->getRandomAction($period->getSocialIssues()->first()); - - if (null !== $action) { - $work - ->setAccompanyingPeriod($period) - ->setSocialAction($action) - ->setStartDate(new \DateTimeImmutable('today')) - ->addPerson($period->getPersons()->first()) - ->setCreatedAt(new \DateTimeImmutable()) - ->setCreatedBy($this->getReference('center a_social')) - ->setUpdatedAt(new \DateTimeImmutable()) - ->setUpdatedBy($this->getReference('center a_social')); - $manager->persist($work); - - if ($action->getEvaluations()->count() > 0) { - $ev = $action->getEvaluations()->first(); - $evaluation = new AccompanyingPeriod\AccompanyingPeriodWorkEvaluation(); - $evaluation->setAccompanyingPeriodWork($work) - ->setEvaluation($ev); - $manager->persist($evaluation); - } - } - - // 1 of 10, force an evaluation - if (0 === $i % 10) { - $evaluation = $this->getRandomEvaluation(); - $action = $evaluation->getSocialAction(); - $issue = $action->getIssue(); - - $period->addSocialIssue($issue); - $work - ->setAccompanyingPeriod($period) - ->setSocialAction($action) - ->setStartDate(new \DateTimeImmutable('today')) - ->addPerson($period->getPersons()->first()) - ->setCreatedAt(new \DateTimeImmutable()) - ->setCreatedBy($this->getReference('center a_social')) - ->setUpdatedAt(new \DateTimeImmutable()) - ->setUpdatedBy($this->getReference('center a_social')) - ; - $manager->persist($work); - $ev = new AccompanyingPeriod\AccompanyingPeriodWorkEvaluation(); - $ev->setAccompanyingPeriodWork($work) - ->setEvaluation($evaluation); - $manager->persist($ev); - } - + if (0 === count($this->cacheEvaluations)) { + $this->cacheEvaluations = $this->evaluationRepository + ->findAll(); } - $manager->flush(); + return $this->cacheEvaluations[array_rand($this->cacheEvaluations)]; } } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadCustomFields.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadCustomFields.php index 235cadd95..1c51e45c3 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, +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,113 @@ 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/LoadHousehold.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHousehold.php index 50bf94e58..6f9edd768 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHousehold.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHousehold.php @@ -1,31 +1,45 @@ loader = new NativeLoader(); } + public function getDependencies() + { + return [ + LoadPeople::class, + LoadHouseholdPosition::class, + ]; + } + public function load(ObjectManager $manager) { // generate two times the participation. This will lead to @@ -45,87 +67,44 @@ class LoadHousehold extends Fixture implements DependentFixtureInterface $this->generateHousehold( $manager, - \DateTimeImmutable::createFromFormat('Y-m-d', '2010-01-01') + DateTimeImmutable::createFromFormat('Y-m-d', '2010-01-01') ); $this->preparePersonIds(); $this->generateHousehold( $manager, - \DateTimeImmutable::createFromFormat('Y-m-d', '2015-01-01') + DateTimeImmutable::createFromFormat('Y-m-d', '2015-01-01') ); $manager->flush(); } - private function generateHousehold(ObjectManager $manager, \DateTimeImmutable $startDate) + private function addAddressToHousehold(Household $household, DateTimeImmutable $date, ObjectManager $manager) { - for ($i=0; $i < self::NUMBER_OF_HOUSEHOLD; $i++) { - $household = new Household(); - $manager->persist($household); - - $this->addAddressToHousehold($household, clone $startDate, $manager); - - $movement = $this->editorFactory->createEditor($household); - - // load adults - $k = 0; - foreach ($this->getRandomPersons(1, 3) as $person) { - $date = $startDate->add(new \DateInterval('P'.\random_int(1, 200).'W')); - $position = $this->getReference(LoadHouseholdPosition::ADULT); - - $movement->addMovement($date, $person, $position, $k === 0, "self generated"); - $k++; - } - - // load children - foreach ($this->getRandomPersons(0, 3) as $person) { - $date = $startDate->add(new \DateInterval('P'.\random_int(1, 200).'W')); - $position = $this->getReference(LoadHouseholdPosition::CHILD); - - $movement->addMovement($date, $person, $position, $k === 0, "self generated"); - $k++; - } - - // load children out - foreach ($this->getRandomPersons(0, 2) as $person) { - $date = $startDate->add(new \DateInterval('P'.\random_int(1, 200).'W')); - $position = $this->getReference(LoadHouseholdPosition::CHILD_OUT); - - $movement->addMovement($date, $person, $position, $k === 0, "self generated"); - $k++; - } - - foreach ($movement->getPersistable() as $obj) { - $manager->persist($obj); - } - } - } - - private function addAddressToHousehold(Household $household, \DateTimeImmutable $date, ObjectManager $manager) - { - if (\random_int(0, 10) > 8) { + if (random_int(0, 10) > 8) { // 20% of household without address return; } - $nb = \random_int(1, 6); + $nb = random_int(1, 6); $i = 0; + while ($i < $nb) { $address = $this->createAddress(); - $address->setValidFrom(\DateTime::createFromImmutable($date)); + $address->setValidFrom(DateTime::createFromImmutable($date)); - if (\random_int(0, 20) < 1) { - $date = $date->add(new \DateInterval('P'.\random_int(8, 52).'W')); - $address->setValidTo(\DateTime::createFromImmutable($date)); + if (random_int(0, 20) < 1) { + $date = $date->add(new DateInterval('P' . random_int(8, 52) . 'W')); + $address->setValidTo(DateTime::createFromImmutable($date)); } $household->addAddress($address); $manager->persist($address); - $date = $date->add(new \DateInterval('P'.\random_int(8, 52).'W')); - $i++; + $date = $date->add(new DateInterval('P' . random_int(8, 52) . 'W')); + ++$i; } } @@ -136,54 +115,92 @@ class LoadHousehold extends Fixture implements DependentFixtureInterface 'address1' => [ 'street' => '', 'streetNumber' => '', - 'postCode' => $this->getPostalCode() - ] - ] + 'postCode' => $this->getPostalCode(), + ], + ], ]); return $objectSet->getObjects()['address1']; } - private function getPostalCode(): PostalCode + private function generateHousehold(ObjectManager $manager, DateTimeImmutable $startDate) { - $ref = LoadPostalCodes::$refs[\array_rand(LoadPostalCodes::$refs)]; + for ($i = 0; self::NUMBER_OF_HOUSEHOLD > $i; ++$i) { + $household = new Household(); + $manager->persist($household); - return $this->getReference($ref); + $this->addAddressToHousehold($household, clone $startDate, $manager); + + $movement = $this->editorFactory->createEditor($household); + + // load adults + $k = 0; + + foreach ($this->getRandomPersons(1, 3) as $person) { + $date = $startDate->add(new DateInterval('P' . random_int(1, 200) . 'W')); + $position = $this->getReference(LoadHouseholdPosition::ADULT); + + $movement->addMovement($date, $person, $position, 0 === $k, 'self generated'); + ++$k; + } + + // load children + foreach ($this->getRandomPersons(0, 3) as $person) { + $date = $startDate->add(new DateInterval('P' . random_int(1, 200) . 'W')); + $position = $this->getReference(LoadHouseholdPosition::CHILD); + + $movement->addMovement($date, $person, $position, 0 === $k, 'self generated'); + ++$k; + } + + // load children out + foreach ($this->getRandomPersons(0, 2) as $person) { + $date = $startDate->add(new DateInterval('P' . random_int(1, 200) . 'W')); + $position = $this->getReference(LoadHouseholdPosition::CHILD_OUT); + + $movement->addMovement($date, $person, $position, 0 === $k, 'self generated'); + ++$k; + } + + foreach ($movement->getPersistable() as $obj) { + $manager->persist($obj); + } + } } - private function preparePersonIds() + private function getPostalCode(): PostalCode { - // @TODO: Remove this and make this service stateless - $this->personIds = $this->em - ->createQuery('SELECT p.id FROM '.Person::class.' p '. - 'JOIN p.center c '. - 'WHERE c.name = :center ' - ) - ->setParameter('center', 'Center A') - ->getScalarResult(); + $ref = LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)]; - \shuffle($this->personIds); + return $this->getReference($ref); } private function getRandomPersons(int $min, int $max): array { $persons = []; - $nb = \random_int($min, $max); + $nb = random_int($min, $max); - for ($i=0; $i < $nb; $i++) { - $personId = \array_pop($this->personIds)['id']; + for ($i = 0; $i < $nb; ++$i) { + $personId = array_pop($this->personIds)['id']; $persons[] = $this->em->getRepository(Person::class)->find($personId); } return $persons; } - public function getDependencies() + private function preparePersonIds() { - return [ - LoadPeople::class, - LoadHouseholdPosition::class - ]; + // @TODO: Remove this and make this service stateless + $this->personIds = $this->em + ->createQuery( + 'SELECT p.id FROM ' . Person::class . ' p ' . + 'JOIN p.center c ' . + 'WHERE c.name = :center ' + ) + ->setParameter('center', 'Center A') + ->getScalarResult(); + + shuffle($this->personIds); } } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php index 23bd499f8..e12c88332 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHouseholdPosition.php @@ -1,5 +1,12 @@ setLabel([ "fr" => $name ]) + ->setLabel(['fr' => $name]) ->setAllowHolder($allowHolder) ->setShareHousehold($share) - ->setOrdering($ordering) - ; + ->setOrdering($ordering); $manager->persist($position); $this->addReference($ref, $position); 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 df471aedd..355dae785 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php @@ -1,26 +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\DataFixtures\ORM; +use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes; +use Chill\MainBundle\Doctrine\Model\Point; +use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Country; use Chill\MainBundle\Entity\PostalCode; @@ -32,386 +23,91 @@ use Chill\MainBundle\Repository\ScopeRepository; use Chill\MainBundle\Repository\UserRepository; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\MaritalStatus; +use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Repository\MaritalStatusRepository; -use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository; +use DateInterval; +use DateTime; +use DateTimeImmutable; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\PersonBundle\Entity\Person; +use Exception; use Faker\Factory; use Faker\Generator; -use Nelmio\Alice\Faker\GeneratorFactory; use Nelmio\Alice\Loader\NativeLoader; use Nelmio\Alice\ObjectSet; use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes; -use Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Doctrine\Model\Point; use Symfony\Component\Workflow\Registry; -use Symfony\Component\Workflow\Workflow; -use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository; +use function random_int; +use function ucfirst; /** - * Load people into database - * + * Load people into database. */ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface { use \Symfony\Component\DependencyInjection\ContainerAwareTrait; - protected Generator $faker; - - protected Registry $workflowRegistry; - - protected SocialIssueRepository $socialIssueRepository; - - protected CountryRepository $countryRepository; - - protected NativeLoader $loader; + public const PERSON = 'person'; /** - * @var array|SocialIssue[] + * @var array|Center[] */ - protected array $cacheSocialIssues = []; + protected array $cacheCenters = []; /** * @var array|Country[] */ protected array $cacheCountries = []; - /** - * @var array|Center[] - */ - protected array $cacheCenters = []; - - protected CenterRepository $centerRepository; - /** * @var array|MaritalStatus[] */ protected array $cacheMaritalStatuses = []; - protected MaritalStatusRepository $maritalStatusRepository; - /** * @var array|Scope[] */ protected array $cacheScopes = []; + /** + * @var array|SocialIssue[] + */ + protected array $cacheSocialIssues = []; + + /** + * @var array|User[] + */ + protected array $cacheUsers = []; + + protected CenterRepository $centerRepository; + + protected CountryRepository $countryRepository; + + protected Generator $faker; + + protected NativeLoader $loader; + + protected MaritalStatusRepository $maritalStatusRepository; + protected ScopeRepository $scopeRepository; - /** @var array|User[] */ - protected array $cacheUsers = []; + protected SocialIssueRepository $socialIssueRepository; protected UserRepository $userRepository; - public const PERSON = 'person'; + protected Registry $workflowRegistry; - public function __construct( - Registry $workflowRegistry, - SocialIssueRepository $socialIssueRepository, - CenterRepository $centerRepository, - CountryRepository $countryRepository, - MaritalStatusRepository $maritalStatusRepository, - ScopeRepository $scopeRepository, - UserRepository $userRepository - ) { - $this->faker = Factory::create('fr_FR'); - $this->faker->addProvider($this); - $this->workflowRegistry = $workflowRegistry; - $this->socialIssueRepository = $socialIssueRepository; - $this->centerRepository = $centerRepository; - $this->countryRepository = $countryRepository; - $this->maritalStatusRepository = $maritalStatusRepository; - $this->loader = new NativeLoader($this->faker); - $this->scopeRepository = $scopeRepository; - $this->userRepository = $userRepository; - } + private $genders = [Person::MALE_GENDER, Person::FEMALE_GENDER, Person::BOTH_GENDER]; - public function getOrder() - { - return 10000; - } - - public function load(ObjectManager $manager) - { - $this->loadExpectedPeople($manager); - $this->loadRandPeople($manager); - - $manager->flush(); - } - - public function loadExpectedPeople(ObjectManager $manager) - { - echo "loading expected people...\n"; - - - foreach ($this->peoples as $personDef) { - $person = $this->createExpectedPerson($personDef); - $this->addAPerson($person, $manager); - } - } - - protected function loadRandPeople(ObjectManager $manager) - { - echo "loading rand people...\n"; - $persons = $this->createRandPerson()->getObjects(); - - foreach ($persons as $person) { - $this->addAPerson($person, $manager); - } - } - - private function createRandPerson(): ObjectSet - { - return $this->loader->loadData([ - Person::class => [ - 'persons{1..300}' => [ - 'firstName' => '', - 'lastName' => '', - 'gender' => '', - 'nationality' => '', - 'center' => '', - 'maritalStatus' => '', - 'birthdate' => '', - 'placeOfBirth' => '', - 'email' => '', - 'countryOfBirth' => '', - ] - ] - ]); - } - - private function createExpectedPerson($default): Person - { - $person = $this->loader->loadData([ - Person::class => [ - "person" => [ - 'firstName' => $default['firstName'] ?? '', - 'lastName' => $default['lastName'] ?? '', - 'gender' => '', - 'nationality' => '', - 'center' => '', - 'maritalStatus' => '', - 'birthdate' => '', - 'placeOfBirth' => '', - 'email' => '', - 'countryOfBirth' => '', - ], - ] - ])->getObjects()['person']; - - // force some values - foreach ($default as $key => $value) { - switch ($key) { - case 'birthdate': - $person->setBirthdate(new \DateTime($value)); - break; - case 'center': - $person->setCenter($this->centerRepository - ->findOneBy(['name' => $value])); - break; - case 'countryOfBirth': - case 'nationality': - $country = $this->countryRepository - ->findOneBy(['countryCode' => $value]); - $person->{'set'.\ucfirst($key)}($country); - break; - case 'maritalStatus': - $person->setMaritalStatus($this->maritalStatusRepository - ->find($value)); - break; - } - } - - return $person; - } - - /** - * create a new person from array data - * - * @throws \Exception - */ - private function addAPerson(Person $person, ObjectManager $manager) - { - $accompanyingPeriod = new AccompanyingPeriod( - (new \DateTime()) - ->sub( - new \DateInterval('P' . \random_int(0, 180) . 'D') - ) - ); - $accompanyingPeriod->setCreatedBy($this->getRandomUser()) - ->setCreatedAt(new \DateTimeImmutable('now')); - $person->addAccompanyingPeriod($accompanyingPeriod); - $accompanyingPeriod->addSocialIssue($this->getRandomSocialIssue()); - - if (\random_int(0, 10) > 3) { - // always add social scope: - $accompanyingPeriod->addScope($this->getReference('scope_social')); - $origin = $this->getReference(LoadAccompanyingPeriodOrigin::ACCOMPANYING_PERIOD_ORIGIN); - $accompanyingPeriod->setOrigin($origin); - $accompanyingPeriod->setIntensity('regular'); - $accompanyingPeriod->setAddressLocation($this->createAddress()); - $manager->persist($accompanyingPeriod->getAddressLocation()); - $workflow = $this->workflowRegistry->get($accompanyingPeriod); - $workflow->apply($accompanyingPeriod, 'confirm'); - } - - $manager->persist($person); - $manager->persist($accompanyingPeriod); - echo "add person'".$person->__toString()."'\n"; - - $this->addReference(self::PERSON.$person->getId(), $person); - } - - private function getRandomUser(): User - { - if (0 === count($this->cacheUsers)) { - $this->cacheUsers = $this->userRepository->findAll(); - } - - return $this->cacheUsers[\array_rand($this->cacheUsers)]; - } - - private function createAddress(): Address - { - $objectSet = $this->loader->loadData([ - Address::class => [ - 'address' => [ - 'street' => '', - 'streetNumber' => '', - 'validFrom' => '', - 'postCode' => $this->getPostalCode() - ], - ], - ]); - - return $objectSet->getObjects()['address']; - } - - - - private function getRandomSocialIssue(): SocialIssue - { - if (0 === count($this->cacheSocialIssues)) { - $this->cacheSocialIssues = $this->socialIssueRepository->findAll(); - } - - return $this->cacheSocialIssues[\array_rand($this->cacheSocialIssues)]; - } - - private function getPostalCode(): PostalCode - { - $ref = LoadPostalCodes::$refs[\array_rand(LoadPostalCodes::$refs)]; - - return $this->getReference($ref); - } - - /** - * Create a random point - * - * @return Point - */ - private function getRandomPoint() - { - $lonBrussels = 4.35243; - $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')) - ; - } - - /** - * @internal This method is public and called by faker as a custom generator - * @return Center - */ - public function getRandomCenter(): Center - { - if (0 === count($this->cacheCenters)) { - $this->cacheCenters = $this->centerRepository->findAll(); - } - - return $this->cacheCenters[\array_rand($this->cacheCenters)]; - } - - /** - * @internal This method is public and called by faker as a custom generator - * @param int $nullPercentage - * @return Country|null - * @throws \Exception - */ - public function getRandomCountry(int $nullPercentage = 20): ?Country - { - if (0 === count($this->cacheCountries)) { - $this->cacheCountries = $this->countryRepository->findAll(); - } - - if ($nullPercentage < \random_int(0, 100)) { - return NULL; - } - - return $this->cacheCountries [\array_rand($this->cacheCountries)]; - } - - /** - * @internal This method is public and called by faker as a custom generator - * @return string - */ - public function getRandomGender(): string - { - return $this->genders[array_rand($this->genders)]; - } - - /** - * @internal This method is public and called by faker as a custom generator - * @param int $nullPercentage - * @return MaritalStatus|null - * @throws \Exception - */ - public function getRandomMaritalStatus(int $nullPercentage = 50): ?MaritalStatus - { - if (0 === count($this->cacheMaritalStatuses)) { - $this->cacheMaritalStatuses = $this->maritalStatusRepository->findAll(); - } - - if ($nullPercentage < \random_int(0, 100)) { - return NULL; - } - - return $this->cacheMaritalStatuses[array_rand($this->cacheMaritalStatuses)]; - } - - private $genders = array(Person::MALE_GENDER, Person::FEMALE_GENDER, Person::BOTH_GENDER); - - private $peoples = array( - array( - 'lastName' => "Depardieu", - 'firstName' => "Gérard", - 'birthdate' => "1948-12-27", - 'placeOfBirth' => "Châteauroux", + private $peoples = [ + [ + 'lastName' => 'Depardieu', + 'firstName' => 'Gérard', + 'birthdate' => '1948-12-27', + 'placeOfBirth' => 'Châteauroux', 'nationality' => 'RU', 'gender' => Person::MALE_GENDER, 'center' => 'Center A', @@ -420,73 +116,73 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con '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", + 'lastName' => 'Depardieu', + 'firstName' => 'Jean', + 'birthdate' => '1960-10-12', 'countryOfBirth' => 'FR', 'nationality' => 'FR', 'center' => 'Center A', - 'maritalStatus' => 'ms_divorce' - ), - array( + 'maritalStatus' => 'ms_divorce', + ], + [ //to have a person with same birthdate of Gérard Depardieu 'lastName' => 'Van Snick', 'firstName' => 'Bart', 'birthdate' => '1948-12-27', 'center' => 'Center A', - 'maritalStatus' => 'ms_legalco' - ), - array( + 'maritalStatus' => 'ms_legalco', + ], + [ //to have a woman with Depardieu as FirstName 'lastName' => 'Depardieu', 'firstName' => 'Charline', 'gender' => Person::FEMALE_GENDER, 'center' => 'Center A', - 'maritalStatus' => 'ms_legalco' - ), - array( + 'maritalStatus' => 'ms_legalco', + ], + [ //to have a special character in lastName 'lastName' => 'Manço', 'firstName' => 'Étienne', 'center' => 'Center A', - 'maritalStatus' => 'ms_unknown' - ), - array( + 'maritalStatus' => 'ms_unknown', + ], + [ //to have true duplicate person - 'lastName' => "Depardieu", - 'firstName' => "Jean", - 'birthdate' => "1960-10-12", + 'lastName' => 'Depardieu', + 'firstName' => 'Jean', + 'birthdate' => '1960-10-12', 'countryOfBirth' => 'FR', 'nationality' => 'FR', 'center' => 'Center A', - 'maritalStatus' => 'ms_divorce' - ), - array( + 'maritalStatus' => 'ms_divorce', + ], + [ //to have false duplicate person - 'lastName' => "Depardieu", - 'firstName' => "Jeanne", - 'birthdate' => "1966-11-13", + 'lastName' => 'Depardieu', + 'firstName' => 'Jeanne', + 'birthdate' => '1966-11-13', 'countryOfBirth' => 'FR', 'nationality' => 'FR', 'center' => 'Center A', - 'maritalStatus' => 'ms_legalco' - ), + 'maritalStatus' => 'ms_legalco', + ], [ 'lastName' => 'Diallo', - 'firstName' => "Fatoumata Binta" + 'firstName' => 'Fatoumata Binta', ], [ 'lastName' => 'Diallo', @@ -510,7 +206,7 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con ], [ 'lastName' => 'Bah', - 'firstName' => "Fatoumata Binta" + 'firstName' => 'Fatoumata Binta', ], [ 'lastName' => 'Bah', @@ -540,24 +236,320 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con 'lastName' => 'Gaillot', 'firstName' => 'Adèle', ], - ); + ]; -/* - private function addAccompanyingPeriods(Person $person, array $periods, ObjectManager $manager) + public function __construct( + Registry $workflowRegistry, + SocialIssueRepository $socialIssueRepository, + CenterRepository $centerRepository, + CountryRepository $countryRepository, + MaritalStatusRepository $maritalStatusRepository, + ScopeRepository $scopeRepository, + UserRepository $userRepository + ) { + $this->faker = Factory::create('fr_FR'); + $this->faker->addProvider($this); + $this->workflowRegistry = $workflowRegistry; + $this->socialIssueRepository = $socialIssueRepository; + $this->centerRepository = $centerRepository; + $this->countryRepository = $countryRepository; + $this->maritalStatusRepository = $maritalStatusRepository; + $this->loader = new NativeLoader($this->faker); + $this->scopeRepository = $scopeRepository; + $this->userRepository = $userRepository; + } + + public function getOrder() { - foreach ($periods as $period) { + return 10000; + } - echo "adding new past Accompanying Period..\n"; + /** + * @internal This method is public and called by faker as a custom generator + */ + public function getRandomCenter(): Center + { + if (0 === count($this->cacheCenters)) { + $this->cacheCenters = $this->centerRepository->findAll(); + } - /** @var AccompanyingPeriod $accompanyingPeriod - $accompanyingPeriod = new AccompanyingPeriod(new \DateTime($period['from'])); - $accompanyingPeriod - ->setClosingDate(new \DateTime($period['to'])) - ->setRemark($period['remark']) - ; + return $this->cacheCenters[\array_rand($this->cacheCenters)]; + } - $person->addAccompanyingPeriod($accompanyingPeriod); + /** + * @internal This method is public and called by faker as a custom generator + * + * @throws Exception + */ + public function getRandomCountry(int $nullPercentage = 20): ?Country + { + if (0 === count($this->cacheCountries)) { + $this->cacheCountries = $this->countryRepository->findAll(); + } + + if (random_int(0, 100) > $nullPercentage) { + return null; + } + + return $this->cacheCountries[\array_rand($this->cacheCountries)]; + } + + /** + * @internal This method is public and called by faker as a custom generator + */ + public function getRandomGender(): string + { + return $this->genders[array_rand($this->genders)]; + } + + /** + * @internal This method is public and called by faker as a custom generator + * + * @throws Exception + */ + public function getRandomMaritalStatus(int $nullPercentage = 50): ?MaritalStatus + { + if (0 === count($this->cacheMaritalStatuses)) { + $this->cacheMaritalStatuses = $this->maritalStatusRepository->findAll(); + } + + if (random_int(0, 100) > $nullPercentage) { + return null; + } + + return $this->cacheMaritalStatuses[array_rand($this->cacheMaritalStatuses)]; + } + + public function load(ObjectManager $manager) + { + $this->loadExpectedPeople($manager); + $this->loadRandPeople($manager); + + $manager->flush(); + } + + public function loadExpectedPeople(ObjectManager $manager) + { + echo "loading expected people...\n"; + + foreach ($this->peoples as $personDef) { + $person = $this->createExpectedPerson($personDef); + $this->addAPerson($person, $manager); } } - */ + + protected function loadRandPeople(ObjectManager $manager) + { + echo "loading rand people...\n"; + $persons = $this->createRandPerson()->getObjects(); + + foreach ($persons as $person) { + $this->addAPerson($person, $manager); + } + } + + /** + * create a new person from array data. + * + * @throws Exception + */ + private function addAPerson(Person $person, ObjectManager $manager) + { + $accompanyingPeriod = new AccompanyingPeriod( + (new DateTime()) + ->sub( + new DateInterval('P' . random_int(0, 180) . 'D') + ) + ); + $accompanyingPeriod->setCreatedBy($this->getRandomUser()) + ->setCreatedAt(new DateTimeImmutable('now')); + $person->addAccompanyingPeriod($accompanyingPeriod); + $accompanyingPeriod->addSocialIssue($this->getRandomSocialIssue()); + + if (random_int(0, 10) > 3) { + // always add social scope: + $accompanyingPeriod->addScope($this->getReference('scope_social')); + $origin = $this->getReference(LoadAccompanyingPeriodOrigin::ACCOMPANYING_PERIOD_ORIGIN); + $accompanyingPeriod->setOrigin($origin); + $accompanyingPeriod->setIntensity('regular'); + $accompanyingPeriod->setAddressLocation($this->createAddress()); + $manager->persist($accompanyingPeriod->getAddressLocation()); + $workflow = $this->workflowRegistry->get($accompanyingPeriod); + $workflow->apply($accompanyingPeriod, 'confirm'); + } + + $manager->persist($person); + $manager->persist($accompanyingPeriod); + echo "add person'" . $person->__toString() . "'\n"; + + $this->addReference(self::PERSON . $person->getId(), $person); + } + + private function createAddress(): Address + { + $objectSet = $this->loader->loadData([ + Address::class => [ + 'address' => [ + 'street' => '', + 'streetNumber' => '', + 'validFrom' => '', + 'postCode' => $this->getPostalCode(), + ], + ], + ]); + + return $objectSet->getObjects()['address']; + } + + private function createExpectedPerson($default): Person + { + $person = $this->loader->loadData([ + Person::class => [ + 'person' => [ + 'firstName' => $default['firstName'] ?? '', + 'lastName' => $default['lastName'] ?? '', + 'gender' => '', + 'nationality' => '', + 'center' => '', + 'maritalStatus' => '', + 'birthdate' => '', + 'placeOfBirth' => '', + 'email' => '', + 'countryOfBirth' => '', + ], + ], + ])->getObjects()['person']; + + // force some values + foreach ($default as $key => $value) { + switch ($key) { + case 'birthdate': + $person->setBirthdate(new DateTime($value)); + + break; + + case 'center': + $person->setCenter($this->centerRepository + ->findOneBy(['name' => $value])); + + break; + + case 'countryOfBirth': + case 'nationality': + $country = $this->countryRepository + ->findOneBy(['countryCode' => $value]); + $person->{'set' . ucfirst($key)}($country); + + break; + + case 'maritalStatus': + $person->setMaritalStatus($this->maritalStatusRepository + ->find($value)); + + break; + } + } + + return $person; + } + + private function createRandPerson(): ObjectSet + { + return $this->loader->loadData([ + Person::class => [ + 'persons{1..300}' => [ + 'firstName' => '', + 'lastName' => '', + 'gender' => '', + 'nationality' => '', + 'center' => '', + 'maritalStatus' => '', + 'birthdate' => '', + 'placeOfBirth' => '', + 'email' => '', + 'countryOfBirth' => '', + ], + ], + ]); + } + + private function getPostalCode(): PostalCode + { + $ref = LoadPostalCodes::$refs[\array_rand(LoadPostalCodes::$refs)]; + + return $this->getReference($ref); + } + + /** + * 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 + */ + private function getRandomPoint() + { + $lonBrussels = 4.35243; + $latBrussels = 50.84676; + $lon = $lonBrussels + 0.01 * rand(-5, 5); + $lat = $latBrussels + 0.01 * rand(-5, 5); + + return Point::fromLonLat($lon, $lat); + } + + private function getRandomSocialIssue(): SocialIssue + { + if (0 === count($this->cacheSocialIssues)) { + $this->cacheSocialIssues = $this->socialIssueRepository->findAll(); + } + + return $this->cacheSocialIssues[\array_rand($this->cacheSocialIssues)]; + } + + private function getRandomUser(): User + { + if (0 === count($this->cacheUsers)) { + $this->cacheUsers = $this->userRepository->findAll(); + } + + return $this->cacheUsers[\array_rand($this->cacheUsers)]; + } + + /* + 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 18f8e5879..a0418e02b 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,7 +28,6 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface return 9600; } - public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { @@ -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,13 +62,13 @@ 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); @@ -89,19 +76,19 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface $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/DataFixtures/ORM/LoadRelations.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php index 3b2b4518e..e2bb469bc 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelations.php @@ -1,4 +1,12 @@ ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fille']], ['title' => ['fr' => 'Mère'], 'reverseTitle' => ['fr' => 'Fils']], ['title' => ['fr' => 'Père'], 'reverseTitle' => ['fr' => 'Fille']], @@ -38,17 +47,16 @@ class LoadRelations extends Fixture implements FixtureGroupInterface public function load(ObjectManager $manager) { - foreach (self::RELATIONS as $key => $value){ - print "Creating a new relation type: relation" . $value['title']['fr'] . "reverse relation: " . $value['reverseTitle']['fr'] . "\n"; + foreach (self::RELATIONS as $key => $value) { + echo 'Creating a new relation type: relation' . $value['title']['fr'] . 'reverse relation: ' . $value['reverseTitle']['fr'] . "\n"; $relation = new Relation(); $relation->setTitle($value['title']) ->setReverseTitle($value['reverseTitle']); $manager->persist($relation); - $this->addReference(self::RELATION_KEY.$key, $relation); + $this->addReference(self::RELATION_KEY . $key, $relation); } $manager->flush(); } - } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php index cce6d0365..3d52e9352 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadRelationships.php @@ -1,4 +1,12 @@ $i; ++$i) { $user = $this->getRandomUser(); - $date = new \DateTimeImmutable(); + $date = new DateTimeImmutable(); $relationship = (new Relationship()) ->setFromPerson($this->getRandomPerson($this->em)) ->setToPerson($this->getRandomPerson($this->em)) - ->setRelation($this->getReference(LoadRelations::RELATION_KEY. + ->setRelation($this->getReference(LoadRelations::RELATION_KEY . \random_int(0, count(LoadRelations::RELATIONS) - 1))) ->setReverse((bool) random_int(0, 1)) ->setCreatedBy($user) ->setUpdatedBy($user) ->setCreatedAt($date) - ->setUpdatedAt($date) - ; + ->setUpdatedAt($date); $manager->persist($relationship); } @@ -55,6 +64,7 @@ class LoadRelationships extends Fixture implements DependentFixtureInterface private function getRandomUser(): User { $userRef = array_rand(LoadUsers::$refs); + return $this->getReference($userRef); } } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadSocialWorkMetadata.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadSocialWorkMetadata.php index eee7df7b6..4501ef51e 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadSocialWorkMetadata.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadSocialWorkMetadata.php @@ -1,5 +1,12 @@ importer = $importer; } - public function load(ObjectManager $manager) - { - try { - $csv = Reader::createFromPath(__DIR__.'/data/social_work_metadata.csv'); - } catch (\Throwable $e) { - throw new \Exception('Error while loading CSV.',0, $e); - } - - $csv->setDelimiter(";"); - - $this->importer->import($csv); - } - public function getOrder() { return 9500; } + + public function load(ObjectManager $manager) + { + try { + $csv = Reader::createFromPath(__DIR__ . '/data/social_work_metadata.csv'); + } catch (Throwable $e) { + throw new Exception('Error while loading CSV.', 0, $e); + } + + $csv->setDelimiter(';'); + + $this->importer->import($csv); + } } diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index ce4169741..84d1c1a71 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -1,50 +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\DependencyInjection; -use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; -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\AccompanyingPeriodVoter; +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,19 +39,23 @@ 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'] + ); // register all configuration in a unique parameter $container->setParameter('chill_person', $config); - $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'); @@ -92,70 +83,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) @@ -169,147 +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' - ) - ) - )); - } - - protected function prependWorkflows(ContainerBuilder $container) - { - $container->prependExtensionConfig('framework', [ - 'workflows' => [ - 'accompanying_period_lifecycle' => [ - 'type' => 'state_machine', - 'audit_trail' => [ - 'enabled' => true - ], - 'marking_store' => [ - 'type' => 'method', - 'property' => 'step', - ], - 'supports' => [ - 'Chill\PersonBundle\Entity\AccompanyingPeriod' - ], - 'initial_marking' => 'DRAFT', - 'places' => [ - 'DRAFT', - 'CONFIRMED', - ], - 'transitions' => [ - 'confirm' => [ - 'from' => 'DRAFT', - 'to' => 'CONFIRMED' - ], - ], + $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', [ - 'role_hierarchy' => [ - PersonVoter::UPDATE => [PersonVoter::SEE], - PersonVoter::CREATE => [PersonVoter::SEE], - PersonVoter::LISTS => [ChillExportVoter::EXPORT], - PersonVoter::STATS => [ChillExportVoter::EXPORT], - // accompanying period - AccompanyingPeriodVoter::SEE_DETAILS => [AccompanyingPeriodVoter::SEE], - AccompanyingPeriodVoter::CREATE => [AccompanyingPeriodVoter::SEE_DETAILS], - AccompanyingPeriodVoter::DELETE => [AccompanyingPeriodVoter::SEE_DETAILS], - AccompanyingPeriodVoter::EDIT => [AccompanyingPeriodVoter::SEE_DETAILS], - // give all ACL for FULL - AccompanyingPeriodVoter::FULL => [ - AccompanyingPeriodVoter::SEE_DETAILS, - AccompanyingPeriodVoter::CREATE, - AccompanyingPeriodVoter::EDIT, - AccompanyingPeriodVoter::DELETE - ] - ] + ], ]); } - /** - * 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', [ @@ -323,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, @@ -346,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', - ] - ] + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\SocialIssue::class, @@ -367,15 +178,15 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/SocialIssue/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\SocialAction::class, @@ -388,15 +199,15 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/SocialAction/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\Goal::class, @@ -409,15 +220,15 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/Goal/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\Result::class, @@ -430,15 +241,15 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/Result/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\Evaluation::class, @@ -451,15 +262,15 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/Evaluation/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/SocialWork/edit.html.twig', - ] - ] + ], + ], ], ], 'apis' => [ @@ -479,7 +290,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_GET => true, Request::METHOD_PUT => true, Request::METHOD_PATCH => true, - ] + ], ], 'participation' => [ 'methods' => [ @@ -490,8 +301,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], '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, + ], ], 'resource' => [ 'methods' => [ @@ -502,8 +313,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], '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, + ], ], 'comment' => [ 'methods' => [ @@ -514,8 +325,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], '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, + ], ], 'requestor' => [ 'methods' => [ @@ -526,8 +337,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], '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, + ], ], 'scope' => [ 'methods' => [ @@ -538,8 +349,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], '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, + ], ], 'socialissue' => [ 'methods' => [ @@ -551,8 +362,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'controller_action' => 'socialIssueApi', '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, + ], ], 'work' => [ 'methods' => [ @@ -565,7 +376,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, Request::METHOD_DELETE => 'ALWAYS_FAILS', - ] + ], ], 'confirm' => [ @@ -576,7 +387,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], 'roles' => [ Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, - ] + ], ], 'findAccompanyingPeriodsByPerson' => [ 'path' => '/by-person/{person_id}.{_format}', @@ -584,9 +395,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - ] - ] - ] + ], + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\Origin::class, @@ -598,16 +409,16 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true - ] + Request::METHOD_HEAD => true, + ], ], - ] + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\SocialIssue::class, @@ -619,16 +430,16 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true - ] + Request::METHOD_HEAD => true, + ], ], - ] + ], ], [ 'class' => \Chill\PersonBundle\Entity\Person::class, @@ -641,8 +452,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - Request::METHOD_POST=> true, - Request::METHOD_PATCH => true + Request::METHOD_POST => true, + Request::METHOD_PATCH => true, ], 'roles' => [ Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE, @@ -658,9 +469,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_GET => false, Request::METHOD_HEAD => false, ], - 'controller_action' => 'personAddressApi' + 'controller_action' => 'personAddressApi', ], - ] + ], ], [ 'class' => \Chill\PersonBundle\Entity\Household\Household::class, @@ -679,7 +490,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - ] + ], ], 'address' => [ 'methods' => [ @@ -688,16 +499,16 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_GET => false, Request::METHOD_HEAD => false, ], - 'controller_action' => 'householdAddressApi' + 'controller_action' => 'householdAddressApi', ], 'suggestHouseholdByAccompanyingPeriodParticipation' => [ 'path' => '/suggest/by-person/{person_id}/through-accompanying-period-participation.{_format}', 'methods' => [ Request::METHOD_GET => true, Request::METHOD_HEAD => true, - ] - ] - ] + ], + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\SocialAction::class, @@ -715,7 +526,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], '_index' => [ 'methods' => [ @@ -725,7 +536,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], 'listBySocialIssue' => [ 'single-collection' => 'collection', @@ -737,10 +548,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] - - ] - ] + ], + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork::class, @@ -762,9 +572,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_HEAD => 'ROLE_USER', Request::METHOD_PATCH => 'ROLE_USER', Request::METHOD_PUT => 'ROLE_USER', - ] + ], ], - ] + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\Result::class, @@ -781,7 +591,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], '_index' => [ 'methods' => [ @@ -791,7 +601,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], 'by-social-action' => [ 'single-collection' => 'collection', @@ -804,7 +614,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], 'by-goal' => [ 'single-collection' => 'collection', @@ -817,9 +627,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], - ] + ], ], [ 'class' => \Chill\PersonBundle\Entity\SocialWork\Goal::class, @@ -836,7 +646,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], '_index' => [ 'methods' => [ @@ -846,7 +656,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], 'by-social-action' => [ 'single-collection' => 'collection', @@ -859,9 +669,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], - ] + ], ], [ 'class' => \Chill\PersonBundle\Entity\Relationships\Relationship::class, @@ -880,7 +690,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac Request::METHOD_POST => 'ROLE_USER', Request::METHOD_PATCH => 'ROLE_USER', Request::METHOD_DELETE => 'ROLE_USER', - ] + ], ], 'relationship-by-person' => [ 'path' => '/by-person/{person_id}.json', @@ -892,9 +702,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'roles' => [ Request::METHOD_GET => 'ROLE_USER', Request::METHOD_HEAD => 'ROLE_USER', - ] + ], ], - ] + ], ], [ 'class' => \Chill\PersonBundle\Entity\Relationships\Relation::class, @@ -905,18 +715,197 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac '_index' => [ 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ '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' => [ + PersonVoter::UPDATE => [PersonVoter::SEE], + PersonVoter::CREATE => [PersonVoter::SEE], + PersonVoter::LISTS => [ChillExportVoter::EXPORT], + PersonVoter::STATS => [ChillExportVoter::EXPORT], + // accompanying period + AccompanyingPeriodVoter::SEE_DETAILS => [AccompanyingPeriodVoter::SEE], + AccompanyingPeriodVoter::CREATE => [AccompanyingPeriodVoter::SEE_DETAILS], + AccompanyingPeriodVoter::DELETE => [AccompanyingPeriodVoter::SEE_DETAILS], + AccompanyingPeriodVoter::EDIT => [AccompanyingPeriodVoter::SEE_DETAILS], + // give all ACL for FULL + AccompanyingPeriodVoter::FULL => [ + AccompanyingPeriodVoter::SEE_DETAILS, + AccompanyingPeriodVoter::CREATE, + AccompanyingPeriodVoter::EDIT, + AccompanyingPeriodVoter::DELETE, + ], + ], + ]); + } + + protected function prependWorkflows(ContainerBuilder $container) + { + $container->prependExtensionConfig('framework', [ + 'workflows' => [ + 'accompanying_period_lifecycle' => [ + 'type' => 'state_machine', + 'audit_trail' => [ + 'enabled' => true, + ], + 'marking_store' => [ + 'type' => 'method', + 'property' => 'step', + ], + 'supports' => [ + 'Chill\PersonBundle\Entity\AccompanyingPeriod', + ], + 'initial_marking' => 'DRAFT', + 'places' => [ + 'DRAFT', + 'CONFIRMED', + 'CLOSED', + ], + 'transitions' => [ + 'confirm' => [ + 'from' => 'DRAFT', + 'to' => 'CONFIRMED', + ], + 'close' => [ + 'from' => 'CONFIRMED', + 'to' => 'CLOSED', + ], + ], + ], + ], + ]); + } + + /** + * @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..a6ce583f2 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/CompilerPass/AccompanyingPeriodTimelineCompilerPass.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/CompilerPass/AccompanyingPeriodTimelineCompilerPass.php @@ -1,29 +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\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 +25,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 4e42e3137..68a8e1fd5 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php @@ -1,140 +1,149 @@ getRootNode('cl_chill_person'); $rootNode - ->canBeDisabled() - ->children() - ->arrayNode('validation') - ->canBeDisabled() - ->children() - ->booleanNode('center_required') - ->info('Enable a center for each person entity. If disabled, you must provide your own center provider') - ->defaultValue(true) - ->end() - ->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" ' + ->canBeDisabled() + ->children() + ->arrayNode('validation') + ->canBeDisabled() + ->children() + ->booleanNode('center_required') + ->info('Enable a center for each person entity. If disabled, you must provide your own center provider') + ->defaultValue(true) + ->end() + ->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('civility')) - ->append($this->addFieldNode('spoken_languages')) - ->append($this->addFieldNode('address')) - ->append($this->addFieldNode('accompanying_period')) - ->append($this->addFieldNode('memo')) - ->append($this->addFieldNode('number_of_children')) - ->append($this->addFieldNode('acceptEmail')) - ->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('civility')) + ->append($this->addFieldNode('spoken_languages')) + ->append($this->addFieldNode('address')) + ->append($this->addFieldNode('accompanying_period')) + ->append($this->addFieldNode('memo')) + ->append($this->addFieldNode('number_of_children')) + ->append($this->addFieldNode('acceptEmail')) + ->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 74c7be856..958d7d58b 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -1,90 +1,85 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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\Doctrine\Model\TrackUpdateInterface; use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; +use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; +use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\HasCentersInterface; use Chill\MainBundle\Entity\HasScopesInterface; use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; 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\PersonBundle\Entity\SocialWork\SocialIssue; +use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap; +use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ResourceDuplicateCheck; use Chill\ThirdPartyBundle\Entity\ThirdParty; +use DateTime; +use DateTimeImmutable; use DateTimeInterface; 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; -use Symfony\Component\Serializer\Annotation\Groups; +use LogicException; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\GroupSequenceProviderInterface; -use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap; -use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ResourceDuplicateCheck; +use UnexpectedValueException; /** - * AccompanyingPeriod Class + * AccompanyingPeriod Class. * * @ORM\Entity * @ORM\Table(name="chill_person_accompanying_period") * @DiscriminatorMap(typeProperty="type", mapping={ - * "accompanying_period"=AccompanyingPeriod::class - * }) + * "accompanying_period": AccompanyingPeriod::class + * }) * @Assert\GroupSequenceProvider */ -class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface, - HasScopesInterface, HasCentersInterface, GroupSequenceProviderInterface +class AccompanyingPeriod implements + TrackCreationInterface, + TrackUpdateInterface, + HasScopesInterface, + HasCentersInterface, + GroupSequenceProviderInterface { + 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". + * Mark an accompanying period as "closed". * - * This means that the accompanying period is not yet - * confirmed by the creator + * This means that the accompanying period **is** + * closed by the creator */ - public const STEP_DRAFT = 'DRAFT'; + public const STEP_CLOSED = 'CLOSED'; /** * Mark an accompanying period as "confirmed". @@ -95,86 +90,64 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface public const STEP_CONFIRMED = 'CONFIRMED'; /** - * @var integer + * Mark an accompanying period as "draft". * - * @ORM\Id - * @ORM\Column(name="id", type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - * @Groups({"read"}) + * This means that the accompanying period is not yet + * confirmed by the creator */ - private $id; - - /** - * @var \DateTime - * - * @ORM\Column(type="date") - * @Groups({"read", "write"}) - */ - private $openingDate; - - /** - * @var \DateTime - * - * @ORM\Column(type="date", nullable=true) - * @Groups({"read", "write"}) - */ - private $closingDate = null; - - /** - * @var string - * - * @ORM\Column(type="text") - * @Groups({"read", "write"}) - */ - private $remark = ''; - - /** - * @var Collection - * - * @ORM\OneToMany(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\Comment", - * mappedBy="accompanyingPeriod", - * cascade={"persist", "remove"}, - * orphanRemoval=true - * ) - * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_DRAFT}) - */ - private $comments; + public const STEP_DRAFT = 'DRAFT'; /** * @ORM\ManyToOne( - * targetEntity=Comment::class + * targetEntity=Address::class * ) - * @Groups({"read"}) */ - private ?Comment $initialComment = null; + private ?Address $addressLocation = null; /** - * @var Collection + * @var DateTime * - * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class, - * mappedBy="accompanyingPeriod", orphanRemoval=true, - * cascade={"persist", "refresh", "remove", "merge", "detach"}) - * @Groups({"read"}) - * @ParticipationOverlap(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED}) + * @ORM\Column(type="date", nullable=true) + * @Groups({"read", "write"}) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CLOSED}) + * @Assert\GreaterThan(propertyPath="openingDate", groups={AccompanyingPeriod::STEP_CLOSED}) */ - private $participations; + private $closingDate; /** * @var AccompanyingPeriod\ClosingMotive * * @ORM\ManyToOne( - * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive") + * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive") * @ORM\JoinColumn(nullable=true) * @Groups({"read", "write"}) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CLOSED}) */ - private $closingMotive = null; + private $closingMotive; /** - * @ORM\ManyToOne(targetEntity=User::class) - * @ORM\JoinColumn(nullable=true) + * @var Collection + * + * @ORM\OneToMany(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\Comment", + * mappedBy="accompanyingPeriod", + * cascade={"persist", "remove"}, + * orphanRemoval=true + * ) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_DRAFT}) + */ + private $comments; + + /** + * @var bool + * @ORM\Column(type="boolean", options={"default": false}) * @Groups({"read", "write"}) */ - private $user; + private $confidential = false; + + /** + * @ORM\Column(type="datetime", nullable=true, options={"default": NULL}) + */ + private DateTimeInterface $createdAt; /** * @ORM\ManyToOne(targetEntity=User::class) @@ -184,19 +157,29 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface private $createdBy; /** - * @var string - * @ORM\Column(type="string", length=32, nullable=true) - * @Groups({"read"}) + * @var bool + * @ORM\Column(type="boolean", options={"default": false}) + * @Groups({"read", "write"}) */ - private $step = self::STEP_DRAFT; + private $emergency = false; /** - * @ORM\ManyToOne(targetEntity=Origin::class) - * @ORM\JoinColumn(nullable=true) - * @Groups({"read", "write"}) - * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED}) + * @var int + * + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + * @Groups({"read"}) */ - private $origin; + private $id; + + /** + * @ORM\ManyToOne( + * targetEntity=Comment::class + * ) + * @Groups({"read"}) + */ + private ?Comment $initialComment = null; /** * @var string @@ -207,20 +190,54 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface private $intensity = self::INTENSITY_OCCASIONAL; /** - * @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")} - * ) - * @Groups({"read"}) - * @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}) + * @var DateTime + * + * @ORM\Column(type="date") + * @Groups({"read", "write"}) */ - private $scopes; + private $openingDate; + + /** + * @ORM\ManyToOne(targetEntity=Origin::class) + * @ORM\JoinColumn(nullable=true) + * @Groups({"read", "write"}) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED}) + */ + private $origin; + + /** + * @var Collection + * + * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class, + * mappedBy="accompanyingPeriod", orphanRemoval=true, + * cascade={"persist", "refresh", "remove", "merge", "detach"}) + * @Groups({"read"}) + * @ParticipationOverlap(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED}) + */ + private $participations; + + /** + * @ORM\ManyToOne( + * targetEntity=Person::class, + * inversedBy="periodLocatedOn" + * ) + */ + private ?Person $personLocation = null; + + /** + * @var string + * + * @ORM\Column(type="text") + * @Groups({"read", "write"}) + */ + private $remark = ''; + + /** + * @var bool + * @ORM\Column(type="boolean", options={"default": false}) + * @Groups({"read", "write"}) + */ + private $requestorAnonymous = false; /** * @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodRequested") @@ -234,27 +251,6 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface */ private $requestorThirdParty; - /** - * @var bool - * @ORM\Column(type="boolean", options={"default": false} ) - * @Groups({"read", "write"}) - */ - private $requestorAnonymous = false; - - /** - * @var bool - * @ORM\Column(type="boolean", options={"default": false} ) - * @Groups({"read", "write"}) - */ - private $emergency = false; - - /** - * @var bool - * @ORM\Column(type="boolean", options={"default": false} ) - * @Groups({"read", "write"}) - */ - private $confidential = false; - /** * @var Collection * @@ -269,68 +265,79 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface */ 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")} + * ) + * @Groups({"read"}) + * @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}) + */ + private $scopes; + /** * @ORM\ManyToMany( * targetEntity=SocialIssue::class * ) * @ORM\JoinTable( * name="chill_person_accompanying_period_social_issues" - * ) + * ) * @Groups({"read"}) * @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}) */ private Collection $socialIssues; + /** + * @var string + * @ORM\Column(type="string", length=32, nullable=true) + * @Groups({"read"}) + */ + private $step = self::STEP_DRAFT; + /** * @ORM\Column(type="datetime", nullable=true, options={"default": NULL}) */ - private \DateTimeInterface $createdAt; + private DateTimeInterface $updatedAt; /** * @ORM\ManyToOne( - * targetEntity=User::class + * targetEntity=User::class * ) */ private User $updatedBy; /** - * @ORM\Column(type="datetime", nullable=true, options={"default": NULL}) + * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\JoinColumn(nullable=true) + * @Groups({"read", "write"}) */ - private \DateTimeInterface $updatedAt; + private $user; /** * @ORM\OneToMany( - * targetEntity=AccompanyingPeriodWork::class, - * mappedBy="accompanyingPeriod" + * targetEntity=AccompanyingPeriodWork::class, + * mappedBy="accompanyingPeriod" * ) * @Assert\Valid(traverse=true) */ private Collection $works; - /** - * @ORM\ManyToOne( - * targetEntity=Person::class, - * inversedBy="periodLocatedOn" - * ) - */ - private ?Person $personLocation = null; - - - /** - * @ORM\ManyToOne( - * targetEntity=Address::class - * ) - */ - private ?Address $addressLocation = null; - /** * AccompanyingPeriod constructor. * - * @param \DateTime $dateOpening + * @param DateTime $dateOpening + * * @uses AccompanyingPeriod::setClosingDate() */ - public function __construct(\DateTime $dateOpening = null) { - $this->setOpeningDate($dateOpening ?? new \DateTime('now')); + public function __construct(?DateTime $dateOpening = null) + { + $this->setOpeningDate($dateOpening ?? new DateTime('now')); $this->participations = new ArrayCollection(); $this->scopes = new ArrayCollection(); $this->socialIssues = new ArrayCollection(); @@ -338,198 +345,6 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface $this->works = 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 = null): self - { - $this->remark = (string) $remark; - - return $this; - } - - public function getRemark(): string - { - return $this->remark; - } - - /** - * @Groups({"read"}) - */ - public function getComments(): Collection - { - return $this->comments->filter(function (Comment $c) { - return $c !== $this->initialComment; - }); - } - - public function addComment(Comment $comment): self - { - $this->comments[] = $comment; - $comment->setAccompanyingPeriod($this); - - return $this; - } - - public function removeComment(Comment $comment): void - { - $comment->setAccompanyingPeriod(null); - $this->comments->removeElement($comment); - } - - /** - * @Groups({"write"}) - */ - public function setInitialComment(?Comment $comment = null): self - { - if (NULL !== $this->initialComment) { - $this->removeComment($this->initialComment); - } - if ($comment instanceof Comment) { - $this->addComment($comment); - } - - $this->initialComment = $comment; - - return $this; - } - - /** - * @Groups({"read"}) - */ - public function getInitialComment(): ?Comment - { - return $this->initialComment; - } - - /** - * Get Participations Collection - */ - public function getParticipations(): Collection - { - return $this->participations; - } - - /** - * Get the participation containing a person - */ - public function getParticipationsContainsPerson(Person $person): Collection - { - return $this - ->getParticipations() - ->filter( - static function(AccompanyingPeriodParticipation $participation) use ($person): bool { - return $person === $participation->getPerson(); - } - ); - } - - /** - * 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( - static function(AccompanyingPeriodParticipation $participation): bool { - return null === $participation->getEndDate(); - } - ); - - return $collection->count() > 0 ? $collection->first() : NULL; - } - - public function getOpenParticipations(): Collection - { - return $this - ->getParticipations() - ->filter( - static function(AccompanyingPeriodParticipation $participation): bool { - return null === $participation->getEndDate(); - } - ); - } - - public function getCurrentParticipations(): Collection - { - return $this->getOpenParticipations(); - } - /** * Return an array with open participations sorted by household * [ @@ -539,112 +354,84 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface * Participation y , Participation z, ... * ] * ], - * ] - * + * ]. */ public function actualParticipationsByHousehold(): array { $participations = $this->getOpenParticipations()->toArray(); $households = []; + foreach ($participations as $p) { $households[] = $p->getPerson()->getCurrentHousehold(); } $households = array_unique($households, SORT_REGULAR); $array = []; + foreach ($households as $household) { $members = []; + foreach ($participations as $p) { - if ($household === $p->getPerson()->getCurrentHousehold()) { + if ($p->getPerson()->getCurrentHousehold() === $household) { $members[] = array_shift($participations); } else { $participations[] = array_shift($participations); } } - $array[] = [ 'household' => $household, 'members' => $members ]; + $array[] = ['household' => $household, 'members' => $members]; } return $array; } - /** - * Return true if the accompanying period contains a person. - * - * **Note**: this participation can be opened or not. - */ - public function containsPerson(Person $person): bool + public function addComment(Comment $comment): self { - return $this->getParticipationsContainsPerson($person)->count() > 0; + $this->comments[] = $comment; + $comment->setAccompanyingPeriod($this); + + return $this; } - /** - * Open a new participation for a person - */ - public function createParticipationFor(Person $person): AccompanyingPeriodParticipation + public function addPerson(?Person $person = null): self { - $participation = new AccompanyingPeriodParticipation($this, $person); - $this->participations[] = $participation; - - return $participation; - } - - public function addPerson(Person $person = null): self - { - if (NULL !== $person) { + if (null !== $person) { $this->createParticipationFor($person); } return $this; } - /** - * Close a participation for a person - * - * Search for the person's participation and set the end date at - * 'now'. - * - * @return void - */ - public function closeParticipationFor($person): ?AccompanyingPeriodParticipation + public function addResource(Resource $resource): self { - $participation = $this->getOpenParticipationContainsPerson($person); - - if ($participation instanceof AccompanyingPeriodParticipation) { - $participation->setEndDate(new \DateTimeImmutable('now')); - } - - return $participation; - } - - /** - * Remove Participation - */ - - public function removeParticipation(AccompanyingPeriodParticipation $participation) - { - $participation->setAccompanyingPeriod(null); - } - - /** - * Remove Person - */ - public function removePerson(Person $person): self - { - $this->closeParticipationFor($person); + $resource->setAccompanyingPeriod($this); + $this->resources[] = $resource; return $this; } - - public function getClosingMotive(): ?ClosingMotive + public function addScope(Scope $scope): self { - return $this->closingMotive; + if (!$this->scopes->contains($scope)) { + $this->scopes[] = $scope; + } + + return $this; } - public function setClosingMotive(ClosingMotive $closingMotive = null): self + public function addSocialIssue(SocialIssue $socialIssue): self { - $this->closingMotive = $closingMotive; + if (!$this->socialIssues->contains($socialIssue)) { + $this->socialIssues[] = $socialIssue; + } + + return $this; + } + + public function addWork(AccompanyingPeriodWork $work): self + { + $this->works[] = $work; + $work->setAccompanyingPeriod($this); return $this; } @@ -663,8 +450,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface $participation = $this->getOpenParticipationContainsPerson($person); - if (null === $participation) - { + if (null === $participation) { return false; } @@ -674,57 +460,229 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface } /** - */ - 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. + * Close a participation for a person. * - * @return boolean + * Search for the person's participation and set the end date at + * 'now'. + * + * @param mixed $person + * + * @return void */ - public function isClosingAfterOpening(): bool + public function closeParticipationFor($person): ?AccompanyingPeriodParticipation { - if (null === $this->getClosingDate()) { - return false; - } - $diff = $this->getOpeningDate()->diff($this->getClosingDate()); + $participation = $this->getOpenParticipationContainsPerson($person); - if ($diff->invert === 0) { - return true; + if ($participation instanceof AccompanyingPeriodParticipation) { + $participation->setEndDate(new DateTimeImmutable('now')); } - return false; + + return $participation; } - function getUser(): ?User + /** + * 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->user; + return $this->getParticipationsContainsPerson($person)->count() > 0; } - function setUser(User $user): self + /** + * Open a new participation for a person. + */ + public function createParticipationFor(Person $person): AccompanyingPeriodParticipation { - $this->user = $user; + $participation = new AccompanyingPeriodParticipation($this, $person); + $this->participations[] = $participation; - return $this; + return $participation; + } + + public function getAddressLocation(): ?Address + { + return $this->addressLocation; + } + + /** + * Get a list of person which have an adresse available for a valid location. + * + * @return Collection|Person[] + */ + public function getAvailablePersonLocation(): Collection + { + return $this->getOpenParticipations() + ->filter(function (AccompanyingPeriodParticipation $p) { + return $p->getPerson()->hasCurrentHouseholdAddress(); + }) + ->map(function (AccompanyingPeriodParticipation $p) { + return $p->getPerson(); + }); + } + + public function getCenter(): ?Center + { + if (count($this->getPersons()) === 0) { + return null; + } + + return $this->getPersons()->first()->getCenter(); + } + + public function getCenters(): ?iterable + { + foreach ($this->getPersons() as $person) { + if (!in_array($person->getCenter(), $centers ?? []) + && null !== $person->getCenter()) { + $centers[] = $person->getCenter(); + } + } + + return $centers ?? null; + } + + /** + * Get closingDate. + * + * @return DateTime + */ + public function getClosingDate(): ?DateTime + { + return $this->closingDate; + } + + public function getClosingMotive(): ?ClosingMotive + { + return $this->closingMotive; + } + + /** + * @Groups({"read"}) + */ + public function getComments(): Collection + { + return $this->comments->filter(function (Comment $c) { + return $c !== $this->initialComment; + }); + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; + } + + public function getCurrentParticipations(): Collection + { + return $this->getOpenParticipations(); + } + + public function getGroupSequence() + { + if ($this->getStep() == self::STEP_DRAFT) { + return [[self::STEP_DRAFT]]; + } + + if ($this->getStep() == self::STEP_CONFIRMED) { + return [[self::STEP_DRAFT, self::STEP_CONFIRMED]]; + } + + throw new LogicException('no validation group permitted with this step'); + } + + /** + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @Groups({"read"}) + */ + public function getInitialComment(): ?Comment + { + return $this->initialComment; + } + + public function getIntensity(): ?string + { + return $this->intensity; + } + + /** + * Get the location, taking precedence into account. + * + * @Groups({"read"}) + */ + public function getLocation(?DateTimeImmutable $at = null): ?Address + { + if ($this->getPersonLocation() instanceof Person) { + return $this->getPersonLocation()->getCurrentHouseholdAddress($at); + } + + return $this->getAddressLocation(); + } + + /** + * Get where the location is. + * + * @Groups({"read"}) + */ + public function getLocationStatus(): string + { + if ($this->getPersonLocation() instanceof Person) { + return 'person'; + } + + if ($this->getAddressLocation() instanceof Address) { + return 'address'; + } + + return 'none'; + } + + /** + * 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( + static function (AccompanyingPeriodParticipation $participation): bool { + return null === $participation->getEndDate(); + } + ); + + return $collection->count() > 0 ? $collection->first() : null; + } + + public function getOpenParticipations(): Collection + { + return $this + ->getParticipations() + ->filter( + static function (AccompanyingPeriodParticipation $participation): bool { + return null === $participation->getEndDate(); + } + ); } public function getOrigin(): ?Origin @@ -732,35 +690,92 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface 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() + ->filter( + static function (AccompanyingPeriodParticipation $participation) use ($person): bool { + return $participation->getPerson() === $person; + } + ); } - private function setRequestorPerson(Person $requestorPerson = null): self + /** + * @Groups({"read"}) + */ + public function getPersonLocation(): ?Person { - $this->requestorPerson = $requestorPerson; - - return $this; + return $this->personLocation; } - public function getRequestorThirdParty(): ?ThirdParty + /** + * Get a list of all persons which are participating to this course. + * + * @psalm-return Collection + */ + public function getPersons(): Collection { - return $this->requestorThirdParty; + return $this + ->participations + ->map( + static function (AccompanyingPeriodParticipation $participation): Person { + return $participation->getPerson(); + } + ); } - private function setRequestorThirdParty(ThirdParty $requestorThirdParty = null): self + /** + * @return Collection|SocialAction[] All the descendant social actions of all + * the descendants of the entity + */ + public function getRecursiveSocialActions(): Collection { - $this->requestorThirdParty = $requestorThirdParty; + $recursiveSocialActions = new ArrayCollection(); - return $this; + foreach ($this->socialIssues as $socialIssue) { + foreach ($socialIssue->getRecursiveSocialActions() as $descendant) { + if (!$recursiveSocialActions->contains($descendant)) { + $recursiveSocialActions->add($descendant); + } + } + } + + return $recursiveSocialActions; + } + + /** + * @return Collection|SocialIssues[] All social issues and their descendants + */ + public function getRecursiveSocialIssues(): Collection + { + $recursiveSocialIssues = new ArrayCollection(); + + foreach ($this->socialIssues as $socialIssue) { + foreach ($socialIssue->getDescendantsWithThis() as $descendant) { + if (!$recursiveSocialIssues->contains($descendant)) { + $recursiveSocialIssues->add($descendant); + } + } + } + + return $recursiveSocialIssues; + } + + public function getRemark(): string + { + return $this->remark; } /** @@ -772,131 +787,14 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this->requestorPerson ?? $this->requestorThirdParty; } - - /** - * Set a requestor - * - * The requestor is either an instance of ThirdParty, or an - * instance of Person - * - * @param $requestor Person|ThirdParty - * @return self - * @throw UnexpectedValueException if the requestor is not a Person or ThirdParty - * @Groups({"write"}) - */ - public function setRequestor($requestor): self + public function getRequestorPerson(): ?Person { - if ($requestor instanceof Person) { - $this->setRequestorThirdParty(NULL); - $this->setRequestorPerson($requestor); - } elseif ($requestor instanceof ThirdParty) { - $this->setRequestorThirdParty($requestor); - $this->setRequestorPerson(NULL); - } elseif (NULL === $requestor) { - $this->setRequestorPerson(NULL); - $this->setRequestorThirdParty(NULL); - } else { - throw new \UnexpectedValueException("requestor is not an instance of Person or ThirdParty"); - } - - return $this; + return $this->requestorPerson; } - - public function isRequestorAnonymous(): bool + public function getRequestorThirdParty(): ?ThirdParty { - return $this->requestorAnonymous; - } - - public function setRequestorAnonymous(bool $requestorAnonymous): self - { - $this->requestorAnonymous = $requestorAnonymous; - - return $this; - } - - public function isEmergency(): bool - { - return $this->emergency; - } - - public function setEmergency(bool $emergency): self - { - $this->emergency = $emergency; - - return $this; - } - - public function isConfidential(): bool - { - return $this->confidential; - } - - public function setConfidential(bool $confidential): self - { - $this->confidential = $confidential; - - return $this; - } - - public function getCreatedBy(): ?User - { - return $this->createdBy; - } - - public function setCreatedBy(User $createdBy): self - { - $this->createdBy = $createdBy; - - return $this; - } - - public function getStep(): ?string - { - return $this->step; - } - - public function setStep(string $step): self - { - $this->step = $step; - - return $this; - } - - public function getIntensity(): ?string - { - return $this->intensity; - } - - public function setIntensity(string $intensity): self - { - $this->intensity = $intensity; - - return $this; - } - - /** - * @return iterable|Collection - */ - public function getScopes(): Collection - { - return $this->scopes; - } - - - - public function addScope(Scope $scope): self - { - if (!$this->scopes->contains($scope)) { - $this->scopes[] = $scope; - } - - return $this; - } - - public function removeScope(Scope $scope): void - { - $this->scopes->removeElement($scope); + return $this->requestorThirdParty; } public function getResources(): Collection @@ -904,18 +802,12 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this->resources; } - public function addResource(Resource $resource): self + /** + * @return Collection|iterable + */ + public function getScopes(): Collection { - $resource->setAccompanyingPeriod($this); - $this->resources[] = $resource; - - return $this; - } - - public function removeResource(Resource $resource): void - { - $resource->setAccompanyingPeriod(null); - $this->resources->removeElement($resource); + return $this->scopes; } public function getSocialIssues(): Collection @@ -923,92 +815,14 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this->socialIssues; } - public function addSocialIssue(SocialIssue $socialIssue): self + public function getStep(): ?string { - if (!$this->socialIssues->contains($socialIssue)) { - $this->socialIssues[] = $socialIssue; - } - - return $this; + return $this->step; } - public function removeSocialIssue(SocialIssue $socialIssue): void + public function getUser(): ?User { - $this->socialIssues->removeElement($socialIssue); - } - - /** - * @return Collection|SocialIssues[] All social issues and their descendants - */ - public function getRecursiveSocialIssues(): Collection - { - $recursiveSocialIssues = new ArrayCollection(); - - foreach( $this->socialIssues as $socialIssue) { - foreach ($socialIssue->getDescendantsWithThis() as $descendant) { - if(! $recursiveSocialIssues->contains($descendant)) { - $recursiveSocialIssues->add($descendant); - } - } - } - return $recursiveSocialIssues; - } - - - /** - * @return Collection|SocialAction[] All the descendant social actions of all - * the descendants of the entity - */ - public function getRecursiveSocialActions(): Collection - { - $recursiveSocialActions = new ArrayCollection(); - - foreach( $this->socialIssues as $socialIssue) { - foreach ($socialIssue->getRecursiveSocialActions() as $descendant) { - if(! $recursiveSocialActions->contains($descendant)) { - $recursiveSocialActions->add($descendant); - } - } - } - - return $recursiveSocialActions; - } - - /** - * Get a list of all persons which are participating to this course - * - * @psalm-return Collection - */ - public function getPersons(): Collection - { - return $this - ->participations - ->map( - static function(AccompanyingPeriodParticipation $participation): Person { - return $participation->getPerson(); - } - ); - } - - public function setCreatedAt(\DateTimeInterface $datetime): self - { - $this->createdAt = $datetime; - - return $this; - } - - public function setUpdatedBy(User $user): self - { - $this->updatedBy = $user; - - return $this; - } - - public function setUpdatedAt(\DateTimeInterface $datetime): self - { - $this->updatedAt = $datetime; - - return $this; + return $this->user; } /** @@ -1019,14 +833,107 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this->works; } - public function addWork(AccompanyingPeriodWork $work): self + /** + * Returns true if the closing date is after the opening date. + */ + public function isClosingAfterOpening(): bool { - $this->works[] = $work; - $work->setAccompanyingPeriod($this); + 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 + { + return $this->emergency; + } + + public function isOpen(): bool + { + 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 + { + $comment->setAccompanyingPeriod(null); + $this->comments->removeElement($comment); + } + + /** + * Remove Participation. + */ + public function removeParticipation(AccompanyingPeriodParticipation $participation) + { + $participation->setAccompanyingPeriod(null); + } + + /** + * Remove Person. + */ + public function removePerson(Person $person): self + { + $this->closeParticipationFor($person); return $this; } + public function removeResource(Resource $resource): void + { + $resource->setAccompanyingPeriod(null); + $this->resources->removeElement($resource); + } + + public function removeScope(Scope $scope): void + { + $this->scopes->removeElement($scope); + } + + public function removeSocialIssue(SocialIssue $socialIssue): void + { + $this->socialIssues->removeElement($socialIssue); + } + public function removeWork(AccompanyingPeriodWork $work): self { $this->work->removeElement($work); @@ -1035,18 +942,10 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this; } - public function getAddressLocation(): ?Address + public function reOpen(): void { - return $this->addressLocation; - } - - public function getCenter(): ?Center - { - if (count($this->getPersons()) === 0){ - return null; - } - - return $this->getPersons()->first()->getCenter(); + $this->setClosingDate(null); + $this->setClosingMotive(null); } /** @@ -1060,27 +959,100 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface } /** - * @Groups({"read"}) + * Set closingDate. + * + * For closing a Person file, you should use Person::setClosed instead. + * + * @param mixed $closingDate + * + * @return AccompanyingPeriod */ - public function getPersonLocation(): ?Person + public function setClosingDate($closingDate) { - return $this->personLocation; + $this->closingDate = $closingDate; + + return $this; + } + + public function setClosingMotive(?ClosingMotive $closingMotive = null): self + { + $this->closingMotive = $closingMotive; + + return $this; + } + + public function setConfidential(bool $confidential): self + { + $this->confidential = $confidential; + + return $this; + } + + public function setCreatedAt(DateTimeInterface $datetime): self + { + $this->createdAt = $datetime; + + return $this; + } + + public function setCreatedBy(User $createdBy): self + { + $this->createdBy = $createdBy; + + return $this; + } + + public function setEmergency(bool $emergency): self + { + $this->emergency = $emergency; + + return $this; } /** - * Get a list of person which have an adresse available for a valid location - * - * @return Collection|Person[] + * @Groups({"write"}) */ - public function getAvailablePersonLocation(): Collection + public function setInitialComment(?Comment $comment = null): self { - return $this->getOpenParticipations() - ->filter(function(AccompanyingPeriodParticipation $p) { - return $p->getPerson()->hasCurrentHouseholdAddress(); - }) - ->map(function(AccompanyingPeriodParticipation $p) { - return $p->getPerson(); - }); + if (null !== $this->initialComment) { + $this->removeComment($this->initialComment); + } + + if ($comment instanceof Comment) { + $this->addComment($comment); + } + + $this->initialComment = $comment; + + return $this; + } + + public function setIntensity(string $intensity): self + { + $this->intensity = $intensity; + + return $this; + } + + /** + * Set openingDate. + * + * @param mixed $openingDate + * + * @return AccompanyingPeriod + */ + public function setOpeningDate($openingDate) + { + $this->openingDate = $openingDate; + + return $this; + } + + public function setOrigin(Origin $origin): self + { + $this->origin = $origin; + + return $this; } /** @@ -1093,61 +1065,87 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this; } - /** - * Get the location, taking precedence into account - * - * @Groups({"read"}) - */ - public function getLocation(\DateTimeImmutable $at = null): ?Address + public function setRemark(?string $remark = null): self { - if ($this->getPersonLocation() instanceof Person) { - return $this->getPersonLocation()->getCurrentHouseholdAddress($at); - } + $this->remark = (string) $remark; - return $this->getAddressLocation(); + return $this; } /** - * Get where the location is + * Set a requestor. * - * @Groups({"read"}) + * The requestor is either an instance of ThirdParty, or an + * instance of Person + * + * @param $requestor Person|ThirdParty + * @throw UnexpectedValueException if the requestor is not a Person or ThirdParty + * @Groups({"write"}) */ - public function getLocationStatus(): string + public function setRequestor($requestor): self { - if ($this->getPersonLocation() instanceof Person) { - return 'person'; - } - - if ($this->getAddressLocation() instanceof Address) { - return 'address'; + if ($requestor instanceof Person) { + $this->setRequestorThirdParty(null); + $this->setRequestorPerson($requestor); + } elseif ($requestor instanceof ThirdParty) { + $this->setRequestorThirdParty($requestor); + $this->setRequestorPerson(null); + } elseif (null === $requestor) { + $this->setRequestorPerson(null); + $this->setRequestorThirdParty(null); } else { - return 'none'; + throw new UnexpectedValueException('requestor is not an instance of Person or ThirdParty'); } + + return $this; } - public function getCenters(): ?iterable + public function setRequestorAnonymous(bool $requestorAnonymous): self { - foreach ($this->getPersons() as $person) { - if (!in_array($person->getCenter(), $centers ?? []) - && NULL !== $person->getCenter()) { - $centers[] = $person->getCenter(); - } - } + $this->requestorAnonymous = $requestorAnonymous; - return $centers ?? null; + return $this; } - public function getGroupSequence() + public function setStep(string $step): self { - if ($this->getStep() == self::STEP_DRAFT) - { - return [[self::STEP_DRAFT]]; - } elseif ($this->getStep() == self::STEP_CONFIRMED) - { - return [[self::STEP_DRAFT, self::STEP_CONFIRMED]]; - } + $this->step = $step; - throw new \LogicException("no validation group permitted with this step"); + return $this; + } + public function setUpdatedAt(DateTimeInterface $datetime): self + { + $this->updatedAt = $datetime; + + return $this; + } + + public function setUpdatedBy(User $user): self + { + $this->updatedBy = $user; + + return $this; + } + + public function setUser(User $user): self + { + $this->user = $user; + + return $this; + } + + private function setRequestorPerson(?Person $requestorPerson = null): self + { + $this->requestorPerson = $requestorPerson; + + return $this; + } + + private function setRequestorThirdParty(?ThirdParty $requestorThirdParty = null): self + { + $this->requestorThirdParty = $requestorThirdParty; + + return $this; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php index 58b27d95d..03c09e1db 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php @@ -1,169 +1,50 @@ goals = new ArrayCollection(); - $this->results = new ArrayCollection(); - $this->thirdParties = new ArrayCollection(); - $this->persons = new ArrayCollection(); - $this->accompanyingPeriodWorkEvaluations = new ArrayCollection(); - } - - public function getId(): ?int - { - return $this->id; - } - - public function getNote(): ?string - { - return $this->note; - } - - public function setNote(string $note): self - { - $this->note = $note; - - return $this; - } - - public function getAccompanyingPeriod(): ?AccompanyingPeriod - { - return $this->accompanyingPeriod; - } - - /** - * Internal: you should use `$accompanyingPeriod->removeWork($work);` or - * `$accompanyingPeriod->addWork($work);` - */ - public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self - { - if ($this->accompanyingPeriod instanceof AccompanyingPeriod && - $accompanyingPeriod !== $this->accompanyingPeriod) { - throw new \LogicException("A work cannot change accompanyingPeriod"); - } - - $this->accompanyingPeriod = $accompanyingPeriod; - - return $this; - } - - public function getSocialAction(): ?SocialAction - { - return $this->socialAction; - } - - public function setSocialAction(?SocialAction $socialAction): self - { - $this->socialAction = $socialAction; - - return $this; - } - - public function getCreatedAt(): ?\DateTimeImmutable - { - 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 setUpdatedBy(User $user): TrackUpdateInterface - { - $this->updatedBy = $user; - - return $this; - } - - public function setUpdatedAt(DateTimeInterface $datetime): TrackUpdateInterface - { - $this->updatedAt = $datetime; - - return $this; - } - - public function getUpdatedAt(): ?\DateTimeImmutable - { - return $this->updatedAt; - } - - public function getUpdatedBy(): ?User - { - return $this->updatedBy; - } - - 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 = null): 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[] - */ - public function getGoals(): Collection - { - return $this->goals; - } - - public function addGoal(AccompanyingPeriodWorkGoal $goal): self - { - if (!$this->goals->contains($goal)) { - $this->goals[] = $goal; - $goal->setAccompanyingPeriodWork($this); - } - - return $this; - } - - public function removeGoal(AccompanyingPeriodWorkGoal $goal): self - { - if ($this->goals->removeElement($goal)) { - // set the owning side to null (unless already changed) - if ($goal->getAccompanyingPeriodWork() === $this) { - $goal->setAccompanyingPeriodWork(null); - } - } - - 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; - } - - /** - * @return Collection|ThirdParty[] - */ - public function getThirdParties(): Collection - { - return $this->thirdParties; - } - - public function getThirdPartys(): Collection - { - return $this->getThirdParties(); - } - - 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 getPersons(): Collection - { - return $this->persons; - } - - public function addPerson(Person $person): self - { - if (!$this->persons->contains($person)) { - $this->persons[] = $person; - } - - return $this; - } - - public function removePerson(Person $person): self - { - $this->persons->removeElement($person); - - return $this; - } + private Collection $accompanyingPeriodWorkEvaluations; /** - * @return Collection + * @ORM\Column(type="datetime_immutable") + * @Serializer\Groups({"read"}) */ - public function getAccompanyingPeriodWorkEvaluations() + private ?DateTimeImmutable $createdAt = null; + + /** + * @ORM\Column(type="boolean") + */ + private bool $createdAutomatically = false; + + /** + * @ORM\Column(type="text") + */ + private string $createdAutomaticallyReason = ''; + + /** + * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\JoinColumn(nullable=false) + * @Serializer\Groups({"read"}) + */ + private ?User $createdBy = null; + + /** + * @ORM\Column(type="date_immutable", nullable=true, options={"default": null}) + * @Serializer\Groups({"accompanying_period_work:create"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"read"}) + * @Assert\GreaterThan(propertyPath="startDate", + * message="accompanying_course_work.The endDate should be greater than the start date" + * ) + */ + private ?DateTimeImmutable $endDate = null; + + /** + * @ORM\OneToMany( + * targetEntity=AccompanyingPeriodWorkGoal::class, + * mappedBy="accompanyingPeriodWork", + * cascade={"persist"}, + * orphanRemoval=true + * ) + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + */ + private Collection $goals; + + /** + * @ORM\ManyToOne(targetEntity=ThirdParty::class) + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + * + * In schema : traitant + */ + private ?ThirdParty $handlingThierParty = null; + + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + * @Serializer\Groups({"read"}) + */ + private ?int $id; + + /** + * @ORM\Column(type="text") + * @Serializer\Groups({"read", "accompanying_period_work:edit"}) + */ + private string $note = ''; + + /** + * @ORM\ManyToMany(targetEntity=Person::class) + * @ORM\JoinTable(name="chill_person_accompanying_period_work_person") + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"accompanying_period_work:create"}) + */ + private Collection $persons; + + /** + * @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorks") + * @ORM\JoinTable(name="chill_person_accompanying_period_work_result") + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + */ + private Collection $results; + + /** + * @ORM\ManyToOne(targetEntity=SocialAction::class) + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:create"}) + */ + private ?SocialAction $socialAction = null; + + /** + * @ORM\Column(type="date_immutable") + * @Serializer\Groups({"accompanying_period_work:create"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + * @Serializer\Groups({"read"}) + */ + private DateTimeImmutable $startDate; + + /** + * @ORM\ManyToMany(targetEntity=ThirdParty::class) + * @ORM\JoinTable(name="chill_person_accompanying_period_work_third_party") + * + * In schema : intervenants + * @Serializer\Groups({"read"}) + * @Serializer\Groups({"accompanying_period_work:edit"}) + */ + private Collection $thirdParties; + + /** + * @ORM\Column(type="datetime_immutable") + * @Serializer\Groups({"read"}) + */ + private ?DateTimeImmutable $updatedAt = null; + + /** + * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\JoinColumn(nullable=false) + * @Serializer\Groups({"read"}) + */ + private ?User $updatedBy = null; + + public function __construct() { - return $this->accompanyingPeriodWorkEvaluations; + $this->goals = new ArrayCollection(); + $this->results = new ArrayCollection(); + $this->thirdParties = new ArrayCollection(); + $this->persons = new ArrayCollection(); + $this->accompanyingPeriodWorkEvaluations = new ArrayCollection(); } public function addAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self @@ -464,6 +200,150 @@ use Symfony\Component\Validator\Constraints as Assert; return $this; } + public function addGoal(AccompanyingPeriodWorkGoal $goal): self + { + if (!$this->goals->contains($goal)) { + $this->goals[] = $goal; + $goal->setAccompanyingPeriodWork($this); + } + + return $this; + } + + public function addPerson(Person $person): self + { + if (!$this->persons->contains($person)) { + $this->persons[] = $person; + } + + 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; + } + + /** + * @return Collection + */ + public function getAccompanyingPeriodWorkEvaluations() + { + return $this->accompanyingPeriodWorkEvaluations; + } + + public function getCreatedAt(): ?DateTimeImmutable + { + 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; + } + + public function getNote(): ?string + { + return $this->note; + } + + public function getPersons(): Collection + { + return $this->persons; + } + + /** + * @return Collection|Result[] + */ + public function getResults(): Collection + { + return $this->results; + } + + public function getSocialAction(): ?SocialAction + { + return $this->socialAction; + } + + public function getStartDate(): ?DateTimeInterface + { + return $this->startDate; + } + + /** + * @return Collection|ThirdParty[] + */ + public function getThirdParties(): Collection + { + return $this->thirdParties; + } + + public function getThirdPartys(): Collection + { + return $this->getThirdParties(); + } + + public function getUpdatedAt(): ?DateTimeImmutable + { + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + public function removeAccompanyingPeriodWorkEvaluation(AccompanyingPeriodWorkEvaluation $evaluation): self { $this->accompanyingPeriodWorkEvaluations @@ -472,4 +352,130 @@ use Symfony\Component\Validator\Constraints as Assert; return $this; } + + public function removeGoal(AccompanyingPeriodWorkGoal $goal): self + { + if ($this->goals->removeElement($goal)) { + // set the owning side to null (unless already changed) + if ($goal->getAccompanyingPeriodWork() === $this) { + $goal->setAccompanyingPeriodWork(null); + } + } + + return $this; + } + + public function removePerson(Person $person): self + { + $this->persons->removeElement($person); + + return $this; + } + + public function removeResult(Result $result): self + { + $this->results->removeElement($result); + + return $this; + } + + public function removeThirdParty(ThirdParty $thirdParty): self + { + $this->thirdParties->removeElement($thirdParty); + + return $this; + } + + /** + * Internal: you should use `$accompanyingPeriod->removeWork($work);` or + * `$accompanyingPeriod->addWork($work);`. + */ + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + { + if ($this->accompanyingPeriod instanceof AccompanyingPeriod + && $accompanyingPeriod !== $this->accompanyingPeriod) { + throw new LogicException('A work cannot change accompanyingPeriod'); + } + + $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 = null): 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; + } + + public function setUpdatedAt(DateTimeInterface $datetime): TrackUpdateInterface + { + $this->updatedAt = $datetime; + + return $this; + } + + public function setUpdatedBy(User $user): TrackUpdateInterface + { + $this->updatedBy = $user; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluation.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluation.php index 996007e96..8317f8838 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluation.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluation.php @@ -1,36 +1,37 @@ documents = new ArrayCollection(); } - /** - * @return int|null - */ - public function getId(): ?int - { - return $this->id; - } - - /** - * @return AccompanyingPeriodWork|null - */ - public function getAccompanyingPeriodWork(): ?AccompanyingPeriodWork - { - return $this->accompanyingPeriodWork; - } - - /** - * @param AccompanyingPeriodWork|null $accompanyingPeriodWork - * @return AccompanyingPeriodWorkEvaluation - */ - public function setAccompanyingPeriodWork(?AccompanyingPeriodWork $accompanyingPeriodWork): AccompanyingPeriodWorkEvaluation - { - if ( - $accompanyingPeriodWork instanceof AccompanyingPeriodWork - && $this->accompanyingPeriodWork instanceof AccompanyingPeriodWork - && $this->accompanyingPeriodWork->getId() !== $accompanyingPeriodWork->getId()) { - throw new \RuntimeException("Changing the ". - "accompanyingPeriodWork is not allowed"); - } - - $this->accompanyingPeriodWork = $accompanyingPeriodWork; - return $this; - } - - /** - * @return Evaluation|null - */ - public function getEvaluation(): ?Evaluation - { - return $this->evaluation; - } - - /** - * @param Evaluation|null $evaluation - * @return AccompanyingPeriodWorkEvaluation - */ - public function setEvaluation(?Evaluation $evaluation): AccompanyingPeriodWorkEvaluation - { - if ( - ($evaluation instanceof Evaluation - && $this->evaluation instanceof Evaluation - && $evaluation->getId() !== $this->evaluation->getId()) - || - ($this->evaluation instanceof Evaluation - && null === $evaluation) - ) { - $cl = AccompanyingPeriodWorkEvaluation::class; - throw new \LogicException("once set, an $cl cannot - change or remove the linked Evaluation::class"); - } - - $this->evaluation = $evaluation; - - return $this; - } - - /** - * @return DateTimeImmutable|null - */ - public function getStartDate(): ?DateTimeImmutable - { - return $this->startDate; - } - - /** - * @param DateTimeImmutable|null $startDate - * @return AccompanyingPeriodWorkEvaluation - */ - public function setStartDate(?DateTimeImmutable $startDate): AccompanyingPeriodWorkEvaluation - { - $this->startDate = $startDate; - return $this; - } - - /** - * @return DateTimeImmutable|null - */ - public function getEndDate(): ?DateTimeImmutable - { - return $this->endDate; - } - - /** - * @param DateTimeImmutable|null $endDate - * @return AccompanyingPeriodWorkEvaluation - */ - public function setEndDate(?DateTimeImmutable $endDate): AccompanyingPeriodWorkEvaluation - { - $this->endDate = $endDate; - return $this; - } - - /** - * @return DateTimeImmutable|null - */ - public function getMaxDate(): ?DateTimeImmutable - { - return $this->maxDate; - } - - /** - * @param DateTimeImmutable|null $maxDate - * @return AccompanyingPeriodWorkEvaluation - */ - public function setMaxDate(?DateTimeImmutable $maxDate): AccompanyingPeriodWorkEvaluation - { - $this->maxDate = $maxDate; - return $this; - } - - /** - * @return DateInterval|null - */ - public function getWarningInterval(): ?DateInterval - { - return $this->warningInterval; - } - - /** - * @param DateInterval|null $warningInterval - * @return AccompanyingPeriodWorkEvaluation - */ - public function setWarningInterval(?DateInterval $warningInterval): AccompanyingPeriodWorkEvaluation - { - $this->warningInterval = $warningInterval; - return $this; - } - - /** - * @return string - */ - public function getComment(): string - { - return $this->comment; - } - - /** - * @param string $comment - * @return AccompanyingPeriodWorkEvaluation - */ - public function setComment(string $comment): AccompanyingPeriodWorkEvaluation - { - $this->comment = $comment; - return $this; - } - - /** - * @return User|null - */ - public function getCreatedBy(): ?User - { - return $this->createdBy; - } - - /** - * @param User|null $createdBy - * @return AccompanyingPeriodWorkEvaluation - */ - public function setCreatedBy(?User $createdBy): AccompanyingPeriodWorkEvaluation - { - $this->createdBy = $createdBy; - return $this; - } - - /** - * @return DateTimeImmutable|null - */ - public function getCreatedAt(): ?DateTimeImmutable - { - return $this->createdAt; - } - - /** - * @param DateTimeImmutable|null $createdAt - * @return AccompanyingPeriodWorkEvaluation - */ - public function setCreatedAt(\DateTimeInterface $createdAt): self - { - $this->createdAt = $createdAt; - return $this; - } - - /** - * @return User|null - */ - public function getUpdatedBy(): ?User - { - return $this->updatedBy; - } - - /** - * @param User|null $updatedBy - * @return AccompanyingPeriodWorkEvaluation - */ - public function setUpdatedBy(?User $updatedBy): AccompanyingPeriodWorkEvaluation - { - $this->updatedBy = $updatedBy; - return $this; - } - - /** - * @return DateTimeImmutable|null - */ - public function getUpdatedAt(): ?DateTimeImmutable - { - return $this->updatedAt; - } - - /** - * @param DateTimeImmutable|null $updatedAt - * @return AccompanyingPeriodWorkEvaluation - */ - public function setUpdatedAt(\DateTimeInterface $updatedAt): self - { - $this->updatedAt = $updatedAt; - return $this; - } - - /** - * @return Collection - */ - public function getDocuments() - { - return $this->documents; - } - public function addDocument(AccompanyingPeriodWorkEvaluationDocument $document): self { if (!$this->documents->contains($document)) { @@ -394,14 +164,51 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre return $this; } - public function removeDocument(AccompanyingPeriodWorkEvaluationDocument $document): self + public function getAccompanyingPeriodWork(): ?AccompanyingPeriodWork { - $this->documents->removeElement($document); - return $this; + return $this->accompanyingPeriodWork; + } + + public function getComment(): string + { + return $this->comment; + } + + public function getCreatedAt(): ?DateTimeImmutable + { + return $this->createdAt; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; } /** - * Arbitrary data, used for client + * @return Collection + */ + public function getDocuments() + { + return $this->documents; + } + + public function getEndDate(): ?DateTimeImmutable + { + return $this->endDate; + } + + public function getEvaluation(): ?Evaluation + { + return $this->evaluation; + } + + public function getId(): ?int + { + return $this->id; + } + + /** + * Arbitrary data, used for client. * * @return mixed */ @@ -410,10 +217,111 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre return $this->key; } + public function getMaxDate(): ?DateTimeImmutable + { + return $this->maxDate; + } + + public function getStartDate(): ?DateTimeImmutable + { + return $this->startDate; + } + + public function getUpdatedAt(): ?DateTimeImmutable + { + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + + public function getWarningInterval(): ?DateInterval + { + return $this->warningInterval; + } + + public function removeDocument(AccompanyingPeriodWorkEvaluationDocument $document): self + { + $this->documents->removeElement($document); + + return $this; + } + + public function setAccompanyingPeriodWork(?AccompanyingPeriodWork $accompanyingPeriodWork): AccompanyingPeriodWorkEvaluation + { + if ( + $accompanyingPeriodWork instanceof AccompanyingPeriodWork + && $this->accompanyingPeriodWork instanceof AccompanyingPeriodWork + && $this->accompanyingPeriodWork->getId() !== $accompanyingPeriodWork->getId()) { + throw new RuntimeException('Changing the ' . + 'accompanyingPeriodWork is not allowed'); + } + + $this->accompanyingPeriodWork = $accompanyingPeriodWork; + + return $this; + } + + public function setComment(string $comment): AccompanyingPeriodWorkEvaluation + { + $this->comment = $comment; + + return $this; + } + /** - * Arbitrary data, used for client + * @param DateTimeImmutable|null $createdAt + * + * @return AccompanyingPeriodWorkEvaluation + */ + public function setCreatedAt(DateTimeInterface $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; + } + + public function setCreatedBy(?User $createdBy): AccompanyingPeriodWorkEvaluation + { + $this->createdBy = $createdBy; + + return $this; + } + + public function setEndDate(?DateTimeImmutable $endDate): AccompanyingPeriodWorkEvaluation + { + $this->endDate = $endDate; + + return $this; + } + + public function setEvaluation(?Evaluation $evaluation): AccompanyingPeriodWorkEvaluation + { + if ( + ($evaluation instanceof Evaluation + && $this->evaluation instanceof Evaluation + && $evaluation->getId() !== $this->evaluation->getId()) + || ($this->evaluation instanceof Evaluation + && null === $evaluation) + ) { + $cl = AccompanyingPeriodWorkEvaluation::class; + + throw new LogicException("once set, an {$cl} cannot + change or remove the linked Evaluation::class"); + } + + $this->evaluation = $evaluation; + + return $this; + } + + /** + * Arbitrary data, used for client. * * @param mixed $key + * * @return AccompanyingPeriodWorkEvaluation */ public function setKey($key): self @@ -422,4 +330,44 @@ class AccompanyingPeriodWorkEvaluation implements TrackUpdateInterface, TrackCre return $this; } + + public function setMaxDate(?DateTimeImmutable $maxDate): AccompanyingPeriodWorkEvaluation + { + $this->maxDate = $maxDate; + + return $this; + } + + public function setStartDate(?DateTimeImmutable $startDate): AccompanyingPeriodWorkEvaluation + { + $this->startDate = $startDate; + + return $this; + } + + /** + * @param DateTimeImmutable|null $updatedAt + * + * @return AccompanyingPeriodWorkEvaluation + */ + public function setUpdatedAt(DateTimeInterface $updatedAt): self + { + $this->updatedAt = $updatedAt; + + return $this; + } + + public function setUpdatedBy(?User $updatedBy): AccompanyingPeriodWorkEvaluation + { + $this->updatedBy = $updatedBy; + + return $this; + } + + public function setWarningInterval(?DateInterval $warningInterval): AccompanyingPeriodWorkEvaluation + { + $this->warningInterval = $warningInterval; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php index 1dfaef99c..d51534240 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php @@ -1,5 +1,12 @@ accompanyingPeriodWorkEvaluation; } /** - * @param AccompanyingPeriodWorkEvaluation|null $accompanyingPeriodWorkEvaluation - * @return AccompanyingPeriodWorkEvaluationDocument + * @return \DateTimeImmutable|null */ + public function getCreatedAt(): ?DateTimeInterface + { + return $this->createdAt; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getStoredObject(): ?StoredObject + { + return $this->storedObject; + } + + public function getTemplate(): ?DocGeneratorTemplate + { + return $this->template; + } + + /** + * @return DateTimeImmutable|null + */ + public function getUpdatedAt(): ?DateTimeInterface + { + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + public function setAccompanyingPeriodWorkEvaluation(?AccompanyingPeriodWorkEvaluation $accompanyingPeriodWorkEvaluation): AccompanyingPeriodWorkEvaluationDocument { // if an evaluation is already associated, we cannot change the association (removing the association, @@ -104,111 +145,53 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct if ($this->accompanyingPeriodWorkEvaluation instanceof AccompanyingPeriodWorkEvaluation && $accompanyingPeriodWorkEvaluation instanceof AccompanyingPeriodWorkEvaluation) { if ($this->accompanyingPeriodWorkEvaluation !== $accompanyingPeriodWorkEvaluation) { - throw new \RuntimeException("It is not allowed to change the evaluation for a document"); + throw new RuntimeException('It is not allowed to change the evaluation for a document'); } } $this->accompanyingPeriodWorkEvaluation = $accompanyingPeriodWorkEvaluation; + return $this; } - /** - * @return StoredObject|null - */ - public function getStoredObject(): ?StoredObject + public function setCreatedAt(DateTimeInterface $datetime): TrackCreationInterface { - return $this->storedObject; + $this->createdAt = $datetime; + + return $this; + } + + public function setCreatedBy(User $user): TrackCreationInterface + { + $this->createdBy = $user; + + return $this; } - /** - * @param StoredObject|null $storedObject - * @return AccompanyingPeriodWorkEvaluationDocument - */ public function setStoredObject(?StoredObject $storedObject): AccompanyingPeriodWorkEvaluationDocument { $this->storedObject = $storedObject; + return $this; } - public function setCreatedBy(User $user): \Chill\MainBundle\Doctrine\Model\TrackCreationInterface - { - $this->createdBy = $user; - return $this; - } - - public function setCreatedAt(\DateTimeInterface $datetime): \Chill\MainBundle\Doctrine\Model\TrackCreationInterface - { - $this->createdAt = $datetime; - return $this; - } - - public function setUpdatedBy(User $user): \Chill\MainBundle\Doctrine\Model\TrackUpdateInterface - { - $this->updatedBy = $user; - return $this; - } - - public function setUpdatedAt(\DateTimeInterface $datetime): \Chill\MainBundle\Doctrine\Model\TrackUpdateInterface - { - $this->updatedAt = $datetime; - return $this; - } - - /** - * @return int|null - */ - public function getId(): ?int - { - return $this->id; - } - - /** - * @return User|null - */ - public function getCreatedBy(): ?User - { - return $this->createdBy; - } - - /** - * @return \DateTimeImmutable|null - */ - public function getCreatedAt(): ?\DateTimeInterface - { - return $this->createdAt; - } - - /** - * @return User|null - */ - public function getUpdatedBy(): ?User - { - return $this->updatedBy; - } - - /** - * @return DateTimeImmutable|null - */ - public function getUpdatedAt(): ?\DateTimeInterface - { - return $this->updatedAt; - } - - /** - * @return DocGeneratorTemplate|null - */ - public function getTemplate(): ?DocGeneratorTemplate - { - return $this->template; - } - - /** - * @param DocGeneratorTemplate|null $template - * @return AccompanyingPeriodWorkEvaluationDocument - */ public function setTemplate(?DocGeneratorTemplate $template): AccompanyingPeriodWorkEvaluationDocument { $this->template = $template; + return $this; } + public function setUpdatedAt(DateTimeInterface $datetime): TrackUpdateInterface + { + $this->updatedAt = $datetime; + + return $this; + } + + public function setUpdatedBy(User $user): TrackUpdateInterface + { + $this->updatedBy = $user; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php index d8cfb4875..0a40be12b 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; @@ -71,25 +98,28 @@ 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 { if ($this->accompanyingPeriodWork instanceof AccompanyingPeriodWork && $accompanyingPeriodWork !== $this->accompanyingPeriodWork - && $accompanyingPeriodWork !== null + && null !== $accompanyingPeriodWork ) { - throw new \LogicException("Change accompanying period work is not allowed"); + throw new LogicException('Change accompanying period work is not allowed'); } $this->accompanyingPeriodWork = $accompanyingPeriodWork; @@ -97,11 +127,6 @@ class AccompanyingPeriodWorkGoal return $this; } - public function getGoal(): ?Goal - { - return $this->goal; - } - public function setGoal(?Goal $goal): self { $this->goal = $goal; @@ -109,26 +134,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 29b2a44aa..b78fcccde 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php @@ -1,33 +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\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 * @ORM\Table(name="chill_person_accompanying_period_closingmotive") @@ -35,7 +22,25 @@ use Doctrine\Common\Collections\ArrayCollection; 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") @@ -49,41 +54,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. */ @@ -91,11 +78,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() { @@ -103,7 +107,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 * @@ -117,161 +201,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 18b5bd38d..758893b93 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php @@ -1,60 +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\Entity\AccompanyingPeriod; -use Chill\MainBundle\Entity\User; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\Serializer\Annotation\Groups; -use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; +use Chill\MainBundle\Entity\User; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use DateTimeInterface; +use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Symfony\Component\Serializer\Annotation\Groups; /** * @ORM\Entity * @ORM\Table(name="chill_person_accompanying_period_comment") * @DiscriminatorMap(typeProperty="type", mapping={ - * "accompanying_period_comment"=Comment::class + * "accompanying_period_comment": Comment::class * }) */ class Comment implements TrackCreationInterface, TrackUpdateInterface { - /** - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - * @Groups({"read"}) - */ - private $id; - /** * @ORM\ManyToOne( * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", - * inversedBy="comments") + * inversedBy="comments") * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ private $accompanyingPeriod; + /** + * @ORM\Column(type="text") + * @Groups({"read", "write"}) + */ + private $content; + + /** + * @ORM\Column(type="datetime") + * @Groups({"read"}) + */ + private $createdAt; + /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(nullable=false) @@ -63,10 +55,12 @@ class Comment implements TrackCreationInterface, TrackUpdateInterface private $creator; /** - * @ORM\Column(type="datetime") + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") * @Groups({"read"}) */ - private $createdAt; + private $id; /** * @ORM\Column(type="datetime") @@ -81,20 +75,39 @@ class Comment implements TrackCreationInterface, TrackUpdateInterface */ private $updatedBy; - /** - * @ORM\Column(type="text") - * @Groups({"read", "write"}) - */ - 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 @@ -104,14 +117,16 @@ class Comment implements TrackCreationInterface, TrackUpdateInterface return $this; } - public function getCreator(): ?User + public function setContent(string $content): self { - return $this->creator; + $this->content = $content; + + return $this; } - public function setCreator(?User $creator): self + public function setCreatedAt(DateTimeInterface $createdAt): self { - $this->creator = $creator; + $this->createdAt = $createdAt; return $this; } @@ -121,51 +136,24 @@ class Comment implements TrackCreationInterface, TrackUpdateInterface return $this->setCreator($user); } - public function getCreatedAt(): ?\DateTimeInterface + public function setCreator(?User $creator): self { - return $this->createdAt; - } - - public function setCreatedAt(\DateTimeInterface $createdAt): self - { - $this->createdAt = $createdAt; + $this->creator = $creator; 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 aaf2bec94..402f9d69d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php @@ -1,40 +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\PersonBundle\Entity\AccompanyingPeriod; +use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation as Serializer; -use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Symfony\Component\Serializer\Annotation\Groups; /** * @ORM\Entity * @ORM\Table(name="chill_person_accompanying_period_origin") * @Serializer\DiscriminatorMap( - * typeProperty="type", - * mapping={ - * "origin"=Origin::class - * }) + * typeProperty="type", + * mapping={ + * "origin": Origin::class + * }) */ class Origin { @@ -68,6 +55,11 @@ class Origin return $this->label; } + public function getNoActiveAfter(): ?DateTimeImmutable + { + return $this->noActiveAfter; + } + public function setLabel(string $label): self { $this->label = $label; @@ -75,12 +67,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 48e532e10..8b3d09cbe 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php @@ -1,59 +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\Entity\AccompanyingPeriod; 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; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use Symfony\Component\Serializer\Annotation\Groups; +use UnexpectedValueException; /** * @ORM\Entity * @ORM\Table( - * name="chill_person_accompanying_period_resource", - * uniqueConstraints={ - * @ORM\UniqueConstraint(name="person_unique", columns={"person_id", "accompanyingperiod_id"}), - * @ORM\UniqueConstraint(name="thirdparty_unique", columns={"thirdparty_id", "accompanyingperiod_id"}) - * } + * name="chill_person_accompanying_period_resource", + * uniqueConstraints={ + * @ORM\UniqueConstraint(name="person_unique", columns={"person_id", "accompanyingperiod_id"}), + * @ORM\UniqueConstraint(name="thirdparty_unique", columns={"thirdparty_id", "accompanyingperiod_id"}) + * } * ) * @DiscriminatorMap(typeProperty="type", mapping={ - * "accompanying_period_resource"=Resource::class - * }) + * "accompanying_period_resource": Resource::class + * }) */ class Resource { - /** - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - * @Groups({"read"}) - */ - private $id; - /** * @ORM\ManyToOne( * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", @@ -64,10 +42,18 @@ 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") + * @Groups({"read"}) + */ + private $id; /** * @ORM\ManyToOne(targetEntity=Person::class) @@ -76,38 +62,24 @@ class Resource private $person; /** - * @ORM\ManyToOne(targetEntity=Comment::class) + * @ORM\ManyToOne(targetEntity=ThirdParty::class) * @ORM\JoinColumn(nullable=true) */ - private $comment; - - public function getId(): ?int - { - return $this->id; - } + private $thirdParty; public function getAccompanyingPeriod(): ?AccompanyingPeriod { return $this->accompanyingPeriod; } - public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + public function getComment(): ?Comment { - $this->accompanyingPeriod = $accompanyingPeriod; - - return $this; + return $this->comment; } - public function getThirdParty(): ?ThirdParty + public function getId(): ?int { - return $this->thirdParty; - } - - private function setThirdParty(?ThirdParty $thirdParty): self - { - $this->thirdParty = $thirdParty; - - return $this; + return $this->id; } public function getPerson(): ?Person @@ -115,16 +87,25 @@ class Resource return $this->person; } - private function setPerson(?Person $person): self + /** + * @return Person|ThirdParty + * @Groups({"read", "write"}) + */ + public function getResource() { - $this->person = $person; - - return $this; + return $this->person ?? $this->thirdParty; } - public function getComment(): ?Comment + public function getThirdParty(): ?ThirdParty { - return $this->comment; + return $this->thirdParty; + } + + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + { + $this->accompanyingPeriod = $accompanyingPeriod; + + return $this; } public function setComment(?Comment $comment): self @@ -135,36 +116,42 @@ class Resource } /** - * * @param $resource Person|ThirdParty */ public function setResource($resource): self { if ($resource instanceof ThirdParty) { $this->setThirdParty($resource); - $this->setPerson(NULL); + $this->setPerson(null); } elseif ($resource instanceof Person) { $this->setPerson($resource); - $this->setThirdParty(NULL); - } elseif (NULL === $resource) { - $this->setPerson(NULL); - $this->setThirdParty(NULL); + $this->setThirdParty(null); + } elseif (null === $resource) { + $this->setPerson(null); + $this->setThirdParty(null); } else { - throw new \UnexpectedValueException(sprintf("the resource ". - "should be an instance of %s or %s", Person::class, - ThirdParty::class)); + throw new UnexpectedValueException(sprintf( + 'the resource ' . + 'should be an instance of %s or %s', + Person::class, + ThirdParty::class + )); } return $this; } - - - /** - * @return ThirdParty|Person - * @Groups({"read", "write"}) - */ - public function getResource() + + private function setPerson(?Person $person): self { - return $this->person ?? $this->thirdParty; + $this->person = $person; + + return $this; + } + + private function setThirdParty(?ThirdParty $thirdParty): self + { + $this->thirdParty = $thirdParty; + + return $this; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php index f246c25bd..191752b97 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php @@ -1,45 +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 . + * 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\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\Person; +use DateTimeImmutable; +use DateTimeInterface; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; +use Symfony\Component\Serializer\Annotation\Groups; /** - * AccompanyingPeriodParticipation Class + * AccompanyingPeriodParticipation Class. * - * @package Chill\PersonBundle\Entity * @ORM\Entity * @ORM\Table(name="chill_person_accompanying_period_participation") * @DiscriminatorMap(typeProperty="type", mapping={ - * "accompanying_period_participation"=AccompanyingPeriodParticipation::class - * }) + * "accompanying_period_participation": AccompanyingPeriodParticipation::class + * }) */ 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) + * @Groups({"read"}) + */ + private $endDate; + /** * @ORM\Id * @ORM\GeneratedValue @@ -55,31 +53,33 @@ class AccompanyingPeriodParticipation */ 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) * @Groups({"read"}) */ private $startDate; - /** - * @ORM\Column(type="date", nullable=true) - * @Groups({"read"}) - */ - 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 getAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->accompanyingPeriod; + } + + /* + * public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; } + */ + + public function getEndDate(): ?DateTimeInterface + { + return $this->endDate; + } + public function getId(): ?int { return $this->id; @@ -90,16 +90,14 @@ class AccompanyingPeriodParticipation return $this->person; } - public function setPerson(?Person $person): self + public function getStartDate(): ?DateTimeInterface { - $this->person = $person; - - return $this; + return $this->startDate; } - public function getAccompanyingPeriod(): ?AccompanyingPeriod + public function isOpen(): bool { - return $this->accompanyingPeriod; + return null === $this->endDate; } public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self @@ -109,35 +107,23 @@ class AccompanyingPeriodParticipation return $this; } - 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 + public function setEndDate(?DateTimeInterface $endDate): self { $this->endDate = $endDate; return $this; } - public function isOpen(): bool + public function setPerson(?Person $person): self { - return $this->endDate === null; + $this->person = $person; + + return $this; } - private function checkSameStartEnd() + private function checkSameStartEnd() { - if($this->endDate == $this->startDate) { + if ($this->endDate == $this->startDate) { $this->accompanyingPeriod->removeParticipation($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 cc497aeca..39b9c3ca3 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php @@ -1,31 +1,57 @@ commentMembers = new CommentEmbeddable(); } - public function getId(): ?int - { - return $this->id; - } - /** - * @param Address $address * @return $this */ public function addAddress(Address $address) { foreach ($this->getAddresses() as $a) { - if ($a->getValidFrom() < $address->getValidFrom() && $a->getValidTo() === NULL) { + if ($a->getValidFrom() < $address->getValidFrom() && $a->getValidTo() === null) { $a->setValidTo($address->getValidFrom()); } } @@ -99,35 +102,22 @@ class Household return $this; } - /** - * Force an address starting at the current day - * on the Household. - * - * This will force the startDate's address on today. - * - * Used on household creation. - * - * @Serializer\Groups({"create"}) - */ - public function setForceAddress(Address $address) + public function addMember(HouseholdMember $member): self { - $address->setValidFrom(new \DateTime('today')); - $this->addAddress($address); - } + if (!$this->members->contains($member)) { + $this->members[] = $member; + $member->setHousehold($this); + } - /** - * @param Address $address - */ - public function removeAddress(Address $address) - { - $this->addresses->removeElement($address); + return $this; } /** * By default, the addresses are ordered by date, descending (the most - * recent first) + * recent first). * * @Assert\Callback(methods={"validate"}) + * * @return \Chill\MainBundle\Entity\Address[] */ public function getAddresses() @@ -135,25 +125,133 @@ class Household return $this->addresses; } + public function getCommentMembers(): CommentEmbeddable + { + return $this->commentMembers; + } + /** * @Serializer\Groups({ "read" }) * @Serializer\SerializedName("current_address") */ - public function getCurrentAddress(\DateTime $at = null): ?Address + public function getCurrentAddress(?DateTime $at = null): ?Address { - $at = $at === null ? new \DateTime('today') : $at; + $at = null === $at ? new DateTime('today') : $at; $addrs = $this->getAddresses()->filter(function (Address $a) use ($at) { return $a->getValidFrom() <= $at && ( - NULL === $a->getValidTo() || $at < $a->getValidTo() + null === $a->getValidTo() || $a->getValidTo() > $at ); }); if ($addrs->count() > 0) { return $addrs->first(); - } else { - return null; } + + return null; + } + + public function getCurrentMembers(?DateTimeImmutable $now = null): Collection + { + return $this->getMembers()->matching($this->buildCriteriaCurrentMembers($now)); + } + + public function getCurrentMembersByPosition(Position $position, ?DateTimeInterface $now = null) + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria->where($expr->eq('position', $position)); + + return $this->getCurrentMembers($now)->matching($criteria); + } + + /** + * get current members ids. + * + * Used in serialization + * + * @Serializer\Groups({"read"}) + * @Serializer\SerializedName("current_members_id") + */ + public function getCurrentMembersIds(?DateTimeImmutable $now = null): Collection + { + return $this->getCurrentMembers($now)->map( + fn (HouseholdMember $m) => $m->getId() + ); + } + + /** + * @return HouseholdMember[] + */ + public function getCurrentMembersOrdered(?DateTimeImmutable $now = null): Collection + { + $members = $this->getCurrentMembers($now); + + $members->getIterator() + ->uasort( + function (HouseholdMember $a, HouseholdMember $b) { + if ($a->getPosition() === null) { + if ($b->getPosition() === null) { + return 0; + } + + return -1; + } + + if ($b->getPosition() === null) { + return 1; + } + + if ($a->getPosition()->getOrdering() < $b->getPosition()->getOrdering()) { + return -1; + } + + if ($a->getPosition()->getOrdering() > $b->getPosition()->getOrdering()) { + return 1; + } + + if ($a->isHolder() && !$b->isHolder()) { + return 1; + } + + if (!$a->isHolder() && $b->isHolder()) { + return -1; + } + + return 0; + } + ); + + return $members; + } + + public function getCurrentMembersWithoutPosition(?DateTimeInterface $now = null) + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria->where($expr->isNull('position')); + + return $this->getCurrentMembers($now)->matching($criteria); + } + + /** + * Get the persons currently associated to the household. + * + * Return a list of Person, instead of a list of HouseholdMembers + * + * @return Person[] + */ + public function getCurrentPersons(?DateTimeImmutable $now = null): Collection + { + return $this->getCurrentMembers($now) + ->map(function (HouseholdMember $m) { return $m->getPerson(); }); + } + + public function getId(): ?int + { + return $this->id; } /** @@ -164,36 +262,13 @@ class Household return $this->members; } - public function getMembersOnRange(\DateTimeImmutable $from, ?\DateTimeImmutable $to): Collection - { - $criteria = new Criteria(); - $expr = Criteria::expr(); - - $criteria->where( - $expr->gte('startDate', $from) - ); - - if (NULL !== $to) { - $criteria->andWhere( - $expr->orX( - $expr->lte('endDate', $to), - $expr->eq('endDate', NULL) - ), - ); - } - - return $this->getMembers() - ->matching($criteria) - ; - } - public function getMembersDuringMembership(HouseholdMember $membership) { return $this->getMembersOnRange( $membership->getStartDate(), $membership->getEndDate() )->filter( - function(HouseholdMember $m) use ($membership) { + function (HouseholdMember $m) use ($membership) { return $m !== $membership; } ); @@ -211,104 +286,33 @@ class Household return $this->getMembers()->matching($criteria); } - public function getCurrentMembers(?\DateTimeImmutable $now = null): Collection - { - return $this->getMembers()->matching($this->buildCriteriaCurrentMembers($now)); - } - - private function buildCriteriaCurrentMembers(?\DateTimeImmutable $now = null): Criteria + public function getMembersOnRange(DateTimeImmutable $from, ?DateTimeImmutable $to): Collection { $criteria = new Criteria(); $expr = Criteria::expr(); - $date = $now === null ? (new \DateTimeImmutable('today')) : $now; - $criteria - ->where($expr->orX( - $expr->isNull('startDate'), - $expr->lte('startDate', $date) - )) - ->andWhere($expr->orX( - $expr->isNull('endDate'), - $expr->gt('endDate', $date) - )); - - return $criteria; - } - - /** - * @return HouseholdMember[] - */ - public function getCurrentMembersOrdered(?\DateTimeImmutable $now = null): Collection - { - $members = $this->getCurrentMembers($now); - - $members->getIterator() - ->uasort( - function (HouseholdMember $a, HouseholdMember $b) { - if ($a->getPosition() === NULL) { - if ($b->getPosition() === NULL) { - return 0; - } else { - return -1; - } - } elseif ($b->getPosition() === NULL) { - return 1; - } - - if ($a->getPosition()->getOrdering() < $b->getPosition()->getOrdering()) { - return -1; - } - if ($a->getPosition()->getOrdering() > $b->getPosition()->getOrdering()) { - return 1; - } - if ($a->isHolder() && !$b->isHolder()) { - return 1; - } - if (!$a->isHolder() && $b->isHolder()) { - return -1; - } - - return 0; - } + $criteria->where( + $expr->gte('startDate', $from) ); - return $members; + if (null !== $to) { + $criteria->andWhere( + $expr->orX( + $expr->lte('endDate', $to), + $expr->eq('endDate', null) + ), + ); + } + + return $this->getMembers() + ->matching($criteria); } - /** - * get current members ids - * - * Used in serialization - * - * @Serializer\Groups({"read"}) - * @Serializer\SerializedName("current_members_id") - * - */ - public function getCurrentMembersIds(?\DateTimeImmutable $now = null): Collection - { - return $this->getCurrentMembers($now)->map( - fn (HouseholdMember $m) => $m->getId() - ); - } - - /** - * Get the persons currently associated to the household. - * - * Return a list of Person, instead of a list of HouseholdMembers - * - * @return Person[] - */ - public function getCurrentPersons(?\DateTimeImmutable $now = null): Collection - { - return $this->getCurrentMembers($now) - ->map(function(HouseholdMember $m) { return $m->getPerson(); }); - } - - public function getNonCurrentMembers(\DateTimeImmutable $now = null): Collection + public function getNonCurrentMembers(?DateTimeImmutable $now = null): Collection { $criteria = new Criteria(); $expr = Criteria::expr(); - $date = $now === null ? (new \DateTimeImmutable('today')) : $now; + $date = null === $now ? (new DateTimeImmutable('today')) : $now; $criteria ->where( @@ -324,17 +328,7 @@ class Household return $this->getMembers()->matching($criteria); } - public function getCurrentMembersByPosition(Position $position, \DateTimeInterface $now = null) - { - $criteria = new Criteria(); - $expr = Criteria::expr(); - - $criteria->where($expr->eq('position', $position)); - - return $this->getCurrentMembers($now)->matching($criteria); - } - - public function getNonCurrentMembersByPosition(Position $position, \DateTimeInterface $now = null) + public function getNonCurrentMembersByPosition(Position $position, ?DateTimeInterface $now = null) { $criteria = new Criteria(); $expr = Criteria::expr(); @@ -344,17 +338,7 @@ class Household return $this->getNonCurrentMembers($now)->matching($criteria); } - public function getCurrentMembersWithoutPosition(\DateTimeInterface $now = null) - { - $criteria = new Criteria(); - $expr = Criteria::expr(); - - $criteria->where($expr->isNull('position')); - - return $this->getCurrentMembers($now)->matching($criteria); - } - - public function getNonCurrentMembersWithoutPosition(\DateTimeInterface $now = null) + public function getNonCurrentMembersWithoutPosition(?DateTimeInterface $now = null) { $criteria = new Criteria(); $expr = Criteria::expr(); @@ -364,14 +348,19 @@ class Household return $this->getNonCurrentMembers($now)->matching($criteria); } - public function addMember(HouseholdMember $member): self + public function getWaitingForBirth(): bool { - if (!$this->members->contains($member)) { - $this->members[] = $member; - $member->setHousehold($this); - } + return $this->waitingForBirth; + } - return $this; + public function getWaitingForBirthDate(): ?DateTimeImmutable + { + return $this->waitingForBirthDate; + } + + public function removeAddress(Address $address) + { + $this->addresses->removeElement($address); } public function removeMember(HouseholdMember $member): self @@ -386,11 +375,6 @@ class Household return $this; } - public function getCommentMembers(): CommentEmbeddable - { - return $this->commentMembers; - } - public function setCommentMembers(CommentEmbeddable $commentMembers): self { $this->commentMembers = $commentMembers; @@ -398,9 +382,20 @@ class Household return $this; } - public function getWaitingForBirth(): bool + /** + * Force an address starting at the current day + * on the Household. + * + * This will force the startDate's address on today. + * + * Used on household creation. + * + * @Serializer\Groups({"create"}) + */ + public function setForceAddress(Address $address) { - return $this->waitingForBirth; + $address->setValidFrom(new DateTime('today')); + $this->addAddress($address); } public function setWaitingForBirth(bool $waitingForBirth): self @@ -410,12 +405,7 @@ class Household return $this; } - public function getWaitingForBirthDate(): ?\DateTimeImmutable - { - return $this->waitingForBirthDate; - } - - public function setWaitingForBirthDate(?\DateTimeImmutable $waitingForBirthDate): self + public function setWaitingForBirthDate(?DateTimeImmutable $waitingForBirthDate): self { $this->waitingForBirthDate = $waitingForBirthDate; @@ -425,14 +415,34 @@ class Household public function validate(ExecutionContextInterface $context, $payload) { $addresses = $this->getAddresses(); - $cond = True; - for ($i=0; $i < count($addresses) - 1; $i++) { + $cond = true; + + for ($i = 0; count($addresses) - 1 > $i; ++$i) { if ($addresses[$i]->getValidFrom() != $addresses[$i + 1]->getValidTo()) { - $cond = False; + $cond = false; $context->buildViolation('The address are not sequentials. The validFrom date of one address should be equal to the validTo date of the previous address.') ->atPath('addresses') ->addViolation(); } } } + + private function buildCriteriaCurrentMembers(?DateTimeImmutable $now = null): Criteria + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + $date = null === $now ? (new DateTimeImmutable('today')) : $now; + + $criteria + ->where($expr->orX( + $expr->isNull('startDate'), + $expr->lte('startDate', $date) + )) + ->andWhere($expr->orX( + $expr->isNull('endDate'), + $expr->gt('endDate', $date) + )); + + return $criteria; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php index d157aa58a..403912328 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php @@ -1,23 +1,62 @@ id; - } - - public function getPosition(): ?Position - { - return $this->position; - } - - public function setPosition(Position $position): self - { - if ($this->position instanceof Position) { - throw new \LogicException("The position is already set. You cannot change ". - "a position of a membership"); - } - - $this->position = $position; - $this->shareHousehold = $position->getShareHousehold(); - - return $this; - } - - public function getStartDate(): ?\DateTimeImmutable - { - return $this->startDate; - } - - public function setStartDate(\DateTimeImmutable $startDate): self - { - $this->startDate = $startDate; - - return $this; - } - - public function getEndDate(): ?\DateTimeImmutable - { - return $this->endDate; - } - - public function setEndDate(?\DateTimeImmutable $endDate = null): self - { - $this->endDate = $endDate; - - return $this; - } + private ?DateTimeImmutable $startDate = null; public function getComment(): ?string { return $this->comment; } - public function setComment(?string $comment): self + public function getEndDate(): ?DateTimeImmutable { - $this->comment = $comment; + return $this->endDate; + } - return $this; + public function getHousehold(): ?Household + { + return $this->household; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getPerson(): ?Person + { + return $this->person; + } + + public function getPosition(): ?Position + { + return $this->position; } /** @@ -159,44 +133,35 @@ class HouseholdMember return $this->shareHousehold; } - public function setShareHousehold(bool $shareHousehold): self + public function getStartDate(): ?DateTimeImmutable { - $this->shareHousehold = $shareHousehold; + return $this->startDate; + } + + public function isCurrent(?DateTimeImmutable $at = null): bool + { + $at = null === $at ? new DateTimeImmutable('now') : $at; + + return $this->getStartDate() < $at && ( + null === $this->getEndDate() || $this->getEndDate() > $at + ); + } + + public function isHolder(): bool + { + return $this->holder; + } + + public function setComment(?string $comment): self + { + $this->comment = $comment; return $this; } - public function getPerson(): ?Person + public function setEndDate(?DateTimeImmutable $endDate = null): self { - return $this->person; - } - - public function setPerson(?Person $person): self - { - if ($this->person instanceof Person) { - throw new \LogicException("You cannot change person ". - "on a membership"); - } - - $this->person = $person; - $this->person->addHouseholdParticipation($this); - - return $this; - } - - public function getHousehold(): ?Household - { - return $this->household; - } - - public function setHousehold(?Household $household): self - { - if ($this->household instanceof Household) { - throw new \LogicException("You cannot change household ". - "on a membership"); - } - - $this->household = $household; + $this->endDate = $endDate; return $this; } @@ -208,17 +173,55 @@ class HouseholdMember return $this; } - public function isHolder(): bool + public function setHousehold(?Household $household): self { - return $this->holder; + if ($this->household instanceof Household) { + throw new LogicException('You cannot change household ' . + 'on a membership'); + } + + $this->household = $household; + + return $this; } - public function isCurrent(\DateTimeImmutable $at = null): bool + public function setPerson(?Person $person): self { - $at = NULL === $at ? new \DateTimeImmutable('now'): $at; + if ($this->person instanceof Person) { + throw new LogicException('You cannot change person ' . + 'on a membership'); + } - return $this->getStartDate() < $at && ( - NULL === $this->getEndDate() || $at < $this->getEndDate() - ); + $this->person = $person; + $this->person->addHouseholdParticipation($this); + + return $this; + } + + public function setPosition(Position $position): self + { + if ($this->position instanceof Position) { + throw new LogicException('The position is already set. You cannot change ' . + 'a position of a membership'); + } + + $this->position = $position; + $this->shareHousehold = $position->getShareHousehold(); + + return $this; + } + + public function setShareHousehold(bool $shareHousehold): self + { + $this->shareHousehold = $shareHousehold; + + return $this; + } + + public function setStartDate(DateTimeImmutable $startDate): self + { + $this->startDate = $startDate; + + return $this; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/PersonHouseholdAddress.php b/src/Bundle/ChillPersonBundle/Entity/Household/PersonHouseholdAddress.php index 28235b521..f23f325f9 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/PersonHouseholdAddress.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/PersonHouseholdAddress.php @@ -1,10 +1,18 @@ validFrom; - } - - /** - * The end date of the intersection address/household - * - * (this is not the enddate of the household, not - * the enddate of the address) - */ - public function getValidTo(): ?\DateTimeImmutable - { - return $this->validTo; - } - - public function getPerson(): ?Person - { - return $this->person; + return $this->address; } public function getHousehold(): ?Household @@ -100,8 +85,30 @@ class PersonHouseholdAddress return $this->relation; } - public function getAddress(): ?Address + public function getPerson(): ?Person { - return $this->address; + return $this->person; + } + + /** + * The start date of the intersection address/household. + * + * (this is not the startdate of the household, not + * the startdate of the address) + */ + public function getValidFrom(): ?DateTimeInterface + { + return $this->validFrom; + } + + /** + * The end date of the intersection address/household. + * + * (this is not the enddate of the household, not + * the enddate of the address) + */ + public function getValidTo(): ?DateTimeImmutable + { + return $this->validTo; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/Position.php b/src/Bundle/ChillPersonBundle/Entity/Household/Position.php index b1bfef173..bd297c09e 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/Position.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/Position.php @@ -1,8 +1,14 @@ allowHolder; + } public function getId(): ?int { @@ -57,11 +68,9 @@ class Position return $this->label; } - public function setLabel(array $label): self + public function getOrdering(): float { - $this->label = $label; - - return $this; + return $this->ordering; } public function getShareHousehold(): bool @@ -69,18 +78,6 @@ class Position return $this->shareHouseHold; } - public function setShareHousehold(bool $shareHouseHold): self - { - $this->shareHouseHold = $shareHouseHold; - - return $this; - } - - public function getAllowHolder(): bool - { - return $this->allowHolder; - } - public function isAllowHolder(): bool { return $this->getAllowHolder(); @@ -93,9 +90,11 @@ class Position return $this; } - public function getOrdering(): float + public function setLabel(array $label): self { - return $this->ordering; + $this->label = $label; + + return $this; } public function setOrdering(float $ordering): self @@ -104,4 +103,11 @@ class Position return $this; } + + public function setShareHousehold(bool $shareHouseHold): self + { + $this->shareHouseHold = $shareHouseHold; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php b/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php index afca96370..02463e5d6 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\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 ?string $id; @@ -46,9 +35,7 @@ class MaritalStatus private array $name; /** - * Get id - * - * @return string + * Get id. */ public function getId(): string { @@ -56,21 +43,32 @@ class MaritalStatus } /** - * Set id + * Get name. + * + * @return string array + */ + public function getName(): array + { + return $this->name; + } + + /** + * Set id. * - * @param string $id * @return MaritalStatus */ public function setId(string $id): self { $this->id = $id; + return $this; } /** - * Set name + * Set name. * * @param string array $name + * * @return MaritalStatus */ public function setName(array $name): self @@ -79,14 +77,4 @@ class MaritalStatus return $this; } - - /** - * Get name - * - * @return string array - */ - public function getName(): array - { - return $this->name; - } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index a7e8fec68..130e1ec10 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -1,5 +1,12 @@ 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 */ @@ -524,277 +544,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI } /** - * Remove AccompanyingPeriod - */ - public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod) : void - { - $participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod); - - if (! null === $participation) { - $participation->setEndDate(\DateTimeImmutable::class); - $this->accompanyingPeriodParticipations->removeElement($participation); - } - } - - /** - * 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 - { - $this->proxyAccompanyingPeriodOpenState = true; - $this->addAccompanyingPeriod($accompanyingPeriod); - } - - /** - * Set the Person file as closed at the given date. - * - * For update a closing date, you should update AccompanyingPeriod instance - * directly. - * - * To check if the Person and its accompanying period are consistent, use validation. - * - * @throws \Exception if two lines of the accompanying period are open. - */ - public function close(AccompanyingPeriod $accompanyingPeriod = null) : void - { - $this->proxyAccompanyingPeriodOpenState = false; - } - - /** - * 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(); - } - } - - return null; - } - - /** - * 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 current accompanyingPeriods array - */ - public function getCurrentAccompanyingPeriods(): array - { - $currentAccompanyingPeriods = []; - $currentDate = new DateTime(); - - foreach ($this->accompanyingPeriodParticipations as $participation) - { - $endDate = $participation->getEndDate(); - - if ($endDate === null || $endDate > $currentDate){ - $currentAccompanyingPeriods[] = $participation->getAccompanyingPeriod(); - } - } - - return $currentAccompanyingPeriods; - } - - /** - * Get AccompanyingPeriodParticipations Collection - * - * @return AccompanyingPeriodParticipation[]|Collection - */ - public function getAccompanyingPeriodParticipations(): Collection - { - return $this->accompanyingPeriodParticipations; - } - - /** - * Return a collection of participation, where the participation - * is still opened, not a draft, and the period is still opened - * - * @return AccompanyingPeriodParticipation[]|Collection - */ - public function getOpenedParticipations(): Collection - { - // create a criteria for filtering easily - $criteria = Criteria::create(); - $criteria - ->andWhere(Criteria::expr()->eq('endDate', NULL)) - ->orWhere(Criteria::expr()->gt('endDate', new \DateTime('now'))) - ; - - return $this->getAccompanyingPeriodParticipations() - ->matching($criteria) - ->filter(function (AccompanyingPeriodParticipation $app) { - $period = $app->getAccompanyingPeriod(); - return ( - NULL === $period->getClosingDate() - || new \DateTime('now') < $period->getClosingDate() - ) - && AccompanyingPeriod::STEP_DRAFT !== $period->getStep(); - }); - } - - /** - * Get the accompanying periods of a give person with the chronological order. - */ - public function getAccompanyingPeriodsOrdered(): array - { - $periods = $this->getAccompanyingPeriods(); - - //order by date : - usort($periods, function($a, $b) { - $dateA = $a->getOpeningDate(); - $dateB = $b->getOpeningDate(); - - if ($dateA == $dateB) { - $dateEA = $a->getClosingDate(); - $dateEB = $b->getClosingDate(); - - if ($dateEA == $dateEB) { - return 0; - } - - if ($dateEA < $dateEB) { - return -1; - } else { - return +1; - } - } - - if ($dateA < $dateB) { - return -1 ; - } else { - return 1; - } - }); - - return $periods; - } - - /** - * Check if the person is opened - */ - public function isOpen() : bool - { - foreach ($this->getAccompanyingPeriods() as $period) { - if ($period->isOpen()) { - return true; - } - } - - return false; - } - - public function getId(): ?int - { - return $this->id; - } - - /** - * Set firstName - * - * @param string $firstName - * @return Person - */ - public function setFirstName($firstName) - { - $this->firstName = $firstName; - - return $this; - } - - /** - * Get firstName - * - * @return string - */ - public function getFirstName() - { - return $this->firstName; - } - - /** - * Set lastName - * - * @param string $lastName - * @return Person - */ - public function setLastName($lastName) - { - $this->lastName = $lastName; - - return $this; - } - - /** - * 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) + public function addAddress(Address $address) { - $this->altNames = $altNames; + $this->addresses[] = $address; return $this; } /** - * @param PersonAltName $altName * @return $this */ public function addAltName(PersonAltName $altName) { - if (FALSE === $this->altNames->contains($altName)) { + if (false === $this->altNames->contains($altName)) { $this->altNames->add($altName); $altName->setPerson($this); } @@ -802,429 +566,14 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this; } - /** - * @param PersonAltName $altName - * @return $this - */ - public function removeAltName(PersonAltName $altName) + public function addHouseholdParticipation(HouseholdMember $member): self { - if ($this->altNames->contains($altName)) { - $altName->setPerson(null); - $this->altNames->removeElement($altName); - } + $this->householdParticipations[] = $member; 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; - } - - /** - * Return the age of a person, calculated at the date 'now'. - * - * If the person has a deathdate, calculate the age at the deathdate. - * - * @param string $at A valid string to create a DateTime. - */ - public function getAge(string $at = 'now'): ?int - { - if ($this->birthdate instanceof \DateTimeInterface) { - if ($this->deathdate instanceof \DateTimeInterface) { - return (int) date_diff($this->birthdate, $this->deathdate)->format('%y'); - } - - return (int) date_diff($this->birthdate, date_create($at))->format('%y'); - } - - return null; - } - - /** - * 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 - * - * @return string - */ - public function getGender() - { - return $this->gender; - } - - /** - * return gender as a Numeric form. - * This is used for translations - * @return int - * @deprecated Keep for legacy. Used in Chill 1.5 for feminize before icu translations - */ - public function getGenderNumeric() - { - switch ($this->getGender()) { - case self::FEMALE_GENDER: - return 1; - case self::MALE_GENDER: - return 0; - case self::BOTH_GENDER: - return 2; - default: - return -1; - } - } - - /** - * Set memo - * - * @param string $memo - * @return Person - */ - public function setMemo($memo) - { - if ($memo === null) { - $memo = ''; - } - - if ($this->memo !== $memo) { - $this->memo = $memo; - } - - return $this; - } - - /** - * Get memo - * - * @return string - */ - public function getMemo() - { - 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 civility - * - * @param Civility $civility - * @return Person - */ - public function setCivility(Civility $civility = null) - { - $this->civility = $civility; - return $this; - } - - /** - * Get civility - * - * @return Civility - */ - public function getCivility() - { - return $this->civility; - } - - /** - * 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 Country - */ - public function getNationality(): ?Country - { - return $this->nationality; - } - - /** - * @return string - */ - public function getLabel() - { - 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(?string $phonenumber = '') - { - $this->phonenumber = (string) $phonenumber; - - return $this; - } - - /** - * Get phonenumber - * - * @return string - */ - public function getPhonenumber(): string - { - return $this->phonenumber; - } - - /** - * Set mobilenumber - * - * @param string $mobilenumber - * @return Person - */ - public function setMobilenumber(?string $mobilenumber = '') - { - $this->mobilenumber = (string) $mobilenumber; - - return $this; - } - - /** - * Get mobilenumber - * - * @return string - */ - public function getMobilenumber(): string - { - 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) @@ -1237,204 +586,6 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI 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; - } - - /** - * @deprecated Use `getCurrentPersonAddress` instead - * @param DateTime|null $from - * @return false|mixed|null - * @throws \Exception - */ - public function getLastAddress(DateTime $from = null) - { - return $this->getCurrentPersonAddress(); - } - - /** - * get the address associated with the person at the given date - * - * If the `$at` parameter is now, use the method `getCurrentPersonAddress`, which is optimized - * on database side. - * - * @param DateTime|null $at - * @return Address|null - * @throws \Exception - */ - public function getAddressAt(?\DateTime $at = null): ?Address - { - $at ??= new DateTime('now'); - - /** @var ArrayIterator $addressesIterator */ - $addressesIterator = $this->getAddresses() - ->filter(static fn (Address $address): bool => $address->getValidFrom() <= $at) - ->getIterator(); - - $addressesIterator->uasort( - static fn (Address $left, Address $right): int => $right->getValidFrom() <=> $left->getValidFrom() - ); - - return [] === ($addresses = iterator_to_array($addressesIterator)) ? - null : - current($addresses); - } - - /** - * Get the current person address - * - * @return Address|null - */ - public function getCurrentPersonAddress(): ?Address - { - if (null === $this->currentPersonAddress) { - return null; - } - - return $this->currentPersonAddress->getAddress(); - } - - /** - * Validation callback that checks if the accompanying periods are valid - * - * This method add violation errors. - * - * @Assert\Callback( - * groups={"accompanying_period_consistent"} - * ) - */ - public function isAccompanyingPeriodValid(ExecutionContextInterface $context) - { - $r = $this->checkAccompanyingPeriodsAreNotCollapsing(); - - if ($r !== true) { - if ($r['result'] === self::ERROR_PERIODS_ARE_COLLAPSING) { - $context->buildViolation('Two accompanying periods have days in commun') - ->atPath('accompanyingPeriods') - ->addViolation(); - } - - 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(); - } - } - } - - /** - * Return true if the person has two addresses with the - * same validFrom date (in format 'Y-m-d') - */ - public function hasTwoAdressWithSameValidFromDate() - { - $validYMDDates = array(); - - foreach ($this->addresses as $ad) { - $validDate = $ad->getValidFrom()->format('Y-m-d'); - - if (in_array($validDate, $validYMDDates)) { - return true; - } - $validYMDDates[] = $validDate; - } - - return false; - } - - /** - * Validation callback that checks if the addresses are valid (do not have - * two addresses with the same validFrom date) - * - * This method add violation errors. - * - * @Assert\Callback( - * groups={"addresses_consistent"} - * ) - */ - public function isAddressesValid(ExecutionContextInterface $context) - { - if ($this->hasTwoAdressWithSameValidFromDate()) { - $context - ->buildViolation('Two addresses has the same validFrom date') - ->atPath('addresses') - ->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 /** @@ -1451,322 +602,55 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI $periodsNbr = sizeof($periods); $i = 0; - while($i < $periodsNbr - 1) { + while ($periodsNbr - 1 > $i) { $periodI = $periods[$i]; $periodAfterI = $periods[$i + 1]; - if($periodI->isOpen()) { - return array( + if ($periodI->isOpen()) { + return [ '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( + 'date' => $periodI->getOpeningDate(), + ]; + } + + if ($periodI->getClosingDate() >= $periodAfterI->getOpeningDate()) { + return [ 'result' => self::ERROR_PERIODS_ARE_COLLAPSING, 'dateOpening' => $periodI->getOpeningDate(), 'dateClosing' => $periodI->getClosingDate(), - 'date' => $periodAfterI->getOpeningDate() - ); + 'date' => $periodAfterI->getOpeningDate(), + ]; } - $i++; + ++$i; } return true; } - public function getFullnameCanonical() : string + /** + * Set the Person file as closed at the given date. + * + * For update a closing date, you should update AccompanyingPeriod instance + * directly. + * + * To check if the Person and its accompanying period are consistent, use validation. + * + * @throws Exception if two lines of the accompanying period are open. + */ + public function close(?AccompanyingPeriod $accompanyingPeriod = null): void { - return $this->fullnameCanonical; - } - - public function setFullnameCanonical($fullnameCanonical) : Person - { - $this->fullnameCanonical = $fullnameCanonical; - return $this; - } - - public function addHouseholdParticipation(HouseholdMember $member): self - { - $this->householdParticipations[] = $member; - - return $this; - } - - public function getHouseholdParticipations(): Collection - { - return $this->householdParticipations; + $this->proxyAccompanyingPeriodOpenState = false; } /** - * Get participation where the person does share the household. - * - * Order by startDate, desc + * This public function is the same but return only true or false. */ - public function getHouseholdParticipationsShareHousehold(): Collection + public function containsAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool { - $criteria = new Criteria(); - $expr = Criteria::expr(); - - $criteria - ->where( - $expr->eq('shareHousehold', true) - ) - ->orderBy(['startDate' => Criteria::DESC]) - ; - - return $this->getHouseholdParticipations() - ->matching($criteria) - ; - } - - /** - * Get participation where the person does not share the household. - * - * Order by startDate, desc - */ - public function getHouseholdParticipationsNotShareHousehold(): Collection - { - $criteria = new Criteria(); - $expr = Criteria::expr(); - - $criteria - ->where( - $expr->eq('shareHousehold', false) - ) - ->orderBy(['startDate' => Criteria::DESC]) - ; - - return $this->getHouseholdParticipations() - ->matching($criteria) - ; - } - - public function getCurrentHousehold(?\DateTimeImmutable $at = null): ?Household - { - $participation = $this->getCurrentHouseholdParticipationShareHousehold($at); - - return $participation instanceof HouseholdMember ? - $participation->getHousehold() - : null; - } - - public function getCurrentHouseholdParticipationShareHousehold(?\DateTimeImmutable $at = null): ?HouseholdMember - { - $criteria = new Criteria(); - $expr = Criteria::expr(); - $date = NULL === $at ? new \DateTimeImmutable('today') : $at; - $datef = $date->format('Y-m-d'); - - if ( - NULL !== ($this->currentHouseholdParticipationAt[$datef] ?? NULL)) { - return $this->currentHouseholdParticipationAt[$datef]; - } - - $criteria - ->where( - $expr->andX( - $expr->lte('startDate', $date), - $expr->orX( - $expr->isNull('endDate'), - $expr->gt('endDate', $date) - ), - $expr->eq('shareHousehold', true) - ) - ); - - $participations = $this->getHouseholdParticipations() - ->matching($criteria) - ; - - return $participations->count() > 0 ? - $this->currentHouseholdParticipationAt[$datef] = $participations->first() - : null; - } - - public function isSharingHousehold(?\DateTimeImmutable $at = null): bool - { - return NULL !== $this->getCurrentHousehold($at); - } - - public function getHouseholdAddresses(): Collection - { - return $this->householdAddresses; - } - - public function getCurrentHouseholdAddress(?\DateTimeImmutable $at = null): ?Address - { - if ( - NULL === $at - || - $at->format('Ymd') === (new \DateTime('today'))->format('Ymd') - ) { - return $this->currentPersonAddress instanceof PersonCurrentAddress - ? $this->currentPersonAddress->getAddress() : NULL; - } - - // if not now, compute the date from history - $criteria = new Criteria(); - $expr = Criteria::expr(); - - $criteria->where( - $expr->lte('validFrom', $at) - ) - ->andWhere( - $expr->orX( - $expr->isNull('validTo'), - $expr->gte('validTo', $at) - ) - ); - - $addrs = $this->getHouseholdAddresses() - ->matching($criteria) - ; - - if ($addrs->count() > 0) { - return $addrs->first()->getAddress(); - } else { - return null; - } - } - - public function hasCurrentHouseholdAddress(?\DateTimeImmutable $at = null): bool - { - return null !== $this->getCurrentHouseholdAddress($at); - } - - public function getGenderComment(): CommentEmbeddable - { - return $this->genderComment; - } - - public function setGenderComment(CommentEmbeddable $genderComment): self - { - $this->genderComment = $genderComment; - - return $this; - } - - public function getMaritalStatusComment(): CommentEmbeddable - { - return $this->maritalStatusComment; - } - - public function setMaritalStatusComment(CommentEmbeddable $maritalStatusComment): self - { - $this->maritalStatusComment = $maritalStatusComment; - - return $this; - } - - public function getDeathdate(): ?\DateTimeInterface - { - return $this->deathdate; - } - - public function setDeathdate(?\DateTimeInterface $deathdate): self - { - $this->deathdate = $deathdate; - - return $this; - } - - public function getMaritalStatusDate(): ?\DateTimeInterface - { - return $this->maritalStatusDate; - } - - public function setMaritalStatusDate(?\DateTimeInterface $maritalStatusDate): self - { - $this->maritalStatusDate = $maritalStatusDate; - - return $this; - } - - public function getAcceptSMS(): ?bool - { - return $this->acceptSMS; - } - - public function setAcceptSMS(bool $acceptSMS): self - { - $this->acceptSMS = $acceptSMS; - - return $this; - } - - public function getAcceptEmail(): ?bool - { - return $this->acceptEmail; - } - - public function setAcceptEmail(bool $acceptEmail): self - { - $this->acceptEmail = $acceptEmail; - - return $this; - } - - public function getNumberOfChildren(): ?int - { - return $this->numberOfChildren; - } - - public function setNumberOfChildren(int $numberOfChildren): self - { - $this->numberOfChildren = $numberOfChildren; - - return $this; - } - - /** - * @return AccompanyingPeriod[]|Collection - */ - public function getAccompanyingPeriodRequested(): Collection - { - return $this->accompanyingPeriodRequested; - } - - /** - * Return a list of all accompanying period where the person is involved: - * - * * as requestor; - * * as participant, only for opened participation; - * - * @param bool $asParticipantOpen add participation which are still opened - * @param bool $asRequestor add accompanying period where the person is requestor - * @return AccompanyingPeriod[]|Collection - */ - public function getAccompanyingPeriodInvolved( - bool $asParticipantOpen = true, - bool $asRequestor = true - ): Collection - { - $result = new ArrayCollection(); - - if ($asParticipantOpen) { - foreach ($this->getOpenedParticipations() - ->map(fn (AccompanyingPeriodParticipation $app) => - $app->getAccompanyingPeriod()) - as $period - ) { - if (!$result->contains($period)) { - $result->add($period); - } - } - } - - if ($asRequestor) { - foreach ($this->accompanyingPeriodRequested as $period) { - if (!$result->contains($period)) { - $result->add($period); - } - } - } - - return $result; + return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true; } /** @@ -1776,7 +660,6 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI * Used in template, to find the participation when iterating on a list * of period. * - * @param \Chill\PersonBundle\Entity\AccompanyingPeriod $period * @return AccompanyingPeriodParticipation */ public function findParticipationForPeriod(AccompanyingPeriod $period): ?AccompanyingPeriodParticipation @@ -1799,11 +682,934 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return null; } + public function getAcceptEmail(): ?bool + { + return $this->acceptEmail; + } + + public function getAcceptSMS(): ?bool + { + return $this->acceptSMS; + } + + /** + * Return a list of all accompanying period where the person is involved:. + * + * * as requestor; + * * as participant, only for opened participation; + * + * @param bool $asParticipantOpen add participation which are still opened + * @param bool $asRequestor add accompanying period where the person is requestor + * + * @return AccompanyingPeriod[]|Collection + */ + public function getAccompanyingPeriodInvolved( + bool $asParticipantOpen = true, + bool $asRequestor = true + ): Collection { + $result = new ArrayCollection(); + + if ($asParticipantOpen) { + foreach ($this->getOpenedParticipations() + ->map(fn (AccompanyingPeriodParticipation $app) => $app->getAccompanyingPeriod()) + as $period + ) { + if (!$result->contains($period)) { + $result->add($period); + } + } + } + + if ($asRequestor) { + foreach ($this->accompanyingPeriodRequested as $period) { + if (!$result->contains($period)) { + $result->add($period); + } + } + } + + return $result; + } + + /** + * Get AccompanyingPeriodParticipations Collection. + * + * @return AccompanyingPeriodParticipation[]|Collection + */ + public function getAccompanyingPeriodParticipations(): Collection + { + return $this->accompanyingPeriodParticipations; + } + + /** + * @return AccompanyingPeriod[]|Collection + */ + public function getAccompanyingPeriodRequested(): Collection + { + return $this->accompanyingPeriodRequested; + } + + /** + * 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. + */ + public function getAccompanyingPeriodsOrdered(): array + { + $periods = $this->getAccompanyingPeriods(); + + //order by date : + usort($periods, function ($a, $b) { + $dateA = $a->getOpeningDate(); + $dateB = $b->getOpeningDate(); + + if ($dateA == $dateB) { + $dateEA = $a->getClosingDate(); + $dateEB = $b->getClosingDate(); + + if ($dateEA == $dateEB) { + return 0; + } + + if ($dateEA < $dateEB) { + return -1; + } + + return +1; + } + + if ($dateA < $dateB) { + return -1; + } + + return 1; + }); + + return $periods; + } + + /** + * get the address associated with the person at the given date. + * + * If the `$at` parameter is now, use the method `getCurrentPersonAddress`, which is optimized + * on database side. + * + * @throws Exception + */ + public function getAddressAt(?DateTime $at = null): ?Address + { + $at ??= new DateTime('now'); + + /** @var ArrayIterator $addressesIterator */ + $addressesIterator = $this->getAddresses() + ->filter(static fn (Address $address): bool => $address->getValidFrom() <= $at) + ->getIterator(); + + $addressesIterator->uasort( + static fn (Address $left, Address $right): int => $right->getValidFrom() <=> $left->getValidFrom() + ); + + return [] === ($addresses = iterator_to_array($addressesIterator)) ? + null : + current($addresses); + } + + /** + * By default, the addresses are ordered by date, descending (the most + * recent first). + */ + public function getAddresses(): Collection + { + return $this->addresses; + } + + /** + * Return the age of a person, calculated at the date 'now'. + * + * If the person has a deathdate, calculate the age at the deathdate. + * + * @param string $at A valid string to create a DateTime. + */ + public function getAge(string $at = 'now'): ?int + { + if ($this->birthdate instanceof DateTimeInterface) { + if ($this->deathdate instanceof DateTimeInterface) { + return (int) date_diff($this->birthdate, $this->deathdate)->format('%y'); + } + + return (int) date_diff($this->birthdate, date_create($at))->format('%y'); + } + + return null; + } + + 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 $this->cFData; + } + + /** + * Get civility. + * + * @return Civility + */ + public function getCivility() + { + return $this->civility; + } + + /** + * Get contactInfo. + * + * @return string + */ + public function getcontactInfo() + { + return $this->contactInfo; + } + + /** + * Get countryOfBirth. + * + * @return Chill\MainBundle\Entity\Country + */ + public function getCountryOfBirth() + { + return $this->countryOfBirth; + } + + public function getCreatedAt(): ?DateTimeInterface + { + return $this->createdAt; + } + public function getCreatedBy(): ?User { return $this->createdBy; } + /** + * Returns the opened accompanying period. + * + * @deprecated since 1.1 use `getOpenedAccompanyingPeriod instead + */ + public function getCurrentAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->getOpenedAccompanyingPeriod(); + } + + /** + * Get current accompanyingPeriods array. + */ + public function getCurrentAccompanyingPeriods(): array + { + $currentAccompanyingPeriods = []; + $currentDate = new DateTime(); + + foreach ($this->accompanyingPeriodParticipations as $participation) { + $endDate = $participation->getEndDate(); + + if (null === $endDate || $endDate > $currentDate) { + $currentAccompanyingPeriods[] = $participation->getAccompanyingPeriod(); + } + } + + return $currentAccompanyingPeriods; + } + + public function getCurrentHousehold(?DateTimeImmutable $at = null): ?Household + { + $participation = $this->getCurrentHouseholdParticipationShareHousehold($at); + + return $participation instanceof HouseholdMember ? + $participation->getHousehold() + : null; + } + + public function getCurrentHouseholdAddress(?DateTimeImmutable $at = null): ?Address + { + if ( + null === $at + || $at->format('Ymd') === (new DateTime('today'))->format('Ymd') + ) { + return $this->currentPersonAddress instanceof PersonCurrentAddress + ? $this->currentPersonAddress->getAddress() : null; + } + + // if not now, compute the date from history + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria->where( + $expr->lte('validFrom', $at) + ) + ->andWhere( + $expr->orX( + $expr->isNull('validTo'), + $expr->gte('validTo', $at) + ) + ); + + $addrs = $this->getHouseholdAddresses() + ->matching($criteria); + + if ($addrs->count() > 0) { + return $addrs->first()->getAddress(); + } + + return null; + } + + public function getCurrentHouseholdParticipationShareHousehold(?DateTimeImmutable $at = null): ?HouseholdMember + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + $date = null === $at ? new DateTimeImmutable('today') : $at; + $datef = $date->format('Y-m-d'); + + if ( + null !== ($this->currentHouseholdParticipationAt[$datef] ?? null)) { + return $this->currentHouseholdParticipationAt[$datef]; + } + + $criteria + ->where( + $expr->andX( + $expr->lte('startDate', $date), + $expr->orX( + $expr->isNull('endDate'), + $expr->gt('endDate', $date) + ), + $expr->eq('shareHousehold', true) + ) + ); + + $participations = $this->getHouseholdParticipations() + ->matching($criteria); + + return $participations->count() > 0 ? + $this->currentHouseholdParticipationAt[$datef] = $participations->first() + : null; + } + + /** + * Get the current person address. + */ + public function getCurrentPersonAddress(): ?Address + { + if (null === $this->currentPersonAddress) { + return null; + } + + return $this->currentPersonAddress->getAddress(); + } + + public function getDeathdate(): ?DateTimeInterface + { + return $this->deathdate; + } + + /** + * Get email. + * + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * Get firstName. + * + * @return string + */ + public function getFirstName() + { + return $this->firstName; + } + + public function getFullnameCanonical(): string + { + return $this->fullnameCanonical; + } + + /** + * Get gender. + * + * @return string + */ + public function getGender() + { + return $this->gender; + } + + public function getGenderComment(): CommentEmbeddable + { + return $this->genderComment; + } + + /** + * return gender as a Numeric form. + * This is used for translations. + * + * @return int + * + * @deprecated Keep for legacy. Used in Chill 1.5 for feminize before icu translations + */ + public function getGenderNumeric() + { + switch ($this->getGender()) { + case self::FEMALE_GENDER: + return 1; + + case self::MALE_GENDER: + return 0; + + case self::BOTH_GENDER: + return 2; + + default: + return -1; + } + } + + public function getHouseholdAddresses(): Collection + { + return $this->householdAddresses; + } + + public function getHouseholdParticipations(): Collection + { + return $this->householdParticipations; + } + + /** + * Get participation where the person does not share the household. + * + * Order by startDate, desc + */ + public function getHouseholdParticipationsNotShareHousehold(): Collection + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria + ->where( + $expr->eq('shareHousehold', false) + ) + ->orderBy(['startDate' => Criteria::DESC]); + + return $this->getHouseholdParticipations() + ->matching($criteria); + } + + /** + * Get participation where the person does share the household. + * + * Order by startDate, desc + */ + public function getHouseholdParticipationsShareHousehold(): Collection + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria + ->where( + $expr->eq('shareHousehold', true) + ) + ->orderBy(['startDate' => Criteria::DESC]); + + return $this->getHouseholdParticipations() + ->matching($criteria); + } + + public function getId(): ?int + { + return $this->id; + } + + /** + * @return string + */ + public function getLabel() + { + return $this->getFirstName() . ' ' . $this->getLastName(); + } + + /** + * @deprecated Use `getCurrentPersonAddress` instead + * + * @throws Exception + * + * @return false|mixed|null + */ + public function getLastAddress(?DateTime $from = null) + { + return $this->getCurrentPersonAddress(); + } + + /** + * Get lastName. + * + * @return string + */ + public function getLastName() + { + return $this->lastName; + } + + /** + * Get maritalStatus. + * + * @return MaritalStatus + */ + public function getMaritalStatus() + { + return $this->maritalStatus; + } + + public function getMaritalStatusComment(): CommentEmbeddable + { + return $this->maritalStatusComment; + } + + public function getMaritalStatusDate(): ?DateTimeInterface + { + return $this->maritalStatusDate; + } + + /** + * Get memo. + * + * @return string + */ + public function getMemo() + { + return $this->memo; + } + + /** + * Get mobilenumber. + */ + public function getMobilenumber(): string + { + return $this->mobilenumber; + } + + /** + * Get nationality. + * + * @return Country + */ + public function getNationality(): ?Country + { + return $this->nationality; + } + + public function getNumberOfChildren(): ?int + { + return $this->numberOfChildren; + } + + /** + * 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(); + } + } + + return null; + } + + /** + * Return a collection of participation, where the participation + * is still opened or in draft state. + * + * @return AccompanyingPeriodParticipation[]|Collection + */ + public function getOpenedParticipations(): Collection + { + // create a criteria for filtering easily + $criteria = Criteria::create(); + $criteria + ->andWhere(Criteria::expr()->eq('endDate', null)) + ->orWhere(Criteria::expr()->gt('endDate', new DateTime('now'))); + + return $this->getAccompanyingPeriodParticipations() + ->matching($criteria) + ->filter(function (AccompanyingPeriodParticipation $app) { + return AccompanyingPeriod::STEP_CLOSED !== $app->getAccompanyingPeriod()->getStep(); + }); + } + + public function getOtherPhoneNumbers(): Collection + { + return $this->otherPhoneNumbers; + } + + /** + * Get phonenumber. + */ + public function getPhonenumber(): string + { + return $this->phonenumber; + } + + /** + * Get placeOfBirth. + * + * @return string + */ + public function getPlaceOfBirth() + { + return $this->placeOfBirth; + } + + /** + * Get spokenLanguages. + * + * @return ArrayCollection + */ + public function getSpokenLanguages() + { + return $this->spokenLanguages; + } + + public function getUpdatedAt(): ?DateTimeInterface + { + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + + public function hasCurrentHouseholdAddress(?DateTimeImmutable $at = null): bool + { + return null !== $this->getCurrentHouseholdAddress($at); + } + + /** + * Return true if the person has two addresses with the + * same validFrom date (in format 'Y-m-d'). + */ + public function hasTwoAdressWithSameValidFromDate() + { + $validYMDDates = []; + + foreach ($this->addresses as $ad) { + $validDate = $ad->getValidFrom()->format('Y-m-d'); + + if (in_array($validDate, $validYMDDates)) { + return true; + } + $validYMDDates[] = $validDate; + } + + return false; + } + + /** + * Validation callback that checks if the accompanying periods are valid. + * + * This method add violation errors. + * + * @Assert\Callback( + * groups={"accompanying_period_consistent"} + * ) + */ + 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). + * + * This method add violation errors. + * + * @Assert\Callback( + * groups={"addresses_consistent"} + * ) + */ + public function isAddressesValid(ExecutionContextInterface $context) + { + if ($this->hasTwoAdressWithSameValidFromDate()) { + $context + ->buildViolation('Two addresses has the same validFrom date') + ->atPath('addresses') + ->addViolation(); + } + } + + /** + * Check if the person is opened. + */ + public function isOpen(): bool + { + foreach ($this->getAccompanyingPeriods() as $period) { + if ($period->isOpen()) { + return true; + } + } + + return false; + } + + public function isSharingHousehold(?DateTimeImmutable $at = null): bool + { + return null !== $this->getCurrentHousehold($at); + } + + /** + * 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 + { + $this->proxyAccompanyingPeriodOpenState = true; + $this->addAccompanyingPeriod($accompanyingPeriod); + } + + /** + * Remove AccompanyingPeriod. + */ + public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): void + { + $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; + } + + public function setAcceptEmail(bool $acceptEmail): self + { + $this->acceptEmail = $acceptEmail; + + return $this; + } + + public function setAcceptSMS(bool $acceptSMS): self + { + $this->acceptSMS = $acceptSMS; + + 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 civility. + * + * @param Civility $civility + * + * @return Person + */ + public function setCivility(?Civility $civility = null) + { + $this->civility = $civility; + + 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; + } + + public function setCreatedAt(DateTimeInterface $datetime): self + { + $this->createdAt = $datetime; + + return $this; + } + public function setCreatedBy(User $createdBy): self { $this->createdBy = $createdBy; @@ -1811,26 +1617,231 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this; } - public function getCreatedAt(): ?DateTimeInterface + public function setDeathdate(?DateTimeInterface $deathdate): self { - return $this->createdAt; - } - - public function setCreatedAt(\DateTimeInterface $datetime): self - { - $this->createdAt = $datetime; + $this->deathdate = $deathdate; return $this; } - public function getUpdatedBy(): ?User + /** + * Set email. + * + * @param string $email + * + * @return Person + */ + public function setEmail($email) { - return $this->updatedBy; + if (null === $email) { + $email = ''; + } + + $this->email = $email; + + return $this; } - public function getUpdatedAt(): ?DateTimeInterface + /** + * Set firstName. + * + * @param string $firstName + * + * @return Person + */ + public function setFirstName($firstName) { - return $this->updatedAt; + $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; + } + + public function setGenderComment(CommentEmbeddable $genderComment): self + { + $this->genderComment = $genderComment; + + 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; + } + + public function setMaritalStatusComment(CommentEmbeddable $maritalStatusComment): self + { + $this->maritalStatusComment = $maritalStatusComment; + + return $this; + } + + public function setMaritalStatusDate(?DateTimeInterface $maritalStatusDate): self + { + $this->maritalStatusDate = $maritalStatusDate; + + 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(?string $mobilenumber = '') + { + $this->mobilenumber = (string) $mobilenumber; + + return $this; + } + + /** + * Set nationality. + * + * @param Chill\MainBundle\Entity\Country $nationality + * + * @return Person + */ + public function setNationality(?Country $nationality = null) + { + $this->nationality = $nationality; + + return $this; + } + + public function setNumberOfChildren(int $numberOfChildren): self + { + $this->numberOfChildren = $numberOfChildren; + + return $this; + } + + /** + * @return $this + */ + public function setOtherPhoneNumbers(Collection $otherPhoneNumbers) + { + $this->otherPhoneNumbers = $otherPhoneNumbers; + + return $this; + } + + /** + * Set phonenumber. + * + * @param string $phonenumber + * + * @return Person + */ + public function setPhonenumber(?string $phonenumber = '') + { + $this->phonenumber = (string) $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; + } + + public function setUpdatedAt(DateTimeInterface $datetime): self + { + $this->updatedAt = $datetime; + + return $this; } public function setUpdatedBy(User $user): self @@ -1840,11 +1851,19 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this; } - public function setUpdatedAt(\DateTimeInterface $datetime): self + /** + * This private function scan accompanyingPeriodParticipations Collection, + * searching for a given AccompanyingPeriod. + */ + private function participationsContainAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): ?AccompanyingPeriodParticipation { - $this->updatedAt = $datetime; + foreach ($this->accompanyingPeriodParticipations as $participation) { + /** @var AccompanyingPeriodParticipation $participation */ + if ($participation->getAccompanyingPeriod() === $accompanyingPeriod) { + return $participation; + } + } - return $this; + return null; } - } diff --git a/src/Bundle/ChillPersonBundle/Entity/Person/PersonCurrentAddress.php b/src/Bundle/ChillPersonBundle/Entity/Person/PersonCurrentAddress.php index e982f8b97..e9b7c8ae2 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person/PersonCurrentAddress.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person/PersonCurrentAddress.php @@ -1,9 +1,17 @@ address; + } - /** - * @return Person - */ public function getPerson(): Person { return $this->person; } - /** - * @return Address - */ - public function getAddress(): Address - { - return $this->address; - } - /** * This date is the intersection of household membership - * and address validity - * - * @return \DateTimeImmutable + * and address validity. */ - public function getValidFrom(): \DateTimeImmutable + public function getValidFrom(): DateTimeImmutable { return $this->validFrom; } /** * This date is the intersection of household membership - * and address validity - * - * @return \DateTimeImmutable|null + * and address validity. */ - public function getValidTo(): ?\DateTimeImmutable + public function getValidTo(): ?DateTimeImmutable { return $this->validTo; } diff --git a/src/Bundle/ChillPersonBundle/Entity/PersonAltName.php b/src/Bundle/ChillPersonBundle/Entity/PersonAltName.php index 95603d4ef..15f0d8eb5 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 9f116c501..0d83dcf6f 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 c4497fce8..12487f74a 100644 --- a/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php +++ b/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php @@ -1,21 +1,38 @@ 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 @@ -66,9 +83,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 @@ -76,24 +93,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 @@ -101,18 +108,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/Relationships/Relation.php b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php index d8cbb3898..0761ba9fa 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php +++ b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php @@ -1,17 +1,23 @@ id; } + public function getIsActive(): bool + { + return $this->isActive; + } + + public function getReverseTitle(): ?array + { + return $this->reverseTitle; + } + public function getTitle(): ?array { return $this->title; } - public function setTitle(?array $title): self + public function setIsActive(?bool $isActive): self { - $this->title = $title; + $this->isActive = $isActive; return $this; } - public function getReverseTitle(): ?array - { - return $this->reverseTitle; - } - public function setReverseTitle(?array $reverseTitle): self { $this->reverseTitle = $reverseTitle; @@ -71,14 +82,9 @@ class Relation return $this; } - public function getIsActive(): bool + public function setTitle(?array $title): self { - return $this->isActive; - } - - public function setIsActive(?bool $isActive): self - { - $this->isActive = $isActive; + $this->title = $title; return $this; } diff --git a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php index 54be21140..57470acfb 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php +++ b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relationship.php @@ -1,30 +1,55 @@ id; + return $this->createdAt; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; } public function getFromPerson(): ?Person @@ -99,23 +109,14 @@ class Relationship implements TrackCreationInterface, TrackUpdateInterface return $this->fromPerson; } - public function setFromPerson(?Person $fromPerson): self + public function getId(): ?int { - $this->fromPerson = $fromPerson; - - return $this; + return $this->id; } - public function getToPerson(): ?Person + public function getRelation(): ?Relation { - return $this->toPerson; - } - - public function setToPerson(?Person $toPerson): self - { - $this->toPerson = $toPerson; - - return $this; + return $this->relation; } public function getReverse(): ?bool @@ -123,16 +124,26 @@ class Relationship implements TrackCreationInterface, TrackUpdateInterface return $this->reverse; } - public function setReverse(bool $reverse): self + public function getToPerson(): ?Person { - $this->reverse = $reverse; - - return $this; + return $this->toPerson; } - public function getCreatedBy(): ?User + public function getUpdatedAt(): ?DateTimeImmutable { - return $this->createdBy; + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; + } + + public function setCreatedAt(DateTimeInterface $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; } public function setCreatedBy(?User $user): self @@ -142,51 +153,45 @@ class Relationship implements TrackCreationInterface, TrackUpdateInterface return $this; } - public function getCreatedAt(): ?\DateTimeImmutable + public function setFromPerson(?Person $fromPerson): self { - return $this->createdAt; - } - - public function setCreatedAt(\DateTimeInterface $createdAt): self - { - $this->createdAt = $createdAt; + $this->fromPerson = $fromPerson; return $this; } - public function getUpdatedBy(): ?User - { - return $this->updatedBy; - } - - public function setUpdatedBy(?User $updatedBy): self - { - $this->updatedBy = $updatedBy; - - return $this; - } - - public function getUpdatedAt(): ?\DateTimeImmutable - { - return $this->updatedAt; - } - - public function setUpdatedAt(?\DateTimeInterface $updatedAt): self - { - $this->updatedAt = $updatedAt; - - return $this; - } - - public function getRelation(): ?Relation - { - return $this->relation; - } - public function setRelation(?Relation $relation): self { $this->relation = $relation; return $this; } -} \ No newline at end of file + + public function setReverse(bool $reverse): self + { + $this->reverse = $reverse; + + return $this; + } + + public function setToPerson(?Person $toPerson): self + { + $this->toPerson = $toPerson; + + return $this; + } + + public function setUpdatedAt(?DateTimeInterface $updatedAt): self + { + $this->updatedAt = $updatedAt; + + return $this; + } + + public function setUpdatedBy(?User $updatedBy): self + { + $this->updatedBy = $updatedBy; + + return $this; + } +} diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php index f01b2a4c1..5c7f5bab1 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php @@ -1,7 +1,15 @@ 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 7ad301875..5a7265944 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php @@ -1,7 +1,15 @@ results = 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|Result[] - */ - public function getResults(): Collection - { - return $this->results; - } - public function addResult(Result $result): self { if (!$this->results->contains($result)) { @@ -125,10 +72,71 @@ 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; + } + + public function getId(): ?int + { + return $this->id; + } + + /** + * @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 42a4c0929..91212e30a 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php @@ -1,9 +1,17 @@ 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)) { @@ -162,26 +85,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; } @@ -192,4 +172,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 bb05c900e..4cde849c9 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php @@ -1,7 +1,16 @@ results = new ArrayCollection(); } - public function getId(): ?int - { - return $this->id; - } - - public function getDesactivationDate(): ?\DateTimeInterface - { - return $this->desactivationDate; - } - - public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self - { - $this->desactivationDate = $desactivationDate; - - return $this; - } - - public function getIssue(): ?SocialIssue - { - return $this->issue; - } - - public function setIssue(?SocialIssue $issue): self - { - $this->issue = $issue; - - return $this; - } - - public function getParent(): ?self - { - return $this->parent; - } - - public function hasParent(): bool - { - return $this->getParent() instanceof self; - } - - 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)) { @@ -148,18 +102,42 @@ class SocialAction return $this; } - public function removeChild(self $child): self + public function addGoal(Goal $goal): self { - if ($this->children->removeElement($child)) { - // set the owning side to null (unless already changed) - if ($child->getParent() === $this) { - $child->setParent(null); - } + if (!$this->goals->contains($goal)) { + $this->goals[] = $goal; } return $this; } + public function addResult(Result $result): self + { + if (!$this->results->contains($result)) { + $this->results[] = $result; + } + + return $this; + } + + /** + * @return Collection|self[] + */ + public function getChildren(): Collection + { + return $this->children; + } + + public function getDefaultNotificationDelay(): ?DateInterval + { + return $this->defaultNotificationDelay; + } + + public function getDesactivationDate(): ?DateTimeInterface + { + return $this->desactivationDate; + } + /** * @return Collection|self[] All the descendants (children, children of children, ...) */ @@ -168,10 +146,11 @@ class SocialAction $descendants = new ArrayCollection(); foreach ($this->getChildren() as $child) { - if(! $descendants->contains($child)) { + if (!$descendants->contains($child)) { $descendants->add($child); - foreach($child->getDescendants() as $descendantsOfChild) { - if(! $descendants->contains($descendantsOfChild)) { + + foreach ($child->getDescendants() as $descendantsOfChild) { + if (!$descendants->contains($descendantsOfChild)) { $descendants->add($descendantsOfChild); } } @@ -188,35 +167,16 @@ class SocialAction { $descendants = $this->getDescendants(); - if(! $descendants->contains($this)) { + if (!$descendants->contains($this)) { $descendants->add($this); } return $descendants; } - public function getDefaultNotificationDelay(): ?\DateInterval + public function getEvaluations(): Collection { - 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 $this->evaluations; } /** @@ -227,10 +187,46 @@ class SocialAction return $this->goals; } - public function addGoal(Goal $goal): self + public function getId(): ?int { - if (!$this->goals->contains($goal)) { - $this->goals[] = $goal; + 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 hasParent(): bool + { + return $this->getParent() instanceof self; + } + + 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; @@ -243,23 +239,6 @@ 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); @@ -267,11 +246,38 @@ class SocialAction return $this; } - /** - * @return Collection - */ - public function getEvaluations(): Collection + public function setDefaultNotificationDelay(DateInterval $defaultNotificationDelay): self { - return $this->evaluations; + $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 f9956e57f..9e862fad6 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php @@ -1,21 +1,40 @@ children = new ArrayCollection(); $this->socialActions = new ArrayCollection(); } - public function getId(): ?int - { - return $this->id; - } - - public function getParent(): ?self - { - return $this->parent; - } - - public function hasParent(): bool - { - return $this->parent !== null; - } - - 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)) { @@ -95,18 +74,64 @@ 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; } + /** + * In a SocialIssues's collection, find the elements which are an ancestor of + * other elements. + * + * Removing those elements of the Collection (which is not done by this method) + * will ensure that only the most descendent elements are present in the collection, + * (any ancestor of another element are present). + * + * @param Collection|SocialIssue[] $socialIssues + * + * @return Collection|SocialIssue[] + */ + public static function findAncestorSocialIssues(Collection $socialIssues): Collection + { + $ancestors = new ArrayCollection(); + + foreach ($socialIssues as $candidateChild) { + if ($ancestors->contains($candidateChild)) { + continue; + } + + foreach ($socialIssues as $candidateParent) { + if ($ancestors->contains($candidateParent)) { + continue; + } + + if ($candidateChild->isDescendantOf($candidateParent)) { + $ancestors->add($candidateParent); + } + } + } + + return $ancestors; + } + + /** + * @return Collection|self[] + */ + public function getChildren(): Collection + { + return $this->children; + } + + public function getDesactivationDate(): ?DateTimeInterface + { + return $this->desactivationDate; + } + /** * @return Collection|self[] All the descendants (children, children of children, ...) */ @@ -115,10 +140,11 @@ class SocialIssue $descendants = new ArrayCollection(); foreach ($this->getChildren() as $child) { - if(! $descendants->contains($child)) { + if (!$descendants->contains($child)) { $descendants->add($child); - foreach($child->getDescendants() as $descendantsOfChild) { - if(! $descendants->contains($descendantsOfChild)) { + + foreach ($child->getDescendants() as $descendantsOfChild) { + if (!$descendants->contains($descendantsOfChild)) { $descendants->add($descendantsOfChild); } } @@ -128,6 +154,24 @@ class SocialIssue return $descendants; } + /** + * @return Collection|SocialAction[] All the descendant social actions of the entity + */ + public function getDescendantsSocialActions(): Collection + { + $descendantsSocialActions = new ArrayCollection(); + + foreach ($this->getSocialActions() as $socialAction) { + foreach ($socialAction->getDescendantsWithThis() as $descendant) { + if (!$descendantsSocialActions->contains($descendant)) { + $descendantsSocialActions->add($descendant); + } + } + } + + return $descendantsSocialActions; + } + /** * @return Collection|self[] All the descendants with the current entity (this) */ @@ -135,36 +179,40 @@ class SocialIssue { $descendants = $this->getDescendants(); - if(! $descendants->contains($this)) { + if (!$descendants->contains($this)) { $descendants->add($this); } return $descendants; } - - public function getDesactivationDate(): ?\DateTimeInterface + public function getId(): ?int { - return $this->desactivationDate; + return $this->id; } - public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self + public function getParent(): ?self { - $this->desactivationDate = $desactivationDate; - - return $this; + return $this->parent; } - public function getTitle(): array + /** + * @return Collection|SocialAction[] All the descendant social actions of all + * the descendants of the entity + */ + public function getRecursiveSocialActions(): Collection { - return $this->title; - } + $recursiveSocialActions = new ArrayCollection(); - public function setTitle(array $title): self - { - $this->title = $title; + foreach ($this->getDescendantsWithThis() as $socialIssue) { + foreach ($socialIssue->getDescendantsSocialActions() as $descendant) { + if (!$recursiveSocialActions->contains($descendant)) { + $recursiveSocialActions->add($descendant); + } + } + } - return $this; + return $recursiveSocialActions; } /** @@ -175,11 +223,40 @@ 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 hasParent(): bool + { + return null !== $this->parent; + } + + /** + * Recursive method which return true if the current $issue is a descendant + * of the $issue given in parameter. + */ + public function isDescendantOf(SocialIssue $issue): bool + { + if (!$this->hasParent()) { + return false; + } + + if ($this->getParent() === $issue) { + return true; + } + + return $this->getParent()->isDescendantOf($issue); + } + + 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; @@ -197,93 +274,24 @@ class SocialIssue return $this; } - /** - * @return Collection|SocialAction[] All the descendant social actions of the entity - */ - public function getDescendantsSocialActions(): Collection + public function setDesactivationDate(?DateTimeInterface $desactivationDate): self { - $descendantsSocialActions = new ArrayCollection(); + $this->desactivationDate = $desactivationDate; - foreach ($this->getSocialActions() as $socialAction) { - foreach ($socialAction->getDescendantsWithThis() as $descendant) { - if(! $descendantsSocialActions->contains($descendant)) { - $descendantsSocialActions->add($descendant); - } - } - } - - return $descendantsSocialActions; + return $this; } - /** - * @return Collection|SocialAction[] All the descendant social actions of all - * the descendants of the entity - */ - public function getRecursiveSocialActions(): Collection + public function setParent(?self $parent): self { - $recursiveSocialActions = new ArrayCollection(); + $this->parent = $parent; - foreach ($this->getDescendantsWithThis() as $socialIssue) { - foreach ($socialIssue->getDescendantsSocialActions() as $descendant) { - if(! $recursiveSocialActions->contains($descendant)) { - $recursiveSocialActions->add($descendant); - } - } - } - - return $recursiveSocialActions; + return $this; } - /** - * Recursive method which return true if the current $issue is a descendant - * of the $issue given in parameter. - * - * @param SocialIssue $issue - * @return bool - */ - public function isDescendantOf(SocialIssue $issue): bool + public function setTitle(array $title): self { - if (!$this->hasParent()) { - return false; - } + $this->title = $title; - if ($this->getParent() === $issue) { - return true; - } - - return $this->getParent()->isDescendantOf($issue); - } - - /** - * In a SocialIssues's collection, find the elements which are an ancestor of - * other elements. - * - * Removing those elements of the Collection (which is not done by this method) - * will ensure that only the most descendent elements are present in the collection, - * (any ancestor of another element are present). - * - * @param Collection|SocialIssue[] $socialIssues - * @return Collection|SocialIssue[] - */ - public static function findAncestorSocialIssues(Collection $socialIssues): Collection - { - $ancestors = new ArrayCollection(); - - foreach ($socialIssues as $candidateChild) { - if ($ancestors->contains($candidateChild)) { - continue; - } - foreach ($socialIssues as $candidateParent) { - if ($ancestors->contains($candidateParent)) { - continue; - } - - if ($candidateChild->isDescendantOf($candidateParent)) { - $ancestors->add($candidateParent); - } - } - } - - return $ancestors; + return $this; } } diff --git a/src/Bundle/ChillPersonBundle/EventListener/PersonEventListener.php b/src/Bundle/ChillPersonBundle/EventListener/PersonEventListener.php index 20855a166..393ed2096 100644 --- a/src/Bundle/ChillPersonBundle/EventListener/PersonEventListener.php +++ b/src/Bundle/ChillPersonBundle/EventListener/PersonEventListener.php @@ -1,17 +1,27 @@ getLabel(), 'UTF-8'); + $altname->setLabel($altnameCaps); + } + public function prePersistPerson(Person $person): void { $firstnameCaps = mb_convert_case(mb_strtolower($person->getFirstName()), MB_CASE_TITLE, 'UTF-8'); @@ -21,10 +31,4 @@ class PersonEventListener $lastnameCaps = mb_strtoupper($person->getLastName(), 'UTF-8'); $person->setLastName($lastnameCaps); } - - public function prePersistAltName(PersonAltName $altname) - { - $altnameCaps = mb_strtoupper($altname->getLabel(), 'UTF-8'); - $altname->setLabel($altnameCaps); - } } diff --git a/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php b/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php index c21d5733a..e12394ad1 100644 --- a/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php +++ b/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php @@ -1,59 +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\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 bd07d3a48..e72c1f977 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AgeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AgeAggregator.php @@ -1,28 +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\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\Contracts\Translation\TranslatorInterface; @@ -54,48 +45,47 @@ final class AgeAggregator implements AggregatorInterface, ExportElementValidated 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 aa2e56121..770812ce5 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.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\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 Chill\MainBundle\Repository\CountryRepository; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Util\CountriesInfo; +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; final class CountryOfBirthAggregator implements AggregatorInterface, ExportElementValidatedInterface { @@ -51,38 +39,17 @@ final class CountryOfBirthAggregator implements AggregatorInterface, ExportEleme $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\' ' @@ -95,24 +62,24 @@ final class CountryOfBirthAggregator implements AggregatorInterface, ExportEleme . '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 @@ -123,36 +90,37 @@ final class CountryOfBirthAggregator implements AggregatorInterface, ExportEleme } 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) { $labels = []; - 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 = [ @@ -160,13 +128,13 @@ final class CountryOfBirthAggregator implements AggregatorInterface, ExportEleme '_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']); } } - if ($data['group_by_level'] === 'continent') { - $labels = array( + if ('continent' === $data['group_by_level']) { + $labels = [ 'EU' => $this->translator->trans('Europe'), 'AS' => $this->translator->trans('Asia'), 'AN' => $this->translator->trans('Antartica'), @@ -175,13 +143,30 @@ final class CountryOfBirthAggregator implements AggregatorInterface, ExportEleme 'NA' => $this->translator->trans('North America'), 'OC' => $this->translator->trans('Oceania'), '' => $this->translator->trans('without data'), - '_header' => $this->translator->trans('Continent of birth') - ); + '_header' => $this->translator->trans('Continent of birth'), + ]; } - return function(string $value) use ($labels): string { + return function (string $value) use ($labels): string { 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 cd3c022d9..9e9e2cc26 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php @@ -1,30 +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\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; final class GenderAggregator implements AggregatorInterface { @@ -35,6 +26,18 @@ final class GenderAggregator implements AggregatorInterface $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; @@ -42,51 +45,40 @@ final class GenderAggregator implements AggregatorInterface 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 97e7d4e4a..d6c69b7bc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.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\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 Chill\MainBundle\Repository\CountryRepository; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Util\CountriesInfo; +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; final class NationalityAggregator implements AggregatorInterface, ExportElementValidatedInterface { @@ -51,39 +39,17 @@ final class NationalityAggregator implements AggregatorInterface, ExportElementV $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\' ' @@ -96,24 +62,24 @@ final class NationalityAggregator implements AggregatorInterface, ExportElementV . '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 @@ -124,36 +90,37 @@ final class NationalityAggregator implements AggregatorInterface, ExportElementV } 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) { $labels = []; - 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 = [ @@ -161,13 +128,13 @@ final class NationalityAggregator implements AggregatorInterface, ExportElementV '_header' => $this->translator->trans('Nationality'), ]; - foreach($countries as $row) { + foreach ($countries as $row) { $labels[$row['c_countryCode']] = $this->translatableStringHelper->localize($row['c_name']); } } - if ($data['group_by_level'] === 'continent') { - $labels = array( + if ('continent' === $data['group_by_level']) { + $labels = [ 'EU' => $this->translator->trans('Europe'), 'AS' => $this->translator->trans('Asia'), 'AN' => $this->translator->trans('Antartica'), @@ -175,14 +142,31 @@ final class NationalityAggregator implements AggregatorInterface, ExportElementV '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(string $value) use ($labels): string { + return function (string $value) use ($labels): string { 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..c621e8217 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -1,136 +1,113 @@ +/** + * 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 508905ba4..b949c5ebc 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -1,59 +1,73 @@ entityManager = $em; $this->translator = $translator; @@ -66,19 +80,18 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface $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' => static function(string $val): array { + 'label' => 'Fields to include in export', + 'choice_attr' => static function (string $val): array { // add a 'data-display-target' for address fields if (substr($val, 0, 8) === 'address_') { return ['data-display-target' => 'address_date']; @@ -86,76 +99,37 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface 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( - $this->fields, - static fn(string $el): bool => substr($el, 0, 8) === 'address_' - ); - - // 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 $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(); + 'block_name' => 'list_export_form_address_date', + ]); } public function getAllowedFormattersTypes() { - return array(FormatterInterface::TYPE_LIST); + return [FormatterInterface::TYPE_LIST]; } public function getDescription() { - return "Create a list of people according to various filters."; + return 'Create a list of people according to various filters.'; } public function getLabels($key, array $values, $data) @@ -164,63 +138,75 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface case 'birthdate': // for birthdate, we have to transform the string into a date // to format the date correctly. - return static function($value) { - if ($value === '_header') { return 'birthdate'; } - - if (empty($value)) - { - return ""; + return static 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 static function(?string $value): string { - if ($value === '_header') { + return static function (?string $value): string { + if ('_header' === $value) { return 'address.address_homeless'; } @@ -230,68 +216,26 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface return ''; }; + default: // for fields which are associated with person if (in_array($key, $this->fields)) { - return static function($value) use ($key) { - if ($value === '_header') { return \strtolower($key); } + return static function ($value) use ($key) { + if ('_header' === $value) { + return strtolower($key); + } return $value; - - }; + }; } 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); - } - - return $cfType->isChecked($cf, $slugChoice, $decoded); - }; - - } - - return $defaultFunction; } public function getQueryKeys($data) { - $fields = array(); + $fields = []; foreach ($data['fields'] as $key) { if (in_array($key, $this->fields)) { @@ -300,36 +244,7 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface } // add the key from slugs and return - return \array_merge($fields, \array_keys($this->slugs)); - } - - /** - * Clean a slug to be usable by DQL. - */ - private function slugToDQL(string $slug, string $type = "default", array $additionalInfos = []): string - { - $uid = 'slug_' . \uniqid('', true); - - $this->slugs[$uid] = [ - 'slug' => $slug, - 'type' => $type, - 'additionnalInfos' => $additionalInfos - ]; - - return $uid; - } - - private function DQLToSlug($cleanedSlug) - { - return $this->slugs[$cleanedSlug]['slug']; - } - - /** - * @return array An array with keys = 'slug', 'type', 'additionnalInfo' - */ - private function extractInfosFromSlug($slug): array - { - return $this->slugs[$slug]; + return array_merge($fields, array_keys($this->slugs)); } public function getResult($query, $data) @@ -339,7 +254,7 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface public function getTitle() { - return "List peoples"; + return 'List peoples'; } public function getType() @@ -347,14 +262,14 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface return Declarations::PERSON_TYPE; } - 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(); @@ -365,7 +280,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': @@ -374,14 +291,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)); } @@ -390,30 +309,37 @@ 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; } @@ -425,6 +351,117 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface 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( + $this->fields, + static fn (string $el): bool => substr($el, 0, 8) === 'address_' + ); + + // 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 array An array with keys = 'slug', 'type', 'additionnalInfo' + */ + private function extractInfosFromSlug($slug): array + { + 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); + }; + } + + return $defaultFunction; + } + + /** + * Clean a slug to be usable by DQL. + */ + private function slugToDQL(string $slug, string $type = 'default', array $additionalInfos = []): string + { + $uid = 'slug_' . uniqid('', true); + + $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 fbf59168c..68f613896 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\Types; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; +use DateTime; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; -/** - * - * - */ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface { public function addRole() @@ -41,7 +30,8 @@ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportEl $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'], Types::DATE_MUTABLE); @@ -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_from', ChillDateType::class, [ + '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_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 be732a028..c52f192d7 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\Types; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; +use DateTime; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; -/** - * - * - */ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface { public function addRole() @@ -43,13 +32,13 @@ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement i $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'], Types::DATE_MUTABLE); @@ -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_from', ChillDateType::class, [ + '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_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 6c81e6e65..a821cd3d3 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\Types; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; +use DateTime; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; -/** - * - * - */ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface { public function addRole() @@ -41,7 +30,8 @@ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportEl $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'], Types::DATE_MUTABLE); @@ -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_from', ChillDateType::class, [ + '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_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..93160690d 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php @@ -1,90 +1,52 @@ +/** + * 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; +use function array_filter; +use function implode; +use function in_array; -/** - * - * - * @author Julien Fastré - */ -class GenderFilter implements FilterInterface, +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 +59,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 +114,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/AccompanyingCourseType.php b/src/Bundle/ChillPersonBundle/Form/AccompanyingCourseType.php new file mode 100644 index 000000000..55d7f7c92 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/AccompanyingCourseType.php @@ -0,0 +1,33 @@ +add( + 'closingDate', + ChillDateType::class, + [ + 'required' => true, + ] + ); + + $builder->add('closingMotive', ClosingMotivePickerType::class); + } +} 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 db1d5c6f8..dd26e3cd9 100644 --- a/src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php +++ b/src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php @@ -1,56 +1,113 @@ +/** + * 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 Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Repository\PersonRepository; +use RuntimeException; +use Symfony\Component\Form\ChoiceList\ChoiceListInterface; +use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; +use function call_user_func; +use function in_array; /** - * Allow to load a list of person + * Allow to load a list of person. */ class PersonChoiceLoader implements ChoiceLoaderInterface { - protected PersonRepository $personRepository; - - protected array $lazyLoadedPersons = []; - protected array $centers = []; - + + protected array $lazyLoadedPersons = []; + + protected PersonRepository $personRepository; + /** * PersonChoiceLoader constructor. * * @param EntityRepository $personRepository - * @param array|null $centers */ public function __construct( PersonRepository $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 */ @@ -58,69 +115,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 704a6e47b..3d409129b 100644 --- a/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php +++ b/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php @@ -1,22 +1,29 @@ configPersonAltNamesHelper = $configPersonAltNamesHelper; $this->dispatcher = $dispatcher; $this->askCenters = $parameterBag->get('chill_main')['acl']['form_show_centers']; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder @@ -52,9 +55,9 @@ final class CreationPersonType extends AbstractType ->add('birthdate', ChillDateType::class, [ 'required' => false, ]) - ->add('gender', GenderType::class, array( - 'required' => true, 'placeholder' => null - )); + ->add('gender', GenderType::class, [ + 'required' => true, 'placeholder' => null, + ]); if ($this->askCenters) { $builder @@ -65,25 +68,22 @@ final class CreationPersonType extends AbstractType } if ($this->configPersonAltNamesHelper->hasAltNames()) { - $builder->add('altNames', PersonAltNameType::class, [ - 'by_reference' => false + $builder->add('altNames', PersonAltNameType::class, [ + 'by_reference' => false, ]); } $this->dispatcher->dispatch( - new CustomizeFormEvent(static::class, $builder), + new CustomizeFormEvent(self::class, $builder), CustomizeFormEvent::NAME ); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => Person::class - )); + $resolver->setDefaults([ + 'data_class' => Person::class, + ]); } /** diff --git a/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php b/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php index d1f50404b..aaa346893 100644 --- a/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php +++ b/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php @@ -1,17 +1,21 @@ 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 +56,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 +75,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 +85,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/HouseholdMemberType.php b/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php index 05a65c7d7..297a58a57 100644 --- a/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php +++ b/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php @@ -1,9 +1,16 @@ 'household.Start date', 'input' => 'datetime_immutable', ]); + if ($options['data']->getPosition()->isAllowHolder()) { $builder ->add('holder', ChoiceType::class, [ 'label' => 'household.holder', 'choices' => [ 'household.is holder' => true, - 'household.is not holder' => false - ] + 'household.is not holder' => false, + ], ]); } $builder ->add('comment', ChillTextareaType::class, [ 'label' => 'household.Comment', - 'required' => false - ]) - ; - } + 'required' => false, + ]); + } } diff --git a/src/Bundle/ChillPersonBundle/Form/HouseholdType.php b/src/Bundle/ChillPersonBundle/Form/HouseholdType.php index 999e2ff79..d628ab47f 100644 --- a/src/Bundle/ChillPersonBundle/Form/HouseholdType.php +++ b/src/Bundle/ChillPersonBundle/Form/HouseholdType.php @@ -1,12 +1,19 @@ add('commentMembers', CommentType::class, [ 'label' => 'household.comment_membership', - 'required' => false + 'required' => false, ]) ->add('waitingForBirth', CheckboxType::class, [ 'required' => false, - 'label' => 'household.expecting_birth' + 'label' => 'household.expecting_birth', ]) ->add('waitingForBirthDate', ChillDateType::class, [ 'required' => false, 'label' => 'household.date_expecting_birth', - 'input' => 'datetime_immutable' - ]) - ; + 'input' => 'datetime_immutable', + ]); } public function configureOptions(OptionsResolver $resolver) 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 664bfe15d..2f2ab79a5 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; @@ -24,29 +12,29 @@ namespace Chill\PersonBundle\Form; use Chill\CustomFieldsBundle\Form\Type\CustomFieldType; use Chill\MainBundle\Entity\Civility; use Chill\MainBundle\Form\Type\ChillCollectionType; +use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillTextareaType; +use Chill\MainBundle\Form\Type\CommentType; use Chill\MainBundle\Form\Type\Select2CountryType; use Chill\MainBundle\Form\Type\Select2LanguageType; +use Chill\MainBundle\Templating\TranslatableStringHelper; 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 Chill\MainBundle\Form\Type\ChillDateType; -use Chill\MainBundle\Form\Type\CommentType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackTransformer; -use Symfony\Component\Form\Extension\Core\Type\EmailType; -use Symfony\Component\Form\Extension\Core\Type\TelType; -use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\EmailType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\TelType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -60,10 +48,9 @@ class PersonType extends AbstractType * * @var string[] */ - protected $config = array(); + protected $config = []; /** - * * @var ConfigPersonAltNamesHelper */ protected $configAltNamesHelper; @@ -71,7 +58,6 @@ class PersonType extends AbstractType protected TranslatableStringHelper $translatableStringHelper; /** - * * @param string[] $personFieldsConfiguration configuration of visibility of some fields */ public function __construct( @@ -84,10 +70,6 @@ class PersonType extends AbstractType $this->translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder @@ -99,35 +81,34 @@ class PersonType extends AbstractType ->add('deathdate', DateType::class, [ 'required' => false, 'input' => 'datetime_immutable', - 'widget' => 'single_text' + 'widget' => 'single_text', ]) - ->add('gender', GenderType::class, array( - 'required' => true - )) - ->add('genderComment', CommentType::class, array( - 'required' => false - )) - ->add('numberOfChildren', IntegerType::class, array( - 'required' => false - )); + ->add('gender', GenderType::class, [ + 'required' => true, + ]) + ->add('genderComment', CommentType::class, [ + 'required' => false, + ]) + ->add('numberOfChildren', IntegerType::class, [ + 'required' => false, + ]); 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( + if ('visible' === $this->config['place_of_birth']) { + $builder->add('placeOfBirth', TextType::class, [ 'required' => false, 'attr' => ['style' => 'text-transform: uppercase;'], - )); + ]); $builder->get('placeOfBirth')->addModelTransformer(new CallbackTransformer( function ($string) { @@ -136,26 +117,26 @@ class PersonType extends AbstractType function ($string) { return strtoupper($string); } - )); - } - - if ($this->config['contact_info'] === 'visible') { - $builder->add('contactInfo', ChillTextareaType::class, array('required' => false)); - } - - if ($this->config['phonenumber'] === 'visible') { - $builder->add('phonenumber', TelType::class, array( - 'required' => false, - // 'placeholder' => '+33623124554' //TODO placeholder for phone numbers )); } - if ($this->config['mobilenumber'] === 'visible') { + if ('visible' === $this->config['contact_info']) { + $builder->add('contactInfo', ChillTextareaType::class, ['required' => false]); + } + + if ('visible' === $this->config['phonenumber']) { + $builder->add('phonenumber', TelType::class, [ + 'required' => false, + // 'placeholder' => '+33623124554' //TODO placeholder for phone numbers + ]); + } + + if ('visible' === $this->config['mobilenumber']) { $builder - ->add('mobilenumber', TelType::class, array('required' => false)) - ->add('acceptSMS', CheckboxType::class, array( - 'required' => false - )); + ->add('mobilenumber', TelType::class, ['required' => false]) + ->add('acceptSMS', CheckboxType::class, [ + 'required' => false, + ]); } $builder->add('otherPhoneNumbers', ChillCollectionType::class, [ @@ -167,43 +148,43 @@ 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, - 'empty_collection_explain' => 'No additional phone numbers' + 'empty_collection_explain' => 'No additional phone numbers', ]); - if ($this->config['email'] === 'visible') { + if ('visible' === $this->config['email']) { $builder - ->add('email', EmailType::class, array('required' => false)); + ->add('email', EmailType::class, ['required' => false]); } - if ($this->config['acceptEmail'] === 'visible') { + if ('visible' === $this->config['acceptEmail']) { $builder - ->add('acceptEmail', CheckboxType::class, array('required' => false)); + ->add('acceptEmail', CheckboxType::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['civility'] === 'visible'){ + if ('visible' === $this->config['nationality']) { + $builder->add('nationality', Select2CountryType::class, [ + 'required' => false, + ]); + } + + if ('visible' === $this->config['spoken_languages']) { + $builder->add('spokenLanguages', Select2LanguageType::class, [ + 'required' => false, + 'multiple' => true, + ]); + } + + if ('visible' === $this->config['civility']) { $builder ->add('civility', EntityType::class, [ 'label' => 'Civility', @@ -216,30 +197,31 @@ class PersonType extends AbstractType ->where('c.active = true'); }, 'placeholder' => 'choose civility', - 'required' => false + 'required' => false, ]); } - if ($this->config['marital_status'] === 'visible'){ + if ('visible' === $this->config['marital_status']) { $builder - ->add('maritalStatus', Select2MaritalStatusType::class, array( - 'required' => false - )) - ->add('maritalStatusDate', ChillDateType::class, array( - 'required' => false - )) - ->add('maritalStatusComment', CommentType::class, array( - 'required' => false - )); + ->add('maritalStatus', Select2MaritalStatusType::class, [ + 'required' => false, + ]) + ->add('maritalStatusDate', ChillDateType::class, [ + 'required' => false, + ]) + ->add('maritalStatusComment', CommentType::class, [ + 'required' => false, + ]); } - if($options['cFGroup']) { + 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']] + ); } - } /** @@ -247,17 +229,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/SocialWork/EvaluationType.php b/src/Bundle/ChillPersonBundle/Form/SocialWork/EvaluationType.php index b45cd327e..a23a065d7 100644 --- a/src/Bundle/ChillPersonBundle/Form/SocialWork/EvaluationType.php +++ b/src/Bundle/ChillPersonBundle/Form/SocialWork/EvaluationType.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\PersonBundle\Form\SocialWork; +use Chill\MainBundle\Form\Type\TranslatableStringFormType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Entity\SocialWork\Evaluation; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Form\Type\TranslatableStringFormType; -use Symfony\Component\Form\Extension\Core\Type\DateType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\PersonBundle\Entity\SocialWork\Evaluation; /** - * Class EvaluationType - * - * @package Chill\PersonBundle\Form + * Class EvaluationType. */ class EvaluationType extends AbstractType { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper) { + public function __construct(TranslatableStringHelper $translatableStringHelper) + { $this->translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder @@ -59,13 +42,9 @@ class EvaluationType extends AbstractType ->add('notificationDelay'); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { $resolver - ->setDefault('class', Evaluation::class) - ; + ->setDefault('class', Evaluation::class); } } diff --git a/src/Bundle/ChillPersonBundle/Form/SocialWork/GoalType.php b/src/Bundle/ChillPersonBundle/Form/SocialWork/GoalType.php index c86a7d6b9..bd5c03584 100644 --- a/src/Bundle/ChillPersonBundle/Form/SocialWork/GoalType.php +++ b/src/Bundle/ChillPersonBundle/Form/SocialWork/GoalType.php @@ -1,85 +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 . - */ -namespace Chill\PersonBundle\Form\SocialWork; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Form\Type\TranslatableStringFormType; -use Symfony\Component\Form\Extension\Core\Type\DateType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\PersonBundle\Entity\SocialWork\Goal; -use Chill\PersonBundle\Entity\SocialWork\SocialAction; /** - * Class GoalType + * 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\SocialWork; + +use Chill\MainBundle\Form\Type\TranslatableStringFormType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Entity\SocialWork\Goal; +use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * Class GoalType. */ class GoalType extends AbstractType { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper) { + public function __construct(TranslatableStringHelper $translatableStringHelper) + { $this->translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('title', TranslatableStringFormType::class, [ - 'label' => 'Nom' + 'label' => 'Nom', ]) ->add('socialActions', EntityType::class, [ 'class' => SocialAction::class, - 'required' => false, + 'required' => false, 'multiple' => true, 'choice_label' => function (SocialAction $issue) { return $this->translatableStringHelper->localize($issue->getTitle()); - } + }, ]) ->add('desactivationDate', DateType::class, [ - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', 'required' => false, ]); -} + } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { $resolver - ->setDefault('class', Goal::class) - ; + ->setDefault('class', Goal::class); } } diff --git a/src/Bundle/ChillPersonBundle/Form/SocialWork/ResultType.php b/src/Bundle/ChillPersonBundle/Form/SocialWork/ResultType.php index ee2cefe48..85f240792 100644 --- a/src/Bundle/ChillPersonBundle/Form/SocialWork/ResultType.php +++ b/src/Bundle/ChillPersonBundle/Form/SocialWork/ResultType.php @@ -1,76 +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\PersonBundle\Form\SocialWork; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Form\Type\TranslatableStringFormType; -use Symfony\Component\Form\Extension\Core\Type\DateType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\PersonBundle\Entity\SocialWork\Result; /** - * Class ResultType + * 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\SocialWork; + +use Chill\MainBundle\Form\Type\TranslatableStringFormType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Entity\SocialWork\Result; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * Class ResultType. */ class ResultType extends AbstractType { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper) { + public function __construct(TranslatableStringHelper $translatableStringHelper) + { $this->translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('title', TranslatableStringFormType::class, [ - 'label' => 'Nom' + 'label' => 'Nom', ]) ->add('accompanyingPeriodWorks') ->add('accompanyingPeriodWorkGoals') ->add('desactivationDate', DateType::class, [ - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', 'required' => false, ]); -} + } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { $resolver - ->setDefault('class', Result::class) - ; + ->setDefault('class', Result::class); } } diff --git a/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialActionType.php b/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialActionType.php index 7613bc2c7..9f340de46 100644 --- a/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialActionType.php +++ b/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialActionType.php @@ -1,90 +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 . - */ -namespace Chill\PersonBundle\Form\SocialWork; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Form\Type\TranslatableStringFormType; -use Symfony\Component\Form\Extension\Core\Type\DateType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\PersonBundle\Entity\SocialWork\SocialAction; -use Chill\PersonBundle\Entity\SocialWork\SocialIssue; - /** - * Class SocialActionType + * 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\SocialWork; + +use Chill\MainBundle\Form\Type\TranslatableStringFormType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Chill\PersonBundle\Entity\SocialWork\SocialIssue; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * Class SocialActionType. */ class SocialActionType extends AbstractType { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper) { + public function __construct(TranslatableStringHelper $translatableStringHelper) + { $this->translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('title', TranslatableStringFormType::class, [ - 'label' => 'Nom' + 'label' => 'Nom', ]) ->add('issue', EntityType::class, [ 'class' => SocialIssue::class, 'choice_label' => function (SocialIssue $issue) { return $this->translatableStringHelper->localize($issue->getTitle()); - } + }, ]) ->add('parent', EntityType::class, [ 'class' => SocialAction::class, - 'required' => false, + 'required' => false, 'choice_label' => function (SocialAction $issue) { return $this->translatableStringHelper->localize($issue->getTitle()); - } + }, ]) ->add('defaultNotificationDelay') ->add('desactivationDate', DateType::class, [ - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', 'required' => false, ]); -} + } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { $resolver - ->setDefault('class', SocialIssue::class) - ; + ->setDefault('class', SocialIssue::class); } } diff --git a/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php b/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php index 430514d21..0058b1e51 100644 --- a/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php +++ b/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php @@ -1,17 +1,24 @@ add('title', TranslatableStringFormType::class, [ - 'label' => 'Nom' + 'label' => 'Nom', ]) ->add('parent', EntityType::class, [ 'class' => SocialIssue::class, - 'required' => false, - 'choice_label' => fn (SocialIssue $issue): ?string => $this->translatableStringHelper->localize($issue->getTitle()) + 'required' => false, + 'choice_label' => fn (SocialIssue $issue): ?string => $this->translatableStringHelper->localize($issue->getTitle()), ]) ->add('desactivationDate', DateType::class, [ - 'attr' => ['class' => 'datepicker'], - 'widget'=> 'single_text', + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', 'required' => false, ]); 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 5cad3b4f1..0949fce0b 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/GenderType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/GenderType.php @@ -1,38 +1,43 @@ 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, - )); + ]); } + 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..422a372db 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,74 @@ 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 34fd9897e..dcd7b9075 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/Select2MaritalStatusType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/Select2MaritalStatusType.php @@ -1,40 +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\PersonBundle\Form\Type; +use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer; +use Chill\MainBundle\Form\Type\Select2ChoiceType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\MaritalStatus; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer; 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 { @@ -48,24 +33,16 @@ class Select2MaritalStatusType extends AbstractType $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); } public function configureOptions(OptionsResolver $resolver) { $maritalStatuses = $this->em->getRepository('Chill\PersonBundle\Entity\MaritalStatus')->findAll(); - $choices = array(); + $choices = []; foreach ($maritalStatuses as $ms) { $choices[$ms->getId()] = $this->translatableStringHelper->localize($ms->getName()); @@ -73,9 +50,19 @@ class Select2MaritalStatusType extends AbstractType asort($choices, SORT_STRING | SORT_FLAG_CASE); - $resolver->setDefaults(array( - 'class' => MaritalStatus::class, - 'choices' => array_combine(array_values($choices),array_keys($choices)) - )); + $resolver->setDefaults([ + 'class' => MaritalStatus::class, + '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/Household/MembersEditor.php b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php index f718bb8a9..2a5254889 100644 --- a/src/Bundle/ChillPersonBundle/Household/MembersEditor.php +++ b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php @@ -1,28 +1,42 @@ household = $household; } - public function addMovement(\DateTimeImmutable $date, Person $person, Position $position, ?bool $holder = false, ?string $comment = null): self + public function addMovement(DateTimeImmutable $date, Person $person, Position $position, ?bool $holder = false, ?string $comment = null): self { - if (NULL === $this->household) { - throw new \LogicException("You must define a household first"); + if (null === $this->household) { + throw new LogicException('You must define a household first'); } $membership = (new HouseholdMember()) @@ -41,8 +55,7 @@ class MembersEditor ->setPerson($person) ->setPosition($position) ->setHolder($holder) - ->setComment($comment) - ; + ->setComment($comment); $this->household->addMember($membership); if ($position->getShareHousehold()) { @@ -55,10 +68,10 @@ class MembersEditor continue; } - if ($participation->getEndDate() === NULL || $participation->getEndDate() > $date) { + if ($participation->getEndDate() === null || $participation->getEndDate() > $date) { $participation->setEndDate($date); $this->membershipsAffected[] = $participation; - $this->oldMembershipsHashes[] = \spl_object_hash($participation); + $this->oldMembershipsHashes[] = spl_object_hash($participation); } } } @@ -69,8 +82,23 @@ class MembersEditor return $this; } + public function getHousehold(): ?Household + { + return $this->household; + } + + public function getPersistable(): array + { + return $this->persistables; + } + + public function hasHousehold(): bool + { + return null !== $this->household; + } + public function leaveMovement( - \DateTimeImmutable $date, + DateTimeImmutable $date, Person $person ): self { $criteria = new Criteria(); @@ -84,8 +112,7 @@ class MembersEditor ); $participations = $person->getHouseholdParticipations() - ->matching($criteria) - ; + ->matching($criteria); foreach ($participations as $participation) { $participation->setEndDate($date); @@ -95,41 +122,24 @@ class MembersEditor return $this; } - public function validate(): ConstraintViolationListInterface { if ($this->hasHousehold()) { $list = $this->validator - ->validate($this->getHousehold(), null, [ self::VALIDATION_GROUP_AFFECTED ]); + ->validate($this->getHousehold(), null, [self::VALIDATION_GROUP_AFFECTED]); } else { $list = new ConstraintViolationList(); } foreach ($this->membershipsAffected as $m) { - if (\in_array(\spl_object_hash($m), $this->oldMembershipsHashes)) { - $list->addAll($this->validator->validate($m, null, [ self::VALIDATION_GROUP_AFFECTED ])); + if (in_array(spl_object_hash($m), $this->oldMembershipsHashes)) { + $list->addAll($this->validator->validate($m, null, [self::VALIDATION_GROUP_AFFECTED])); } else { - $list->addAll($this->validator->validate($m, null, [ self::VALIDATION_GROUP_CREATED, - self::VALIDATION_GROUP_AFFECTED ])); + $list->addAll($this->validator->validate($m, null, [self::VALIDATION_GROUP_CREATED, + self::VALIDATION_GROUP_AFFECTED, ])); } } return $list; } - - public function getPersistable(): array - { - return $this->persistables; - } - - - public function getHousehold(): ?Household - { - return $this->household; - } - - public function hasHousehold(): bool - { - return $this->household !== null; - } } diff --git a/src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php b/src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php index adf55277e..884209136 100644 --- a/src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php +++ b/src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php @@ -1,12 +1,17 @@ translator = $translator; - } - - public static function getMenuIds(): array - { - return [ 'accompanyingCourse' ]; + $this->registry = $registry; } public function buildMenu($menuId, MenuItem $menu, array $parameters): void { + /** @var AccompanyingPeriod $period */ $period = $parameters['accompanyingCourse']; $menu->addChild($this->translator->trans('Resume Accompanying Course'), [ 'route' => 'chill_person_accompanying_course_index', 'routeParameters' => [ - 'accompanying_period_id' => $period->getId() - ]]) - ->setExtras(['order' => 10]); + 'accompanying_period_id' => $period->getId(), + ], ]) + ->setExtras(['order' => 10]); $menu->addChild($this->translator->trans('Edit Accompanying Course'), [ 'route' => 'chill_person_accompanying_course_edit', 'routeParameters' => [ - 'accompanying_period_id' => $period->getId() - ]]) - ->setExtras(['order' => 20]); + 'accompanying_period_id' => $period->getId(), + ], ]) + ->setExtras(['order' => 20]); if (AccompanyingPeriod::STEP_DRAFT === $period->getStep()) { // no more menu items if the period is draft @@ -57,17 +60,31 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface $menu->addChild($this->translator->trans('Accompanying Course History'), [ 'route' => 'chill_person_accompanying_course_history', 'routeParameters' => [ - 'accompanying_period_id' => $period->getId() - ]]) - ->setExtras(['order' => 30]); + 'accompanying_period_id' => $period->getId(), + ], ]) + ->setExtras(['order' => 30]); $menu->addChild($this->translator->trans('Accompanying Course Action'), [ 'route' => 'chill_person_accompanying_period_work_list', 'routeParameters' => [ - 'id' => $period->getId() - ]]) - ->setExtras(['order' => 40]); + 'id' => $period->getId(), + ], ]) + ->setExtras(['order' => 40]); + + $workflow = $this->registry->get($period, 'accompanying_period_lifecycle'); + + if ($workflow->can($period, 'close')) { + $menu->addChild($this->translator->trans('Close Accompanying Course'), [ + 'route' => 'chill_person_accompanying_course_close', + 'routeParameters' => [ + 'accompanying_period_id' => $period->getId(), + ], ]) + ->setExtras(['order' => 99999]); + } } - + 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/HouseholdMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php index c6a76445d..7a2712be3 100644 --- a/src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/HouseholdMenuBuilder.php @@ -1,15 +1,20 @@ translator = $translator; } - public static function getMenuIds(): array - { - return [ 'household' ]; - } - public function buildMenu($menuId, MenuItem $menu, array $parameters): void { $household = $parameters['household']; @@ -32,32 +32,34 @@ class HouseholdMenuBuilder implements LocalMenuBuilderInterface $menu->addChild($this->translator->trans('household.Household summary'), [ 'route' => 'chill_person_household_summary', 'routeParameters' => [ - 'household_id' => $household->getId() - ]]) - ->setExtras(['order' => 10]); + 'household_id' => $household->getId(), + ], ]) + ->setExtras(['order' => 10]); $menu->addChild($this->translator->trans('household.Accompanying period'), [ 'route' => 'chill_person_household_accompanying_period', 'routeParameters' => [ - 'household_id' => $household->getId() - ]]) - ->setExtras(['order' => 20]); + 'household_id' => $household->getId(), + ], ]) + ->setExtras(['order' => 20]); $menu->addChild($this->translator->trans('household.Addresses'), [ 'route' => 'chill_person_household_addresses', 'routeParameters' => [ - 'household_id' => $household->getId() - ]]) - ->setExtras(['order' => 30]); + 'household_id' => $household->getId(), + ], ]) + ->setExtras(['order' => 30]); $menu->addChild($this->translator->trans('household.Relationship'), [ 'route' => 'chill_person_household_relationship', 'routeParameters' => [ - 'household_id' => $household->getId() - ]]) + 'household_id' => $household->getId(), + ], ]) ->setExtras(['order' => 40]); - } - + public static function getMenuIds(): array + { + return ['household']; + } } diff --git a/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php index 0c83d8a6a..3de6d6323 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; @@ -31,18 +23,15 @@ use Symfony\Contracts\Translation\TranslatorInterface; * * - person details ; * - accompanying period (if `visible`) - * */ class PersonMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var string 'visible' or 'hidden' */ protected $showAccompanyingPeriod; /** - * * @var TranslatorInterface */ protected $translator; @@ -62,52 +51,52 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface 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('household.person history'), [ - 'route' => 'chill_person_household_person_history', - 'routeParameters' => [ - 'person_id' => $parameters['person']->getId() - ] + 'route' => 'chill_person_household_person_history', + 'routeParameters' => [ + 'person_id' => $parameters['person']->getId(), + ], ]) - ->setExtras([ - 'order' => 99999 - ]); + ->setExtras([ + 'order' => 99999, + ]); $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' => 99999 - ]); + ->setExtras([ + 'order' => 99999, + ]); - if ($this->showAccompanyingPeriod === 'visible' + if ('visible' === $this->showAccompanyingPeriod && $this->security->isGranted(AccompanyingPeriodVoter::SEE, $parameters['person']) ) { $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 0b307204d..52e2205e4 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,55 +24,47 @@ 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'], ]); } $menu->addChild($this->translator->trans('Create an accompanying course'), [ - 'route' => 'chill_person_accompanying_course_new' - ]) + 'route' => 'chill_person_accompanying_course_new', + ]) ->setExtras([ 'order' => 11, - 'icons' => [ 'plus' ] + 'icons' => ['plus'], ]); } - - /** - * @return array - */ + public static function getMenuIds(): array { - return [ 'section' ]; + return ['section']; } } diff --git a/src/Bundle/ChillPersonBundle/Notification/AccompanyingPeriodNotificationRenderer.php b/src/Bundle/ChillPersonBundle/Notification/AccompanyingPeriodNotificationRenderer.php index ca76fbd5c..fb3bd070b 100644 --- a/src/Bundle/ChillPersonBundle/Notification/AccompanyingPeriodNotificationRenderer.php +++ b/src/Bundle/ChillPersonBundle/Notification/AccompanyingPeriodNotificationRenderer.php @@ -1,5 +1,12 @@ getRelatedEntityClass() == AccompanyingPeriod::class; - } - public function getTemplate() { return 'ChillPersonBundle:AccompanyingPeriod:showInNotification.html.twig'; @@ -21,4 +23,9 @@ final class AccompanyingPeriodNotificationRenderer { return ['notification' => $notification]; } + + public function supports(Notification $notification) + { + return $notification->getRelatedEntityClass() == AccompanyingPeriod::class; + } } 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..958b8424f 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 +49,6 @@ class PrivacyEventSubscriber implements EventSubscriberInterface /** * PrivacyEventSubscriber constructor. - * - * @param LoggerInterface $logger */ public function __construct(LoggerInterface $logger, TokenStorageInterface $token) { @@ -56,11 +60,11 @@ class PrivacyEventSubscriber implements EventSubscriberInterface { return [ PrivacyEvent::PERSON_PRIVACY_EVENT => [ - ['onPrivacyEvent'] + ['onPrivacyEvent'], ], AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT => [ - ['onAccompanyingPeriodPrivacyEvent'] - ] + ['onAccompanyingPeriodPrivacyEvent'], + ], ]; } @@ -69,11 +73,11 @@ 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 +96,14 @@ 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 d9fa5b6e3..4c0dd3fc4 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkGoalRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkGoalRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(AccompanyingPeriodWork::class); } + public function countByAccompanyingPeriod(AccompanyingPeriod $period): int + { + return $this->repository->countByAccompanyingPeriod($period); + } + + public function countBySocialActionWithDescendants(SocialAction $action): int + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('COUNT(g)'); + + return $qb + ->getQuery() + ->getSingleScalarResult(); + } + public function find($id): ?AccompanyingPeriodWork { return $this->repository->find($id); @@ -34,6 +56,18 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } + /** + * @param mixed|null $orderBy + * @param mixed|null $limit + * @param mixed|null $offset + * + * @return AccompanyingPeriodWork[] + */ + public function findByAccompanyingPeriod(AccompanyingPeriod $period, $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset); + } + public function findOneBy(array $criteria): ?AccompanyingPeriodWork { return $this->repository->findOneBy($criteria); @@ -44,49 +78,23 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository return AccompanyingPeriodWork::class; } - /** - * - * @return AccompanyingPeriodWork[] - */ - public function findByAccompanyingPeriod(AccompanyingPeriod $period, $orderBy = null, $limit = null, $offset = null): array - { - return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset); - } - - public function countByAccompanyingPeriod(AccompanyingPeriod $period): int - { - return $this->repository->countByAccompanyingPeriod($period); - } - public function toDelete() { $qb = $this->buildQueryBySocialActionWithDescendants($action); $qb->select('g'); foreach ($orderBy as $sort => $order) { - $qb->addOrderBy('g.'.$sort, $order); + $qb->addOrderBy('g.' . $sort, $order); } return $qb ->setMaxResults($limit) ->setFirstResult($offset) ->getQuery() - ->getResult() - ; + ->getResult(); } - public function countBySocialActionWithDescendants(SocialAction $action): int - { - $qb = $this->buildQueryBySocialActionWithDescendants($action); - $qb->select('COUNT(g)'); - - return $qb - ->getQuery() - ->getSingleScalarResult() - ; - } - - protected function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder + private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder { $actions = $action->getDescendantsWithThis(); @@ -94,6 +102,7 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository $orx = $qb->expr()->orX(); $i = 0; + foreach ($actions as $action) { $orx->add(":action_{$i} MEMBER OF g.socialActions"); $qb->setParameter("action_{$i}", $action); diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ClosingMotiveRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ClosingMotiveRepository.php index 5c1525b52..0b6eff3c2 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ClosingMotiveRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ClosingMotiveRepository.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; @@ -29,10 +16,10 @@ use Doctrine\ORM\Query\ResultSetMappingBuilder; final class ClosingMotiveRepository { - private EntityRepository $repository; - private EntityManagerInterface $entityManager; + private EntityRepository $repository; + public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; @@ -47,18 +34,18 @@ final class ClosingMotiveRepository $rsm = new ResultSetMappingBuilder($this->entityManager); $rsm->addRootEntityFromClassMetadata($this->repository->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 ->entityManager diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php index b3a20780e..05e7c19e8 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; diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php index 596bfc2ee..9392180e2 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; diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php index 3923126aa..339258e70 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php @@ -1,30 +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\Repository\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; final class ResourceRepository { diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepository.php index c8cca82f5..f2e4af721 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepository.php @@ -1,9 +1,18 @@ accompanyingPeriodRepository = $accompanyingPeriodRepository; $this->security = $security; $this->authorizationHelper = $authorizationHelper; @@ -27,13 +43,16 @@ final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodAC Person $person, string $role, ?array $orderBy = [], - int $limit = null, - int $offset = null + ?int $limit = null, + ?int $offset = null ): array { $qb = $this->accompanyingPeriodRepository->createQueryBuilder('ap'); $scopes = $this->authorizationHelper - ->getReachableCircles($this->security->getUser(), $role, - $this->centerResolverDispatcher->resolveCenter($person)); + ->getReachableCircles( + $this->security->getUser(), + $role, + $this->centerResolverDispatcher->resolveCenter($person) + ); if (0 === count($scopes)) { return []; @@ -57,20 +76,18 @@ final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodAC ->setParameter('draft', AccompanyingPeriod::STEP_DRAFT) ->setParameter('person', $person) ->setParameter('user', $this->security->getUser()) - ->setParameter('creator', $this->security->getUser()) - ; + ->setParameter('creator', $this->security->getUser()); // add join condition for scopes $orx = $qb->expr()->orX( $qb->expr()->eq('ap.step', ':draft') ); foreach ($scopes as $key => $scope) { - $orx->add($qb->expr()->isMemberOf(':scope_'.$key, 'ap.scopes')); - $qb->setParameter('scope_'.$key, $scope); + $orx->add($qb->expr()->isMemberOf(':scope_' . $key, 'ap.scopes')); + $qb->setParameter('scope_' . $key, $scope); } $qb->andWhere($orx); return $qb->getQuery()->getResult(); } - } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepositoryInterface.php index a5798d3e8..655b3792e 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodACLAwareRepositoryInterface.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; diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php index c9e8397a8..d6ad39d57 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.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; @@ -36,6 +23,12 @@ final class AccompanyingPeriodRepository implements ObjectRepository { $this->repository = $entityManager->getRepository(AccompanyingPeriod::class); } + + public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder + { + return $this->repository->createQueryBuilder($alias, $indexBy); + } + public function find($id): ?AccompanyingPeriod { return $this->repository->find($id); @@ -59,11 +52,6 @@ final class AccompanyingPeriodRepository implements ObjectRepository return $this->findOneBy($criteria); } - public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder - { - return $this->repository->createQueryBuilder($alias, $indexBy); - } - public function getClassName() { return AccompanyingPeriod::class; diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php index 38236df14..f06812986 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php @@ -1,22 +1,29 @@ security = $security; } + public function addACL(QueryBuilder $qb, string $alias = 'h'): QueryBuilder + { + $centers = $this->authorizationHelper->getReachableCenters( + $this->security->getUser(), + HouseholdVoter::SHOW + ); + + if ([] === $centers) { + return $qb + ->andWhere("'FALSE' = 'TRUE'"); + } + + $qb + ->join($alias . '.members', 'members') + ->join('members.person', 'person') + ->andWhere( + $qb->expr()->in('person.center', ':centers') + ) + ->setParameter('centers', $centers); + + return $qb; + } + + public function buildQueryByAddressReference(AddressReference $addressReference): QueryBuilder + { + $qb = $this->em->createQueryBuilder(); + $qb + ->select('h') + ->from(Household::class, 'h') + ->join('h.addresses', 'address') + ->where( + $qb->expr()->eq('address.addressReference', ':reference') + ) + ->setParameter(':reference', $addressReference) + ->andWhere( + $qb->expr()->andX( + $qb->expr()->lte('address.validFrom', ':today'), + $qb->expr()->orX( + $qb->expr()->isNull('address.validTo'), + $qb->expr()->gt('address.validTo', ':today') + ) + ) + ) + ->setParameter('today', new DateTime('today')); + + return $qb; + } + public function countByAddressReference(AddressReference $addressReference): int { $qb = $this->buildQueryByAddressReference($addressReference); @@ -51,53 +106,4 @@ final class HouseholdACLAwareRepository implements HouseholdACLAwareRepositoryIn ->getQuery() ->getResult(); } - - public function buildQueryByAddressReference(AddressReference $addressReference): QueryBuilder - { - $qb = $this->em->createQueryBuilder(); - $qb - ->select('h') - ->from(Household::class, 'h') - ->join('h.addresses', 'address') - ->where( - $qb->expr()->eq('address.addressReference', ':reference') - ) - ->setParameter(':reference', $addressReference) - ->andWhere( - $qb->expr()->andX( - $qb->expr()->lte('address.validFrom', ':today'), - $qb->expr()->orX( - $qb->expr()->isNull('address.validTo'), - $qb->expr()->gt('address.validTo', ':today') - ) - ) - ) - ->setParameter('today', new \DateTime('today')) - ; - - return $qb; - } - - public function addACL(QueryBuilder $qb, string $alias = 'h'): QueryBuilder - { - $centers = $this->authorizationHelper->getReachableCenters( - $this->security->getUser(), - HouseholdVoter::SHOW - ); - - if ([] === $centers) { - return $qb - ->andWhere("'FALSE' = 'TRUE'"); - } - - $qb - ->join($alias.'.members', 'members') - ->join('members.person', 'person') - ->andWhere( - $qb->expr()->in('person.center', ':centers') - ) - ->setParameter('centers', $centers); - - return $qb; - } } diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepositoryInterface.php index 56a927ae5..1323361ee 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepositoryInterface.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(Household::class); $this->em = $entityManager; } + public function countByAccompanyingPeriodParticipation(Person $person) + { + return $this->buildQueryByAccompanyingPeriodParticipation($person, true); + } + public function find($id) { return $this->repository->find($id); @@ -35,6 +69,11 @@ final class HouseholdRepository implements ObjectRepository return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } + public function findByAccompanyingPeriodParticipation(Person $person, int $limit, int $offset) + { + return $this->buildQueryByAccompanyingPeriodParticipation($person, false, $limit, $offset); + } + public function findOneBy(array $criteria) { return $this->findOneBy($criteria); @@ -45,16 +84,6 @@ final class HouseholdRepository implements ObjectRepository return Household::class; } - public function countByAccompanyingPeriodParticipation(Person $person) - { - return $this->buildQueryByAccompanyingPeriodParticipation($person, true); - } - - public function findByAccompanyingPeriodParticipation(Person $person, int $limit, int $offset) - { - return $this->buildQueryByAccompanyingPeriodParticipation($person, false, $limit, $offset); - } - private function buildQueryByAccompanyingPeriodParticipation(Person $person, bool $isCount = false, int $limit = 50, int $offset = 0) { $rsm = new ResultSetMappingBuilder($this->em); @@ -62,14 +91,14 @@ final class HouseholdRepository implements ObjectRepository if ($isCount) { $rsm->addScalarResult('count', 'count'); - $sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [ + $sql = strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [ '{select}' => 'COUNT(households.*) AS count', - '{limits}' => '' + '{limits}' => '', ]); } else { - $sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [ + $sql = strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [ '{select}' => $rsm->generateSelectClause(['h' => 'households']), - '{limits}' => "OFFSET {$offset} LIMIT {$limit}" + '{limits}' => "OFFSET {$offset} LIMIT {$limit}", ]); } $native = $this->em->createNativeQuery($sql, $rsm); @@ -77,28 +106,8 @@ final class HouseholdRepository implements ObjectRepository if ($isCount) { return $native->getSingleScalarResult(); - } else { - return $native->getResult(); } - } - private CONST SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION = <<getResult(); + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/PersonHouseholdAddressRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/PersonHouseholdAddressRepository.php index d0676d172..8e9b789a7 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/PersonHouseholdAddressRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/PersonHouseholdAddressRepository.php @@ -1,5 +1,12 @@ repository->find($id, $lockMode, $lockVersion); } - public function findOneBy(array $criteria, array $orderBy = null): ?PersonHouseholdAddress - { - return $this->repository->findOneBy($criteria, $orderBy); - } - /** * @return PersonHouseholdAddress[] */ @@ -35,14 +37,23 @@ final class PersonHouseholdAddressRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return PersonHouseholdAddress[] */ - public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array { return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } - public function getClassName() { + public function findOneBy(array $criteria, ?array $orderBy = null): ?PersonHouseholdAddress + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + public function getClassName() + { return PersonHouseholdAddress::class; } } diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/PositionRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/PositionRepository.php index 58a0995d6..f8d264449 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/PositionRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/PositionRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(Position::class); } + /** + * @param mixed $id + * + * @return Position + */ + public function find($id) + { + return $this->repository->find($id); + } + /** * @return Position[] */ @@ -26,6 +43,17 @@ final class PositionRepository implements ObjectRepository return $this->repository->findAll(); } + /** + * @param mixed|null $limit + * @param mixed|null $offset + * + * @return Position[] + */ + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + /** * @return Position[] */ @@ -38,14 +66,6 @@ final class PositionRepository implements ObjectRepository ->getResult(); } - /** - * @return Position[] - */ - public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array - { - return $this->repository->findBy($criteria, $orderBy, $limit, $offset); - } - /** * @return Position[] */ @@ -54,14 +74,6 @@ final class PositionRepository implements ObjectRepository return $this->repository->findOneBy($criteria); } - /** - * @return Position - */ - public function find($id) - { - return $this->repository->find($id); - } - public function getClassName() { return Position::class; diff --git a/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php b/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php index 1a69d1319..c0558ef4e 100644 --- a/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/MaritalStatusRepository.php @@ -1,12 +1,18 @@ repository = $entityManager->getRepository(MaritalStatus::class); } + public function find($id): ?MaritalStatus { return $this->repository->find($id); diff --git a/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php b/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php index af8ed1a12..b55e69655 100644 --- a/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php @@ -1,33 +1,42 @@ authorizationHelper = $authorizationHelper; } - /** - * @return array|Person[] - * @throws NonUniqueResultException - * @throws ParsingException - */ - public function findBySearchCriteria( - int $start, - int $limit, - bool $simplify = false, - string $default = null, - string $firstname = null, - string $lastname = null, - ?\DateTimeInterface $birthdate = null, - ?\DateTimeInterface $birthdateBefore = null, - ?\DateTimeInterface $birthdateAfter = null, - string $gender = null, - string $countryCode = null, - string $phonenumber = null, - string $city = null - ): array { - $query = $this->buildAuthorizedQuery($default, $firstname, $lastname, - $birthdate, $birthdateBefore, $birthdateAfter, $gender, - $countryCode, $phonenumber, $city); + public function buildAuthorizedQuery( + ?string $default = null, + ?string $firstname = null, + ?string $lastname = null, + ?DateTimeInterface $birthdate = null, + ?DateTimeInterface $birthdateBefore = null, + ?DateTimeInterface $birthdateAfter = null, + ?string $gender = null, + ?string $countryCode = null, + ?string $phonenumber = null, + ?string $city = null + ): SearchApiQuery { + $query = $this->createSearchQuery( + $default, + $firstname, + $lastname, + $birthdate, + $birthdateBefore, + $birthdateAfter, + $gender, + $countryCode, + $phonenumber + ); - return $this->fetchQueryPerson($query); + return $this->addAuthorizations($query); } public function countBySearchCriteria( - string $default = null, - string $firstname = null, - string $lastname = null, - ?\DateTimeInterface $birthdate = null, - ?\DateTimeInterface $birthdateBefore = null, - ?\DateTimeInterface $birthdateAfter = null, - string $gender = null, - string $countryCode = null, - string $phonenumber = null, - string $city = null + ?string $default = null, + ?string $firstname = null, + ?string $lastname = null, + ?DateTimeInterface $birthdate = null, + ?DateTimeInterface $birthdateBefore = null, + ?DateTimeInterface $birthdateAfter = null, + ?string $gender = null, + ?string $countryCode = null, + ?string $phonenumber = null, + ?string $city = null ): int { - $query = $this->buildAuthorizedQuery($default, $firstname, $lastname, - $birthdate, $birthdateBefore, $birthdateAfter, $gender, - $countryCode, $phonenumber, $city) - ; + $query = $this->buildAuthorizedQuery( + $default, + $firstname, + $lastname, + $birthdate, + $birthdateBefore, + $birthdateAfter, + $gender, + $countryCode, + $phonenumber, + $city + ); return $this->fetchQueryCount($query); } + /** + * Create a search query without ACL. + * + * @throws NonUniqueResultException + * @throws ParsingException + */ + public function createSearchQuery( + ?string $default = null, + ?string $firstname = null, + ?string $lastname = null, + ?DateTimeInterface $birthdate = null, + ?DateTimeInterface $birthdateBefore = null, + ?DateTimeInterface $birthdateAfter = null, + ?string $gender = null, + ?string $countryCode = null, + ?string $phonenumber = null, + ?string $city = null + ): SearchApiQuery { + $query = new SearchApiQuery(); + $query + ->setFromClause('chill_person_person AS person'); + + $pertinence = []; + $pertinenceArgs = []; + $orWhereSearchClause = []; + $orWhereSearchClauseArgs = []; + + if ('' !== $default) { + foreach (explode(' ', $default) as $str) { + $pertinence[] = + 'STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), person.fullnamecanonical) + ' . + "(person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%')::int + " . + "(EXISTS (SELECT 1 FROM unnest(string_to_array(fullnamecanonical, ' ')) AS t WHERE starts_with(t, UNACCENT(LOWER(?)))))::int"; + array_push($pertinenceArgs, $str, $str, $str); + + $orWhereSearchClause[] = + '(LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ' . + "person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%' )"; + array_push($orWhereSearchClauseArgs, $str, $str); + } + + $query->andWhereClause( + implode(' OR ', $orWhereSearchClause), + $orWhereSearchClauseArgs + ); + } else { + $pertinence = ['1']; + $pertinenceArgs = []; + } + $query + ->setSelectPertinence(implode(' + ', $pertinence), $pertinenceArgs); + + if (null !== $birthdate) { + $query->andWhereClause( + 'person.birthdate = ?::date', + [$birthdate->format('Y-m-d')] + ); + } + + if (null !== $firstname) { + $query->andWhereClause( + "UNACCENT(LOWER(person.firstname)) LIKE '%' || UNACCENT(LOWER(?)) || '%'", + [$firstname] + ); + } + + if (null !== $lastname) { + $query->andWhereClause( + "UNACCENT(LOWER(person.lastname)) LIKE '%' || UNACCENT(LOWER(?)) || '%'", + [$lastname] + ); + } + + if (null !== $birthdateBefore) { + $query->andWhereClause( + 'p.birthdate < ?::date', + [$birthdateBefore->format('Y-m-d')] + ); + } + + if (null !== $birthdateAfter) { + $query->andWhereClause( + 'p.birthdate > ?::date', + [$birthdateAfter->format('Y-m-d')] + ); + } + + if (null !== $phonenumber) { + $query->andWhereClause( + "person.phonenumber LIKE '%' || ? || '%' OR person.mobilenumber LIKE '%' || ? || '%' OR pp.phonenumber LIKE '%' || ? || '%'", + [$phonenumber, $phonenumber, $phonenumber] + ); + $query->setFromClause($query->getFromClause() . ' LEFT JOIN chill_person_phone pp ON pp.person_id = person.id'); + } + + if (null !== $city) { + $query->setFromClause($query->getFromClause() . ' ' . + 'JOIN view_chill_person_current_address vcpca ON vcpca.person_id = person.id ' . + 'JOIN chill_main_address cma ON vcpca.address_id = cma.id ' . + 'JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id'); + + foreach (explode(' ', $city) as $cityStr) { + $query->andWhereClause( + "(UNACCENT(LOWER(cmpc.label)) LIKE '%' || UNACCENT(LOWER(?)) || '%' OR cmpc.code LIKE '%' || UNACCENT(LOWER(?)) || '%')", + [$cityStr, $city] + ); + } + } + + if (null !== $countryCode) { + $query->setFromClause($query->getFromClause() . ' JOIN country ON person.nationality_id = country.id'); + $query->andWhereClause('country.countrycode = UPPER(?)', [$countryCode]); + } + + if (null !== $gender) { + $query->andWhereClause('person.gender = ?', [$gender]); + } + + return $query; + } + public function fetchQueryCount(SearchApiQuery $query): int { $rsm = new Query\ResultSetMapping(); @@ -110,30 +248,48 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac $query->addSelectClause($rsm->generateSelectClause()); $nql = $this->em->createNativeQuery( - $query->buildQuery()." ORDER BY pertinence DESC OFFSET ? LIMIT ?", $rsm - )->setParameters(\array_merge($query->buildParameters(), [$start, $limit])); + $query->buildQuery() . ' ORDER BY pertinence DESC OFFSET ? LIMIT ?', + $rsm + )->setParameters(array_merge($query->buildParameters(), [$start, $limit])); return $nql->getResult(); } - public function buildAuthorizedQuery( - string $default = null, - string $firstname = null, - string $lastname = null, - ?\DateTimeInterface $birthdate = null, - ?\DateTimeInterface $birthdateBefore = null, - ?\DateTimeInterface $birthdateAfter = null, - string $gender = null, - string $countryCode = null, - string $phonenumber = null, - string $city = null - ): SearchApiQuery { - $query = $this->createSearchQuery($default, $firstname, $lastname, - $birthdate, $birthdateBefore, $birthdateAfter, $gender, - $countryCode, $phonenumber) - ; + /** + * @throws NonUniqueResultException + * @throws ParsingException + * + * @return array|Person[] + */ + public function findBySearchCriteria( + int $start, + int $limit, + bool $simplify = false, + ?string $default = null, + ?string $firstname = null, + ?string $lastname = null, + ?DateTimeInterface $birthdate = null, + ?DateTimeInterface $birthdateBefore = null, + ?DateTimeInterface $birthdateAfter = null, + ?string $gender = null, + ?string $countryCode = null, + ?string $phonenumber = null, + ?string $city = null + ): array { + $query = $this->buildAuthorizedQuery( + $default, + $firstname, + $lastname, + $birthdate, + $birthdateBefore, + $birthdateAfter, + $gender, + $countryCode, + $phonenumber, + $city + ); - return $this->addAuthorizations($query); + return $this->fetchQueryPerson($query); } private function addAuthorizations(SearchApiQuery $query): SearchApiQuery @@ -142,133 +298,21 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac ->getReachableCenters($this->security->getUser(), PersonVoter::SEE); if ([] === $authorizedCenters) { - return $query->andWhereClause("FALSE = TRUE", []); + return $query->andWhereClause('FALSE = TRUE', []); } return $query ->andWhereClause( strtr( - "person.center_id IN ({{ center_ids }})", + 'person.center_id IN ({{ center_ids }})', [ - '{{ center_ids }}' => \implode(', ', - \array_fill(0, count($authorizedCenters), '?')), + '{{ center_ids }}' => implode( + ', ', + array_fill(0, count($authorizedCenters), '?') + ), ] ), - \array_map(function(Center $c) {return $c->getId();}, $authorizedCenters) + array_map(function (Center $c) {return $c->getId(); }, $authorizedCenters) ); } - - /** - * Create a search query without ACL - * - * @throws NonUniqueResultException - * @throws ParsingException - */ - public function createSearchQuery( - string $default = null, - string $firstname = null, - string $lastname = null, - ?\DateTimeInterface $birthdate = null, - ?\DateTimeInterface $birthdateBefore = null, - ?\DateTimeInterface $birthdateAfter = null, - string $gender = null, - string $countryCode = null, - string $phonenumber = null, - string $city = null - ): SearchApiQuery { - $query = new SearchApiQuery(); - $query - ->setFromClause("chill_person_person AS person") - ; - - $pertinence = []; - $pertinenceArgs = []; - $orWhereSearchClause = []; - $orWhereSearchClauseArgs = []; - - if ("" !== $default) { - foreach (\explode(" ", $default) as $str) { - $pertinence[] = - "STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), person.fullnamecanonical) + ". - "(person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%')::int + ". - "(EXISTS (SELECT 1 FROM unnest(string_to_array(fullnamecanonical, ' ')) AS t WHERE starts_with(t, UNACCENT(LOWER(?)))))::int"; - \array_push($pertinenceArgs, $str, $str, $str); - - $orWhereSearchClause[] = - "(LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ". - "person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%' )"; - \array_push($orWhereSearchClauseArgs, $str, $str); - } - - $query->andWhereClause(\implode(' OR ', $orWhereSearchClause), - $orWhereSearchClauseArgs); - } else { - $pertinence = ["1"]; - $pertinenceArgs = []; - } - $query - ->setSelectPertinence(\implode(' + ', $pertinence), $pertinenceArgs) - ; - - if (NULL !== $birthdate) { - $query->andWhereClause( - "person.birthdate = ?::date", - [$birthdate->format('Y-m-d')] - ); - } - if (NULL !== $firstname) { - $query->andWhereClause( - "UNACCENT(LOWER(person.firstname)) LIKE '%' || UNACCENT(LOWER(?)) || '%'", - [$firstname] - ); - } - if (NULL !== $lastname) { - $query->andWhereClause( - "UNACCENT(LOWER(person.lastname)) LIKE '%' || UNACCENT(LOWER(?)) || '%'", - [$lastname] - ); - } - if (NULL !== $birthdateBefore) { - $query->andWhereClause( - 'p.birthdate < ?::date', - [$birthdateBefore->format('Y-m-d')] - ); - } - if (NULL !== $birthdateAfter) { - $query->andWhereClause( - 'p.birthdate > ?::date', - [$birthdateAfter->format('Y-m-d')] - ); - } - if (NULL !== $phonenumber) { - $query->andWhereClause( - "person.phonenumber LIKE '%' || ? || '%' OR person.mobilenumber LIKE '%' || ? || '%' OR pp.phonenumber LIKE '%' || ? || '%'" - , - [$phonenumber, $phonenumber, $phonenumber] - ); - $query->setFromClause($query->getFromClause()." LEFT JOIN chill_person_phone pp ON pp.person_id = person.id"); - } - if (null !== $city) { - $query->setFromClause($query->getFromClause()." ". - "JOIN view_chill_person_current_address vcpca ON vcpca.person_id = person.id ". - "JOIN chill_main_address cma ON vcpca.address_id = cma.id ". - "JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id"); - - foreach (\explode(" ", $city) as $cityStr) { - $query->andWhereClause( - "(UNACCENT(LOWER(cmpc.label)) LIKE '%' || UNACCENT(LOWER(?)) || '%' OR cmpc.code LIKE '%' || UNACCENT(LOWER(?)) || '%')", - [$cityStr, $city] - ); - } - } - if (null !== $countryCode) { - $query->setFromClause($query->getFromClause()." JOIN country ON person.nationality_id = country.id"); - $query->andWhereClause("country.countrycode = UPPER(?)", [$countryCode]); - } - if (null !== $gender) { - $query->andWhereClause("person.gender = ?", [$gender]); - } - - return $query; - } } diff --git a/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepositoryInterface.php index 89566b5a6..7bb46d84f 100644 --- a/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepositoryInterface.php @@ -1,14 +1,46 @@ repository->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(); diff --git a/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php b/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php index 0235ccc13..d9b858139 100644 --- a/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php @@ -1,31 +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\Repository; - use Chill\PersonBundle\Entity\Person; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectRepository; -use UnexpectedValueException; - +use Exception; +use function in_array; +use function str_replace; final class PersonRepository implements ObjectRepository { @@ -36,65 +27,9 @@ final class PersonRepository implements ObjectRepository $this->repository = $entityManager->getRepository(Person::class); } - public function find($id, $lockMode = null, $lockVersion = null): ?Person - { - return $this->repository->find($id, $lockMode, $lockVersion); - } - - public function findByIds($ids): array - { - return $this->repository->findBy(['id' => $ids]); - } - - public function findAll() - { - return $this->repository->findAll(); - } - - public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) - { - return $this->repository->findBy($criteria, $orderBy, $limit, $offset); - } - - public function findOneBy(array $criteria) - { - return $this->repository->findOneBy($criteria); - } - - public function getClassName() - { - return Person::class; - } - - /** - * @param $centers - * @param $firstResult - * @param $maxResults - * @return mixed - * @throws \Exception - */ - public function findByPhone( - string $phonenumber, - $centers, - $firstResult, - $maxResults, - array $only = ['mobile', 'phone'] - ) { - $qb = $this->repository->createQueryBuilder('p'); - $qb->select('p'); - - $this->addByCenters($qb, $centers); - $this->addPhoneNumber($qb, $phonenumber, $only); - - $qb->setFirstResult($firstResult) - ->setMaxResults($maxResults) - ; - - return $qb->getQuery()->getResult(); - } - /** * @param $centers + * * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException */ @@ -112,50 +47,103 @@ final class PersonRepository implements ObjectRepository return $qb->getQuery()->getSingleScalarResult(); } - /** - * @throws \Exception - */ - protected function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only): void + public function find($id, $lockMode = null, $lockVersion = null): ?Person { - 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.'%'); + return $this->repository->find($id, $lockMode, $lockVersion); } - - /** - * @param $phonenumber - * @return string - */ - protected function parsePhoneNumber(string $phonenumber): string + public function findAll() { - return \str_replace(' ', '', $phonenumber); + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findByIds($ids): array + { + return $this->repository->findBy(['id' => $ids]); } /** - * @param QueryBuilder $qb - * @param array $centers + * @param $centers + * @param $firstResult + * @param $maxResults + * + * @throws Exception + * + * @return mixed */ - protected function addByCenters(QueryBuilder $qb, array $centers): void + public function findByPhone( + string $phonenumber, + $centers, + $firstResult, + $maxResults, + array $only = ['mobile', 'phone'] + ) { + $qb = $this->repository->createQueryBuilder('p'); + $qb->select('p'); + + $this->addByCenters($qb, $centers); + $this->addPhoneNumber($qb, $phonenumber, $only); + + $qb->setFirstResult($firstResult) + ->setMaxResults($maxResults); + + return $qb->getQuery()->getResult(); + } + + public function findOneBy(array $criteria) + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName() + { + return Person::class; + } + + private function addByCenters(QueryBuilder $qb, array $centers): void { if (count($centers) > 0) { $qb->andWhere($qb->expr()->in('p.center', ':centers')); $qb->setParameter('centers', $centers); } } + + /** + * @throws Exception + */ + private function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only): void + { + 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 + */ + private function parsePhoneNumber(string $phonenumber): string + { + return str_replace(' ', '', $phonenumber); + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php index b68055581..22a95b3ca 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(Relation::class); } + public function find($id): ?Relation { return $this->repository->find($id); diff --git a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php index 7e5f2af24..2b2bf9136 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Relationships/RelationshipRepository.php @@ -1,11 +1,17 @@ repository->findBy($criteria, $orderBy, $limit, $offset); } - public function findOneBy(array $criteria): ?Relationship - { - return $this->findOneBy($criteria); - } - - public function getClassName(): string - { - return Relationship::class; - } - public function findByPerson($personId): array { // return all relationships of which person is part? or only where person is the fromPerson? @@ -52,8 +48,16 @@ class RelationshipRepository implements ObjectRepository ->orWhere('r.toPerson = :val') ->setParameter('val', $personId) ->getQuery() - ->getResult() - ; + ->getResult(); } + public function findOneBy(array $criteria): ?Relationship + { + return $this->findOneBy($criteria); + } + + public function getClassName(): string + { + return Relationship::class; + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php index d0f11c2d3..ac8e4d9d3 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php @@ -1,5 +1,12 @@ */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array @@ -49,6 +59,4 @@ final class EvaluationRepository implements ObjectRepository { return Evaluation::class; } - - } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php index 3c96c837c..211d86ba0 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/GoalRepository.php @@ -1,5 +1,12 @@ repository = $entityManager->getRepository(Goal::class); } + public function countBySocialActionWithDescendants(SocialAction $action): int + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('COUNT(g)'); + + return $qb + ->getQuery() + ->getSingleScalarResult(); + } + public function find($id, ?int $lockMode = null, ?int $lockVersion = null): ?Goal { return $this->repository->find($id, $lockMode, $lockVersion); @@ -32,6 +49,9 @@ final class GoalRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * * @return array */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array @@ -40,6 +60,9 @@ final class GoalRepository implements ObjectRepository } /** + * @param mixed|null $orderBy + * @param mixed|null $limit + * @param mixed|null $offset * * @return Goal[] */ @@ -49,44 +72,16 @@ final class GoalRepository implements ObjectRepository $qb->select('g'); foreach ($orderBy as $sort => $order) { - $qb->addOrderBy('g.'.$sort, $order); + $qb->addOrderBy('g.' . $sort, $order); } return $qb ->setMaxResults($limit) ->setFirstResult($offset) ->getQuery() - ->getResult() - ; + ->getResult(); } - public function countBySocialActionWithDescendants(SocialAction $action): int - { - $qb = $this->buildQueryBySocialActionWithDescendants($action); - $qb->select('COUNT(g)'); - - return $qb - ->getQuery() - ->getSingleScalarResult() - ; - } - - protected function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder - { - $actions = $action->getDescendantsWithThis(); - - $qb = $this->repository->createQueryBuilder('g'); - - $orx = $qb->expr()->orX(); - $i = 0; - foreach ($actions as $action) { - $orx->add(":action_{$i} MEMBER OF g.socialActions"); - $qb->setParameter("action_{$i}", $action); - } - $qb->where($orx); - - return $qb; - } public function findOneBy(array $criteria, ?array $orderBy = null): ?Goal { return $this->repository->findOneBy($criteria, $orderBy); @@ -99,4 +94,22 @@ final class GoalRepository implements ObjectRepository { return Goal::class; } + + private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder + { + $actions = $action->getDescendantsWithThis(); + + $qb = $this->repository->createQueryBuilder('g'); + + $orx = $qb->expr()->orX(); + $i = 0; + + foreach ($actions as $action) { + $orx->add(":action_{$i} MEMBER OF g.socialActions"); + $qb->setParameter("action_{$i}", $action); + } + $qb->where($orx); + + return $qb; + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php index 33bd8f7ef..1dca70d1e 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/ResultRepository.php @@ -1,10 +1,17 @@ repository = $entityManager->getRepository(Result::class); } + public function countByGoal(Goal $goal): int + { + $qb = $this->buildQueryByGoal($goal); + $qb->select('COUNT(r)'); + + return $qb + ->getQuery() + ->getSingleScalarResult(); + } + + public function countBySocialActionWithDescendants(SocialAction $action): int + { + $qb = $this->buildQueryBySocialActionWithDescendants($action); + $qb->select('COUNT(r)'); + + return $qb + ->getQuery() + ->getSingleScalarResult(); + } + public function find($id, ?int $lockMode = null, ?int $lockVersion = null): ?Result { return $this->repository->find($id, $lockMode, $lockVersion); @@ -33,6 +60,43 @@ final class ResultRepository implements ObjectRepository } /** + * @param mixed|null $limit + * @param mixed|null $offset + * + * @return array + */ + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + /** + * @param mixed|null $orderBy + * @param mixed|null $limit + * @param mixed|null $offset + * + * @return Result[] + */ + public function findByGoal(Goal $goal, $orderBy = null, $limit = null, $offset = null): array + { + $qb = $this->buildQueryByGoal($goal); + + foreach ($orderBy as $sort => $order) { + $qb->addOrderBy('r.' . $sort, $order); + } + + return $qb + ->select('r') + ->setMaxResults($limit) + ->setFirstResult($offset) + ->getQuery() + ->getResult(); + } + + /** + * @param mixed|null $orderBy + * @param mixed|null $limit + * @param mixed|null $offset * * @return Result[] */ @@ -42,92 +106,14 @@ final class ResultRepository implements ObjectRepository $qb->select('r'); foreach ($orderBy as $sort => $order) { - $qb->addOrderBy('r.'.$sort, $order); + $qb->addOrderBy('r.' . $sort, $order); } return $qb ->setMaxResults($limit) ->setFirstResult($offset) ->getQuery() - ->getResult() - ; - } - - public function countBySocialActionWithDescendants(SocialAction $action): int - { - $qb = $this->buildQueryBySocialActionWithDescendants($action); - $qb->select('COUNT(r)'); - - return $qb - ->getQuery() - ->getSingleScalarResult() - ; - } - - protected function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder - { - $actions = $action->getDescendantsWithThis(); - - $qb = $this->repository->createQueryBuilder('r'); - - $orx = $qb->expr()->orX(); - $i = 0; - foreach ($actions as $action) { - $orx->add(":action_{$i} MEMBER OF r.socialActions"); - $qb->setParameter("action_{$i}", $action); - } - $qb->where($orx); - - return $qb; - } - protected function buildQueryByGoal(Goal $goal): QueryBuilder - { - $qb = $this->repository->createQueryBuilder('r'); - - $qb->where(":goal MEMBER OF r.goals") - ->setParameter('goal', $goal) - ; - - return $qb; - } - - /** - * @return Result[] - */ - public function findByGoal(Goal $goal, $orderBy = null, $limit = null, $offset = null): array - { - $qb = $this->buildQueryByGoal($goal); - - foreach ($orderBy as $sort => $order) { - $qb->addOrderBy('r.'.$sort, $order); - } - - return $qb - ->select('r') - ->setMaxResults($limit) - ->setFirstResult($offset) - ->getQuery() - ->getResult() - ; - } - - public function countByGoal(Goal $goal): int - { - $qb = $this->buildQueryByGoal($goal); - $qb->select('COUNT(r)'); - - return $qb - ->getQuery() - ->getSingleScalarResult() - ; - } - - /** - * @return array - */ - public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array - { - return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + ->getResult(); } public function findOneBy(array $criteria, ?array $orderBy = null): ?Result @@ -142,4 +128,32 @@ final class ResultRepository implements ObjectRepository { return Result::class; } + + private function buildQueryByGoal(Goal $goal): QueryBuilder + { + $qb = $this->repository->createQueryBuilder('r'); + + $qb->where(':goal MEMBER OF r.goals') + ->setParameter('goal', $goal); + + return $qb; + } + + private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder + { + $actions = $action->getDescendantsWithThis(); + + $qb = $this->repository->createQueryBuilder('r'); + + $orx = $qb->expr()->orX(); + $i = 0; + + foreach ($actions as $action) { + $orx->add(":action_{$i} MEMBER OF r.socialActions"); + $qb->setParameter("action_{$i}", $action); + } + $qb->where($orx); + + return $qb; + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php index a81789c0a..1a8623d5e 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php @@ -1,5 +1,12 @@ */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php index 51ced6976..7c5983fd3 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php @@ -1,5 +1,12 @@ */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue index 7cce4d900..7e3b45103 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue @@ -11,7 +11,7 @@ {{ $t('course.step.draft') }} - + {{ $t('course.step.active') }} @@ -22,7 +22,20 @@ {{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }} - {{ $t('course.referrer') }}: {{ accompanyingCourse.user.username }} + {{ $t('course.referrer') }}: {{ accompanyingCourse.user.text }} + + + + + + {{ $t('course.step.closed') }} + + + + {{ $d(accompanyingCourse.openingDate.datetime, 'text') }} - {{ $d(accompanyingCourse.closingDate.datetime, 'text') }} + + + {{ $t('course.referrer') }}: {{ accompanyingCourse.user.text }} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js index 2a562f600..7e58ebba8 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js @@ -20,7 +20,8 @@ const appMessages = { status: "État", step: { draft: "Brouillon", - active: "En file active" + active: "En file active", + closed: "Cloturé" }, open_at: "ouvert le ", by: "par ", diff --git a/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/AppKernel.php b/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/AppKernel.php index 29c257406..67e742bf1 100644 --- a/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/AppKernel.php +++ b/src/Bundle/ChillPersonBundle/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().'/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/Resources/views/AccompanyingCourse/close.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/close.html.twig new file mode 100644 index 000000000..f0c819b35 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/close.html.twig @@ -0,0 +1,28 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% block content %} +

{{ "Close accompanying course"|trans }}

+ + {{ form_start(form) }} + + {{ form_row(form.closingDate) }} + {{ form_row(form.closingMotive) }} + + {% set accompanying_course_id = null %} + {% if accompanyingCourse %} + {% set accompanying_course_id = accompanyingCourse.id %} + {% endif %} + + + + {{ form_end(form) }} +{% endblock %} \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig index c5797a4b2..af8657e28 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig @@ -21,8 +21,10 @@
{% if accompanying_period.step == 'DRAFT' %} {{- 'Draft'|trans|upper -}} - {% else %} + {% elseif accompanying_period.step == 'CONFIRMED' %} {{- 'Confirmed'|trans|upper -}} + {% else %} + {{- 'Closed'|trans|upper -}} {% endif %}
diff --git a/src/Bundle/ChillPersonBundle/Search/PersonSearch.php b/src/Bundle/ChillPersonBundle/Search/PersonSearch.php index f4a6c19bf..78a657f7b 100644 --- a/src/Bundle/ChillPersonBundle/Search/PersonSearch.php +++ b/src/Bundle/ChillPersonBundle/Search/PersonSearch.php @@ -1,41 +1,57 @@ personACLAwareRepository = $personACLAwareRepository; } + 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('phonenumber', TelType::class, [ + 'required' => false, + 'label' => 'Part of the phonenumber', + ]) + ->add('gender', GenderType::class, [ + 'label' => 'Gender', + 'required' => false, + 'expanded' => false, + 'placeholder' => 'All genders', + ]) + ->add('city', TextType::class, [ + 'required' => false, + 'label' => 'City or postal code', + ]); + } + + public function convertFormDataToQuery(array $data) + { + $string = '@person '; + + $string .= empty($data['_default']) ? '' : $data['_default'] . ' '; + + foreach (['firstname', 'lastname', 'gender', 'phonenumber', 'city'] 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) + { + $data = []; + + foreach (['firstname', 'lastname', 'gender', '_default', 'phonenumber', 'city'] 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'; + } + + public static function getAlias(): string + { + return self::NAME; + } + /* * (non-PHPdoc) * @see \Chill\MainBundle\Search\SearchInterface::getOrder() @@ -68,66 +184,89 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf return true; } - 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') + public function renderResult(array $terms, $start = 0, $limit = 50, array $options = [], $format = 'html') { $terms = $this->findAdditionnalInDefault($terms); $total = $this->count($terms); $paginator = $this->paginatorFactory->create($total); - if ($format === 'html') { - return $this->templating->render('@ChillPerson/Person/list_with_period.html.twig', - array( - 'persons' => $this->search($terms, $start, $limit, $options), - 'pattern' => $this->recomposePattern( - $terms, - \array_filter(self::POSSIBLE_KEYS, fn($item) => $item !== '_default'), - $terms['_domain'] - ), - 'total' => $total, - 'start' => $start, - 'search_name' => self::NAME, - 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], - 'paginator' => $paginator - )); + if ('html' === $format) { + return $this->templating->render( + '@ChillPerson/Person/list_with_period.html.twig', + [ + 'persons' => $this->search($terms, $start, $limit, $options), + 'pattern' => $this->recomposePattern( + $terms, + array_filter(self::POSSIBLE_KEYS, fn ($item) => '_default' !== $item), + $terms['_domain'] + ), + 'total' => $total, + 'start' => $start, + 'search_name' => self::NAME, + 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], + 'paginator' => $paginator, + ] + ); } - if ($format === 'json') { + 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(), + ], ]; } } - private function findAdditionnalInDefault(array $terms): array + public function supports($domain, $format) { - // chaining some extractor - $datesResults = $this->extractDateFromPattern->extractDates($terms['_default']); - $phoneResults = $this->extractPhonenumberFromPattern->extractPhonenumber($datesResults->getFilteredSubject()); - $terms['_default'] = $phoneResults->getFilteredSubject(); + return 'person' === $domain; + } - if ($datesResults->hasResult() && (!\array_key_exists('birthdate', $terms) - || NULL !== $terms['birthdate'])) { - $terms['birthdate'] = $datesResults->getFound()[0]->format('Y-m-d'); + protected function count(array $terms): int + { + [ + '_default' => $default, + 'firstname' => $firstname, + 'lastname' => $lastname, + 'birthdate' => $birthdate, + 'birthdate-before' => $birthdateBefore, + 'birthdate-after' => $birthdateAfter, + 'gender' => $gender, + 'nationality' => $countryCode, + 'phonenumber' => $phonenumber, + 'city' => $city, + ] = $terms + array_fill_keys(self::POSSIBLE_KEYS, null); + + foreach (['birthdateBefore', 'birthdateAfter', 'birthdate'] as $v) { + if (null !== ${$v}) { + try { + ${$v} = new DateTime(${$v}); + } catch (Exception $e) { + throw new ParsingException('The date is ' + . 'not parsable', 0, $e); + } + } } - if ($phoneResults->hasResult() && (!\array_key_exists('phonenumber', $terms) - || NULL !== $terms['phonenumber'])) { - $terms['phonenumber'] = $phoneResults->getFound()[0]; - } - - return $terms; + return $this->personACLAwareRepository + ->countBySearchCriteria( + $default, + $firstname, + $lastname, + $birthdate, + $birthdateBefore, + $birthdateAfter, + $gender, + $countryCode, + $phonenumber, + $city + ); } /** @@ -146,13 +285,13 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf 'nationality' => $countryCode, 'phonenumber' => $phonenumber, 'city' => $city, - ] = $terms + \array_fill_keys(self::POSSIBLE_KEYS, null); + ] = $terms + array_fill_keys(self::POSSIBLE_KEYS, null); foreach (['birthdateBefore', 'birthdateAfter', 'birthdate'] as $v) { - if (NULL !== ${$v}) { + if (null !== ${$v}) { try { - ${$v} = new \DateTime(${$v}); - } catch (\Exception $e) { + ${$v} = new DateTime(${$v}); + } catch (Exception $e) { throw new ParsingException('The date is ' . 'not parsable', 0, $e); } @@ -177,146 +316,23 @@ class PersonSearch extends AbstractSearch implements HasAdvancedSearchFormInterf ); } - protected function count(array $terms): int + private function findAdditionnalInDefault(array $terms): array { - [ - '_default' => $default, - 'firstname' => $firstname, - 'lastname' => $lastname, - 'birthdate' => $birthdate, - 'birthdate-before' => $birthdateBefore, - 'birthdate-after' => $birthdateAfter, - 'gender' => $gender, - 'nationality' => $countryCode, - 'phonenumber' => $phonenumber, - 'city' => $city, - ] = $terms + \array_fill_keys(self::POSSIBLE_KEYS, null); + // chaining some extractor + $datesResults = $this->extractDateFromPattern->extractDates($terms['_default']); + $phoneResults = $this->extractPhonenumberFromPattern->extractPhonenumber($datesResults->getFilteredSubject()); + $terms['_default'] = $phoneResults->getFilteredSubject(); - foreach (['birthdateBefore', 'birthdateAfter', 'birthdate'] as $v) { - if (NULL !== ${$v}) { - try { - ${$v} = new \DateTime(${$v}); - } catch (\Exception $e) { - throw new ParsingException('The date is ' - . 'not parsable', 0, $e); - } - } + if ($datesResults->hasResult() && (!array_key_exists('birthdate', $terms) + || null !== $terms['birthdate'])) { + $terms['birthdate'] = $datesResults->getFound()[0]->format('Y-m-d'); } - return $this->personACLAwareRepository - ->countBySearchCriteria( - $default, - $firstname, - $lastname, - $birthdate, - $birthdateBefore, - $birthdateAfter, - $gender, - $countryCode, - $phonenumber, - $city - ); - } - - 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('phonenumber', TelType::class, [ - 'required' => false, - 'label' => 'Part of the phonenumber' - ]) - ->add('gender', GenderType::class, [ - 'label' => 'Gender', - 'required' => false, - 'expanded' => false, - 'placeholder' => 'All genders' - ]) - ->add('city', TextType::class, [ - 'required' => false, - 'label' => 'City or postal code' - ]) - ; - } - - public function convertFormDataToQuery(array $data) - { - $string = '@person '; - - $string .= empty($data['_default']) ? '' : $data['_default'].' '; - - foreach(['firstname', 'lastname', 'gender', 'phonenumber', 'city'] as $key) { - $string .= empty($data[$key]) ? '' : $key.':'. - // add quote if contains spaces - (strpos($data[$key], ' ') !== false ? '"'.$data[$key].'"': $data[$key]) - .' '; + if ($phoneResults->hasResult() && (!array_key_exists('phonenumber', $terms) + || null !== $terms['phonenumber'])) { + $terms['phonenumber'] = $phoneResults->getFound()[0]; } - 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) - { - $data = []; - - foreach(['firstname', 'lastname', 'gender', '_default', 'phonenumber', 'city'] 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'; - } - - public static function getAlias(): string - { - return self::NAME; + return $terms; } } diff --git a/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php b/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php index 1677072a4..3bcafae97 100644 --- a/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php +++ b/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php @@ -1,25 +1,39 @@ extractPhonenumberFromPattern = $extractPhonenumberFromPattern; } + public function getResult(string $key, array $metadata, float $pertinence) + { + return $this->personRepository->find($metadata['id']); + } + + public function prepare(array $metadatas): void + { + $ids = array_map(fn ($m) => $m['id'], $metadatas); + + $this->personRepository->findByIds($ids); + } + public function provideQuery(string $pattern, array $parameters): SearchApiQuery { $datesResult = $this->extractDateFromPattern->extractDates($pattern); @@ -43,40 +69,27 @@ class SearchPersonApiProvider implements SearchApiInterface $filtered = $phoneResult->getFilteredSubject(); return $this->personACLAwareRepository->buildAuthorizedQuery( - $filtered, - null, - null, - count($datesResult->getFound()) > 0 ? $datesResult->getFound()[0] : null, - null, - null, - null, - null, - count($phoneResult->getFound()) > 0 ? $phoneResult->getFound()[0] : null - ) - ->setSelectKey("person") + $filtered, + null, + null, + count($datesResult->getFound()) > 0 ? $datesResult->getFound()[0] : null, + null, + null, + null, + null, + count($phoneResult->getFound()) > 0 ? $phoneResult->getFound()[0] : null + ) + ->setSelectKey('person') ->setSelectJsonbMetadata("jsonb_build_object('id', person.id)"); } - - public function supportsTypes(string $pattern, array $types, array $parameters): bool - { - return \in_array('person', $types); - } - - public function prepare(array $metadatas): void - { - $ids = \array_map(fn($m) => $m['id'], $metadatas); - - $this->personRepository->findByIds($ids); - } - public function supportsResult(string $key, array $metadatas): bool { - return $key === 'person'; + return 'person' === $key; } - public function getResult(string $key, array $metadata, float $pertinence) + public function supportsTypes(string $pattern, array $types, array $parameters): bool { - return $this->personRepository->find($metadata['id']); + return in_array('person', $types); } } diff --git a/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php b/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php index 273367711..2afb7ef75 100644 --- a/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php +++ b/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php @@ -1,48 +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 . - */ -namespace Chill\PersonBundle\Search; - -use Chill\PersonBundle\Entity\PersonNotDuplicate; -use Chill\PersonBundle\Templating\Entity\PersonRender; -use Doctrine\ORM\EntityManagerInterface; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\PersonBundle\Repository\PersonNotDuplicateRepository; -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\Repository\PersonNotDuplicateRepository; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Chill\PersonBundle\Templating\Entity\PersonRender; +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'; - - /** - * @var EntityManagerInterface - */ - protected $em; + public const SIMILAR_SEARCH_ORDER_BY_SIMILARITY = 'similarity'; /** * @var AuthorizationHelper @@ -50,14 +30,19 @@ class SimilarPersonMatcher protected $authorizationHelper; /** - * @var TokenStorageInterface + * @var EntityManagerInterface */ - protected $tokenStorage; + protected $em; protected PersonNotDuplicateRepository $personNotDuplicateRepository; protected PersonRender $personRender; + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + public function __construct( EntityManagerInterface $em, AuthorizationHelper $authorizationHelper, @@ -88,11 +73,9 @@ class SimilarPersonMatcher . ' WHERE (' . ' SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) >= :precision ' . ' ) ' - . ' AND p.center IN (:centers)' + . ' AND p.center IN (:centers)'; - ; - - if ($person->getId() !== NULL) { + if ($person->getId() !== null) { $dql .= ' AND p.id != :personId '; $notDuplicatePersons = $this->personNotDuplicateRepository->findNotDuplicatePerson($person); @@ -107,9 +90,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 '; } @@ -117,8 +102,7 @@ class SimilarPersonMatcher ->setDQL($dql) ->setParameter('fullName', $this->personRender->renderString($person, [])) ->setParameter('centers', $centers) - ->setParameter('precision', $precision) - ; + ->setParameter('precision', $precision); return $query->getResult(); } diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php index 5247df505..ae226e848 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php @@ -1,35 +1,29 @@ build(); } + public function getRoles(): array + { + return self::ALL; + } + + public function getRolesWithHierarchy(): array + { + return ['Accompanying period' => $this->getRoles()]; + } + + public function getRolesWithoutScope(): array + { + return []; + } + protected function supports($attribute, $subject) { return $this->voterHelper->supports($attribute, $subject); @@ -68,10 +97,16 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRole } if ($subject instanceof AccompanyingPeriod) { + if (AccompanyingPeriod::STEP_CLOSED === $subject->getStep()) { + if (in_array($attribute, [self::EDIT, self::DELETE], true)) { + return false; + } + } + if (AccompanyingPeriod::STEP_DRAFT === $subject->getStep()) { // only creator can see, edit, delete, etc. if ($subject->getCreatedBy() === $token->getUser() - || NULL === $subject->getCreatedBy()) { + || null === $subject->getCreatedBy()) { return true; } @@ -86,19 +121,4 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRole return $this->voterHelper->voteOnAttribute($attribute, $subject, $token); } - - public function getRoles() - { - return self::ALL; - } - - public function getRolesWithoutScope() - { - return []; - } - - public function getRolesWithHierarchy() - { - return [ 'Accompanying period' => $this->getRoles() ]; - } } diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php index 2cc3f0d17..0e1dd493b 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/HouseholdVoter.php @@ -1,8 +1,15 @@ +/** + * 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\Entity\Center; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface; use Chill\MainBundle\Security\Authorization\VoterHelperInterface; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; -use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; 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; 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'; protected VoterHelperInterface $voter; @@ -49,9 +40,23 @@ class PersonVoter extends AbstractChillVoter implements ProvideRoleHierarchyInte ->generate(self::class) ->addCheckFor(Center::class, [self::STATS, self::LISTS, self::DUPLICATE]) ->addCheckFor(Person::class, [self::CREATE, self::UPDATE, self::SEE, self::DUPLICATE]) - ->addCheckFor(null, [self::CREATE] ) - ->build() - ; + ->addCheckFor(null, [self::CREATE]) + ->build(); + } + + public function getRoles(): array + { + return $this->getAttributes(); + } + + public function getRolesWithHierarchy(): array + { + return ['Person' => $this->getRoles()]; + } + + public function getRolesWithoutScope(): array + { + return $this->getAttributes(); } protected function supports($attribute, $subject) @@ -66,22 +71,6 @@ class PersonVoter extends AbstractChillVoter implements ProvideRoleHierarchyInte private function getAttributes() { - return array(self::CREATE, self::UPDATE, self::SEE, self::STATS, self::LISTS, self::DUPLICATE); + return [self::CREATE, self::UPDATE, self::SEE, self::STATS, self::LISTS, self::DUPLICATE]; } - - public function getRoles() - { - return $this->getAttributes(); - } - - public function getRolesWithoutScope() - { - return $this->getAttributes(); - } - - public function getRolesWithHierarchy() - { - return [ 'Person' => $this->getRoles() ]; - } - } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodOriginNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodOriginNormalizer.php index 7c9174217..45f9c7f05 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodOriginNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodOriginNormalizer.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\PersonBundle\Serializer\Normalizer; @@ -23,23 +13,22 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** - * * @internal we keep this normalizer, because the property 'text' may be replace by a rendering in the future */ class AccompanyingPeriodOriginNormalizer implements NormalizerInterface { - public function normalize($origin, string $format = null, array $context = array()) + public function normalize($origin, ?string $format = null, array $context = []) { /** @var Origin $origin */ return [ 'type' => 'origin', 'id' => $origin->getId(), 'label' => $origin->getLabel(), - 'text' => $origin->getLabel() + 'text' => $origin->getLabel(), ]; } - public function supportsNormalization($data, string $format = null): bool + public function supportsNormalization($data, ?string $format = null): bool { return $data instanceof Origin; } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php index a1321b3ef..c35d55b96 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php @@ -1,52 +1,42 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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 false; - return $data instanceof AccompanyingPeriodParticipation; - } - public function setNormalizer(NormalizerInterface $normalizer) { $this->normalizer = $normalizer; } + + public function supportsNormalization($data, ?string $format = null): bool + { + return false; + + return $data instanceof AccompanyingPeriodParticipation; + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodResourceNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodResourceNormalizer.php index b5fca8d59..0b6434a49 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodResourceNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodResourceNormalizer.php @@ -1,23 +1,30 @@ repository = $repository; } - public function denormalize($data, string $type, string $format = null, array $context = []) + public function denormalize($data, string $type, ?string $format = null, array $context = []) { $resource = $this->extractObjectToPopulate($type, $context); - if ('accompanying_period_resource' !== ($data['type'] ?? NULL)) { + if ('accompanying_period_resource' !== ($data['type'] ?? null)) { throw new Exception\InvalidArgumentException("the key type must be present in data and set to 'accompanying_period_resource'"); } - if ($resource === NULL && \array_key_exists('id', $data)) { + if (null === $resource && array_key_exists('id', $data)) { $resource = $this->repository->find($data['id']); - if (NULL === $resource) { - throw new Exception\UnexpectedValueException(sprintf("the resource with". - "id %d is not found", $data['id'])); + if (null === $resource) { + throw new Exception\UnexpectedValueException(sprintf('the resource with' . + 'id %d is not found', $data['id'])); } // if resource found, available only for read-only if (count($data) > 2) { - unset($data['id']); - unset($data['type']); + unset($data['id'], $data['type']); + throw new Exception\ExtraAttributesException($data); } } - if ($resource === NULL) { + if (null === $resource) { $resource = new Resource(); } - if (\array_key_exists('resource', $data)) { + if (array_key_exists('resource', $data)) { $res = $this->denormalizer->denormalize( $data['resource'], DiscriminatedObjectDenormalizer::TYPE, $format, - \array_merge( + array_merge( $context, - [ - DiscriminatedObjectDenormalizer::ALLOWED_TYPES => - [ - Person::class, ThirdParty::class - ] + [ + DiscriminatedObjectDenormalizer::ALLOWED_TYPES => [ + Person::class, ThirdParty::class, + ], ] ) ); $resource->setResource($res); - } + } return $resource; } - - public function supportsDenormalization($data, string $type, string $format = null) + public function supportsDenormalization($data, string $type, ?string $format = null) { - return $type === Resource::class; - } + return Resource::class === $type; + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkDenormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkDenormalizer.php index 4a8d51aa1..25bbb924c 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkDenormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkDenormalizer.php @@ -1,29 +1,27 @@ em = $em; } - /** - * @inheritDoc - */ - public function denormalize($data, string $type, string $format = null, array $context = []) + public function denormalize($data, string $type, ?string $format = null, array $context = []) { - $work = $this->denormalizer->denormalize($data, $type, $format, \array_merge($context, - ['skip' => self::class])); + $work = $this->denormalizer->denormalize($data, $type, $format, array_merge( + $context, + ['skip' => self::class] + )); - if (\in_array('accompanying_period_work:edit', $context['groups'] ?? [])) { + if (in_array('accompanying_period_work:edit', $context['groups'] ?? [])) { $this->handleEvaluationCollection($data, $work, $format, $context); } return $work; } + public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []): bool + { + return AccompanyingPeriodWork::class === $type + && self::class !== ($context['skip'] ?? null) + && is_array($data) + && array_key_exists('type', $data) + && 'accompanying_period_work' === $data['type']; + } + private function handleEvaluationCollection(array $data, AccompanyingPeriodWork $work, string $format, array $context) { $dataById = []; $dataWithoutId = []; + foreach ($data['accompanyingPeriodWorkEvaluations'] as $e) { - if (\array_key_exists('id', $e)) { - $dataById[$e['id']] = $e; - } else { - $dataWithoutId[] = $e; - } + if (array_key_exists('id', $e)) { + $dataById[$e['id']] = $e; + } else { + $dataWithoutId[] = $e; + } } // partition the separate kept evaluations and removed one - list($kept, $removed) = $work->getAccompanyingPeriodWorkEvaluations() + [$kept, $removed] = $work->getAccompanyingPeriodWorkEvaluations() ->partition( - fn(int $key, AccompanyingPeriodWorkEvaluation $a) => \array_key_exists($a->getId(), $dataById) + fn (int $key, AccompanyingPeriodWorkEvaluation $a) => array_key_exists($a->getId(), $dataById) ); // remove the evaluations from work @@ -92,13 +98,13 @@ class AccompanyingPeriodWorkDenormalizer implements DenormalizerAwareInterface, foreach ($kept as $k) { $this->denormalizer->denormalize( $dataById[$k->getId()], - AccompanyingPeriodWorkEvaluation::class, + AccompanyingPeriodWorkEvaluation::class, $format, - \array_merge( + array_merge( $context, [ - 'groups' => [ 'write' ], - AbstractNormalizer::OBJECT_TO_POPULATE => $k + 'groups' => ['write'], + AbstractNormalizer::OBJECT_TO_POPULATE => $k, ] ) ); @@ -109,24 +115,12 @@ class AccompanyingPeriodWorkDenormalizer implements DenormalizerAwareInterface, $newData, AccompanyingPeriodWorkEvaluation::class, $format, - \array_merge($context, ['groups' => [ 'accompanying_period_work_evaluation:create']] + array_merge( + $context, + ['groups' => ['accompanying_period_work_evaluation:create']] ) ); $work->addAccompanyingPeriodWorkEvaluation($evaluation); } } - - /** - * @inheritDoc - */ - public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool - { - return $type === AccompanyingPeriodWork::class - && ($context['skip'] ?? null) !== self::class - && \is_array($data) - && \array_key_exists("type", $data) - && $data["type"] === 'accompanying_period_work'; - } - - } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php index f3bcd74af..4e54c11be 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php @@ -1,31 +1,40 @@ factory = $factory; } - public function denormalize($data, string $type, string $format = null, array $context = []) + public function denormalize($data, string $type, ?string $format = null, array $context = []) { // some test about schema first... $this->performChecks($data); @@ -33,23 +42,16 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar // route to "leave movement" (all concerned leave household) // or "move to another household" (all concerned go to another // household) - if (NULL === $data['destination']) { + if (null === $data['destination']) { return $this->denormalizeLeave($data, $type, $format, $context); } return $this->denormalizeMove($data, $type, $format, $context); } - private function performChecks($data): void + public function supportsDenormalization($data, string $type, ?string $format = null) { - if (NULL == $data['concerned'] ?? NULL - && FALSE === ·\is_array('concerned')) { - throw new Exception\UnexpectedValueException("The schema does not have any key 'concerned'"); - } - - if (FALSE === \array_key_exists('destination', $data)) { - throw new Exception\UnexpectedValueException("The schema does not have any key 'destination'"); - } + return MembersEditor::class === $type; } protected function denormalizeLeave($data, string $type, string $format, array $context = []) @@ -57,18 +59,26 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar $editor = $this->factory->createEditor(null); foreach ($data['concerned'] as $key => $concerned) { - $person = $this->denormalizer->denormalize($concerned['person'] ?? null, Person::class, - $format, $context); - $startDate = $this->denormalizer->denormalize($concerned['start_date'] ?? null, \DateTimeImmutable::class, - $format, $context); + $person = $this->denormalizer->denormalize( + $concerned['person'] ?? null, + Person::class, + $format, + $context + ); + $startDate = $this->denormalizer->denormalize( + $concerned['start_date'] ?? null, + DateTimeImmutable::class, + $format, + $context + ); if ( - NULL === $person - && NULL === $startDate + null === $person + && null === $startDate ) { - throw new Exception\InvalidArgumentException("position with ". - "key $key could not be denormalized: missing ". - "person or start_date."); + throw new Exception\InvalidArgumentException('position with ' . + "key {$key} could not be denormalized: missing " . + 'person or start_date.'); } $editor->leaveMovement($startDate, $person); @@ -82,46 +92,73 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar $householdContext = $context; $householdContext['groups'][] = 'create'; - $household = $this->denormalizer->denormalize($data['destination'], Household::class, - $format, $householdContext); + $household = $this->denormalizer->denormalize( + $data['destination'], + Household::class, + $format, + $householdContext + ); - if (NULL === $household) { - throw new Exception\InvalidArgumentException("household could not be denormalized. Impossible to process"); + if (null === $household) { + throw new Exception\InvalidArgumentException('household could not be denormalized. Impossible to process'); } $editor = $this->factory->createEditor($household); foreach ($data['concerned'] as $key => $concerned) { - $person = $this->denormalizer->denormalize($concerned['person'] ?? null, Person::class, - $format, $context); - $position = $this->denormalizer->denormalize($concerned['position'] ?? null, Position::class, - $format, $context); - $startDate = $this->denormalizer->denormalize($concerned['start_date'] ?? null, \DateTimeImmutable::class, - $format, $context); + $person = $this->denormalizer->denormalize( + $concerned['person'] ?? null, + Person::class, + $format, + $context + ); + $position = $this->denormalizer->denormalize( + $concerned['position'] ?? null, + Position::class, + $format, + $context + ); + $startDate = $this->denormalizer->denormalize( + $concerned['start_date'] ?? null, + DateTimeImmutable::class, + $format, + $context + ); $holder = (bool) $concerned['holder'] ?? false; $comment = (string) $concerned['comment'] ?? false; if ( - NULL === $person - && NULL === $position - && NULL === $startDate + null === $person + && null === $position + && null === $startDate ) { - throw new Exception\InvalidArgumentException("position with ". - "key $key could not be denormalized: missing ". - "person, position or start_date."); + throw new Exception\InvalidArgumentException('position with ' . + "key {$key} could not be denormalized: missing " . + 'person, position or start_date.'); } - $editor->addMovement($startDate, $person, $position, $holder, - $comment); + $editor->addMovement( + $startDate, + $person, + $position, + $holder, + $comment + ); } return $editor; } - public function supportsDenormalization($data, string $type, string $format = null) + private function performChecks($data): void { - return $type === MembersEditor::class; - } + if (null == $data['concerned'] ?? null + && false === ·\is_array('concerned')) { + throw new Exception\UnexpectedValueException("The schema does not have any key 'concerned'"); + } + if (false === array_key_exists('destination', $data)) { + throw new Exception\UnexpectedValueException("The schema does not have any key 'destination'"); + } + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php index 769e1c907..3ad1bf4c1 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php @@ -1,5 +1,12 @@ translatableStringHelper = $translatableStringHelper; } - public function normalize($person, string $format = null, array $context = []) + public function normalize($person, ?string $format = null, array $context = []) { /** @var Person $person */ - $dateContext = $context; - $dateContext['docgen:expects'] = \DateTimeInterface::class; + $dateContext['docgen:expects'] = DateTimeInterface::class; if (null === $person) { return $this->normalizeNullValue($format, $context); @@ -57,9 +58,9 @@ class PersonDocGenNormalizer implements return [ 'firstname' => $person->getFirstName(), 'lastname' => $person->getLastName(), - 'altNames' => \implode( + 'altNames' => implode( ', ', - \array_map( + array_map( function (PersonAltName $altName) { return $altName->getLabel(); }, @@ -83,34 +84,34 @@ class PersonDocGenNormalizer implements ]; } - private function normalizeNullValue(string $format, array $context) + public function supportsNormalization($data, ?string $format = null, array $context = []) { - $normalizer = new NormalizeNullValueHelper($this->normalizer); - - $attributes = [ - 'firstname', 'lastname', 'altNames', 'text', - 'birthdate' => \DateTimeInterface::class, - 'deathdate' => \DateTimeInterface::class, - 'gender', 'maritalStatus', - 'maritalStatusDate' => \DateTimeInterface::class, - 'email', 'firstPhoneNumber', 'fixPhoneNumber', 'mobilePhoneNumber', 'nationality', - 'placeOfBirth', 'memo', 'numberOfChildren' - ]; - - return $normalizer->normalize($attributes, $format, $context); - } - - public function supportsNormalization($data, string $format = null, array $context = []) - { - if ($format !== 'docgen') { + if ('docgen' !== $format) { return false; } return $data instanceof Person || ( - \array_key_exists('docgen:expects', $context) - && $context['docgen:expects'] === Person::class + array_key_exists('docgen:expects', $context) + && Person::class === $context['docgen:expects'] ); } + + private function normalizeNullValue(string $format, array $context) + { + $normalizer = new NormalizeNullValueHelper($this->normalizer); + + $attributes = [ + 'firstname', 'lastname', 'altNames', 'text', + 'birthdate' => DateTimeInterface::class, + 'deathdate' => DateTimeInterface::class, + 'gender', 'maritalStatus', + 'maritalStatusDate' => DateTimeInterface::class, + 'email', 'firstPhoneNumber', 'fixPhoneNumber', 'mobilePhoneNumber', 'nationality', + 'placeOfBirth', 'memo', 'numberOfChildren', + ]; + + return $normalizer->normalize($attributes, $format, $context); + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php index 54c801c4b..cbb704d28 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php @@ -1,44 +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 . + * 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\MainBundle\Entity\Center; -use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface; +use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension; use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Repository\PersonRepository; +use DateTime; +use LogicException; +use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; -use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; -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 Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension; -use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait; +use function array_key_exists; /** - * Serialize a Person entity - * + * Serialize a Person entity. */ class PersonJsonNormalizer implements NormalizerInterface, @@ -46,17 +36,15 @@ class PersonJsonNormalizer implements DenormalizerInterface, DenormalizerAwareInterface { - private ChillEntityRenderExtension $render; - - private PersonRepository $repository; + use DenormalizerAwareTrait; + use NormalizerAwareTrait; + use ObjectToPopulateTrait; private CenterResolverManagerInterface $centerResolverManager; - use NormalizerAwareTrait; + private ChillEntityRenderExtension $render; - use ObjectToPopulateTrait; - - use DenormalizerAwareTrait; + private PersonRepository $repository; public function __construct( ChillEntityRenderExtension $render, @@ -68,7 +56,92 @@ class PersonJsonNormalizer implements $this->centerResolverManager = $centerResolverManager; } - public function normalize($person, string $format = null, array $context = []) + public function denormalize($data, string $type, ?string $format = null, array $context = []) + { + $person = $this->extractObjectToPopulate($type, $context); + + if (array_key_exists('id', $data)) { + $person = $this->repository->find($data['id']); + + if (null === $person) { + throw new UnexpectedValueException("The person with id \"{$data['id']}\" does " . + 'not exists'); + } + // currently, not allowed to update a person through api + // if instantiated with id + return $person; + } + + if (null === $person) { + $person = new Person(); + } + + foreach (['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender', + 'birthdate', 'deathdate', 'center', ] + as $item) { + if (!array_key_exists($item, $data)) { + continue; + } + + switch ($item) { + case 'firstName': + $person->setFirstName($data[$item]); + + break; + + case 'lastName': + $person->setLastName($data[$item]); + + break; + + case 'phonenumber': + $person->setPhonenumber($data[$item]); + + break; + + case 'mobilenumber': + $person->setMobilenumber($data[$item]); + + break; + + case 'gender': + $person->setGender($data[$item]); + + break; + + case 'birthdate': + $object = $this->denormalizer->denormalize($data[$item], DateTime::class, $format, $context); + + if ($object instanceof DateTime) { + $person->setBirthdate($object); + } + + break; + + case 'deathdate': + $object = $this->denormalizer->denormalize($data[$item], DateTime::class, $format, $context); + + if ($object instanceof DateTime) { + $person->setDeathdate($object); + } + + break; + + case 'center': + $object = $this->denormalizer->denormalize($data[$item], Center::class, $format, $context); + $person->setCenter($object); + + break; + + default: + throw new LogicException("item not defined: {$item}"); + } + } + + return $person; + } + + public function normalize($person, ?string $format = null, array $context = []) { /** @var Household $household */ $household = $person->getCurrentHousehold(); @@ -92,93 +165,24 @@ class PersonJsonNormalizer implements ]; } + public function supportsDenormalization($data, string $type, ?string $format = null) + { + return Person::class === $type && 'person' === ($data['type'] ?? null); + } + + public function supportsNormalization($data, ?string $format = null): bool + { + return $data instanceof Person && 'json' === $format; + } + protected function normalizeAltNames($altNames): array { $r = []; foreach ($altNames as $n) { - $r[] = [ 'key' => $n->getKey(), 'label' => $n->getLabel() ]; + $r[] = ['key' => $n->getKey(), 'label' => $n->getLabel()]; } return $r; } - - - public function supportsNormalization($data, string $format = null): bool - { - return $data instanceof Person && $format === 'json'; - } - - public function denormalize($data, string $type, string $format = null, array $context = []) - { - $person = $this->extractObjectToPopulate($type, $context); - - if (\array_key_exists('id', $data)) { - $person = $this->repository->find($data['id']); - - if (null === $person) { - throw new UnexpectedValueException("The person with id \"{$data['id']}\" does ". - "not exists"); - } - // currently, not allowed to update a person through api - // if instantiated with id - return $person; - } - - if (null === $person) { - $person = new Person(); - } - - foreach (['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender', - 'birthdate', 'deathdate', 'center'] - as $item) { - - if (!\array_key_exists($item, $data)) { - continue; - } - - switch ($item) { - case 'firstName': - $person->setFirstName($data[$item]); - break; - case 'lastName': - $person->setLastName($data[$item]); - break; - case 'phonenumber': - $person->setPhonenumber($data[$item]); - break; - case 'mobilenumber': - $person->setMobilenumber($data[$item]); - break; - case 'gender': - $person->setGender($data[$item]); - break; - case 'birthdate': - $object = $this->denormalizer->denormalize($data[$item], \DateTime::class, $format, $context); - if ($object instanceof \DateTime) { - $person->setBirthdate($object); - } - break; - case 'deathdate': - $object = $this->denormalizer->denormalize($data[$item], \DateTime::class, $format, $context); - if ($object instanceof \DateTime) { - $person->setDeathdate($object); - } - break; - case 'center': - $object = $this->denormalizer->denormalize($data[$item], Center::class, $format, $context); - $person->setCenter($object); - break; - default: - throw new \LogicException("item not defined: $item"); - } - } - - return $person; - } - - public function supportsDenormalization($data, string $type, string $format = null) - { - return $type === Person::class && ($data['type'] ?? NULL) === 'person'; - } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php index 1ced09a1e..e77aea18c 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialActionNormalizer.php @@ -1,13 +1,19 @@ render = $render; } - /** - * {@inheritDoc} - */ - public function normalize($socialAction, string $format = null, array $context = []) + public function normalize($socialAction, ?string $format = null, array $context = []) { return [ 'id' => $socialAction->getId(), @@ -31,14 +34,11 @@ class SocialActionNormalizer implements NormalizerInterface, NormalizerAwareInte 'text' => $this->render->renderString($socialAction, []), 'parent' => $this->normalizer->normalize($socialAction->getParent()), 'desactivationDate' => $this->normalizer->normalize($socialAction->getDesactivationDate()), - 'title' => $socialAction->getTitle() + 'title' => $socialAction->getTitle(), ]; } - /** - * {@inheritDoc} - */ - public function supportsNormalization($data, string $format = null) + public function supportsNormalization($data, ?string $format = null) { return $data instanceof SocialAction; } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialIssueNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialIssueNormalizer.php index 383110764..ffbadf50a 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialIssueNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/SocialIssueNormalizer.php @@ -1,25 +1,32 @@ render = $render; } - public function normalize($socialIssue, string $format = null, array $context = []) + public function normalize($socialIssue, ?string $format = null, array $context = []) { /** @var SocialIssue $socialIssue */ return [ @@ -28,11 +35,11 @@ class SocialIssueNormalizer implements NormalizerInterface, NormalizerAwareInter 'parent_id' => $socialIssue->hasParent() ? $socialIssue->getParent()->getId() : null, 'children_ids' => $socialIssue->getChildren()->map(function (SocialIssue $si) { return $si->getId(); }), 'title' => $socialIssue->getTitle(), - 'text' => $this->render->renderString($socialIssue, []) + 'text' => $this->render->renderString($socialIssue, []), ]; } - public function supportsNormalization($data, string $format = null): bool + public function supportsNormalization($data, ?string $format = null): bool { return $data instanceof SocialIssue; } diff --git a/src/Bundle/ChillPersonBundle/Service/Import/ChillImporter.php b/src/Bundle/ChillPersonBundle/Service/Import/ChillImporter.php index 4360a7cfa..8f0a53157 100644 --- a/src/Bundle/ChillPersonBundle/Service/Import/ChillImporter.php +++ b/src/Bundle/ChillPersonBundle/Service/Import/ChillImporter.php @@ -1,5 +1,12 @@ entityManager + ->createQueryBuilder() + ->select('s') + ->from($repository->getClassName(), 's'); - $socialIssue = $this->handleSocialIssue($row[0], $row[1]); + $expr = $qb->expr(); - $socialAction = $this->handleSocialAction($row[2], $row[3], $socialIssue); + $temporaryJsonCriterias = $jsonParameters = []; - $goal = $this->handleGoal($row[4], $socialAction); + foreach ($jsonCriterias as $key => $value) { + $temporaryJsonCriterias[] = [$field, $key, $value, sprintf(':placeholder_%s_%s', $field, $key)]; + } - $result = $this->handleResult($row[5], $socialAction, $goal); + $jsonParameters = array_reduce( + $temporaryJsonCriterias, + static function (array $carry, array $row): array { + [,, $value, $placeholder] = $row; - $eval = $this->handleEvaluation($row[6], $socialAction); + return array_merge( + $carry, + [ + $placeholder => sprintf('"%s"', $value), + ] + ); + }, + [] + ); - $this->entityManager->flush(); + $jsonPredicates = array_map( + static function (array $row) use ($expr): Comparison { + [$field, $key,, $placeholder] = $row; + + $left = sprintf( + "GET_JSON_FIELD_BY_KEY(s.%s, '%s')", + $field, + $key + ); + + return $expr + ->eq( + $left, + $placeholder + ); + }, + $temporaryJsonCriterias + ); + + $query = $qb + ->select('s') + ->where(...$jsonPredicates) + ->setParameters($jsonParameters) + ->getQuery(); + + return $query->getResult(); } - private function handleSocialIssue(?string $socialIssueTitle = null, ?string $socialIssueChildrenTitle = null): SocialIssue + private function getOrCreateEntity(ObjectRepository $repository, string $field, array $jsonCriterias = []) { - if (null !== $socialIssueChildrenTitle) { - /** @var SocialIssue $socialIssueChildren */ - $socialIssueChildren = $this->getOrCreateEntity($this->socialIssueRepository, 'title', ['fr' => $socialIssueChildrenTitle]); - $socialIssueChildren->setTitle(['fr' => $socialIssueChildrenTitle]); + $results = $this + ->findByJson( + $repository, + $field, + $jsonCriterias + ); - $this->entityManager->persist($socialIssueChildren); + $entity = null; + + switch (true) { + case count($results) === 0: + $entity = $repository->getClassName(); + $entity = new $entity(); + + break; + + case count($results) === 1: + $entity = current($results); + + break; + + case count($results) > 1: + throw new Exception( + sprintf( + 'More than one entity(%s) found.', + $repository->getClassName() + ) + ); } - /** @var SocialIssue $socialIssue */ - $socialIssue = $this->getOrCreateEntity($this->socialIssueRepository, 'title', ['fr' => $socialIssueTitle]); - $socialIssue->setTitle(['fr' => $socialIssueTitle]); - - if (null !== $socialIssueChildrenTitle) { - $socialIssue->addChild($socialIssueChildren); + if (null === $entity) { + throw new Exception('Unable to create entity.'); } - $this->entityManager->persist($socialIssue); - - return null === $socialIssueChildrenTitle ? $socialIssue : $socialIssueChildren; + return $entity; } - private function handleSocialAction(?string $socialActionTitle, ?string $socialActionChildrenTitle, SocialIssue $socialIssue): SocialAction + private function handleEvaluation(?string $evaluationTitle, SocialAction $socialAction): ?Evaluation { - if (null !== $socialActionChildrenTitle) { - /** @var SocialAction $socialActionChildren */ - $socialActionChildren = $this->getOrCreateEntity($this->socialActionRepository, 'title', ['fr' => $socialActionChildrenTitle]); - $socialActionChildren->setTitle(['fr' => $socialActionChildrenTitle]); - - $this->entityManager->persist($socialActionChildren); + if (null === $evaluationTitle) { + return null; } - /** @var SocialIssue $socialIssue */ - $socialAction = $this->getOrCreateEntity($this->socialActionRepository, 'title', ['fr' => $socialActionTitle]); - $socialAction->setTitle(['fr' => $socialActionTitle]); + /** @var Evaluation $eval */ + $eval = $this->getOrCreateEntity($this->evaluationRepository, 'title', ['fr' => $evaluationTitle]); + $eval->setTitle(['fr' => $evaluationTitle]); + $eval->setSocialAction($socialAction); - if (null !== $socialActionChildrenTitle) { - $socialActionChildren->setIssue($socialIssue); - $this->entityManager->persist($socialActionChildren); + $this->entityManager->persist($eval); - $socialAction->addChild($socialActionChildren); - } else { - $socialAction->setIssue($socialIssue); - } - - $this->entityManager->persist($socialAction); - - return null === $socialActionChildrenTitle ? $socialAction : $socialActionChildren; + return $eval; } private function handleGoal(?string $goalTitle = null, ?SocialAction $socialAction = null): ?Goal @@ -188,117 +234,78 @@ final class SocialWorkMetadata implements SocialWorkMetadataInterface return $result; } - private function handleEvaluation(?string $evaluationTitle, SocialAction $socialAction): ?Evaluation + private function handleSocialAction(?string $socialActionTitle, ?string $socialActionChildrenTitle, SocialIssue $socialIssue): SocialAction { - if (null === $evaluationTitle) { - return null; + if (null !== $socialActionChildrenTitle) { + /** @var SocialAction $socialActionChildren */ + $socialActionChildren = $this->getOrCreateEntity($this->socialActionRepository, 'title', ['fr' => $socialActionChildrenTitle]); + $socialActionChildren->setTitle(['fr' => $socialActionChildrenTitle]); + + $this->entityManager->persist($socialActionChildren); } - /** @var Evaluation $eval */ - $eval = $this->getOrCreateEntity($this->evaluationRepository, 'title', ['fr' => $evaluationTitle]); - $eval->setTitle(['fr' => $evaluationTitle]); - $eval->setSocialAction($socialAction); + /** @var SocialIssue $socialIssue */ + $socialAction = $this->getOrCreateEntity($this->socialActionRepository, 'title', ['fr' => $socialActionTitle]); + $socialAction->setTitle(['fr' => $socialActionTitle]); - $this->entityManager->persist($eval); + if (null !== $socialActionChildrenTitle) { + $socialActionChildren->setIssue($socialIssue); + $this->entityManager->persist($socialActionChildren); - return $eval; + $socialAction->addChild($socialActionChildren); + } else { + $socialAction->setIssue($socialIssue); + } + + $this->entityManager->persist($socialAction); + + return null === $socialActionChildrenTitle ? $socialAction : $socialActionChildren; } - private function findByJson(ObjectRepository $repository, string $field, array $jsonCriterias): array + private function handleSocialIssue(?string $socialIssueTitle = null, ?string $socialIssueChildrenTitle = null): SocialIssue { - $qb = $this - ->entityManager - ->createQueryBuilder() - ->select('s') - ->from($repository->getClassName(), 's'); + if (null !== $socialIssueChildrenTitle) { + /** @var SocialIssue $socialIssueChildren */ + $socialIssueChildren = $this->getOrCreateEntity($this->socialIssueRepository, 'title', ['fr' => $socialIssueChildrenTitle]); + $socialIssueChildren->setTitle(['fr' => $socialIssueChildrenTitle]); - $expr = $qb->expr(); - - $temporaryJsonCriterias = $jsonParameters = []; - - foreach ($jsonCriterias as $key => $value) { - $temporaryJsonCriterias[] = [$field, $key, $value, sprintf(':placeholder_%s_%s', $field, $key)]; + $this->entityManager->persist($socialIssueChildren); } - $jsonParameters = array_reduce( - $temporaryJsonCriterias, - static function (array $carry, array $row): array - { - [,, $value, $placeholder] = $row; + /** @var SocialIssue $socialIssue */ + $socialIssue = $this->getOrCreateEntity($this->socialIssueRepository, 'title', ['fr' => $socialIssueTitle]); + $socialIssue->setTitle(['fr' => $socialIssueTitle]); - return array_merge( - $carry, - [ - $placeholder => sprintf('"%s"', $value), - ] - ); - }, - [] - ); + if (null !== $socialIssueChildrenTitle) { + $socialIssue->addChild($socialIssueChildren); + } - $jsonPredicates = array_map( - static function (array $row) use ($expr): Comparison - { - [$field, $key,, $placeholder] = $row; + $this->entityManager->persist($socialIssue); - $left = sprintf( - "GET_JSON_FIELD_BY_KEY(s.%s, '%s')", - $field, - $key - ); - - return $expr - ->eq( - $left, - $placeholder - ); - }, - $temporaryJsonCriterias - ); - - $query = $qb - ->select('s') - ->where(...$jsonPredicates) - ->setParameters($jsonParameters) - ->getQuery(); - - return $query->getResult(); + return null === $socialIssueChildrenTitle ? $socialIssue : $socialIssueChildren; } - private function getOrCreateEntity(ObjectRepository $repository, string $field, array $jsonCriterias = []) + private function import1(array $row): void { - $results = $this - ->findByJson( - $repository, - $field, - $jsonCriterias - ); + // Structure: + // Index 0: SocialIssue.parent + // Index 1: SocialIssue + // Index 2: SocialAction.parent + // Index 3: SocialAction + // Index 4: Goal + // Index 5: Result + // Index 6: Evaluation - $entity = null; + $socialIssue = $this->handleSocialIssue($row[0], $row[1]); - switch (true) { - case count($results) === 0: - $entity = $repository->getClassName(); - $entity = new $entity(); - break; - case count($results) === 1; - $entity = current($results); - break; - case count($results) > 1; - throw new Exception( - sprintf( - 'More than one entity(%s) found.', - $repository->getClassName() - ) - ); - } + $socialAction = $this->handleSocialAction($row[2], $row[3], $socialIssue); - if (null === $entity) { - throw new Exception('Unable to create entity.'); - } + $goal = $this->handleGoal($row[4], $socialAction); - return $entity; + $result = $this->handleResult($row[5], $socialAction, $goal); + + $eval = $this->handleEvaluation($row[6], $socialAction); + + $this->entityManager->flush(); } - - } diff --git a/src/Bundle/ChillPersonBundle/Service/Import/SocialWorkMetadataInterface.php b/src/Bundle/ChillPersonBundle/Service/Import/SocialWorkMetadataInterface.php index 015ef7485..00d1de6ef 100644 --- a/src/Bundle/ChillPersonBundle/Service/Import/SocialWorkMetadataInterface.php +++ b/src/Bundle/ChillPersonBundle/Service/Import/SocialWorkMetadataInterface.php @@ -1,5 +1,12 @@ '; - + 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 fc112a1e7..5220957cd 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/PersonRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/PersonRender.php @@ -1,33 +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\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 Symfony\Component\Templating\EngineInterface; +use function array_key_exists; /** - * Render a Person - * + * Render a Person. */ class PersonRender extends AbstractChillEntityRender { @@ -44,10 +33,7 @@ class PersonRender extends AbstractChillEntityRender } /** - * * @param Person $person - * @param array $options - * @return string */ public function renderBox($person, array $options): string { @@ -70,21 +56,23 @@ class PersonRender extends AbstractChillEntityRender $this->engine->render('@ChillPerson/Entity/person.html.twig', [ 'person' => $person, 'render' => $options['render'] ?? 'raw', - 'options' => $params + 'options' => $params, ]) . $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); + 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): string @@ -97,34 +85,30 @@ class PersonRender extends AbstractChillEntityRender foreach ($person->getAltNames()->getIterator() as $altName) { /** @var \Chill\PersonBundle\Entity\PersonAltName $altName */ - if (\array_key_exists($altName->getKey(), $altNames)) { + if (array_key_exists($altName->getKey(), $altNames)) { if ($isFirst) { - $str .= " ("; + $str .= ' ('; $isFirst = false; } else { - $str.= " "; + $str .= ' '; } + if ($addSpan) { - $str .= ''; + $str .= ''; } $str .= $altName->getLabel(); if ($addSpan) { - $str .= ""; + $str .= ''; } } } if (!$isFirst) { - $str .= ")"; + $str .= ')'; } } return $str; } - - public function supports($entity, array $options): bool - { - return $entity instanceof Person; - } } diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php index c68e300cf..6140b5ded 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php @@ -1,27 +1,39 @@ ' > ', self::NO_BADGE => false, - ]; + ]; + + /** + * if true, the action will not be encapsulated into a "badge". + */ + public const NO_BADGE = 'no-badge'; + + public const SEPARATOR_KEY = 'default.separator'; + + private EngineInterface $engine; + + private TranslatableStringHelper $translatableStringHelper; public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine) { @@ -29,15 +41,23 @@ class SocialActionRender implements ChillEntityRenderInterface $this->engine = $engine; } - public function supports($entity, array $options): bool + public function renderBox($socialAction, array $options): string { - return $entity instanceof SocialAction; + $options = array_merge(self::DEFAULT_ARGS, $options); + // give some help to twig: an array of parents + $parents = $this->buildParents($socialAction); + + return $this->engine->render('@ChillPerson/Entity/social_action.html.twig', [ + 'socialAction' => $socialAction, + 'parents' => $parents, + 'options' => $options, + ]); } public function renderString($socialAction, array $options): string { - /** @var $socialAction SocialAction */ - $options = \array_merge(self::DEFAULT_ARGS, $options); + /** @var SocialAction $socialAction */ + $options = array_merge(self::DEFAULT_ARGS, $options); $titles = [$this->translatableStringHelper->localize($socialAction->getTitle())]; while ($socialAction->hasParent()) { @@ -47,31 +67,24 @@ class SocialActionRender implements ChillEntityRenderInterface ); } - $titles = \array_reverse($titles); + $titles = array_reverse($titles); - return \implode($options[self::SEPARATOR_KEY], $titles); + return implode($options[self::SEPARATOR_KEY], $titles); + } + + public function supports($entity, array $options): bool + { + return $entity instanceof SocialAction; } protected function buildParents($socialAction): array { $parents = []; + while ($socialAction->hasParent()) { $socialAction = $parents[] = $socialAction->getParent(); } return $parents; } - - public function renderBox($socialAction, array $options): string - { - $options = \array_merge(self::DEFAULT_ARGS, $options); - // give some help to twig: an array of parents - $parents = $this->buildParents($socialAction); - - return $this->engine->render('@ChillPerson/Entity/social_action.html.twig', [ - 'socialAction' => $socialAction, - 'parents' => $parents, - 'options' => $options - ]); - } } diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php index 80254d989..2b3e31159 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php @@ -1,23 +1,32 @@ ' > ', + ]; public const SEPARATOR_KEY = 'default.separator'; - public const DEFAULT_ARGS = [ - self::SEPARATOR_KEY => ' > ', - ]; + private EngineInterface $engine; + + private TranslatableStringHelper $translatableStringHelper; public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine) { @@ -25,49 +34,9 @@ final class SocialIssueRender implements ChillEntityRenderInterface $this->engine = $engine; } - public function supports($entity, array $options): bool - { - return $entity instanceof SocialIssue; - } - /** * @param SocialIssue $socialIssue */ - public function renderString($socialIssue, array $options): string - { - /** @var $socialIssue SocialIssue */ - $options = array_merge(self::DEFAULT_ARGS, $options); - - $titles = [$this->translatableStringHelper->localize($socialIssue->getTitle())]; - - // loop to parent, until root - while ($socialIssue->hasParent()) { - $socialIssue = $socialIssue->getParent(); - $titles[] = $this->translatableStringHelper->localize( - $socialIssue->getTitle() - ); - } - - $titles = \array_reverse($titles); - - return \implode($options[self::SEPARATOR_KEY], $titles); - } - - protected function buildParents(SocialIssue $socialIssue): array - { - $parents = []; - - while ($socialIssue->hasParent()) { - $socialIssue = $parents[] = $socialIssue->getParent(); - } - - return $parents; - } - - /** - * - * @param SocialIssue $socialIssue - */ public function renderBox($socialIssue, array $options): string { $options = array_merge(self::DEFAULT_ARGS, $options); @@ -81,8 +50,47 @@ final class SocialIssueRender implements ChillEntityRenderInterface [ 'socialIssue' => $socialIssue, 'parents' => $parents, - 'options' => $options + 'options' => $options, ] ); } + + /** + * @param SocialIssue $socialIssue + */ + public function renderString($socialIssue, array $options): string + { + /** @var SocialIssue $socialIssue */ + $options = array_merge(self::DEFAULT_ARGS, $options); + + $titles = [$this->translatableStringHelper->localize($socialIssue->getTitle())]; + + // loop to parent, until root + while ($socialIssue->hasParent()) { + $socialIssue = $socialIssue->getParent(); + $titles[] = $this->translatableStringHelper->localize( + $socialIssue->getTitle() + ); + } + + $titles = array_reverse($titles); + + return implode($options[self::SEPARATOR_KEY], $titles); + } + + public function supports($entity, array $options): bool + { + return $entity instanceof SocialIssue; + } + + private function buildParents(SocialIssue $socialIssue): array + { + $parents = []; + + while ($socialIssue->hasParent()) { + $socialIssue = $parents[] = $socialIssue->getParent(); + } + + return $parents; + } } 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/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php b/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php index a94280dd0..c57f24332 100644 --- a/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/AccompanyingPeriod/SocialIssueConsistency/AccompanyingPeriodSocialIssueConsistencyEntityListenerTest.php @@ -1,5 +1,12 @@ setParent($parent), + $grandChild = (new SocialIssue())->setParent($child), + $grandGrandChild = (new SocialIssue())->setParent($grandChild), + ]); + $period = (new AccompanyingPeriod())->addSocialIssue($unrelated = new SocialIssue()); + $entity = $this->generateClass($period, $socialIssues); + $consistency = new AccompanyingPeriodSocialIssueConsistencyEntityListener(); + + $consistency->prePersist($entity, $this->generateLifecycleArgs()); + + $this->assertCount(2, $period->getSocialIssues()); + $this->assertContains($grandGrandChild, $period->getSocialIssues()); + $this->assertContains($unrelated, $period->getSocialIssues()); + + $this->assertCount(1, $entity->getSocialIssues()); + $this->assertContains($grandGrandChild, $entity->getSocialIssues()); + } public function testPrePersistAccompanyingPeriod() { @@ -57,29 +89,6 @@ class AccompanyingPeriodSocialIssueConsistencyEntityListenerTest extends TestCas $this->assertContains($grandGrandChild, $entity->getSocialIssues()); } - public function testPrePersist() - { - $socialIssues = new ArrayCollection([ - $parent = new SocialIssue(), - $child = (new SocialIssue())->setParent($parent), - $grandChild = (new SocialIssue())->setParent($child), - $grandGrandChild = (new SocialIssue())->setParent($grandChild), - ]); - $period = (new AccompanyingPeriod())->addSocialIssue($unrelated = new SocialIssue()); - $entity = $this->generateClass($period, $socialIssues); - $consistency = new AccompanyingPeriodSocialIssueConsistencyEntityListener(); - - $consistency->prePersist($entity, $this->generateLifecycleArgs()); - - $this->assertCount(2, $period->getSocialIssues()); - $this->assertContains($grandGrandChild, $period->getSocialIssues()); - $this->assertContains($unrelated, $period->getSocialIssues()); - - $this->assertCount(1, $entity->getSocialIssues()); - $this->assertContains($grandGrandChild, $entity->getSocialIssues()); - - } - public function testPreUpdateAccompanyingPeriod() { $arraySocialIssues = [ @@ -101,40 +110,40 @@ class AccompanyingPeriodSocialIssueConsistencyEntityListenerTest extends TestCas $this->assertSame($grandGrandChild, $period->getSocialIssues()->first()); } + protected function generateClass(AccompanyingPeriod $period, Collection $socialIssues): AccompanyingPeriodLinkedWithSocialIssuesEntityInterface + { + return new class($period, $socialIssues) implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface { + public Collection $socialIssues; + + public AccompanyingPeriod $period; + + public function __construct($period, $socialIssues) + { + $this->period = $period; + $this->socialIssues = $socialIssues; + } + + public function getAccompanyingPeriod(): AccompanyingPeriod + { + return $this->period; + } + + public function getSocialIssues(): Collection + { + return $this->socialIssues; + } + + public function removeSocialIssue(SocialIssue $issue): AccompanyingPeriodLinkedWithSocialIssuesEntityInterface + { + $this->socialIssues->removeElement($issue); + + return $this; + } + }; + } + protected function generateLifecycleArgs(): LifecycleEventArgs { return $this->createMock(LifecycleEventArgs::class); } - - protected function generateClass(AccompanyingPeriod $period, Collection $socialIssues): AccompanyingPeriodLinkedWithSocialIssuesEntityInterface - { - return new class($period, $socialIssues) implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterface - { - public Collection $socialIssues; - public AccompanyingPeriod $period; - - public function __construct($period, $socialIssues) - { - $this->period = $period; - $this->socialIssues = $socialIssues; - } - - public function getAccompanyingPeriod(): AccompanyingPeriod - { - return $this->period; - } - - public function getSocialIssues(): Collection - { - return $this->socialIssues; - } - - public function removeSocialIssue(SocialIssue $issue): AccompanyingPeriodLinkedWithSocialIssuesEntityInterface - { - $this->socialIssues->removeElement($issue); - - return $this; - } - }; - } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php index 78376b8bd..3d92f8760 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php @@ -1,57 +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\PersonBundle\Tests\Controller; - -use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; +use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; +use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; use Chill\ThirdPartyBundle\Entity\ThirdParty; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\Center; -use Doctrine\Common\Collections\Criteria; +use DateTime; use Doctrine\ORM\EntityManagerInterface; +use Iterator; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpFoundation\Request; -use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; +use function array_map; +use function array_pop; +use function array_rand; +use function json_decode; +use function json_encode; /** - * Test api for AccompanyingCourseControllerTest + * Test api for AccompanyingCourseControllerTest. + * + * @internal + * @coversNothing */ class AccompanyingCourseApiControllerTest extends WebTestCase { protected static EntityManagerInterface $em; - protected ?int $personId = NULL; + protected ?AccompanyingPeriod $period = null; - protected ?AccompanyingPeriod $period = NULL; + protected ?int $periodId = null; - protected ?int $periodId = NULL; + protected ?int $personId = null; /** - * 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() { @@ -59,44 +53,308 @@ class AccompanyingCourseApiControllerTest extends WebTestCase } /** - * 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', + ]); + } + + public function dataGenerateNewAccompanyingCourse() + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + + $period = new AccompanyingPeriod(new DateTime('1 week ago')); + $user = $em->getRepository(User::class) + ->findOneByUsernameCanonical('center a_social'); + $period->setCreatedBy($user); + //$period->setCreatedAt(new \DateTime('yesterday')); + + $center = $em->getRepository(Center::class) + ->findOneBy(['name' => 'Center A']); + + $personIds = $em->createQuery('SELECT p.id FROM ' . + Person::class . ' p ' . + ' WHERE p.center = :center') + ->setParameter('center', $center) + ->setMaxResults(100) + ->getScalarResult(); + + // create a random order + shuffle($personIds); + + for ($i = 0; 2 > $i; ++$i) { + $person = $em->getRepository(Person::class)->find(array_pop($personIds)); + $period->addPerson($person); + } + + $em->persist($period); + $em->flush(); + + yield [$period]; + } + + 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 + // + // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) + $maxGenerated = 3; + $maxResults = $maxGenerated * 8; + + static::bootKernel(); + $em = static::$container->get(EntityManagerInterface::class); + $center = $em->getRepository(Center::class) + ->findOneBy(['name' => 'Center A']); + + $qb = $em->createQueryBuilder(); + $personIds = $qb + ->select('p.id') + ->distinct(true) + ->from(Person::class, 'p') + ->join('p.accompanyingPeriodParticipations', 'participation') + ->join('participation.accompanyingPeriod', 'ap') + ->where( + $qb->expr()->eq( + 'p.center', + ':center' + ) + ) + ->andWhere( + $qb->expr()->gt( + 'SIZE(p.accompanyingPeriodParticipations)', + 0 + ) + ) + ->andWhere( + $qb->expr()->eq('ap.step', ':step') + ) + ->setParameter('center', $center) + ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) + ->setMaxResults($maxResults) + ->getQuery() + ->getScalarResult(); + + // create a random order + shuffle($personIds); + + $nbGenerated = 0; + + while ($nbGenerated < $maxGenerated) { + $id = array_pop($personIds)['id']; + + $person = $em->getRepository(Person::class) + ->find($id); + $periods = $person->getAccompanyingPeriods(); + + yield [array_pop($personIds)['id'], $periods[array_rand($periods)]->getId()]; + + ++$nbGenerated; + } + } + + public function dataGenerateRandomAccompanyingCourseWithSocialIssue() + { + // 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 + // + // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) + $maxGenerated = 3; + $maxResults = $maxGenerated * 8; + + static::bootKernel(); + $em = static::$container->get(EntityManagerInterface::class); + $center = $em->getRepository(Center::class) + ->findOneBy(['name' => 'Center A']); + $qb = $em->createQueryBuilder(); + + $personIds = $qb + ->select('p.id') + ->distinct(true) + ->from(Person::class, 'p') + ->join('p.accompanyingPeriodParticipations', 'participation') + ->join('participation.accompanyingPeriod', 'ap') + ->where( + $qb->expr()->eq( + 'p.center', + ':center' + ) + ) + ->andWhere( + $qb->expr()->gt( + 'SIZE(p.accompanyingPeriodParticipations)', + 0 + ) + ) + ->andWhere( + $qb->expr()->eq('ap.step', ':step') + ) + ->setParameter('center', $center) + ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) + ->setMaxResults($maxResults) + ->getQuery() + ->getScalarResult(); + + // create a random order + shuffle($personIds); + + $socialIssues = $em->createQuery('SELECT s FROM ' . + SocialIssue::class . ' s ') + ->setMaxResults(10) + ->getResult(); + + $nbGenerated = 0; + + while ($nbGenerated < $maxGenerated) { + $id = array_pop($personIds)['id']; + + $person = $em->getRepository(Person::class) + ->find($id); + $periods = $person->getAccompanyingPeriods(); + + yield [$periods[array_rand($periods)], $socialIssues[array_rand($socialIssues)]]; + + ++$nbGenerated; + } + } + + public function dataGenerateRandomRequestorValidData(): Iterator + { + $dataLength = 2; + $maxResults = 100; + + static::bootKernel(); + $em = static::$container->get(EntityManagerInterface::class); + $center = $em->getRepository(Center::class) + ->findOneBy(['name' => 'Center A']); + $qb = $em->createQueryBuilder(); + + $personIds = $qb + ->select('p.id') + ->distinct(true) + ->from(Person::class, 'p') + ->join('p.accompanyingPeriodParticipations', 'participation') + ->join('participation.accompanyingPeriod', 'ap') + ->where( + $qb->expr()->eq( + 'p.center', + ':center' + ) + ) + ->andWhere( + $qb->expr()->gt( + 'SIZE(p.accompanyingPeriodParticipations)', + 0 + ) + ) + ->andWhere( + $qb->expr()->eq('ap.step', ':step') + ) + ->setParameter('center', $center) + ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) + ->setMaxResults($maxResults) + ->getQuery() + ->getScalarResult(); + + // create a random order + shuffle($personIds); + + $thirdPartyIds = $em->createQuery('SELECT t.id FROM ' . + ThirdParty::class . ' t ') + ->setMaxResults($maxResults) + ->getScalarResult(); + + // create a random order + shuffle($thirdPartyIds); + + $i = 0; + + while ($i <= $dataLength) { + $person = $em->getRepository(Person::class) + ->find(array_pop($personIds)['id']); + + if (count($person->getAccompanyingPeriods()) === 0) { + continue; + } + + $period = $person->getAccompanyingPeriods()[0]; + + yield [$period, array_pop($personIds)['id'], array_pop($thirdPartyIds)['id']]; + ++$i; + } } /** - * * @dataProvider dataGenerateRandomAccompanyingCourse */ - public function testAccompanyingCourseShow(int $personId, int $periodId) + public function testAccompanyingCourseAddParticipation(int $personId, int $periodId) { - $c = $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $periodId)); - $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, $periodId, - "test that the response's data contains the id of the period" + $this->client->request( + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $periodId), + [], // parameters + [], // files + [], // server parameters + json_encode(['type' => 'person', 'id' => $personId]) ); - $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(); + $data = json_decode($response->getContent(), true); - $this->assertEquals(404, $response->getStatusCode(), "Test that the response of rest api has a status code 'not found' (404)"); + $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', $periodId)); + $this->assertEquals(200, $response->getStatusCode(), 'Test that the response of rest api has a status code ok (200)'); + + $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', $periodId), + [], // parameters + [], // files + [], // server parameters + json_encode(['type' => 'person', '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']); } /** - * * @dataProvider dataGenerateRandomAccompanyingCourseWithSocialIssue */ public function testAccompanyingCourseAddRemoveSocialIssue(AccompanyingPeriod $period, SocialIssue $si) @@ -107,31 +365,82 @@ class AccompanyingCourseApiControllerTest extends WebTestCase [], [], [], - \json_encode([ 'type' => 'social_issue', 'id' => $si->getId() ]) + json_encode(['type' => 'social_issue', 'id' => $si->getId()]) ); $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); - $data = \json_decode($this->client->getResponse()->getContent(), true); + $data = json_decode($this->client->getResponse()->getContent(), true); $this->assertArrayHasKey('id', $data); $this->assertArrayHasKey('type', $data); $this->assertEquals('social_issue', $data['type']); - $this->client->request( Request::METHOD_DELETE, sprintf('/api/1.0/person/accompanying-course/%d/socialissue.json', $period->getId()), [], [], [], - \json_encode([ 'type' => 'social_issue', 'id' => $si->getId() ]) + json_encode(['type' => 'social_issue', 'id' => $si->getId()]) ); $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); } + /** + * @dataProvider dataGenerateRandomAccompanyingCourse + */ + public function testAccompanyingCourseShow(int $personId, int $periodId) + { + $c = $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $periodId)); + $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, + $periodId, + "test that the response's data contains the id of the period" + ); + $this->assertGreaterThan(0, $data->participations); + } + + /** + * @dataProvider dataGenerateRandomAccompanyingCourse + */ + public function testAccompanyingPeriodPatch(int $personId, int $periodId) + { + $period = self::$container->get(AccompanyingPeriodRepository::class) + ->find($periodId); + $initialValueEmergency = $period->isEmergency(); + $em = self::$container->get(EntityManagerInterface::class); + + $this->client->request( + Request::METHOD_PATCH, + sprintf('/api/1.0/person/accompanying-course/%d.json', $periodId), + [], // parameters + [], // files + [], // server parameters + json_encode(['type' => 'accompanying_period', 'emergency' => !$initialValueEmergency]) + ); + $response = $this->client->getResponse(); + + $this->assertEquals(200, $response->getStatusCode()); + $period = $em->getRepository(AccompanyingPeriod::class) + ->find($periodId); + $this->assertEquals(!$initialValueEmergency, $period->isEmergency()); + + // restore the initial value + $period->setEmergency($initialValueEmergency); + $em->flush(); + } + /** * @dataProvider dataGenerateRandomRequestorValidData + * + * @param mixed $personId + * @param mixed $thirdPartyId */ public function testCommentWithValidData(AccompanyingPeriod $period, $personId, $thirdPartyId) { @@ -143,10 +452,10 @@ class AccompanyingCourseApiControllerTest extends WebTestCase [], // parameters [], // files [], // server parameters - \json_encode([ 'type' => 'accompanying_period_comment', 'content' => "this is a text"]) + json_encode(['type' => 'accompanying_period_comment', 'content' => 'this is a text']) ); $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); + $data = json_decode($response->getContent(), true); $this->assertEquals(200, $response->getStatusCode()); $this->assertArrayHasKey('id', $data); @@ -157,158 +466,14 @@ class AccompanyingCourseApiControllerTest extends WebTestCase [], // parameters [], // files [], // server parameters - \json_encode([ 'type' => 'accompanying_period_comment', 'id' => $data['id']]) + json_encode(['type' => 'accompanying_period_comment', 'id' => $data['id']]) ); $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); + $data = json_decode($response->getContent(), true); $this->assertEquals(200, $response->getStatusCode()); } - /** - * @dataProvider dataGenerateRandomRequestorValidData - */ - public function testResourceWithValidData(AccompanyingPeriod $period, $personId, $thirdPartyId) - { - $em = self::$container->get(EntityManagerInterface::class); - - // post a person - $this->client->request( - Request::METHOD_POST, - sprintf('/api/1.0/person/accompanying-course/%d/resource.json', $period->getId()), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'type' => 'accompanying_period_resource', 'resource' => [ 'type' => 'person', 'id' => $personId ]]) - ); - $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertArrayHasKey('id', $data); - $this->assertEquals($personId, $data['resource']['id']); - - // check into database - $resource = $em->getRepository(Resource::class) - ->find($data['id']); - $this->assertInstanceOf(Resource::class, $resource); - $this->assertInstanceOf(Person::class, $resource->getResource()); - $this->assertEquals($personId, $resource->getResource()->getId()); - - // remove the resource - $this->client->request( - Request::METHOD_DELETE, - sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), - [], - [], - [], //server - \json_encode([ 'type' => 'accompanying_period_resource', 'id' => $resource->getId()]) - ); - $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - - // post a third party - $this->client->request( - Request::METHOD_POST, - sprintf('/api/1.0/person/accompanying-course/%d/resource.json', $period->getId()), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'type' => 'accompanying_period_resource', 'resource' => [ 'type' => 'thirdparty', 'id' => $thirdPartyId ]]) - ); - $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertArrayHasKey('id', $data); - $this->assertEquals($thirdPartyId, $data['resource']['id']); - - // check into database - $resource = $em->getRepository(Resource::class) - ->find($data['id']); - $this->assertInstanceOf(Resource::class, $resource); - $this->assertInstanceOf(ThirdParty::class, $resource->getResource()); - $this->assertEquals($thirdPartyId, $resource->getResource()->getId()); - - // remove the resource - $this->client->request( - Request::METHOD_DELETE, - sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), - [], - [], - [], //server - \json_encode([ 'type' => 'accompanying_period_resource', 'id' => $resource->getId()]) - ); - $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - } - - /** - * @dataProvider dataGenerateRandomRequestorValidData - */ - public function testRequestorWithValidData(AccompanyingPeriod $period, $personId, $thirdPartyId) - { - $em = self::$container->get(EntityManagerInterface::class); - - // post a person - $this->client->request( - Request::METHOD_POST, - sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'type' => 'person', 'id' => $personId ]) - ); - $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertArrayHasKey('id', $data); - $this->assertEquals($personId, $data['id']); - - // check into database - $period = $em->getRepository(AccompanyingPeriod::class) - ->find($period->getId()); - $this->assertInstanceOf(Person::class, $period->getRequestor()); - $this->assertEquals($personId, $period->getRequestor()->getId()); - - // post a third party - $this->client->request( - Request::METHOD_POST, - sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'type' => 'thirdparty', 'id' => $thirdPartyId ]) - ); - $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertArrayHasKey('id', $data); - $this->assertEquals($thirdPartyId, $data['id']); - - // check into database - $period = $em->getRepository(AccompanyingPeriod::class) - ->find($period->getId()); - $this->assertInstanceOf(ThirdParty::class, $period->getRequestor()); - $this->assertEquals($thirdPartyId, $period->getRequestor()->getId()); - - // remove the requestor - $this->client->request( - Request::METHOD_DELETE, - sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()) - ); - $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - - // check into database - $period = $em->getRepository(AccompanyingPeriod::class) - ->find($period->getId()); - $em->refresh($period); - $this->assertNull($period->getRequestor()); - } - /** * @dataProvider dataGenerateNewAccompanyingCourse */ @@ -339,318 +504,160 @@ class AccompanyingCourseApiControllerTest extends WebTestCase } /** + * @dataProvider dataGenerateRandomRequestorValidData * - * @dataProvider dataGenerateRandomAccompanyingCourse + * @param mixed $personId + * @param mixed $thirdPartyId */ - public function testAccompanyingPeriodPatch(int $personId, int $periodId) + public function testRequestorWithValidData(AccompanyingPeriod $period, $personId, $thirdPartyId) { - $period = self::$container->get(AccompanyingPeriodRepository::class) - ->find($periodId); - $initialValueEmergency = $period->isEmergency(); $em = self::$container->get(EntityManagerInterface::class); + // post a person $this->client->request( - Request::METHOD_PATCH, - sprintf('/api/1.0/person/accompanying-course/%d.json', $periodId), + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), [], // parameters [], // files [], // server parameters - \json_encode([ 'type' => 'accompanying_period', 'emergency' => !$initialValueEmergency ]) + json_encode(['type' => 'person', 'id' => $personId]) ); $response = $this->client->getResponse(); + $data = json_decode($response->getContent(), true); $this->assertEquals(200, $response->getStatusCode()); + $this->assertArrayHasKey('id', $data); + $this->assertEquals($personId, $data['id']); + + // check into database $period = $em->getRepository(AccompanyingPeriod::class) - ->find($periodId); - $this->assertEquals(!$initialValueEmergency, $period->isEmergency()); + ->find($period->getId()); + $this->assertInstanceOf(Person::class, $period->getRequestor()); + $this->assertEquals($personId, $period->getRequestor()->getId()); - // restore the initial value - $period->setEmergency($initialValueEmergency); - $em->flush(); - } + // post a third party + $this->client->request( + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), + [], // parameters + [], // files + [], // server parameters + json_encode(['type' => 'thirdparty', 'id' => $thirdPartyId]) + ); + $response = $this->client->getResponse(); + $data = json_decode($response->getContent(), true); - public function dataGenerateRandomRequestorValidData(): \Iterator - { - $dataLength = 2; - $maxResults = 100; + $this->assertEquals(200, $response->getStatusCode()); + $this->assertArrayHasKey('id', $data); + $this->assertEquals($thirdPartyId, $data['id']); - static::bootKernel(); - $em = static::$container->get(EntityManagerInterface::class); - $center = $em->getRepository(Center::class) - ->findOneBy(array('name' => 'Center A')); - $qb = $em->createQueryBuilder(); + // check into database + $period = $em->getRepository(AccompanyingPeriod::class) + ->find($period->getId()); + $this->assertInstanceOf(ThirdParty::class, $period->getRequestor()); + $this->assertEquals($thirdPartyId, $period->getRequestor()->getId()); - $personIds = $qb - ->select('p.id') - ->distinct(true) - ->from(Person::class, 'p') - ->join('p.accompanyingPeriodParticipations', 'participation') - ->join('participation.accompanyingPeriod', 'ap') - ->where( - $qb->expr()->eq( - 'p.center', - ':center' - ) - ) - ->andWhere( - $qb->expr()->gt( - 'SIZE(p.accompanyingPeriodParticipations)', - 0) - ) - ->andWhere( - $qb->expr()->eq('ap.step', ':step') - ) - ->setParameter('center', $center) - ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) - ->setMaxResults($maxResults) - ->getQuery() - ->getScalarResult(); + // remove the requestor + $this->client->request( + Request::METHOD_DELETE, + sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()) + ); + $response = $this->client->getResponse(); + $this->assertEquals(200, $response->getStatusCode()); - // create a random order - shuffle($personIds); - - $thirdPartyIds = $em->createQuery("SELECT t.id FROM ". - ThirdParty::class." t ") - ->setMaxResults($maxResults) - ->getScalarResult(); - - // create a random order - shuffle($thirdPartyIds); - - $i = 0; - while ($i <= $dataLength) { - $person = $em->getRepository(Person::class) - ->find(\array_pop($personIds)['id']); - - if (count($person->getAccompanyingPeriods()) === 0) { - continue; - } - - $period = $person->getAccompanyingPeriods()[0]; - - yield [$period, \array_pop($personIds)['id'], \array_pop($thirdPartyIds)['id'] ]; - $i++; - } + // check into database + $period = $em->getRepository(AccompanyingPeriod::class) + ->find($period->getId()); + $em->refresh($period); + $this->assertNull($period->getRequestor()); } /** + * @dataProvider dataGenerateRandomRequestorValidData * - * @dataProvider dataGenerateRandomAccompanyingCourse + * @param mixed $personId + * @param mixed $thirdPartyId */ - public function testAccompanyingCourseAddParticipation(int $personId, int $periodId) + public function testResourceWithValidData(AccompanyingPeriod $period, $personId, $thirdPartyId) { - $this->client->request( - Request::METHOD_POST, - sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $periodId), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'type' => 'person', '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', $periodId)); - $this->assertEquals(200, $response->getStatusCode(), "Test that the response of rest api has a status code ok (200)"); - - $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', $periodId), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'type' => 'person', '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']); - } - - public function dataGenerateRandomAccompanyingCourseWithSocialIssue() - { - // 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 - // - // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) - $maxGenerated = 3; - $maxResults = $maxGenerated * 8; - - static::bootKernel(); - $em = static::$container->get(EntityManagerInterface::class); - $center = $em->getRepository(Center::class) - ->findOneBy(array('name' => 'Center A')); - $qb = $em->createQueryBuilder(); - - $personIds = $qb - ->select('p.id') - ->distinct(true) - ->from(Person::class, 'p') - ->join('p.accompanyingPeriodParticipations', 'participation') - ->join('participation.accompanyingPeriod', 'ap') - ->where( - $qb->expr()->eq( - 'p.center', - ':center' - ) - ) - ->andWhere( - $qb->expr()->gt( - 'SIZE(p.accompanyingPeriodParticipations)', - 0) - ) - ->andWhere( - $qb->expr()->eq('ap.step', ':step') - ) - ->setParameter('center', $center) - ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) - ->setMaxResults($maxResults) - ->getQuery() - ->getScalarResult(); - - // create a random order - shuffle($personIds); - - $socialIssues = $em->createQuery("SELECT s FROM ". - SocialIssue::class." s ") - ->setMaxResults(10) - ->getResult(); - - $nbGenerated = 0; - while ($nbGenerated < $maxGenerated) { - $id = \array_pop($personIds)["id"]; - - $person = $em->getRepository(Person::class) - ->find($id); - $periods = $person->getAccompanyingPeriods(); - - yield [$periods[\array_rand($periods)], $socialIssues[\array_rand($socialIssues)] ]; - - $nbGenerated++; - } - } - - 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 - // - // Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :) - $maxGenerated = 3; - $maxResults = $maxGenerated * 8; - - static::bootKernel(); - $em = static::$container->get(EntityManagerInterface::class); - $center = $em->getRepository(Center::class) - ->findOneBy(array('name' => 'Center A')); - - $qb = $em->createQueryBuilder(); - $personIds = $qb - ->select('p.id') - ->distinct(true) - ->from(Person::class, 'p') - ->join('p.accompanyingPeriodParticipations', 'participation') - ->join('participation.accompanyingPeriod', 'ap') - ->where( - $qb->expr()->eq( - 'p.center', - ':center' - ) - ) - ->andWhere( - $qb->expr()->gt( - 'SIZE(p.accompanyingPeriodParticipations)', - 0) - ) - ->andWhere( - $qb->expr()->eq('ap.step', ':step') - ) - ->setParameter('center', $center) - ->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED) - ->setMaxResults($maxResults) - ->getQuery() - ->getScalarResult(); - - // create a random order - shuffle($personIds); - - $nbGenerated = 0; - while ($nbGenerated < $maxGenerated) { - $id = \array_pop($personIds)["id"]; - - $person = $em->getRepository(Person::class) - ->find($id); - $periods = $person->getAccompanyingPeriods(); - - yield [\array_pop($personIds)["id"], $periods[\array_rand($periods)]->getId() ]; - - $nbGenerated++; - } - } - - public function dataGenerateNewAccompanyingCourse() - { - self::bootKernel(); $em = self::$container->get(EntityManagerInterface::class); - $period = new AccompanyingPeriod(new \DateTime('1 week ago')); - $user = $em->getRepository(User::class) - ->findOneByUsernameCanonical('center a_social'); - $period->setCreatedBy($user); - //$period->setCreatedAt(new \DateTime('yesterday')); + // post a person + $this->client->request( + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/resource.json', $period->getId()), + [], // parameters + [], // files + [], // server parameters + json_encode(['type' => 'accompanying_period_resource', 'resource' => ['type' => 'person', 'id' => $personId]]) + ); + $response = $this->client->getResponse(); + $data = json_decode($response->getContent(), true); - $center = $em->getRepository(Center::class) - ->findOneBy(array('name' => 'Center A')); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertArrayHasKey('id', $data); + $this->assertEquals($personId, $data['resource']['id']); - $personIds = $em->createQuery("SELECT p.id FROM ". - Person::class." p ". - " WHERE p.center = :center") - ->setParameter('center', $center) - ->setMaxResults(100) - ->getScalarResult(); + // check into database + $resource = $em->getRepository(Resource::class) + ->find($data['id']); + $this->assertInstanceOf(Resource::class, $resource); + $this->assertInstanceOf(Person::class, $resource->getResource()); + $this->assertEquals($personId, $resource->getResource()->getId()); - // create a random order - shuffle($personIds); + // remove the resource + $this->client->request( + Request::METHOD_DELETE, + sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), + [], + [], + [], //server + json_encode(['type' => 'accompanying_period_resource', 'id' => $resource->getId()]) + ); + $response = $this->client->getResponse(); + $this->assertEquals(200, $response->getStatusCode()); - for ($i = 0; $i<2; $i++) { - $person = $em->getRepository(Person::class)->find(\array_pop($personIds)); - $period->addPerson($person); - } + // post a third party + $this->client->request( + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/resource.json', $period->getId()), + [], // parameters + [], // files + [], // server parameters + json_encode(['type' => 'accompanying_period_resource', 'resource' => ['type' => 'thirdparty', 'id' => $thirdPartyId]]) + ); + $response = $this->client->getResponse(); + $data = json_decode($response->getContent(), true); - $em->persist($period); - $em->flush(); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertArrayHasKey('id', $data); + $this->assertEquals($thirdPartyId, $data['resource']['id']); - yield [ $period ]; + // check into database + $resource = $em->getRepository(Resource::class) + ->find($data['id']); + $this->assertInstanceOf(Resource::class, $resource); + $this->assertInstanceOf(ThirdParty::class, $resource->getResource()); + $this->assertEquals($thirdPartyId, $resource->getResource()->getId()); + + // remove the resource + $this->client->request( + Request::METHOD_DELETE, + sprintf('/api/1.0/person/accompanying-course/%d/requestor.json', $period->getId()), + [], + [], + [], //server + json_encode(['type' => 'accompanying_period_resource', 'id' => $resource->getId()]) + ); + $response = $this->client->getResponse(); + $this->assertEquals(200, $response->getStatusCode()); + } + + 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/AccompanyingCourseControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseControllerTest.php index 38f65ce45..b5a2266e9 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseControllerTest.php @@ -1,5 +1,12 @@ client = $this->getClientAuthenticated(); } + public function dataGenerateRandomUsers(): Iterator + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + + $period = new AccompanyingPeriod(new DateTime('1 week ago')); + $user = $em->getRepository(User::class) + ->findOneByUsernameCanonical('center a_social'); + $period->setCreatedBy($user); + //$period->setCreatedAt(new \DateTime('yesterday')); + + $center = $em->getRepository(Center::class) + ->findOneBy(['name' => 'Center A']); + + $personIds = $em->createQuery('SELECT p.id FROM ' . + Person::class . ' p ' . + ' WHERE p.center = :center') + ->setParameter('center', $center) + ->setMaxResults(100) + ->getScalarResult(); + + yield [array_pop($personIds), array_pop($personIds)]; + } + public function testNewWithoutUsers() { - $this->client->request('GET', '/fr/person/parcours/new'); + $this->client->request('GET', '/fr/person/parcours/new'); $this->assertResponseRedirects(); $location = $this->client->getResponse()->headers->get('Location'); - $this->assertEquals(1, \preg_match("|^\/[^\/]+\/parcours/([\d]+)/edit$|", $location)); - + $this->assertEquals(1, preg_match('|^\\/[^\\/]+\\/parcours/([\\d]+)/edit$|', $location)); } /** * @dataProvider dataGenerateRandomUsers + * + * @param mixed $personId0 + * @param mixed $personId1 */ public function testWithNewUsers($personId0, $personId1) { $this->client->request('GET', '/fr/person/parcours/new', [ 'person_id' => [ - $personId0, - $personId1 - ] - ]); + $personId0, + $personId1, + ], + ]); $this->assertResponseRedirects(); $location = $this->client->getResponse()->headers->get('Location'); $matches = []; - $this->assertEquals(1, \preg_match("|^\/[^\/]+\/parcours/([\d]+)/edit$|", $location, $matches)); + $this->assertEquals(1, preg_match('|^\\/[^\\/]+\\/parcours/([\\d]+)/edit$|', $location, $matches)); $id = $matches[1]; $period = self::$container->get(EntityManagerInterface::class) @@ -59,30 +100,4 @@ class AccompanyingCourseControllerTest extends WebTestCase $this->assertEquals(2, count($period->getParticipations())); } - - public function dataGenerateRandomUsers(): \Iterator - { - self::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); - - $period = new AccompanyingPeriod(new \DateTime('1 week ago')); - $user = $em->getRepository(User::class) - ->findOneByUsernameCanonical('center a_social'); - $period->setCreatedBy($user); - //$period->setCreatedAt(new \DateTime('yesterday')); - - $center = $em->getRepository(Center::class) - ->findOneBy(array('name' => 'Center A')); - - $personIds = $em->createQuery("SELECT p.id FROM ". - Person::class." p ". - " WHERE p.center = :center") - ->setParameter('center', $center) - ->setMaxResults(100) - ->getScalarResult(); - - yield [ \array_pop($personIds), \array_pop($personIds) ]; - } - - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php index e841f2615..e57f3f569 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 /fr/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 `.alert-danger` element present in page - * - * @todo - */ - public function testClosingCurrentPeriod() - { - $crawler = $this->client->request('GET', '/fr/person/' - .$this->person->getId().'/accompanying-period/close'); - $form = $crawler->selectButton('Clôre la période')->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( - '/fr/person/'.$this->person->getId().'/accompanying-period'), - 'the server redirects to /accompanying-period page'); - $this->assertGreaterThan(0, $this->client->followRedirect() - ->filter('.alert-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 /fr/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 `.alert-danger` element present in page - * - * @todo - */ - public function testClosingCurrentPeriodWithDateClosingBeforeOpeningFails() - { - $crawler = $this->client->request('GET', '/fr/person/' - .$this->person->getId().'/accompanying-period/close'); - - $form = $crawler->selectButton('Clôre la période')->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('.alert-danger')->count(), - "an '.alert-danger' 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', '/fr/person/' - .$this->person->getId().'/accompanying-period/create'); - + . $this->person->getId() . '/accompanying-period/create'); + $form = $crawler->selectButton('Créer une période d\'accompagnement')->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( - '/fr/person/'.$this->person->getId().'/accompanying-period'), - 'the server redirects to /accompanying-period page'); - $this->assertGreaterThan(0, $this->client->followRedirect() - ->filter('.alert-success')->count(), - "a 'success' element is shown"); + + $this->assertTrue( + $this->client->getResponse()->isRedirect( + '/fr/person/' . $this->person->getId() . '/accompanying-period' + ), + 'the server redirects to /accompanying-period page' + ); + $this->assertGreaterThan( + 0, + $this->client->followRedirect() + ->filter('.alert-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 /fr/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 `.alert-danger` element present in page + * + * @todo + */ + public function testClosingCurrentPeriod() + { + $crawler = $this->client->request('GET', '/fr/person/' + . $this->person->getId() . '/accompanying-period/close'); + + $form = $crawler->selectButton('Clôre la période')->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( + '/fr/person/' . $this->person->getId() . '/accompanying-period' + ), + 'the server redirects to /accompanying-period page' + ); + $this->assertGreaterThan( + 0, + $this->client->followRedirect() + ->filter('.alert-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 /fr/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 `.alert-danger` element present in page + * + * @todo + */ + public function testClosingCurrentPeriodWithDateClosingBeforeOpeningFails() + { + $crawler = $this->client->request('GET', '/fr/person/' + . $this->person->getId() . '/accompanying-period/close'); + + $form = $crawler->selectButton('Clôre la période')->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('.alert-danger')->count(), + "an '.alert-danger' 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', '/fr/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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) @@ -257,31 +269,164 @@ class AccompanyingPeriodControllerTest extends WebTestCase */ public function testCreatePeriodWithClosingAfterCurrentFails() { - $this->markTestSkipped("Multiple period may now cover. This test is kept ". - "in case of a configuration may add this feature again"); + $this->markTestSkipped('Multiple period may now cover. This test is kept ' . + 'in case of a configuration may add this feature again'); $crawler = $this->client->request('GET', '/fr/person/' - .$this->person->getId().'/accompanying-period/create'); - + . $this->person->getId() . '/accompanying-period/create'); + $form = $crawler->selectButton("Créer une période d'accompagnement")->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('.alert-danger')->count(), - "an 'error' element is shown"); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.alert-danger')->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', '/fr/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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', '/fr/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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', '/fr/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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 @@ -292,212 +437,66 @@ class AccompanyingPeriodControllerTest extends WebTestCase */ public function testCreatePeriodWithOpeningAndClosingAfterCurrentFails() { - $this->markTestSkipped("Multiple period may now cover. This test is kept ". - "in case of a configuration may add this feature again"); + $this->markTestSkipped('Multiple period may now cover. This test is kept ' . + 'in case of a configuration may add this feature again'); $crawler = $this->client->request('GET', '/fr/person/' - .$this->person->getId().'/accompanying-period/create'); - + . $this->person->getId() . '/accompanying-period/create'); + $form = $crawler->selectButton("Créer une période d'accompagnement")->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('.alert-danger')->count(), - "an 'error' element is shown"); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.alert-danger')->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', '/fr/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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', '/fr/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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', '/fr/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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', '/fr/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Créer une période d\'accompagnement')->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('.alert-danger')->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(); @@ -505,29 +504,91 @@ class AccompanyingPeriodControllerTest extends WebTestCase $firstPeriod = reset($periods); $lastPeriod = end($periods); - $this->markTestSkipped("From here, the test should be rewritten"); + $this->markTestSkipped('From here, the test should be rewritten'); // 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' + ); + } + + /** + * 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/HouseholdApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php index c6c935306..e1c78b361 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php @@ -1,79 +1,52 @@ getClientAuthenticated(); + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); - $client->request( - Request::METHOD_GET, - "/api/1.0/person/household/suggest/by-person/{$personId}/through-accompanying-period-participation.json" - ); + foreach ($this->toDelete as [$class, $id]) { + $obj = $em->getRepository($class)->find($id); + $em->remove($obj); + } - $this->assertResponseIsSuccessful(); - } - - /** - * @dataProvider generateHouseholdId - */ - public function testSuggestAddressByHousehold(int $householdId) - { - $client = $this->getClientAuthenticated(); - - $client->request( - Request::METHOD_GET, - "/api/1.0/person/address/suggest/by-household/{$householdId}.json" - ); - - $this->assertResponseIsSuccessful(); - } - - /** - * @dataProvider generateHouseholdAssociatedWithAddressReference - */ - public function testFindHouseholdByAddressReference(int $addressReferenceId, int $expectedHouseholdId) - { - $client = $this->getClientAuthenticated(); - - $client->request( - Request::METHOD_GET, - "/api/1.0/person/household/by-address-reference/$addressReferenceId.json" - ); - - $this->assertResponseIsSuccessful(); - $data = json_decode($client->getResponse()->getContent(), true); - $this->assertArrayHasKey('count', $data); - $this->assertArrayHasKey('results', $data); - - $householdIds = \array_map(function($r) { - return $r['id']; - }, $data['results']); - - $this->assertContains($expectedHouseholdId, $householdIds); + $em->flush(); } public function generateHouseholdAssociatedWithAddressReference() @@ -84,18 +57,17 @@ class HouseholdApiControllerTest extends WebTestCase $nbReference = $em->createQueryBuilder()->select('count(ar)')->from(AddressReference::class, 'ar') ->getQuery()->getSingleScalarResult(); $reference = $em->createQueryBuilder()->select('ar')->from(AddressReference::class, 'ar') - ->setFirstResult(\random_int(0, $nbReference)) + ->setFirstResult(random_int(0, $nbReference)) ->setMaxResults(1) ->getQuery()->getSingleResult(); $p = new Person(); $p->setFirstname('test')->setLastName('test lastname') ->setGender(Person::BOTH_GENDER) - ->setCenter($centerA) - ; + ->setCenter($centerA); $em->persist($p); $h = new Household(); $h->addMember($m = (new HouseholdMember())->setPerson($p)); - $h->addAddress(Address::createFromAddressReference($reference)->setValidFrom(new \DateTime('today'))); + $h->addAddress(Address::createFromAddressReference($reference)->setValidFrom(new DateTime('today'))); $em->persist($m); $em->persist($h); @@ -104,49 +76,12 @@ class HouseholdApiControllerTest extends WebTestCase $this->toDelete = $this->toDelete + [ [HouseholdMember::class, $m->getId()], [User::class, $p->getId()], - [Household::class, $h->getId()] + [Household::class, $h->getId()], ]; yield [$reference->getId(), $h->getId()]; } - protected function tearDown() - { - self::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); - - foreach ($this->toDelete as list($class, $id)) { - $obj = $em->getRepository($class)->find($id); - $em->remove($obj); - } - - $em->flush(); - } - - public function generatePersonId() - { - self::bootKernel(); - - $qb = self::$container->get(EntityManagerInterface::class) - ->createQueryBuilder(); - - $period = $qb - ->select('ap') - ->from(AccompanyingPeriod::class, 'ap') - ->where( - $qb->expr()->gte('SIZE(ap.participations)', 2) - ) - ->getQuery() - ->setMaxResults(1) - ->getSingleResult() - ; - - $person = $period->getParticipations() - ->first()->getPerson(); - - yield [ $person->getId() ]; - } - public function generateHouseholdId() { self::bootKernel(); @@ -165,13 +100,91 @@ class HouseholdApiControllerTest extends WebTestCase ->setParameter('center_name', 'Center A') ->setMaxResults(100) ->getQuery() - ->getResult() - ; + ->getResult(); - \shuffle($householdIds); + shuffle($householdIds); - yield [ \array_pop($householdIds)['id'] ]; - yield [ \array_pop($householdIds)['id'] ]; - yield [ \array_pop($householdIds)['id'] ]; + yield [array_pop($householdIds)['id']]; + + yield [array_pop($householdIds)['id']]; + + yield [array_pop($householdIds)['id']]; + } + + public function generatePersonId() + { + self::bootKernel(); + + $qb = self::$container->get(EntityManagerInterface::class) + ->createQueryBuilder(); + + $period = $qb + ->select('ap') + ->from(AccompanyingPeriod::class, 'ap') + ->where( + $qb->expr()->gte('SIZE(ap.participations)', 2) + ) + ->getQuery() + ->setMaxResults(1) + ->getSingleResult(); + + $person = $period->getParticipations() + ->first()->getPerson(); + + yield [$person->getId()]; + } + + /** + * @dataProvider generateHouseholdAssociatedWithAddressReference + */ + public function testFindHouseholdByAddressReference(int $addressReferenceId, int $expectedHouseholdId) + { + $client = $this->getClientAuthenticated(); + + $client->request( + Request::METHOD_GET, + "/api/1.0/person/household/by-address-reference/{$addressReferenceId}.json" + ); + + $this->assertResponseIsSuccessful(); + $data = json_decode($client->getResponse()->getContent(), true); + $this->assertArrayHasKey('count', $data); + $this->assertArrayHasKey('results', $data); + + $householdIds = array_map(function ($r) { + return $r['id']; + }, $data['results']); + + $this->assertContains($expectedHouseholdId, $householdIds); + } + + /** + * @dataProvider generateHouseholdId + */ + public function testSuggestAddressByHousehold(int $householdId) + { + $client = $this->getClientAuthenticated(); + + $client->request( + Request::METHOD_GET, + "/api/1.0/person/address/suggest/by-household/{$householdId}.json" + ); + + $this->assertResponseIsSuccessful(); + } + + /** + * @dataProvider generatePersonId + */ + public function testSuggestByAccompanyingPeriodParticipation(int $personId) + { + $client = $this->getClientAuthenticated(); + + $client->request( + Request::METHOD_GET, + "/api/1.0/person/household/suggest/by-person/{$personId}/through-accompanying-period-participation.json" + ); + + $this->assertResponseIsSuccessful(); } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdControllerTest.php index d76a2df0c..047a21888 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdControllerTest.php @@ -1,14 +1,29 @@ client = $this->getClientAuthenticated(); } - /** - * @dataProvider generateValidHouseholdIds - */ - public function testSummary($householdId) + public function generateValidHouseholdIds() { - $this->client->request( - Request::METHOD_GET, - "/fr/person/household/{$householdId}/summary" - ); + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); - $this->assertResponseIsSuccessful(); - } - - /** - * @dataProvider generateValidHouseholdIds - */ - public function testEditMetadata($householdId) - { - - $crawler = $this->client->request( - Request::METHOD_GET, - "/fr/person/household/{$householdId}/summary", - [ - 'edit' => true - ] - ); - - $this->assertResponseIsSuccessful(); - - $form = $crawler->filter('#form_household_comment_confirm') - ->form(); - - $form['household[commentMembers][comment]'] = "This is a text **generated** by automatic tests"; - $form['household[waitingForBirth]']->tick(); - $form['household[waitingForBirthDate]'] = (new \DateTime('today')) - ->add(new \DateInterval('P1M'))->format('Y-m-d'); - - $this->client->submit($form); - - $this->assertResponseRedirects("/fr/person/household/{$householdId}/summary"); + $ids = $em->createQuery( + 'SELECT DISTINCT h.id FROM ' . Household::class . ' h ' . + 'JOIN h.members m ' . + 'JOIN m.person p ' . + 'JOIN p.center c ' . + 'WHERE c.name = :center' + ) + ->setParameter('center', 'Center A') + ->setMaxResults(100) + ->getScalarResult(); + + shuffle($ids); + + yield [array_pop($ids)['id']]; + + yield [array_pop($ids)['id']]; + + yield [array_pop($ids)['id']]; } /** * @dataProvider generateValidHouseholdIds + * + * @param mixed $householdId */ public function testAddresses($householdId) { @@ -73,11 +73,12 @@ class HouseholdControllerTest extends WebTestCase ); $this->assertResponseIsSuccessful(); - } /** * @dataProvider generateValidHouseholdIds + * + * @param mixed $householdId */ public function testAddressMove($householdId) { @@ -91,26 +92,48 @@ class HouseholdControllerTest extends WebTestCase // ici, il faudrait tester la requête POST } - public function generateValidHouseholdIds() + /** + * @dataProvider generateValidHouseholdIds + * + * @param mixed $householdId + */ + public function testEditMetadata($householdId) { - self::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); + $crawler = $this->client->request( + Request::METHOD_GET, + "/fr/person/household/{$householdId}/summary", + [ + 'edit' => true, + ] + ); - $ids = $em->createQuery("SELECT DISTINCT h.id FROM ".Household::class." h ". - "JOIN h.members m ". - "JOIN m.person p ". - "JOIN p.center c ". - "WHERE c.name = :center" - ) - ->setParameter('center', "Center A") - ->setMaxResults(100) - ->getScalarResult() - ; + $this->assertResponseIsSuccessful(); - \shuffle($ids); + $form = $crawler->filter('#form_household_comment_confirm') + ->form(); - yield [ \array_pop($ids)['id'] ]; - yield [ \array_pop($ids)['id'] ]; - yield [ \array_pop($ids)['id'] ]; + $form['household[commentMembers][comment]'] = 'This is a text **generated** by automatic tests'; + $form['household[waitingForBirth]']->tick(); + $form['household[waitingForBirthDate]'] = (new DateTime('today')) + ->add(new DateInterval('P1M'))->format('Y-m-d'); + + $this->client->submit($form); + + $this->assertResponseRedirects("/fr/person/household/{$householdId}/summary"); + } + + /** + * @dataProvider generateValidHouseholdIds + * + * @param mixed $householdId + */ + public function testSummary($householdId) + { + $this->client->request( + Request::METHOD_GET, + "/fr/person/household/{$householdId}/summary" + ); + + $this->assertResponseIsSuccessful(); } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php index 9b7b97a4f..141fa2ded 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdMemberControllerTest.php @@ -1,184 +1,114 @@ getClientAuthenticated(); + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); - $client->request( - Request::METHOD_POST, - '/api/1.0/person/household/members/move.json', - [], // parameters - [], // files - [], // server - \json_encode( - [ - 'concerned' => - [ - [ - 'person' => - [ - 'type' => 'person', - 'id' => $personId - ], - 'start_date' => - [ - 'datetime' => $date->format(\DateTimeInterface::RFC3339) - ], - 'position' => - [ - 'type' => 'household_position', - 'id' => $positionId - ], - 'holder' => false, - 'comment' => "Introduced by automated test", - ], - ], - 'destination' => - [ - 'type' => 'household', - 'id' => $householdId - ] - ], - true) - ); + $membershipIds = $em->createQuery('SELECT m.id FROM ' . HouseholdMember::class . ' m ' . + 'JOIN m.person p ' . + 'JOIN p.center c ' . + 'WHERE c.name = :center AND m.endDate IS NULL') + ->setParameter('center', 'Center A') + ->getScalarResult(); - $this->assertEquals(Response::HTTP_OK, - $client->getResponse()->getStatusCode() - ); + shuffle($membershipIds); + + yield [array_pop($membershipIds)['id']]; } - /** - * @dataProvider provideValidDataMove - */ - public function testMoveMemberToNewHousehold($personId, $householdId, $positionId, \DateTimeInterface $date) + public function provideValidDataMove(): Iterator { - $client = $this->getClientAuthenticated(); + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + $yesterday = new DateTimeImmutable('yesterday'); - $client->request( - Request::METHOD_POST, - '/api/1.0/person/household/members/move.json', - [], // parameters - [], // files - [], // server - \json_encode( - [ - 'concerned' => - [ - [ - 'person' => - [ - 'type' => 'person', - 'id' => $personId - ], - 'start_date' => - [ - 'datetime' => $date->format(\DateTimeInterface::RFC3339) - ], - 'position' => - [ - 'type' => 'household_position', - 'id' => $positionId - ], - 'holder' => false, - 'comment' => "Introduced by automated test", - ], - ], - 'destination' => - [ - 'type' => 'household', - ] - ], - true) - ); + $personIds = $em->createQuery( + 'SELECT p.id FROM ' . Person::class . ' p ' . + 'JOIN p.center c ' . + 'WHERE ' . + 'c.name = :center ' + ) + ->setParameter('center', 'Center A') + ->setMaxResults(100) + ->getScalarResult(); - $this->assertEquals(Response::HTTP_OK, - $client->getResponse()->getStatusCode() - ); + shuffle($personIds); - $data = \json_decode($client->getResponse()->getContent(), true); + $household = new Household(); + $em->persist($household); + $em->flush(); - $this->assertIsArray($data); - $this->assertArrayHasKey('members', $data); - $this->assertIsArray($data['members']); - $this->assertEquals(1, count($data['members']), - "assert new household count one member"); - $this->assertArrayHasKey('person', $data['members'][0]); - $this->assertArrayHasKey('id', $data['members'][0]['person']); - $this->assertEquals($personId, $data['members'][0]['person']['id']); - } + $positions = $em->createQuery('SELECT pos.id FROM ' . Position::class . ' pos ' . + 'WHERE pos.shareHouseHold = TRUE') + ->getResult(); - /** - * @dataProvider provideValidDataMove - */ - public function testLeaveWithoutHousehold($personId, $householdId, $positionId, \DateTimeInterface $date) - { - $client = $this->getClientAuthenticated(); + $i = 0; - $client->request( - Request::METHOD_POST, - '/api/1.0/person/household/members/move.json', - [], // parameters - [], // files - [], // server - \json_encode( - [ - 'concerned' => - [ - [ - 'person' => - [ - 'type' => 'person', - 'id' => $personId - ], - 'start_date' => - [ - 'datetime' => $date->format(\DateTimeInterface::RFC3339) - ], - 'position' => - [ - 'type' => 'household_position', - 'id' => $positionId - ], - 'holder' => false, - 'comment' => "Introduced by automated test", - ], - ], - 'destination' => null - ], - true) - ); + do { + $id = array_pop($personIds)['id']; + $person = self::$container->get(EntityManagerInterface::class) + ->getRepository(Person::class) + ->find($id); - $this->assertEquals(Response::HTTP_OK, - $client->getResponse()->getStatusCode() - ); + $participation = $person->getCurrentHouseholdParticipationShareHousehold(); - $data = \json_decode($client->getResponse()->getContent(), true); + if (null == $participation + || ( + null === $participation->getEndDate() + && $participation->getStartDate() <= $yesterday + )) { + ++$i; - $this->assertEquals(null, $data); + yield [ + $id, + $household->getId(), + $positions[random_int(0, count($positions) - 1)]['id'], + new DateTimeImmutable('tomorrow'), + ]; + } + } while (1 >= $i); } /** * @dataProvider provideValidDataEditMember + * + * @param mixed $memberId */ public function testEditMember($memberId) { @@ -199,75 +129,170 @@ class HouseholdMemberControllerTest extends WebTestCase $this->assertEquals(302, $client->getResponse()->getStatusCode()); } - public function provideValidDataMove(): \Iterator + /** + * @dataProvider provideValidDataMove + * + * @param mixed $personId + * @param mixed $householdId + * @param mixed $positionId + */ + public function testLeaveWithoutHousehold($personId, $householdId, $positionId, DateTimeInterface $date) { - self::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); - $yesterday = new \DateTimeImmutable('yesterday'); + $client = $this->getClientAuthenticated(); - $personIds = $em->createQuery("SELECT p.id FROM ".Person::class." p ". - "JOIN p.center c ". - "WHERE ". - "c.name = :center " + $client->request( + Request::METHOD_POST, + '/api/1.0/person/household/members/move.json', + [], // parameters + [], // files + [], // server + json_encode( + [ + 'concerned' => [ + [ + 'person' => [ + 'type' => 'person', + 'id' => $personId, + ], + 'start_date' => [ + 'datetime' => $date->format(DateTimeInterface::RFC3339), + ], + 'position' => [ + 'type' => 'household_position', + 'id' => $positionId, + ], + 'holder' => false, + 'comment' => 'Introduced by automated test', + ], + ], + 'destination' => null, + ], + true ) - ->setParameter('center', "Center A") - ->setMaxResults(100) - ->getScalarResult() - ; + ); - \shuffle($personIds); + $this->assertEquals( + Response::HTTP_OK, + $client->getResponse()->getStatusCode() + ); - $household = new Household(); - $em->persist($household); - $em->flush(); + $data = json_decode($client->getResponse()->getContent(), true); - $positions = $em->createQuery("SELECT pos.id FROM ".Position::class." pos ". - "WHERE pos.shareHouseHold = TRUE") - ->getResult() - ; - - $i = 0; - do { - $id = \array_pop($personIds)['id']; - $person = self::$container->get(EntityManagerInterface::class) - ->getRepository(Person::Class) - ->find($id); - - $participation = $person->getCurrentHouseholdParticipationShareHousehold(); - - if (NULL == $participation || - ( - NULL === $participation->getEndDate() - && $participation->getStartDate() <= $yesterday - )) { - - $i++; - yield [ - $id, - $household->getId(), - $positions[\random_int(0, count($positions) - 1)]['id'], - new \DateTimeImmutable('tomorrow') - ]; - } - - } while ($i <= 1); + $this->assertEquals(null, $data); } - public function provideValidDataEditMember(): \Iterator + /** + * @dataProvider provideValidDataMove + * + * @param mixed $personId + * @param mixed $householdId + * @param mixed $positionId + */ + public function testMoveMember($personId, $householdId, $positionId, DateTimeInterface $date) { - self::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); + $client = $this->getClientAuthenticated(); - $membershipIds = $em->createQuery("SELECT m.id FROM ".HouseholdMember::class." m ". - "JOIN m.person p ". - "JOIN p.center c ". - "WHERE c.name = :center AND m.endDate IS NULL") - ->setParameter('center', 'Center A') - ->getScalarResult() - ; + $client->request( + Request::METHOD_POST, + '/api/1.0/person/household/members/move.json', + [], // parameters + [], // files + [], // server + json_encode( + [ + 'concerned' => [ + [ + 'person' => [ + 'type' => 'person', + 'id' => $personId, + ], + 'start_date' => [ + 'datetime' => $date->format(DateTimeInterface::RFC3339), + ], + 'position' => [ + 'type' => 'household_position', + 'id' => $positionId, + ], + 'holder' => false, + 'comment' => 'Introduced by automated test', + ], + ], + 'destination' => [ + 'type' => 'household', + 'id' => $householdId, + ], + ], + true + ) + ); - \shuffle($membershipIds); + $this->assertEquals( + Response::HTTP_OK, + $client->getResponse()->getStatusCode() + ); + } - yield [ \array_pop($membershipIds)['id'] ]; + /** + * @dataProvider provideValidDataMove + * + * @param mixed $personId + * @param mixed $householdId + * @param mixed $positionId + */ + public function testMoveMemberToNewHousehold($personId, $householdId, $positionId, DateTimeInterface $date) + { + $client = $this->getClientAuthenticated(); + + $client->request( + Request::METHOD_POST, + '/api/1.0/person/household/members/move.json', + [], // parameters + [], // files + [], // server + json_encode( + [ + 'concerned' => [ + [ + 'person' => [ + 'type' => 'person', + 'id' => $personId, + ], + 'start_date' => [ + 'datetime' => $date->format(DateTimeInterface::RFC3339), + ], + 'position' => [ + 'type' => 'household_position', + 'id' => $positionId, + ], + 'holder' => false, + 'comment' => 'Introduced by automated test', + ], + ], + 'destination' => [ + 'type' => 'household', + ], + ], + true + ) + ); + + $this->assertEquals( + Response::HTTP_OK, + $client->getResponse()->getStatusCode() + ); + + $data = json_decode($client->getResponse()->getContent(), true); + + $this->assertIsArray($data); + $this->assertArrayHasKey('members', $data); + $this->assertIsArray($data['members']); + $this->assertEquals( + 1, + count($data['members']), + 'assert new household count one member' + ); + $this->assertArrayHasKey('person', $data['members'][0]); + $this->assertArrayHasKey('id', $data['members'][0]['person']); + $this->assertEquals($personId, $data['members'][0]['person']['id']); } } 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/PersonApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonApiControllerTest.php index 23890cdb9..ef910a5c8 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonApiControllerTest.php @@ -1,52 +1,76 @@ getClientAuthenticated(); + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + $personIds = $em->createQuery('SELECT p.id FROM ' . Person::class . ' p ' . + 'JOIN p.center c ' . + 'WHERE c.name = :center') + ->setParameter('center', 'Center A') + ->setMaxResults(100) + ->getScalarResult(); - $client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json"); - $response = $client->getResponse(); + shuffle($personIds); - $this->assertEquals(403, $response->getStatusCode()); - } - - /** - * @dataProvider dataGetPersonFromCenterA - */ - public function testPersonGet($personId): void - { - $client = $this->getClientAuthenticated(); - - $client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json"); - $response = $client->getResponse(); - - $this->assertResponseIsSuccessful(); - - $data = \json_decode($client->getResponse()->getContent(), true); - - $this->assertArrayHasKey('type', $data); - $this->assertArrayHasKey('id', $data); - $this->assertEquals('person', $data['type']); - $this->assertEquals($personId, $data['id']); + yield array_pop($personIds); + + yield array_pop($personIds); + + yield array_pop($personIds); + + yield array_pop($personIds); + } + + public function dataGetPersonFromCenterB(): Iterator + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + $personIds = $em->createQuery('SELECT p.id FROM ' . Person::class . ' p ' . + 'JOIN p.center c ' . + 'WHERE c.name = :center') + ->setParameter('center', 'Center B') + ->setMaxResults(100) + ->getScalarResult(); + + shuffle($personIds); + + yield array_pop($personIds); + + yield array_pop($personIds); } /** * @dataProvider dataGetPersonFromCenterA + * + * @param mixed $personId */ public function testPersonAddressSuggestion($personId): void { @@ -59,6 +83,8 @@ class PersonApiControllerTest extends WebTestCase /** * @dataProvider dataGetPersonFromCenterB + * + * @param mixed $personId */ public function testPersonAddressSuggestionUnauthorized($personId): void { @@ -70,41 +96,40 @@ class PersonApiControllerTest extends WebTestCase $this->assertEquals(403, $response->getStatusCode()); } - public function dataGetPersonFromCenterA(): \Iterator + /** + * @dataProvider dataGetPersonFromCenterA + * + * @param mixed $personId + */ + public function testPersonGet($personId): void { - self::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); - $personIds= $em->createQuery("SELECT p.id FROM ".Person::class." p ". - "JOIN p.center c ". - "WHERE c.name = :center") - ->setParameter('center', 'Center A') - ->setMaxResults(100) - ->getScalarResult() - ; + $client = $this->getClientAuthenticated(); - \shuffle($personIds); + $client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json"); + $response = $client->getResponse(); - yield \array_pop($personIds); - yield \array_pop($personIds); - yield \array_pop($personIds); - yield \array_pop($personIds); - } + $this->assertResponseIsSuccessful(); - public function dataGetPersonFromCenterB(): \Iterator + $data = json_decode($client->getResponse()->getContent(), true); + + $this->assertArrayHasKey('type', $data); + $this->assertArrayHasKey('id', $data); + $this->assertEquals('person', $data['type']); + $this->assertEquals($personId, $data['id']); + } + + /** + * @dataProvider dataGetPersonFromCenterB + * + * @param mixed $personId + */ + public function testPersonGetUnauthorized($personId): void { - self::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); - $personIds= $em->createQuery("SELECT p.id FROM ".Person::class." p ". - "JOIN p.center c ". - "WHERE c.name = :center") - ->setParameter('center', 'Center B') - ->setMaxResults(100) - ->getScalarResult() - ; + $client = $this->getClientAuthenticated(); - \shuffle($personIds); + $client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json"); + $response = $client->getResponse(); - yield \array_pop($personIds); - yield \array_pop($personIds); - } + $this->assertEquals(403, $response->getStatusCode()); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php index 6eabc6658..d3eceb4b1 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php @@ -1,49 +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\PersonBundle\Tests\Controller; +use Chill\MainBundle\Test\PrepareClientTrait; +use DateTime; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\DomCrawler\Form; -use Chill\MainBundle\Test\PrepareClientTrait; -use Symfony\Bundle\FrameworkBundle\KernelBrowser; /** - * Test creation and deletion for persons + * Test creation and deletion for persons. + * + * @internal + * @coversNothing */ class PersonControllerCreateTest extends WebTestCase { use PrepareClientTrait; + 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.'; + private KernelBrowser $client; - 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]"; + public static function tearDownAfterClass() + { + static::bootKernel(); + $em = static::$kernel->getContainer()->get('doctrine.orm.entity_manager'); - 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."; + //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(): void { @@ -51,147 +69,84 @@ class PersonControllerCreateTest extends WebTestCase } /** - * - * @param Form $creationForm - */ - private function fillAValidCreationForm( - Form &$creationForm, - string $firstname = 'God', - string $lastname = 'Jesus' - ) { - $creationForm->get(self::FIRSTNAME_INPUT)->setValue($firstname.'_'.uniqid()); - $creationForm->get(self::LASTNAME_INPUT)->setValue($lastname.'_'.uniqid()); - $creationForm->get(self::GENDER_INPUT)->select("man"); - $date = new \DateTime('1947-02-01'); - $creationForm->get(self::BIRTHDATE_INPUT)->setValue($date->format('Y-m-d')); - - 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->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->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' + ); $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'); return $form; } - - /** - * Test the creation of a valid person. - * - * @param Form $form - * @return string The id of the created person - */ - public function testValidForm() - { - $client = $this->client; - $crawler = $client->request('GET', '/fr/person/new'); - - $form = $crawler->selectButton("Ajouter la personne")->form(); - $this->fillAValidCreationForm($form); - $client = $this->client; - $client->submit($form); - - $this->assertTrue($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$|', - $client->getHistory()->current()->getUri(), - "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); - return $regexPersonId[1]; - } - /** * Test if, for a given person if its person view page (at the url - * fr/person/$personID/general) is accessible + * fr/person/$personID/general) is accessible. * - * @param string|int $personId The is of the person + * @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"); - } - - /** - * test adding a person with a user with multi center - * 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(); - - // create a very long name to avoid collision - $this->fillAValidCreationForm($form, 'Carmela Girdana Assuntamente Castalle', 'rabbit'); - - $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"); - $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"); + $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() @@ -203,39 +158,121 @@ class PersonControllerCreateTest extends WebTestCase //test the page is loaded before continuing $this->assertTrue($client->getResponse()->isSuccessful()); - $form = $crawler->selectButton("Ajouter la personne")->form(); + $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"); + $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 = $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"); + $this->assertContains( + 'DEPARDIEU', + $client->getCrawler()->text(), + 'check that the page has detected the lastname of a person existing in database' + ); } - public static function tearDownAfterClass() + /** + * Test the creation of a valid person. + * + * @return string The id of the created person + */ + public function testValidForm() { - static::bootKernel(); - $em = static::$kernel->getContainer()->get('doctrine.orm.entity_manager'); + $client = $this->client; + $crawler = $client->request('GET', '/fr/person/new'); - //remove two people created during test - $jesus = $em->getRepository('ChillPersonBundle:Person') - ->findOneBy(array('firstName' => 'God')); - if ($jesus !== NULL) { - $em->remove($jesus); - } + $form = $crawler->selectButton('Ajouter la personne')->form(); + $this->fillAValidCreationForm($form); + $client = $this->client; + $client->submit($form); - $jesus2 = $em->getRepository('ChillPersonBundle:Person') - ->findOneBy(array('firstName' => 'roger')); - if ($jesus2 !== NULL) { - $em->remove($jesus2); - } - $em->flush(); + $this->assertTrue( + $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$|', + $client->getHistory()->current()->getUri(), + '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 + ); + + return $regexPersonId[1]; + } + + /** + * test adding a person with a user with multi center + * 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(); + + // create a very long name to avoid collision + $this->fillAValidCreationForm($form, 'Carmela Girdana Assuntamente Castalle', 'rabbit'); + + $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' + ); + $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' + ); + } + + private function fillAValidCreationForm( + Form &$creationForm, + string $firstname = 'God', + string $lastname = 'Jesus' + ) { + $creationForm->get(self::FIRSTNAME_INPUT)->setValue($firstname . '_' . uniqid()); + $creationForm->get(self::LASTNAME_INPUT)->setValue($lastname . '_' . uniqid()); + $creationForm->get(self::GENDER_INPUT)->select('man'); + $date = new DateTime('1947-02-01'); + $creationForm->get(self::BIRTHDATE_INPUT)->setValue($date->format('Y-m-d')); + + return $creationForm; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php index 7e18c7c65..9dd309be7 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php @@ -1,54 +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\Tests\Controller; -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" * + * @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 */ + /** + * @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 + * Prepare client and create a random person. */ public function setUp() { @@ -58,235 +57,23 @@ class PersonControllerUpdateTest extends WebTestCase ->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 = '/fr/person/'.$this->person->getId().'/general/edit'; - $this->viewUrl = '/fr/person/'.$this->person->getId().'/general'; + $this->editUrl = '/fr/person/' . $this->person->getId() . '/general/edit'; + $this->viewUrl = '/fr/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('Enregistrer')->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('Enregistrer') - ->form(); - //transform countries into value if needed - switch ($field) { - case 'nationality': - case 'countryOfBirth': - if (FALSE === empty($value)) { - $country = $this->em->getRepository('ChillMainBundle:Country') - ->findOneByCountryCode($value); - $transformedValue = $country->getId(); - } else { - $transformedValue = ''; - } - 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('.alert-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('Enregistrer') - ->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('Enregistrer') - ->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('.alert-danger')->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(); } ], - // reminder: this value is capitalized - ['placeOfBirth', 'A PLACE', function(Person $person) { return $person->getPlaceOfBirth(); }], - ['birthdate', '1980-12-15', function(Person $person) { return $person->getBirthdate()->format('Y-m-d'); }], - ['phonenumber', '+32123456789', 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(); }], - ); - } - - public function providesInvalidFieldsValues() - { - return array( - ['firstName', $this->getVeryLongText()], - ['lastName', $this->getVeryLongText()], - ['firstName', ''], - ['lastName', ''], - ['birthdate', 'false date'] - ); - } - public function tearDown() { $this->refreshPerson(); @@ -294,10 +81,247 @@ class PersonControllerUpdateTest extends WebTestCase $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('Enregistrer') + ->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('Enregistrer') + ->form(); + //transform countries into value if needed + switch ($field) { + case 'nationality': + case 'countryOfBirth': + if (false === empty($value)) { + $country = $this->em->getRepository('ChillMainBundle:Country') + ->findOneByCountryCode($value); + $transformedValue = $country->getId(); + } else { + $transformedValue = ''; + } + + 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('.alert-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('Enregistrer')->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('Enregistrer') + ->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('.alert-danger')->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(); }], + // reminder: this value is capitalized + ['placeOfBirth', 'A PLACE', function (Person $person) { return $person->getPlaceOfBirth(); }], + ['birthdate', '1980-12-15', function (Person $person) { return $person->getBirthdate()->format('Y-m-d'); }], + ['phonenumber', '+32123456789', 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(); }], + ]; + } + + /** + * 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() @@ -45,31 +41,38 @@ class PersonControllerViewTest extends WebTestCase ->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(); @@ -86,34 +89,29 @@ class PersonControllerViewTest extends WebTestCase /** * 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() { $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 533d4a683..76d5d124f 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewWithHiddenFieldsTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewWithHiddenFieldsTest.php @@ -1,80 +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\Tests\Controller; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\PersonBundle\Entity\Person; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +/** + * @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() { - $this->markTestSkipped("This configuration does not allow multiple environnements"); + $this->markTestSkipped('This configuration does not allow multiple environnements'); $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()); @@ -84,21 +91,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 e6d0c207f..a37632b17 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/Controller/RelationshipApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php index ac785f781..d2da9298b 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/RelationshipApiControllerTest.php @@ -1,17 +1,31 @@ client = $this->getClientAuthenticated(); } - /** - * @dataProvider personProvider - */ - public function testGetRelationshipByPerson($personId) - { - $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/relations/relationship/by-person/%d.json', $personId)); - - $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode(), 'Test to see that API response returns a status code 200'); - } - - /** - * @dataProvider relationProvider - */ - public function testPostRelationship($fromPersonId, $toPersonId, $relationId, $isReverse): void - { - $this->client->request(Request::METHOD_POST, - '/api/1.0/relations/relationship.json', - [], - [], - [], - \json_encode([ - 'type' => 'relationship', - 'fromPerson' => ['id' => $fromPersonId, 'type' => 'person'], - 'toPerson' => ['id' => $toPersonId, 'type' => 'person'], - 'relation' => ['id' => $relationId, 'type' => 'relation'], - 'reverse' => $isReverse - ])); - - $response = $this->client->getResponse(); - $this->assertEquals(200, $response->getStatusCode()); - } - - public function relationProvider(): array - { - static::bootKernel(); - $em = self::$container->get(EntityManagerInterface::class); - $countPersons = $em->createQueryBuilder() - ->select('count(p)') - ->from(Person::class, 'p') - ->join('p.center', 'c') - ->where('c.name LIKE :name') - ->setParameter('name', 'Center A') - ->getQuery() - ->getSingleScalarResult() - ; - $persons = $em->createQueryBuilder() - ->select('p') - ->from(Person::class, 'p') - ->join('p.center', 'c') - ->where('c.name LIKE :name') - ->setParameter('name', 'Center A') - ->getQuery() - ->setMaxResults(2) - ->setFirstResult(\random_int(0, $countPersons - 1)) - ->getResult() - ; - - return [ - [$persons[0]->getId(), $persons[1]->getId(), $this->getRandomRelation($em)->getId(), true], - ]; - - } - - private function getRandomRelation(EntityManagerInterface $em): Relation - { - if (null === $this->relations) { - $this->relations = $em->getRepository(Relation::class) - ->findAll(); - } - - return $this->relations[\array_rand($this->relations)]; - } - public function personProvider(): array { static::bootKernel(); @@ -115,8 +56,7 @@ class RelationshipApiControllerTest extends WebTestCase ->where('c.name LIKE :name') ->setParameter('name', 'Center A') ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); $person = $em->createQueryBuilder() ->select('p') ->from(Person::class, 'p') @@ -125,12 +65,91 @@ class RelationshipApiControllerTest extends WebTestCase ->setParameter('name', 'Center A') ->getQuery() ->setMaxResults(1) - ->setFirstResult(\random_int(0, $countPersons - 1)) - ->getSingleResult() - ; + ->setFirstResult(random_int(0, $countPersons - 1)) + ->getSingleResult(); return [ [$person->getId()], ]; } + + public function relationProvider(): array + { + static::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + $countPersons = $em->createQueryBuilder() + ->select('count(p)') + ->from(Person::class, 'p') + ->join('p.center', 'c') + ->where('c.name LIKE :name') + ->setParameter('name', 'Center A') + ->getQuery() + ->getSingleScalarResult(); + $persons = $em->createQueryBuilder() + ->select('p') + ->from(Person::class, 'p') + ->join('p.center', 'c') + ->where('c.name LIKE :name') + ->setParameter('name', 'Center A') + ->getQuery() + ->setMaxResults(2) + ->setFirstResult(random_int(0, $countPersons - 1)) + ->getResult(); + + return [ + [$persons[0]->getId(), $persons[1]->getId(), $this->getRandomRelation($em)->getId(), true], + ]; + } + + /** + * @dataProvider personProvider + * + * @param mixed $personId + */ + public function testGetRelationshipByPerson($personId) + { + $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/relations/relationship/by-person/%d.json', $personId)); + + $response = $this->client->getResponse(); + $this->assertEquals(200, $response->getStatusCode(), 'Test to see that API response returns a status code 200'); + } + + /** + * @dataProvider relationProvider + * + * @param mixed $fromPersonId + * @param mixed $toPersonId + * @param mixed $relationId + * @param mixed $isReverse + */ + public function testPostRelationship($fromPersonId, $toPersonId, $relationId, $isReverse): void + { + $this->client->request( + Request::METHOD_POST, + '/api/1.0/relations/relationship.json', + [], + [], + [], + json_encode([ + 'type' => 'relationship', + 'fromPerson' => ['id' => $fromPersonId, 'type' => 'person'], + 'toPerson' => ['id' => $toPersonId, 'type' => 'person'], + 'relation' => ['id' => $relationId, 'type' => 'relation'], + 'reverse' => $isReverse, + ]) + ); + + $response = $this->client->getResponse(); + $this->assertEquals(200, $response->getStatusCode()); + } + + private function getRandomRelation(EntityManagerInterface $em): Relation + { + if (null === $this->relations) { + $this->relations = $em->getRepository(Relation::class) + ->findAll(); + } + + return $this->relations[array_rand($this->relations)]; + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/SocialIssueApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/SocialIssueApiControllerTest.php index 36d5dca37..f6b18582f 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/SocialIssueApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/SocialIssueApiControllerTest.php @@ -1,11 +1,24 @@ getClientAuthenticated(); - $client->request(Request::METHOD_GET, '/api/1.0/person/social-work/social-issue.json'); - - $this->assertEquals(200, $client->getResponse()->getStatusCode()); - - $data = \json_decode($client->getResponse()->getContent(), true); - - $this->assertGreaterThan(0, $data['count']); - $this->assertGreaterThan(0, count($data['results'])); - - return $data; - } - /** * @depends testList */ @@ -39,17 +37,31 @@ class SocialIssueApiControllerTest extends WebTestCase { $socialIssues = $data['results']; shuffle($socialIssues); - $socialIssue = \array_pop($socialIssues); - + $socialIssue = array_pop($socialIssues); $client = $this->getClientAuthenticated(); $client->request(Request::METHOD_GET, sprintf('/api/1.0/person/social-work/social-issue/%d.json', $socialIssue['id'])); $this->assertEquals(200, $client->getResponse()->getStatusCode()); - $data = \json_decode($client->getResponse()->getContent(), true); + $data = json_decode($client->getResponse()->getContent(), true); $this->assertArrayHasKey('id', $data); $this->assertArrayHasKey('type', $data); } + + public function testList(): array + { + $client = $this->getClientAuthenticated(); + $client->request(Request::METHOD_GET, '/api/1.0/person/social-work/social-issue.json'); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + + $data = json_decode($client->getResponse()->getContent(), true); + + $this->assertGreaterThan(0, $data['count']); + $this->assertGreaterThan(0, count($data['results'])); + + return $data; + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriod/ResourceTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriod/ResourceTest.php index 2fef00ec6..7b0e4df7b 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriod/ResourceTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriod/ResourceTest.php @@ -1,12 +1,23 @@ assertNull($resource->getThirdParty()); $resource->setResource($thirdParty); - + $this->assertSame($thirdParty, $resource->getResource()); $this->assertNull($resource->getPerson()); diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php index 744cc76dc..d790599ae 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php @@ -1,39 +1,42 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person; use Chill\ThirdPartyBundle\Entity\ThirdParty; -use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; +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); @@ -45,8 +48,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); @@ -54,37 +57,53 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase $this->assertFalse($period->isClosingAfterOpening()); } - public function testClosingEqualOpening() + public function testInitialComment() { - $datetime = new \DateTime('now'); + $period = new AccompanyingPeriod(new DateTime()); + $comment = new Comment(); + $replacingComment = new Comment(); - $period = new AccompanyingPeriod($datetime); - $period->setClosingDate($datetime); + $period->setInitialComment(null); + $this->assertNull($period->getInitialComment()); - $this->assertTrue($period->isClosingAfterOpening()); - } + $period->setInitialComment($comment); + $this->assertSame($period->getInitialComment(), $comment); + $this->assertSame($period, $comment->getAccompanyingPeriod()); + $this->assertEquals(0, count($period->getComments()), 'The initial comment should not appears in the list of comments'); - public function testIsOpen() - { - $period = new AccompanyingPeriod(new \DateTime()); + $period->setInitialComment($replacingComment); + $this->assertSame($period->getInitialComment(), $replacingComment); + $this->assertSame($period, $replacingComment->getAccompanyingPeriod()); + $this->assertEquals(0, count($period->getComments()), 'The initial comment should not appears in the list of comments'); + $this->assertNull($comment->getAccompanyingPeriod()); - $this->assertTrue($period->isOpen()); + $period->setInitialComment(null); + $this->assertNull($period->getInitialComment()); + $this->assertNull($replacingComment->getAccompanyingPeriod()); + $this->assertEquals(0, count($period->getComments()), 'The initial comment should not appears in the list of comments'); } public function testIsClosed() { - $period = new AccompanyingPeriod(new \DateTime()); - $period->setClosingDate(new \DateTime('tomorrow')); + $period = new AccompanyingPeriod(new DateTime()); + $period->setClosingDate(new DateTime('tomorrow')); $this->assertFalse($period->isOpen()); } + public function testIsOpen() + { + $period = new AccompanyingPeriod(new DateTime()); + + $this->assertTrue($period->isOpen()); + } + public function testPersonPeriod() { $person = new Person(); $person2 = new Person(); $person3 = new Person(); - $period = new AccompanyingPeriod(new \DateTime()); + $period = new AccompanyingPeriod(new DateTime()); $participation0 = $period->createParticipationFor($person); $period->createParticipationFor($person2); @@ -104,7 +123,7 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase $participationL = $period->closeParticipationFor($person); $this->assertSame($participationL, $participation); - $this->assertTrue($participation->getEndDate() instanceof \DateTimeInterface); + $this->assertTrue($participation->getEndDate() instanceof DateTimeInterface); $participation = $period->getOpenParticipationContainsPerson($person); $this->assertNull($participation); @@ -125,7 +144,7 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase public function testRequestor() { - $period = new AccompanyingPeriod(new \DateTime()); + $period = new AccompanyingPeriod(new DateTime()); $person = new Person(); $thirdParty = new ThirdParty(); @@ -143,35 +162,9 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase $this->assertSame($thirdParty, $period->getRequestorThirdParty()); $this->assertSame($thirdParty, $period->getRequestor()); - $period->setRequestor(NULL); + $period->setRequestor(null); $this->assertNull($period->getRequestorThirdParty()); $this->assertNull($period->getRequestorPerson()); $this->assertNull($period->getRequestor()); } - - public function testInitialComment() - { - $period = new AccompanyingPeriod(new \DateTime()); - $comment = new Comment(); - $replacingComment = new Comment(); - - $period->setInitialComment(NULL); - $this->assertNull($period->getInitialComment()); - - $period->setInitialComment($comment); - $this->assertSame($period->getInitialComment(), $comment); - $this->assertSame($period, $comment->getAccompanyingPeriod()); - $this->assertEquals(0, count($period->getComments()), "The initial comment should not appears in the list of comments"); - - $period->setInitialComment($replacingComment); - $this->assertSame($period->getInitialComment(), $replacingComment); - $this->assertSame($period, $replacingComment->getAccompanyingPeriod()); - $this->assertEquals(0, count($period->getComments()), "The initial comment should not appears in the list of comments"); - $this->assertNull($comment->getAccompanyingPeriod()); - - $period->setInitialComment(NULL); - $this->assertNull($period->getInitialComment()); - $this->assertNull($replacingComment->getAccompanyingPeriod()); - $this->assertEquals(0, count($period->getComments()), "The initial comment should not appears in the list of comments"); - } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdMemberTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdMemberTest.php index f18a62781..d033edb6a 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdMemberTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdMemberTest.php @@ -1,34 +1,41 @@ setShareHousehold(true) - ; - $membership = (new HouseholdMember()) - ->setPosition($position) - ; - - $this->assertTrue($membership->getShareHousehold()); - } - public function testPositionDoNotSharehousehold() { $position = (new Position()) - ->setShareHousehold(false) - ; + ->setShareHousehold(false); $membership = (new HouseholdMember()) - ->setPosition($position) - ; + ->setPosition($position); $this->assertFalse($membership->getShareHousehold()); } + + public function testPositionSharehousehold() + { + $position = (new Position()) + ->setShareHousehold(true); + $membership = (new HouseholdMember()) + ->setPosition($position); + + $this->assertTrue($membership->getShareHousehold()); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php index 5b8dce6b2..de05adc59 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php @@ -1,111 +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\PersonBundle\Tests\Entity; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Entity\Household\Position; -use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\MainBundle\Entity\Address; -use DateInterval; use DateTime; -use Generator; +use DateTimeImmutable; /** - * 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() - { - $d = new \DateTime('yesterday'); - $p = new Person(); - $p->addAccompanyingPeriod(new AccompanyingPeriod($d)); - - $period = $p->getCurrentAccompanyingPeriod(); - - $this->assertInstanceOf(AccompanyingPeriod::class, $period); - $this->assertTrue($period->isOpen()); - $this->assertEquals($d, $period->getOpeningDate()); - - //close and test - $period->setClosingDate(new \DateTime('tomorrow')); - - $shouldBeNull = $p->getCurrentAccompanyingPeriod(); - $this->assertNull($shouldBeNull); - } - - /** - * Test if the getAccompanyingPeriodsOrdered function return a list of - * periods ordered ascendency. - */ - public function testAccompanyingPeriodOrderWithUnorderedAccompanyingPeriod() - { - $d = new \DateTime("2013/2/1"); - $p = new Person(); - $p->addAccompanyingPeriod(new AccompanyingPeriod($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"); + public function testAccompanyingPeriodOrderSameDateOpening() + { + $d = new DateTime('2013/2/1'); $p = new Person(); $p->addAccompanyingPeriod(new AccompanyingPeriod($d)); - $g = new \DateTime("2013/4/1"); + $g = new DateTime('2013/4/1'); $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g); $p->close($period); - $f = new \DateTime("2013/2/1"); + $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); @@ -117,23 +54,52 @@ class PersonTest extends \PHPUnit\Framework\TestCase } /** - * 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 + * Test if the getAccompanyingPeriodsOrdered function return a list of + * periods ordered ascendency. */ - public function testDateCoveringWithCoveringAccompanyingPeriod() { - $d = new \DateTime("2013/2/1"); + public function testAccompanyingPeriodOrderWithUnorderedAccompanyingPeriod() + { + $d = new DateTime('2013/2/1'); $p = new Person(); $p->addAccompanyingPeriod(new AccompanyingPeriod($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->getAccompanyingPeriodsOrdered(); + + $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. + */ + public function testDateCoveringWithCoveringAccompanyingPeriod() + { + $d = new DateTime('2013/2/1'); + $p = new Person(); + $p->addAccompanyingPeriod(new AccompanyingPeriod($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); @@ -143,25 +109,27 @@ class PersonTest extends \PHPUnit\Framework\TestCase } /** - * Test if the function checkAccompanyingPeriodIsNotCovering returns - * the good constant when two periods are collapsing : a period is open - * before an existing period + * Test the creation of an accompanying, its closure and the access to + * the current accompaniying period via the getCurrentAccompanyingPeriod + * function. */ - public function testNotOpenAFileReOpenedLater() { - $d = new \DateTime("2013/2/1"); + public function testGetCurrentAccompanyingPeriod() + { + $d = new DateTime('yesterday'); $p = new Person(); $p->addAccompanyingPeriod(new AccompanyingPeriod($d)); - $e = new \DateTime("2013/3/1"); - $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e); - $p->close($period); + $period = $p->getCurrentAccompanyingPeriod(); - $f = new \DateTime("2013/1/1"); - $p->open(new AccompanyingPeriod($f)); + $this->assertInstanceOf(AccompanyingPeriod::class, $period); + $this->assertTrue($period->isOpen()); + $this->assertEquals($d, $period->getOpeningDate()); - $r = $p->checkAccompanyingPeriodsAreNotCollapsing(); + //close and test + $period->setClosingDate(new DateTime('tomorrow')); - $this->assertEquals($r['result'], Person::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD); + $shouldBeNull = $p->getCurrentAccompanyingPeriod(); + $this->assertNull($shouldBeNull); } public function testIsSharingHousehold() @@ -174,19 +142,17 @@ class PersonTest extends \PHPUnit\Framework\TestCase ->setShareHousehold(false); $membership1 = (new HouseholdMember()) - ->setStartDate(new \DateTimeImmutable('10 years ago')) - ->setEndDate(new \DateTimeImmutable('5 years ago')) + ->setStartDate(new DateTimeImmutable('10 years ago')) + ->setEndDate(new DateTimeImmutable('5 years ago')) ->setPerson($person) - ->setPosition($positionShare) - ; + ->setPosition($positionShare); $household->addMember($membership1); $membership2 = (new HouseholdMember()) - ->setStartDate(new \DateTimeImmutable('4 years ago')) - ->setEndDate(new \DateTimeImmutable('2 years ago')) + ->setStartDate(new DateTimeImmutable('4 years ago')) + ->setEndDate(new DateTimeImmutable('2 years ago')) ->setPerson($person) - ->setPosition($positionNotShare) - ; + ->setPosition($positionNotShare); $household->addMember($membership2); $this->assertEquals(2, $person->getHouseholdParticipations() @@ -194,9 +160,33 @@ class PersonTest extends \PHPUnit\Framework\TestCase $this->assertFalse($person->isSharingHousehold()); $this->assertTrue($person->isSharingHousehold( - new \DateTimeImmutable('6 years ago'))); + new DateTimeImmutable('6 years ago') + )); $this->assertFalse($person->isSharingHousehold( - new \DateTimeImmutable('3 years ago'))); + new DateTimeImmutable('3 years ago') + )); } + /** + * 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(); + $p->addAccompanyingPeriod(new AccompanyingPeriod($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/Entity/SocialWork/SocialIssueTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialIssueTest.php index 16bff1199..01ced7760 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialIssueTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialIssueTest.php @@ -1,13 +1,42 @@ setParent($parent), + $grandChild = (new SocialIssue())->setParent($child), + $grandGrandChild = (new SocialIssue())->setParent($grandChild), + $unrelated = new SocialIssue(), + ]); + + $ancestors = SocialIssue::findAncestorSocialIssues($socialIssues); + + $this->assertCount(3, $ancestors); + $this->assertContains($parent, $ancestors); + $this->assertContains($child, $ancestors); + $this->assertContains($grandChild, $ancestors); + } + public function testIsDescendantOf() { $parent = new SocialIssue(); @@ -30,22 +59,4 @@ class SocialIssueTest extends TestCase $this->assertFalse($child->isDescendantOf($grandChild)); } - - public function testFindSocialIssuesAncestors() - { - $socialIssues = new ArrayCollection([ - $parent = new SocialIssue(), - $child = (new SocialIssue())->setParent($parent), - $grandChild = (new SocialIssue())->setParent($child), - $grandGrandChild = (new SocialIssue())->setParent($grandChild), - $unrelated = new SocialIssue(), - ]); - - $ancestors = SocialIssue::findAncestorSocialIssues($socialIssues); - - $this->assertCount(3, $ancestors); - $this->assertContains($parent, $ancestors); - $this->assertContains($child, $ancestors); - $this->assertContains($grandChild, $ancestors); - } } diff --git a/src/Bundle/ChillPersonBundle/Tests/EventListener/PersonCreateEventTest.php b/src/Bundle/ChillPersonBundle/Tests/EventListener/PersonCreateEventTest.php index fb878053f..7fac9220e 100644 --- a/src/Bundle/ChillPersonBundle/Tests/EventListener/PersonCreateEventTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/EventListener/PersonCreateEventTest.php @@ -1,16 +1,74 @@ setLabel($altname); + + $listener->prePersistAltName($personAltname); + + $this->assertEquals($altnameExpected, $personAltname->getLabel()); + } + + /** + * @dataProvider generateNames + * + * @param mixed $firstname + * @param mixed $firstnameExpected + * @param mixed $lastname + * @param mixed $lastnameExpected + */ public function testOnPrePersist($firstname, $firstnameExpected, $lastname, $lastnameExpected) { $listener = new PersonEventListener(); @@ -25,37 +83,4 @@ class PersonCreateEventTest extends TestCase $this->assertEquals($firstnameExpected, $person->getFirstName()); $this->assertEquals($lastnameExpected, $person->getLastName()); } - - /** - * @dataProvider generateAltNames - */ - public function testAltNamesOnPrePersist($altname, $altnameExpected) - { - $listener = new PersonEventListener(); - - $personAltname = new PersonAltName(); - - $personAltname->setLabel($altname); - - $listener->prePersistAltName($personAltname); - - $this->assertEquals($altnameExpected, $personAltname->getLabel()); - } - - public function generateNames(): iterator - { - yield ['émelie-marie', 'Émelie-Marie', 'lenaerts', 'LENAERTS']; - yield ['jean-marie', 'Jean-Marie', 'lenaerts', 'LENAERTS']; - yield ['vinCENT', 'Vincent', 'fastré', 'FASTRÉ']; - yield ['Vincent', 'Vincent', 'van Gogh', 'VAN GOGH']; - yield ['André marie', 'André Marie', 'Bah', 'BAH']; - } - - public function generateAltNames(): iterator - { - yield ['vinCENT', 'VINCENT']; - yield ['jean-marie', 'JEAN-MARIE']; - yield ['fastré', 'FASTRÉ']; - yield ['émile', 'ÉMILE']; - } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php index 299cc62d5..e344bd784 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php @@ -1,74 +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\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(); - - $this->aggregator = static::$container->get('chill.person.export.aggregator_age'); + + $this->aggregator = static::$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::$container - ->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::$container + ->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 724a793e3..c72459466 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/GenderAggregatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/GenderAggregatorTest.php @@ -1,70 +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\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(); - - $this->aggregator = static::$container->get('chill.person.export.aggregator_gender'); + + $this->aggregator = static::$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::$container ->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/NationalityAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregatorTest.php index 1c358530c..3d6bb9551 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregatorTest.php @@ -1,70 +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\Tests\Export\Aggregator; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class NationalityAggregatorTest extends AbstractAggregatorTest { /** - * * @var \Chill\PersonBundle\Export\Aggregator\NationalityAggregator */ private $aggregator; - + public function setUp() { static::bootKernel(); - - $this->aggregator = static::$container->get('chill.person.export.aggregator_nationality'); + + $this->aggregator = static::$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::$container ->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 8edc6e59d..18b189807 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.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\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(); - + $this->export = static::$container->get('chill.person.export.export_count_person'); } - - + public function getExport() { return $this->export; @@ -47,13 +38,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 2ca369a24..8822d5e92 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php @@ -1,61 +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\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(); + $this->export = static::$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'); - + static::$container->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - - /** - * - * {@inheritDoc} - */ + public function getExport() { return $this->export; @@ -63,26 +49,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 bf040619c..e57a5f673 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/AccompanyingPeriodFilterTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/AccompanyingPeriodFilterTest.php @@ -1,49 +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\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(); - + try { $this->filter = static::$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; @@ -51,24 +42,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::$container ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('person.firstName') ->from('ChillPersonBundle:Person', 'person'), @@ -91,9 +82,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 e580c0f20..e5f61212e 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/BirthdayFilterTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/BirthdayFilterTest.php @@ -1,45 +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\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(); - - $this->filter = static::$container->get('chill.person.export.filter_birthdate'); + + $this->filter = static::$container->get('chill.person.export.filter_birthdate'); } - - + public function getFilter() { return $this->filter; @@ -47,24 +37,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::$container ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('p.firstName') ->from('ChillPersonBundle:Person', 'p'), @@ -77,7 +67,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 2d6d7e309..91c9e213f 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/GenderFilterTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/GenderFilterTest.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\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'); - - $this->filter = static::$container->get('chill.person.export.filter_gender'); + + $this->filter = static::$container->get('chill.person.export.filter_gender'); } - - + public function getFilter() { return $this->filter; @@ -54,32 +43,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::$container ->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 6ca28bf2b..6c9832626 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Form/Type/PickPersonTypeTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Form/Type/PickPersonTypeTest.php @@ -1,178 +1,171 @@ +/** + * 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; /** - * - * + * @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() - { - $this->markTestSkipped("need to inject locale into url generator without request"); - $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() - { - $this->markTestSkipped("need to inject locale into url generator without request"); - $center = self::$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() - { - $this->markTestSkipped("need to inject locale into url generator without request"); - $centers = self::$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() { - - $this->markTestSkipped("need to inject locale into url generator without request"); + $this->markTestSkipped('need to inject locale into url generator without request'); $form = $this->formFactory - ->createBuilder(PickPersonType::class, null, array( - 'centers' => array('string') - )) - ->getForm(); + ->createBuilder(PickPersonType::class, null, [ + 'centers' => ['string'], + ]) + ->getForm(); } - - public function testWithOptionRoleInvalid() + + /** + * Test the form with an option 'centers' with an unique center + * entity (not in an array). + */ + public function testWithOptionCenter() { - $this->markTestSkipped("need to inject locale into url generator without request"); + $this->markTestSkipped('need to inject locale into url generator without request'); + $center = self::$container->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:Center') + ->findOneBy(['name' => 'Center A']); + $form = $this->formFactory - ->createBuilder(PickPersonType::class, null, array( - 'role' => new \Symfony\Component\Security\Core\Role\Role('INVALID') - )) - ->getForm(); - + ->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() + { + $this->markTestSkipped('need to inject locale into url generator without request'); + $centers = self::$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() + { + $this->markTestSkipped('need to inject locale into url generator without request'); + $form = $this->formFactory + ->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() + { + $this->markTestSkipped('need to inject locale into url generator without request'); + + $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/Household/MembersEditorTest.php b/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php index 8ef409296..482cd44b3 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php @@ -1,16 +1,26 @@ factory = new MembersEditorFactory($validator); } - public function testMovePersonWithSharedHousehold() - { - $person = new Person(); - $position = (new Position()) - ->setShareHousehold(true) - ; - $household1 = new Household(); - $household2 = new Household(); - $editor = $this->factory->createEditor($household1); - - $editor->addMovement( - \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01'), - $person, - $position); - - $persistables = $editor->getPersistable(); - $this->assertEquals(\count($persistables), 1); - - $membership1 = $persistables[0]; - $this->assertSame($household1, $membership1->getHousehold()); - $this->assertNull($membership1->getEndDate()); - - // move to another household - $date = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01'); - $editor = $this->factory->createEditor($household2); - $editor->addMovement( - $date, - $person, - $position); - - $persistables = $editor->getPersistable(); - $this->assertEquals(1, count($persistables)); - - $membership2 = $persistables[0]; - $this->assertSame($household2, $membership2->getHousehold()); - $this->assertNull($membership2->getEndDate()); - $this->assertNotNull($membership1->getEndDate(), - "assert that the membership1 is closed"); - $this->assertEquals($date, $membership1->getEndDate()); - } - public function testMovePersonWithoutSharedHousehold() { $person = new Person(); $position = (new Position()) - ->setShareHousehold(false) - ; + ->setShareHousehold(false); $household1 = new Household(); $household2 = new Household(); $editor = $this->factory->createEditor($household1); $editor->addMovement( - \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01'), + DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01'), $person, - $position); + $position + ); $persistables = $editor->getPersistable(); $this->assertEquals(1, count($persistables)); @@ -86,12 +55,13 @@ class MembersEditorTest extends TestCase $this->assertNull($membership1->getEndDate()); // move to another household - $date = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01'); + $date = DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01'); $editor = $this->factory->createEditor($household2); $editor->addMovement( $date, $person, - $position); + $position + ); $persistables = $editor->getPersistable(); $this->assertEquals(1, count($persistables)); @@ -99,7 +69,53 @@ class MembersEditorTest extends TestCase $membership2 = $person->getHouseholdParticipations()->last(); $this->assertNull($membership2->getEndDate()); $this->assertSame($household2, $membership2->getHousehold()); - $this->assertNull($membership1->getEndDate(), - "assert that the membership1 is not closed"); + $this->assertNull( + $membership1->getEndDate(), + 'assert that the membership1 is not closed' + ); + } + + public function testMovePersonWithSharedHousehold() + { + $person = new Person(); + $position = (new Position()) + ->setShareHousehold(true); + $household1 = new Household(); + $household2 = new Household(); + $editor = $this->factory->createEditor($household1); + + $editor->addMovement( + DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01'), + $person, + $position + ); + + $persistables = $editor->getPersistable(); + $this->assertEquals(\count($persistables), 1); + + $membership1 = $persistables[0]; + $this->assertSame($household1, $membership1->getHousehold()); + $this->assertNull($membership1->getEndDate()); + + // move to another household + $date = DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01'); + $editor = $this->factory->createEditor($household2); + $editor->addMovement( + $date, + $person, + $position + ); + + $persistables = $editor->getPersistable(); + $this->assertEquals(1, count($persistables)); + + $membership2 = $persistables[0]; + $this->assertSame($household2, $membership2->getHousehold()); + $this->assertNull($membership2->getEndDate()); + $this->assertNotNull( + $membership1->getEndDate(), + 'assert that the membership1 is closed' + ); + $this->assertEquals($date, $membership1->getEndDate()); } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php b/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php index 023a67231..4447b2fea 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php @@ -1,41 +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\PersonBundle\Tests\Search; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - /** - * Test Person search + * Test Person search. * + * @internal + * @coversNothing */ class PersonSearchTest extends WebTestCase { + public function testDefaultAccented() + { + $this->markTestSkipped('skipped until adapted to new fixtures'); + $crawlerSpecial = $this->generateCrawlerForSearch('@person manço'); + + $this->assertRegExp('/MANÇO/', $crawlerSpecial->filter('.list-with-period')->text()); + + $crawlerNoSpecial = $this->generateCrawlerForSearch('@person manco'); + + $this->assertRegExp('/MANÇO/', $crawlerNoSpecial->filter('.list-with-period')->text()); + + $crawlerSpecial = $this->generateCrawlerForSearch('@person Étienne'); + + $this->assertRegExp('/Étienne/', $crawlerSpecial->filter('.list-with-period')->text()); + + $crawlerNoSpecial = $this->generateCrawlerForSearch('@person etienne'); + + $this->assertRegExp('/Étienne/', $crawlerNoSpecial->filter('.list-with-period')->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->filter('.list-with-period')->text()); } @@ -44,30 +54,9 @@ class PersonSearchTest extends WebTestCase { $client = $this->getAuthenticatedClient(); - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@person Depardieu', 'name' => 'person_regular' - )); - - $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); - } - - public function testSearchByLastName() - { - $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu'); - - $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); - } - - public function testSearchByFirstNameLower() - { - $crawler = $this->generateCrawlerForSearch('@person firstname:Gérard'); - - $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); - } - - public function testSearchByFirstNamePartim() - { - $crawler = $this->generateCrawlerForSearch('@person firstname:Ger'); + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@person Depardieu', 'name' => 'person_regular', + ]); $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); } @@ -78,12 +67,19 @@ class PersonSearchTest extends WebTestCase $this->assertRegExp('/MANÇO/', $crawlerSpecial->filter('.list-with-period')->text()); - $crawlerNoSpecial = $this->generateCrawlerForSearch('@person lastname:manco'); $this->assertRegExp('/MANÇO/', $crawlerNoSpecial->filter('.list-with-period')->text()); } + public function testSearchBirthdate() + { + $crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27'); + + $this->assertRegExp('/Gérard/', $crawler->filter('.list-with-period')->text()); + $this->assertRegExp('/Bart/', $crawler->filter('.list-with-period')->text()); + } + public function testSearchByFirstName() { $crawler = $this->generateCrawlerForSearch('@person firstname:Jean'); @@ -91,6 +87,24 @@ class PersonSearchTest extends WebTestCase $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); } + public function testSearchByFirstNameAccented() + { + $crawlerSpecial = $this->generateCrawlerForSearch('@person firstname:Gérard'); + + $this->assertRegExp('/Gérard/', $crawlerSpecial->filter('.list-with-period')->text()); + + $crawlerNoSpecial = $this->generateCrawlerForSearch('@person firstname:Gerard'); + + $this->assertRegExp('/Gérard/', $crawlerNoSpecial->filter('.list-with-period')->text()); + } + + public function testSearchByFirstNameLower() + { + $crawler = $this->generateCrawlerForSearch('@person firstname:Gérard'); + + $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); + } + public function testSearchByFirstNameLower2() { $crawler = $this->generateCrawlerForSearch('@person firstname:jean'); @@ -98,6 +112,13 @@ class PersonSearchTest extends WebTestCase $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); } + public function testSearchByFirstNamePartim() + { + $crawler = $this->generateCrawlerForSearch('@person firstname:Ger'); + + $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); + } + public function testSearchByFirstNamePartim2() { $crawler = $this->generateCrawlerForSearch('@person firstname:ean'); @@ -105,51 +126,16 @@ class PersonSearchTest extends WebTestCase $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); } - public function testSearchByFirstNameAccented() + public function testSearchByLastName() { - $crawlerSpecial = $this->generateCrawlerForSearch('@person firstname:Gérard'); + $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu'); - $this->assertRegExp('/Gérard/', $crawlerSpecial->filter('.list-with-period')->text()); - - - $crawlerNoSpecial = $this->generateCrawlerForSearch('@person firstname:Gerard'); - - $this->assertRegExp('/Gérard/', $crawlerNoSpecial->filter('.list-with-period')->text()); - } - - public function testSearchCombineLastnameAndNationality() - { - $this->markTestSkipped("skipped until adapted to new fixtures"); - $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu nationality:RU'); - - $this->assertRegExp('/Gérard/', $crawler->filter('.list-with-period')->text()); - //if this is a AND clause, Jean Depardieu should not appears - $this->assertNotRegExp('/Jean/', $crawler->filter('.list-with-period')->text(), - "assert clause firstname and nationality are AND"); - } - - public function testSearchCombineLastnameAndFirstName() - { - $this->markTestSkipped("skipped until adapted to new fixtures"); - $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu firstname:Jean'); - - $this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text()); - //if this is a AND clause, Jean Depardieu should not appears - $this->assertNotRegExp('/Gérard/', $crawler->filter('.list-with-period')->text(), - "assert clause firstname and nationality are AND"); - } - - public function testSearchBirthdate() - { - $crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27'); - - $this->assertRegExp('/Gérard/', $crawler->filter('.list-with-period')->text()); - $this->assertRegExp('/Bart/', $crawler->filter('.list-with-period')->text()); + $this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text()); } public function testSearchCombineBirthdateAndLastName() { - $this->markTestSkipped("skipped until adapted to new fixtures"); + $this->markTestSkipped('skipped until adapted to new fixtures'); $crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27 lastname:(Van Snick)'); $this->assertRegExp('/Bart/', $crawler->filter('.list-with-period')->text()); @@ -158,16 +144,44 @@ class PersonSearchTest extends WebTestCase public function testSearchCombineGenderAndLastName() { - $this->markTestSkipped("skipped until adapted to new fixtures"); + $this->markTestSkipped('skipped until adapted to new fixtures'); $crawler = $this->generateCrawlerForSearch('@person gender:woman lastname:(Depardieu)'); $this->assertRegExp('/Charline/', $crawler->filter('.list-with-period')->text()); $this->assertNotRegExp('/Gérard/', $crawler->filter('.list-with-period')->text()); } + public function testSearchCombineLastnameAndFirstName() + { + $this->markTestSkipped('skipped until adapted to new fixtures'); + $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu firstname:Jean'); + + $this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text()); + //if this is a AND clause, Jean Depardieu should not appears + $this->assertNotRegExp( + '/Gérard/', + $crawler->filter('.list-with-period')->text(), + 'assert clause firstname and nationality are AND' + ); + } + + public function testSearchCombineLastnameAndNationality() + { + $this->markTestSkipped('skipped until adapted to new fixtures'); + $crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu nationality:RU'); + + $this->assertRegExp('/Gérard/', $crawler->filter('.list-with-period')->text()); + //if this is a AND clause, Jean Depardieu should not appears + $this->assertNotRegExp( + '/Jean/', + $crawler->filter('.list-with-period')->text(), + 'assert clause firstname and nationality are AND' + ); + } + public function testSearchMultipleTrigramUseAndClauseInDefault() { - $this->markTestSkipped("skipped until adapted to new fixtures"); + $this->markTestSkipped('skipped until adapted to new fixtures'); $crawler = $this->generateCrawlerForSearch('@person cha dep'); $this->assertRegExp('/Charline/', $crawler->filter('.list-with-period')->text()); @@ -175,50 +189,33 @@ class PersonSearchTest extends WebTestCase $this->assertNotRegExp('/Jean/', $crawler->filter('.list-with-period')->text()); } - public function testDefaultAccented() - { - $this->markTestSkipped("skipped until adapted to new fixtures"); - $crawlerSpecial = $this->generateCrawlerForSearch('@person manço'); - - $this->assertRegExp('/MANÇO/', $crawlerSpecial->filter('.list-with-period')->text()); - - - $crawlerNoSpecial = $this->generateCrawlerForSearch('@person manco'); - - $this->assertRegExp('/MANÇO/', $crawlerNoSpecial->filter('.list-with-period')->text()); - - $crawlerSpecial = $this->generateCrawlerForSearch('@person Étienne'); - - $this->assertRegExp('/Étienne/', $crawlerSpecial->filter('.list-with-period')->text()); - - - $crawlerNoSpecial = $this->generateCrawlerForSearch('@person etienne'); - - $this->assertRegExp('/Étienne/', $crawlerNoSpecial->filter('.list-with-period')->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('/DEPARDIEU/', $crawlerCanSee->text(), - 'center a_social may see "Depardieu" in center a'); - $this->assertNotRegExp('/DEPARDIEU/', $crawlerCannotSee->text(), - 'center b_social may not see "Depardieu" in center b'); - + $this->assertRegExp( + '/DEPARDIEU/', + $crawlerCanSee->text(), + 'center a_social may see "Depardieu" in center a' + ); + $this->assertNotRegExp( + '/DEPARDIEU/', + $crawlerCannotSee->text(), + 'center b_social may not see "Depardieu" in 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()); @@ -226,14 +223,15 @@ class PersonSearchTest extends WebTestCase } /** + * @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 09f6cc2ba..c7ae0d4d4 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::$container - ->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/Serializer/Normalizer/HouseholdNormalizerTest.php b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php index 9dd348c82..75a3802c7 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/HouseholdNormalizerTest.php @@ -1,16 +1,26 @@ normalizer= self::$container->get(NormalizerInterface::class); + $this->normalizer = self::$container->get(NormalizerInterface::class); } public function testNormalizationRecursive() @@ -28,21 +38,22 @@ class HouseholdNormalizerTest extends KernelTestCase $household = new Household(); $position = (new Position()) ->setShareHousehold(true) - ->setAllowHolder(true) - ; + ->setAllowHolder(true); $member->setPerson($person) - ->setStartDate(new \DateTimeImmutable('1 year ago')) - ->setEndDate(new \DateTimeImmutable('1 month ago')); + ->setStartDate(new DateTimeImmutable('1 year ago')) + ->setEndDate(new DateTimeImmutable('1 month ago')); $household->addMember($member); - $normalized = $this->normalizer->normalize($household, - 'json', [ 'groups' => [ 'read' ]]); + $normalized = $this->normalizer->normalize( + $household, + 'json', + ['groups' => ['read']] + ); $this->assertIsArray($normalized); $this->assertArrayHasKey('type', $normalized); $this->assertEquals('household', $normalized['type']); } - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php index 96a744913..34ac0e674 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php @@ -1,53 +1,25 @@ normalizer = self::$container->get(NormalizerInterface::class); - } - - /** - * @dataProvider generateData - */ - public function testNormalize(?Person $person, $expected, $msg) - { - $normalized = $this->normalizer->normalize($person, 'docgen', ['docgen:expects' => Person::class]); - - $this->assertEquals($expected, $normalized, $msg); - } - - public function generateData() - { - $person = new Person(); - $person - ->setFirstName('Renaud') - ->setLastName('Mégane') - ; - - $expected = \array_merge( - self::BLANK, ['firstname' => 'Renaud', 'lastname' => 'Mégane', - 'text' => 'Renaud Mégane'] - ); - - yield [$person, $expected, 'partial normalization for a person']; - - yield [null, self::BLANK, 'normalization for a null person']; - } - - private const BLANK = [ 'firstname' => '', 'lastname' => '', @@ -65,7 +37,46 @@ class PersonDocGenNormalizerTest extends KernelTestCase 'nationality' => '', 'placeOfBirth' => '', 'memo' => '', - 'numberOfChildren' => '' + 'numberOfChildren' => '', ]; + private NormalizerInterface $normalizer; + + protected function setUp() + { + self::bootKernel(); + + $this->normalizer = self::$container->get(NormalizerInterface::class); + } + + public function generateData() + { + $person = new Person(); + $person + ->setFirstName('Renaud') + ->setLastName('Mégane'); + + $expected = array_merge( + self::BLANK, + ['firstname' => 'Renaud', 'lastname' => 'Mégane', + 'text' => 'Renaud Mégane', ] + ); + + yield [$person, $expected, 'partial normalization for a person']; + + yield [null, self::BLANK, 'normalization for a null person']; + } + + /** + * @dataProvider generateData + * + * @param mixed $expected + * @param mixed $msg + */ + public function testNormalize(?Person $person, $expected, $msg) + { + $normalized = $this->normalizer->normalize($person, 'docgen', ['docgen:expects' => Person::class]); + + $this->assertEquals($expected, $normalized, $msg); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonJsonNormalizerTest.php b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonJsonNormalizerTest.php index 4839d84f5..349af455b 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonJsonNormalizerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonJsonNormalizerTest.php @@ -1,13 +1,23 @@ normalizer->normalize($person, 'json', [AbstractNormalizer::GROUPS => [ 'read' ]]); + $result = $this->normalizer->normalize($person, 'json', [AbstractNormalizer::GROUPS => ['read']]); $this->assertIsArray($result); } diff --git a/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php index 92be039be..a10b47c94 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php @@ -1,67 +1,38 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. 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\FrameworkBundle\Test\WebTestCase; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Doctrine\ORM\EntityManagerInterface; use Chill\MainBundle\Test\PrepareClientTrait; +use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use function array_pop; +use function shuffle; /** * This class tests entries are shown for closing and opening * periods in timeline. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class TimelineAccompanyingPeriodTest extends WebTestCase { use PrepareClientTrait; - /** - * @dataProvider provideDataPersonWithAccompanyingPeriod - */ - public function testEntriesAreShown($personId) - { - $client = $this->getClientAuthenticated(); - - $crawler = $client->request('GET', "/en/person/{$personId}/timeline"); - - $this->assertTrue($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("est ouvert", - $crawler->filter('.timeline')->text(), - "the text 'est ouvert' is present"); - } - public function provideDataPersonWithAccompanyingPeriod() { self::bootKernel(); $qb = self::$container->get(EntityManagerInterface::class) - ->createQueryBuilder() - ; + ->createQueryBuilder(); $personIds = $qb ->from(Person::class, 'p') ->join('p.accompanyingPeriodParticipations', 'part') @@ -72,15 +43,41 @@ class TimelineAccompanyingPeriodTest extends WebTestCase ->setParameter('center', 'Center A') ->setMaxResults(1000) ->getQuery() - ->getResult() - ; + ->getResult(); - \shuffle($personIds); + shuffle($personIds); - yield [ \array_pop($personIds)['id'] ]; - yield [ \array_pop($personIds)['id'] ]; - yield [ \array_pop($personIds)['id'] ]; + yield [array_pop($personIds)['id']]; + yield [array_pop($personIds)['id']]; + + yield [array_pop($personIds)['id']]; } + /** + * @dataProvider provideDataPersonWithAccompanyingPeriod + * + * @param mixed $personId + */ + public function testEntriesAreShown($personId) + { + $client = $this->getClientAuthenticated(); + + $crawler = $client->request('GET', "/en/person/{$personId}/timeline"); + + $this->assertTrue( + $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( + 'est ouvert', + $crawler->filter('.timeline')->text(), + "the text 'est ouvert' is present" + ); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/AccompanyingPeriod/LocationValidityValidatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/AccompanyingPeriod/LocationValidityValidatorTest.php index b70a8146b..2b4217c3a 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/AccompanyingPeriod/LocationValidityValidatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/AccompanyingPeriod/LocationValidityValidatorTest.php @@ -1,29 +1,62 @@ getConstraint(); $period = new AccompanyingPeriod(); - $person = new Person(); - $period->addPerson($person); - - $period->setPersonLocation($person); + $person1 = new Person(); + $period->setPersonLocation($person1); $this->validator->validate($period, $constraint); - $this->assertNoViolation(); + $this->buildViolation('messagePersonLocatedMustBeAssociated') + ->setParameters([ + '{{ person_name }}' => 'name', + ]) + ->assertRaised(); + } + + public function testPeriodDoesNotContainsPersonOnOtherPerson() + { + $constraint = $this->getConstraint(); + + $period = new AccompanyingPeriod(); + $person1 = new Person(); + $person2 = new Person(); + $period->addPerson($person1); + + $period->setPersonLocation($person2); + + $this->validator->validate($period, $constraint); + + $this->buildViolation('messagePersonLocatedMustBeAssociated') + ->setParameters([ + '{{ person_name }}' => 'name', + ]) + ->assertRaised(); } public function testPeriodDoesNotContainsPersonOnRemovedPerson() @@ -41,50 +74,10 @@ class LocationValidityValidatorTest extends ConstraintValidatorTestCase $this->validator->validate($period, $constraint); $this->buildViolation('messagePersonLocatedMustBeAssociated') - ->setParameters([ - '{{ person_name }}' => 'name' - ]) - ->assertRaised() - ; - } - - public function testPeriodDoesNotContainsPersonOnOtherPerson() - { - $constraint = $this->getConstraint(); - - $period = new AccompanyingPeriod(); - $person1 = new Person(); - $person2 = new Person(); - $period->addPerson($person1); - - $period->setPersonLocation($person2); - - $this->validator->validate($period, $constraint); - - $this->buildViolation('messagePersonLocatedMustBeAssociated') - ->setParameters([ - '{{ person_name }}' => 'name' - ]) - ->assertRaised() - ; - } - - public function testPeriodDoesNotContainsPersonOnAnyPerson() - { - $constraint = $this->getConstraint(); - - $period = new AccompanyingPeriod(); - $person1 = new Person(); - $period->setPersonLocation($person1); - - $this->validator->validate($period, $constraint); - - $this->buildViolation('messagePersonLocatedMustBeAssociated') - ->setParameters([ - '{{ person_name }}' => 'name' - ]) - ->assertRaised() - ; + ->setParameters([ + '{{ person_name }}' => 'name', + ]) + ->assertRaised(); } public function testRemoveLocationOnPeriodValidated() @@ -97,26 +90,38 @@ class LocationValidityValidatorTest extends ConstraintValidatorTestCase $this->validator->validate($period, $constraint); $this->buildViolation('messagePeriodMustRemainsLocated') - ->assertRaised() - ; + ->assertRaised(); + } + + public function testValidAddress() + { + $constraint = $this->getConstraint(); + + $period = new AccompanyingPeriod(); + $person = new Person(); + $period->addPerson($person); + + $period->setPersonLocation($person); + + $this->validator->validate($period, $constraint); + + $this->assertNoViolation(); + } + + protected function createValidator() + { + $render = $this->createMock(PersonRender::class); + $render->method('renderString') + ->willReturn('name'); + + return new LocationValidityValidator($render); } protected function getConstraint() { return new LocationValidity([ 'messagePersonLocatedMustBeAssociated' => 'messagePersonLocatedMustBeAssociated', - 'messagePeriodMustRemainsLocated' => 'messagePeriodMustRemainsLocated' + 'messagePeriodMustRemainsLocated' => 'messagePeriodMustRemainsLocated', ]); } - - protected function createValidator() - { - $render= $this->createMock(PersonRender::class); - $render->method('renderString') - ->willReturn('name') - ; - - return new LocationValidityValidator($render); - } - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/Household/HouseholdMembershipSequentialValidatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/Household/HouseholdMembershipSequentialValidatorTest.php index fad902e73..d79112d01 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/Household/HouseholdMembershipSequentialValidatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/Household/HouseholdMembershipSequentialValidatorTest.php @@ -1,16 +1,28 @@ validator->validate($person, $constraint); - + $this->assertNoViolation(); } @@ -31,18 +43,15 @@ class HouseholdMembershipSequentialValidatorTest extends ConstraintValidatorTest $person = new Person(); $household = new Household(); $position = (new Position()) - ->setShareHousehold(true) - ; + ->setShareHousehold(true); $membership = (new HouseholdMember()) ->setPosition($position) - ->setStartDate(new \DateTimeImmutable('2010-01-01')) - ->setPerson($person) - ; + ->setStartDate(new DateTimeImmutable('2010-01-01')) + ->setPerson($person); $membership = (new HouseholdMember()) ->setPosition($position) - ->setStartDate(new \DateTimeImmutable('2011-01-01')) - ->setPerson($person) - ; + ->setStartDate(new DateTimeImmutable('2011-01-01')) + ->setPerson($person); $this->validator->validate($person, $constraint); @@ -50,10 +59,9 @@ class HouseholdMembershipSequentialValidatorTest extends ConstraintValidatorTest ->setParameters([ '%person_name%' => 'name', '%from%' => '01-01-2011', - '%nbHousehold%' => 2 + '%nbHousehold%' => 2, ]) - ->assertRaised() - ; + ->assertRaised(); } public function testMembershipCoveringNoShareHousehold() @@ -63,38 +71,34 @@ class HouseholdMembershipSequentialValidatorTest extends ConstraintValidatorTest $person = new Person(); $household = new Household(); $position = (new Position()) - ->setShareHousehold(false) - ; + ->setShareHousehold(false); $membership = (new HouseholdMember()) ->setPosition($position) - ->setStartDate(new \DateTimeImmutable('2010-01-01')) - ->setPerson($person) - ; + ->setStartDate(new DateTimeImmutable('2010-01-01')) + ->setPerson($person); $membership = (new HouseholdMember()) ->setPosition($position) - ->setStartDate(new \DateTimeImmutable('2011-01-01')) - ->setPerson($person) - ; + ->setStartDate(new DateTimeImmutable('2011-01-01')) + ->setPerson($person); $this->validator->validate($person, $constraint); $this->assertNoViolation(); } - protected function getConstraint() - { - return new HouseholdMembershipSequential([ - 'message' => 'msg' - ]); - } - protected function createValidator() { $render = $this->createMock(PersonRender::class); $render->method('renderString') - ->willReturn('name') - ; + ->willReturn('name'); return new HouseholdMembershipSequentialValidator($render); - } + } + + protected function getConstraint() + { + return new HouseholdMembershipSequential([ + 'message' => 'msg', + ]); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/Household/MaxHolderValidatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/Household/MaxHolderValidatorTest.php index 02b03eb33..aca79b011 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/Household/MaxHolderValidatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/Household/MaxHolderValidatorTest.php @@ -1,39 +1,28 @@ getConstraint(); - - $this->validator->validate($household, $constraint); - - $this->buildViolation('msg') - ->setParameters($parameters) - ->assertRaised() - ; - } - - protected function getConstraint() - { - return new MaxHolder([ - 'message' => 'msg', - 'messageInfinity' => 'msgInfinity' - ]); - } - public function provideInvalidHousehold() { $household = new Household(); @@ -43,34 +32,57 @@ class MaxHolderValidatorTest extends ConstraintValidatorTestCase ->addMember( (new HouseholdMember()) ->setHolder(true) - ->setStartDate(new \DateTimeImmutable('2010-01-01')) - ->setEndDate(new \DateTimeImmutable('2010-12-01')) - ) + ->setStartDate(new DateTimeImmutable('2010-01-01')) + ->setEndDate(new DateTimeImmutable('2010-12-01')) + ) ->addMember( (new HouseholdMember()) ->setHolder(true) - ->setStartDate(new \DateTimeImmutable('2010-06-01')) - ->setEndDate(new \DateTimeImmutable('2010-07-01')) - ) + ->setStartDate(new DateTimeImmutable('2010-06-01')) + ->setEndDate(new DateTimeImmutable('2010-07-01')) + ) ->addMember( (new HouseholdMember()) ->setHolder(true) - ->setStartDate(new \DateTimeImmutable('2010-01-01')) - ->setEndDate(new \DateTimeImmutable('2010-12-01')) - ) - ; + ->setStartDate(new DateTimeImmutable('2010-01-01')) + ->setEndDate(new DateTimeImmutable('2010-12-01')) + ); yield [ - $household, + $household, [ - '{{ start }}' => '01-06-2010', - '{{ end }}' => '01-07-2010' - ] + '{{ start }}' => '01-06-2010', + '{{ end }}' => '01-07-2010', + ], ]; } + /** + * @dataProvider provideInvalidHousehold + * + * @param mixed $parameters + */ + public function testHouseholdInvalid(Household $household, $parameters) + { + $constraint = $this->getConstraint(); + + $this->validator->validate($household, $constraint); + + $this->buildViolation('msg') + ->setParameters($parameters) + ->assertRaised(); + } + protected function createValidator() { return new MaxHolderValidator(); } + + protected function getConstraint() + { + return new MaxHolder([ + 'message' => 'msg', + 'messageInfinity' => 'msgInfinity', + ]); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/BirthdateValidatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/BirthdateValidatorTest.php index 6c726dd1c..bc2e0e3cc 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/BirthdateValidatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/BirthdateValidatorTest.php @@ -1,74 +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\Validator\Person; -use Chill\PersonBundle\Validator\Constraints\Person\BirthdateValidator; use Chill\PersonBundle\Validator\Constraints\Person\Birthdate; +use Chill\PersonBundle\Validator\Constraints\Person\BirthdateValidator; +use DateTime; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; -use Chill\PersonBundle\Entity\Person; /** - * Test the behaviour of BirthdayValidator + * Test the behaviour of BirthdayValidator. * - * @author Julien Fastré + * @internal + * @coversNothing */ class BirthdateValidatorTest extends ConstraintValidatorTestCase { + public function testTomorrowInvalid() + { + $bornAfter = new DateTime('+2 days'); + $this->validator->validate($bornAfter, $this->createConstraint()); + $this->buildViolation('msg') + ->setParameter('%date%', (new DateTime('yesterday'))->format('d-m-Y')) + ->setCode('3f42fd96-0b2d-11ec-8cf3-0f3b1b1ca1c4') + ->assertRaised(); + } public function testValidateTodayInvalid() { - $bornToday = new \DateTime('now'); + $bornToday = new DateTime('now'); $this->validator->validate($bornToday, $this->createConstraint()); $this->buildViolation('msg') - ->setParameter('%date%', (new \DateTime('yesterday'))->format('d-m-Y')) + ->setParameter('%date%', (new DateTime('yesterday'))->format('d-m-Y')) ->setCode('3f42fd96-0b2d-11ec-8cf3-0f3b1b1ca1c4') ->assertRaised(); } public function testValidateYesterdayValid() { - $bornYesterday = new \DateTime('yesterday'); + $bornYesterday = new DateTime('yesterday'); $this->validator->validate($bornYesterday, $this->createConstraint()); $this->assertNoViolation(); } - public function testTomorrowInvalid() - { - $bornAfter = new \DateTime('+2 days'); - $this->validator->validate($bornAfter, $this->createConstraint()); - $this->buildViolation('msg') - ->setParameter('%date%', (new \DateTime('yesterday'))->format('d-m-Y')) - ->setCode('3f42fd96-0b2d-11ec-8cf3-0f3b1b1ca1c4') - ->assertRaised(); - } - - private function createConstraint() - { - return new Birthdate([ - 'message' => 'msg' - ]); - } - - protected function createValidator() { return new BirthdateValidator('P1D'); } + + private function createConstraint() + { + return new Birthdate([ + 'message' => 'msg', + ]); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php index a237b3571..5d1bbeb9e 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php @@ -1,17 +1,28 @@ assertRaised(); } - protected function getConstraint() - { - return new PersonHasCenter([ - 'message' => 'msg' - ]); - } - protected function createValidator() { $parameterBag = $this->createMock(ParameterBagInterface::class); @@ -44,12 +48,19 @@ class PersonHasCenterValidatorTest extends ConstraintValidatorTestCase ->with($this->equalTo('chill_person')) ->willReturn([ 'validation' => [ - 'center_required' => true - ] + 'center_required' => true, + ], ]); - $centerResolverDispatcher = $this->createMock(CenterResolverDispatcher::class); + $centerResolverDispatcher = $this->createMock(CenterResolverDispatcherInterface::class); return new PersonHasCenterValidator($parameterBag, $centerResolverDispatcher); } + + protected function getConstraint() + { + return new PersonHasCenter([ + 'message' => 'msg', + ]); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonValidationTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonValidationTest.php index 8d6c930d9..e6ea0bb67 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonValidationTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonValidationTest.php @@ -1,13 +1,26 @@ validator = self::$container->get(ValidatorInterface::class); } - public function testFirstnameValidation() - { - $person = (new Person()) - ->setFirstname(\str_repeat('a', 500)); - $errors = $this->validator->validate($person, null, ["creation"]); - foreach ($errors->getIterator() as $error) { - if (Length::TOO_LONG_ERROR === $error->getCode()) { - $this->assertTrue(true, - "error code for firstname too long is present"); - return; - } - } - $this->assertTrue(false, - "error code for fistname too long is present"); - - } - public function testBirthdateInFuture() { $person = (new Person()) - ->setBirthdate(new \Datetime('+2 months')); - $errors = $this->validator->validate($person, null, ["creation"]); + ->setBirthdate(new Datetime('+2 months')); + $errors = $this->validator->validate($person, null, ['creation']); + foreach ($errors->getIterator() as $error) { if (Birthdate::BIRTHDATE_INVALID_CODE === $error->getCode()) { - $this->assertTrue(true, - "error code for birthdate invalid is present"); + $this->assertTrue( + true, + 'error code for birthdate invalid is present' + ); + return; } } - $this->assertTrue(false, - "error code for birthdate invalid is present"); - + $this->assertTrue( + false, + 'error code for birthdate invalid is present' + ); } + public function testFirstnameValidation() + { + $person = (new Person()) + ->setFirstname(str_repeat('a', 500)); + $errors = $this->validator->validate($person, null, ['creation']); + + foreach ($errors->getIterator() as $error) { + if (Length::TOO_LONG_ERROR === $error->getCode()) { + $this->assertTrue( + true, + 'error code for firstname too long is present' + ); + + return; + } + } + $this->assertTrue( + false, + 'error code for fistname too long is present' + ); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php b/src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php index df86d79a6..8a149c7d3 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php +++ b/src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php @@ -1,14 +1,25 @@ get(Registry::class); - $period = new AccompanyingPeriod(new \DateTime('now')); + $period = new AccompanyingPeriod(new DateTime('now')); $workflow = $registry->get($period); $this->assertArrayHasKey('DRAFT', $workflow->getMarking($period)->getPlaces()); $this->assertTrue($workflow->can($period, 'confirm')); } - } 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 Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; -use Chill\MainBundle\Entity\Center; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Symfony\Component\Security\Core\Security; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\MainBundle\Timeline\TimelineSingleQuery; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Doctrine\ORM\EntityManager; +use LogicException; +use Symfony\Component\Security\Core\Security; +use function implode; +use function in_array; /** - * 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) - * */ abstract class AbstractTimelineAccompanyingPeriod implements TimelineProviderInterface { - protected EntityManager $em; + private const SUPPORTED_CONTEXTS = ['person', 'center']; - private Security $security; + protected EntityManager $em; private AuthorizationHelper $authorizationHelper; - private const SUPPORTED_CONTEXTS = [ 'person', 'center' ]; - + private Security $security; + public function __construct(EntityManager $em, Security $security, AuthorizationHelper $authorizationHelper) { $this->em = $em; @@ -54,53 +45,96 @@ abstract class AbstractTimelineAccompanyingPeriod implements TimelineProviderInt $this->authorizationHelper = $authorizationHelper; } - /** - * - * {@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 (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) { - throw new \LogicException('TimelineAccompanyingPeriod is not able ' - . 'to render context '.$context); + if (false === in_array($context, self::SUPPORTED_CONTEXTS)) { + throw new LogicException('TimelineAccompanyingPeriod is not able ' + . 'to render context ' . $context); } - + $metadata = $this->em - ->getClassMetadata(AccompanyingPeriod::class) - ; + ->getClassMetadata(AccompanyingPeriod::class); [$where, $parameters] = $this->buildWhereClause($context, $args); return TimelineSingleQuery::fromArray([ 'id' => "{$metadata->getTableName()}.{$metadata->getColumnName('id')}", 'FROM' => $this->buildFromClause($context), 'WHERE' => $where, - 'parameters' => $parameters + 'parameters' => $parameters, ]); } + protected function buildWhereClause($context, array $args): array + { + $participation = $this->em->getClassMetadata(AccompanyingPeriodParticipation::class); + $join = $participation->getAssociationMapping('person')['joinColumns'][0]; + $person = $this->em->getClassMetadata(Person::class); + $joinCenter = $person->getAssociationMapping('center')['joinColumns'][0]; + + if ('center' === $context) { + $allowedCenters = $this->authorizationHelper->filterReachableCenters($this->security->getUser(), $args['centers'], PersonVoter::SEE); + $params = []; + $questionMarks = []; + $query = "{$person->getTableName()}.{$joinCenter['name']} IN ("; + + foreach ($allowedCenters as $c) { + $questionMarks[] = '?'; + $params[] = $c->getId(); + } + $query .= implode(', ', $questionMarks) . ')'; + + return [$query, $params]; + } + + if ('person' === $context) { + return ["{$participation->getTableName()}.{$join['name']} = ?", [$args['person']->getId()]]; + } + + throw new LogicException("this context is not supported: {$context}"); + } + + /** + * return the expected response for TimelineProviderInterface::getEntityTemplate. + * + * @param string $template the template for rendering + * @param mixed $entity + * @param string $context + * + * @return array + */ + protected function getBasicEntityTemplate($template, $entity, $context, array $args) + { + return [ + 'template' => $template, + 'template_data' => ['period' => $entity, 'context' => $context], + ]; + } + private function buildFromClause($context) { $period = $this->em->getClassMetadata(AccompanyingPeriod::class); @@ -109,64 +143,19 @@ abstract class AbstractTimelineAccompanyingPeriod implements TimelineProviderInt $join = $participation->getAssociationMapping('accompanyingPeriod')['joinColumns'][0]; $joinPerson = $participation->getAssociationMapping('person')['joinColumns'][0]; - if ($context === 'person') { - return "{$period->getTableName()} ". - "JOIN {$participation->getTableName()} ". - "ON {$participation->getTableName()}.{$join['name']} = ". + if ('person' === $context) { + return "{$period->getTableName()} " . + "JOIN {$participation->getTableName()} " . + "ON {$participation->getTableName()}.{$join['name']} = " . "{$period->getTableName()}.{$join['referencedColumnName']}"; - } else { - return "{$period->getTableName()} ". - "JOIN {$participation->getTableName()} ". - "ON {$participation->getTableName()}.{$join['name']} = ". - "{$period->getTableName()}.{$join['referencedColumnName']} ". - "JOIN {$person->getTableName()} ". - "ON {$participation->getTableName()}.{$joinPerson['name']} = ". - "{$person->getTableName()}.{$joinPerson['referencedColumnName']}" - ; } - } - - protected function buildWhereClause($context, array $args): array - { - $participation = $this->em->getClassMetadata(AccompanyingPeriodParticipation::class); - $join = $participation->getAssociationMapping('person')['joinColumns'][0]; - $person = $this->em->getClassMetadata(Person::class); - $joinCenter = $person->getAssociationMapping('center')['joinColumns'][0]; - - if ($context === 'center') { - $allowedCenters = $this->authorizationHelper->filterReachableCenters($this->security->getUser(), $args['centers'], PersonVoter::SEE); - $params = []; - $questionMarks = []; - $query = "{$person->getTableName()}.{$joinCenter['name']} IN ("; - foreach ($allowedCenters as $c) { - $questionMarks[] = '?'; - $params[] = $c->getId(); - } - $query .= \implode(", ", $questionMarks).")"; - - return [$query, $params]; - } elseif ($context === 'person') { - return [ "{$participation->getTableName()}.{$join['name']} = ?", [ $args['person']->getId() ]]; - } - - throw new \LogicException("this context is not supported: $context"); - } - - /** - * 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( - 'template' => $template, - 'template_data' => ['period' => $entity, 'context' => $context] - ); + return "{$period->getTableName()} " . + "JOIN {$participation->getTableName()} " . + "ON {$participation->getTableName()}.{$join['name']} = " . + "{$period->getTableName()}.{$join['referencedColumnName']} " . + "JOIN {$person->getTableName()} " . + "ON {$participation->getTableName()}.{$joinPerson['name']} = " . + "{$person->getTableName()}.{$joinPerson['referencedColumnName']}"; } } diff --git a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php index c873b6405..becca4ddb 100644 --- a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php +++ b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php @@ -1,84 +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\PersonBundle\Timeline; -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManager; use Chill\PersonBundle\Entity\AccompanyingPeriod; /** - * Provide information for opening periods to timeline + * 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(AccompanyingPeriod::class); - + ->getClassMetadata(AccompanyingPeriod::class); + $query = $this->basicFetchQuery($context, $args); [$where, $parameters] = $this->buildWhereClause($context, $args); $query->setKey('accompanying_period_closing') ->setDate($metadata->getColumnName('closingDate')) ->setWhere($where) - ->setParameters($parameters) - ; - + ->setParameters($parameters); + return $query; } + public function getEntityTemplate($entity, $context, array $args) + { + return $this->getBasicEntityTemplate( + 'ChillPersonBundle:Timeline:closing_period.html.twig', + $entity, + $context, + $args + ); + } + + public function supportsType($type) + { + return 'accompanying_period_closing' === $type; + } + protected function buildWhereClause($context, array $args): array { - list($query, $params) = parent::buildWhereClause($context, $args); + [$query, $params] = parent::buildWhereClause($context, $args); $period = $this->em->getClassMetadata(AccompanyingPeriod::class); $query .= " AND {$period->getColumnName('closingDate')} IS NOT NULL "; - return [ $query, $params ]; - } - - /** - * - * {@inheritDoc} - */ - public function getEntityTemplate($entity, $context, array $args) - { - return $this->getBasicEntityTemplate( - 'ChillPersonBundle:Timeline:closing_period.html.twig', - $entity, - $context, - $args - ); + return [$query, $params]; } } diff --git a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php index 04b3df5b8..e4d24fbed 100644 --- a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php +++ b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php @@ -1,71 +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\Timeline; -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManager; use Chill\PersonBundle\Entity\AccompanyingPeriod; /** - * Provide information for opening periods to timeline + * 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(AccompanyingPeriod::class); - + ->getClassMetadata(AccompanyingPeriod::class); + $query = $this->basicFetchQuery($context, $args); - + $query->setKey('accompanying_period_opening') ->setDate($metadata->getColumnName('openingDate')); - + return $query; } - /** - * - * {@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/AccompanyingPeriod/LocationValidity.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidity.php index b1b660596..326e37a49 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidity.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidity.php @@ -1,5 +1,12 @@ getLocationStatus() === 'person') { if (null === $period->getOpenParticipationContainsPerson( - $period->getPersonLocation())) { + $period->getPersonLocation() + )) { $this->context->buildViolation($constraint->messagePersonLocatedMustBeAssociated) - ->setParameter('{{ person_name }}', $this->render->renderString( - $period->getPersonLocation(), [] - )) - ->addViolation() - ; + ->setParameter('{{ person_name }}', $this->render->renderString( + $period->getPersonLocation(), + [] + )) + ->addViolation(); } } if ($period->getStep() !== AccompanyingPeriod::STEP_DRAFT && $period->getLocationStatus() === 'none') { $this->context - ->buildViolation( - $constraint->messagePeriodMustRemainsLocated - ) - ->addViolation() - ; + ->buildViolation( + $constraint->messagePeriodMustRemainsLocated + ) + ->addViolation(); } - } } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php index 38d5516b5..e7bc4ea93 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ParticipationOverlap.php @@ -1,15 +1,22 @@ getPerson()->getId(); $participationList[$personId][] = $participation; - } foreach ($participationList as $group) { @@ -55,19 +60,18 @@ class ParticipationOverlapValidator extends ConstraintValidator $overlaps->compute(); if ($overlaps->hasIntersections()) { - foreach ($overlaps->getIntersections() as list($start, $end, $ids)) { - $msg = $end === null ? $constraint->message : + foreach ($overlaps->getIntersections() as [$start, $end, $ids]) { + $msg = null === $end ? $constraint->message : $constraint->message; $this->context->buildViolation($msg) ->setParameters([ '{{ start }}' => $start->format('d-m-Y'), - '{{ end }}' => $end === null ? null : $end->format('d-m-Y'), + '{{ end }}' => null === $end ? null : $end->format('d-m-Y'), '{{ ids }}' => $ids, ]) ->addViolation(); } } - } } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php index bfc9d62af..4619b37f9 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/ResourceDuplicateCheck.php @@ -1,11 +1,18 @@ getResource() instanceof Person ? 'p' : - 't').$resource->getResource()->getId(); + 't') . $resource->getResource()->getId(); - if (\in_array($id, $resourceList, true)) { + if (in_array($id, $resourceList, true)) { $this->context->buildViolation($constraint->message) - ->setParameter('{{ name }}', $resource->getResource() instanceof Person ? $this->personRender->renderString($resource->getResource(), []) : + ->setParameter('{{ name }}', $resource->getResource() instanceof Person ? $this->personRender->renderString($resource->getResource(), []) : $this->thirdpartyRender->renderString($resource->getResource(), [])) ->addViolation(); } $resourceList[] = $id; - } - } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/HouseholdMembershipSequential.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/HouseholdMembershipSequential.php index 00d9e3306..8c194ac41 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/HouseholdMembershipSequential.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/HouseholdMembershipSequential.php @@ -1,5 +1,12 @@ compute(); if ($covers->hasIntersections()) { - foreach ($covers->getIntersections() as list($start, $end, $metadata)) { + foreach ($covers->getIntersections() as [$start, $end, $metadata]) { $participation = $participations[$metadata[0]]; $nbHousehold = count($metadata); @@ -53,15 +59,14 @@ class HouseholdMembershipSequentialValidator extends ConstraintValidator ->buildViolation($constraint->message) ->setParameters([ '%person_name%' => $this->render->renderString( - $participation->getPerson(), [] + $participation->getPerson(), + [] ), // TODO when date is correctly i18n, fix this '%from%' => $start->format('d-m-Y'), '%nbHousehold%' => $nbHousehold, - ]) - ->addViolation() - ; + ->addViolation(); } } } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/MaxHolder.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/MaxHolder.php index 62ddc2420..047cacf05 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/MaxHolder.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Household/MaxHolder.php @@ -1,5 +1,12 @@ getStartDate()->getTimezone()); + $covers = new DateRangeCovering( + self::MAX_HOLDERS, + $holders[0]->getStartDate()->getTimezone() + ); foreach ($holders as $key => $member) { $covers->add($member->getStartDate(), $member->getEndDate(), $key); @@ -30,18 +37,17 @@ class MaxHolderValidator extends ConstraintValidator $covers->compute(); if ($covers->hasIntersections()) { - foreach ($covers->getIntersections() as list($start, $end, $ids)) { - $msg = $end === null ? $constraint->messageInfinity : + foreach ($covers->getIntersections() as [$start, $end, $ids]) { + $msg = null === $end ? $constraint->messageInfinity : $constraint->message; $this->context->buildViolation($msg) ->setParameters([ '{{ start }}' => $start->format('d-m-Y'), // TODO fix when MessageParameter works with timezone - '{{ end }}' => $end === null ? null : $end->format('d-m-Y') + '{{ end }}' => null === $end ? null : $end->format('d-m-Y'), ]) ->addViolation(); } } - } } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/Birthdate.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/Birthdate.php index 20f3ed97b..ab0a413a5 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/Birthdate.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/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\Person; @@ -35,5 +25,5 @@ class Birthdate extends Constraint { public const BIRTHDATE_INVALID_CODE = '3f42fd96-0b2d-11ec-8cf3-0f3b1b1ca1c4'; - public $message = "The birthdate must be before %date%"; + public $message = 'The birthdate must be before %date%'; } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/BirthdateValidator.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/BirthdateValidator.php index 238a3d160..f49a4b24e 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/BirthdateValidator.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/BirthdateValidator.php @@ -1,35 +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\Validator\Constraints\Person; +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) { @@ -38,13 +26,12 @@ class BirthdateValidator extends ConstraintValidator 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))); } @@ -56,21 +43,19 @@ class BirthdateValidator extends ConstraintValidator ->setCode(Birthdate::BIRTHDATE_INVALID_CODE) ->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/Validator/Constraints/Person/PersonHasCenter.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenter.php index 5cabd8838..8e7b8642a 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenter.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenter.php @@ -1,5 +1,12 @@ centerRequired = $parameterBag->get('chill_person')['validation']['center_required']; $this->centerResolverDispatcher = $centerResolverDispatcher; } - /** - * @inheritDoc - */ public function validate($person, Constraint $constraint) { if (!$person instanceof Person) { @@ -32,13 +40,12 @@ class PersonHasCenterValidator extends \Symfony\Component\Validator\ConstraintVa return; } - if (NULL === $this->centerResolverDispatcher->resolveCenter($person)) { + if (null === $this->centerResolverDispatcher->resolveCenter($person)) { $this ->context ->buildViolation($constraint->message) ->atPath('center') - ->addViolation() - ; + ->addViolation(); } } } 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 f1a631882..b95c17259 100644 --- a/src/Bundle/ChillPersonBundle/Widget/PersonListWidget.php +++ b/src/Bundle/ChillPersonBundle/Widget/PersonListWidget.php @@ -1,5 +1,12 @@ personRepository = $personRepostory; $this->authorizationHelper = $authorizationHelper; @@ -52,26 +60,24 @@ class PersonListWidget implements WidgetInterface } /** - * @param array $context - * @param array $config + * @param mixed $place */ 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 @@ -81,19 +87,22 @@ 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(), Types::DATE_MUTABLE); + $qb->setParameter('now', new DateTime(), Types::DATE_MUTABLE); } + if (array_key_exists('filtering_class', $config) && null !== $config['filtering_class']) { + $filteringClass = new $config['filtering_class'](); - 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 (!$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, @@ -109,8 +118,7 @@ class PersonListWidget implements WidgetInterface // ordering the query by lastname, firstname $qb->addOrderBy('person.lastName', 'ASC') - ->addOrderBy('person.firstName', 'ASC'); - + ->addOrderBy('person.firstName', 'ASC'); $qb->setFirstResult(0)->setMaxResults($numberOfItems); @@ -118,14 +126,15 @@ class PersonListWidget implements WidgetInterface // 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; } } @@ -133,31 +142,29 @@ class PersonListWidget implements WidgetInterface return $env->render( 'ChillPersonBundle:Widget:homepage_person_list.html.twig', - array( + [ 'persons' => $persons, - 'customFields' => $cfields - - ) - ); + 'customFields' => $cfields, + ] + ); } private function getUser(): UserInterface { $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 === null) { - throw new \RuntimeException( + if (null === $user) { + throw new RuntimeException( 'The user should implement UserInterface. Are you logged in ?' ); } return $user; } - } diff --git a/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.php b/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.php index b21151b83..b3a94e19f 100644 --- a/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.php +++ b/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.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\PersonBundle\Widget\PersonListWidget; -use Doctrine\ORM\EntityManager; use Chill\MainBundle\Entity\User; +use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\User\UserInterface; - /** * 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: @@ -37,7 +25,6 @@ use Symfony\Component\Security\Core\User\UserInterface; * # where \FQDN\To\Class implements PersonFiltering * class_filtering: \FQDN\To\Class * ``` - * */ interface PersonFilteringInterface { @@ -57,27 +44,27 @@ interface PersonFilteringInterface * * 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', Types::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', Types::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(); + * } + * } * ``` * * @return int[] an array of persons id to show 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/config/services/controller.yaml b/src/Bundle/ChillPersonBundle/config/services/controller.yaml index 369fe63bb..fb31e8ee9 100644 --- a/src/Bundle/ChillPersonBundle/config/services/controller.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/controller.yaml @@ -32,11 +32,8 @@ services: tags: ['controller.service_arguments'] Chill\PersonBundle\Controller\AccompanyingCourseController: - arguments: - $serializer: '@Symfony\Component\Serializer\SerializerInterface' - $dispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' - $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface' - $workRepository: '@Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository' + autoconfigure: true + autowire: true tags: ['controller.service_arguments'] Chill\PersonBundle\Controller\AccompanyingCourseApiController: 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 a7384e2f4..2206e463f 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20150607231010.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20150607231010.php @@ -1,58 +1,23 @@ abortIf( - $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.' - ); - - $this->addSql('ALTER TABLE person ADD center_id INT'); - - // retrieve center for setting a default center - $stmt = $this->connection->executeQuery("SELECT id FROM centers ORDER BY id ASC LIMIT 1"); - $center = $stmt->fetchOne(); - - if ($center !== false) { - $defaultCenterId = $center['id']; - } - - if (isset($defaultCenterId)) { - $this->addSql('UPDATE person SET center_id = :id', array('id' => $defaultCenterId)); - } - - // this will fail if a person is defined, which should not happen any more at this - // time of writing (2021-11-09) - $this->addSql('ALTER TABLE person ALTER center_id SET NOT NULL'); - $this->addSql('ALTER TABLE person ' - . 'ADD CONSTRAINT FK_person_center FOREIGN KEY (center_id) ' - . 'REFERENCES centers (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE INDEX IDX_person_center ON person (center_id)'); - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { $this->abortIf( @@ -64,4 +29,40 @@ class Version20150607231010 extends AbstractMigration $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.'; + } + + 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 ADD center_id INT'); + + // retrieve center for setting a default center + $stmt = $this->connection->executeQuery('SELECT id FROM centers ORDER BY id ASC LIMIT 1'); + $center = $stmt->fetchOne(); + + if (false !== $center) { + $defaultCenterId = $center['id']; + } + + if (isset($defaultCenterId)) { + $this->addSql('UPDATE person SET center_id = :id', ['id' => $defaultCenterId]); + } + + // this will fail if a person is defined, which should not happen any more at this + // time of writing (2021-11-09) + $this->addSql('ALTER TABLE person ALTER center_id SET NOT NULL'); + $this->addSql('ALTER TABLE person ' + . 'ADD CONSTRAINT FK_person_center FOREIGN KEY (center_id) ' + . 'REFERENCES centers (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_person_center ON person (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 52d4b0e88..7232a8dac 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\'.'); @@ -19,12 +36,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 89828f862..cdf9d3374 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 NULL'); } - - public function down(Schema $schema) : void - { - } } 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/ChillPersonBundle/migrations/Version20210518075908.php b/src/Bundle/ChillPersonBundle/migrations/Version20210518075908.php index e2806e761..7b3517c19 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210518075908.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210518075908.php @@ -1,5 +1,12 @@ addSql('DROP TABLE chill_person_accompanying_period_social_issues'); + } + public function getDescription(): string { return 'Add a link between social issue and accompanying period'; @@ -25,9 +37,4 @@ final class Version20210518075908 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period_social_issues ADD CONSTRAINT FK_CAFE078F550B0C53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_person_accompanying_period_social_issues ADD CONSTRAINT FK_CAFE078FA549916C FOREIGN KEY (socialissue_id) REFERENCES chill_person_social_issue (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP TABLE chill_person_accompanying_period_social_issues'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210518162439.php b/src/Bundle/ChillPersonBundle/migrations/Version20210518162439.php index 6907a64c6..210d35008 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210518162439.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210518162439.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period DROP initialComment_id'); + } + public function getDescription(): string { return 'Add a column "initial comment" in accompanying period'; @@ -23,9 +35,4 @@ final class Version20210518162439 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A8683111D50B FOREIGN KEY (initialComment_id) REFERENCES chill_person_accompanying_period_comment (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_E260A8683111D50B ON chill_person_accompanying_period (initialComment_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP initialComment_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210519204938.php b/src/Bundle/ChillPersonBundle/migrations/Version20210519204938.php index c71f7b203..c2c9333fc 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210519204938.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210519204938.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period DROP createdAt'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP updatedAt'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP updatedBy_id'); + } + public function getDescription(): string { return 'Add updatedAt, updatedBy, createdAt on accompanying period'; @@ -25,11 +39,4 @@ final class Version20210519204938 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A86865FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_E260A86865FF1AEC ON chill_person_accompanying_period (updatedBy_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP createdAt'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP updatedAt'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP updatedBy_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210525211214.php b/src/Bundle/ChillPersonBundle/migrations/Version20210525211214.php index 15df9386e..6953689b0 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210525211214.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210525211214.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period_comment DROP CONSTRAINT fk_cd960ef3d7fa8ef0'); + $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'); + } + public function getDescription(): string { return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables'; @@ -22,10 +35,4 @@ final class Version20210525211214 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period_comment DROP CONSTRAINT FK_CD960EF3D7FA8EF0'); $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF3D7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period_comment DROP CONSTRAINT fk_cd960ef3d7fa8ef0'); - $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'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210528092625.php b/src/Bundle/ChillPersonBundle/migrations/Version20210528092625.php index 1ce855140..ad261b59a 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210528092625.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210528092625.php @@ -1,5 +1,12 @@ throwIrreversibleMigrationException('the down method is not implemented'); + } + public function getDescription(): string { return 'prefix table concerning household with \'chill_person\' and add constraints'; @@ -37,13 +49,13 @@ final class Version20210528092625 extends AbstractMigration // create constraint 'householdmembers not overlaps' $this->addSql('ALTER TABLE chill_person_household_members ADD CHECK (startdate < enddate)'); - $this->addSql('ALTER TABLE chill_person_household_members ADD CONSTRAINT '. - "household_members_not_overlaps EXCLUDE USING GIST( + $this->addSql('ALTER TABLE chill_person_household_members ADD CONSTRAINT ' . + 'household_members_not_overlaps EXCLUDE USING GIST( -- extension btree_gist required to include comparaison with integer person_id WITH =, daterange(startdate, enddate) WITH && ) WHERE (sharedhousehold IS TRUE) - INITIALLY DEFERRED"); + INITIALLY DEFERRED'); // rename constraints $this->addSql('ALTER TABLE public.chill_person_household_to_addresses DROP CONSTRAINT fk_7109483e79ff843'); @@ -55,9 +67,4 @@ final class Version20210528092625 extends AbstractMigration $this->addSql('ALTER INDEX idx_4d1fb288e79ff843 RENAME TO IDX_EEF5DED7E79FF843'); $this->addSql('ALTER INDEX idx_4d1fb288217bbb47 RENAME TO IDX_EEF5DED7217BBB47'); } - - public function down(Schema $schema): void - { - $this->throwIrreversibleMigrationException("the down method is not implemented"); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210528111624.php b/src/Bundle/ChillPersonBundle/migrations/Version20210528111624.php index 2228d42c3..9e90da31a 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210528111624.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210528111624.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_household_members DROP CONSTRAINT FK_EEF5DED7DD842E46'); + $this->addSql('DROP SEQUENCE chill_person_household_position_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_household_position'); + $this->addSql('ALTER TABLE chill_person_household_members ADD "position" VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_household_members DROP position_id'); + } + public function getDescription(): string { return 'Add position to househould_member'; @@ -21,19 +37,10 @@ final class Version20210528111624 extends AbstractMigration { $this->addSql('CREATE SEQUENCE chill_person_household_position_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE chill_person_household_position (id INT NOT NULL, label JSON NOT NULL, shareHouseHold BOOLEAN NOT NULL, allowHolder BOOLEAN NOT NULL, ordering DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))'); - + $this->addSql('ALTER TABLE chill_person_household_members ADD position_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE chill_person_household_members DROP "position"'); $this->addSql('ALTER TABLE chill_person_household_members ADD CONSTRAINT FK_EEF5DED7DD842E46 FOREIGN KEY (position_id) REFERENCES chill_person_household_position (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_EEF5DED7DD842E46 ON chill_person_household_members (position_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_household_members DROP CONSTRAINT FK_EEF5DED7DD842E46'); - $this->addSql('DROP SEQUENCE chill_person_household_position_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_household_position'); - $this->addSql('ALTER TABLE chill_person_household_members ADD "position" VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_household_members DROP position_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210528132405.php b/src/Bundle/ChillPersonBundle/migrations/Version20210528132405.php index f9e94532a..926bf605a 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210528132405.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210528132405.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_household_members ALTER startDate SET NOT NULL'); + $this->addSql('ALTER TABLE chill_person_household_members ALTER endDate SET NOT NULL'); + } + public function getDescription(): string { return 'Household members: allow startdate and enddate to be null'; @@ -22,10 +35,4 @@ final class Version20210528132405 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_household_members ALTER startdate DROP NOT NULL'); $this->addSql('ALTER TABLE chill_person_household_members ALTER enddate DROP NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_household_members ALTER startDate SET NOT NULL'); - $this->addSql('ALTER TABLE chill_person_household_members ALTER endDate SET NOT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210528142121.php b/src/Bundle/ChillPersonBundle/migrations/Version20210528142121.php index 4eaf149af..e1a39b258 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210528142121.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210528142121.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_household_members DROP COLUMN holder'); + } + public function getDescription(): string { return 'Add house holder on membership'; @@ -21,9 +33,4 @@ final class Version20210528142121 extends AbstractMigration { $this->addSql('ALTER TABLE chill_person_household_members ADD holder BOOLEAN DEFAULT FALSE NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_household_members DROP COLUMN holder'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210614191600.php b/src/Bundle/ChillPersonBundle/migrations/Version20210614191600.php index 991ed49fd..37f740e09 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210614191600.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210614191600.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_household DROP comment_members'); + $this->addSql('ALTER TABLE chill_person_household DROP waiting_for_birth'); + $this->addSql('ALTER TABLE chill_person_household DROP waiting_for_birth_date'); + } + public function getDescription(): string { return 'Add comments and expecting birth to household'; @@ -24,11 +38,4 @@ final class Version20210614191600 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_household ADD waiting_for_birth_date DATE DEFAULT NULL'); $this->addSql('COMMENT ON COLUMN chill_person_household.waiting_for_birth_date IS \'(DC2Type:date_immutable)\''); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_household DROP comment_members'); - $this->addSql('ALTER TABLE chill_person_household DROP waiting_for_birth'); - $this->addSql('ALTER TABLE chill_person_household DROP waiting_for_birth_date'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210615074857.php b/src/Bundle/ChillPersonBundle/migrations/Version20210615074857.php index d2024b0b5..97926c02a 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210615074857.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210615074857.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_household RENAME comment_members_comment TO comment_members'); + $this->addSql('ALTER TABLE chill_person_household ALTER comment_members SET DEFAULT \'\''); + $this->addSql('ALTER TABLE chill_person_household ALTER comment_members SET NOT NULL'); + $this->addSql('ALTER TABLE chill_person_household DROP comment_members_comment'); + $this->addSql('ALTER TABLE chill_person_household DROP comment_members_userId'); + $this->addSql('ALTER TABLE chill_person_household DROP comment_members_date'); + } + public function getDescription(): string { return 'replace comment in household as embedded comment'; @@ -26,14 +43,4 @@ final class Version20210615074857 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_household ADD comment_members_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); $this->addSql('ALTER TABLE chill_person_household ADD CONSTRAINT fk_household_comment_embeddable_user FOREIGN KEY (comment_members_userId) REFERENCES users (id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_household RENAME comment_members_comment TO comment_members'); - $this->addSql('ALTER TABLE chill_person_household ALTER comment_members SET DEFAULT \'\''); - $this->addSql('ALTER TABLE chill_person_household ALTER comment_members SET NOT NULL'); - $this->addSql('ALTER TABLE chill_person_household DROP comment_members_comment'); - $this->addSql('ALTER TABLE chill_person_household DROP comment_members_userId'); - $this->addSql('ALTER TABLE chill_person_household DROP comment_members_date'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210616102900.php b/src/Bundle/ChillPersonBundle/migrations/Version20210616102900.php index 1774cb0b3..ad6b44dfe 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210616102900.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210616102900.php @@ -1,5 +1,12 @@ addSql('DROP VIEW view_chill_person_household_address'); + } + public function getDescription(): string { return 'Create a view for assembling household, person and addresses'; @@ -19,25 +31,20 @@ final class Version20210616102900 extends AbstractMigration public function up(Schema $schema): void { - $this->addSql("CREATE VIEW view_chill_person_household_address AS ". - "SELECT ". - "members.person_id AS person_id, ". - "members.household_id AS household_id, ". - "members.id AS member_id, ". - "address.id AS address_id, ". - "CASE WHEN address.validFrom < members.startDate THEN members.startDate ELSE address.validFrom END AS validFrom, ". - "CASE WHEN COALESCE(address.validTo, 'infinity') < COALESCE(members.endDate, 'infinity') THEN address.validTo ELSE members.endDate END AS validTo ". - "FROM chill_person_household_members AS members ". - "JOIN chill_person_household_to_addresses AS household_to_addr ON household_to_addr.household_id = members.household_id ". - "JOIN chill_main_address AS address ON household_to_addr.address_id = address.id ". - "AND daterange(address.validFrom, address.validTo) && daterange(members.startDate, members.endDate) ". - "WHERE members.sharedhousehold IS TRUE " + $this->addSql( + 'CREATE VIEW view_chill_person_household_address AS ' . + 'SELECT ' . + 'members.person_id AS person_id, ' . + 'members.household_id AS household_id, ' . + 'members.id AS member_id, ' . + 'address.id AS address_id, ' . + 'CASE WHEN address.validFrom < members.startDate THEN members.startDate ELSE address.validFrom END AS validFrom, ' . + "CASE WHEN COALESCE(address.validTo, 'infinity') < COALESCE(members.endDate, 'infinity') THEN address.validTo ELSE members.endDate END AS validTo " . + 'FROM chill_person_household_members AS members ' . + 'JOIN chill_person_household_to_addresses AS household_to_addr ON household_to_addr.household_id = members.household_id ' . + 'JOIN chill_main_address AS address ON household_to_addr.address_id = address.id ' . + 'AND daterange(address.validFrom, address.validTo) && daterange(members.startDate, members.endDate) ' . + 'WHERE members.sharedhousehold IS TRUE ' ); - - } - - public function down(Schema $schema): void - { - $this->addSql("DROP VIEW view_chill_person_household_address"); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210617073504.php b/src/Bundle/ChillPersonBundle/migrations/Version20210617073504.php index f9e96697d..1083d872d 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210617073504.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210617073504.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_person DROP deathdate'); + $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusDate'); + $this->addSql('ALTER TABLE chill_person_person DROP acceptSMS'); + $this->addSql('ALTER TABLE chill_person_person DROP acceptEmail'); + $this->addSql('ALTER TABLE chill_person_person DROP numberOfChildren'); + $this->addSql('ALTER TABLE chill_person_person DROP genderComment_comment'); + $this->addSql('ALTER TABLE chill_person_person DROP genderComment_userId'); + $this->addSql('ALTER TABLE chill_person_person DROP genderComment_date'); + $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusComment_comment'); + $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusComment_userId'); + $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusComment_date'); + } + public function getDescription(): string { return 'Add new fields to Person entity'; @@ -31,19 +53,4 @@ final class Version20210617073504 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_person ADD maritalStatusComment_userId INT DEFAULT NULL'); $this->addSql('ALTER TABLE chill_person_person ADD maritalStatusComment_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_person DROP deathdate'); - $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusDate'); - $this->addSql('ALTER TABLE chill_person_person DROP acceptSMS'); - $this->addSql('ALTER TABLE chill_person_person DROP acceptEmail'); - $this->addSql('ALTER TABLE chill_person_person DROP numberOfChildren'); - $this->addSql('ALTER TABLE chill_person_person DROP genderComment_comment'); - $this->addSql('ALTER TABLE chill_person_person DROP genderComment_userId'); - $this->addSql('ALTER TABLE chill_person_person DROP genderComment_date'); - $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusComment_comment'); - $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusComment_userId'); - $this->addSql('ALTER TABLE chill_person_person DROP maritalStatusComment_date'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210618080702.php b/src/Bundle/ChillPersonBundle/migrations/Version20210618080702.php index 93c6b8bf0..a75377615 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210618080702.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210618080702.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A143174800F'); + $this->addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A1465FF1AEC'); + $this->addSql('DROP INDEX IDX_BF210A143174800F'); + $this->addSql('DROP INDEX IDX_BF210A1465FF1AEC'); + $this->addSql('ALTER TABLE chill_person_person DROP createdAt'); + $this->addSql('ALTER TABLE chill_person_person DROP updatedAt'); + $this->addSql('ALTER TABLE chill_person_person DROP createdBy_id'); + $this->addSql('ALTER TABLE chill_person_person DROP updatedBy_id'); + $this->addSql('COMMENT ON COLUMN chill_person_person.deathdate IS NULL'); + } + public function getDescription(): string { return 'Add createdAt, createdBy, updatedAt, updatedBy fields on Person'; @@ -29,17 +49,4 @@ final class Version20210618080702 extends AbstractMigration $this->addSql('CREATE INDEX IDX_BF210A143174800F ON chill_person_person (createdBy_id)'); $this->addSql('CREATE INDEX IDX_BF210A1465FF1AEC ON chill_person_person (updatedBy_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A143174800F'); - $this->addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A1465FF1AEC'); - $this->addSql('DROP INDEX IDX_BF210A143174800F'); - $this->addSql('DROP INDEX IDX_BF210A1465FF1AEC'); - $this->addSql('ALTER TABLE chill_person_person DROP createdAt'); - $this->addSql('ALTER TABLE chill_person_person DROP updatedAt'); - $this->addSql('ALTER TABLE chill_person_person DROP createdBy_id'); - $this->addSql('ALTER TABLE chill_person_person DROP updatedBy_id'); - $this->addSql('COMMENT ON COLUMN chill_person_person.deathdate IS NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210620143757.php b/src/Bundle/ChillPersonBundle/migrations/Version20210620143757.php index 17d1e31aa..fbea185f4 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210620143757.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210620143757.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period_work DROP updatedAt'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work DROP updatedBy_id'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER createdAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER createdAt DROP DEFAULT'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER startDate TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER startDate DROP DEFAULT'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER endDate TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER endDate DROP DEFAULT'); + $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.createdat IS NULL'); + $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.startdate IS NULL'); + $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.enddate IS NULL'); + } + public function getDescription(): string { return 'add updated information to accompanying period work'; @@ -33,19 +55,4 @@ final class Version20210620143757 extends AbstractMigration $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.startDate IS \'(DC2Type:datetime_immutable)\''); $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.endDate IS \'(DC2Type:datetime_immutable)\''); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period_work DROP updatedAt'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work DROP updatedBy_id'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER createdAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER createdAt DROP DEFAULT'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER startDate TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER startDate DROP DEFAULT'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER endDate TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work ALTER endDate DROP DEFAULT'); - $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.createdat IS NULL'); - $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.startdate IS NULL'); - $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_work.enddate IS NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210623135043.php b/src/Bundle/ChillPersonBundle/migrations/Version20210623135043.php index d7f2f4ccc..8cb57e5e1 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210623135043.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210623135043.php @@ -1,5 +1,12 @@ addSql('DROP TABLE chill_person_accompanying_period_work_person'); + } + public function getDescription(): string { return 'Add link to accompanying period work and persons'; @@ -19,16 +31,10 @@ final class Version20210623135043 extends AbstractMigration public function up(Schema $schema): void { - $this->addSql("CREATE TABLE chill_person_accompanying_period_work_person (accompanyingperiodwork_id INT NOT NULL, person_id INT NOT NULL, PRIMARY KEY(accompanyingperiodwork_id, person_id))"); - $this->addSql("CREATE INDEX IDX_615F494CB99F6060 ON chill_person_accompanying_period_work_person (accompanyingperiodwork_id)"); - $this->addSql("CREATE INDEX IDX_615F494C217BBB47 ON chill_person_accompanying_period_work_person (person_id)"); - $this->addSql("ALTER TABLE chill_person_accompanying_period_work_person ADD CONSTRAINT FK_615F494CB99F6060 FOREIGN KEY (accompanyingperiodwork_id) REFERENCES chill_person_accompanying_period_work (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE"); - $this->addSql("ALTER TABLE chill_person_accompanying_period_work_person ADD CONSTRAINT FK_615F494C217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE"); - - } - - public function down(Schema $schema): void - { - $this->addSql("DROP TABLE chill_person_accompanying_period_work_person"); + $this->addSql('CREATE TABLE chill_person_accompanying_period_work_person (accompanyingperiodwork_id INT NOT NULL, person_id INT NOT NULL, PRIMARY KEY(accompanyingperiodwork_id, person_id))'); + $this->addSql('CREATE INDEX IDX_615F494CB99F6060 ON chill_person_accompanying_period_work_person (accompanyingperiodwork_id)'); + $this->addSql('CREATE INDEX IDX_615F494C217BBB47 ON chill_person_accompanying_period_work_person (person_id)'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_person ADD CONSTRAINT FK_615F494CB99F6060 FOREIGN KEY (accompanyingperiodwork_id) REFERENCES chill_person_accompanying_period_work (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_person ADD CONSTRAINT FK_615F494C217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210623142046.php b/src/Bundle/ChillPersonBundle/migrations/Version20210623142046.php index 8baffb867..3e7d6a22e 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210623142046.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210623142046.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_social_action ALTER defaultNotificationDelay SET NOT NULL'); + } + public function getDescription(): string { return ''; @@ -21,9 +33,4 @@ final class Version20210623142046 extends AbstractMigration { $this->addSql('ALTER TABLE chill_person_social_action ALTER defaultnotificationdelay DROP NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_social_action ALTER defaultNotificationDelay SET NOT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210624131722.php b/src/Bundle/ChillPersonBundle/migrations/Version20210624131722.php index ebeb33e50..32de7a8da 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210624131722.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210624131722.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_social_work_evaluation ALTER delay SET NOT NULL'); + } + public function getDescription(): string { return ''; @@ -21,9 +33,4 @@ final class Version20210624131722 extends AbstractMigration { $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER delay DROP NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER delay SET NOT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210624131723.php b/src/Bundle/ChillPersonBundle/migrations/Version20210624131723.php index d36d23733..98f73e0c6 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210624131723.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210624131723.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_social_work_evaluation ALTER notificationdelay SET NOT NULL'); + } + public function getDescription(): string { return ''; @@ -21,9 +33,4 @@ final class Version20210624131723 extends AbstractMigration { $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER notificationdelay DROP NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER notificationdelay SET NOT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210727152826.php b/src/Bundle/ChillPersonBundle/migrations/Version20210727152826.php index f49c819d7..226c06bb5 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210727152826.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210727152826.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A868D5213D34'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A8689B07D6BF'); + $this->addSql('DROP INDEX IDX_E260A868D5213D34'); + $this->addSql('DROP INDEX IDX_E260A8689B07D6BF'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP personLocation_id'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP addressLocation_id'); + } + public function getDescription(): string { return 'Add location to accompanying period'; @@ -26,14 +43,4 @@ final class Version20210727152826 extends AbstractMigration $this->addSql('CREATE INDEX IDX_E260A868D5213D34 ON chill_person_accompanying_period (personLocation_id)'); $this->addSql('CREATE INDEX IDX_E260A8689B07D6BF ON chill_person_accompanying_period (addressLocation_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A868D5213D34'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A8689B07D6BF'); - $this->addSql('DROP INDEX IDX_E260A868D5213D34'); - $this->addSql('DROP INDEX IDX_E260A8689B07D6BF'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP personLocation_id'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP addressLocation_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210729163023.php b/src/Bundle/ChillPersonBundle/migrations/Version20210729163023.php index 40fd84266..b303b5fbc 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210729163023.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210729163023.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_person_accompanying_period_work_evaluation_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_accompanying_period_work_evaluation'); + } + public function getDescription(): string { return 'create class and tables for AccompanyingPeriodWorkEvaluation'; @@ -36,10 +49,4 @@ final class Version20210729163023 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation ADD CONSTRAINT FK_741A3A0B3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation ADD CONSTRAINT FK_741A3A0B65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP SEQUENCE chill_person_accompanying_period_work_evaluation_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_accompanying_period_work_evaluation'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210730094514.php b/src/Bundle/ChillPersonBundle/migrations/Version20210730094514.php index a96d0fd58..e1f6a1c29 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210730094514.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210730094514.php @@ -1,5 +1,12 @@ addSql('COMMENT ON COLUMN chill_calendar.calendar_range.startdate IS \'(DC2Type:datetimetz_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.enddate IS \'(DC2Type:datetimetz_immutable)\''); + $this->addSql('DROP TABLE chill_person_accompanying_period_work_evaluation_document'); + $this->addSql('DROP SEQUENCE chill_person_accompanying_period_work_eval_doc_id_seq'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work DROP CONSTRAINT FK_B694FB365FF1AEC'); + $this->addSql('DROP INDEX IDX_B694FB365FF1AEC'); + } + public function getDescription(): string { return 'add documents to AccompanyingPeriodWorkEvaluation'; @@ -34,14 +51,4 @@ final class Version20210730094514 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period_work ADD CONSTRAINT FK_B694FB365FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_B694FB365FF1AEC ON chill_person_accompanying_period_work (updatedBy_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.startdate IS \'(DC2Type:datetimetz_immutable)\''); - $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.enddate IS \'(DC2Type:datetimetz_immutable)\''); - $this->addSql('DROP TABLE chill_person_accompanying_period_work_evaluation_document'); - $this->addSql('DROP SEQUENCE chill_person_accompanying_period_work_eval_doc_id_seq'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work DROP CONSTRAINT FK_B694FB365FF1AEC'); - $this->addSql('DROP INDEX IDX_B694FB365FF1AEC'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210730205407.php b/src/Bundle/ChillPersonBundle/migrations/Version20210730205407.php index 0904856c4..f93d33e06 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210730205407.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210730205407.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_social_work_evaluation ALTER delay SET NOT NULL'); + $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER notificationDelay SET NOT NULL'); + } + public function getDescription(): string { return 'add nullable fields to social work evaluation'; @@ -22,10 +35,4 @@ final class Version20210730205407 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER delay DROP NOT NULL'); $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER notificationdelay DROP NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER delay SET NOT NULL'); - $this->addSql('ALTER TABLE chill_person_social_work_evaluation ALTER notificationDelay SET NOT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210802202838.php b/src/Bundle/ChillPersonBundle/migrations/Version20210802202838.php index 8ef9f59d2..c83390b80 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210802202838.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210802202838.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation DROP comment'); + } + public function getDescription(): string { return 'Add comment to accompanying period work evaluation'; @@ -21,9 +33,4 @@ final class Version20210802202838 extends AbstractMigration { $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation ADD comment TEXT DEFAULT \'\' NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation DROP comment'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210820093927.php b/src/Bundle/ChillPersonBundle/migrations/Version20210820093927.php index 65b07766c..02553b629 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210820093927.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210820093927.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP CONSTRAINT FK_33EC92296C99C13A'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP CONSTRAINT FK_33EC92295DA0FB8'); + $this->addSql('DROP INDEX IDX_33EC92296C99C13A'); + $this->addSql('DROP INDEX IDX_33EC92295DA0FB8'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP template_id'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP storedObject_id'); + } + public function getDescription(): string { return 'Add a link between evaluation document, stored object, and document template'; @@ -26,14 +43,4 @@ final class Version20210820093927 extends AbstractMigration $this->addSql('CREATE INDEX IDX_33EC92296C99C13A ON chill_person_accompanying_period_work_evaluation_document (storedObject_id)'); $this->addSql('CREATE INDEX IDX_33EC92295DA0FB8 ON chill_person_accompanying_period_work_evaluation_document (template_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP CONSTRAINT FK_33EC92296C99C13A'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP CONSTRAINT FK_33EC92295DA0FB8'); - $this->addSql('DROP INDEX IDX_33EC92296C99C13A'); - $this->addSql('DROP INDEX IDX_33EC92295DA0FB8'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP template_id'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP storedObject_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210820100407.php b/src/Bundle/ChillPersonBundle/migrations/Version20210820100407.php index fd05a884c..dbb2aaa33 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210820100407.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210820100407.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_person_social_work_eval_doc_id_seq'); + } + public function getDescription(): string { return 'Add missing sequence for evaluation documents'; @@ -21,9 +33,4 @@ final class Version20210820100407 extends AbstractMigration { $this->addSql('CREATE SEQUENCE chill_person_social_work_eval_doc_id_seq INCREMENT BY 1 MINVALUE 1000 START 1000'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP SEQUENCE chill_person_social_work_eval_doc_id_seq'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210831140339.php b/src/Bundle/ChillPersonBundle/migrations/Version20210831140339.php index dd3a60d75..2b2baa1d3 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210831140339.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210831140339.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_person ALTER center_id SET NOT NULL'); + } + public function getDescription(): string { return 'Allow to create persons without center'; @@ -21,9 +33,4 @@ final class Version20210831140339 extends AbstractMigration { $this->addSql('ALTER TABLE chill_person_person ALTER center_id DROP NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_person ALTER center_id SET NOT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210910161858.php b/src/Bundle/ChillPersonBundle/migrations/Version20210910161858.php index 82cade6cf..f3535787f 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210910161858.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210910161858.php @@ -1,5 +1,12 @@ addSql('DROP INDEX fullnamecanonical_trgm_idx'); + $this->addSql('CREATE INDEX fullnameCanonical_trgm_idx ON chill_person_person USING GIST (fullnameCanonical gist_trgm_ops)'); + } + public function getDescription(): string { return 'Optimize trigram index on person fullname: create index for both center_id and fullname'; @@ -22,10 +35,4 @@ final class Version20210910161858 extends AbstractMigration $this->addSql('DROP INDEX fullnamecanonical_trgm_idx'); $this->addSql('CREATE INDEX fullnameCanonical_trgm_idx ON chill_person_person USING GIST (center_id, fullnameCanonical gist_trgm_ops)'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP INDEX fullnamecanonical_trgm_idx'); - $this->addSql('CREATE INDEX fullnameCanonical_trgm_idx ON chill_person_person USING GIST (fullnameCanonical gist_trgm_ops)'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210915093624.php b/src/Bundle/ChillPersonBundle/migrations/Version20210915093624.php index f285fde47..980218c92 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210915093624.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210915093624.php @@ -1,5 +1,12 @@ addSql('DROP VIEW view_chill_person_current_address'); + $this->addSql('DROP INDEX chill_custom_main_address_filtering_idx'); + $this->addSql('DROP INDEX chill_custom_person_household_members_sharing_idx'); + } + public function getDescription(): string { return 'Create view for PersonCurrentAddress and related indexes'; @@ -36,14 +50,7 @@ final class Version20210915093624 extends AbstractMigration current_date between cma.validfrom AND coalesce(validto, 'infinity'::date) "); - $this->addSql("CREATE INDEX chill_custom_main_address_filtering_idx ON chill_main_address USING btree (id, validfrom ASC, validto DESC)"); - $this->addSql("CREATE INDEX chill_custom_person_household_members_sharing_idx ON chill_person_household_members USING btree (person_id, startdate ASC, enddate DESC, household_id) WHERE sharedhousehold IS TRUE"); - } - - public function down(Schema $schema): void - { - $this->addSql("DROP VIEW view_chill_person_current_address"); - $this->addSql("DROP INDEX chill_custom_main_address_filtering_idx"); - $this->addSql("DROP INDEX chill_custom_person_household_members_sharing_idx"); + $this->addSql('CREATE INDEX chill_custom_main_address_filtering_idx ON chill_main_address USING btree (id, validfrom ASC, validto DESC)'); + $this->addSql('CREATE INDEX chill_custom_person_household_members_sharing_idx ON chill_person_household_members USING btree (person_id, startdate ASC, enddate DESC, household_id) WHERE sharedhousehold IS TRUE'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php b/src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php index 031356cd3..43e1e4535 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211020131133.php @@ -1,5 +1,12 @@ addSql('DROP INDEX person_unique'); + $this->addSql('DROP INDEX thirdparty_unique'); + } + public function getDescription(): string { return 'Validation added to accompanying period resources and accompanying period.'; @@ -22,10 +35,4 @@ final class Version20211020131133 extends AbstractMigration $this->addSql('CREATE UNIQUE INDEX person_unique ON chill_person_accompanying_period_resource (person_id, accompanyingperiod_id) WHERE person_id IS NOT NULL'); $this->addSql('CREATE UNIQUE INDEX thirdparty_unique ON chill_person_accompanying_period_resource (thirdparty_id, accompanyingperiod_id) WHERE thirdparty_id IS NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP INDEX person_unique'); - $this->addSql('DROP INDEX thirdparty_unique'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php b/src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php index a4ed54254..adaf6b578 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211021125359.php @@ -1,5 +1,12 @@ addSql('CREATE UNIQUE INDEX participation_unique ON chill_person_accompanying_period_participation (accompanyingperiod_id, person_id)'); + } + public function getDescription(): string { return 'Custom constraint added to database to prevent identical participations.'; @@ -20,17 +32,12 @@ final class Version20211021125359 extends AbstractMigration public function up(Schema $schema): void { // creates a constraint 'participations may not overlap' - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT '. - "participations_no_overlap EXCLUDE USING GIST( + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT ' . + 'participations_no_overlap EXCLUDE USING GIST( -- extension btree_gist required to include comparaison with integer person_id WITH =, accompanyingperiod_id WITH =, daterange(startdate, enddate) WITH && ) - INITIALLY DEFERRED"); - } - - public function down(Schema $schema): void - { - $this->addSql('CREATE UNIQUE INDEX participation_unique ON chill_person_accompanying_period_participation (accompanyingperiod_id, person_id)'); + INITIALLY DEFERRED'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211025141226.php b/src/Bundle/ChillPersonBundle/migrations/Version20211025141226.php index 9d67b0f4d..289b5e090 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211025141226.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211025141226.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_relationships DROP CONSTRAINT FK_23D47C513256915B'); + $this->addSql('DROP SEQUENCE chill_person_relations_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_person_relationships_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_relations'); + $this->addSql('DROP TABLE chill_person_relationships'); + } + public function getDescription(): string { return 'Create the relationship and relation entity'; @@ -36,14 +52,4 @@ final class Version20211025141226 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_relationships ADD CONSTRAINT FK_23D47C513174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_person_relationships ADD CONSTRAINT FK_23D47C5165FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - - $this->addSql('ALTER TABLE chill_person_relationships DROP CONSTRAINT FK_23D47C513256915B'); - $this->addSql('DROP SEQUENCE chill_person_relations_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_person_relationships_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_relations'); - $this->addSql('DROP TABLE chill_person_relationships'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php b/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php index ef739dcb8..222900450 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211029075117.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_relations DROP isActive'); + } + public function getDescription(): string { return 'isActive property added to Relation entity.'; @@ -21,9 +33,4 @@ final class Version20211029075117 extends AbstractMigration { $this->addSql('ALTER TABLE chill_person_relations ADD isActive BOOLEAN DEFAULT true NOT NULL'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_relations DROP isActive'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211108100849.php b/src/Bundle/ChillPersonBundle/migrations/Version20211108100849.php index 49395dfae..2fea4a64c 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211108100849.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211108100849.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A1423D6A298'); + $this->addSql('DROP INDEX IDX_BF210A1423D6A298'); + $this->addSql('ALTER TABLE chill_person_person DROP civility_id'); + } + public function getDescription(): string { return 'Add Civility to Person'; @@ -23,11 +37,4 @@ final class Version20211108100849 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_person ADD CONSTRAINT FK_BF210A1423D6A298 FOREIGN KEY (civility_id) REFERENCES chill_main_civility (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_BF210A1423D6A298 ON chill_person_person (civility_id)'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_person DROP CONSTRAINT FK_BF210A1423D6A298'); - $this->addSql('DROP INDEX IDX_BF210A1423D6A298'); - $this->addSql('ALTER TABLE chill_person_person DROP civility_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211112170027.php b/src/Bundle/ChillPersonBundle/migrations/Version20211112170027.php index 65434bb33..4339b43a9 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211112170027.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211112170027.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_person ALTER mobilenumber DROP NOT NULL'); + $this->addSql('ALTER TABLE chill_person_person ALTER phonenumber DROP NOT NULL'); + $this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber SET DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_person ALTER phonenumber SET DEFAULT NULL'); + } + public function getDescription(): string { return 'Drop not null in person table: set default empty value'; @@ -26,12 +41,4 @@ final class Version20211112170027 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber SET DEFAULT \'\''); $this->addSql('ALTER TABLE chill_person_person ALTER phonenumber SET DEFAULT \'\''); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber DROP NOT NULL'); - $this->addSql('ALTER TABLE chill_person_person ALTER phonenumber DROP NOT NULL'); - $this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber SET DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_person ALTER phonenumber SET DEFAULT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211119211101.php b/src/Bundle/ChillPersonBundle/migrations/Version20211119211101.php index 3f4a141d6..e3ba27e81 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211119211101.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211119211101.php @@ -1,5 +1,12 @@ addSql('DROP INDEX person_birthdate'); + $this->addSql('DROP INDEX phonenumber'); + } + public function getDescription(): string { return 'add indexes for searching by birthdate'; @@ -19,10 +32,4 @@ final class Version20211119211101 extends AbstractMigration $this->addSql('CREATE INDEX person_birthdate ON chill_person_person (birthdate)'); $this->addSql('CREATE INDEX phonenumber ON chill_person_phone USING GIST (phonenumber gist_trgm_ops)'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP INDEX person_birthdate'); - $this->addSql('DROP INDEX phonenumber'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20211119215630.php b/src/Bundle/ChillPersonBundle/migrations/Version20211119215630.php index fe4ce1daf..bcc461104 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20211119215630.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20211119215630.php @@ -1,5 +1,12 @@ addSql("CREATE OR REPLACE VIEW view_chill_person_current_address AS + SELECT + cphm.person_id AS person_id, + cma.id AS address_id, + CASE WHEN cphm.startdate > COALESCE(cma.validfrom, '-infinity'::date) THEN cphm.startdate ELSE cma.validfrom END AS valid_from, + CASE WHEN COALESCE(cphm.enddate, 'infinity'::date) < COALESCE(cma.validto, 'infinity'::date) THEN cphm.enddate ELSE cma.validto END AS valid_to + FROM chill_person_household_members AS cphm + LEFT JOIN chill_person_household_to_addresses AS cphta ON cphta.household_id = cphm.household_id + LEFT JOIN chill_main_address AS cma ON cphta.address_id = cma.id + WHERE + cphm.sharedhousehold IS TRUE + AND + current_date between cphm.startdate AND coalesce(enddate, 'infinity'::date) + AND + current_date between cma.validfrom AND coalesce(validto, 'infinity'::date) + "); + } + public function getDescription(): string { return 'update computation of view_chill_person_current_address: do not take enddate into account'; @@ -33,26 +60,4 @@ final class Version20211119215630 extends AbstractMigration daterange(cma.validfrom, cma.validto, '[)') @> current_date "); } - - public function down(Schema $schema): void - { - $this->addSql("CREATE OR REPLACE VIEW view_chill_person_current_address AS - SELECT - cphm.person_id AS person_id, - cma.id AS address_id, - CASE WHEN cphm.startdate > COALESCE(cma.validfrom, '-infinity'::date) THEN cphm.startdate ELSE cma.validfrom END AS valid_from, - CASE WHEN COALESCE(cphm.enddate, 'infinity'::date) < COALESCE(cma.validto, 'infinity'::date) THEN cphm.enddate ELSE cma.validto END AS valid_to - FROM chill_person_household_members AS cphm - LEFT JOIN chill_person_household_to_addresses AS cphta ON cphta.household_id = cphm.household_id - LEFT JOIN chill_main_address AS cma ON cphta.address_id = cma.id - WHERE - cphm.sharedhousehold IS TRUE - AND - current_date between cphm.startdate AND coalesce(enddate, 'infinity'::date) - AND - current_date between cma.validfrom AND coalesce(validto, 'infinity'::date) - "); - - - } } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 31996117e..5db109692 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -169,6 +169,7 @@ Update accompanying period: Mettre à jour une période d'accompagnement 'Period not opened': "La période d'accompagnement n'a pas été ouverte" "Period not opened : form is invalid": "La période n'a pas été ouverte: le formulaire est invalide." 'Closing motive': 'Motif de clôture' +Close accompanying course: Clôturer le parcours 'Person details': 'Détails de la personne' 'Update details for %name%': 'Modifier détails de %name%' An accompanying period ends: Une periode d'accompagnement se clôture @@ -379,6 +380,7 @@ regular: régulier Confidential: confidentiel Draft: brouillon Confirmed: en file active +Closed: Cloturé # Accompanying Course Accompanying Course: Parcours d'accompagnement @@ -386,6 +388,7 @@ Accompanying Course History: Historique du parcours Resume Accompanying Course: Résumé du parcours Show Accompanying Course: Voir le parcours Edit Accompanying Course: Modifier le parcours +Close Accompanying Course: Clôturer le parcours Create Accompanying Course: Créer un nouveau parcours Drop Accompanying Course: Supprimer le parcours This course is located at a temporarily address. You should locate this course to an user: Le parcours est localisé à une adresse temporaire. Il devrait être localisé auprès d'une personne concernée. 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 a19537cc4..5b2d975b9 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 { @@ -39,53 +27,52 @@ class LoadCustomField extends AbstractFixture implements OrderedFixtureInterface public function load(ObjectManager $manager) { $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++) { - $cFType = $cFTypes[rand(0,sizeof($cFTypes) - 1)]; + for ($i = 0; 25 >= $i; ++$i) { + $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); } @@ -101,119 +88,108 @@ class LoadCustomField extends AbstractFixture implements OrderedFixtureInterface $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); - - - } } 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 31994c2e6..d7a030b75 100644 --- a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php +++ b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php @@ -1,46 +1,33 @@ +/** + * 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\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 */ private $faker; @@ -66,6 +53,26 @@ class LoadReports extends AbstractFixture implements OrderedFixtureInterface, Co $manager->flush(); } + private function createExpected(ObjectManager $manager) + { + $charline = $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillPersonBundle:Person') + ->findOneBy(['firstName' => 'Charline', 'lastName' => 'DEPARDIEU']); + + if (null !== $charline) { + $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); + } else { + echo 'WARNING: Charline DEPARDIEU not found in database'; + } + } + private function createRandom(ObjectManager $manager, $percentage) { $people = $this->getPeopleRandom($percentage); @@ -73,100 +80,57 @@ class LoadReports extends AbstractFixture implements OrderedFixtureInterface, Co 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')) - ; - - if (NULL !== $charline) { - $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); - } else { - print("WARNING: Charline DEPARDIEU not found in database"); - } - } - - /** - * - * @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; } } @@ -175,11 +139,28 @@ class LoadReports extends AbstractFixture implements OrderedFixtureInterface, Co 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 + * pick a random choice. * - * @param CustomField $field - * @return string[]|string the array of slug if multiple, a single slug otherwise + * @return string|string[] the array of slug if multiple, a single slug otherwise */ private function getRandomChoice(CustomField $field) { @@ -188,21 +169,22 @@ class LoadReports extends AbstractFixture implements OrderedFixtureInterface, Co $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); @@ -210,35 +192,38 @@ class LoadReports extends AbstractFixture implements OrderedFixtureInterface, Co return $result; } - } else { $picked = $this->pickChoice($choices); if ($other) { - $result = array('_other' => NULL, '_choices' => $picked); + $result = ['_other' => null, '_choices' => $picked]; - if ($picked === '_other') { + if ('_other' === $picked) { $result['_other'] = $this->faker->realText(70); } return $result; } } - - } /** - * pick a choice within a 'choices' options (for choice type) + * @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). * - * @param array $choices * @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 . + * 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") @@ -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; + $this->date = $date; + + return $this; } /** - * @return Center + * Set person. + * + * @return Report */ - public function getCenter() + public function setPerson(Person $person) { - return $this->person->getCenter(); + $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 432cb8e3f..a9edd8aa6 100644 --- a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php +++ b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php @@ -1,42 +1,56 @@ em = $em; } - public function buildForm(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(); } @@ -81,8 +97,8 @@ class ReportList implements ListInterface, ExportElementValidatedInterface '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']; @@ -90,72 +106,41 @@ class ReportList implements ListInterface, ExportElementValidatedInterface return []; }, - 'choice_label' => function(string $key, string $label): string { + 'choice_label' => function (string $key, string $label): string { 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([ - 'callback' => function($selected, ExecutionContextInterface $context) { + '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, [ - 'label' => "Address valid at this date", - 'data' => new \DateTime(), + 'label' => 'Address valid at this date', + 'data' => new DateTime(), 'required' => false, - 'block_name' => 'list_export_form_address_date' + 'block_name' => 'list_export_form_address_date', ]); } - public function validateForm($data, ExecutionContextInterface $context) - { - // get the field starting with address_ - $addressFields = array_filter( - $this->fields, - static fn(string $el): bool => substr($el, 0, 8) === 'address_' - ); - - // 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'; - }); - } - public function getAllowedFormattersTypes() { return [FormatterInterface::TYPE_LIST]; @@ -166,92 +151,95 @@ class ReportList implements ListInterface, ExportElementValidatedInterface return $this->translator->trans( "Generate list of report '%type%'", [ - '%type%' => $this->translatableStringHelper->localize($this->customfieldsGroup->getName()) + '%type%' => $this->translatableStringHelper->localize($this->customfieldsGroup->getName()), ] ); } - public function getLabels($key, array $values, $data): \Closure + public function getLabels($key, array $values, $data): Closure { switch ($key) { case 'person_birthdate': 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'); }; + 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); $scopes = []; - foreach($rows as $row) { + foreach ($rows as $row) { $scopes[$row['id']] = $this->translatableStringHelper->localize($row['name']); } - return function($value) use ($scopes): string { - if ($value === '_header') { + return function ($value) use ($scopes): string { + 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); $users = []; - foreach($rows as $row) { + foreach ($rows as $row) { $users[$row['id']] = $row['username']; } - return function($value) use ($users): string { - if ($value === '_header') { + return function ($value) use ($users): string { + 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 @@ -260,86 +248,49 @@ class ReportList implements ListInterface, ExportElementValidatedInterface // load all countries in a single query $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 'person_address_country_name': - return function($value) use ($key) { - if ($value === '_header') { return \strtolower($key); } - if ($value === NULL) { + case 'person_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)); }; + 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 $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(['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); - } - - return $cfType->isChecked($cf, $slugChoice, $decoded); - }; - - } - - return $defaultFunction; } public function getQueryKeys($data) @@ -353,30 +304,7 @@ class ReportList implements ListInterface, ExportElementValidatedInterface } // add the key from slugs and return - return \array_merge($fields, \array_keys($this->slugs)); - } - - private function slugToDQL($slug, $type = "default", array $additionalInfos = []) - { - $uid = 'slug_' . \uniqid('', true); - - $this->slugs[$uid] = [ - 'slug' => $slug, - 'type' => $type, - 'additionnalInfos' => $additionalInfos - ]; - - return $uid; - } - - private function DQLToSlug($cleanedSlug) - { - return $this->slugs[$cleanedSlug]['slug']; - } - - private function extractInfosFromSlug($slug) - { - return $this->slugs[$slug]; + return array_merge($fields, array_keys($this->slugs)); } public function getResult($query, $data) @@ -389,7 +317,7 @@ 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()), ] ); } @@ -401,12 +329,12 @@ class ReportList implements ListInterface, ExportElementValidatedInterface 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(); @@ -424,7 +352,9 @@ class ReportList implements ListInterface, ExportElementValidatedInterface 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': @@ -439,32 +369,42 @@ class ReportList implements ListInterface, ExportElementValidatedInterface 'GET_PERSON_ADDRESS_%s(person.id, :address_date) AS %s', // get the part after address_ strtoupper(substr($suffix, 8)), - $f)); + $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 @@ -478,19 +418,27 @@ class ReportList implements ListInterface, ExportElementValidatedInterface // 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()); } } @@ -514,4 +462,102 @@ 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( + $this->fields, + static fn (string $el): bool => substr($el, 0, 8) === 'address_' + ); + + // 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']; + } + + 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); + }; + } + + return $defaultFunction; + } + + private function slugToDQL($slug, $type = 'default', array $additionalInfos = []) + { + $uid = 'slug_' . uniqid('', true); + + $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 1b0b2dc8f..52efd0892 100644 --- a/src/Bundle/ChillReportBundle/Form/ReportType.php +++ b/src/Bundle/ChillReportBundle/Form/ReportType.php @@ -1,110 +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 Chill\CustomFieldsBundle\Form\Type\CustomFieldType; +use Chill\MainBundle\Form\Type\AppendScopeChoiceTypeTrait; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Form\Type\AppendScopeChoiceTypeTrait; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\MainBundle\Form\Type\ChillDateType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\Persistence\ObjectManager; -use Chill\CustomFieldsBundle\Form\Type\CustomFieldType; 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', ChillDateType::class, - array('required' => true) + ->add( + 'date', + ChillDateType::class, + ['required' => true] ) - ->add('cFData', CustomFieldType::class, - array('attr' => array('class' => 'cf-fields'), - 'group' => $options['cFGroup'])) - ; + ->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,103 @@ 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..e62752897 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(): array + { + return [self::CREATE, self::UPDATE, self::SEE, self::LISTS]; + } + + public function getRolesWithHierarchy(): array + { + return ['Report' => $this->getRoles()]; + } + + public function getRolesWithoutScope(): array + { + 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 @@ showEmptyValues = $showEmptyValues; } - /** - * - * {@inheritDoc} - */ public function fetchQuery($context, array $args) { $this->checkContext($context); @@ -58,15 +63,140 @@ class TimelineReportProvider implements TimelineProviderInterface [$where, $parameters] = $this->getWhereClause($context, $args); return TimelineSingleQuery::fromArray([ - 'id' => $report->getTableName() - .'.'.$report->getColumnName('id'), - 'type' => 'report', - 'date' => $report->getTableName() - .'.'.$report->getColumnName('date'), - 'FROM' => $this->getFromClause($context), - 'WHERE' => $where, - 'parameters' => $parameters - ]); + 'id' => $report->getTableName() + . '.' . $report->getColumnName('id'), + 'type' => 'report', + 'date' => $report->getTableName() + . '.' . $report->getColumnName('date'), + 'FROM' => $this->getFromClause($context), + 'WHERE' => $where, + 'parameters' => $parameters, + ]); + } + + public function getEntities(array $ids) + { + $reports = $this->em->getRepository('ChillReportBundle:Report') + ->findBy(['id' => $ids]); + + $result = []; + + foreach ($reports as $report) { + $result[$report->getId()] = $report; + } + + return $result; + } + + public function getEntityTemplate($entity, $context, array $args) + { + $this->checkContext($context); + + return [ + 'template' => 'ChillReportBundle:Timeline:report.html.twig', + 'template_data' => [ + 'report' => $entity, + 'context' => $context, + 'custom_fields_in_summary' => $this->getFieldsToRender($entity, $context), + ], + ]; + } + + 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 = []; + + 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 we do not want to show empty values + if (false === $this->showEmptyValues) { + if ($customField->getType() === 'title') { + $options = $customField->getOptions(); + + switch ($options['type']) { + case 'title': $title = $customField; + +break; + + case 'subtitle': $subtitle = $customField; + +break; + } + } else { + if ($this->customFieldsHelper->isEmptyValue($entity->getCFData(), $customField) + === false) { + if (null !== $title) { + $gatheredFields[] = $title; + $title = null; + } + + if (null !== $subtitle) { + $gatheredFields[] = $subtitle; + $subtitle = null; + } + $gatheredFields[] = $customField; + } + } + } else { + $gatheredFields[] = $customField; + } + } + } + } + + return $gatheredFields; + } + + /** + * check if the context is supported. + * + * @param string $context + * + * @throws LogicException if the context is not supported + */ + private function checkContext($context) + { + if ('person' !== $context && 'center' !== $context) { + throw new LogicException("The context '{$context}' is not " + . "supported. Currently only 'person' and 'center' is supported"); + } + } + + private function getFromClause(string $context): string + { + $report = $this->em->getClassMetadata(Report::class); + $person = $this->em->getClassMetadata(Person::class); + $reportPersonId = $report + ->getAssociationMapping('person')['joinColumns'][0]['name']; + $personId = $report + ->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; + + $clause = '{report} ' . + 'JOIN {person} ON {report}.{person_id} = {person}.{id_person} '; + + return strtr( + $clause, + [ + '{report}' => $report->getTableName(), + '{person}' => $person->getTableName(), + '{person_id}' => $reportPersonId, + '{id_person}' => $personId, + ] + ); } private function getWhereClause(string $context, array $args): array @@ -74,10 +204,12 @@ class TimelineReportProvider implements TimelineProviderInterface switch ($context) { case 'person': return $this->getWhereClauseForPerson($context, $args); + case 'center': return $this->getWhereClauseForCenter($context, $args); + default: - throw new \UnexpectedValueException("This context $context is not implemented"); + throw new UnexpectedValueException("This context {$context} is not implemented"); } } @@ -96,14 +228,15 @@ class TimelineReportProvider implements TimelineProviderInterface $parameters = []; // the clause, that will be joined with an "OR" - $centerScopesClause = "({person}.{center_id} = ? ". - "AND {report}.{scopes_id} IN ({scopes_ids}))"; + $centerScopesClause = '({person}.{center_id} = ? ' . + 'AND {report}.{scopes_id} IN ({scopes_ids}))'; // container for formatted clauses $formattedClauses = []; $askedCenters = $args['centers']; + foreach ($reachableCenters as $center) { - if (FALSE === \in_array($center, $askedCenters)) { + if (false === \in_array($center, $askedCenters)) { continue; } @@ -111,6 +244,7 @@ class TimelineReportProvider implements TimelineProviderInterface $parameters[] = $center->getId(); // loop over scopes $scopeIds = []; + foreach ($this->helper->getReachableScopes($this->security->getUser(), $role, $center) as $scope) { if (\in_array($scope->getId(), $scopeIds)) { continue; @@ -118,20 +252,20 @@ class TimelineReportProvider implements TimelineProviderInterface $scopeIds[] = $scope->getId(); } - $formattedClauses[] = \strtr($centerScopesClause, [ - '{scopes_ids}' => \implode(', ', \array_fill(0, \count($scopeIds), '?')) + $formattedClauses[] = strtr($centerScopesClause, [ + '{scopes_ids}' => implode(', ', array_fill(0, \count($scopeIds), '?')), ]); // append $scopeIds to parameters - $parameters = \array_merge($parameters, $scopeIds); + $parameters = array_merge($parameters, $scopeIds); } if (0 === count($formattedClauses)) { - return [ 'FALSE = TRUE', [] ]; + return ['FALSE = TRUE', []]; } return [ - \strtr( - \implode(' OR ', $formattedClauses), + strtr( + implode(' OR ', $formattedClauses), [ '{person}' => $person->getTableName(), '{center_id}' => $personCenterId, @@ -139,7 +273,7 @@ class TimelineReportProvider implements TimelineProviderInterface '{scopes_id}' => $reportScopeId, ] ), - $parameters + $parameters, ]; } @@ -152,10 +286,10 @@ class TimelineReportProvider implements TimelineProviderInterface $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name']; $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name']; // parameters for the query, will be filled later - $parameters = [ $args['person']->getId() ]; + $parameters = [$args['person']->getId()]; // this is the final clause that we are going to fill - $clause = "{report}.{person_id} = ? AND {report}.{scopes_id} IN ({scopes_ids})"; + $clause = '{report}.{person_id} = ? AND {report}.{scopes_id} IN ({scopes_ids})'; // iterate over reachable scopes $scopes = $this->helper->getReachableScopes($this->security->getUser(), $role, $args['person']->getCenter()); @@ -169,150 +303,23 @@ class TimelineReportProvider implements TimelineProviderInterface if (1 === count($parameters)) { // nothing change, we simplify the clause - $clause = "{report}.{person_id} = ? AND FALSE = TRUE"; + $clause = '{report}.{person_id} = ? AND FALSE = TRUE'; } return [ - \strtr( + strtr( $clause, [ '{report}' => $report->getTableName(), '{person_id}' => $reportPersonId, '{scopes_id}' => $reportScopeId, - '{scopes_ids}' => \implode(', ', - \array_fill(0, \count($parameters)-1, '?')) + '{scopes_ids}' => implode( + ', ', + array_fill(0, \count($parameters) - 1, '?') + ), ] ), - $parameters + $parameters, ]; } - - private function getFromClause(string $context): string - { - $report = $this->em->getClassMetadata(Report::class); - $person = $this->em->getClassMetadata(Person::class); - $reportPersonId = $report - ->getAssociationMapping('person')['joinColumns'][0]['name'] - ; - $personId = $report - ->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName'] - ; - - $clause = "{report} ". - "JOIN {person} ON {report}.{person_id} = {person}.{id_person} "; - - return \strtr($clause, - [ - '{report}' => $report->getTableName(), - '{person}' => $person->getTableName(), - '{person_id}' => $reportPersonId, - '{id_person}' => $personId - ] - ); - } - - /** - * - * {@inheritDoc} - */ - public function getEntities(array $ids) - { - $reports = $this->em->getRepository('ChillReportBundle:Report') - ->findBy(array('id' => $ids)); - - $result = array(); - 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.html.twig', - 'template_data' => array( - 'report' => $entity, - 'context' => $context, - 'custom_fields_in_summary' => $this->getFieldsToRender($entity, $context), - ) - ); - } - - protected function getFieldsToRender(Report $entity, $context, array $args = array()) - { - //gather all custom fields which should appears in summary - $gatheredFields = array(); - - 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 we do not want to show empty values - if ($this->showEmptyValues === false) { - if ($customField->getType() === 'title') { - $options = $customField->getOptions(); - 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) { - $gatheredFields[] = $title; - $title = null; - } - if ($subtitle !== NULL) { - $gatheredFields[] = $subtitle; - $subtitle = null; - } - $gatheredFields[] = $customField; - } - } - } else { - $gatheredFields[] = $customField; - } - } - } - } - - return $gatheredFields; - - } - - /** - * - * {@inheritDoc} - */ - public function supportsType($type) - { - return $type === 'report'; - } - - /** - * check if the context is supported - * - * @param string $context - * @throws \LogicException if the context is not supported - */ - private function checkContext($context) - { - if ($context !== 'person' && $context !== 'center') { - throw new \LogicException("The context '$context' is not " - . "supported. Currently only 'person' and 'center' is supported"); - } - } - } 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 5e0161a7c..396a2960d 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -1,49 +1,65 @@ filterOrderHelperFactory = $filterOrderHelperFactory; } - private function getEntityContext(Request $request) + /** + * @Route( + * "/{_locale}/task/single-task/{id}/delete", + * name="chill_task_single_task_delete" + * ) + * + * @param mixed $id + */ + public function deleteAction(Request $request, $id) { - if ($request->query->has('person_id')) { - return 'person'; - } else if ($request->query->has('course_id')) { - return 'course'; - } else { - return null; - } - } - - - /** - * @Route( - * "/{_locale}/task/single-task/new", - * name="chill_task_single_task_new" - * ) - */ - public function newAction(Request $request) { - - $task = (new SingleTask()) - ->setAssignee($this->getUser()) - ->setType('task_default') - ; - - $entityType = $this->getEntityContext($request); - - if (NULL === $entityType) { - throw new BadRequestHttpException("You must provide a entity_type"); - } - - $entityId = $request->query->getInt("{$entityType}_id", 0); - - if ($entityId === null) { - return new BadRequestHttpException("You must provide a {$entityType}_id"); - } - - switch ($entityType) { - case 'person': - $person = $this->getDoctrine()->getManager() - ->getRepository(Person::class) - ->find($entityId); - - if ($person === null) { - $this->createNotFoundException("Invalid person id"); - } - - $task->setPerson($person); - $role = TaskVoter::CREATE_PERSON; - break; - case 'course': - $course = $this->getDoctrine()->getManager() - ->getRepository(AccompanyingPeriod::class) - ->find($entityId); - - if ($course === null) { - $this->createNotFoundException("Invalid accompanying course id"); - } - - $task->setCourse($course); - $role = TaskVoter::CREATE_COURSE; - break; - default: - return new BadRequestHttpException("context with {$entityType} is not supported"); - } - - $this->denyAccessUnlessGranted($role, $task, 'You are not ' - . 'allowed to create this task'); - - $form = $this->setCreateForm($task, new Role($role)); - - $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', $this->translator->trans("The task is created")); - - if ($request->query->has('returnPath')) { - return $this->redirect($request->query->get('returnPath')); - } - - if ($entityType === 'person') { - return $this->redirectToRoute('chill_task_singletask_by-person_list', [ - 'id' => $task->getPerson()->getId() - ]); - } elseif ($entityType === 'course') { - return $this->redirectToRoute('chill_task_singletask_by-course_list', [ - 'id' => $task->getCourse()->getId() - ]); - } - } else { - $this->addFlash('error', $this->translator->trans("This form contains errors")); - } - } - - switch ($entityType) { - case 'person': - return $this->render('@ChillTask/SingleTask/Person/new.html.twig', array( - 'form' => $form->createView(), - 'task' => $task, - 'person' => $task->getPerson(), - )); - case 'course': - return $this->render('@ChillTask/SingleTask/AccompanyingCourse/new.html.twig', array( - 'form' => $form->createView(), - 'task' => $task, - 'accompanyingCourse' => $task->getCourse(), - )); - default: - throw new \LogicException("entity context not supported"); - } - } - - /** - * @Route( - * "/{_locale}/task/single-task/{id}/show", - * name="chill_task_single_task_show" - * ) - */ - public function showAction(SingleTask $task, Request $request) - { - $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task); - - if ($person = $task->getContext() instanceof Person) { - $event = new PrivacyEvent($person, array( - 'element_class' => SingleTask::class, - 'element_id' => $task->getId(), - 'action' => 'show' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - } - - $timeline = $this->timelineBuilder - ->getTimelineHTML('task', array('task' => $task)); - - if ($task->getContext() instanceof Person) { - return $this->render('@ChillTask/SingleTask/Person/show.html.twig', array( - 'task' => $task, - 'timeline' => $timeline - )); - } else { - return $this->render('@ChillTask/SingleTask/AccompanyingCourse/show.html.twig', array( - 'task' => $task, - 'timeline' => $timeline - )); - } - - } - - - /** - * @Route( - * "/{_locale}/task/single-task/{id}/edit", - * name="chill_task_single_task_edit" - * ) - */ - public function editAction( - SingleTask $task, - Request $request - ) { - - $this->denyAccessUnlessGranted(TaskVoter::UPDATE, $task, 'You are not ' - . 'allowed to edit this task'); - - $event = (new UIEvent('single-task', $task)) - ->setForm($this->setCreateForm($task, new Role(TaskVoter::UPDATE))) - ; - $this->eventDispatcher->dispatch(UIEvent::EDIT_FORM, $event); - - $form = $event->getForm(); - - $form->handleRequest($request); - - if ($form->isSubmitted()) { - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->persist($task); - - $em->flush(); - - $this->addFlash('success', $this->translator - ->trans("The task has been updated")); - - if ($task->getContext() instanceof Person) { - $event = new PrivacyEvent($task->getPerson(), array( - 'element_class' => SingleTask::class, - 'element_id' => $task->getId(), - 'action' => 'update' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - if ($request->query->has('returnPath')) { - return $this->redirect($request->query->get('returnPath')); - } - - return $this->redirectToRoute( - 'chill_task_singletask_list', - ); - } else { - if ($request->query->has('returnPath')) { - return $this->redirect($request->query->get('returnPath')); - } - - return $this->redirectToRoute( - 'chill_task_singletask_by-course_list', ['id' => $task->getCourse()->getId()] - ); - } - } else { - $this->addFlash('error', $this->translator->trans("This form contains errors")); - } - } - - $this->eventDispatcher->dispatch(UIEvent::EDIT_PAGE, $event); - - if ($event->hasResponse()) { - return $event->getResponse(); - } - - if ($task->getContext() instanceof Person) { - $event = new PrivacyEvent($task->getPerson(), array( - 'element_class' => SingleTask::class, - 'element_id' => $task->getId(), - 'action' => 'edit' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('@ChillTask/SingleTask/Person/edit.html.twig', array( - 'task' => $task, - 'form' => $form->createView() - )); - } else { - return $this->render('@ChillTask/SingleTask/AccompanyingCourse/edit.html.twig', array( - 'task' => $task, - 'form' => $form->createView(), - 'accompanyingCourse' => $task->getCourse() - )); - } - - } - - - /** - * @Route( - * "/{_locale}/task/single-task/{id}/delete", - * name="chill_task_single_task_delete" - * ) - */ - public function deleteAction(Request $request, $id) { $course = null; $em = $this->getDoctrine()->getManager(); $task = $em->getRepository(SingleTask::class)->find($id); @@ -327,30 +98,31 @@ final class SingleTaskController extends AbstractController 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'); } - } else { $courseId = $task->getCourse()->getId(); - if ($courseId === null){ - return new Response("You must provide a course_id", Response::HTTP_BAD_REQUEST); + + if (null === $courseId) { + return new Response('You must provide a course_id', Response::HTTP_BAD_REQUEST); } $course = $this->getDoctrine()->getManager() ->getRepository(AccompanyingPeriod::class) ->find($courseId); - if($course === null){ - throw $this->createNotFoundException("Invalid accompanying period id"); + if (null === $course) { + throw $this->createNotFoundException('Invalid accompanying period id'); } } @@ -365,34 +137,33 @@ final class SingleTaskController extends AbstractController $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(), - // TODO reimplement scope - // 'scope_id' => $task->getScope()->getId(), - )); + $this->logger->notice('A task has been removed', [ + 'by_user' => $this->getUser()->getUsername(), + 'task_id' => $task->getId(), + 'description' => $task->getDescription(), + 'assignee' => $task->getAssignee(), + // TODO reimplement scope + // 'scope_id' => $task->getScope()->getId(), + ]); $em = $this->getDoctrine()->getManager(); $em->remove($task); $em->flush(); $this->addFlash('success', $this->translator - ->trans("The task has been successfully removed.")); + ->trans('The task has been successfully removed.')); if ($task->getContext() instanceof Person) { return $this->redirect($this->generateUrl( 'chill_task_singletask_by-person_list', - [ 'id' => $task->getPerson()->getId() ] - )); - } else { - return $this->redirect($this->generateUrl( - 'chill_task_singletask_by-course_list', - ['id' => $task->getCourse()->getId()] - )); + ['id' => $task->getPerson()->getId()] + )); } + + return $this->redirect($this->generateUrl( + 'chill_task_singletask_by-course_list', + ['id' => $task->getCourse()->getId()] + )); } } @@ -411,102 +182,110 @@ final class SingleTaskController extends AbstractController [ 'task' => $task, 'delete_form' => $form->createView(), - 'accompanyingCourse' => $course + 'accompanyingCourse' => $course, ] ); } /** - * - * @param SingleTask $task - * @param Role $role - * @return \Symfony\Component\Form\FormInterface - */ - protected function setCreateForm(SingleTask $task, Role $role) - { - $form = $this->createForm(SingleTaskType::class, $task, [ - 'role' => $role, - ]); - - $form->add('submit', SubmitType::class); - - return $form; - } - - /** - * - * @return Response * @Route( - * "/{_locale}/task/single-task/list/my", - * name="chill_task_singletask_my_tasks" + * "/{_locale}/task/single-task/{id}/edit", + * name="chill_task_single_task_edit" * ) */ - public function myTasksAction() - { - $this->denyAccessUnlessGranted('ROLE_USER'); + public function editAction( + SingleTask $task, + Request $request + ) { + $this->denyAccessUnlessGranted(TaskVoter::UPDATE, $task, 'You are not ' + . 'allowed to edit this task'); - $filterOrder = $this->buildFilterOrder(); - $flags = \array_merge( - $filterOrder->getCheckboxData('status'), - \array_map(fn ($i) => 'state_'.$i, $filterOrder->getCheckboxData('states')) - ); - $nb = $this->singleTaskAclAwareRepository->countByCurrentUsersTasks( - $filterOrder->getQueryString(), - $flags - ); - $paginator = $this->paginatorFactory->create($nb); - $tasks = $this->singleTaskAclAwareRepository->findByCurrentUsersTasks( - $filterOrder->getQueryString(), - $flags, - $paginator->getCurrentPageFirstItemNumber(), - $paginator->getItemsPerPage(), - [ - 'startDate' => 'DESC', - 'endDate' => 'DESC', - ] - ); + $event = (new UIEvent('single-task', $task)) + ->setForm($this->setCreateForm($task, new Role(TaskVoter::UPDATE))); + $this->eventDispatcher->dispatch(UIEvent::EDIT_FORM, $event); - return $this->render('@ChillTask/SingleTask/List/index_my_tasks.html.twig', [ - 'tasks' => $tasks, - 'paginator' => $paginator, - 'filter_order' => $filterOrder, + $form = $event->getForm(); + + $form->handleRequest($request); + + if ($form->isSubmitted()) { + if ($form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->persist($task); + + $em->flush(); + + $this->addFlash('success', $this->translator + ->trans('The task has been updated')); + + if ($task->getContext() instanceof Person) { + $event = new PrivacyEvent($task->getPerson(), [ + 'element_class' => SingleTask::class, + 'element_id' => $task->getId(), + 'action' => 'update', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + if ($request->query->has('returnPath')) { + return $this->redirect($request->query->get('returnPath')); + } + + return $this->redirectToRoute( + 'chill_task_singletask_list', + ); + } + + if ($request->query->has('returnPath')) { + return $this->redirect($request->query->get('returnPath')); + } + + return $this->redirectToRoute( + 'chill_task_singletask_by-course_list', + ['id' => $task->getCourse()->getId()] + ); + } + $this->addFlash('error', $this->translator->trans('This form contains errors')); + } + + $this->eventDispatcher->dispatch(UIEvent::EDIT_PAGE, $event); + + if ($event->hasResponse()) { + return $event->getResponse(); + } + + if ($task->getContext() instanceof Person) { + $event = new PrivacyEvent($task->getPerson(), [ + 'element_class' => SingleTask::class, + 'element_id' => $task->getId(), + 'action' => 'edit', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('@ChillTask/SingleTask/Person/edit.html.twig', [ + 'task' => $task, + 'form' => $form->createView(), + ]); + } + + return $this->render('@ChillTask/SingleTask/AccompanyingCourse/edit.html.twig', [ + 'task' => $task, + 'form' => $form->createView(), + 'accompanyingCourse' => $task->getCourse(), ]); } - private function buildFilterOrder(): FilterOrderHelper - { - $statuses = ['no-alert', 'warning', 'alert']; - $statusTrans = [ - 'Tasks without alert', - 'Tasks near deadline', - 'Tasks over deadline', - ]; - $states = [ - // todo: get a list of possible states dynamically - 'new', 'in_progress', 'closed', 'canceled' - ]; - return $this->filterOrderHelperFactory - ->create(self::class) - ->addSearchBox() - ->addCheckbox('status', $statuses, $statuses, $statusTrans) - ->addCheckbox('states', $states, ['new', 'in_progress']) - ->build() - ; - } - /** - * * Arguments: * - user_id * - scope_id * - s * - 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/single-task/list", - * name="chill_task_singletask_list" + * "/{_locale}/task/single-task/list", + * name="chill_task_singletask_list" * ) */ public function listAction( @@ -515,9 +294,9 @@ final class SingleTaskController extends AbstractController $this->denyAccessUnlessGranted(TaskVoter::SHOW, null); $filterOrder = $this->buildFilterOrder(); - $flags = \array_merge( + $flags = array_merge( $filterOrder->getCheckboxData('status'), - \array_map(fn ($i) => 'state_'.$i, $filterOrder->getCheckboxData('states')) + array_map(fn ($i) => 'state_' . $i, $filterOrder->getCheckboxData('states')) ); $nb = $this->singleTaskAclAwareRepository->countByAllViewable( $filterOrder->getQueryString(), @@ -541,49 +320,28 @@ final class SingleTaskController extends AbstractController } return $this->render('@ChillTask/SingleTask/List/index.html.twig', [ - 'tasks' => $tasks, - 'paginator' => $paginator, - 'filter_order' => $filterOrder - ]); - - } - - /** - * Creates a form to delete a Task entity by id. - * - * @param mixed $id The entity id - * - * @return \Symfony\Component\Form\Form The form - */ - private function createDeleteForm($id) - { - return $this->createFormBuilder() - ->setAction($this->generateUrl( - 'chill_task_single_task_delete', - array('id' => $id))) - ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + 'tasks' => $tasks, + 'paginator' => $paginator, + 'filter_order' => $filterOrder, + ]); } /** * @Route( - * "/{_locale}/task/single-task/by-course/{id}", - * name="chill_task_singletask_by-course_list") + * "/{_locale}/task/single-task/by-course/{id}", + * name="chill_task_singletask_by-course_list") */ public function listCourseTasks( AccompanyingPeriod $course, FormFactoryInterface $formFactory, Request $request - ): Response - { + ): Response { $this->denyAccessUnlessGranted(TaskVoter::SHOW, $course); $filterOrder = $this->buildFilterOrder(); - $flags = \array_merge( + $flags = array_merge( $filterOrder->getCheckboxData('status'), - \array_map(fn ($i) => 'state_'.$i, $filterOrder->getCheckboxData('states')) + array_map(fn ($i) => 'state_' . $i, $filterOrder->getCheckboxData('states')) ); $nb = $this->singleTaskAclAwareRepository->countByCourse( $course, @@ -614,25 +372,25 @@ final class SingleTaskController extends AbstractController 'tasks' => $tasks, 'accompanyingCourse' => $course, 'paginator' => $paginator, - 'filter_order' => $filterOrder - ]); + 'filter_order' => $filterOrder, + ] + ); } /** * @Route( - * "/{_locale}/task/single-task/by-person/{id}", - * name="chill_task_singletask_by-person_list") + * "/{_locale}/task/single-task/by-person/{id}", + * name="chill_task_singletask_by-person_list") */ public function listPersonTasks( Person $person ): Response { - $this->denyAccessUnlessGranted(TaskVoter::SHOW, $person); $filterOrder = $this->buildFilterOrder(); - $flags = \array_merge( + $flags = array_merge( $filterOrder->getCheckboxData('status'), - \array_map(fn ($i) => 'state_'.$i, $filterOrder->getCheckboxData('states')) + array_map(fn ($i) => 'state_' . $i, $filterOrder->getCheckboxData('states')) ); $nb = $this->singleTaskAclAwareRepository->countByPerson( $person, @@ -663,7 +421,264 @@ final class SingleTaskController extends AbstractController 'tasks' => $tasks, 'person' => $person, 'paginator' => $paginator, - 'filter_order' => $filterOrder + 'filter_order' => $filterOrder, + ] + ); + } + + /** + * @return Response + * @Route( + * "/{_locale}/task/single-task/list/my", + * name="chill_task_singletask_my_tasks" + * ) + */ + public function myTasksAction() + { + $this->denyAccessUnlessGranted('ROLE_USER'); + + $filterOrder = $this->buildFilterOrder(); + $flags = array_merge( + $filterOrder->getCheckboxData('status'), + array_map(fn ($i) => 'state_' . $i, $filterOrder->getCheckboxData('states')) + ); + $nb = $this->singleTaskAclAwareRepository->countByCurrentUsersTasks( + $filterOrder->getQueryString(), + $flags + ); + $paginator = $this->paginatorFactory->create($nb); + $tasks = $this->singleTaskAclAwareRepository->findByCurrentUsersTasks( + $filterOrder->getQueryString(), + $flags, + $paginator->getCurrentPageFirstItemNumber(), + $paginator->getItemsPerPage(), + [ + 'startDate' => 'DESC', + 'endDate' => 'DESC', + ] + ); + + return $this->render('@ChillTask/SingleTask/List/index_my_tasks.html.twig', [ + 'tasks' => $tasks, + 'paginator' => $paginator, + 'filter_order' => $filterOrder, + ]); + } + + /** + * @Route( + * "/{_locale}/task/single-task/new", + * name="chill_task_single_task_new" + * ) + */ + public function newAction(Request $request) + { + $task = (new SingleTask()) + ->setAssignee($this->getUser()) + ->setType('task_default'); + + $entityType = $this->getEntityContext($request); + + if (null === $entityType) { + throw new BadRequestHttpException('You must provide a entity_type'); + } + + $entityId = $request->query->getInt("{$entityType}_id", 0); + + if (null === $entityId) { + return new BadRequestHttpException("You must provide a {$entityType}_id"); + } + + switch ($entityType) { + case 'person': + $person = $this->getDoctrine()->getManager() + ->getRepository(Person::class) + ->find($entityId); + + if (null === $person) { + $this->createNotFoundException('Invalid person id'); + } + + $task->setPerson($person); + $role = TaskVoter::CREATE_PERSON; + + break; + + case 'course': + $course = $this->getDoctrine()->getManager() + ->getRepository(AccompanyingPeriod::class) + ->find($entityId); + + if (null === $course) { + $this->createNotFoundException('Invalid accompanying course id'); + } + + $task->setCourse($course); + $role = TaskVoter::CREATE_COURSE; + + break; + + default: + return new BadRequestHttpException("context with {$entityType} is not supported"); + } + + $this->denyAccessUnlessGranted($role, $task, 'You are not ' + . 'allowed to create this task'); + + $form = $this->setCreateForm($task, new Role($role)); + + $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', $this->translator->trans('The task is created')); + + if ($request->query->has('returnPath')) { + return $this->redirect($request->query->get('returnPath')); + } + + if ('person' === $entityType) { + return $this->redirectToRoute('chill_task_singletask_by-person_list', [ + 'id' => $task->getPerson()->getId(), + ]); + } + + if ('course' === $entityType) { + return $this->redirectToRoute('chill_task_singletask_by-course_list', [ + 'id' => $task->getCourse()->getId(), + ]); + } + } else { + $this->addFlash('error', $this->translator->trans('This form contains errors')); + } + } + + switch ($entityType) { + case 'person': + return $this->render('@ChillTask/SingleTask/Person/new.html.twig', [ + 'form' => $form->createView(), + 'task' => $task, + 'person' => $task->getPerson(), + ]); + + case 'course': + return $this->render('@ChillTask/SingleTask/AccompanyingCourse/new.html.twig', [ + 'form' => $form->createView(), + 'task' => $task, + 'accompanyingCourse' => $task->getCourse(), + ]); + + default: + throw new LogicException('entity context not supported'); + } + } + + /** + * @Route( + * "/{_locale}/task/single-task/{id}/show", + * name="chill_task_single_task_show" + * ) + */ + public function showAction(SingleTask $task, Request $request) + { + $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task); + + if ($person = $task->getContext() instanceof Person) { + $event = new PrivacyEvent($person, [ + 'element_class' => SingleTask::class, + 'element_id' => $task->getId(), + 'action' => 'show', ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + } + + $timeline = $this->timelineBuilder + ->getTimelineHTML('task', ['task' => $task]); + + if ($task->getContext() instanceof Person) { + return $this->render('@ChillTask/SingleTask/Person/show.html.twig', [ + 'task' => $task, + 'timeline' => $timeline, + ]); + } + + return $this->render('@ChillTask/SingleTask/AccompanyingCourse/show.html.twig', [ + 'task' => $task, + 'timeline' => $timeline, + ]); + } + + /** + * @return \Symfony\Component\Form\FormInterface + */ + protected function setCreateForm(SingleTask $task, Role $role) + { + $form = $this->createForm(SingleTaskType::class, $task, [ + 'role' => $role, + ]); + + $form->add('submit', SubmitType::class); + + return $form; + } + + private function buildFilterOrder(): FilterOrderHelper + { + $statuses = ['no-alert', 'warning', 'alert']; + $statusTrans = [ + 'Tasks without alert', + 'Tasks near deadline', + 'Tasks over deadline', + ]; + $states = [ + // todo: get a list of possible states dynamically + 'new', 'in_progress', 'closed', 'canceled', + ]; + + return $this->filterOrderHelperFactory + ->create(self::class) + ->addSearchBox() + ->addCheckbox('status', $statuses, $statuses, $statusTrans) + ->addCheckbox('states', $states, ['new', 'in_progress']) + ->build(); + } + + /** + * Creates a form to delete a Task entity by id. + * + * @param mixed $id The entity id + * + * @return \Symfony\Component\Form\Form The form + */ + private function createDeleteForm($id) + { + return $this->createFormBuilder() + ->setAction($this->generateUrl( + 'chill_task_single_task_delete', + ['id' => $id] + )) + ->setMethod('DELETE') + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); + } + + private function getEntityContext(Request $request) + { + if ($request->query->has('person_id')) { + return 'person'; + } + + if ($request->query->has('course_id')) { + return 'course'; + } + + return null; } } diff --git a/src/Bundle/ChillTaskBundle/Controller/TaskController.php b/src/Bundle/ChillTaskBundle/Controller/TaskController.php index c137c166d..498997abc 100644 --- a/src/Bundle/ChillTaskBundle/Controller/TaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/TaskController.php @@ -1,45 +1,48 @@ 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', []), + ] + ); $task->getCourse() === null ? $defaultTemplate = '@ChillTask/SingleTask/Person/transition.html.twig' : $defaultTemplate = '@ChillTask/SingleTask/AccompanyingCourse/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 513d18ea8..f51bb292a 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,33 +41,39 @@ 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 " + 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']); + $permissionsGroup->getName(), + $scope->getName()['en'] + ); $roleScopeUpdate = (new RoleScope()) - ->setRole(TaskVoter::UPDATE) - ->setScope($scope); + ->setRole(TaskVoter::UPDATE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeUpdate); $roleScopeCreateP = (new RoleScope()) - ->setRole(TaskVoter::CREATE_PERSON) - ->setScope($scope); + ->setRole(TaskVoter::CREATE_PERSON) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreateP); $roleScopeCreateC = (new RoleScope()) ->setRole(TaskVoter::CREATE_COURSE) ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreateC); $roleScopeDelete = (new RoleScope()) - ->setRole(TaskVoter::DELETE) - ->setScope($scope); + ->setRole(TaskVoter::DELETE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeDelete); $manager->persist($roleScopeUpdate); @@ -87,10 +81,8 @@ class LoadTaskACL extends AbstractFixture implements OrderedFixtureInterface $manager->persist($roleScopeCreateC); $manager->persist($roleScopeDelete); } - } $manager->flush(); } - } diff --git a/src/Bundle/ChillTaskBundle/DependencyInjection/ChillTaskExtension.php b/src/Bundle/ChillTaskBundle/DependencyInjection/ChillTaskExtension.php index ed2a36595..0c73c16da 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'); @@ -45,27 +49,27 @@ class ChillTaskExtension extends Extension implements PrependExtensionInterface $this->prependWorkflows($container); } + protected function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + TaskVoter::UPDATE => [TaskVoter::SHOW], + TaskVoter::CREATE_COURSE => [TaskVoter::SHOW], + TaskVoter::CREATE_PERSON => [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' - ) - ) - )); - } - - protected function prependAuthorization(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - TaskVoter::UPDATE => [TaskVoter::SHOW], - TaskVoter::CREATE_COURSE => [TaskVoter::SHOW], - TaskVoter::CREATE_PERSON => [TaskVoter::SHOW], - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillTaskBundle/config/routes.yaml', + ], + ], + ]); } protected function prependWorkflows(ContainerBuilder $container) @@ -76,29 +80,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 $this->getCourse()->getCenter(); + + return null; + } + + public function getCircle(): ?Scope + { + return $this->circle; + } + + public function getContext() + { + return $this->getPerson() ?? $this->getCourse(); + } + + public function getCourse(): ?AccompanyingPeriod + { + return $this->course; } /** - * 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 */ @@ -114,8 +175,39 @@ 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; + } + + public function setCourse(AccompanyingPeriod $course) + { + $this->course = $course; + + return $this; + } + /** - * Set currentStates + * Set currentStates. * * The current states are sorted in a single array, non associative. * @@ -125,25 +217,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 + * Set description. * - * The states are returned as required by marking store format. + * @param string $description * - * @return array + * @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 * @@ -157,120 +258,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 getCourse(): ?AccompanyingPeriod - { - return $this->course; - } - - 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 setCourse(AccompanyingPeriod $course) - { - $this->course = $course; - 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(); - } else { - return $this->getCourse()->getCenter(); - } - - return null; - - } - - public function getContext() - { - return $this->getPerson() ?? $this->getCourse(); - } - - 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..34df011b0 100644 --- a/src/Bundle/ChillTaskBundle/Entity/RecurringTask.php +++ b/src/Bundle/ChillTaskBundle/Entity/RecurringTask.php @@ -1,20 +1,35 @@ singleTasks = new ArrayCollection(); } - /** - * Get id + * Get firstOccurenceEndDate. + * + * @return DateTime + */ + public function getFirstOccurenceEndDate() + { + return $this->firstOccurenceEndDate; + } + + /** + * Get id. * * @return int */ @@ -88,9 +103,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 +157,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 +171,7 @@ class RecurringTask extends AbstractTask } /** - * Get lastOccurenceEndDate - * - * @return \DateTime - */ - public function getLastOccurenceEndDate() - { - return $this->lastOccurenceEndDate; - } - - /** - * Set occurenceFrequency + * Set occurenceFrequency. * * @param string $occurenceFrequency * @@ -150,17 +185,7 @@ class RecurringTask extends AbstractTask } /** - * Get occurenceFrequency - * - * @return string - */ - public function getOccurenceFrequency() - { - return $this->occurenceFrequency; - } - - /** - * Set occurenceStartDate + * Set occurenceStartDate. * * @param dateinterval $occurenceStartDate * @@ -174,17 +199,7 @@ class RecurringTask extends AbstractTask } /** - * Get occurenceStartDate - * - * @return dateinterval - */ - public function getOccurenceStartDate() - { - return $this->occurenceStartDate; - } - - /** - * Set occurenceWarningInterval + * Set occurenceWarningInterval. * * @param dateinterval $occurenceWarningInterval * @@ -196,15 +211,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 579143718..d6e918799 100644 --- a/src/Bundle/ChillTaskBundle/Entity/SingleTask.php +++ b/src/Bundle/ChillTaskBundle/Entity/SingleTask.php @@ -1,36 +1,54 @@ 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" + * targetEntity="RecurringTask", + * inversedBy="singleTasks" * ) */ private $recurringTask; /** + * @var DateTime * + * @ORM\Column(name="start_date", type="date", nullable=true) + * @Assert\Date + * + * @Assert\Expression( + * "value === null or this.getEndDate() === null or value < this.getEndDate()", + * message="The start date must be before the end date" + * ) + * + * @Assert\Expression( + * "value === null or this.getWarningDate() === null or this.getWarningDate() > this.getStartDate()", + * message="The start date must be before warning date" + * ) + */ + private $startDate; + + /** * @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 = new ArrayCollection(); } + /** + * Get endDate. + * + * @return DateTime + */ + public function getEndDate() + { + return $this->endDate; + } /** - * Get id + * Get id. * * @return int */ @@ -118,85 +133,33 @@ 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; } - /** - * Set endDate - * - * @param \DateTime $endDate - * - * @return SingleTask - */ - public function setEndDate($endDate) + public function getTaskPlaceEvents(): Collection { - $this->endDate = $endDate; - - return $this; - } - - /** - * Get endDate - * - * @return \DateTime - */ - public function getEndDate() - { - return $this->endDate; - } - - /** - * Set warningInterval - * - * @param string $warningInterval - * - * @return SingleTask - */ - public function setWarningInterval($warningInterval) - { - $this->warningInterval = $warningInterval; - - return $this; - } - - /** - * Get warningInterval - * - * @return \DateInterval - */ - public function getWarningInterval() - { - return $this->warningInterval; + return $this->taskPlaceEvents; } /** * Get the Warning date, computed from the difference between the - * end date and the warning interval + * end date and the warning interval. * * Return null if warningDate or endDate is null * - * @return \DateTimeImmutable + * @return DateTimeImmutable */ public function getWarningDate() { @@ -208,23 +171,51 @@ class SingleTask extends AbstractTask return null; } - return \DateTimeImmutable::createFromMutable($this->getEndDate()) + return DateTimeImmutable::createFromMutable($this->getEndDate()) ->sub($this->getWarningInterval()); } - function getRecurringTask(): RecurringTask + /** + * Get warningInterval. + * + * @return DateInterval + */ + public function getWarningInterval() { - return $this->recurringTask; + return $this->warningInterval; } - function setRecurringTask(RecurringTask $recurringTask) + /** + * Set endDate. + * + * @param DateTime $endDate + * + * @return SingleTask + */ + public function setEndDate($endDate) + { + $this->endDate = $endDate; + + return $this; + } + + public function setRecurringTask(RecurringTask $recurringTask) { $this->recurringTask = $recurringTask; } - public function getTaskPlaceEvents(): Collection + /** + * Set startDate. + * + * @param DateTime $startDate + * + * @return SingleTask + */ + public function setStartDate($startDate) { - return $this->taskPlaceEvents; + $this->startDate = $startDate; + + return $this; } public function setTaskPlaceEvents(Collection $taskPlaceEvents) @@ -233,5 +224,18 @@ class SingleTask extends AbstractTask return $this; } -} + /** + * Set warningInterval. + * + * @param string $warningInterval + * + * @return SingleTask + */ + public function setWarningInterval($warningInterval) + { + $this->warningInterval = $warningInterval; + + 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 634035f96..d4c230469 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php @@ -1,75 +1,60 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public 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 +64,6 @@ class SingleTaskListType extends AbstractType $this->taskWorkflowManager = $taskWorkflowManager; } - public function buildForm(FormBuilderInterface $builder, array $options) { $statuses = [ @@ -87,56 +71,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 +126,7 @@ class SingleTaskListType extends AbstractType 'choices' => $reachablesCenters, 'label' => 'Center', 'required' => false, - 'placeholder' => 'All centers' + 'placeholder' => 'All centers', ]); } } else { @@ -152,130 +134,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) @@ -290,7 +150,124 @@ 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 9af1197c2..7bb5a10c4 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php @@ -1,33 +1,44 @@ parameterBag = $parameterBag; $this->centerResolverDispatcher = $centerResolverDispatcher; $this->scopeResolverDispatcher = $scopeResolverDispatcher; @@ -38,7 +49,7 @@ class SingleTaskType extends AbstractType $center = null; $isScopeConcerned = false; - if (NULL !== $task = $options['data']) { + if (null !== $task = $options['data']) { $center = $this->centerResolverDispatcher->resolveCenter($task); $isScopeConcerned = $this->scopeResolverDispatcher->isConcerned($task); } @@ -46,23 +57,23 @@ class SingleTaskType extends AbstractType $builder ->add('title', TextType::class) ->add('description', ChillTextareaType::class, [ - 'required' => false + 'required' => false, ]) ->add('assignee', UserPickerType::class, [ 'required' => false, 'center' => $center, - 'role' => TaskVoter::SHOW, + 'role' => TaskVoter::SHOW, 'placeholder' => 'Not assigned', - 'attr' => [ 'class' => ' select2 '] - ]) + 'attr' => ['class' => ' select2 '], + ]) ->add('startDate', ChillDateType::class, [ - 'required' => false + 'required' => false, ]) ->add('endDate', ChillDateType::class, [ - 'required' => false + 'required' => false, ]) ->add('warningInterval', DateIntervalType::class, [ - 'required' => false + 'required' => false, ]); if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) { @@ -70,7 +81,7 @@ class SingleTaskType extends AbstractType ->add('circle', ScopePickerType::class, [ 'center' => $center, 'role' => $options['role'], - 'required' => false + 'required' => false, ]); } } @@ -79,7 +90,6 @@ class SingleTaskType extends AbstractType { $resolver ->setRequired('role') - ->setAllowedTypes('role', [ Role::class, 'string' ]) - ; + ->setAllowedTypes('role', [Role::class, 'string']); } } diff --git a/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php index dfc95535b..d97980efe 100644 --- a/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php @@ -1,105 +1,97 @@ + +/** + * 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 Knp\Menu\MenuItem; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Chill\TaskBundle\Security\Authorization\TaskVoter; +use Knp\Menu\MenuItem; +use LogicException; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ class MenuBuilder 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) + public function buildAccompanyingCourseMenu($menu, $parameters) { - switch($menuId) { - case 'person': - $this->buildPersonMenu($menu, $parameters); - break; - case 'accompanyingCourse': - $this->buildAccompanyingCourseMenu($menu, $parameters); - break; - case 'section': - $menu->setExtras('icons', 'tasks'); - break; - default: - throw new \LogicException("this menuid $menuId is not implemented"); + $course = $parameters['accompanyingCourse']; + + if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $course)) { + $menu->addChild( + $this->translator->trans('Tasks'), + [ + 'route' => 'chill_task_singletask_by-course_list', + 'routeParameters' => ['id' => $course->getId()], + ] + ) + ->setExtra('order', 400); } } - public function buildPersonMenu($menu, $parameters){ + public function buildMenu($menuId, MenuItem $menu, array $parameters) + { + switch ($menuId) { + case 'person': + $this->buildPersonMenu($menu, $parameters); + break; + + case 'accompanyingCourse': + $this->buildAccompanyingCourseMenu($menu, $parameters); + + break; + + case 'section': + $menu->setExtras('icons', 'tasks'); + + break; + + default: + throw new LogicException("this menuid {$menuId} is not implemented"); + } + } + + public function buildPersonMenu($menu, $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_by-person_list', - 'routeParameters' => - [ 'id' => $person->getId() ] - ]) + 'routeParameters' => ['id' => $person->getId()], + ] + ) ->setExtra('order', 400); } } - public function buildAccompanyingCourseMenu($menu, $parameters){ - - $course = $parameters['accompanyingCourse']; - - if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $course)) { - $menu->addChild( - $this->translator->trans('Tasks'), [ - 'route' => 'chill_task_singletask_by-course_list', - 'routeParameters' => - [ 'id' => $course->getId() ] - ]) - ->setExtra('order', 400); - } - } - - public static function getMenuIds(): array { return ['person', 'accompanyingCourse']; 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 419dab9b3..09209d560 100644 --- a/src/Bundle/ChillTaskBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/UserMenuBuilder.php @@ -1,42 +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\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; +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; -/** - * - * - * @author Julien Fastré - */ class UserMenuBuilder implements LocalMenuBuilderInterface { + /** + * @var AuthorizationCheckerInterface + */ + public $authorizationChecker; /** - * * @var CountNotificationTask */ public $counter; @@ -47,17 +35,10 @@ class UserMenuBuilder implements LocalMenuBuilderInterface public $tokenStorage; /** - * * @var TranslatorInterface */ public $translator; - /** - * - * @var AuthorizationCheckerInterface - */ - public $authorizationChecker; - public function __construct( CountNotificationTask $counter, TokenStorageInterface $tokenStorage, @@ -70,14 +51,9 @@ class UserMenuBuilder implements LocalMenuBuilderInterface $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; } @@ -85,7 +61,7 @@ class UserMenuBuilder implements LocalMenuBuilderInterface $ended = $this->counter->countNotificationEnded($user); $warning = $this->counter->countNotificationWarning($user); - if ($ended > 0) { + if (0 < $ended) { $this->addItemInMenu( $menu, '%number% tasks over deadline', @@ -96,7 +72,7 @@ class UserMenuBuilder implements LocalMenuBuilderInterface ); } - if ($warning > 0) { + if (0 < $warning) { $this->addItemInMenu( $menu, '%number% tasks near deadline', @@ -107,19 +83,23 @@ class UserMenuBuilder implements LocalMenuBuilderInterface ); } - $menu->addChild("My tasks", [ - 'route' => 'chill_task_singletask_my_tasks' - ]) + $menu->addChild('My tasks', [ + 'route' => 'chill_task_singletask_my_tasks', + ]) ->setExtras([ 'order' => -10, - 'icon' => 'tasks' + 'icon' => 'tasks', ]); + } + public static function getMenuIds(): array + { + return ['user']; } protected function addItemInMenu(MenuItem $menu, $message, $number, $order, array $states = [], array $status = []) { - if ($number > 0) { + if (0 < $number) { $menu->addChild( $this->translator->transChoice($message, $number), [ @@ -128,15 +108,16 @@ class UserMenuBuilder implements LocalMenuBuilderInterface 'f' => [ 'checkboxes' => [ 'states' => $states, - 'status' => $status - ] - ] + 'status' => $status, + ], + ], + ], ] - ]) + ) ->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; } - public function findByCurrentUsersTasks( + public function buildBaseQuery( ?string $pattern = null, - ?array $flags = [], - ?int $start = 0, - ?int $limit = 50, - ?array $orderBy = [] - ): array { - $qb = $this->buildQueryMyTasks($pattern, $flags); + ?array $flags = [] + ): QueryBuilder { + $qb = $this->em->createQueryBuilder(); + $qb + ->from(SingleTask::class, 't'); - return $this->getResult($qb, $start, $limit, $orderBy); + if (!empty($pattern)) { + $qb->andWhere($qb->expr()->like('LOWER(UNACCENT(t.title))', 'LOWER(UNACCENT(:pattern))')) + ->setParameter('pattern', '%' . $pattern . '%'); + } + + if (count($flags) > 0) { + $orXDate = $qb->expr()->orX(); + $orXState = $qb->expr()->orX(); + $now = new DateTime(); + + foreach ($flags as $key => $flag) { + switch ($flag) { + case 'no-alert': + $orXDate + ->add( + $qb->expr()->orX( + $qb->expr()->isNull('t.endDate'), + $qb->expr()->gte('t.endDate - COALESCE(t.warningInterval, :intervalBlank)', ':now') + ) + ); + $qb + ->setParameter('intervalBlank', new DateInterval('P0D')) + ->setParameter('now', $now); + + break; + + case 'warning': + $orXDate + ->add( + $qb->expr()->andX( + $qb->expr()->not($qb->expr()->isNull('t.endDate')), + $qb->expr()->not($qb->expr()->isNull('t.warningInterval')), + $qb->expr()->lte('t.endDate - t.warningInterval', ':now'), + $qb->expr()->gt('t.endDate', ':now') + ) + ); + $qb + ->setParameter('now', $now); + + break; + + case 'alert': + $orXDate + ->add( + $qb->expr()->andX( + $qb->expr()->not($qb->expr()->isNull('t.endDate')), + $qb->expr()->lte('t.endDate', ':now') + ) + ); + $qb + ->setParameter('now', $now); + + break; + + case 'state_new': + $orXState + ->add( + 'JSONB_ARRAY_LENGTH(t.currentStates) = 0' + ); + + break; + + case substr($flag, 0, 6) === 'state_': + $state = substr($flag, 6); + $orXState + ->add( + "JSONB_EXISTS_IN_ARRAY(t.currentStates, :state_{$key}) = 'TRUE'" + ); + $qb->setParameter("state_{$key}", $state); + + break; + + default: + throw new LogicException("this flag is not supported: {$flag}"); + } + } + + if ($orXDate->count() > 0) { + $qb->andWhere($orXDate); + } + + if ($orXState->count() > 0) { + $qb->andWhere($orXState); + } + } + + return $qb; } - public function countByCurrentUsersTasks( + public function buildQueryByCourse( + AccompanyingPeriod $course, + ?string $pattern = null, + ?array $flags = [] + ): QueryBuilder { + $qb = $this->buildBaseQuery($pattern, $flags); + + return $qb + ->andWhere($qb->expr()->eq('t.course', ':course')) + ->setParameter('course', $course); + } + + public function buildQueryByPerson( + Person $person, + ?string $pattern = null, + ?array $flags = [] + ): QueryBuilder { + $qb = $this->buildBaseQuery($pattern, $flags); + + return $qb + ->andWhere($qb->expr()->eq('t.person', ':person')) + ->setParameter('person', $person); + } + + public function buildQueryMyTasks( + ?string $pattern = null, + ?array $flags = [] + ): QueryBuilder { + $qb = $this->buildBaseQuery($pattern, $flags); + + return $qb + ->andWhere($qb->expr()->eq('t.assignee', ':user')) + ->setParameter('user', $this->security->getUser()); + } + + public function countByAllViewable( ?string $pattern = null, ?array $flags = [] ): int { - return $this->buildQueryMyTasks($pattern, $flags) + $qb = $this->buildBaseQuery($pattern, $flags); + + return $this + ->addACLGlobal($qb) ->select('COUNT(t)') ->getQuery()->getSingleScalarResult(); } - public function findByCourse( - AccompanyingPeriod $course, - ?string $pattern = null, - ?array $flags = [], - ?int $start = 0, - ?int $limit = 50, - ?array $orderBy = [] - ): array { - $qb = $this->buildQueryByCourse($course, $pattern, $flags); - $qb = $this->addACL($qb, $course); - - return $this->getResult($qb, $start, $limit, $orderBy); - } - public function countByCourse( AccompanyingPeriod $course, ?string $pattern = null, @@ -79,18 +204,13 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository ->getQuery()->getSingleScalarResult(); } - public function findByPerson( - Person $person, + public function countByCurrentUsersTasks( ?string $pattern = null, - ?array $flags = [], - ?int $start = 0, - ?int $limit = 50, - ?array $orderBy = [] - ): array { - $qb = $this->buildQueryByPerson($person, $pattern, $flags); - $qb = $this->addACL($qb, $person); - - return $this->getResult($qb, $start, $limit, $orderBy); + ?array $flags = [] + ): int { + return $this->buildQueryMyTasks($pattern, $flags) + ->select('COUNT(t)') + ->getQuery()->getSingleScalarResult(); } public function countByPerson( @@ -106,18 +226,6 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository ->getQuery()->getSingleScalarResult(); } - public function countByAllViewable( - ?string $pattern = null, - ?array $flags = [] - ): int { - $qb = $this->buildBaseQuery($pattern, $flags); - - return $this - ->addACLGlobal($qb) - ->select('COUNT(t)') - ->getQuery()->getSingleScalarResult(); - } - public function findByAllViewable( ?string $pattern = null, ?array $flags = [], @@ -131,42 +239,44 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository return $this->getResult($qb, $start, $limit, $orderBy); } - public function buildQueryByCourse( + public function findByCourse( AccompanyingPeriod $course, ?string $pattern = null, - ?array $flags = [] - ) : QueryBuilder { - $qb = $this->buildBaseQuery($pattern, $flags); + ?array $flags = [], + ?int $start = 0, + ?int $limit = 50, + ?array $orderBy = [] + ): array { + $qb = $this->buildQueryByCourse($course, $pattern, $flags); + $qb = $this->addACL($qb, $course); - return $qb - ->andWhere($qb->expr()->eq('t.course', ':course')) - ->setParameter('course', $course) - ; + return $this->getResult($qb, $start, $limit, $orderBy); } - public function buildQueryByPerson( - Person $person, - ?string $pattern = null, - ?array $flags = [] - ): QueryBuilder - { - $qb = $this->buildBaseQuery($pattern, $flags); - - return $qb - ->andWhere($qb->expr()->eq('t.person', ':person')) - ->setParameter('person', $person); - } - - public function buildQueryMyTasks( + public function findByCurrentUsersTasks( ?string $pattern = null, - ?array $flags = [] - ): QueryBuilder { - $qb = $this->buildBaseQuery($pattern, $flags); + ?array $flags = [], + ?int $start = 0, + ?int $limit = 50, + ?array $orderBy = [] + ): array { + $qb = $this->buildQueryMyTasks($pattern, $flags); - return $qb - ->andWhere($qb->expr()->eq('t.assignee', ':user')) - ->setParameter('user', $this->security->getUser()) - ; + return $this->getResult($qb, $start, $limit, $orderBy); + } + + public function findByPerson( + Person $person, + ?string $pattern = null, + ?array $flags = [], + ?int $start = 0, + ?int $limit = 50, + ?array $orderBy = [] + ): array { + $qb = $this->buildQueryByPerson($person, $pattern, $flags); + $qb = $this->addACL($qb, $person); + + return $this->getResult($qb, $start, $limit, $orderBy); } public function getResult( @@ -179,11 +289,10 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository $qb ->setFirstResult($start) - ->setMaxResults($limit) - ; + ->setMaxResults($limit); foreach ($orderBy as $field => $direction) { - $qb->addOrderBy('t.'.$field, $direction); + $qb->addOrderBy('t.' . $field, $direction); } return $qb->getQuery()->getResult(); @@ -193,11 +302,14 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository QueryBuilder $qb, $entity ): QueryBuilder { - $scopes = $this->authorizationHelper->getReachableScopes($this->security->getUser(), - TaskVoter::SHOW, $this->centerResolverDispatcher->resolveCenter($entity)); + $scopes = $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + TaskVoter::SHOW, + $this->centerResolverDispatcher->resolveCenter($entity) + ); - return $qb->andWhere($qb->expr()->in('t.circle', ':scopes')) - ->setParameter('scopes', $scopes); + return $qb->andWhere($qb->expr()->in('t.circle', ':scopes')) + ->setParameter('scopes', $scopes); } private function addACLGlobal( @@ -215,121 +327,35 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository $qb->leftJoin('t.person', 'person') ->leftJoin('t.course', 'course') ->leftJoin('course.participations', 'participation') - ->leftJoin('participation.person', 'person_p') - ; + ->leftJoin('participation.person', 'person_p'); $qb->distinct(true); $k = 0; $orX = $qb->expr()->orX(); + foreach ($allowedCenters as $center) { - $allowedScopes = $this->authorizationHelper->getReachableScopes($this->security->getUser(), - TaskVoter::SHOW, $center); + $allowedScopes = $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + TaskVoter::SHOW, + $center + ); $and = $qb->expr()->andX( $qb->expr()->orX( - $qb->expr()->eq('person.center', ':center_'.$k), - $qb->expr()->eq('person_p.center', ':center_'.$k) + $qb->expr()->eq('person.center', ':center_' . $k), + $qb->expr()->eq('person_p.center', ':center_' . $k) ), - $qb->expr()->in('t.circle', ':scopes_'.$k) + $qb->expr()->in('t.circle', ':scopes_' . $k) ); $qb - ->setParameter('center_'.$k, $center) - ->setParameter('scopes_'.$k, $allowedScopes); + ->setParameter('center_' . $k, $center) + ->setParameter('scopes_' . $k, $allowedScopes); $orX->add($and); - $k++; + ++$k; } $qb->andWhere($orX); return $qb; } - - public function buildBaseQuery ( - ?string $pattern = null, - ?array $flags = [] - ): QueryBuilder { - $qb = $this->em->createQueryBuilder(); - $qb - ->from(SingleTask::class, 't') - ; - - if (!empty($pattern)) { - $qb->andWhere($qb->expr()->like('LOWER(UNACCENT(t.title))', 'LOWER(UNACCENT(:pattern))')) - ->setParameter('pattern', '%'.$pattern.'%') - ; - } - - if (count($flags) > 0) { - $orXDate = $qb->expr()->orX(); - $orXState = $qb->expr()->orX(); - $now = new \DateTime(); - - foreach ($flags as $key => $flag) { - switch ($flag) { - case 'no-alert': - $orXDate - ->add( - $qb->expr()->orX( - $qb->expr()->isNull('t.endDate'), - $qb->expr()->gte('t.endDate - COALESCE(t.warningInterval, :intervalBlank)', ':now') - ) - ); - $qb - ->setParameter('intervalBlank', new \DateInterval('P0D')) - ->setParameter('now', $now); - break; - case 'warning': - $orXDate - ->add( - $qb->expr()->andX( - $qb->expr()->not($qb->expr()->isNull('t.endDate')), - $qb->expr()->not($qb->expr()->isNull('t.warningInterval')), - $qb->expr()->lte('t.endDate - t.warningInterval', ':now'), - $qb->expr()->gt('t.endDate', ':now') - ) - ); - $qb - ->setParameter('now', $now); - break; - case 'alert': - $orXDate - ->add( - $qb->expr()->andX( - $qb->expr()->not($qb->expr()->isNull('t.endDate')), - $qb->expr()->lte('t.endDate', ':now') - ) - ); - $qb - ->setParameter('now', $now); - break; - case 'state_new': - $orXState - ->add( - "JSONB_ARRAY_LENGTH(t.currentStates) = 0" - ); - break; - case \substr($flag, 0, 6) === 'state_': - $state = \substr($flag, 6); - $orXState - ->add( - "JSONB_EXISTS_IN_ARRAY(t.currentStates, :state_$key) = 'TRUE'" - ); - $qb->setParameter("state_$key", $state); - break; - default: - throw new \LogicException("this flag is not supported: $flag"); - } - } - - if ($orXDate->count() > 0) { - $qb->andWhere($orXDate); - } - if ($orXState->count() > 0) { - $qb->andWhere($orXState); - } - } - - return $qb; - } - } diff --git a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php index 58532daa0..fc9480a91 100644 --- a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php +++ b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php @@ -1,5 +1,12 @@ 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 +68,7 @@ class SingleTaskRepository extends EntityRepository return (int) $qb ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); } /** @@ -80,9 +86,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 +97,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 +116,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 +132,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'), Types::DATE_MUTABLE); + $qb->setParameter('now', new DateTime('today'), Types::DATE_MUTABLE); $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 a3f1fff92..c1df4e743 100644 --- a/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php +++ b/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php @@ -1,38 +1,39 @@ build(); } + public function getRoles(): array + { + return self::ROLES; + } + + public function getRolesWithHierarchy(): array + { + return [ + 'Task' => self::ROLES, + ]; + } + + public function getRolesWithoutScope(): array + { + return []; + } + public function supports($attribute, $subject) { return $this->voter->supports($attribute, $subject); @@ -76,7 +98,7 @@ final class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchy 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; @@ -87,10 +109,10 @@ final class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchy $this->eventDispatcher->dispatch(AuthorizationEvent::VOTE, $event); if ($event->hasVote()) { - $this->logger->debug("The TaskVoter is overriding by " - .AuthorizationEvent::VOTE, [ + $this->logger->debug('The TaskVoter is overriding by ' + . AuthorizationEvent::VOTE, [ 'vote' => $event->getVote(), - 'task_id' => $subject->getId() + 'task_id' => $subject->getId(), ]); return $event->getVote(); @@ -104,35 +126,26 @@ final class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchy return true; } - if (NULL !== $person = $subject->getPerson()) { + if (null !== $person = $subject->getPerson()) { if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { return false; } - } elseif (NULL !== $period = $subject->getCourse()) { + } elseif (null !== $period = $subject->getCourse()) { if (!$this->accessDecisionManager->decide($token, [AccompanyingPeriodVoter::SEE], $period)) { return false; } } } + if ($subject instanceof AccompanyingPeriod) { + if (AccompanyingPeriod::STEP_CLOSED === $subject->getStep()) { + if (in_array($attribute, [self::UPDATE, self::CREATE_COURSE, self::DELETE], true)) { + return false; + } + } + } + // do regular check. return $this->voter->voteOnAttribute($attribute, $subject, $token); } - - public function getRoles() - { - return self::ROLES; - } - - public function getRolesWithHierarchy(): array - { - return [ - 'Task' => self::ROLES - ]; - } - - public function getRolesWithoutScope() - { - return []; - } } 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..b45c013f0 100644 --- a/src/Bundle/ChillTaskBundle/Templating/UI/CountNotificationTask.php +++ b/src/Bundle/ChillTaskBundle/Templating/UI/CountNotificationTask.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 . - */ -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,65 +38,38 @@ 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()) { + + if (null !== $task->getAssignee()) { foreach ([ SingleTaskRepository::DATE_STATUS_ENDED, - SingleTaskRepository::DATE_STATUS_WARNING + SingleTaskRepository::DATE_STATUS_WARNING, ] as $status) { $key = $this->getCacheKey($task->getAssignee(), $status); $sumCache = $this->cachePool->getItem($key); @@ -121,9 +80,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 Chill\MainBundle\Timeline\TimelineSingleQuery; -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; +use function array_combine; +use function array_map; /** - * Provide timeline elements related to tasks, in tasks context - * + * Provide timeline elements related to tasks, in tasks context. */ 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 +45,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,33 +59,33 @@ 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() - ), + ), 'parameters' => [], ]); - } 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) @@ -102,21 +94,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) @@ -127,9 +123,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 20e6a5480..8dc8debe9 100644 --- a/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php +++ b/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php @@ -1,53 +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\TaskBundle\Timeline; +use Chill\ActivityBundle\Security\Authorization\ActivityVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManagerInterface; -use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; -use Chill\TaskBundle\Entity\SingleTask; +use Chill\MainBundle\Timeline\TimelineSingleQuery; use Chill\PersonBundle\Entity\Person; +use Chill\TaskBundle\Entity\SingleTask; +use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Security; 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; -use Chill\MainBundle\Timeline\TimelineSingleQuery; +use UnexpectedValueException; +use function array_combine; +use function array_fill; +use function array_map; +use function implode; +use function in_array; +use function strtr; /** - * Provide element for timeline for 'person' and 'center' context - * + * Provide element for timeline for 'person' and 'center' context. */ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface { + public const TYPE = 'chill_task.transition'; + + protected AuthorizationHelper $authorizationHelper; + protected EntityManagerInterface $em; protected Registry $registry; - protected AuthorizationHelper $authorizationHelper; - protected Security $security; - - const TYPE = 'chill_task.transition'; - public function __construct( EntityManagerInterface $em, Registry $registry, @@ -68,12 +64,16 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface switch ($context) { case 'person': [ $where, $parameters ] = $this->getWhereClauseForPerson($args['person']); + break; + case 'center': [ $where, $parameters ] = $this->getWhereClauseForCenter($args['centers']); + break; + default: - throw new \UnexpectedValueException("context {$context} is not supported"); + throw new UnexpectedValueException("context {$context} is not supported"); } return TimelineSingleQuery::fromArray([ @@ -82,160 +82,26 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface 'date' => $metadata->getColumnName('datetime'), 'FROM' => $this->getFromClause($context), 'WHERE' => $where, - 'parameters' => $parameters + 'parameters' => $parameters, ]); } - private function getWhereClauseForCenter(array $centers): array - { - $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); - $singleTask = $this->em->getClassMetadata(SingleTask::class); - $person = $this->em->getClassMetadata(Person::class); - $personFkCenter = $person->getAssociationMapping('center')['joinColumns'][0]['name']; - $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name']; - - // the parameters - $parameters = []; - - // the clause that we will repeat for each center, joined by 'OR' - $clause = "{person}.{center_id} = ? AND {task}.{circle} IN ({circle_ids})"; - - // array to gather clauses - $clauses = []; - - // loop over centers - foreach ($this->authorizationHelper->getReachableCenters( - $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS)) as $center) { - - if (FALSE === \in_array($center, $centers)) { - continue; - } - - // fill center parameter - $parameters[] = $center->getId(); - - // we loop over circles - $circles = $this->authorizationHelper->getReachableCircles( - $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS), $center); - $circleIds = []; - - foreach ($circles as $circle) { - $parameters[] = $circleIds[] = $circle->getId(); - } - - $clauses[] = \strtr( - $clause, - [ - '{person}' => $person->getTableName(), - '{center_id}' => $personFkCenter, - '{task}' => $singleTask->getSchemaName().".".$singleTask->getTableName(), - '{circle}' => $taskFkCircle, - '{circle_ids}' => \implode(', ', \array_fill(0, count($circleIds), '?')) - ] - ); - } - - if (0 === \count($clauses)) { - return [ 'FALSE = TRUE' , [] ]; - } - - return [ - \implode(' OR ', $clauses), - $parameters - ]; - } - - private function getWhereClauseForPerson(Person $personArg): array - { - $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); - $singleTask = $this->em->getClassMetadata(SingleTask::class); - $person = $this->em->getClassMetadata(Person::class); - $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name']; - $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name']; - $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; - $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name']; - - - // the parameters - $parameters = $circleIds = []; - - // the clause that we will fill - $clause = "{person}.{person_id} = ? AND {task}.{circle} IN ({circle_ids})"; - - // person is the first parameter - $parameters[] = $personArg->getId(); - - // we loop over circles - $circles = $this->authorizationHelper->getReachableCircles( - $this->security->getUser(), new Role(ActivityVoter::SEE_DETAILS), $personArg->getCenter()); - - if (0 === count($circles)) { - // go fast to block access to every tasks - return [ "FALSE = TRUE", [] ]; - } - - foreach ($circles as $circle) { - $parameters[] = $circleIds[] = $circle->getId(); - } - - return [ - \strtr( - $clause, - [ - '{person}' => $person->getTableName(), - '{person_id}' => $person->getColumnName('id'), - '{task}' => $singleTask->getSchemaName().".".$singleTask->getTableName(), - '{circle}' => $taskFkCircle, - '{circle_ids}' => \implode(', ', \array_fill(0, count($circleIds), '?')) - ] - ), - $parameters - ]; - } - - private function getFromClause(string $context) - { - $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); - $singleTask = $this->em->getClassMetadata(SingleTask::class); - $person = $this->em->getClassMetadata(Person::class); - $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name']; - $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name']; - $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; - - $from = "{single_task_event} ". - "JOIN {single_task} ON {single_task}.{task_pk} = {single_task_event}.{event_fk_task} ". - "JOIN {person} ON {single_task}.{task_person_fk} = {person}.{person_pk}"; - - return \strtr( - $from, - [ - '{single_task}' => sprintf('%s.%s', $singleTask->getSchemaName(), $singleTask->getTableName()), - '{single_task_event}' => sprintf('%s.%s', $taskEvent->getSchemaName(), $taskEvent->getTableName()), - '{task_pk}' => $singleTask->getColumnName('id'), - '{event_fk_task}' => $eventFkTask, - '{person}' => $person->getTableName(), - '{task_person_fk}' => $taskFkPerson, - '{person_pk}' => $personPk - ] - ); - } - 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) { - $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: @@ -251,15 +117,19 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface 'context' => $context, 'event' => $entity, 'task' => $entity->getTask(), - '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) @@ -271,8 +141,143 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface } } - public function supportsType($type): bool + private function getFromClause(string $context) { - return $type === self::TYPE; + $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); + $singleTask = $this->em->getClassMetadata(SingleTask::class); + $person = $this->em->getClassMetadata(Person::class); + $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name']; + $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name']; + $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; + + $from = '{single_task_event} ' . + 'JOIN {single_task} ON {single_task}.{task_pk} = {single_task_event}.{event_fk_task} ' . + 'JOIN {person} ON {single_task}.{task_person_fk} = {person}.{person_pk}'; + + return strtr( + $from, + [ + '{single_task}' => sprintf('%s.%s', $singleTask->getSchemaName(), $singleTask->getTableName()), + '{single_task_event}' => sprintf('%s.%s', $taskEvent->getSchemaName(), $taskEvent->getTableName()), + '{task_pk}' => $singleTask->getColumnName('id'), + '{event_fk_task}' => $eventFkTask, + '{person}' => $person->getTableName(), + '{task_person_fk}' => $taskFkPerson, + '{person_pk}' => $personPk, + ] + ); + } + + private function getWhereClauseForCenter(array $centers): array + { + $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); + $singleTask = $this->em->getClassMetadata(SingleTask::class); + $person = $this->em->getClassMetadata(Person::class); + $personFkCenter = $person->getAssociationMapping('center')['joinColumns'][0]['name']; + $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name']; + + // the parameters + $parameters = []; + + // the clause that we will repeat for each center, joined by 'OR' + $clause = '{person}.{center_id} = ? AND {task}.{circle} IN ({circle_ids})'; + + // array to gather clauses + $clauses = []; + + // loop over centers + foreach ($this->authorizationHelper->getReachableCenters( + $this->security->getUser(), + new Role(ActivityVoter::SEE_DETAILS) + ) as $center) { + if (false === in_array($center, $centers)) { + continue; + } + + // fill center parameter + $parameters[] = $center->getId(); + + // we loop over circles + $circles = $this->authorizationHelper->getReachableCircles( + $this->security->getUser(), + new Role(ActivityVoter::SEE_DETAILS), + $center + ); + $circleIds = []; + + foreach ($circles as $circle) { + $parameters[] = $circleIds[] = $circle->getId(); + } + + $clauses[] = strtr( + $clause, + [ + '{person}' => $person->getTableName(), + '{center_id}' => $personFkCenter, + '{task}' => $singleTask->getSchemaName() . '.' . $singleTask->getTableName(), + '{circle}' => $taskFkCircle, + '{circle_ids}' => implode(', ', array_fill(0, count($circleIds), '?')), + ] + ); + } + + if (0 === \count($clauses)) { + return ['FALSE = TRUE', []]; + } + + return [ + implode(' OR ', $clauses), + $parameters, + ]; + } + + private function getWhereClauseForPerson(Person $personArg): array + { + $taskEvent = $this->em->getClassMetadata(SingleTaskPlaceEvent::class); + $singleTask = $this->em->getClassMetadata(SingleTask::class); + $person = $this->em->getClassMetadata(Person::class); + $eventFkTask = $taskEvent->getAssociationMapping('task')['joinColumns'][0]['name']; + $taskFkPerson = $singleTask->getAssociationMapping('person')['joinColumns'][0]['name']; + $personPk = $singleTask->getAssociationMapping('person')['joinColumns'][0]['referencedColumnName']; + $taskFkCircle = $singleTask->getAssociationMapping('circle')['joinColumns'][0]['name']; + + // the parameters + $parameters = $circleIds = []; + + // the clause that we will fill + $clause = '{person}.{person_id} = ? AND {task}.{circle} IN ({circle_ids})'; + + // person is the first parameter + $parameters[] = $personArg->getId(); + + // we loop over circles + $circles = $this->authorizationHelper->getReachableCircles( + $this->security->getUser(), + new Role(ActivityVoter::SEE_DETAILS), + $personArg->getCenter() + ); + + if (0 === count($circles)) { + // go fast to block access to every tasks + return ['FALSE = TRUE', []]; + } + + foreach ($circles as $circle) { + $parameters[] = $circleIds[] = $circle->getId(); + } + + return [ + strtr( + $clause, + [ + '{person}' => $person->getTableName(), + '{person_id}' => $person->getColumnName('id'), + '{task}' => $singleTask->getSchemaName() . '.' . $singleTask->getTableName(), + '{circle}' => $taskFkCircle, + '{circle_ids}' => implode(', ', array_fill(0, count($circleIds), '?')), + ] + ), + $parameters, + ]; } } diff --git a/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php b/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php index 64f5c7acc..71331d860 100644 --- a/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php +++ b/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php @@ -1,67 +1,52 @@ + +/** + * 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; +use function array_key_exists; +use function array_slice; +use function explode; +use function implode; -/** - * - * - * @author Julien Fastré - */ 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' => 'btn btn-task-label btn-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' => 'btn btn-task-label btn-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' => 'btn btn-task-label btn-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 +58,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..92699ff46 100644 --- a/src/Bundle/ChillTaskBundle/Workflow/Event/DefaultTaskGuardEvent.php +++ b/src/Bundle/ChillTaskBundle/Workflow/Event/DefaultTaskGuardEvent.php @@ -1,59 +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 . - */ -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..f69e3d0b0 100644 --- a/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowManager.php +++ b/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowManager.php @@ -1,93 +1,84 @@ + +/** + * 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; +use function sprintf; -/** - * - * - * @author Julien Fastré - */ 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/ChillTaskBundle/migrations/Version20210909153533.php b/src/Bundle/ChillTaskBundle/migrations/Version20210909153533.php index 8a81b4ab9..edffd12f9 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20210909153533.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20210909153533.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_task.recurring_task ADD course_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_task.recurring_task ADD CONSTRAINT FK_9F663B90591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE INDEX IDX_9F663B90591CC992 ON chill_task.recurring_task (course_id)'); - $this->addSql('ALTER TABLE chill_task.single_task ADD course_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_task.single_task ADD CONSTRAINT FK_194CB3D8591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE INDEX IDX_194CB3D8591CC992 ON chill_task.single_task (course_id)'); - } - public function down(Schema $schema): void { $this->addSql('ALTER TABLE chill_task.recurring_task DROP CONSTRAINT FK_9F663B90591CC992'); @@ -35,4 +26,19 @@ final class Version20210909153533 extends AbstractMigration $this->addSql('ALTER TABLE chill_task.single_task DROP CONSTRAINT FK_194CB3D8591CC992'); $this->addSql('ALTER TABLE chill_task.single_task DROP course_id'); } + + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_task.recurring_task ADD course_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_task.recurring_task ADD CONSTRAINT FK_9F663B90591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_9F663B90591CC992 ON chill_task.recurring_task (course_id)'); + $this->addSql('ALTER TABLE chill_task.single_task ADD course_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_task.single_task ADD CONSTRAINT FK_194CB3D8591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_194CB3D8591CC992 ON chill_task.single_task (course_id)'); + } } diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20211029213909.php b/src/Bundle/ChillTaskBundle/migrations/Version20211029213909.php index 1ccf52bcb..93ec4207d 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20211029213909.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20211029213909.php @@ -1,5 +1,12 @@ addSql('DROP INDEX chill_task.by_end_date'); + } + public function getDescription(): string { return 'Add index for task state and end date'; @@ -18,9 +30,4 @@ final class Version20211029213909 extends AbstractMigration { $this->addSql('CREATE INDEX by_end_date ON chill_task.single_task (end_date DESC NULLS FIRST)'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP INDEX chill_task.by_end_date'); - } } diff --git a/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php b/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php index 6c6ff08c9..690660656 100644 --- a/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php +++ b/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php @@ -1,10 +1,17 @@ addTag('chill_3party.provider'); $container->addCompilerPass(new ThirdPartyTypeCompilerPass()); } - } diff --git a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php index f7d47a32d..f05d6a0a8 100644 --- a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php +++ b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php @@ -1,55 +1,51 @@ thirdPartyACLAwareRepository = $thirdPartyACLAwareRepository; } + protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper + { + return $this->getFilterOrderHelperFactory() + ->create(self::class) + ->addSearchBox(['name', 'company_name', 'acronym']) + //->addToggle('only-active', []) + // ->addOrderBy() + ->build(); + } + protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int { - if (NULL === $filterOrder){ - throw new \LogicException('filterOrder should not be null'); + if (null === $filterOrder) { + throw new LogicException('filterOrder should not be null'); } - return $this->thirdPartyACLAwareRepository->countThirdParties(ThirdPartyVoter::SHOW, - $filterOrder->getQueryString()); + return $this->thirdPartyACLAwareRepository->countThirdParties( + ThirdPartyVoter::SHOW, + $filterOrder->getQueryString() + ); + } + + protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface + { + if ('new' === $action) { + return parent::createFormFor($action, $entity, $formClass, array_merge( + $formOptions, + ['kind' => $this->requestStack->getCurrentRequest()->query->getAlpha('kind')] + )); + } + + if ('edit' === $action) { + return parent::createFormFor($action, $entity, $formClass, array_merge( + $formOptions, + ['kind' => $entity->getKind()] + )); + } + + return parent::createFormFor($action, $entity, $formClass, $formOptions); } protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, ?FilterOrderHelper $filterOrder = null) { return $this->thirdPartyACLAwareRepository - ->listThirdParties(ThirdPartyVoter::SHOW, $filterOrder->getQueryString(), ['name' => 'ASC'], $paginator->getItemsPerPage(), - $paginator->getCurrentPageFirstItemNumber()); + ->listThirdParties( + ThirdPartyVoter::SHOW, + $filterOrder->getQueryString(), + ['name' => 'ASC'], + $paginator->getItemsPerPage(), + $paginator->getCurrentPageFirstItemNumber() + ); } protected function onPostCheckACL($action, Request $request, $entity): ?Response @@ -93,42 +125,16 @@ final class ThirdPartyController extends CRUDController if ('new' === $action) { if (!$request->query->has('kind')) { return $this->render('@ChillThirdParty/ThirdParty/new_pick_kind.html.twig'); - } else { - $kind = $request->query->getAlpha('kind', ''); - - if (!(ThirdParty::KIND_COMPANY === $kind || ThirdParty::KIND_CONTACT === $kind)) { - throw new BadRequestHttpException('This kind is not supported: '.$kind); - } - - $entity->setKind($kind); } + $kind = $request->query->getAlpha('kind', ''); + + if (!(ThirdParty::KIND_COMPANY === $kind || ThirdParty::KIND_CONTACT === $kind)) { + throw new BadRequestHttpException('This kind is not supported: ' . $kind); + } + + $entity->setKind($kind); } return null; } - - protected function createFormFor(string $action, $entity, string $formClass = null, array $formOptions = []): FormInterface - { - if ('new' === $action) { - return parent::createFormFor($action, $entity, $formClass, \array_merge( - $formOptions, [ 'kind' => $this->requestStack->getCurrentRequest()->query->getAlpha('kind')] - )); - } elseif ('edit' === $action) { - return parent::createFormFor($action, $entity, $formClass, \array_merge( - $formOptions, [ 'kind' => $entity->getKind()] - )); - } - - return parent::createFormFor($action, $entity, $formClass, $formOptions); - } - - protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper - { - return $this->getFilterOrderHelperFactory() - ->create(self::class) - ->addSearchBox(['name', 'company_name', 'acronym']) - //->addToggle('only-active', []) - // ->addOrderBy() - ->build(); - } } diff --git a/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdParty.php b/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdParty.php index 1d343f1fd..baa8b5349 100644 --- a/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdParty.php +++ b/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdParty.php @@ -1,21 +1,38 @@ getThirdParties()->getObjects(); @@ -25,10 +42,10 @@ class LoadThirdParty extends Fixture Implements DependentFixtureInterface // this is an address continue; } - $thirdParty->setCreatedAt(new \DateTimeImmutable('today')); + $thirdParty->setCreatedAt(new DateTimeImmutable('today')); foreach ($this->getCenters() as $center) { - $thirdParty->addCenter($center); + $thirdParty->addCenter($center); } $manager->persist($thirdParty); @@ -37,13 +54,31 @@ class LoadThirdParty extends Fixture Implements DependentFixtureInterface $manager->flush(); } - private function getCenters(): \Iterator + private function createAddress(): ObjectSet { - $references = \array_map(function($a) { return $a['ref']; }, - LoadCenters::$centers); + $loader = new NativeLoader(); + + return $loader->loadData([ + Address::class => [ + 'address1' => [ + 'name' => '', + 'telephone' => '', + 'email' => '', + 'comment' => '', + ], + ], + ]); + } + + private function getCenters(): Iterator + { + $references = array_map( + function ($a) { return $a['ref']; }, + LoadCenters::$centers + ); $number = random_int(1, count($references)); - if ($number === 1) { + if (1 === $number) { yield $this->getReference($references[\array_rand($references)]); } else { foreach (array_rand($references, $number) as $index) { @@ -52,40 +87,6 @@ class LoadThirdParty extends Fixture Implements DependentFixtureInterface } } - public function getDependencies() - { - return [ - LoadCenters::class, - LoadPostalCodes::class - ]; - } - - private function getThirdParties(): ObjectSet - { - $loader = new NativeLoader(); - $objectSet = $loader->loadData([ - Address::class => [ - 'address{1..75}' => [ - 'street' => '', - 'streetNumber' => '', - 'validFrom' => '', - 'postCode' => $this->getPostalCode() - ], - ], - ThirdParty::class => [ - 'thirdparty{1..75}' => [ - 'name' => '', - 'telephone' => '', - 'email' => '', - 'comment' => '', - 'address' => '@address' - ] - ] - ]); - - return $objectSet; - } - private function getPostalCode(): PostalCode { $ref = LoadPostalCodes::$refs[\array_rand(LoadPostalCodes::$refs)]; @@ -93,22 +94,28 @@ class LoadThirdParty extends Fixture Implements DependentFixtureInterface return $this->getReference($ref); } - private function createAddress(): ObjectSet + private function getThirdParties(): ObjectSet { $loader = new NativeLoader(); - $objectSet = $loader->loadData([ + + return $loader->loadData([ Address::class => [ - 'address1' => [ + 'address{1..75}' => [ + 'street' => '', + 'streetNumber' => '', + 'validFrom' => '', + 'postCode' => $this->getPostalCode(), + ], + ], + ThirdParty::class => [ + 'thirdparty{1..75}' => [ 'name' => '', 'telephone' => '', 'email' => '', - 'comment' => '' - ] - ] + 'comment' => '', + 'address' => '@address', + ], + ], ]); - - return $objectSet; - } - } diff --git a/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyCategory.php b/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyCategory.php index bb86e20f1..f218f7783 100644 --- a/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyCategory.php +++ b/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyCategory.php @@ -1,5 +1,12 @@ ['fr' => "maison médicale" ]], - ['name' => ['fr' => "hôpital" ]], - ['name' => ['fr' => "médecin généraliste" ]], - ['name' => ['fr' => "pharmacien" ]], - ['name' => ['fr' => "assistance aux personnes âgées" ]], - ['name' => ['fr' => "assistante maternelle" ]], - ['name' => ['fr' => "assistant social" ]], - ['name' => ['fr' => "éducateur spécialisé" ]], - ['name' => ['fr' => "infirmier.ère" ]], + ['name' => ['fr' => 'maison médicale']], + ['name' => ['fr' => 'hôpital']], + ['name' => ['fr' => 'médecin généraliste']], + ['name' => ['fr' => 'pharmacien']], + ['name' => ['fr' => 'assistance aux personnes âgées']], + ['name' => ['fr' => 'assistante maternelle']], + ['name' => ['fr' => 'assistant social']], + ['name' => ['fr' => 'éducateur spécialisé']], + ['name' => ['fr' => 'infirmier.ère']], ]; - foreach ( $categories as $val) { - print "Creating thirdparty category : " . $val['name']['fr'] . "\n"; + foreach ($categories as $val) { + echo 'Creating thirdparty category : ' . $val['name']['fr'] . "\n"; $category = (new ThirdPartyCategory()) ->setName($val['name']) ->setActive(true); diff --git a/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyProfession.php b/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyProfession.php index ff38bd9ac..6eef003a1 100644 --- a/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyProfession.php +++ b/src/Bundle/ChillThirdPartyBundle/DataFixtures/ORM/LoadThirdPartyProfession.php @@ -1,5 +1,12 @@ ['fr' => "Directeur" ]], - ['name' => ['fr' => "Docteur" ]], - ['name' => ['fr' => "Médecin" ]], - ['name' => ['fr' => "Opérateur" ]], - ['name' => ['fr' => "Personnel administratif" ]], - ['name' => ['fr' => "Président" ]], - ['name' => ['fr' => "Responsable infirmier.ère" ]], + ['name' => ['fr' => 'Directeur']], + ['name' => ['fr' => 'Docteur']], + ['name' => ['fr' => 'Médecin']], + ['name' => ['fr' => 'Opérateur']], + ['name' => ['fr' => 'Personnel administratif']], + ['name' => ['fr' => 'Président']], + ['name' => ['fr' => 'Responsable infirmier.ère']], ]; - foreach ( $professions as $val) { - print "Creating thirdparty professions : " . $val['name']['fr'] . "\n"; + foreach ($professions as $val) { + echo 'Creating thirdparty professions : ' . $val['name']['fr'] . "\n"; $profession = (new ThirdPartyProfession()) ->setName($val['name']) ->setActive(true); diff --git a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php index bdf21c05a..2314f19ef 100644 --- a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php +++ b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php @@ -1,35 +1,38 @@ 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'); @@ -49,15 +52,25 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte $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' => [ - 'resources' => array( - '@ChillThirdPartyBundle/config/routes.yaml' - ) - ], + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillThirdPartyBundle/config/routes.yaml', + ], + ], 'cruds' => [ [ 'class' => ThirdParty::class, @@ -81,10 +94,9 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte 'view' => [ 'template' => '@ChillThirdParty/ThirdParty/view.html.twig', 'role' => ThirdPartyVoter::SHOW, - ] - ] - - ] + ], + ], + ], ], 'apis' => [ [ @@ -100,29 +112,19 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte Request::METHOD_HEAD => true, Request::METHOD_POST => true, Request::METHOD_PUT => true, - Request::METHOD_PATCH => true + Request::METHOD_PATCH => true, ], 'roles' => [ Request::METHOD_GET => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::SHOW, Request::METHOD_HEAD => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::SHOW, Request::METHOD_POST => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::CREATE, Request::METHOD_PUT => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::CREATE, - Request::METHOD_PATCH => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::CREATE + Request::METHOD_PATCH => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::CREATE, ], - ] - ] - ] + ], + ], + ], ], - )); - } - - protected function prependRoleHierarchy(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - ThirdPartyVoter::CREATE => [ThirdPartyVoter::SHOW], - ThirdPartyVoter::UPDATE => [ThirdPartyVoter::SHOW], - ) - )); + ]); } } diff --git a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php index e15510a5b..3842595aa 100644 --- a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php +++ b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php @@ -1,38 +1,48 @@ 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 Chill\MainBundle\Doctrine\Model\TrackCreationInterface; use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; +use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Civility; use Chill\MainBundle\Entity\User; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; +use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint; +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; use Doctrine\Common\Collections\ArrayCollection; -use Chill\MainBundle\Entity\Center; -use Symfony\Component\Validator\Constraints as Assert; -use Chill\MainBundle\Entity\Address; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use Symfony\Component\Serializer\Annotation\Groups; -use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint; +use Symfony\Component\Validator\Constraints as Assert; +use UnexpectedValueException; +use function array_filter; +use function array_map; +use function array_merge; +use function array_values; +use function in_array; +use function spl_object_hash; /** * ThirdParty is a party recorded in the database. @@ -46,96 +43,77 @@ use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint; * @ORM\Entity * @ORM\Table(name="chill_3party.third_party") * @DiscriminatorMap(typeProperty="type", mapping={ - * "thirdparty"=ThirdParty::class + * "thirdparty": ThirdParty::class * }) */ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface { - /** - * @var int - * @ORM\Column(name="id", type="integer") - * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") - */ - private ?int $id = null; + public const KIND_CHILD = 'child'; - const KIND_CONTACT = 'contact'; - const KIND_COMPANY = 'company'; - const KIND_CHILD = 'child'; - - /** - * @ORM\Column(name="kind", type="string", length="20", options={"default":""}) - * @Groups({"write"}) - */ - private ?string $kind = ""; + public const KIND_COMPANY = 'company'; + + public const KIND_CONTACT = 'contact'; /** + * [fr] Sigle. + * * @var string - * @ORM\Column(name="name", type="string", length=255) + * @ORM\Column(name="acronym", type="string", length=64, nullable=true) * @Assert\Length(min="2") * @Groups({"read", "write"}) */ - private ?string $name = ""; + private ?string $acronym = ''; /** - * [fr] Raison sociale - * @var string - * @ORM\Column(name="name_company", type="string", length=255, nullable=true) - * @Assert\Length(min="3") + * Soft-delete flag. + * + * @ORM\Column(name="active", type="boolean", options={"defaut": true}) + */ + private bool $active = true; + + /** + * @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address", + * cascade={"persist", "remove"}) + * @ORM\JoinColumn(nullable=true, onDelete="SET NULL") * @Groups({"read", "write"}) - */ - private ?string $nameCompany = ""; + */ + private ?Address $address = null; /** * Canonicalized form composed of name, company name and acronym. * * This field is read-only, and is generated on database side. * - * @ORM\Column(name="canonicalized", type="text", options={"default":""}) + * @ORM\Column(name="canonicalized", type="text", options={"default": ""}) */ - private ?string $canonicalized = ""; - - /** - * [fr] Sigle - * @var string - * @ORM\Column(name="acronym", type="string", length=64, nullable=true) - * @Assert\Length(min="2") - * @Groups({"read", "write"}) - */ - private ?string $acronym = ""; + private ?string $canonicalized = ''; /** * @var ThirdPartyCategory * @ORM\ManyToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdPartyCategory") * @ORM\JoinTable(name="chill_3party.thirdparty_category", * joinColumns={@ORM\JoinColumn(name="thirdparty_id", referencedColumnName="id")}, - * inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")}) - */ + * inverseJoinColumns={@ORM\JoinColumn(name="category_id", referencedColumnName="id")}) + */ private Collection $categories; /** - * @var array|null - * @ORM\Column(name="types", type="json", nullable=true) + * @ORM\ManyToMany(targetEntity="\Chill\MainBundle\Entity\Center") + * @ORM\JoinTable(name="chill_3party.party_center") */ - private $types; + private Collection $centers; /** - * Contact Persons: One Institutional ThirdParty has Many Contact Persons + * Contact Persons: One Institutional ThirdParty has Many Contact Persons. + * * @ORM\OneToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty", mappedBy="parent", - * cascade={"persist"}, orphanRemoval=true) - * @var ThirdParty[]|Collection + * cascade={"persist"}, orphanRemoval=true) + * + * @var Collection|ThirdParty[] * @Assert\Valid(traverse=true) */ private Collection $children; - /** - * Institutional ThirdParty: Many Contact Persons have One Institutional ThirdParty - * @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty", inversedBy="children") - * @ORM\JoinColumn(name="parent_id", referencedColumnName="id") - * @Groups({"read"}) - */ - private ?ThirdParty $parent = null; - /** * @var Civility * @ORM\ManyToOne(targetEntity=Civility::class) @@ -143,81 +121,21 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface */ private ?Civility $civility = null; - /** - * [fr] Qualité - * @var ThirdPartyProfession - * @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdPartyProfession") - * ORM\JoinColumn(name="profession", referencedColumnName="id", nullable=true) - */ - private ?ThirdPartyProfession $profession = null; - - /** - * @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" - * ) - * @PhonenumberConstraint(type="any") - * @Groups({"read", "write"}) - */ - private ?string $telephone = null; - - /** - * @var string|null - * @ORM\Column(name="email", type="string", length=255, nullable=true) - * @Assert\Email(checkMX=false) - * @Groups({"read", "write"}) - */ - private ?string $email = null; - - /** - * @var bool - * @ORM\Column(name="contact_data_anonymous", type="boolean", options={"default":false}) - * @Groups({"read"}) - */ - private bool $contactDataAnonymous = false; - - /** - * @var Address|null - * @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address", - * cascade={"persist", "remove"}) - * @ORM\JoinColumn(nullable=true, onDelete="SET NULL") - * @Groups({"read", "write"}) - */ - private ?Address $address = null; - - /** - * Soft-delete flag - * @ORM\Column(name="active", type="boolean", options={"defaut": true}) - */ - private bool $active = true; - /** * @ORM\Column(name="comment", type="text", nullable=true) */ private ?string $comment = null; /** - * @ORM\ManyToMany(targetEntity="\Chill\MainBundle\Entity\Center") - * @ORM\JoinTable(name="chill_3party.party_center") + * @ORM\Column(name="contact_data_anonymous", type="boolean", options={"default": false}) + * @Groups({"read"}) */ - private Collection $centers; + private bool $contactDataAnonymous = false; /** * @ORM\Column(name="created_at", type="datetime_immutable", nullable=false) */ - private \DateTimeImmutable $createdAt; - - /** - * @ORM\Column(name="updated_at", type="datetime_immutable", nullable=true) - */ - private ?\DateTimeImmutable $updatedAt; - - /** - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") - * @ORM\JoinColumn(name="updated_by", referencedColumnName="id") - */ - private ?User $updatedBy; + private DateTimeImmutable $createdAt; /** * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") @@ -225,6 +143,89 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface */ private ?User $createdBy; + /** + * @ORM\Column(name="email", type="string", length=255, nullable=true) + * @Assert\Email(checkMX=false) + * @Groups({"read", "write"}) + */ + private ?string $email = null; + + /** + * @var int + * @ORM\Column(name="id", type="integer") + * @ORM\Id + * @ORM\GeneratedValue(strategy="AUTO") + */ + private ?int $id = null; + + /** + * @ORM\Column(name="kind", type="string", length="20", options={"default": ""}) + * @Groups({"write"}) + */ + private ?string $kind = ''; + + /** + * @var string + * @ORM\Column(name="name", type="string", length=255) + * @Assert\Length(min="2") + * @Groups({"read", "write"}) + */ + private ?string $name = ''; + + /** + * [fr] Raison sociale. + * + * @var string + * @ORM\Column(name="name_company", type="string", length=255, nullable=true) + * @Assert\Length(min="3") + * @Groups({"read", "write"}) + */ + private ?string $nameCompany = ''; + + /** + * Institutional ThirdParty: Many Contact Persons have One Institutional ThirdParty. + * + * @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty", inversedBy="children") + * @ORM\JoinColumn(name="parent_id", referencedColumnName="id") + * @Groups({"read"}) + */ + private ?ThirdParty $parent = null; + + /** + * [fr] Qualité. + * + * @var ThirdPartyProfession + * @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdPartyProfession") + * ORM\JoinColumn(name="profession", referencedColumnName="id", nullable=true) + */ + private ?ThirdPartyProfession $profession = 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" + * ) + * @PhonenumberConstraint(type="any") + * @Groups({"read", "write"}) + */ + private ?string $telephone = null; + + /** + * @var array|null + * @ORM\Column(name="types", type="json", nullable=true) + */ + private $types; + + /** + * @ORM\Column(name="updated_at", type="datetime_immutable", nullable=true) + */ + private ?DateTimeImmutable $updatedAt; + + /** + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") + * @ORM\JoinColumn(name="updated_by", referencedColumnName="id") + */ + private ?User $updatedBy; /** * ThirdParty constructor. @@ -236,6 +237,176 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface $this->children = new ArrayCollection(); } + /** + * @return string + */ + public function __toString() + { + return $this->getName(); + } + + /** + * Add a child and set the child as active. + * + * Method used in conjonction with getActiveChildren in form. + * + * @internal use the method addChild + * + * @return $this + */ + public function addActiveChild(ThirdParty $child): self + { + $child->setActive(true); + + return $this->addChild($child); + } + + /** + * @return $this + */ + public function addCategory(ThirdPartyCategory $category): self + { + if (!$this->categories->contains($category)) { + $this->categories[] = $category; + } + + foreach ($this->children as $child) { + $child->addCategory($category); + } + + return $this; + } + + public function addCenter(Center $center) + { + if (false === $this->centers->contains($center)) { + $this->centers->add($center); + } + } + + /** + * @return $this + */ + public function addChild(ThirdParty $child): self + { + $this->children[] = $child; + $child->setParent($this)->setKind(ThirdParty::KIND_CHILD); + + return $this; + } + + public function addType(?string $type): self + { + if (null === $type) { + return $this; + } + + if (!in_array($type, $this->types ?? [])) { + $this->types[] = $type; + } + + foreach ($this->children as $child) { + $child->addType($type); + } + + return $this; + } + + public function addTypesAndCategories($typeAndCategory): self + { + if ($typeAndCategory instanceof ThirdPartyCategory) { + $this->addCategory($typeAndCategory); + + return $this; + } + + if (is_string($typeAndCategory)) { + $this->addType($typeAndCategory); + + return $this; + } + + throw new UnexpectedValueException(sprintf( + 'typeAndCategory should be a string or a %s', + ThirdPartyCategory::class + )); + } + + /** + * @return string + */ + public function getAcronym(): ?string + { + return $this->acronym; + } + + public function getActive(): bool + { + return $this->active; + } + + /** + * Get the children where active = true. + */ + public function getActiveChildren(): Collection + { + return $this->children->filter(fn (ThirdParty $tp) => $tp->getActive()); + } + + public function getAddress(): ?Address + { + if ($this->isChild()) { + return $this->getParent()->getAddress(); + } + + return $this->address; + } + + public function getCategories(): Collection + { + return $this->categories; + } + + public function getCenters(): Collection + { + return $this->centers; + } + + public function getChildren(): Collection + { + return $this->children; + } + + public function getCivility(): ?Civility + { + return $this->civility; + } + + /** + * Get comment. + * + * @return string|null + */ + public function getComment() + { + return $this->comment; + } + + public function getCreatedAt(): DateTimeImmutable + { + return $this->createdAt; + } + + /** + * Get email. + * + * @return string|null + */ + public function getEmail() + { + return $this->email; + } + /** * Get id. * @@ -251,25 +422,6 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this->kind; } - public function setKind(?string $kind): ThirdParty - { - $this->kind = $kind; - return $this; - } - - /** - * Set name. - * - * @param string $name - * @return ThirdParty - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - /** * Get name. * @@ -280,17 +432,22 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this->name; } - /** - * Set telephone. - * - * @param string|null $telephone - * @return ThirdParty - */ - public function setTelephone($telephone = null) + public function getNameCompany(): ?string { - $this->telephone = $telephone; + return $this->nameCompany; + } - return $this; + public function getParent(): ?ThirdParty + { + return $this->parent; + } + + /** + * @return ThirdPartyProfession + */ + public function getProfession(): ?ThirdPartyProfession + { + return $this->profession; } /** @@ -303,81 +460,6 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this->telephone; } - /** - * Set email. - * - * @param string|null $email - * @return ThirdParty - */ - public function setEmail($email = null) - { - $this->email = $email; - - return $this; - } - - /** - * Get email. - * - * @return string|null - */ - public function getEmail() - { - return $this->email; - } - - public function isContactDataAnonymous(): bool - { - return $this->contactDataAnonymous; - } - - public function setContactDataAnonymous(bool $contactDataAnonymous): ThirdParty - { - $this->contactDataAnonymous = $contactDataAnonymous; - return $this; - } - - /** - * Set comment. - * - * @param string|null $comment - * @return ThirdParty - */ - public function setComment($comment = null) - { - $this->comment = $comment; - - return $this; - } - - /** - * Get comment. - * - * @return string|null - */ - public function getComment() - { - return $this->comment; - } - - /** - * Set type. - * - * @param array|null $type - * @return ThirdParty - */ - public function setTypes(array $type = null) - { - // remove all keys from the input data - $this->types = \array_values($type); - - foreach ($this->children as $child) { - $child->setTypes($type); - } - - return $this; - } - /** * Get type. * @@ -388,202 +470,67 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this->types; } - public function addType(?string $type): self + public function getTypesAndCategories(): array { - if (NULL === $type) { - return $this; - } - - if (!\in_array($type, $this->types ?? [])) { - $this->types[] = $type; - } - - foreach ($this->children as $child) { - $child->addType($type); - } - - return $this; - } - - public function removeType(?string $type): self - { - if (NULL === $type) { - return $this; - } - - if (\in_array($type, $this->types ?? [])) { - $this->types = \array_filter($this->types, fn($e) => !\in_array($e, $this->types)); - } - - foreach ($this->children as $child) { - $child->removeType($type); - } - - return $this; + return array_merge( + $this->getCategories()->toArray(), + $this->getTypes() ?? [] + ); } /** - * @return bool + * @return DateTime|null */ - public function getActive(): bool + public function getUpdatedAt(): ?DateTimeImmutable { - return $this->active; + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; } /** - * @return Collection + * @Groups({"read"}) */ - public function getCenters(): Collection + public function isChild(): bool { - return $this->centers; + return null !== $this->parent; + } + + public function isContactDataAnonymous(): bool + { + return $this->contactDataAnonymous; } /** - * @param bool $active + * Mechanism to differentiate children and parents. + */ + public function isLeaf(): bool + { + return $this->children->count() !== 0; + } + + public function isParent(): bool + { + return !$this->isChild(); + } + + /** + * mark the child as unactive, but keep the child existing in the + * database. To effectively remove the child, use removeChild instead. + * * @return $this */ - public function setActive(bool $active) + public function removeActiveChild(ThirdParty $child): self { - $this->active = $active; - foreach ($this->children as $child) { - $child->setActive($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); - } - } - - /** - * @param Collection $centers - * @return $this - */ - public function setCenters(Collection $centers) - { - foreach ($centers as $center) { - $this->addCenter($center); - } - - foreach ($this->centers as $center) { - if (FALSE === $centers->contains($center)) { - $this->removeCenter($center); - } - } + $child->setActive(false); return $this; } /** - * @return Address|null - */ - public function getAddress(): ?Address - { - if ($this->isChild()) { - return $this->getParent()->getAddress(); - } - - return $this->address; - } - - /** - * @param Address|null $address - * @return $this - */ - public function setAddress(?Address $address = null) - { - $this->address = $address; - - return $this; - } - - /** - * @return string - */ - public function __toString() - { - return $this->getName(); - } - - /** - * @return string|null - */ - public function getNameCompany(): ?string - { - return $this->nameCompany; - } - - /** - * @param string $nameCompany - * @return ThirdParty - */ - public function setNameCompany(?string $nameCompany): ThirdParty - { - $this->nameCompany = (string) $nameCompany; - return $this; - } - - /** - * @return string - */ - public function getAcronym(): ?string - { - return $this->acronym; - } - - /** - * @param string $acronym - * @return $this - */ - public function setAcronym(?string $acronym = null): ThirdParty - { - $this->acronym = (string) $acronym; - return $this; - } - - /** - * @return Collection - */ - public function getCategories(): Collection - { - return $this->categories; - } - - /** - * @param ThirdPartyCategory $category - * @return $this - */ - public function addCategory(ThirdPartyCategory $category): self - { - if (!$this->categories->contains($category)) { - $this->categories[] = $category; - } - - foreach ($this->children as $child) { - $child->addCategory($category); - } - - return $this; - } - - /** - * @param ThirdPartyCategory $category * @return $this */ public function removeCategory(ThirdPartyCategory $category): self @@ -597,152 +544,11 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this; } - /** - * Mechanism to differentiate children and parents - */ - public function isLeaf(): bool + public function removeCenter(Center $center) { - return $this->children->count() !== 0; - } - - /** - * @Groups({"read"}) - */ - public function isChild():bool - { - return $this->parent !== null; - } - - public function isParent():bool - { - return !$this->isChild(); - } - - /** - * @return Collection - */ - public function getChildren(): Collection - { - return $this->children; - } - - /** - * Get the children where active = true - * - * @return Collection - */ - public function getActiveChildren(): Collection - { - return $this->children->filter(fn (ThirdParty $tp) => $tp->getActive()); - } - - /** - * Add a child and set the child as active - * - * Method used in conjonction with getActiveChildren in form. - * - * @internal use the method addChild - * @param ThirdParty $child - * @return $this - */ - public function addActiveChild(ThirdParty $child): self - { - $child->setActive(true); - - return $this->addChild($child); - } - - /** - * mark the child as unactive, but keep the child existing in the - * database. To effectively remove the child, use removeChild instead. - * - * @param ThirdParty $child - * @return $this - */ - public function removeActiveChild(ThirdParty $child): self - { - $child->setActive(false); - - return $this; - } - - public function addTypesAndCategories($typeAndCategory): self - { - if ($typeAndCategory instanceof ThirdPartyCategory) { - $this->addCategory($typeAndCategory); - return $this; + if ($this->centers->contains($center)) { + $this->centers->removeElement($center); } - - if (is_string($typeAndCategory)) { - $this->addType($typeAndCategory); - return $this; - } - - throw new \UnexpectedValueException(sprintf( - "typeAndCategory should be a string or a %s", ThirdPartyCategory::class)); - } - - public function removeTypesAndCategories($typeAndCategory): self - { - if ($typeAndCategory instanceof ThirdPartyCategory) { - $this->removeCategory($typeAndCategory); - return $this; - } - - if (is_string($typeAndCategory)) { - $this->removeType($typeAndCategory); - return $this; - } - - throw new \UnexpectedValueException(sprintf( - "typeAndCategory should be a string or a %s", ThirdPartyCategory::class)); - } - - public function getTypesAndCategories(): array - { - return \array_merge( - $this->getCategories()->toArray(), - $this->getTypes() ?? [] - ); - } - - public function setTypesAndCategories(array $typesAndCategories): self - { - $types = \array_filter($typesAndCategories, fn($item) => !$item instanceof ThirdPartyCategory); - $this->setTypes($types); - - // handle categories - foreach ($typesAndCategories as $t) { - $this->addTypesAndCategories($t); - } - - $categories = \array_filter($typesAndCategories, fn($item) => $item instanceof ThirdPartyCategory); - $categoriesHashes = \array_map(fn(ThirdPartyCategory $c) => \spl_object_hash($c), $categories); - - foreach ($categories as $c) { - $this->addCategory($c); - } - - foreach ($this->getCategories() as $t) { - if (!\in_array(\spl_object_hash($t), $categoriesHashes)) { - $this->removeCategory($t); - } - } - - return $this; - } - - - /** - * @param ThirdParty $child - * @return $this - */ - public function addChild(ThirdParty $child): self - { - $this->children[] = $child; - $child->setParent($this)->setKind(ThirdParty::KIND_CHILD);; - - return $this; } /** @@ -751,7 +557,6 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface * If you want to keep the child into the database * but desactivate it, use removeActiveChildren instead. * - * @param ThirdParty $child * @return $this */ public function removeChild(ThirdParty $child): self @@ -761,111 +566,137 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this; } - /** - * @return ThirdParty|null - */ - public function getParent(): ?ThirdParty + public function removeType(?string $type): self { - return $this->parent; + if (null === $type) { + return $this; + } + + if (in_array($type, $this->types ?? [])) { + $this->types = array_filter($this->types, fn ($e) => !in_array($e, $this->types)); + } + + foreach ($this->children as $child) { + $child->removeType($type); + } + + return $this; + } + + public function removeTypesAndCategories($typeAndCategory): self + { + if ($typeAndCategory instanceof ThirdPartyCategory) { + $this->removeCategory($typeAndCategory); + + return $this; + } + + if (is_string($typeAndCategory)) { + $this->removeType($typeAndCategory); + + return $this; + } + + throw new UnexpectedValueException(sprintf( + 'typeAndCategory should be a string or a %s', + ThirdPartyCategory::class + )); } /** - * @param ThirdParty|null $parent + * @param string $acronym + * * @return $this */ - public function setParent(?ThirdParty $parent): ThirdParty + public function setAcronym(?string $acronym = null): ThirdParty { - $this->parent = $parent; + $this->acronym = (string) $acronym; + return $this; } /** - * @return Civility|null + * @return $this */ - public function getCivility(): ?Civility + public function setActive(bool $active) { - return $this->civility; + $this->active = $active; + + foreach ($this->children as $child) { + $child->setActive($active); + } + + return $this; + } + + /** + * @return $this + */ + public function setAddress(?Address $address = null) + { + $this->address = $address; + + return $this; + } + + /** + * @return $this + */ + public function setCenters(Collection $centers) + { + foreach ($centers as $center) { + $this->addCenter($center); + } + + foreach ($this->centers as $center) { + if (false === $centers->contains($center)) { + $this->removeCenter($center); + } + } + + return $this; } /** - * @param Civility $civility * @return $this */ public function setCivility(Civility $civility): ThirdParty { $this->civility = $civility; + return $this; } /** - * @return ThirdPartyProfession + * Set comment. + * + * @param string|null $comment + * + * @return ThirdParty */ - public function getProfession(): ?ThirdPartyProfession + public function setComment($comment = null) { - return $this->profession; + $this->comment = $comment; + + return $this; } - /** - * @param ThirdPartyProfession $profession - * @return $this - */ - public function setProfession(ThirdPartyProfession $profession): ThirdParty + public function setContactDataAnonymous(bool $contactDataAnonymous): ThirdParty { - $this->profession = $profession; + $this->contactDataAnonymous = $contactDataAnonymous; + return $this; } /** - * @return \DateTimeImmutable - */ - public function getCreatedAt(): \DateTimeImmutable - { - return $this->createdAt; - } - - /** - * @param \DateTimeImmutable $createdAt + * @param DateTimeImmutable $createdAt + * * @return $this */ - public function setCreatedAt(\DateTimeInterface $createdAt): ThirdParty + public function setCreatedAt(DateTimeInterface $createdAt): ThirdParty { $this->createdAt = $createdAt; - return $this; - } - /** - * @return \DateTime|null - */ - public function getUpdatedAt(): ?\DateTimeImmutable - { - return $this->updatedAt; - } - - /** - * @param \DateTimeImmutable $updatedAt - * @return $this - */ - public function setUpdatedAt(\DateTimeInterface $updatedAt): ThirdParty - { - $this->updatedAt = $updatedAt; - return $this; - } - - /** - * @return User|null - */ - public function getUpdatedBy(): ?User - { - return $this->updatedBy; - } - - /** - * @param User $updatedBy - * @return $this - */ - public function setUpdatedBy(User $updatedBy): ThirdParty - { - $this->updatedBy = $updatedBy; return $this; } @@ -876,5 +707,147 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this; } + /** + * Set email. + * + * @param string|null $email + * + * @return ThirdParty + */ + public function setEmail($email = null) + { + $this->email = $email; + return $this; + } + + public function setKind(?string $kind): ThirdParty + { + $this->kind = $kind; + + return $this; + } + + /** + * Set name. + * + * @param string $name + * + * @return ThirdParty + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * @param string $nameCompany + */ + public function setNameCompany(?string $nameCompany): ThirdParty + { + $this->nameCompany = (string) $nameCompany; + + return $this; + } + + /** + * @return $this + */ + public function setParent(?ThirdParty $parent): ThirdParty + { + $this->parent = $parent; + + return $this; + } + + /** + * @return $this + */ + public function setProfession(ThirdPartyProfession $profession): ThirdParty + { + $this->profession = $profession; + + 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 setTypes(?array $type = null) + { + // remove all keys from the input data + $this->types = array_values($type); + + foreach ($this->children as $child) { + $child->setTypes($type); + } + + return $this; + } + + public function setTypesAndCategories(array $typesAndCategories): self + { + $types = array_filter($typesAndCategories, fn ($item) => !$item instanceof ThirdPartyCategory); + $this->setTypes($types); + + // handle categories + foreach ($typesAndCategories as $t) { + $this->addTypesAndCategories($t); + } + + $categories = array_filter($typesAndCategories, fn ($item) => $item instanceof ThirdPartyCategory); + $categoriesHashes = array_map(fn (ThirdPartyCategory $c) => spl_object_hash($c), $categories); + + foreach ($categories as $c) { + $this->addCategory($c); + } + + foreach ($this->getCategories() as $t) { + if (!in_array(spl_object_hash($t), $categoriesHashes)) { + $this->removeCategory($t); + } + } + + return $this; + } + + /** + * @param DateTimeImmutable $updatedAt + * + * @return $this + */ + public function setUpdatedAt(DateTimeInterface $updatedAt): ThirdParty + { + $this->updatedAt = $updatedAt; + + return $this; + } + + /** + * @return $this + */ + public function setUpdatedBy(User $updatedBy): ThirdParty + { + $this->updatedBy = $updatedBy; + + return $this; + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyCategory.php b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyCategory.php index ee0a633e6..373f2fe6d 100644 --- a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyCategory.php +++ b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyCategory.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\ThirdPartyBundle\Entity; @@ -31,6 +18,11 @@ use Doctrine\ORM\Mapping as ORM; */ class ThirdPartyCategory { + /** + * @ORM\Column(type="boolean") + */ + private $active = true; + /** * @ORM\Id * @ORM\GeneratedValue @@ -43,10 +35,10 @@ class ThirdPartyCategory */ private $name = []; - /** - * @ORM\Column(type="boolean") - */ - private $active = true; + public function getActive(): ?bool + { + return $this->active; + } public function getId(): ?int { @@ -58,22 +50,17 @@ class ThirdPartyCategory return $this->name; } - public function setName(array $name): self - { - $this->name = $name; - - return $this; - } - - public function getActive(): ?bool - { - return $this->active; - } - public function setActive(bool $active): self { $this->active = $active; return $this; } + + public function setName(array $name): self + { + $this->name = $name; + + return $this; + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyProfession.php b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyProfession.php index 0a9048e25..659cba50a 100644 --- a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyProfession.php +++ b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdPartyProfession.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\ThirdPartyBundle\Entity; @@ -31,6 +18,11 @@ use Doctrine\ORM\Mapping as ORM; */ class ThirdPartyProfession { + /** + * @ORM\Column(type="boolean") + */ + private $active = true; + /** * @ORM\Id * @ORM\GeneratedValue @@ -43,10 +35,10 @@ class ThirdPartyProfession */ private $name = []; - /** - * @ORM\Column(type="boolean") - */ - private $active = true; + public function getActive(): ?bool + { + return $this->active; + } public function getId(): ?int { @@ -58,22 +50,17 @@ class ThirdPartyProfession return $this->name; } - public function setName(array $name): self - { - $this->name = $name; - - return $this; - } - - public function getActive(): ?bool - { - return $this->active; - } - public function setActive(bool $active): self { $this->active = $active; return $this; } + + public function setName(array $name): self + { + $this->name = $name; + + return $this; + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php b/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php index a3c7e154b..0e534b42c 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php @@ -1,45 +1,49 @@ center = $center; $this->partyRepository = $partyRepository; } - public function loadChoiceList($value = null): ChoiceListInterface { return new ArrayChoiceList($this->lazyLoadedParties, $value); @@ -48,39 +52,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 e2ebfa6d9..416dbd95c 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php @@ -1,51 +1,52 @@ askCenter = $parameterBag->get('chill_main')['acl']['form_show_centers']; } - /** - * {@inheritdoc} - */ public function buildForm(FormBuilderInterface $builder, array $options) { $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', ChillTextareaType::class, [ - 'required' => false + 'required' => false, ]); if ($this->askCenter) { $builder ->add('centers', PickCenterType::class, [ - 'role' => (\array_key_exists('data', $options) && $this->om->contains($options['data'])) ? + 'role' => (array_key_exists('data', $options) && $this->om->contains($options['data'])) ? ThirdPartyVoter::UPDATE : ThirdPartyVoter::CREATE, 'choice_options' => [ 'multiple' => true, - 'attr' => ['class' => 'select2'] - ] + 'attr' => ['class' => 'select2'], + ], ]); } @@ -111,7 +109,7 @@ class ThirdPartyType extends AbstractType ->where('c.active = true'); }, 'placeholder' => 'thirdparty.choose civility', - 'required' => false + 'required' => false, ]) ->add('profession', EntityType::class, [ 'label' => 'thirdparty.Profession', @@ -124,19 +122,18 @@ class ThirdPartyType extends AbstractType ->where('p.active = true'); }, 'placeholder' => 'thirdparty.choose profession', - 'required' => false + 'required' => false, ]) ->add('contactDataAnonymous', CheckboxType::class, [ 'required' => false, - 'label' => 'thirdparty.Contact data are confidential' - ]) - ; + 'label' => 'thirdparty.Contact data are confidential', + ]); // Institutional ThirdParty (parent) } else { $builder ->add('address', PickAddressType::class, [ - 'label' => 'Address' + 'label' => 'Address', ]) ->add('address2', PickAddressType::class, [ 'label' => 'Address', @@ -146,11 +143,11 @@ class ThirdPartyType extends AbstractType ]) ->add('nameCompany', TextType::class, [ 'label' => 'thirdparty.NameCompany', - 'required' => false + 'required' => false, ]) ->add('acronym', TextType::class, [ 'label' => 'thirdparty.Acronym', - 'required' => false + 'required' => false, ]) ->add('activeChildren', ChillCollectionType::class, [ 'entry_type' => ThirdPartyType::class, @@ -163,40 +160,35 @@ class ThirdPartyType extends AbstractType 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, - 'button_add_label' => "Add a contact", - 'button_remove_label' => "Remove a contact", - 'empty_collection_explain' => "Any contact" - ]) - ; + 'button_add_label' => 'Add a contact', + 'button_remove_label' => 'Remove a contact', + 'empty_collection_explain' => 'Any contact', + ]); } if (ThirdParty::KIND_CHILD !== $options['kind']) { $builder ->add('typesAndCategories', PickThirdPartyTypeCategoryType::class, [ - 'label' => 'thirdparty.Categories' + 'label' => 'thirdparty.Categories', ]) ->add('active', ChoiceType::class, [ 'label' => 'thirdparty.Status', 'choices' => [ 'Active, shown to users' => true, - 'Inactive, not shown to users' => false + 'Inactive, not shown to users' => false, ], 'expanded' => true, - 'multiple' => false + 'multiple' => false, ]); } } - - /** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( + $resolver->setDefaults([ 'data_class' => ThirdParty::class, 'is_child' => false, - 'kind' => null - )); + 'kind' => null, + ]); } } diff --git a/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php index 98d3e585b..56fbc5d73 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php @@ -1,55 +1,55 @@ 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/Form/Type/PickThirdPartyTypeCategoryType.php b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php index 2af962895..ac157d566 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php @@ -1,27 +1,38 @@ translator = $translator; } + public function configureOptions(OptionsResolver $resolver) + { + $choices = array_merge( + $this->thirdPartyCategoryRepository->findBy(['active' => true]), + $this->thirdPartyTypeManager->getTypes() + ); + + uasort($choices, function ($itemA, $itemB) { + $strA = $itemA instanceof ThirdPartyCategory ? $this->translatableStringHelper + ->localize($itemA->getName()) : $this->translator->trans(self::PREFIX_TYPE . $itemA); + $strB = $itemB instanceof ThirdPartyCategory ? $this->translatableStringHelper + ->localize($itemB->getName()) : $this->translator->trans(self::PREFIX_TYPE . $itemB); + + return $strA <=> $strB; + }); + + $resolver->setDefaults([ + 'choices' => $choices, + 'attr' => ['class' => 'select2'], + 'multiple' => true, + 'choice_label' => function ($item) { + if ($item instanceof ThirdPartyCategory) { + return $this->translatableStringHelper->localize($item->getName()); + } + + return self::PREFIX_TYPE . $item; + }, + 'choice_value' => function ($item) { + return $this->reverseTransform($item); + }, + ]); + } + public function getParent() { return ChoiceType::class; } - public function configureOptions(OptionsResolver $resolver) - { - $choices = \array_merge( - $this->thirdPartyCategoryRepository->findBy(['active' => true]), - $this->thirdPartyTypeManager->getTypes() - ); - - \uasort($choices, function ($itemA, $itemB) { - $strA = $itemA instanceof ThirdPartyCategory ? $this->translatableStringHelper - ->localize($itemA->getName()) : $this->translator->trans(self::PREFIX_TYPE.$itemA); - $strB = $itemB instanceof ThirdPartyCategory ? $this->translatableStringHelper - ->localize($itemB->getName()) : $this->translator->trans(self::PREFIX_TYPE.$itemB); - - return $strA <=> $strB; - }); - - - $resolver->setDefaults([ - 'choices' => $choices, - 'attr' => [ 'class' => 'select2' ], - 'multiple' => true, - 'choice_label' => function($item) { - if ($item instanceof ThirdPartyCategory) { - return $this->translatableStringHelper->localize($item->getName()); - } - return self::PREFIX_TYPE.$item; - }, - 'choice_value' => function($item) { - return $this->reverseTransform($item); - } - ]); - } - public function reverseTransform($value) { - if ($value === null) { + if (null === $value) { return null; } - if (is_array($value)){ + + if (is_array($value)) { $r = []; foreach ($value as $v) { - $r[] = $this->transform($v); + $r[] = $this->transform($v); } return $r; } if ($value instanceof ThirdPartyCategory) { - return 'category:'.$value->getId(); + return 'category:' . $value->getId(); } if (is_string($value)) { - return 'type:'.$value; + return 'type:' . $value; } - throw new UnexpectedTypeException($value, \implode(' or ', ['array', 'string', ThirdPartyCategory::class])); + throw new UnexpectedTypeException($value, implode(' or ', ['array', 'string', ThirdPartyCategory::class])); } } diff --git a/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php b/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php index e52ba66e1..609e485e8 100644 --- a/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php +++ b/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php @@ -1,45 +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\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; @@ -52,7 +38,6 @@ class MenuBuilder implements LocalMenuBuilderInterface $this->translator = $translator; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { if ($this->authorizationChecker->isGranted(ThirdPartyVoter::SHOW)) { @@ -61,11 +46,11 @@ class MenuBuilder implements LocalMenuBuilderInterface $this->translator->trans('Third parties'), [ 'route' => 'chill_crud_3party_3party_index', - ]) + ] + ) ->setExtras([ - 'order' => 112 - ]) - ; + 'order' => 112, + ]); } } diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php index ab535e60e..b08c36f7c 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php @@ -1,16 +1,24 @@ thirdPartyRepository = $thirdPartyRepository; } - public function listThirdParties( - string $role, - ?string $filterString, - ?array $orderBy = [], - ?int $limit = null, - ?int $offset = null - ): array { - $qb = $this->buildQuery($filterString); + public function buildQuery(?string $filterString = null): QueryBuilder + { + $qb = $this->thirdPartyRepository->createQueryBuilder('tp'); - foreach ($orderBy as $sort => $direction) { - $qb->addOrderBy('tp.'.$sort, $direction); + if (null !== $filterString) { + $qb->andWhere($qb->expr()->like('tp.canonicalized', 'LOWER(UNACCENT(:filterString))')) + ->setParameter('filterString', '%' . $filterString . '%'); } - $qb->setFirstResult($offset) - ->setMaxResults($limit); - - return $qb->getQuery()->getResult(); + return $qb; } public function countThirdParties( @@ -49,15 +50,22 @@ final class ThirdPartyACLAwareRepository implements ThirdPartyACLAwareRepository return $qb->getQuery()->getSingleScalarResult(); } - public function buildQuery(?string $filterString = null): QueryBuilder - { - $qb = $this->thirdPartyRepository->createQueryBuilder('tp'); + public function listThirdParties( + string $role, + ?string $filterString, + ?array $orderBy = [], + ?int $limit = null, + ?int $offset = null + ): array { + $qb = $this->buildQuery($filterString); - if (NULL !== $filterString) { - $qb->andWhere($qb->expr()->like('tp.canonicalized', 'LOWER(UNACCENT(:filterString))')) - ->setParameter('filterString', '%'.$filterString.'%'); + foreach ($orderBy as $sort => $direction) { + $qb->addOrderBy('tp.' . $sort, $direction); } - return $qb; + $qb->setFirstResult($offset) + ->setMaxResults($limit); + + return $qb->getQuery()->getResult(); } } diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.php index 459ac896a..9b8b4607c 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.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\Repository; @@ -38,5 +25,4 @@ class ThirdPartyCategoryRepository extends ServiceEntityRepository { parent::__construct($registry, ThirdPartyCategory::class); } - } diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyProfessionRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyProfessionRepository.php index 1216ee018..99c38e6fc 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyProfessionRepository.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyProfessionRepository.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\ThirdPartyBundle\Repository; @@ -38,5 +25,4 @@ class ThirdPartyProfessionRepository extends ServiceEntityRepository { parent::__construct($registry, ThirdPartyProfession::class); } - } diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php index f91501c59..71eac4340 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php @@ -1,14 +1,22 @@ getQuery()->getSingleScalarResult(); } - /** - * 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 - * 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 + public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder { - $qb = $this->buildQuery($centers, $terms); - 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); - $first = false; - } else { - $qb->addSelect($dql); - } - } - break; - default: - 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; - } - - /** - * Add parameters to filter by containing $terms["name"] or - * $terms["_default"] - * - * @param QueryBuilder $qb - * @param array $terms - */ - protected function setNameCondition(QueryBuilder $qb, array $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.'%'); - } - } - - protected function setTypesCondition(QueryBuilder $qb, array $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); - } - $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'") - ); - } + return $this->repository->createQueryBuilder($alias, $indexBy); } public function find($id): ?ThirdParty @@ -165,10 +59,9 @@ final class ThirdPartyRepository implements ObjectRepository } /** - * @param array $criteria - * @param array|null $orderBy * @param null $limit * @param null $offset + * * @return array|ThirdParty[] */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array @@ -176,6 +69,60 @@ final class ThirdPartyRepository implements ObjectRepository return $this->repository->findBy($criteria, $orderBy, $limit, $offset); } + /** + * 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 + * 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 int $firstResult + * @param int $maxResults + * @param array $terms + * @param string[] $returnFormat a format for returning + */ + public function findByMemberOfCenters(array $centers, $firstResult = 0, $maxResults = 20, $terms = [], $returnFormat = ['entity']): array + { + $qb = $this->buildQuery($centers, $terms); + + 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); + $first = false; + } else { + $qb->addSelect($dql); + } + } + + break; + + default: + throw new DomainException('This return format is invalid'); + } + $qb->setFirstResult($firstResult) + ->setMaxResults($maxResults); + + return $qb->getQuery()->getResult(); + } + public function findOneBy(array $criteria): ?ThirdParty { return $this->repository->findOneBy($criteria); @@ -186,9 +133,69 @@ final class ThirdPartyRepository implements ObjectRepository return ThirdParty::class; } - public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder + private function buildQuery($centers, $terms): QueryBuilder { - return $this->repository->createQueryBuilder($alias, $indexBy); + $qb = $this->createMemberOfCentersQuery($centers); + $this->setNameCondition($qb, $terms); + $this->setTypesCondition($qb, $terms); + $this->setIsActiveCondition($qb, $terms); + + return $qb; } + private 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; + } + + private 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"]. + */ + private function setNameCondition(QueryBuilder $qb, array $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 . '%'); + } + } + + private function setTypesCondition(QueryBuilder $qb, array $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); + } + $qb->andWhere($orx); + } + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php index d25b6ac8f..f708b0d9f 100644 --- a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php +++ b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php @@ -1,12 +1,21 @@ thirdPartyRepository = $thirdPartyRepository; } + public function getResult(string $key, array $metadata, float $pertinence) + { + return $this->thirdPartyRepository->find($metadata['id']); + } + + public function prepare(array $metadatas): void + { + } + public function provideQuery(string $pattern, array $parameters): SearchApiQuery { - $query = (new SearchApiQuery) + $query = (new SearchApiQuery()) ->setSelectKey('tparty') ->setSelectJsonbMetadata("jsonb_build_object('id', tparty.id)") ->setFromClause('chill_3party.third_party AS tparty @@ -55,8 +73,7 @@ class ThirdPartyApiSearch implements SearchApiInterface LEFT JOIN chill_3party.third_party AS parent ON tparty.parent_id = parent.id LEFT JOIN chill_main_address cma_p ON parent.address_id = cma_p.id LEFT JOIN chill_main_postal_code cmpc_p ON cma_p.postcode_id = cmpc.id') - ->andWhereClause("tparty.active IS TRUE") - ; + ->andWhereClause('tparty.active IS TRUE'); $strs = explode(' ', $pattern); $wheres = []; @@ -65,45 +82,39 @@ class ThirdPartyApiSearch implements SearchApiInterface $pertinenceArgs = []; foreach ($strs as $str) { - if (!empty($str)) { - $wheres[] = "(LOWER(UNACCENT(?)) <<% tparty.canonicalized OR + if (!empty($str)) { + $wheres[] = "(LOWER(UNACCENT(?)) <<% tparty.canonicalized OR tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')"; - $whereArgs[] = [$str, $str]; - $pertinence[] = "STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), tparty.canonicalized) + ". - "(tparty.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int + ". + $whereArgs[] = [$str, $str]; + $pertinence[] = 'STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), tparty.canonicalized) + ' . + "(tparty.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int + " . // take postcode label into account, but lower than the canonicalized field - "COALESCE((LOWER(UNACCENT(cmpc.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0) + ". + "COALESCE((LOWER(UNACCENT(cmpc.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0) + " . "COALESCE((LOWER(UNACCENT(cmpc_p.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0)"; - $pertinenceArgs[] = [$str, $str, $str, $str]; - } + $pertinenceArgs[] = [$str, $str, $str, $str]; + } } $query - ->setSelectPertinence(\implode(' + ', $pertinence), \array_merge([], - ...$pertinenceArgs)) - ->andWhereClause(\implode(' OR ', $wheres), \array_merge([], - ...$whereArgs)); + ->setSelectPertinence(implode(' + ', $pertinence), array_merge( + [], + ...$pertinenceArgs + )) + ->andWhereClause(implode(' OR ', $wheres), array_merge( + [], + ...$whereArgs + )); return $query; } - public function supportsTypes(string $pattern, array $types, array $parameters): bool - { - return \in_array('thirdparty', $types); - } - - public function prepare(array $metadatas): void - { - - } - public function supportsResult(string $key, array $metadatas): bool { - return $key === 'tparty'; + return 'tparty' === $key; } - public function getResult(string $key, array $metadata, float $pertinence) + public function supportsTypes(string $pattern, array $types, array $parameters): bool { - return $this->thirdPartyRepository->find($metadata['id']); + return in_array('thirdparty', $types); } } 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 ab78c7701..20f13cae8 100644 --- a/src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php +++ b/src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php @@ -1,94 +1,56 @@ 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) - { - return true; - - $user = $token->getUser(); - - if (!$user instanceof User) { - return false; - } - - return true; - - $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(), ]; } @@ -96,4 +58,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 + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool + { + return true; + $user = $token->getUser(); + + if (!$user instanceof User) { + return false; + } + + return true; + $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/Serializer/Normalizer/ThirdPartyNormalizer.php b/src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php index fb4456756..c086d7c1a 100644 --- a/src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php +++ b/src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php @@ -1,5 +1,12 @@ 'thirdparty', 'text' => $this->thirdPartyRender->renderString($thirdParty, []), 'id' => $thirdParty->getId(), 'kind' => $thirdParty->getKind(), - 'address' => $this->normalizer->normalize($thirdParty->getAddress(), $format, [ 'address_rendering' => 'short' ]), + 'address' => $this->normalizer->normalize($thirdParty->getAddress(), $format, ['address_rendering' => 'short']), 'phonenumber' => $thirdParty->getTelephone(), 'email' => $thirdParty->getEmail(), 'isChild' => $thirdParty->isChild(), @@ -42,9 +48,8 @@ class ThirdPartyNormalizer implements NormalizerInterface, NormalizerAwareInterf ]; } - public function supportsNormalization($data, string $format = null) + public function supportsNormalization($data, ?string $format = null) { return $data instanceof ThirdParty; } - } diff --git a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php index 01ff02e0a..11f24c136 100644 --- a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php +++ b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.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\ThirdPartyBundle\Templating\Entity; use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender; @@ -25,30 +14,22 @@ use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\ThirdPartyBundle\Entity\ThirdParty; use Symfony\Component\Templating\EngineInterface; -/** - * - * - */ class ThirdPartyRender extends AbstractChillEntityRender { - protected EngineInterface $engine; + protected TranslatableStringHelper $translatableStringHelper; public function __construct( EngineInterface $engine, TranslatableStringHelper $translatableStringHelper - ) - { + ) { $this->engine = $engine; $this->translatableStringHelper = $translatableStringHelper; } /** - * * @param ThirdParty $entity - * @param array $options - * @return string */ public function renderBox($entity, array $options): string { @@ -63,7 +44,7 @@ class ThirdPartyRender extends AbstractChillEntityRender 'customArea' => $options['customArea'] ?? [], 'showContacts' => $options['showContacts'] ?? false, 'showParent' => $options['showParent'] ?? true, - 'isConfidential' => $options['isConfidential'] ?? false + 'isConfidential' => $options['isConfidential'] ?? false, ]; return @@ -71,31 +52,30 @@ class ThirdPartyRender extends AbstractChillEntityRender $this->engine->render('@ChillThirdParty/Entity/thirdparty.html.twig', [ 'thirdparty' => $entity, 'render' => $options['render'] ?? 'raw', - 'options' => $params + 'options' => $params, ]) . $this->getDefaultClosingBox(); } /** - * * @param ThirdParty $entity - * @param array $options - * @return string */ public function renderString($entity, array $options): string { - if ($entity->getCivility() !== NULL) { + if ($entity->getCivility() !== null) { $civility = $this->translatableStringHelper - ->localize($entity->getCivility()->getAbbreviation()).' '; + ->localize($entity->getCivility()->getAbbreviation()) . ' '; } else { $civility = ''; } + if (!empty($entity->getAcronym())) { - $acronym = ' ('.$entity->getAcronym().')'; + $acronym = ' (' . $entity->getAcronym() . ')'; } else { $acronym = ''; } - return $civility.$entity->getName().$acronym; + + return $civility . $entity->getName() . $acronym; } public function supports($entity, array $options): bool 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/Tests/Entity/ThirdPartyTest.php b/src/Bundle/ChillThirdPartyBundle/Tests/Entity/ThirdPartyTest.php index ac1758030..fefecfb0d 100644 --- a/src/Bundle/ChillThirdPartyBundle/Tests/Entity/ThirdPartyTest.php +++ b/src/Bundle/ChillThirdPartyBundle/Tests/Entity/ThirdPartyTest.php @@ -1,11 +1,22 @@ removeTypesAndCategories('type'); $tp->removeTypesAndCategories($cat2); - $this->assertTrue($tp->getCategories()->contains($cat1), - "test that cat1 is still present"); + $this->assertTrue( + $tp->getCategories()->contains($cat1), + 'test that cat1 is still present' + ); $this->assertFalse($tp->getCategories()->contains($cat2)); $this->assertCount(1, $tp->getCategories()); @@ -55,7 +68,7 @@ class ThirdPartyTest extends TestCase 'type1', 'type2', $cat1 = new ThirdPartyCategory(), - $cat2 = new ThirdPartyCategory() + $cat2 = new ThirdPartyCategory(), ]); $this->assertTrue($tp->getCategories()->contains($cat1)); @@ -88,5 +101,4 @@ class ThirdPartyTest extends TestCase $this->assertContains('type1', $tp->getTypesAndCategories()); $this->assertNotContains('type2', $tp->getTypesAndCategories()); } - } diff --git a/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php b/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php index 87208bdcf..af0f7de06 100644 --- a/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php +++ b/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php @@ -1,56 +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('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))'); - - } - public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs @@ -29,6 +28,14 @@ final class Version20190307111314 extends AbstractMigration $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 + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $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))'); } } 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'); } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20210525211216.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20210525211216.php index ae270a1d1..507c0316e 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20210525211216.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20210525211216.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT fk_d952467bf5b7af75'); + $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'); + } + public function getDescription(): string { return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables'; @@ -22,10 +35,4 @@ final class Version20210525211216 extends AbstractMigration $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BF5B7AF75'); $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT FK_D952467BF5B7AF75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT fk_d952467bf5b7af75'); - $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'); - } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20210719105918.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20210719105918.php index cb7ba9835..3242e677b 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20210719105918.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20210719105918.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_3party.thirdparty_category DROP CONSTRAINT FK_7049563712469DE2'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B384D4799'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BBA930D69'); + $this->addSql('DROP SEQUENCE chill_3party.party_category_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_3party.party_civility_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_3party.party_profession_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_3party.party_category'); + $this->addSql('DROP TABLE chill_3party.party_civility'); + $this->addSql('DROP TABLE chill_3party.party_profession'); + $this->addSql('DROP TABLE chill_3party.thirdparty_category'); + $this->addSql('ALTER INDEX chill_3party.idx_14dc44755932f377 RENAME TO idx_c65d43975932f377'); + $this->addSql('ALTER INDEX chill_3party.idx_14dc4475c7d3a8e6 RENAME TO idx_c65d4397c7d3a8e6'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B727ACA70'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B16FE72E1'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP parent_id'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP civility'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP profession'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP updated_by'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP name_company'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP acronym'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP created_at'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP updated_at'); + } + public function getDescription(): string { return 'Add new fields to ThirdParty Entity + new join tables'; @@ -50,30 +82,4 @@ final class Version20210719105918 extends AbstractMigration $this->addSql('ALTER INDEX chill_3party.idx_c65d4397c7d3a8e6 RENAME TO IDX_14DC4475C7D3A8E6'); $this->addSql('ALTER INDEX chill_3party.idx_c65d43975932f377 RENAME TO IDX_14DC44755932F377'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_3party.thirdparty_category DROP CONSTRAINT FK_7049563712469DE2'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B384D4799'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BBA930D69'); - $this->addSql('DROP SEQUENCE chill_3party.party_category_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_3party.party_civility_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_3party.party_profession_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_3party.party_category'); - $this->addSql('DROP TABLE chill_3party.party_civility'); - $this->addSql('DROP TABLE chill_3party.party_profession'); - $this->addSql('DROP TABLE chill_3party.thirdparty_category'); - $this->addSql('ALTER INDEX chill_3party.idx_14dc44755932f377 RENAME TO idx_c65d43975932f377'); - $this->addSql('ALTER INDEX chill_3party.idx_14dc4475c7d3a8e6 RENAME TO idx_c65d4397c7d3a8e6'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B727ACA70'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B16FE72E1'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP parent_id'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP civility'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP profession'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP updated_by'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP name_company'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP acronym'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP created_at'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP updated_at'); - } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211006200924.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211006200924.php index d35552604..60ab49cd8 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211006200924.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211006200924.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_3party.third_party DROP created_by'); + } + public function getDescription(): string { return 'Add link to creator (created_by) to thirdParty'; @@ -19,19 +31,14 @@ final class Version20211006200924 extends AbstractMigration public function up(Schema $schema): void { - $this->addSql('ALTER TABLE chill_3party.third_party ADD created_by INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_3party.third_party ALTER created_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_3party.third_party ALTER created_at DROP DEFAULT'); - $this->addSql('ALTER TABLE chill_3party.third_party ALTER updated_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_3party.third_party ALTER updated_at DROP DEFAULT'); - $this->addSql('COMMENT ON COLUMN chill_3party.third_party.created_at IS \'(DC2Type:datetime_immutable)\''); - $this->addSql('COMMENT ON COLUMN chill_3party.third_party.updated_at IS \'(DC2Type:datetime_immutable)\''); - $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT FK_D952467BDE12AB56 FOREIGN KEY (created_by) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE INDEX IDX_D952467BDE12AB56 ON chill_3party.third_party (created_by)'); - } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_3party.third_party DROP created_by'); + $this->addSql('ALTER TABLE chill_3party.third_party ADD created_by INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_3party.third_party ALTER created_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_3party.third_party ALTER created_at DROP DEFAULT'); + $this->addSql('ALTER TABLE chill_3party.third_party ALTER updated_at TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_3party.third_party ALTER updated_at DROP DEFAULT'); + $this->addSql('COMMENT ON COLUMN chill_3party.third_party.created_at IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('COMMENT ON COLUMN chill_3party.third_party.updated_at IS \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT FK_D952467BDE12AB56 FOREIGN KEY (created_by) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_D952467BDE12AB56 ON chill_3party.third_party (created_by)'); } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007150459.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007150459.php index fb4f9bed1..29ecc702e 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007150459.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007150459.php @@ -1,5 +1,12 @@ throwIrreversibleMigrationException('Reversible migration not implemented'); + + // for reference: + $this->addSql('CREATE SEQUENCE chill_3party.party_civility_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_3party.party_civility (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B23D6A298'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BFDEF8996'); + $this->addSql('ALTER TABLE chill_3party.third_party ADD civility INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_3party.third_party ADD profession INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP civility_id'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP profession_id'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP kind'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP canonicalized'); + $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT fk_d952467b384d4799 FOREIGN KEY (civility) REFERENCES chill_3party.party_civility (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT fk_d952467bba930d69 FOREIGN KEY (profession) REFERENCES chill_3party.party_profession (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE UNIQUE INDEX uniq_d952467b384d4799 ON chill_3party.third_party (civility)'); + $this->addSql('CREATE UNIQUE INDEX uniq_d952467bba930d69 ON chill_3party.third_party (profession)'); + } + public function getDescription(): string { return 'migrate data from 3party.civility to chill_main_civility table'; @@ -45,25 +73,4 @@ final class Version20211007150459 extends AbstractMigration $this->addSql('CREATE INDEX IDX_D952467B23D6A298 ON chill_3party.third_party (civility_id)'); $this->addSql('CREATE INDEX IDX_D952467BFDEF8996 ON chill_3party.third_party (profession_id)'); } - - public function down(Schema $schema): void - { - $this->throwIrreversibleMigrationException('Reversible migration not implemented'); - - // for reference: - $this->addSql('CREATE SEQUENCE chill_3party.party_civility_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE TABLE chill_3party.party_civility (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467B23D6A298'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BFDEF8996'); - $this->addSql('ALTER TABLE chill_3party.third_party ADD civility INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_3party.third_party ADD profession INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP civility_id'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP profession_id'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP kind'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP canonicalized'); - $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT fk_d952467b384d4799 FOREIGN KEY (civility) REFERENCES chill_3party.party_civility (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT fk_d952467bba930d69 FOREIGN KEY (profession) REFERENCES chill_3party.party_profession (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE UNIQUE INDEX uniq_d952467b384d4799 ON chill_3party.third_party (civility)'); - $this->addSql('CREATE UNIQUE INDEX uniq_d952467bba930d69 ON chill_3party.third_party (profession)'); - } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php index f58fa1a79..2d33bbeb4 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php @@ -1,5 +1,12 @@ addSql('DROP TRIGGER canonicalize_fullname_on_update ON chill_3party.third_party'); + $this->addSql('DROP TRIGGER canonicalize_fullname_on_insert ON chill_3party.third_party'); + $this->addSql('DROP FUNCTION chill_3party.canonicalize()'); + $this->addSql(' + DROP INDEX chill_3party.chill_custom_canonicalized_trgm_idx_gist + '); + } + public function getDescription(): string { return 'Create trigger for canonicalisation on 3party + indexes'; @@ -54,33 +71,23 @@ final class Version20211007165001 extends AbstractMigration END $$ "); - $this->addSql(" + $this->addSql(' CREATE TRIGGER canonicalize_fullname_on_insert BEFORE INSERT ON chill_3party.third_party FOR EACH ROW EXECUTE procedure chill_3party.canonicalize(); - "); - $this->addSql(" + '); + $this->addSql(' CREATE TRIGGER canonicalize_fullname_on_update BEFORE UPDATE ON chill_3party.third_party FOR EACH ROW EXECUTE procedure chill_3party.canonicalize(); - "); - $this->addSql(" + '); + $this->addSql(' CREATE INDEX chill_custom_canonicalized_trgm_idx_gist ON chill_3party.third_party USING GIST (canonicalized gist_trgm_ops) WHERE active IS TRUE - "); - } - - public function down(Schema $schema): void - { - $this->addSql('DROP TRIGGER canonicalize_fullname_on_update ON chill_3party.third_party'); - $this->addSql('DROP TRIGGER canonicalize_fullname_on_insert ON chill_3party.third_party'); - $this->addSql('DROP FUNCTION chill_3party.canonicalize()'); - $this->addSql(" - DROP INDEX chill_3party.chill_custom_canonicalized_trgm_idx_gist - "); + '); } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007194942.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007194942.php index 7a6f5fb76..ac1b04486 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007194942.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007194942.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_3party.third_party DROP contact_data_anonymous'); + } + public function getDescription(): string { return 'Add anonymous flag for contacts'; @@ -21,9 +33,4 @@ final class Version20211007194942 extends AbstractMigration { $this->addSql('ALTER TABLE chill_3party.third_party ADD contact_data_anonymous BOOLEAN DEFAULT \'false\' NOT NULL;'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_3party.third_party DROP contact_data_anonymous'); - } } diff --git a/src/Bundle/ChillWopiBundle/src/ChillWopiBundle.php b/src/Bundle/ChillWopiBundle/src/ChillWopiBundle.php index 694503987..ac7ed05cb 100644 --- a/src/Bundle/ChillWopiBundle/src/ChillWopiBundle.php +++ b/src/Bundle/ChillWopiBundle/src/ChillWopiBundle.php @@ -1,6 +1,8 @@ 1 + 'closebutton' => 1, ] ) ); @@ -99,6 +105,5 @@ final class Test '@ChillWopi/Editor/page.html.twig', $configuration ); - } } diff --git a/src/Bundle/ChillWopiBundle/src/DependencyInjection/ChillWopiExtension.php b/src/Bundle/ChillWopiBundle/src/DependencyInjection/ChillWopiExtension.php index d67a62d94..37a9e2fa6 100644 --- a/src/Bundle/ChillWopiBundle/src/DependencyInjection/ChillWopiExtension.php +++ b/src/Bundle/ChillWopiBundle/src/DependencyInjection/ChillWopiExtension.php @@ -1,6 +1,8 @@ documentLockManager->deleteLock($document, $this->request); } /** * @param string $documentFilename without extension ! */ - public function findByDocumentFilename(string $documentFilename): ?Document { + public function findByDocumentFilename(string $documentFilename): ?Document + { return $this->storedObjectRepository->findOneBy( [ 'filename' => $documentFilename, @@ -101,7 +105,8 @@ final class ChillDocumentManager implements DocumentManagerInterface ); } - public function findByDocumentId(string $documentId): ?Document { + public function findByDocumentId(string $documentId): ?Document + { return $this->storedObjectRepository->findOneBy( [ 'uuid' => Uuid::fromString($documentId), @@ -109,6 +114,22 @@ final class ChillDocumentManager implements DocumentManagerInterface ); } + /** + * @param StoredObject $document + * + * @return string The document filename with its extension. + */ + public function getBasename(Document $document): string + { + $exts = (new MimeTypes())->getExtensions($document->getType()); + + if ([] === $exts) { + throw new Error('Unknown mimetype for stored document.'); + } + + return sprintf('%s.%s', $document->getFilename(), reset($exts)); + } + /** * @param StoredObject $document */ @@ -117,6 +138,14 @@ final class ChillDocumentManager implements DocumentManagerInterface return $document->getCreationDate(); } + /** + * @param StoredObject $document + */ + public function getDocumentId(Document $document): string + { + return (string) $document->getUuid(); + } + /** * @param StoredObject $document */ @@ -126,24 +155,46 @@ final class ChillDocumentManager implements DocumentManagerInterface return $document->getCreationDate(); } - public function getLock(Document $document): string { + public function getLock(Document $document): string + { return $this->documentLockManager->getLock($document, $this->request); } - public function getVersion(Document $document): string { + public function getSha256(Document $document): string + { + return base64_encode(hash('sha256', $this->getContent($document))); + } + + public function getSize(Document $document): int + { + return strlen($this->getContent($document)); + } + + public function getVersion(Document $document): string + { // TODO ? return '0'; } - public function hasLock(Document $document): bool { + public function hasLock(Document $document): bool + { return $this->documentLockManager->hasLock($document, $this->request); } - public function lock(Document $document, string $lock): void { + public function lock(Document $document, string $lock): void + { $this->documentLockManager->setLock($document, $lock, $this->request); } - public function remove(Document $document): void { + public function read(Document $document): StreamInterface + { + return $this + ->psr17 + ->createStream($this->getContent($document)); + } + + public function remove(Document $document): void + { $entityIsDeleted = false; try { @@ -153,7 +204,7 @@ final class ChillDocumentManager implements DocumentManagerInterface $entityIsDeleted = false; } - if ($entityIsDeleted === true) { + if (true === $entityIsDeleted) { $this->deleteContent($document); } } @@ -163,42 +214,6 @@ final class ChillDocumentManager implements DocumentManagerInterface $this->setContent($document, $properties['content']); } - /** - * @param StoredObject $document - * - * @return string The document filename with its extension. - */ - public function getBasename(Document $document): string { - $exts = (new MimeTypes())->getExtensions($document->getType()); - - if ([] === $exts) { - throw new Error('Unknown mimetype for stored document.'); - } - - return sprintf('%s.%s', $document->getFilename(), reset($exts)); - } - - /** - * @param StoredObject $document - */ - public function getDocumentId(Document $document): string { - return (string) $document->getUuid(); - } - - public function getSha256(Document $document): string { - return base64_encode(hash('sha256', $this->getContent($document))); - } - - public function getSize(Document $document): int { - return strlen($this->getContent($document)); - } - - public function read(Document $document): StreamInterface { - return $this - ->psr17 - ->createStream($this->getContent($document)); - } - private function deleteContent(StoredObject $storedObject): void { /** @var StdClass $object */ @@ -206,8 +221,7 @@ final class ChillDocumentManager implements DocumentManagerInterface $response = $this->httpClient->request('DELETE', $object->url); - if (200 !== $response->getStatusCode()) - { + if (200 !== $response->getStatusCode()) { throw new Error('Unable to delete stored object.'); } } @@ -219,8 +233,7 @@ final class ChillDocumentManager implements DocumentManagerInterface $response = $this->httpClient->request('GET', $object->url); - if (200 !== $response->getStatusCode()) - { + if (200 !== $response->getStatusCode()) { throw new Error('Unable to retrieve stored object.'); } @@ -235,10 +248,8 @@ final class ChillDocumentManager implements DocumentManagerInterface $response = $this->httpClient->request('PUT', $object->url, ['body' => $content]); - if (201 !== $response->getStatusCode()) - { + if (201 !== $response->getStatusCode()) { throw new Error('Unable to save stored object.'); } } - } diff --git a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php index ba289630e..21725c3f1 100644 --- a/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php +++ b/src/Bundle/ChillWopiBundle/src/Service/Wopi/ChillWopi.php @@ -1,6 +1,8 @@