This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Victoire\Bundle\WidgetBundle\Command; |
||
4 | |||
5 | use Doctrine\DBAL\Types\Type; |
||
6 | use Sensio\Bundle\GeneratorBundle\Command\GenerateBundleCommand; |
||
7 | use Sensio\Bundle\GeneratorBundle\Command\Helper\QuestionHelper; |
||
8 | use Sensio\Bundle\GeneratorBundle\Command\Validators; |
||
9 | use Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator; |
||
10 | use Symfony\Component\Console\Input\InputInterface; |
||
11 | use Symfony\Component\Console\Input\InputOption; |
||
12 | use Symfony\Component\Console\Output\OutputInterface; |
||
13 | use Symfony\Component\Console\Question\ConfirmationQuestion; |
||
14 | use Symfony\Component\Console\Question\Question; |
||
15 | use Symfony\Component\DependencyInjection\Container; |
||
16 | use Symfony\Component\HttpKernel\Bundle\BundleInterface; |
||
17 | use Victoire\Bundle\WidgetBundle\Generator\WidgetGenerator; |
||
18 | |||
19 | /** |
||
20 | * Create a new Widget for VictoireCMS. |
||
21 | */ |
||
22 | class CreateWidgetCommand extends GenerateBundleCommand |
||
23 | { |
||
24 | protected $skeletonDirs; |
||
25 | |||
26 | /** |
||
27 | * {@inheritdoc} |
||
28 | */ |
||
29 | public function configure() |
||
30 | { |
||
31 | parent::configure(); |
||
32 | |||
33 | $this |
||
34 | ->setName('victoire:generate:widget') |
||
35 | ->setDefinition([ |
||
36 | new InputOption('namespace', '', InputOption::VALUE_REQUIRED, 'The namespace of the widget bundle to create'), |
||
37 | new InputOption('dir', '', InputOption::VALUE_REQUIRED, 'The directory where to create the bundle'), |
||
38 | new InputOption('bundle-name', '', InputOption::VALUE_REQUIRED, 'The optional bundle name'), |
||
39 | new InputOption('orgname', '', InputOption::VALUE_REQUIRED, 'Your organisation name'), |
||
40 | new InputOption('widget-name', '', InputOption::VALUE_REQUIRED, 'The widget name'), |
||
41 | new InputOption('format', '', InputOption::VALUE_REQUIRED, 'Use the format for configuration files (php, xml, yml, or annotation)'), |
||
42 | new InputOption('structure', '', InputOption::VALUE_NONE, 'Whether to generate the whole directory structure'), |
||
43 | new InputOption('fields', '', InputOption::VALUE_REQUIRED, 'The fields to create with the new entity'), |
||
44 | new InputOption('entity', '', InputOption::VALUE_REQUIRED, 'The entity class name to initialize (shortcut notation)'), |
||
45 | new InputOption('parent', '', InputOption::VALUE_REQUIRED, 'The widget this widget will extends'), |
||
46 | new InputOption('packagist-parent-name', '', InputOption::VALUE_REQUIRED, 'The packagist name of the widget you want to extends'), |
||
47 | new InputOption('content-resolver', '', InputOption::VALUE_NONE, 'Whether to generate a blank ContentResolver to customize widget rendering logic'), |
||
48 | new InputOption('cache', '', InputOption::VALUE_NONE, 'Use redis cache to store widgets until next modification'), |
||
49 | ]) |
||
50 | ->setDescription('Generate a new widget') |
||
51 | ->setHelp(<<<'EOT' |
||
52 | The <info>victoire:generate:widget</info> command helps you to generate new widgets. |
||
53 | |||
54 | By default, the command interacts with the developer to tweak the generation. |
||
55 | Any passed option will be used as a default value for the interaction |
||
56 | (<comment>--widget-name</comment> is the only one needed if you follow the |
||
57 | conventions): |
||
58 | |||
59 | <info>php app/console victoire:generate:widget --widget-name=myAwesomeWidget</info> |
||
60 | |||
61 | If you want to disable any user interaction, use <comment>--no-interaction</comment> but don't forget to pass all needed options: |
||
62 | |||
63 | Love you guys, you're awesome xxx |
||
64 | EOT |
||
65 | ); |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Take arguments and options defined in $this->interact() and generate a new Widget. |
||
70 | * |
||
71 | * @param InputInterface $input |
||
72 | * @param OutputInterface $output |
||
73 | * |
||
74 | * @see Command |
||
75 | * |
||
76 | * @throws \InvalidArgumentException When namespace doesn't end with Bundle |
||
77 | * @throws \RuntimeException When bundle can't be executed |
||
78 | * |
||
79 | * @return int|null |
||
80 | */ |
||
81 | protected function execute(InputInterface $input, OutputInterface $output) |
||
82 | { |
||
83 | $questionHelper = $this->getQuestionHelper(); |
||
84 | |||
85 | if ($input->isInteractive()) { |
||
86 | $question = new ConfirmationQuestion($questionHelper->getQuestion('Do you confirm generation', 'yes', '?'), true); |
||
87 | if (!$questionHelper->ask($input, $output, $question)) { |
||
88 | $output->writeln('<error>Command aborted</error>'); |
||
89 | |||
90 | return 1; |
||
91 | } |
||
92 | } |
||
93 | |||
94 | foreach (['namespace', 'dir'] as $option) { |
||
95 | if (null === $input->getOption($option)) { |
||
96 | throw new \RuntimeException(sprintf('The "%s" option must be provided.', $option)); |
||
97 | } |
||
98 | } |
||
99 | |||
100 | $namespace = Validators::validateBundleNamespace($input->getOption('namespace')); |
||
101 | |||
102 | if (!$bundle = $input->getOption('bundle-name')) { |
||
103 | $bundle = strtr($namespace, ['\\' => '']); |
||
104 | } |
||
105 | |||
106 | $orgname = $input->getOption('orgname'); |
||
107 | |||
108 | if (null === $input->getOption('orgname')) { |
||
109 | $orgname = $input->setOption('orgname', 'friendsofvictoire'); |
||
110 | } |
||
111 | |||
112 | $parent = $input->getOption('parent'); |
||
113 | |||
114 | if (null === $input->getOption('parent')) { |
||
115 | $parent = $input->setOption('parent', null); |
||
116 | } |
||
117 | |||
118 | $packagistParentName = $input->getOption('packagist-parent-name'); |
||
119 | |||
120 | if (null === $input->getOption('packagist-parent-name')) { |
||
121 | $packagistParentName = $input->setOption('packagist-parent-name', null); |
||
122 | } |
||
123 | |||
124 | $bundle = Validators::validateBundleName($bundle); |
||
125 | $dir = Validators::validateTargetDir($input->getOption('dir'), $bundle, $namespace); |
||
126 | |||
127 | if (null === $input->getOption('format')) { |
||
128 | $input->setOption('format', 'annotation'); |
||
129 | } |
||
130 | |||
131 | $format = Validators::validateFormat($input->getOption('format')); |
||
132 | $structure = $input->getOption('structure'); |
||
133 | |||
134 | $contentResolver = $input->getOption('content-resolver'); |
||
135 | $cache = $input->getOption('cache'); |
||
136 | |||
137 | $questionHelper->writeSection($output, 'Bundle generation'); |
||
138 | |||
139 | if (!$this->getContainer()->get('filesystem')->isAbsolutePath($dir)) { |
||
140 | $dir = getcwd().'/'.$dir; |
||
141 | } |
||
142 | |||
143 | $fields = $this->parseFields($input->getOption('fields')); |
||
144 | |||
145 | $parentContentResolver = $this->getContainer()->has('victoire_core.widget_'.strtolower($parent).'_content_resolver'); |
||
146 | |||
147 | $generator = $this->getGenerator(); |
||
148 | $generator->generate($namespace, $bundle, $dir, $format, $structure, $fields, $parent, $packagistParentName, $contentResolver, $parentContentResolver, $orgname, $cache); |
||
149 | |||
150 | $output->writeln('Generating the bundle code: <info>OK</info>'); |
||
151 | |||
152 | $errors = []; |
||
153 | $runner = $questionHelper->getRunner($output, $errors); |
||
154 | |||
155 | // check that the namespace is already autoloaded |
||
156 | $runner($this->checkAutoloader($output, $namespace, $bundle, $dir)); |
||
157 | |||
158 | // register the bundle in the Kernel class |
||
159 | $runner($this->updateKernel($questionHelper, $input, $output, $this->getContainer()->get('kernel'), $namespace, $bundle)); |
||
160 | |||
161 | $questionHelper->writeGeneratorSummary($output, $errors); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * get a generator for given widget and type, and attach it skeleton dirs. |
||
166 | * |
||
167 | * @return $generator |
||
0 ignored issues
–
show
|
|||
168 | */ |
||
169 | View Code Duplication | protected function getEntityGenerator() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
170 | { |
||
171 | $dirs[] = $this->getContainer()->get('file_locator')->locate('@VictoireWidgetBundle/Resources/skeleton/'); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$dirs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $dirs = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
172 | $dirs[] = $this->getContainer()->get('file_locator')->locate('@VictoireWidgetBundle/Resources/'); |
||
173 | |||
174 | $generator = $this->createEntityGenerator(); |
||
175 | |||
176 | $this->skeletonDirs = array_merge($this->getSkeletonDirs(), $dirs); |
||
177 | $generator->setSkeletonDirs($this->skeletonDirs); |
||
178 | $this->setGenerator($generator); |
||
179 | |||
180 | return $generator; |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * get a generator for given widget and type, and attach it skeleton dirs. |
||
185 | * |
||
186 | * @return $generator |
||
0 ignored issues
–
show
The doc-type
$generator could not be parsed: Unknown type name "$generator" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
187 | */ |
||
188 | View Code Duplication | protected function getGenerator(BundleInterface $bundle = null) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
189 | { |
||
190 | $dirs[] = $this->getContainer()->get('file_locator')->locate('@VictoireWidgetBundle/Resources/skeleton/'); |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$dirs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $dirs = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. ![]() |
|||
191 | $dirs[] = $this->getContainer()->get('file_locator')->locate('@VictoireWidgetBundle/Resources/'); |
||
192 | |||
193 | $generator = $this->createWidgetGenerator(); |
||
194 | |||
195 | $this->skeletonDirs = array_merge($this->getSkeletonDirs(), $dirs); |
||
196 | $generator->setSkeletonDirs($this->skeletonDirs); |
||
197 | $this->setGenerator($generator); |
||
198 | |||
199 | return $generator; |
||
200 | } |
||
201 | |||
202 | /** |
||
203 | * Collect options and arguments. |
||
204 | * |
||
205 | * @param InputInterface $input |
||
206 | * @param OutputInterface $output |
||
207 | * |
||
208 | * @return void |
||
209 | */ |
||
210 | protected function interact(InputInterface $input, OutputInterface $output) |
||
211 | { |
||
212 | $questionHelper = $this->getQuestionHelper(); |
||
213 | $questionHelper->writeSection($output, 'Welcome to the Victoire widget bundle generator'); |
||
214 | |||
215 | /////////////////////// |
||
216 | // // |
||
217 | // Create Bundle // |
||
218 | // // |
||
219 | /////////////////////// |
||
220 | |||
221 | // namespace |
||
222 | $namespace = null; |
||
223 | try { |
||
224 | $namespace = $input->getOption('namespace') ? Validators::validateBundleNamespace($input->getOption('namespace')) : null; |
||
225 | } catch (\Exception $error) { |
||
226 | $output->writeln($questionHelper->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error')); |
||
227 | } |
||
228 | |||
229 | if (null === $namespace) { |
||
230 | $output->writeln([ |
||
231 | '', |
||
232 | 'Your application code must be written in <comment>widget bundles</comment>. This command helps', |
||
233 | 'you generate them easily.', |
||
234 | '', |
||
235 | 'Each widget is hosted under a namespace (like <comment>Victoire/Widget/YourAwesomeWidgetNameBundle</comment>).', |
||
236 | '', |
||
237 | 'If you want for example a BlogWidget, the Widget Name should be Blog', |
||
238 | ]); |
||
239 | |||
240 | $question = new Question($questionHelper->getQuestion('Widget name', $input->getOption('bundle-name'))); |
||
241 | $question->setValidator(function ($answer) { |
||
242 | return self::validateWidgetName($answer, false); |
||
0 ignored issues
–
show
The call to
CreateWidgetCommand::validateWidgetName() has too many arguments starting with false .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the ![]() |
|||
243 | }); |
||
244 | |||
245 | $name = $questionHelper->ask( |
||
246 | $input, |
||
247 | $output, |
||
248 | $question |
||
249 | ); |
||
250 | |||
251 | $bundle = 'VictoireWidget'.$name.'Bundle'; |
||
252 | $input->setOption('bundle-name', $bundle); |
||
253 | $namespace = 'Victoire\\Widget\\'.$name.'Bundle'; |
||
254 | $input->setOption('namespace', $namespace); |
||
255 | } |
||
256 | |||
257 | $orgname = $input->getOption('orgname'); |
||
258 | |||
259 | if (null === $orgname) { |
||
260 | $output->writeln([ |
||
261 | '', |
||
262 | 'A composer.json file will be generated, we need to know under which organisation you will publish the widget', |
||
263 | '', |
||
264 | 'The default organisation will be friendsofvictoire', |
||
265 | ]); |
||
266 | $question = new Question($questionHelper->getQuestion('Under which organisation do you want to publish your widget ?', 'friendsofvictoire'), 'friendsofvictoire'); |
||
267 | |||
268 | $orgname = $questionHelper->ask($input, $output, $question); |
||
269 | } |
||
270 | |||
271 | $input->setOption('orgname', $orgname); |
||
272 | |||
273 | $parent = $input->getOption('parent'); |
||
274 | |||
275 | $question = new ConfirmationQuestion($questionHelper->getQuestion('Does your widget extends another widget ?', 'no', '?'), false); |
||
276 | |||
277 | if (null === $parent && $questionHelper->ask($input, $output, $question)) { |
||
278 | $output->writeln([ |
||
279 | '', |
||
280 | 'A widget can extends another to reproduce its behavior', |
||
281 | '', |
||
282 | 'If you wabt to do so, please give the name of the widget to extend', |
||
283 | '', |
||
284 | 'If you want to extends the TestWidget, the widget name should be Test', |
||
285 | ]); |
||
286 | |||
287 | $question = new Question($questionHelper->getQuestion('Parent widget name', false)); |
||
288 | $question->setValidator(function ($answer) { |
||
289 | return self::validateWidgetName($answer, false); |
||
0 ignored issues
–
show
The call to
CreateWidgetCommand::validateWidgetName() has too many arguments starting with false .
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. In this case you can add the ![]() |
|||
290 | }); |
||
291 | $parent = $questionHelper->ask($input, $output, $question); |
||
292 | |||
293 | $input->setOption('parent', $parent); |
||
294 | |||
295 | $packagistParentName = 'friendsofvictoire/'.strtolower($parent).'-widget'; |
||
296 | $question = new Question($questionHelper->getQuestion('Parent widget packagist name', $packagistParentName)); |
||
297 | |||
298 | $parent = $questionHelper->ask($input, $output, $question); |
||
0 ignored issues
–
show
$parent is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
299 | |||
300 | $input->setOption('packagist-parent-name', $packagistParentName); |
||
301 | } |
||
302 | |||
303 | $dir = dirname($this->getContainer()->getParameter('kernel.root_dir')).'/src'; |
||
304 | |||
305 | $output->writeln([ |
||
306 | '', |
||
307 | 'The bundle can be generated anywhere. The suggested default directory uses', |
||
308 | 'the standard conventions.', |
||
309 | '', |
||
310 | ]); |
||
311 | |||
312 | $question = new Question($questionHelper->getQuestion('Target directory', $dir), $dir); |
||
313 | $question->setValidator(function ($dir) use ($bundle, $namespace) { |
||
0 ignored issues
–
show
The variable
$bundle does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
314 | return Validators::validateTargetDir($dir, $bundle, $namespace); |
||
315 | }); |
||
316 | $dir = $questionHelper->ask($input, $output, $question); |
||
317 | $input->setOption('dir', $dir); |
||
318 | |||
319 | // format |
||
320 | $format = null; |
||
321 | try { |
||
322 | $format = $input->getOption('format') ? Validators::validateFormat($input->getOption('format')) : null; |
||
323 | } catch (\Exception $error) { |
||
324 | $output->writeln($questionHelper->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error')); |
||
325 | } |
||
326 | |||
327 | if (null === $format) { |
||
328 | $output->writeln([ |
||
329 | '', |
||
330 | 'Determine the format to use for the generated configuration.', |
||
331 | '', |
||
332 | ]); |
||
333 | |||
334 | $question = new Question($questionHelper->getQuestion('Configuration format (yml, xml, php, or annotation)', 'annotation'), 'annotation'); |
||
335 | $question->setValidator( |
||
336 | ['Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateFormat'] |
||
337 | ); |
||
338 | $format = $questionHelper->ask($input, $output, $question); |
||
339 | $input->setOption('format', $format); |
||
340 | } |
||
341 | |||
342 | $input->setOption('structure', false); |
||
343 | |||
344 | $contentResolver = $input->getOption('content-resolver'); |
||
345 | |||
346 | $question = new ConfirmationQuestion($questionHelper->getQuestion('Do you want to customize widget rendering logic ?', 'no', '?'), false); |
||
347 | if (!$contentResolver && $questionHelper->ask($input, $output, $question)) { |
||
348 | $contentResolver = true; |
||
349 | } |
||
350 | $input->setOption('content-resolver', $contentResolver); |
||
351 | |||
352 | /////////////////////// |
||
353 | // // |
||
354 | // Create Entity // |
||
355 | // // |
||
356 | /////////////////////// |
||
357 | |||
358 | $input->setOption('fields', $this->addFields($input, $output, $questionHelper)); |
||
0 ignored issues
–
show
$this->addFields($input,...utput, $questionHelper) is of type array , but the function expects a string|boolean .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
359 | $entity = 'Widget'.$name; |
||
0 ignored issues
–
show
The variable
$name does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
360 | $input->setOption('entity', $bundle.':'.$entity); |
||
361 | |||
362 | $cache = $input->getOption('cache'); |
||
363 | $question = new ConfirmationQuestion($questionHelper->getQuestion('Do you want use cache for this widget ?', 'no', '?'), false); |
||
364 | if (null !== $cache) { |
||
365 | $cache = $questionHelper->ask($input, $output, $question); |
||
366 | } |
||
367 | $input->setOption('cache', $cache); |
||
368 | |||
369 | // summary |
||
370 | $output->writeln([ |
||
371 | '', |
||
372 | $this->getHelper('formatter')->formatBlock('Summary before generation', 'bg=blue;fg=white', true), |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Symfony\Component\Console\Helper\HelperInterface as the method formatBlock() does only exist in the following implementations of said interface: Symfony\Component\Console\Helper\FormatterHelper .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
373 | '', |
||
374 | sprintf("You are going to generate a \"<info>%s\\%s</info>\" widget bundle\nin \"<info>%s</info>\" using the \"<info>%s</info>\" format.", $namespace, $bundle, $dir, $format), |
||
375 | '', |
||
376 | ]); |
||
377 | } |
||
378 | |||
379 | /** |
||
380 | * Check that provided widget name is correct. |
||
381 | * |
||
382 | * @param string $widget |
||
383 | * |
||
384 | * @return string $widget |
||
385 | */ |
||
386 | public static function validateWidgetName($widget) |
||
0 ignored issues
–
show
|
|||
387 | { |
||
388 | if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $widget)) { |
||
389 | throw new \InvalidArgumentException('The widget name contains invalid characters.'); |
||
390 | } |
||
391 | |||
392 | if (!preg_match('/^([A-Z][a-z]+)+$/', $widget)) { |
||
393 | throw new \InvalidArgumentException('The widget name must be PascalCased.'); |
||
394 | } |
||
395 | |||
396 | return $widget; |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * Instanciate a new WidgetGenerator. |
||
401 | * |
||
402 | * @return $generator |
||
0 ignored issues
–
show
The doc-type
$generator could not be parsed: Unknown type name "$generator" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
403 | */ |
||
404 | protected function createWidgetGenerator() |
||
405 | { |
||
406 | $generator = new WidgetGenerator(); |
||
407 | $generator->setTemplating($this->getContainer()->get('twig')); |
||
408 | |||
409 | return $generator; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * Instanciate a new Entity generator. |
||
414 | * |
||
415 | * @return $generator |
||
0 ignored issues
–
show
The doc-type
$generator could not be parsed: Unknown type name "$generator" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
416 | */ |
||
417 | protected function createEntityGenerator() |
||
418 | { |
||
419 | return new DoctrineEntityGenerator($this->getContainer()->get('filesystem'), $this->getContainer()->get('doctrine')); |
||
420 | } |
||
421 | |||
422 | /** |
||
423 | * transform console's output string fields into an array of fields. |
||
424 | * |
||
425 | * @param string $input |
||
426 | * |
||
427 | * @return array $fields |
||
428 | */ |
||
429 | private function parseFields($input) |
||
430 | { |
||
431 | if (is_array($input)) { |
||
432 | return $input; |
||
433 | } |
||
434 | |||
435 | $fields = []; |
||
436 | foreach (explode(' ', $input) as $value) { |
||
437 | $elements = explode(':', $value); |
||
438 | $name = $elements[0]; |
||
439 | if (strlen($name)) { |
||
440 | $type = isset($elements[1]) ? $elements[1] : 'string'; |
||
441 | preg_match_all('/(.*)\((.*)\)/', $type, $matches); |
||
442 | $type = isset($matches[1][0]) ? $matches[1][0] : $type; |
||
443 | $length = isset($matches[2][0]) ? $matches[2][0] : null; |
||
444 | |||
445 | $fields[$name] = ['fieldName' => $name, 'type' => $type, 'length' => $length]; |
||
446 | } |
||
447 | } |
||
448 | |||
449 | return $fields; |
||
450 | } |
||
451 | |||
452 | /** |
||
453 | * Interactively ask user to add field to his new Entity. |
||
454 | * |
||
455 | * @param InputInterface $input |
||
456 | * @param OutputInterface $output |
||
457 | * @param QuestionHelper $questionHelper |
||
458 | * |
||
459 | * @return $fields |
||
0 ignored issues
–
show
The doc-type
$fields could not be parsed: Unknown type name "$fields" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
460 | */ |
||
461 | private function addFields(InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper) |
||
462 | { |
||
463 | $fields = $this->parseFields($input->getOption('fields')); |
||
464 | $output->writeln([ |
||
465 | '', |
||
466 | 'Instead of starting with a blank entity, you can add some fields now.', |
||
467 | 'Note that the primary key will be added automatically (named <comment>id</comment>).', |
||
468 | '', |
||
469 | ]); |
||
470 | $output->write('<info>Available types:</info> '); |
||
471 | |||
472 | $types = array_keys(Type::getTypesMap()); |
||
473 | $count = 20; |
||
474 | foreach ($types as $i => $type) { |
||
475 | if ($count > 50) { |
||
476 | $count = 0; |
||
477 | $output->writeln(''); |
||
478 | } |
||
479 | $count += strlen($type); |
||
480 | $output->write(sprintf('<comment>%s</comment>', $type)); |
||
481 | if (count($types) != $i + 1) { |
||
482 | $output->write(', '); |
||
483 | } else { |
||
484 | $output->write('.'); |
||
485 | } |
||
486 | } |
||
487 | $output->writeln(''); |
||
488 | |||
489 | $fieldValidator = function ($type) use ($types) { |
||
490 | if (!in_array($type, $types)) { |
||
491 | throw new \InvalidArgumentException(sprintf('Invalid type "%s".', $type)); |
||
492 | } |
||
493 | |||
494 | return $type; |
||
495 | }; |
||
496 | |||
497 | $lengthValidator = function ($length) { |
||
498 | if (!$length) { |
||
499 | return $length; |
||
500 | } |
||
501 | |||
502 | $result = filter_var($length, FILTER_VALIDATE_INT, [ |
||
503 | 'options' => ['min_range' => 1], |
||
504 | ]); |
||
505 | |||
506 | if (false === $result) { |
||
507 | throw new \InvalidArgumentException(sprintf('Invalid length "%s".', $length)); |
||
508 | } |
||
509 | |||
510 | return $length; |
||
511 | }; |
||
512 | |||
513 | while (true) { |
||
514 | $output->writeln(''); |
||
515 | $generator = $this->getEntityGenerator(); |
||
516 | |||
517 | $question = new Question($questionHelper->getQuestion('New field name (press <return> to stop adding fields)', null)); |
||
518 | $question->setValidator( |
||
519 | function ($name) use ($fields, $generator) { |
||
520 | if (isset($fields[$name]) || 'id' == $name) { |
||
521 | throw new \InvalidArgumentException(sprintf('Field "%s" is already defined.', $name)); |
||
522 | } |
||
523 | |||
524 | // check reserved words by database |
||
525 | if ($generator->isReservedKeyword($name)) { |
||
526 | throw new \InvalidArgumentException(sprintf('Name "%s" is a reserved word.', $name)); |
||
527 | } |
||
528 | // check reserved words by victoire |
||
529 | if ($this->isReservedKeyword($name)) { |
||
530 | throw new \InvalidArgumentException(sprintf('Name "%s" is a Victoire reserved word.', $name)); |
||
531 | } |
||
532 | |||
533 | return $name; |
||
534 | } |
||
535 | ); |
||
536 | |||
537 | $columnName = $questionHelper->ask($input, $output, $question); |
||
538 | if (!$columnName) { |
||
539 | break; |
||
540 | } |
||
541 | |||
542 | $defaultType = 'string'; |
||
543 | |||
544 | // try to guess the type by the column name prefix/suffix |
||
545 | if (substr($columnName, -3) == '_at') { |
||
546 | $defaultType = 'datetime'; |
||
547 | } elseif (substr($columnName, -3) == '_id') { |
||
548 | $defaultType = 'integer'; |
||
549 | } elseif (substr($columnName, 0, 3) == 'is_') { |
||
550 | $defaultType = 'boolean'; |
||
551 | } elseif (substr($columnName, 0, 4) == 'has_') { |
||
552 | $defaultType = 'boolean'; |
||
553 | } |
||
554 | |||
555 | $question = new Question($questionHelper->getQuestion('Field type', $defaultType), $defaultType); |
||
556 | $question->setValidator($fieldValidator); |
||
557 | $question->setAutocompleterValues($types); |
||
558 | $type = $questionHelper->ask($input, $output, $question); |
||
559 | |||
560 | $data = ['columnName' => $columnName, 'fieldName' => lcfirst(Container::camelize($columnName)), 'type' => $type]; |
||
561 | |||
562 | if ($type == 'string') { |
||
563 | $question = new Question($questionHelper->getQuestion('Field length', 255), 255); |
||
564 | $question->setValidator($lengthValidator); |
||
565 | $data['length'] = $questionHelper->ask($input, $output, $question); |
||
566 | } |
||
567 | |||
568 | $fields[$columnName] = $data; |
||
569 | } |
||
570 | |||
571 | return $fields; |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Validate Entity short namepace. |
||
576 | * |
||
577 | * @param string $shortcut |
||
578 | * |
||
579 | * @return $shortcut |
||
0 ignored issues
–
show
The doc-type
$shortcut could not be parsed: Unknown type name "$shortcut" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
580 | */ |
||
581 | protected function parseShortcutNotation($shortcut) |
||
0 ignored issues
–
show
|
|||
582 | { |
||
583 | $entity = str_replace('/', '\\', $shortcut); |
||
584 | |||
585 | if (false === $pos = strpos($entity, ':')) { |
||
586 | throw new \InvalidArgumentException(sprintf('The entity name must contain a : ("%s" given, expecting something like AcmeBlogBundle:Blog/Post)', $entity)); |
||
587 | } |
||
588 | |||
589 | return [substr($entity, 0, $pos), substr($entity, $pos + 1)]; |
||
590 | } |
||
591 | |||
592 | protected function isReservedKeyword($keyword) |
||
593 | { |
||
594 | return in_array($keyword, ['widget']); |
||
595 | } |
||
596 | } |
||
597 |
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.