From ad085a00e1e96aa1962bf35f3bfa164c16a48c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=9F=D0=B5=D1=88?= =?UTF-8?q?=D0=B5=D1=85=D0=BE=D0=BD=D0=BE=D0=B2?= Date: Mon, 25 May 2020 12:30:17 +0300 Subject: [PATCH] fix #814 --- DependencyInjection/SgDatatablesExtension.php | 6 + Maker/MakeDatatable.php | 237 ++++++++++++++++++ Resources/config/maker.yml | 8 + Resources/doc/index013.md | 27 -- Resources/views/skeleton/datatable.tpl.php | 102 ++++++++ 5 files changed, 353 insertions(+), 27 deletions(-) create mode 100644 Maker/MakeDatatable.php create mode 100644 Resources/config/maker.yml delete mode 100644 Resources/doc/index013.md create mode 100644 Resources/views/skeleton/datatable.tpl.php diff --git a/DependencyInjection/SgDatatablesExtension.php b/DependencyInjection/SgDatatablesExtension.php index de9e785b..80e108cf 100644 --- a/DependencyInjection/SgDatatablesExtension.php +++ b/DependencyInjection/SgDatatablesExtension.php @@ -31,6 +31,12 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('services.yml'); $container->setParameter('sg_datatables.datatable.query', $config['datatable']['query']); + + $bundles = $container->getParameter('kernel.bundles'); + + if(isset($bundles['MakerBundle'])) { + $loader->load('maker.yml'); + } } /** diff --git a/Maker/MakeDatatable.php b/Maker/MakeDatatable.php new file mode 100644 index 00000000..762c671e --- /dev/null +++ b/Maker/MakeDatatable.php @@ -0,0 +1,237 @@ + 'ActionColumn']; + + public function __construct(DoctrineHelper $doctrineHelper) + { + $this->doctrineHelper = $doctrineHelper; + $this->baseSleleton = realpath(__DIR__.'/../Resources/views/skeleton'); + } + + + public static function getCommandName(): string + { + return 'make:datatable'; + } + + /** + * {@inheritdoc} + */ + public function configureCommand(Command $command, InputConfiguration $inputConfig) + { + $command + ->setDescription('Creates Datable for Doctrine entity class') + ->addArgument('entity-class', InputArgument::OPTIONAL, sprintf('The class name of the entity to create CRUD (e.g. %s)', Str::asClassName(Str::getRandomTerm()))) + ->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeDatatable.txt')) + ; + $inputConfig->setArgumentAsNonInteractive('entity-class'); + } + + public function interact(InputInterface $input, ConsoleStyle $io, Command $command) + { + if (null === $input->getArgument('entity-class')) { + $argument = $command->getDefinition()->getArgument('entity-class'); + $entities = $this->doctrineHelper->getEntitiesForAutocomplete(); + $question = new Question($argument->getDescription()); + $question->setAutocompleterValues($entities); + $value = $io->askQuestion($question); + $input->setArgument('entity-class', $value); + } + } + + /** + * {@inheritdoc} + */ + public function configureDependencies(DependencyBuilder $dependencies) + { + } + + public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator) + { + $entityClassDetails = $generator->createClassNameDetails( + Validator::entityExists($input->getArgument('entity-class'), $this->doctrineHelper->getEntitiesForAutocomplete()), + 'Entity\\' + ); + + + $entityDoctrineDetails = $this->doctrineHelper->createDoctrineDetails($entityClassDetails->getFullName()); + + $datatableClassDetails = $generator->createClassNameDetails( + $entityClassDetails->getRelativeNameWithoutSuffix(), + 'Datatables\\', + 'Datatable' + ); + + $className = $datatableClassDetails->getShortName(); + $entityClassLowerCase = strtolower($className); + + $metadata = $this->getEntityMetadata($entityClassDetails->getFullName()); + $fields = $this->getFieldsFromMetadata($metadata); + + sort($this->columnTypes); + $generator->generateClass( + $datatableClassDetails->getFullName(), + $this->baseSleleton . '/Datatable.tpl.php', + [ + 'bounded_full_class_name' => $entityClassDetails->getFullName(), + 'bounded_class_name' => $entityClassDetails->getShortName(), + 'fields' => $fields, + 'class_name' => $className, + 'datatable_name' => $entityClassLowerCase.'_datatable', + 'route_pref' => $entityClassLowerCase, + 'column_types' => $this->columnTypes, + 'id' => $this->getIdentifierFromMetadata($metadata), + ] + ); + + $generator->writeChanges(); + + } + + //------------------------------------------------- + // Helper + //------------------------------------------------- + + /** + * Parse fields. + * + * @param string $input + * + * @return array + */ + private static function parseFields($input) + { + $fields = array(); + + foreach (explode(' ', $input) as $value) { + $elements = explode(':', $value); + + $row = array(); + $row['property'] = $elements[0]; + $row['column_type'] = 'Column::class'; + $row['data'] = null; + $row['title'] = ucwords(str_replace('.', ' ', $elements[0])); + + if (isset($elements[1])) { + switch ($elements[1]) { + case 'datetime': + $row['column_type'] = 'DateTimeColumn::class'; + break; + case 'boolean': + $row['column_type'] = 'BooleanColumn::class'; + break; + } + } + + $fields[] = $row; + } + + return $fields; + } + + private function getEntityMetadata($class) + { + return $this->doctrineHelper->getMetadata($class, true); + } + + /** + * Get Id from metadata. + * + * @param array $metadata + * + * @return mixed + * @throws Exception + */ + private function getIdentifierFromMetadata(ClassMetadataInfo $metadata) + { + if (count($metadata->identifier) > 1) { + throw new Exception('CreateDatatableCommand::getIdentifierFromMetadata(): The Datatable generator does not support entities with multiple primary keys.'); + } + + return $metadata->identifier; + } + + /** + * Returns an array of fields. Fields can be both column fields and + * association fields. + * + * @param ClassMetadataInfo $metadata + * + * @return array $fields + */ + private function getFieldsFromMetadata(ClassMetadataInfo $metadata) + { + $fields = array(); + + foreach ($metadata->fieldMappings as $field) { + $row = array(); + $row['property'] = $field['fieldName']; + + switch ($field['type']) { + case 'datetime': + $row['column_type'] = 'DateTimeColumn::class'; + break; + case 'boolean': + $row['column_type'] = 'BooleanColumn::class'; + break; + default: + $row['column_type'] = 'Column::class'; + } + + $row['title'] = ucwords($field['fieldName']); + $row['data'] = null; + $fields[] = $row; + if(!isset($this->columnTypes[$row['column_type']])) { + $this->columnTypes[$row['column_type']] = substr($row['column_type'], 0, -7); + } + + } + + foreach ($metadata->associationMappings as $relation) { + $targetClass = $relation['targetEntity']; + $targetMetadata = $this->getEntityMetadata($targetClass, true); + + foreach ($targetMetadata->fieldMappings as $field) { + $row = array(); + $row['property'] = $relation['fieldName'].'.'.$field['fieldName']; + $row['column_type'] = 'Column::class'; + $row['title'] = ucwords(str_replace('.', ' ', $row['property'])); + if ($relation['type'] === ClassMetadataInfo::ONE_TO_MANY || $relation['type'] === ClassMetadataInfo::MANY_TO_MANY) { + $row['data'] = $relation['fieldName'].'[, ].'.$field['fieldName']; + } else { + $row['data'] = null; + } + $fields[] = $row; + } + } + + return $fields; + } +} \ No newline at end of file diff --git a/Resources/config/maker.yml b/Resources/config/maker.yml new file mode 100644 index 00000000..6b63036a --- /dev/null +++ b/Resources/config/maker.yml @@ -0,0 +1,8 @@ +services: + sg_datatables.maker: + class: Sg\DatatablesBundle\Maker\MakeDatatable + public: true + arguments: + - '@maker.doctrine_helper' + tags: + - { name: maker.command } \ No newline at end of file diff --git a/Resources/doc/index013.md b/Resources/doc/index013.md deleted file mode 100644 index b9082456..00000000 --- a/Resources/doc/index013.md +++ /dev/null @@ -1,27 +0,0 @@ -[Installation](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/installation.md) - -[Column types](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/columns.md) - -[In-place editing](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/editable.md) - -[How to use the ColumnBuilder](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/columnBuilder.md) - -[Setup Datatable Class](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/setup.md) - -[Filtering](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/filter.md) - -[To use a line formatter](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/lineFormatter.md) - -[Query callbacks](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/query.md) - -[Extensions like Buttons or Responsive](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/extensions.md) - -[Options of the generator](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/generator.md) - -[Reference configuration](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/configuration.md) - -[Integrate Bootstrap3](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/bootstrap3.md) - -[Integrate the Translatable behavior extension for Doctrine 2](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/translatable.md) - -[Integrate the LiipImagineBundle / ImageColumn, GalleryColumn and thumbnails](https://github.com/stwe/DatatablesBundle/blob/v0.13/Resources/doc/thumbs.md) diff --git a/Resources/views/skeleton/datatable.tpl.php b/Resources/views/skeleton/datatable.tpl.php new file mode 100644 index 00000000..9e5bb8a5 --- /dev/null +++ b/Resources/views/skeleton/datatable.tpl.php @@ -0,0 +1,102 @@ + + +namespace ; + +use Sg\DatatablesBundle\Datatable\AbstractDatatable; + + + use Sg\DatatablesBundle\Datatable\Column\; + + +/** +* Class +* +* @package \Datatables +*/ +class extends AbstractDatatable +{ + +/** +* {@inheritdoc} +* +* @throws \Exception +*/ +public function buildDatatable(array $options = array()) +{ +$this->language->set(array( +'cdn_language_by_locale' => true +//'language' => 'de' +)); + +$this->ajax->set(array( +)); + +$this->options->set(array( +'individual_filtering' => true, +'individual_filtering_position' => 'head', +'order_cells_top' => true, +)); + +$this->features->set(array( +)); + +$this->columnBuilder + + ->add('', , array( + 'title' => '', + + 'data' => '' + + )) + +->add(null, ActionColumn::class, array( +'title' => $this->translator->trans('sg.datatables.actions.title'), +'actions' => array( +array( +'route' => '_show', +'route_parameters' => array( +'id' => 'id' +), +'label' => $this->translator->trans('sg.datatables.actions.show'), +'icon' => 'glyphicon glyphicon-eye-open', +'attributes' => array( +'rel' => 'tooltip', +'title' => $this->translator->trans('sg.datatables.actions.show'), +'class' => 'btn btn-primary btn-xs', +'role' => 'button' +), +), +array( +'route' => '_edit', +'route_parameters' => array( +'id' => 'id' +), +'label' => $this->translator->trans('sg.datatables.actions.edit'), +'icon' => 'glyphicon glyphicon-edit', +'attributes' => array( +'rel' => 'tooltip', +'title' => $this->translator->trans('sg.datatables.actions.edit'), +'class' => 'btn btn-primary btn-xs', +'role' => 'button' +), +) +) +)); +} + +/** +* {@inheritdoc} +*/ +public function getEntity() +{ +return ''; +} + +/** +* {@inheritdoc} +*/ +public function getName() +{ +return ''; +} +} \ No newline at end of file