From 2711fcee6d9cde16be08a99f623c90f6272333dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 2 Jan 2016 16:46:11 +0100 Subject: [PATCH 01/10] [export] add a first export and first filters - nationality aggregator (work in progress: we have to set the feature 'group by continent') - gender filter - nationality filter - gender filter --- Export/Aggregator/NationalityAggregator.php | 362 ++++++++++++++++++++ Export/Export/CountPerson.php | 79 +++++ Export/Filter/GenderFilter.php | 81 +++++ Export/Filter/NationalityFilter.php | 66 ++++ Resources/config/services.yml | 21 ++ 5 files changed, 609 insertions(+) create mode 100644 Export/Aggregator/NationalityAggregator.php create mode 100644 Export/Export/CountPerson.php create mode 100644 Export/Filter/GenderFilter.php create mode 100644 Export/Filter/NationalityFilter.php diff --git a/Export/Aggregator/NationalityAggregator.php b/Export/Aggregator/NationalityAggregator.php new file mode 100644 index 000000000..1c08d0111 --- /dev/null +++ b/Export/Aggregator/NationalityAggregator.php @@ -0,0 +1,362 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public 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\Export\Aggregator; + +use Chill\MainBundle\Export\AggregatorInterface; +use Symfony\Component\Form\FormBuilderInterface; +use Doctrine\ORM\QueryBuilder; + +/** + * + * + * @author Julien Fastré + */ +class NationalityAggregator implements AggregatorInterface +{ + + const EUROPE_COUNTRY_CODE = array('BE', 'FR'); + + public function applyOn() + { + return 'person'; + } + + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('group_by_level', 'choice', array( + 'choices' => array( + 'Group by continents' => 'continent', + 'Group by country' => 'country' + ), + 'choices_as_values' => true, + 'expanded' => true, + 'multiple' => false + )); + + } + + public function alterQuery(QueryBuilder $qb, $data) + { + // add a clause in select part + if ($data['group_by_level'] === 'country') { + $qb->addSelect('nationality.countryCode as nationality_aggregator'); + } elseif ($data['group_by_level'] === 'continent') { + $clause = 'CASE ' + . 'WHEN nationality.countryCode IN(:europe_country_codes) THEN \'europe\' ' + . 'ELSE \'other\' ' + . 'END as nationality_aggregator '; + $qb->addSelect($clause); + $qb->setParameter('europe_country_codes', self::EUROPE_COUNTRY_CODE); + } + + + $qb->leftJoin('person.nationality', 'nationality'); + + // add group by + $groupBy = $qb->getDQLPart('groupBy'); + + if (!empty($groupBy)) { + $qb->addGroupBy('nationality_aggregator'); + } else { + $qb->groupBy('nationality_aggregator'); + } + + } + + public function getTitle() + { + return "Group people by nationality"; + } + + public static function getCountryData() + { + // this list is extracted by https://en.wikipedia.org/wiki/List_of_sovereign_states_and_dependent_territories_by_continent_%28data_file%29 + // source : + // Wikipedia contributors, "List of sovereign states and dependent territories by continent (data file)," + // Wikipedia, The Free Encyclopedia, https://en.wikipedia.org/w/index.php?title=List_of_sovereign_states_and_dependent_territories_by_continent_(data_file)&oldid=688980440 + // (accessed January 2, 2016). + 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 . + */ + +namespace Chill\PersonBundle\Export\Export; + +use Chill\MainBundle\Export\ExportInterface; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; + +/** + * + * + * @author Julien Fastré + */ +class CountPerson implements ExportInterface +{ + /** + * + */ + public function getType() + { + return 'person'; + } + + public function getDescription() + { + return "Count persons by various parameters."; + } + + public function getTitle() + { + return "Count persons"; + } + + /** + * Initiate the query + * + * @param QueryBuilder $qb + * @return QueryBuilder + */ + public function initiateQuery(QueryBuilder $qb, array $requiredModifiers) + { + $qb->select('COUNT(person.id) AS export_result') + ->from('ChillPersonBundle:Person', 'person') + ; + + return $qb; + } + + public function buildForm(FormBuilderInterface $builder) { + throw new \LogicException('This export does not require a form'); + } + + public function hasForm(){ + return false; + } + + public function supportsModifiers() + { + return array('person'); + } + +} diff --git a/Export/Filter/GenderFilter.php b/Export/Filter/GenderFilter.php new file mode 100644 index 000000000..3b101e5e7 --- /dev/null +++ b/Export/Filter/GenderFilter.php @@ -0,0 +1,81 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public 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\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; + +/** + * + * + * @author Julien Fastré + */ +class GenderFilter implements FilterInterface +{ + + public function applyOn() + { + return 'person'; + } + + /** + * + */ + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('accepted_genders', 'choice', array( + 'choices' => array( + Person::FEMALE_GENDER => 'Woman', + Person::MALE_GENDER => 'Man' + ), + 'multiple' => true, + 'expanded' => false + )); + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $where = $qb->getDQLPart('where'); + $clause = $qb->expr()->in('person.gender', ':person_gender'); + + + if ($where instanceof Expr\Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->add('where', $where); + $qb->setParameter('person_gender', $data['accepted_genders']); + } + + /** + * A title which will be used in the label for the form + * + * @return string + */ + public function getTitle() + { + return 'Filter by person gender'; + } +} diff --git a/Export/Filter/NationalityFilter.php b/Export/Filter/NationalityFilter.php new file mode 100644 index 000000000..0f24c5e90 --- /dev/null +++ b/Export/Filter/NationalityFilter.php @@ -0,0 +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\Export\Filter; + +use Symfony\Component\Form\FormBuilderInterface; +use Doctrine\ORM\QueryBuilder; +use Chill\MainBundle\Export\FilterInterface; +use Doctrine\ORM\Query\Expr; + +/** + * + * + * @author Julien Fastré + */ +class NationalityFilter implements FilterInterface +{ + public function applyOn() + { + return 'person'; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('nationalities', 'select2_chill_country', array( + 'placeholder' => 'Choose countries' + )); + + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $where = $qb->getDQLPart('where'); + $clause = $qb->expr()->in('person.nationality', ':person_nationality'); + + if ($where instanceof Expr\Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->add('where', $where); + $qb->setParameter('person_nationality', array($data['nationalities'])); + } + + public function getTitle() + { + return "Filter by person's nationality"; + } +} diff --git a/Resources/config/services.yml b/Resources/config/services.yml index e934a7c71..575fe4b95 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -62,4 +62,25 @@ services: - "@chill.main.form.data_transformer.center_transformer" tags: - { name: form.type, alias: chill_personbundle_person_creation } + + chill.person.export.export_count_person: + class: Chill\PersonBundle\Export\Export\CountPerson + tags: + - { name: chill.export, alias: count_person } + + chill.person.export.filter_gender: + class: Chill\PersonBundle\Export\Filter\GenderFilter + tags: + - { name: chill.export_filter, alias: person_gender_filter } + + + chill.person.export.filter_nationality: + class: Chill\PersonBundle\Export\Filter\NationalityFilter + tags: + - { name: chill.export_filter, alias: person_nationality_filter } + + chill.person.export.aggregator_nationality: + class: Chill\PersonBundle\Export\Aggregator\NationalityAggregator + tags: + - { name: chill.export_aggregator, alias: person_nationality_aggregator } \ No newline at end of file From d81b2e1037713788c47b517179ca99665166a8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 11 Jan 2016 21:46:41 +0100 Subject: [PATCH 02/10] [wip] add different steps to exports --- Export/Aggregator/NationalityAggregator.php | 78 ++++++++++++++++++++- Export/Export/CountPerson.php | 28 ++++++++ Resources/config/services.yml | 4 ++ 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/Export/Aggregator/NationalityAggregator.php b/Export/Aggregator/NationalityAggregator.php index 1c08d0111..ce1a991b0 100644 --- a/Export/Aggregator/NationalityAggregator.php +++ b/Export/Aggregator/NationalityAggregator.php @@ -22,6 +22,9 @@ 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; /** * @@ -30,6 +33,32 @@ use Doctrine\ORM\QueryBuilder; */ class NationalityAggregator implements AggregatorInterface { + /** + * + * @var EntityRepository + */ + protected $countriesRepository; + + /** + * + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** + * + * @var TranslatorInterface + */ + protected $translator; + + public function __construct(EntityRepository $countriesRepository, + TranslatableStringHelper $translatableStringHelper, + TranslatorInterface $translator) + { + $this->countriesRepository = $countriesRepository; + $this->translatableStringHelper = $translatableStringHelper; + $this->translator = $translator; + } const EUROPE_COUNTRY_CODE = array('BE', 'FR'); @@ -60,11 +89,14 @@ class NationalityAggregator implements AggregatorInterface $qb->addSelect('nationality.countryCode as nationality_aggregator'); } elseif ($data['group_by_level'] === 'continent') { $clause = 'CASE ' - . 'WHEN nationality.countryCode IN(:europe_country_codes) THEN \'europe\' ' - . 'ELSE \'other\' ' + . 'WHEN nationality.countryCode IN(:europe_country_codes) THEN \'EU\' ' + . 'ELSE \'OC\' ' //this is dummy code ! . 'END as nationality_aggregator '; $qb->addSelect($clause); $qb->setParameter('europe_country_codes', self::EUROPE_COUNTRY_CODE); + } else { + throw new \LogicException("The group_by_level '".$data['group_by_level'] + ." is not known."); } @@ -86,6 +118,48 @@ class NationalityAggregator implements AggregatorInterface return "Group people by nationality"; } + public function getQueryKeys($data) + { + return array('nationality_aggregator'); + } + + public function getLabels($key, array $values, $data) + { + if ($data['group_by_level'] === 'country') { + $qb = $this->countriesRepository->createQueryBuilder('c'); + + $countries = $qb + ->andWhere($qb->expr()->in('c.countryCode', ':countries')) + ->setParameter('countries', $values) + ->getQuery() + ->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR); + + // initialize array and add blank key for null values + $labels[''] = $this->translator->trans('without data'); + $labels['_header'] = $this->translator->trans('Nationality'); + foreach($countries as $row) { + $labels[$row['c_countryCode']] = $this->translatableStringHelper->localize($row['c_name']); + } + + return $labels; + + } elseif ($data['group_by_level'] === 'continent') { + + return array( + 'EU' => $this->translator->trans('Europe'), + 'AS' => $this->translator->trans('Asia'), + 'AN' => $this->translator->trans('Antartica'), + 'AF' => $this->translator->trans('Africa'), + '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') + ); + } + + } + public static function getCountryData() { // this list is extracted by https://en.wikipedia.org/wiki/List_of_sovereign_states_and_dependent_territories_by_continent_%28data_file%29 diff --git a/Export/Export/CountPerson.php b/Export/Export/CountPerson.php index d5772b39f..e4185ba9f 100644 --- a/Export/Export/CountPerson.php +++ b/Export/Export/CountPerson.php @@ -22,6 +22,7 @@ namespace Chill\PersonBundle\Export\Export; use Chill\MainBundle\Export\ExportInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; +use Doctrine\ORM\Query; /** * @@ -63,6 +64,33 @@ class CountPerson implements ExportInterface 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'] = 'Number of people'; + + return $labels; + } + + public function getAllowedFormattersTypes() + { + return array('tabular'); + } + public function buildForm(FormBuilderInterface $builder) { throw new \LogicException('This export does not require a form'); } diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 575fe4b95..55e939020 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -81,6 +81,10 @@ services: chill.person.export.aggregator_nationality: class: Chill\PersonBundle\Export\Aggregator\NationalityAggregator + arguments: + - "@chill.main.countries_repository" + - "@chill.main.helper.translatable_string" + - "@translator" tags: - { name: chill.export_aggregator, alias: person_nationality_aggregator } \ No newline at end of file From a5065f798ac7d07889a7fcbf8b682eb990e39714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 14 Jan 2016 12:19:29 +0100 Subject: [PATCH 03/10] add gender aggregator --- Export/Aggregator/GenderAggregator.php | 85 ++++++++++++++++++++++++++ Resources/config/services.yml | 8 ++- 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 Export/Aggregator/GenderAggregator.php diff --git a/Export/Aggregator/GenderAggregator.php b/Export/Aggregator/GenderAggregator.php new file mode 100644 index 000000000..d0be7295b --- /dev/null +++ b/Export/Aggregator/GenderAggregator.php @@ -0,0 +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 . + */ + +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; + +/** + * + * + * @author Julien Fastré + */ +class GenderAggregator implements AggregatorInterface +{ + + /** + * + * @var TranslatorInterface + */ + protected $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function applyOn() + { + return 'person'; + } + + + 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 array( + Person::FEMALE_GENDER => $this->translator->trans('woman'), + Person::MALE_GENDER => $this->translator->trans('man'), + '_header' => $this->translator->trans('Gender') + ); + } +} diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 55e939020..0e15965de 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -87,4 +87,10 @@ services: - "@translator" tags: - { name: chill.export_aggregator, alias: person_nationality_aggregator } - \ No newline at end of file + + chill.person.export.aggregator_gender: + class: Chill\PersonBundle\Export\Aggregator\GenderAggregator + arguments: + - "@translator" + tags: + - { name: chill.export_aggregator, alias: person_gender_aggregator } \ No newline at end of file From 5b3bd6545a46a7536f2767ea3e2e99476dcef9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 23 Jan 2016 01:20:41 +0100 Subject: [PATCH 04/10] add a role for stats, apply role on export --- DependencyInjection/ChillPersonExtension.php | 4 +++- Export/Export/CountPerson.php | 7 +++++++ Security/Authorization/PersonVoter.php | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/DependencyInjection/ChillPersonExtension.php b/DependencyInjection/ChillPersonExtension.php index 589e2c14e..cc3c593be 100644 --- a/DependencyInjection/ChillPersonExtension.php +++ b/DependencyInjection/ChillPersonExtension.php @@ -8,6 +8,7 @@ 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; /** * This is the class that loads and manages your bundle configuration @@ -84,7 +85,8 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac $container->prependExtensionConfig('security', array( 'role_hierarchy' => array( 'CHILL_PERSON_UPDATE' => array('CHILL_PERSON_SEE'), - 'CHILL_PERSON_CREATE' => array('CHILL_PERSON_SEE') + 'CHILL_PERSON_CREATE' => array('CHILL_PERSON_SEE'), + 'CHILL_PERSON_SEE' => array(PersonVoter::STATS) ) )); } diff --git a/Export/Export/CountPerson.php b/Export/Export/CountPerson.php index e4185ba9f..6078d7ea8 100644 --- a/Export/Export/CountPerson.php +++ b/Export/Export/CountPerson.php @@ -23,6 +23,8 @@ 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; /** * @@ -49,6 +51,11 @@ class CountPerson implements ExportInterface return "Count persons"; } + public function requiredRole() + { + return new Role(PersonVoter::STATS); + } + /** * Initiate the query * diff --git a/Security/Authorization/PersonVoter.php b/Security/Authorization/PersonVoter.php index d795c39cf..1f1116abe 100644 --- a/Security/Authorization/PersonVoter.php +++ b/Security/Authorization/PersonVoter.php @@ -34,6 +34,7 @@ class PersonVoter extends AbstractChillVoter implements ProvideRoleInterface const CREATE = 'CHILL_PERSON_CREATE'; const UPDATE = 'CHILL_PERSON_UPDATE'; const SEE = 'CHILL_PERSON_SEE'; + const STATS = 'CHILL_PERSON_STATS'; /** * From 9cb37a61158ef4a0bdc1a417bcc2786a503afadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 24 Jan 2016 22:25:55 +0100 Subject: [PATCH 05/10] add ACL for export --- Export/Filter/GenderFilter.php | 6 ++++++ Export/Filter/NationalityFilter.php | 6 ++++++ Security/Authorization/PersonVoter.php | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Export/Filter/GenderFilter.php b/Export/Filter/GenderFilter.php index 3b101e5e7..f1ae8f7e2 100644 --- a/Export/Filter/GenderFilter.php +++ b/Export/Filter/GenderFilter.php @@ -24,6 +24,7 @@ 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; /** * @@ -78,4 +79,9 @@ class GenderFilter implements FilterInterface { return 'Filter by person gender'; } + + public function requiredRole() + { + return new Role(\Chill\PersonBundle\Security\Authorization\PersonVoter::STATS); + } } diff --git a/Export/Filter/NationalityFilter.php b/Export/Filter/NationalityFilter.php index 0f24c5e90..6b2d5966e 100644 --- a/Export/Filter/NationalityFilter.php +++ b/Export/Filter/NationalityFilter.php @@ -23,6 +23,7 @@ use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Export\FilterInterface; use Doctrine\ORM\Query\Expr; +use Symfony\Component\Security\Core\Role\Role; /** * @@ -63,4 +64,9 @@ class NationalityFilter implements FilterInterface { return "Filter by person's nationality"; } + + public function requiredRole() + { + return new Role(\Chill\PersonBundle\Security\Authorization\PersonVoter::STATS); + } } diff --git a/Security/Authorization/PersonVoter.php b/Security/Authorization/PersonVoter.php index 1f1116abe..8808882f8 100644 --- a/Security/Authorization/PersonVoter.php +++ b/Security/Authorization/PersonVoter.php @@ -49,12 +49,12 @@ class PersonVoter extends AbstractChillVoter implements ProvideRoleInterface protected function getSupportedAttributes() { - return array(self::CREATE, self::UPDATE, self::SEE); + return array(self::CREATE, self::UPDATE, self::SEE, self::STATS); } protected function getSupportedClasses() { - return array('Chill\PersonBundle\Entity\Person'); + return array('Chill\PersonBundle\Entity\Person', 'Chill\MainBundle\Entity\Center'); } protected function isGranted($attribute, $person, $user = null) From 0ab2e85aef55d9ff2775411d6fcfef6fd7bbf621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 26 Jan 2016 11:23:38 +0100 Subject: [PATCH 06/10] refactor voter to take into account two differents object type --- Security/Authorization/PersonVoter.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Security/Authorization/PersonVoter.php b/Security/Authorization/PersonVoter.php index 8808882f8..916966a8a 100644 --- a/Security/Authorization/PersonVoter.php +++ b/Security/Authorization/PersonVoter.php @@ -57,13 +57,23 @@ class PersonVoter extends AbstractChillVoter implements ProvideRoleInterface return array('Chill\PersonBundle\Entity\Person', 'Chill\MainBundle\Entity\Center'); } - protected function isGranted($attribute, $person, $user = null) + protected function isGranted($attribute, $object, $user = null) { if (!$user instanceof User) { return false; } - return $this->helper->userHasAccess($user, $person, $attribute); + if ($attribute === self::STATS and !$object instanceof \Chill\MainBundle\Entity\Center) { + throw new \LogicException("the expected type is \Chill\MainBundle\Entity\Center for " + . "role ".self::STATS." ".get_class($object)." given."); + } + + if ($attribute !== self::STATS and !$object instanceof \Chill\PersonBundle\Entity\Person) { + throw new \LogicException("the expected type is \Chill\PersonBundle\Entity\Person for " + . "role ".$attribute." ".get_class($object)." given."); + } + + return $this->helper->userHasAccess($user, $object, $attribute); } From 2f9b4a8c81071c961a491769d290b16937779574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 26 Jan 2016 11:47:04 +0100 Subject: [PATCH 07/10] make aggregor take roles into account --- Export/Aggregator/GenderAggregator.php | 8 ++++++++ Export/Aggregator/NationalityAggregator.php | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/Export/Aggregator/GenderAggregator.php b/Export/Aggregator/GenderAggregator.php index d0be7295b..56cbfacfa 100644 --- a/Export/Aggregator/GenderAggregator.php +++ b/Export/Aggregator/GenderAggregator.php @@ -24,6 +24,8 @@ use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Translation\TranslatorInterface; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Symfony\Component\Security\Core\Role\Role; /** * @@ -82,4 +84,10 @@ class GenderAggregator implements AggregatorInterface '_header' => $this->translator->trans('Gender') ); } + + public function requiredRole() + { + return new Role(PersonVoter::STATS); + } + } diff --git a/Export/Aggregator/NationalityAggregator.php b/Export/Aggregator/NationalityAggregator.php index ce1a991b0..dbbaaa596 100644 --- a/Export/Aggregator/NationalityAggregator.php +++ b/Export/Aggregator/NationalityAggregator.php @@ -25,6 +25,8 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\EntityRepository; use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Security\Core\Role\Role; +use Chill\PersonBundle\Security\Authorization\PersonVoter; /** * @@ -123,6 +125,11 @@ class NationalityAggregator implements AggregatorInterface return array('nationality_aggregator'); } + public function requiredRole() + { + return new Role(PersonVoter::STATS); + } + public function getLabels($key, array $values, $data) { if ($data['group_by_level'] === 'country') { From e79aebabffbe696972b85fd56fde34697f0d2f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 26 Jan 2016 12:21:44 +0100 Subject: [PATCH 08/10] implement acl in query --- Export/Export/CountPerson.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Export/Export/CountPerson.php b/Export/Export/CountPerson.php index 6078d7ea8..9adeee712 100644 --- a/Export/Export/CountPerson.php +++ b/Export/Export/CountPerson.php @@ -62,12 +62,18 @@ class CountPerson implements ExportInterface * @param QueryBuilder $qb * @return QueryBuilder */ - public function initiateQuery(QueryBuilder $qb, array $requiredModifiers) + public function initiateQuery(QueryBuilder $qb, array $requiredModifiers, $acl) { + $centers = array_map(function($el) { return $el['center']; }, $acl); + $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; } From e616626cc2b7dd7ad36fe9fa4e270e270a29e064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 31 Jan 2016 23:43:53 +0100 Subject: [PATCH 09/10] adapt elements to new interface definition --- Export/Aggregator/GenderAggregator.php | 9 +++--- Export/Aggregator/NationalityAggregator.php | 4 +-- Export/Declarations.php | 31 +++++++++++++++++++++ Export/Export/CountPerson.php | 10 ++++--- Export/Filter/GenderFilter.php | 4 +-- Export/Filter/NationalityFilter.php | 4 +-- 6 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 Export/Declarations.php diff --git a/Export/Aggregator/GenderAggregator.php b/Export/Aggregator/GenderAggregator.php index 56cbfacfa..bc75c4350 100644 --- a/Export/Aggregator/GenderAggregator.php +++ b/Export/Aggregator/GenderAggregator.php @@ -24,8 +24,7 @@ use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Translation\TranslatorInterface; use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Symfony\Component\Security\Core\Role\Role; +use Chill\PersonBundle\Export\Declarations; /** * @@ -48,7 +47,7 @@ class GenderAggregator implements AggregatorInterface public function applyOn() { - return 'person'; + return Declarations::PERSON_TYPE; } @@ -85,9 +84,9 @@ class GenderAggregator implements AggregatorInterface ); } - public function requiredRole() + public function addRole() { - return new Role(PersonVoter::STATS); + return NULL; } } diff --git a/Export/Aggregator/NationalityAggregator.php b/Export/Aggregator/NationalityAggregator.php index dbbaaa596..834921f68 100644 --- a/Export/Aggregator/NationalityAggregator.php +++ b/Export/Aggregator/NationalityAggregator.php @@ -125,9 +125,9 @@ class NationalityAggregator implements AggregatorInterface return array('nationality_aggregator'); } - public function requiredRole() + public function addRole() { - return new Role(PersonVoter::STATS); + return NULL; } public function getLabels($key, array $values, $data) diff --git a/Export/Declarations.php b/Export/Declarations.php new file mode 100644 index 000000000..6c0735d18 --- /dev/null +++ b/Export/Declarations.php @@ -0,0 +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\PersonBundle\Export; + +/** + * This class declare constants used for the export framework. + * + * + * @author Julien Fastré + */ +abstract class Declarations +{ + CONST PERSON_TYPE = 'person'; +} diff --git a/Export/Export/CountPerson.php b/Export/Export/CountPerson.php index 9adeee712..3a573e635 100644 --- a/Export/Export/CountPerson.php +++ b/Export/Export/CountPerson.php @@ -25,6 +25,8 @@ 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; /** * @@ -38,7 +40,7 @@ class CountPerson implements ExportInterface */ public function getType() { - return 'person'; + return Declarations::PERSON_TYPE; } public function getDescription() @@ -77,7 +79,7 @@ class CountPerson implements ExportInterface return $qb; } - public function getResult($qb, $data) + public function getResult(QueryBuilder $qb, $data) { return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); } @@ -101,7 +103,7 @@ class CountPerson implements ExportInterface public function getAllowedFormattersTypes() { - return array('tabular'); + return array(FormatterInterface::TYPE_TABULAR); } public function buildForm(FormBuilderInterface $builder) { @@ -114,7 +116,7 @@ class CountPerson implements ExportInterface public function supportsModifiers() { - return array('person'); + return array(Declarations::PERSON_TYPE); } } diff --git a/Export/Filter/GenderFilter.php b/Export/Filter/GenderFilter.php index f1ae8f7e2..14aba4376 100644 --- a/Export/Filter/GenderFilter.php +++ b/Export/Filter/GenderFilter.php @@ -80,8 +80,8 @@ class GenderFilter implements FilterInterface return 'Filter by person gender'; } - public function requiredRole() + public function addRole() { - return new Role(\Chill\PersonBundle\Security\Authorization\PersonVoter::STATS); + return NULL; } } diff --git a/Export/Filter/NationalityFilter.php b/Export/Filter/NationalityFilter.php index 6b2d5966e..136002853 100644 --- a/Export/Filter/NationalityFilter.php +++ b/Export/Filter/NationalityFilter.php @@ -65,8 +65,8 @@ class NationalityFilter implements FilterInterface return "Filter by person's nationality"; } - public function requiredRole() + public function addRole() { - return new Role(\Chill\PersonBundle\Security\Authorization\PersonVoter::STATS); + return NULL; } } From 2012170724701ec8a0861c13e2f6a861d57f657b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 5 Feb 2016 15:03:22 +0100 Subject: [PATCH 10/10] adapt to new ExportInterface --- Export/Export/CountPerson.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Export/Export/CountPerson.php b/Export/Export/CountPerson.php index 3a573e635..df7611c25 100644 --- a/Export/Export/CountPerson.php +++ b/Export/Export/CountPerson.php @@ -64,7 +64,7 @@ class CountPerson implements ExportInterface * @param QueryBuilder $qb * @return QueryBuilder */ - public function initiateQuery(QueryBuilder $qb, array $requiredModifiers, $acl) + public function initiateQuery(QueryBuilder $qb, array $requiredModifiers, array $acl, array $data = array()) { $centers = array_map(function($el) { return $el['center']; }, $acl); @@ -107,11 +107,7 @@ class CountPerson implements ExportInterface } public function buildForm(FormBuilderInterface $builder) { - throw new \LogicException('This export does not require a form'); - } - - public function hasForm(){ - return false; + } public function supportsModifiers()