Skip to content
This repository was archived by the owner on Feb 4, 2023. It is now read-only.

Commit 783d0f5

Browse files
committed
Add symfony4 maker bundle support
1 parent 4bb03c8 commit 783d0f5

File tree

5 files changed

+358
-0
lines changed

5 files changed

+358
-0
lines changed

DependencyInjection/SgDatatablesExtension.php

+6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ public function load(array $configs, ContainerBuilder $container)
3636
$loader->load('services.yml');
3737

3838
$container->setParameter('sg_datatables.datatable.query', $config['datatable']['query']);
39+
40+
$bundles = $container->getParameter('kernel.bundles');
41+
42+
if(isset($bundles['MakerBundle'])) {
43+
$loader->load('maker.yml');
44+
}
3945
}
4046

4147
/**

Maker/MakeDatatable.php

+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
3+
namespace Sg\DatatablesBundle\Maker;
4+
5+
6+
use Symfony\Bundle\MakerBundle\InputAwareMakerInterface;
7+
use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
8+
use Symfony\Bundle\MakerBundle\ConsoleStyle;
9+
use Symfony\Bundle\MakerBundle\MakerInterface;
10+
use Symfony\Component\Console\Command\Command;
11+
use Symfony\Component\Console\Input\InputInterface;
12+
use Symfony\Bundle\MakerBundle\InputConfiguration;
13+
use Symfony\Bundle\MakerBundle\DependencyBuilder;
14+
Use Symfony\Bundle\MakerBundle\Generator;
15+
use Symfony\Bundle\MakerBundle\Doctrine\DoctrineHelper;
16+
use Symfony\Component\Console\Input\InputArgument;
17+
use Symfony\Bundle\MakerBundle\Str;
18+
use Symfony\Bundle\MakerBundle\Validator;
19+
use Symfony\Bundle\TwigBundle;
20+
use Doctrine\Bundle\DoctrineBundle;
21+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
22+
use Symfony\Component\Console\Question\Question;
23+
use Doctrine\ORM\Mapping\ClassMetadataInfo;
24+
25+
26+
class MakeDatatable extends AbstractMaker
27+
{
28+
private $doctrineHelper;
29+
private $baseSleleton;
30+
private $columnTypes = [ 'ActionColumn' => 'ActionColumn'];
31+
32+
public function __construct(DoctrineHelper $doctrineHelper)
33+
{
34+
$this->doctrineHelper = $doctrineHelper;
35+
$this->baseSleleton = realpath(__DIR__.'/../Resources/views/skeleton');
36+
}
37+
38+
39+
public static function getCommandName(): string
40+
{
41+
return 'make:datatable';
42+
}
43+
44+
/**
45+
* {@inheritdoc}
46+
*/
47+
public function configureCommand(Command $command, InputConfiguration $inputConfig)
48+
{
49+
$command
50+
->setDescription('Creates Datable for Doctrine entity class')
51+
->addArgument('entity-class', InputArgument::OPTIONAL, sprintf('The class name of the entity to create CRUD (e.g. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())))
52+
->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeDatatable.txt'))
53+
;
54+
$inputConfig->setArgumentAsNonInteractive('entity-class');
55+
}
56+
57+
public function interact(InputInterface $input, ConsoleStyle $io, Command $command)
58+
{
59+
if (null === $input->getArgument('entity-class')) {
60+
$argument = $command->getDefinition()->getArgument('entity-class');
61+
$entities = $this->doctrineHelper->getEntitiesForAutocomplete();
62+
$question = new Question($argument->getDescription());
63+
$question->setAutocompleterValues($entities);
64+
$value = $io->askQuestion($question);
65+
$input->setArgument('entity-class', $value);
66+
}
67+
}
68+
69+
/**
70+
* {@inheritdoc}
71+
*/
72+
public function configureDependencies(DependencyBuilder $dependencies)
73+
{
74+
}
75+
76+
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
77+
{
78+
$entityClassDetails = $generator->createClassNameDetails(
79+
Validator::entityExists($input->getArgument('entity-class'), $this->doctrineHelper->getEntitiesForAutocomplete()),
80+
'Entity\\'
81+
);
82+
83+
84+
$entityDoctrineDetails = $this->doctrineHelper->createDoctrineDetails($entityClassDetails->getFullName());
85+
86+
$datatableClassDetails = $generator->createClassNameDetails(
87+
$entityClassDetails->getRelativeNameWithoutSuffix(),
88+
'Datatables\\',
89+
'Datatable'
90+
);
91+
92+
$className = $datatableClassDetails->getShortName();
93+
$entityClassLowerCase = strtolower($className);
94+
95+
$metadata = $this->getEntityMetadata($entityClassDetails->getFullName());
96+
$fields = $this->getFieldsFromMetadata($metadata);
97+
98+
sort($this->columnTypes);
99+
$generator->generateClass(
100+
$datatableClassDetails->getFullName(),
101+
$this->baseSleleton . '/Datatable.tpl.php',
102+
[
103+
'bounded_full_class_name' => $entityClassDetails->getFullName(),
104+
'bounded_class_name' => $entityClassDetails->getShortName(),
105+
'fields' => $fields,
106+
'class_name' => $className,
107+
'datatable_name' => $entityClassLowerCase.'_datatable',
108+
'route_pref' => $entityClassLowerCase,
109+
'column_types' => $this->columnTypes,
110+
'id' => $this->getIdentifierFromMetadata($metadata),
111+
]
112+
);
113+
114+
$generator->writeChanges();
115+
116+
}
117+
118+
//-------------------------------------------------
119+
// Helper
120+
//-------------------------------------------------
121+
122+
/**
123+
* Parse fields.
124+
*
125+
* @param string $input
126+
*
127+
* @return array
128+
*/
129+
private static function parseFields($input)
130+
{
131+
$fields = array();
132+
133+
foreach (explode(' ', $input) as $value) {
134+
$elements = explode(':', $value);
135+
136+
$row = array();
137+
$row['property'] = $elements[0];
138+
$row['column_type'] = 'Column::class';
139+
$row['data'] = null;
140+
$row['title'] = ucwords(str_replace('.', ' ', $elements[0]));
141+
142+
if (isset($elements[1])) {
143+
switch ($elements[1]) {
144+
case 'datetime':
145+
$row['column_type'] = 'DateTimeColumn::class';
146+
break;
147+
case 'boolean':
148+
$row['column_type'] = 'BooleanColumn::class';
149+
break;
150+
}
151+
}
152+
153+
$fields[] = $row;
154+
}
155+
156+
return $fields;
157+
}
158+
159+
private function getEntityMetadata($class)
160+
{
161+
return $this->doctrineHelper->getMetadata($class, true);
162+
}
163+
164+
/**
165+
* Get Id from metadata.
166+
*
167+
* @param array $metadata
168+
*
169+
* @return mixed
170+
* @throws Exception
171+
*/
172+
private function getIdentifierFromMetadata(ClassMetadataInfo $metadata)
173+
{
174+
if (count($metadata->identifier) > 1) {
175+
throw new Exception('CreateDatatableCommand::getIdentifierFromMetadata(): The Datatable generator does not support entities with multiple primary keys.');
176+
}
177+
178+
return $metadata->identifier;
179+
}
180+
181+
/**
182+
* Returns an array of fields. Fields can be both column fields and
183+
* association fields.
184+
*
185+
* @param ClassMetadataInfo $metadata
186+
*
187+
* @return array $fields
188+
*/
189+
private function getFieldsFromMetadata(ClassMetadataInfo $metadata)
190+
{
191+
$fields = array();
192+
193+
foreach ($metadata->fieldMappings as $field) {
194+
$row = array();
195+
$row['property'] = $field['fieldName'];
196+
197+
switch ($field['type']) {
198+
case 'datetime':
199+
$row['column_type'] = 'DateTimeColumn::class';
200+
break;
201+
case 'boolean':
202+
$row['column_type'] = 'BooleanColumn::class';
203+
break;
204+
default:
205+
$row['column_type'] = 'Column::class';
206+
}
207+
208+
$row['title'] = ucwords($field['fieldName']);
209+
$row['data'] = null;
210+
$fields[] = $row;
211+
if(!isset($this->columnTypes[$row['column_type']])) {
212+
$this->columnTypes[$row['column_type']] = substr($row['column_type'], 0, -7);
213+
}
214+
215+
}
216+
217+
foreach ($metadata->associationMappings as $relation) {
218+
$targetClass = $relation['targetEntity'];
219+
$targetMetadata = $this->getEntityMetadata($targetClass, true);
220+
221+
foreach ($targetMetadata->fieldMappings as $field) {
222+
$row = array();
223+
$row['property'] = $relation['fieldName'].'.'.$field['fieldName'];
224+
$row['column_type'] = 'Column::class';
225+
$row['title'] = ucwords(str_replace('.', ' ', $row['property']));
226+
if ($relation['type'] === ClassMetadataInfo::ONE_TO_MANY || $relation['type'] === ClassMetadataInfo::MANY_TO_MANY) {
227+
$row['data'] = $relation['fieldName'].'[, ].'.$field['fieldName'];
228+
} else {
229+
$row['data'] = null;
230+
}
231+
$fields[] = $row;
232+
}
233+
}
234+
235+
return $fields;
236+
}
237+
}

Resources/config/maker.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
services:
2+
sg_datatables.maker:
3+
class: Sg\DatatablesBundle\Maker\MakeDatatable
4+
public: true
5+
arguments:
6+
- '@maker.doctrine_helper'
7+
tags:
8+
- { name: maker.command }

Resources/help/MakeDatatable.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
The <info>%command.name%</info> command generates datatable class for selected entity.
2+
3+
<info>php %command.full_name% BlogPost</info>
4+
5+
If the argument is missing, the command will ask for the entity class name interactively.
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?= "<?php" . PHP_EOL ?>
2+
3+
namespace <?= $namespace ?>;
4+
5+
use Sg\DatatablesBundle\Datatable\AbstractDatatable;
6+
7+
<?php foreach ($column_types as $type): ?>
8+
use Sg\DatatablesBundle\Datatable\Column\<?= $type ?>;
9+
<?php endforeach; ?>
10+
11+
/**
12+
* Class <?= $class_name.PHP_EOL ?>
13+
*
14+
* @package <?= $namespace ?>\Datatables
15+
*/
16+
class <?= $class_name ?> extends AbstractDatatable
17+
{
18+
19+
/**
20+
* {@inheritdoc}
21+
*
22+
* @throws \Exception
23+
*/
24+
public function buildDatatable(array $options = array())
25+
{
26+
$this->language->set(array(
27+
'cdn_language_by_locale' => true
28+
//'language' => 'de'
29+
));
30+
31+
$this->ajax->set(array(
32+
));
33+
34+
$this->options->set(array(
35+
'individual_filtering' => true,
36+
'individual_filtering_position' => 'head',
37+
'order_cells_top' => true,
38+
));
39+
40+
$this->features->set(array(
41+
));
42+
43+
$this->columnBuilder
44+
<?php foreach ($fields as $field): ?>
45+
->add('<?= $field['property'] ?>', <?= $field['column_type'] ?>, array(
46+
'title' => '<?= $field['title'] ?>',
47+
<?php if (isset($field['data']) && $field['data']!== null ): ?>
48+
'data' => '<?= $field['data'] ?>'
49+
<?php endif ?>
50+
))
51+
<?php endforeach; ?>
52+
->add(null, ActionColumn::class, array(
53+
'title' => $this->translator->trans('sg.datatables.actions.title'),
54+
'actions' => array(
55+
array(
56+
'route' => '<?= $route_pref ?>_show',
57+
'route_parameters' => array(
58+
'id' => 'id'
59+
),
60+
'label' => $this->translator->trans('sg.datatables.actions.show'),
61+
'icon' => 'glyphicon glyphicon-eye-open',
62+
'attributes' => array(
63+
'rel' => 'tooltip',
64+
'title' => $this->translator->trans('sg.datatables.actions.show'),
65+
'class' => 'btn btn-primary btn-xs',
66+
'role' => 'button'
67+
),
68+
),
69+
array(
70+
'route' => '<?= $route_pref ?>_edit',
71+
'route_parameters' => array(
72+
'id' => 'id'
73+
),
74+
'label' => $this->translator->trans('sg.datatables.actions.edit'),
75+
'icon' => 'glyphicon glyphicon-edit',
76+
'attributes' => array(
77+
'rel' => 'tooltip',
78+
'title' => $this->translator->trans('sg.datatables.actions.edit'),
79+
'class' => 'btn btn-primary btn-xs',
80+
'role' => 'button'
81+
),
82+
)
83+
)
84+
));
85+
}
86+
87+
/**
88+
* {@inheritdoc}
89+
*/
90+
public function getEntity()
91+
{
92+
return '<?= $bounded_full_class_name ?>';
93+
}
94+
95+
/**
96+
* {@inheritdoc}
97+
*/
98+
public function getName()
99+
{
100+
return '<?= $datatable_name ?>';
101+
}
102+
}

0 commit comments

Comments
 (0)