From b40b85527a4f506fe66a992872b25573c351a7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 2 Jan 2016 16:44:30 +0100 Subject: [PATCH] create a first set of export framework - create interfaces - create an export manager - add a compiler pass to gather services tagged for export --- ChillMainBundle.php | 4 +- Controller/ExportController.php | 63 +++- .../CompilerPass/ExportsCompilerPass.php | 147 ++++++++ Export/AggregatorInterface.php | 38 ++ Export/ExportInterface.php | 55 +++ Export/ExportManager.php | 338 ++++++++++++++++++ Export/FilterInterface.php | 39 ++ Export/FormatterInterface.php | 29 ++ Form/Type/Export/AggregatorType.php | 82 +++++ Form/Type/Export/ExportType.php | 102 ++++++ Form/Type/Export/FilterType.php | 75 ++++ Resources/config/routing.yml | 13 +- Resources/config/routing/exports.yml | 18 + Resources/config/services.yml | 13 + Resources/views/Export/layout.html.twig | 19 +- Resources/views/Export/new.html.twig | 51 +++ 16 files changed, 1070 insertions(+), 16 deletions(-) create mode 100644 DependencyInjection/CompilerPass/ExportsCompilerPass.php create mode 100644 Export/AggregatorInterface.php create mode 100644 Export/ExportInterface.php create mode 100644 Export/ExportManager.php create mode 100644 Export/FilterInterface.php create mode 100644 Export/FormatterInterface.php create mode 100644 Form/Type/Export/AggregatorType.php create mode 100644 Form/Type/Export/ExportType.php create mode 100644 Form/Type/Export/FilterType.php create mode 100644 Resources/config/routing/exports.yml create mode 100644 Resources/views/Export/new.html.twig diff --git a/ChillMainBundle.php b/ChillMainBundle.php index 682a85cf1..2f53f8e69 100644 --- a/ChillMainBundle.php +++ b/ChillMainBundle.php @@ -8,6 +8,7 @@ use Chill\MainBundle\DependencyInjection\SearchableServicesCompilerPass; use Chill\MainBundle\DependencyInjection\ConfigConsistencyCompilerPass; use Chill\MainBundle\DependencyInjection\TimelineCompilerClass; use Chill\MainBundle\DependencyInjection\RoleProvidersCompilerPass; +use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass; class ChillMainBundle extends Bundle { @@ -17,6 +18,7 @@ class ChillMainBundle extends Bundle $container->addCompilerPass(new SearchableServicesCompilerPass()); $container->addCompilerPass(new ConfigConsistencyCompilerPass()); $container->addCompilerPass(new TimelineCompilerClass()); - $container->addCompilerPass(new RoleProvidersCompilerPass); + $container->addCompilerPass(new RoleProvidersCompilerPass()); + $container->addCompilerPass(new ExportsCompilerPass()); } } diff --git a/Controller/ExportController.php b/Controller/ExportController.php index af143c3e1..392340eab 100644 --- a/Controller/ExportController.php +++ b/Controller/ExportController.php @@ -23,6 +23,9 @@ namespace Chill\MainBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\HttpFoundation\Request; +use Chill\MainBundle\Form\Type\Export\ExportType; + /** * ExportController is the controller use for exporting data. @@ -30,10 +33,62 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; */ class ExportController extends Controller { - public function indexAction($menu = 'admin', - $header_title = 'views.Main.admin.index.header_title', - $page_title = 'views.Main.admin.index.page_title') + public function indexAction(Request $request) { - return $this->render('ChillMainBundle:Export:layout.html.twig'); + $exportManager = $this->get('chill.main.export_manager'); + + $exports = $exportManager->getExports(); + + return $this->render('ChillMainBundle:Export:layout.html.twig', array( + 'exports' => $exports + )); + } + + public function newAction($alias) + { + $exportManager = $this->get('chill.main.export_manager'); + + $export = $exportManager->getExport($alias); + + $form = $this->createCreateForm($alias); + + return $this->render('ChillMainBundle:Export:new.html.twig', array( + 'form' => $form->createView(), + 'export_alias' => $alias, + 'export' => $export + )); + + } + + /** + * + * @param string $alias + * @return \Symfony\Component\Form\Form + */ + protected function createCreateForm($alias) + { + $form = $this->createForm(ExportType::class, array(), array( + 'export_alias' => $alias, + 'method' => 'GET', + 'action' => $this->generateUrl('chill_main_export_generate', array( + 'alias' => $alias + )) + )); + + $form->add('submit', 'submit', array( + 'label' => 'Generate' + )); + + return $form; + } + + public function generateAction(Request $request, $alias) + { + $exportManager = $this->get('chill.main.export_manager'); + + $form = $this->createCreateForm($alias); + $form->handleRequest($request); + + return $exportManager->generate($alias, $form->getData()); } } diff --git a/DependencyInjection/CompilerPass/ExportsCompilerPass.php b/DependencyInjection/CompilerPass/ExportsCompilerPass.php new file mode 100644 index 000000000..39045495f --- /dev/null +++ b/DependencyInjection/CompilerPass/ExportsCompilerPass.php @@ -0,0 +1,147 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public 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 Symfony\Component\DependencyInjection\Definition; + +/** + * Compiles the services tagged with : + * + * - chill.export + * - chill.export_formatter + * - chill.export_aggregator + * - chill.export_filter + * + * + * @author Julien Fastré + */ +class ExportsCompilerPass implements CompilerPassInterface +{ + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('chill.main.export_manager')) { + throw new \LogicException('service chill.main.export_manager ' + . 'is not defined. It is required by ExportsCompilerPass'); + } + + $chillManagerDefinition = $container->getDefinition( + 'chill.main.export_manager' + ); + + $this->compileExports($chillManagerDefinition, $container); + $this->compileFilters($chillManagerDefinition, $container); + $this->compileAggregators($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) + { + $taggedServices = $container->findTaggedServiceIds( + 'chill.export_aggregator' + ); + + $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_aggregator service with alias " + .$attributes["alias"].". Choose another alias."); + } + $knownAliases[] = $attributes["alias"]; + + $chillManagerDefinition->addMethodCall( + 'addAggregator', + array(new Reference($id), $attributes["alias"]) + ); + } + } + } + +} diff --git a/Export/AggregatorInterface.php b/Export/AggregatorInterface.php new file mode 100644 index 000000000..c2c876f06 --- /dev/null +++ b/Export/AggregatorInterface.php @@ -0,0 +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; + +use Symfony\Component\Form\FormBuilderInterface; +use Doctrine\ORM\QueryBuilder; + +/** + * + * @author Julien Fastré + */ +interface AggregatorInterface +{ + public function applyOn(); + + public function buildForm(FormBuilderInterface $builder); + + public function alterQuery(QueryBuilder $qb, $data); + + public function getTitle(); +} diff --git a/Export/ExportInterface.php b/Export/ExportInterface.php new file mode 100644 index 000000000..a44a9ef6d --- /dev/null +++ b/Export/ExportInterface.php @@ -0,0 +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\MainBundle\Export; + +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; + +/** + * + * @author Julien Fastré + */ +interface ExportInterface +{ + + public function getType(); + + public function getDescription(); + + public function getTitle(); + + /** + * + * @param QueryBuilder $qb + * @param array $requiredModifiers + * TODO : we should add ability to receive data from a form + */ + public function initiateQuery(QueryBuilder $qb, array $requiredModifiers); + + public function buildForm(FormBuilderInterface $builder); + + /** + * @return bool + */ + public function hasForm(); + + public function supportsModifiers(); + +} diff --git a/Export/ExportManager.php b/Export/ExportManager.php new file mode 100644 index 000000000..f243f8492 --- /dev/null +++ b/Export/ExportManager.php @@ -0,0 +1,338 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public 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; + +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 Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\QueryBuilder; + +/** + * Collects all agregators, filters and export from + * the installed bundle. + * + * + * @author Julien Fastré + */ +class ExportManager +{ + /** + * + * @var FilterInterface[] + */ + private $filters = array(); + + /** + * + * @var AggregatorInterface[] + */ + private $aggregators = array(); + + /** + * + * @var ExportInterface[] + */ + private $exports = array(); + + /** + * + * @var FormatterInterface[] + */ + private $formatters = array(); + + /** + * + * @var LoggerInterface + */ + private $logger; + + /** + * + * @var EntityManagerInterface + */ + private $em; + + public function __construct(LoggerInterface $logger, EntityManagerInterface $em) + { + $this->logger = $logger; + $this->em = $em; + } + + public function addFilter(FilterInterface $filter, $alias) + { + $this->filters[$alias] = $filter; + } + + public function addAggregator(AggregatorInterface $aggregator, $alias) + { + $this->aggregators[$alias] = $aggregator; + } + + public function addExport(ExportInterface $export, $alias) + { + $this->exports[$alias] = $export; + } + + public function addFormatter(FormatterInterface $formatter) + { + array_push($this->formatters, $formatter); + } + + /** + * + * @return string[] the existing type for known exports + */ + public function getExistingExportsTypes() + { + $existingTypes = array(); + + foreach($this->exports as $export) { + if (!in_array($export->getType(), $existingTypes)) { + array_push($existingTypes, $export->getType()); + } + } + + return $existingTypes; + } + + /** + * Return all exports. The exports's alias are the array's keys. + * + * @return ExportInterface[] an array where export's alias are keys + */ + public function getExports() + { + return $this->exports; + } + + /** + * 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 + * @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."); + } + + return $this->filters[$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]; + } + + + /** + * Return a \Generator containing filter which support type + * + * @param string[] $types + * @return FilterInterface[] a \Generator that contains filters. The key is the filter's alias + */ + public function &getFiltersApplyingOn(array $types) + { + foreach ($this->filters as $alias => $filter) { + if (in_array($filter->applyOn(), $types)) { + yield $alias => $filter; + } + } + } + + /** + * Return a \Generator containing filter which support type + * + * @param string $types + * @return FilterInterface[] a \Generator that contains filters. The key is the filter's alias + */ + public function &getFiltersSupportingType($type) + { + foreach ($this->filters as $alias => $filter) { + if ($filter->supportsType($type)) { + yield $alias => $filter; + } + } + } + + /** + * Return a \Generator containing aggregators which support type + * + * @param string[] $types + * @return AggregatorInterface[] a \Generator that contains aggretagors. The key is the filter's alias + */ + public function &getAggregatorsApplyingOn(array $types) + { + foreach ($this->aggregators as $alias => $aggregator) { + if (in_array($aggregator->applyOn(), $types)) { + yield $alias => $aggregator; + } + } + } + + /** + * Generate a response which contains the requested data. + * + * @param string $exportAlias + * @param mixed[] $data + * @return Response + */ + public function generate($exportAlias, array $data) + { + $export = $this->getExport($exportAlias); + $qb = $this->em->createQueryBuilder(); + + $qb = $export->initiateQuery($qb, $this->retrieveUsedModifiers($data)); + + //handle filters + $this->handleFilters($export, $qb, $data['filters']); + + //handle aggregators + $this->handleAggregators($export, $qb, $data['aggregators']); + + $this->logger->debug('current query is '.$qb->getDQL(), array( + 'class' => self::class, 'function' => __FUNCTION__ + )); + + $results = $qb->getQuery()->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR); + + var_dump($results); + + return new Response('everything is fine !'); + } + + /** + * parse the data to retrieve the used filters and aggregators + * + * @param mixed $data + * @return string[] + */ + private function retrieveUsedModifiers($data) + { + $usedTypes = array(); + + // used filters + $this->retrieveUsedFilters($data, $usedTypes); + // used aggregators + $this->retrieveUsedAggregators($data, $usedTypes); + + $this->logger->debug('Required types are '.implode(', ', $usedTypes), + array('class' => self::class, 'function' => __FUNCTION__)); + + return $usedTypes; + } + + private function retrieveUsedFilters($data, &$usedTypes) + { + foreach($data['filters'] as $alias => $filterData) { + if ($filterData['enabled'] == true){ + $filter = $this->getFilter($alias); + if (!in_array($filter->applyOn(), $usedTypes)) { + array_push($usedTypes, $filter->applyOn()); + } + } + } + } + + private function retrieveUsedAggregators($data, &$usedTypes) + { + foreach($data['aggregators'] as $alias => $aggregatorData) { + if ($aggregatorData['order']> 0){ + $aggregator = $this->getAggregator($alias); + if (!in_array($aggregator->applyOn(), $usedTypes)) { + array_push($usedTypes, $aggregator->applyOn()); + } + } + } + } + + /** + * + * @param ExportInterface $export + * @param QueryBuilder $qb + * @param mixed $data the data under the initial 'filters' data + */ + private function handleFilters(ExportInterface $export, QueryBuilder $qb, $data) + { + $filters = $this->getFiltersApplyingOn($export->supportsModifiers()); + + foreach($filters as $alias => $filter) { + $this->logger->debug('handling filter '.$alias, array( + 'class' => self::class, 'function' => __FUNCTION__ + )); + + $formData = $data[$alias]; + + if ($formData['enabled'] == true) { + $this->logger->debug('alter query by filter '.$alias, array( + 'class' => self::class, 'function' => __FUNCTION__ + )); + $filter->alterQuery($qb, $formData['form']); + } else { + $this->logger->debug('skipping filter '.$alias.' because not enabled', + array('class' => self::class, 'function' => __FUNCTION__)); + } + } + } + + private function handleAggregators(ExportInterface $export, QueryBuilder $qb, $data) + { + $aggregators = $this->getAggregatorsApplyingOn($export->supportsModifiers()); + + foreach ($aggregators as $alias => $aggregator) { + $formData = $data[$alias]; + if ($formData['order'] >= 0) { + $aggregator->alterQuery($qb, $formData['form']); + } + } + } + +} diff --git a/Export/FilterInterface.php b/Export/FilterInterface.php new file mode 100644 index 000000000..da43a6845 --- /dev/null +++ b/Export/FilterInterface.php @@ -0,0 +1,39 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\MainBundle\Export; + +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; + +/** + * + * + * @author Julien Fastré + */ +interface FilterInterface +{ + public function applyOn(); + + public function buildForm(FormBuilderInterface $builder); + + public function alterQuery(QueryBuilder $qb, $data); + + public function getTitle(); +} diff --git a/Export/FormatterInterface.php b/Export/FormatterInterface.php new file mode 100644 index 000000000..e980af624 --- /dev/null +++ b/Export/FormatterInterface.php @@ -0,0 +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\Export; + +/** + * + * @author Julien Fastré + */ +interface FormatterInterface +{ + //put your code here +} diff --git a/Form/Type/Export/AggregatorType.php b/Form/Type/Export/AggregatorType.php new file mode 100644 index 000000000..7c96e612c --- /dev/null +++ b/Form/Type/Export/AggregatorType.php @@ -0,0 +1,82 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public 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\Export; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Form\FormBuilderInterface; +use Chill\MainBundle\Export\ExportManager; +use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; + +/** + * + * + * @author Julien Fastré + */ +class AggregatorType extends AbstractType +{ + /** + * + * @var \ExportManager + */ + private $exportManager; + + public function __construct(ExportManager $exportManager) + { + $this->exportManager = $exportManager; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $aggregator = $this->exportManager->getAggregator($options['aggregator_alias']); + + $builder + ->add('order', IntegerType::class, array( + 'constraints' => array( + new Assert\GreaterThanOrEqual(array( + 'value' => -1 + )), + new Assert\LessThanOrEqual(array( + 'value' => $options['aggregators_length'] + )) + ) + )); + + $filterFormBuilder = $builder->create('form', 'form', array( + 'compound' => true, 'required' => false)); + $aggregator->buildForm($filterFormBuilder); + + $builder->add($filterFormBuilder); + + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('aggregator_alias') + ->setRequired('aggregators_length') + ->setAllowedTypes(array( + 'aggregators_length' => 'int' + )) + ->setDefault('compound', true) + ; + } + +} diff --git a/Form/Type/Export/ExportType.php b/Form/Type/Export/ExportType.php new file mode 100644 index 000000000..6c6b06584 --- /dev/null +++ b/Form/Type/Export/ExportType.php @@ -0,0 +1,102 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +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; + +/** + * + * + * @author Julien Fastré + */ +class ExportType extends AbstractType +{ + /** + * + * @var ExportManager + */ + protected $exportManager; + + public function __construct(ExportManager $exportManager) + { + $this->exportManager = $exportManager; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $export = $this->exportManager->getExport($options['export_alias']); + + /* this part has not been experimented + if ($export->hasForm()) { + $exportBuilder = $builder->create('export', null, array('compound' => true)); + $export->buildForm($exportBuilder); + $builder->add($exportBuilder); + } */ + + //add filters + $filters = $this->exportManager->getFiltersApplyingOn($export->supportsModifiers()); + $filterBuilder = $builder->create('filters', 'form', array('compound' => true)); + + foreach($filters as $alias => $filter) { + $filterBuilder->add($alias, new FilterType($this->exportManager), array( + 'filter_alias' => $alias, + 'label' => $filter->getTitle() + )); + } + + $builder->add($filterBuilder); + + //add aggregators + $aggregators = iterator_to_array($this->exportManager + ->getAggregatorsApplyingOn($export->supportsModifiers())); + $aggregatorBuilder = $builder->create('aggregators', 'form', + array('compound' => true)); + $nb = count($aggregators); + + foreach($aggregators as $alias => $aggregator) { + $aggregatorBuilder->add($alias, new AggregatorType($this->exportManager), array( + 'aggregator_alias' => $alias, + 'aggregators_length' => $nb, + 'label' => $aggregator->getTitle() + )); + } + + $builder->add($aggregatorBuilder); + + } + + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired(array('export_alias')) + ->setAllowedTypes('export_alias', array('string')) + ->setDefault('compound', true) + ; + + } +} diff --git a/Form/Type/Export/FilterType.php b/Form/Type/Export/FilterType.php new file mode 100644 index 000000000..a497f93d6 --- /dev/null +++ b/Form/Type/Export/FilterType.php @@ -0,0 +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 . + */ + +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; + +/** + * + * + * @author Julien Fastré + */ +class FilterType extends AbstractType +{ + /** + * + * @var \ExportManager + */ + private $exportManager; + + public function __construct(ExportManager $exportManager) + { + $this->exportManager = $exportManager; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $filter = $this->exportManager->getFilter($options['filter_alias']); + + $builder + ->add('enabled', 'choice', array( + 'choices' => array( + 'enabled' => true, + 'disabled' => false + ), + 'multiple' => false, + 'expanded' => true, + 'choices_as_values' => true + )); + + $filterFormBuilder = $builder->create('form', null, array( + 'compound' => true, 'required' => false)); + $filter->buildForm($filterFormBuilder); + + $builder->add($filterFormBuilder); + + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired('filter_alias') + ->setDefault('compound', true) + ; + } + +} diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index 3246ea9d3..6656b70f9 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -13,6 +13,10 @@ chill_main_admin_scope: chill_main_admin: resource: "@ChillMainBundle/Resources/config/routing/center.yml" prefix: "{_locale}/admin/center" + +chill_main_exports: + resource: "@ChillMainBundle/Resources/config/routing/exports.yml" + prefix: "{_locale}/exports" root: path: / @@ -35,15 +39,6 @@ chill_main_homepage: label: Homepage icons: [home] -chill_main_export_index: - path: /{_locale}/export - defaults: { _controller: ChillMainBundle:Export:index } - options: - menus: - section: - order: 20 - label: Export Menu - icons: [upload] chill_main_admin_central: path: /{_locale}/admin diff --git a/Resources/config/routing/exports.yml b/Resources/config/routing/exports.yml new file mode 100644 index 000000000..7c7eb7db0 --- /dev/null +++ b/Resources/config/routing/exports.yml @@ -0,0 +1,18 @@ +chill_main_export_index: + path: / + defaults: { _controller: ChillMainBundle:Export:index } + options: + menus: + section: + order: 20 + label: Export Menu + icons: [upload] + +chill_main_export_new: + path: /new/{alias} + defaults: { _controller: ChillMainBundle:Export:new } + +chill_main_export_generate: + path: /generate/{alias} + defaults: { _controller: ChillMainBundle:Export:generate } + methods: [GET] diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 34184ebf9..2d8b5b0e3 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -148,3 +148,16 @@ services: - "@chill.main.helper.translatable_string" tags: - { name: form.type } + + chill.main.export_manager: + class: Chill\MainBundle\Export\ExportManager + arguments: + - "@logger" + - "@doctrine.orm.entity_manager" + + chill.main.form.type.export: + class: Chill\MainBundle\Form\Type\Export\ExportType + arguments: + - "@chill.main.export_manager" + tags: + - { name: form.type } diff --git a/Resources/views/Export/layout.html.twig b/Resources/views/Export/layout.html.twig index d8b1d41fb..8a125d4f7 100644 --- a/Resources/views/Export/layout.html.twig +++ b/Resources/views/Export/layout.html.twig @@ -18,6 +18,8 @@ {% extends "ChillMainBundle::layoutWithVerticalMenu.html.twig" %} +{% block title %}{{ 'Exports list'|trans }}{% endblock %} + {% block vertical_menu_content %} {{ chill_menu('export', { 'layout': 'ChillMainBundle::Menu/export.html.twig', @@ -25,7 +27,20 @@ {% endblock %} {% block layout_wvm_content %} - {% block export_content %} - Welcome to the Export section ! + {% block export_content %} +

{{ 'Exports list'|trans }}

+ + {% for export_alias,export in exports %} +
+

{{ export.title|trans }}

+

{{ export.description|trans }}

+ +

+ + {{ 'Create an export'|trans }} + +

+
+ {% endfor %} {% endblock %} {% endblock %} \ No newline at end of file diff --git a/Resources/views/Export/new.html.twig b/Resources/views/Export/new.html.twig new file mode 100644 index 000000000..637b16694 --- /dev/null +++ b/Resources/views/Export/new.html.twig @@ -0,0 +1,51 @@ +{# + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + / + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} + +{% extends "ChillMainBundle::layoutWithVerticalMenu.html.twig" %} + +{% block title %}{{ export.title|trans }}{% endblock %} + +{% block layout_wvm_content %} + +

{{ export.title|trans }}

+ +

{{ export.description|trans }}

+ + {{ form_start(form) }} +
+

{{ 'Filters'| trans }}

+ {% for filter_form in form.children.filters %} + {{ form_label(filter_form) }} + {{ form_row(filter_form.enabled) }} + {{ form_widget(filter_form.form) }} + {% endfor %} +
+ +
+

{{ 'Aggregators'| trans }}

+ {% for aggregator_form in form.children.aggregators %} + {{ form_label(aggregator_form) }} + {{ form_row(aggregator_form.order) }} + {{ form_widget(aggregator_form.form) }} + {% endfor %} +
+ +

{{ form_widget(form.submit, { 'attr' : { 'class' : 'sc-button btn-action' } } ) }}

+ {{ form_end(form) }} + +{% endblock layout_wvm_content %}