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 Kunstmaan\GeneratorBundle\Command; |
||
4 | |||
5 | use Kunstmaan\AdminBundle\Form\WysiwygType; |
||
6 | use Kunstmaan\GeneratorBundle\Helper\CommandAssistant; |
||
7 | use Kunstmaan\GeneratorBundle\Helper\GeneratorUtils; |
||
8 | use Kunstmaan\GeneratorBundle\Helper\Sf4AppBundle; |
||
9 | use Kunstmaan\MediaBundle\Form\Type\MediaType; |
||
10 | use Kunstmaan\NodeBundle\Form\Type\URLChooserType; |
||
11 | use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCommand; |
||
12 | use Symfony\Bridge\Doctrine\Form\Type\EntityType; |
||
13 | use Symfony\Component\Console\Input\InputInterface; |
||
14 | use Symfony\Component\Console\Output\OutputInterface; |
||
15 | use Symfony\Component\DependencyInjection\Container; |
||
16 | use Symfony\Component\Finder\Finder; |
||
17 | use Symfony\Component\Form\Extension\Core\Type\CheckboxType; |
||
18 | use Symfony\Component\Form\Extension\Core\Type\DateTimeType; |
||
19 | use Symfony\Component\Form\Extension\Core\Type\IntegerType; |
||
20 | use Symfony\Component\Form\Extension\Core\Type\NumberType; |
||
21 | use Symfony\Component\Form\Extension\Core\Type\TextareaType; |
||
22 | use Symfony\Component\Form\Extension\Core\Type\TextType; |
||
23 | use Symfony\Component\HttpKernel\Bundle\BundleInterface; |
||
24 | use Symfony\Component\HttpKernel\Kernel; |
||
25 | use Symfony\Component\Yaml\Exception\ParseException; |
||
26 | use Symfony\Component\Yaml\Yaml; |
||
27 | |||
28 | abstract class KunstmaanGenerateCommand extends GenerateDoctrineCommand |
||
29 | { |
||
30 | /** |
||
31 | * @var CommandAssistant |
||
32 | */ |
||
33 | protected $assistant; |
||
34 | |||
35 | /** |
||
36 | * Interacts with the user. |
||
37 | * |
||
38 | * @param InputInterface $input An InputInterface instance |
||
39 | * @param OutputInterface $output An OutputInterface instance |
||
40 | */ |
||
41 | protected function interact(InputInterface $input, OutputInterface $output) |
||
42 | { |
||
43 | $this->setInputAndOutput($input, $output); |
||
44 | |||
45 | $welcomeText = $this->getWelcomeText(); |
||
46 | if (!empty($welcomeText)) { |
||
47 | $this->assistant->writeSection($this->getWelcomeText()); |
||
48 | } |
||
49 | |||
50 | $this->doInteract(); |
||
51 | } |
||
52 | |||
53 | /** |
||
54 | * @param InputInterface $input |
||
55 | * @param OutputInterface $output |
||
56 | * |
||
57 | * @return int|null |
||
58 | */ |
||
59 | protected function execute(InputInterface $input, OutputInterface $output) |
||
60 | { |
||
61 | $this->setInputAndOutput($input, $output); |
||
62 | |||
63 | return $this->doExecute(); |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * Create the CommandAssistant. |
||
68 | * |
||
69 | * @param InputInterface $input |
||
70 | * @param OutputInterface $output |
||
71 | */ |
||
72 | View Code Duplication | private function setInputAndOutput(InputInterface $input, OutputInterface $output) |
|
0 ignored issues
–
show
|
|||
73 | { |
||
74 | if (is_null($this->assistant)) { |
||
75 | $this->assistant = new CommandAssistant(); |
||
76 | $this->assistant->setQuestionHelper($this->getQuestionHelper()); |
||
77 | $this->assistant->setKernel($this->getApplication()->getKernel()); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Symfony\Component\Console\Application as the method getKernel() does only exist in the following sub-classes of Symfony\Component\Console\Application : Symfony\Bundle\FrameworkBundle\Console\Application . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends 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 sub-classes 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.
Loading history...
|
|||
78 | } |
||
79 | $this->assistant->setOutput($output); |
||
80 | $this->assistant->setInput($input); |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * Do the interaction with the end user. |
||
85 | */ |
||
86 | abstract protected function doInteract(); |
||
87 | |||
88 | /** |
||
89 | * This function implements the final execution of the Generator. |
||
90 | * It calls the execute function with the correct parameters. |
||
91 | */ |
||
92 | abstract protected function doExecute(); |
||
0 ignored issues
–
show
For interfaces and abstract methods it is generally a good practice to add a
@return annotation even if it is just @return void or @return null , so that implementors know what to do in the overridden method.
For interface and abstract methods, it is impossible to infer the return type
from the immediate code. In these cases, it is generally advisible to explicitly
annotate these methods with a
Loading history...
|
|||
93 | |||
94 | /** |
||
95 | * The text to be displayed on top of the generator. |
||
96 | * |
||
97 | * @return string|array |
||
98 | */ |
||
99 | abstract protected function getWelcomeText(); |
||
100 | |||
101 | /** |
||
102 | * Get an array with all the bundles the user has created. |
||
103 | * |
||
104 | * @return array |
||
105 | */ |
||
106 | protected function getOwnBundles() |
||
107 | { |
||
108 | $bundles = []; |
||
109 | $counter = 1; |
||
110 | $dir = dirname($this->getContainer()->getParameter('kernel.root_dir').'/').'/src/'; |
||
111 | $finder = new Finder(); |
||
112 | $finder->in($dir)->name('*Bundle.php'); |
||
113 | |||
114 | foreach ($finder as $file) { |
||
115 | $bundles[$counter++] = [ |
||
116 | 'name' => basename($file->getFilename(), '.php'), |
||
117 | 'namespace' => $file->getRelativePath(), |
||
118 | 'dir' => $file->getPath(), |
||
119 | ]; |
||
120 | } |
||
121 | |||
122 | return $bundles; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Check that a bundle is available (loaded in AppKernel) |
||
127 | * |
||
128 | * @param string $bundleName |
||
129 | * |
||
130 | * @return bool |
||
131 | */ |
||
132 | protected function isBundleAvailable($bundleName) |
||
133 | { |
||
134 | $allBundles = array_keys($this->assistant->getKernel()->getBundles()); |
||
135 | |||
136 | return in_array($bundleName, $allBundles); |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Asks for the prefix and sets it on the InputInterface as the 'prefix' option, if this option is not set yet. |
||
141 | * Will set the default to a snake_cased namespace when the namespace has been set on the InputInterface. |
||
142 | * |
||
143 | * @param array $text What you want printed before the prefix is asked. If null is provided it'll write a default text. |
||
144 | * @param string $namespace An optional namespace. If this is set it'll create the default based on this prefix. |
||
0 ignored issues
–
show
Should the type for parameter
$namespace not be string|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
145 | * If it's not provided it'll check if the InputInterface already has the namespace option. |
||
146 | * |
||
147 | * @return string The prefix. But it's also been set on the InputInterface. |
||
148 | */ |
||
149 | protected function askForPrefix(array $text = null, $namespace = null) |
||
150 | { |
||
151 | $prefix = $this->assistant->getOptionOrDefault('prefix', null); |
||
152 | |||
153 | if (is_null($text)) { |
||
154 | $text = [ |
||
155 | 'You can add a prefix to the table names of the generated entities for example: '. |
||
156 | '<comment>projectname_bundlename_</comment>', |
||
157 | 'Enter an underscore \'_\' if you don\'t want a prefix.', |
||
158 | '', |
||
159 | ]; |
||
160 | } |
||
161 | |||
162 | while (is_null($prefix)) { |
||
163 | if (count($text) > 0) { |
||
164 | $this->assistant->writeLine($text); |
||
165 | } |
||
166 | |||
167 | if (is_null($namespace) || empty($namespace)) { |
||
168 | $namespace = $this->assistant->getOption('namespace'); |
||
169 | } else { |
||
170 | $namespace = $this->fixNamespace($namespace); |
||
171 | } |
||
172 | $defaultPrefix = GeneratorUtils::cleanPrefix($this->convertNamespaceToSnakeCase($namespace)); |
||
173 | $prefix = GeneratorUtils::cleanPrefix($this->assistant->ask('Tablename prefix', $defaultPrefix)); |
||
174 | |||
175 | if ($prefix == '') { |
||
176 | break; |
||
177 | } |
||
178 | |||
179 | $output = $this->assistant->getOutput(); |
||
180 | View Code Duplication | if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $prefix)) { |
|
181 | $output->writeln(sprintf('<bg=red> "%s" contains invalid characters</>', $prefix)); |
||
182 | $prefix = $text = null; |
||
183 | |||
184 | continue; |
||
185 | } |
||
186 | |||
187 | $this->assistant->setOption('prefix', $prefix); |
||
188 | } |
||
189 | |||
190 | return $prefix; |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Converts something like Namespace\BundleNameBundle to namespace_bundlenamebundle. |
||
195 | * |
||
196 | * @param string $namespace |
||
197 | * |
||
198 | * @return string |
||
0 ignored issues
–
show
|
|||
199 | */ |
||
200 | View Code Duplication | private function convertNamespaceToSnakeCase($namespace) |
|
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.
Loading history...
|
|||
201 | { |
||
202 | if (is_null($namespace)) { |
||
203 | return null; |
||
204 | } |
||
205 | |||
206 | return str_replace('/', '_', strtolower($this->fixNamespace($namespace))); |
||
207 | } |
||
208 | |||
209 | /** |
||
210 | * Replaces '\' with '/'. |
||
211 | * |
||
212 | * @param $namespace |
||
213 | * |
||
214 | * @return mixed |
||
215 | */ |
||
216 | private function fixNamespace($namespace) |
||
217 | { |
||
218 | return str_replace('\\', '/', $namespace); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Ask for which bundle we need to generate something. It there is only one custom bundle |
||
223 | * created by the user, we don't ask anything and just use that bundle. If the user provided |
||
224 | * a namespace as input option, we try to get that bundle first. |
||
225 | * |
||
226 | * @param string $objectName The thing we are going to create (pagepart, bundle, layout, ...) |
||
227 | * @param string|null $namespace The namespace provided as input option |
||
228 | * @param string $questionMoreBundles |
||
229 | * @param string $questionOneBundle |
||
230 | * |
||
231 | * @return BundleInterface |
||
232 | */ |
||
233 | protected function askForBundleName( |
||
234 | $objectName, |
||
235 | $namespace = null, |
||
236 | $questionMoreBundles = "\nIn which bundle do you want to create the %s", |
||
237 | $questionOneBundle = "The %s will be created for the <comment>%s</comment> bundle.\n" |
||
238 | ) { |
||
239 | if (Kernel::VERSION_ID >= 40000) { |
||
240 | return new Sf4AppBundle($this->getContainer()->getParameter('kernel.project_dir')); |
||
241 | } |
||
242 | |||
243 | $ownBundles = $this->getOwnBundles(); |
||
244 | if (count($ownBundles) <= 0) { |
||
245 | $this->assistant->writeError("Looks like you don't have created any bundles for your project...", true); |
||
246 | } |
||
247 | |||
248 | // If the user provided the namespace as input option |
||
249 | if (!is_null($namespace)) { |
||
250 | foreach ($ownBundles as $key => $bundleInfo) { |
||
251 | if (GeneratorUtils::fixNamespace($namespace) == GeneratorUtils::fixNamespace( |
||
252 | $bundleInfo['namespace'] |
||
253 | ) |
||
254 | ) { |
||
255 | $bundleName = $bundleInfo['name']; |
||
256 | |||
257 | break; |
||
258 | } |
||
259 | } |
||
260 | |||
261 | // When the provided namespace was not found, we show an error on the screen and ask the bundle again |
||
262 | if (empty($bundleName)) { |
||
263 | $this->assistant->writeError("The provided bundle namespace '$namespace' was not found..."); |
||
264 | } |
||
265 | } |
||
266 | |||
267 | if (empty($bundleName)) { |
||
268 | // If we only have 1 bundle, we don't need to ask |
||
269 | if (count($ownBundles) > 1) { |
||
270 | $bundleSelect = []; |
||
271 | foreach ($ownBundles as $key => $bundleInfo) { |
||
272 | $bundleSelect[$key] = $bundleInfo['name']; |
||
273 | } |
||
274 | $bundleId = $this->assistant->askSelect( |
||
275 | sprintf($questionMoreBundles, $objectName), |
||
276 | $bundleSelect |
||
277 | ); |
||
278 | $bundleName = $ownBundles[$bundleId]['name']; |
||
279 | |||
280 | $this->assistant->writeLine(''); |
||
281 | } else { |
||
282 | $bundleName = $ownBundles[1]['name']; |
||
283 | $this->assistant->writeLine( |
||
284 | [sprintf($questionOneBundle, $objectName, $bundleName)] |
||
285 | ); |
||
286 | } |
||
287 | } |
||
288 | |||
289 | $bundle = $this->assistant->getKernel()->getBundle($bundleName); |
||
290 | |||
291 | return $bundle; |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * Ask the end user to select one (or more) section configuration(s). |
||
296 | * |
||
297 | * @param string $question |
||
298 | * @param BundleInterface $bundle |
||
299 | * @param bool $multiple |
||
300 | * @param string|null $context |
||
301 | * @param array $defaultSections |
||
302 | * |
||
303 | * @return array|null |
||
304 | */ |
||
305 | protected function askForSections( |
||
306 | $question, |
||
307 | BundleInterface $bundle, |
||
308 | $multiple = false, |
||
309 | $context = null, |
||
310 | $defaultSections = [] |
||
311 | ) { |
||
312 | $allSections = $this->getAvailableSections($bundle, $context, $defaultSections); |
||
313 | $sections = []; |
||
314 | |||
315 | // If there are more options to choose from, we ask the end user |
||
316 | if (count($allSections) > 0) { |
||
317 | $sectionSelect = []; |
||
318 | foreach ($allSections as $key => $sectionInfo) { |
||
319 | $sectionSelect[$key] = $sectionInfo['name'].' ('.$sectionInfo['file'].')'; |
||
320 | } |
||
321 | $this->assistant->writeLine(''); |
||
322 | $sectionIds = $this->assistant->askSelect($question, $sectionSelect, null, $multiple); |
||
323 | if (is_array($sectionIds)) { |
||
324 | foreach ($sectionIds as $id) { |
||
325 | $sections[] = $allSections[$id]['file']; |
||
326 | } |
||
327 | } else { |
||
328 | $sections[] = $allSections[$sectionIds]['file']; |
||
329 | } |
||
330 | } |
||
331 | |||
332 | if ($multiple) { |
||
333 | return $sections; |
||
334 | } else { |
||
335 | return count($sections) > 0 ? $sections[0] : null; |
||
336 | } |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * Get an array with the available page sections. We also parse the yaml files to get more information about |
||
341 | * the sections. |
||
342 | * |
||
343 | * @param BundleInterface $bundle The bundle for which we want to get the section configuration |
||
344 | * @param string|null $context If provided, only return configurations with this context |
||
345 | * @param array $defaultSections The default section configurations that are always available |
||
346 | * |
||
347 | * @return array |
||
348 | */ |
||
349 | protected function getAvailableSections(BundleInterface $bundle, $context = null, $defaultSections = []) |
||
350 | { |
||
351 | $configs = []; |
||
352 | $counter = 1; |
||
353 | |||
354 | // Get the available sections from disc |
||
355 | $dir = Kernel::VERSION_ID >= 40000 ? |
||
356 | $this->getContainer()->getParameter('kernel.project_dir').'/config/kunstmaancms/pageparts/' : |
||
357 | $bundle->getPath().'/Resources/config/pageparts/' |
||
358 | ; |
||
359 | if (file_exists($dir) && is_dir($dir)) { |
||
360 | $finder = new Finder(); |
||
361 | $finder->files()->in($dir)->depth('== 0'); |
||
362 | foreach ($finder as $file) { |
||
363 | $info = $this->getSectionInfo($dir, $file->getFileName()); |
||
364 | |||
365 | if (is_array($info) && (is_null($context) || $info['context'] == $context)) { |
||
366 | $configs[$counter++] = $info; |
||
367 | if (array_key_exists($info['file'], $defaultSections)) { |
||
368 | unset($defaultSections[$info['file']]); |
||
369 | } |
||
370 | } |
||
371 | } |
||
372 | } |
||
373 | |||
374 | // Add the default sections |
||
375 | foreach ($defaultSections as $file => $info) { |
||
376 | if (is_null($context) || $info['context'] == $context) { |
||
377 | $configs[$counter++] = $info; |
||
378 | } |
||
379 | } |
||
380 | |||
381 | return $configs; |
||
382 | } |
||
383 | |||
384 | /** |
||
385 | * Get the information about a pagepart section configuration file. |
||
386 | * |
||
387 | * @param string $dir |
||
388 | * @param string $file |
||
389 | * |
||
390 | * @return array|null |
||
0 ignored issues
–
show
|
|||
391 | */ |
||
392 | private function getSectionInfo($dir, $file) |
||
393 | { |
||
394 | $info = null; |
||
395 | |||
396 | try { |
||
397 | $data = Yaml::parse(file_get_contents($dir.$file)); |
||
398 | |||
399 | View Code Duplication | if (array_key_exists('kunstmaan_page_part', $data)) { |
|
400 | //Get rid of the bundle config lines |
||
401 | $data = array_values(array_values(array_values($data)[0])[0])[0]; |
||
402 | } |
||
403 | |||
404 | $info = [ |
||
405 | 'name' => $data['name'], |
||
406 | 'context' => $data['context'], |
||
407 | 'file' => $file, |
||
408 | //'file_clean' => substr($file, 0, strlen($file)-4) |
||
409 | ]; |
||
410 | } catch (ParseException $e) { |
||
411 | } |
||
412 | |||
413 | return $info; |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Get an array of fields that need to be added to the entity. |
||
418 | * |
||
419 | * @param BundleInterface $bundle |
||
420 | * @param array $reservedFields |
||
421 | * |
||
422 | * @return array |
||
423 | */ |
||
424 | protected function askEntityFields(BundleInterface $bundle, array $reservedFields = ['id']) |
||
425 | { |
||
426 | $this->assistant->writeLine('<info>Available field types:</info> '); |
||
427 | $typeSelect = $this->getTypes(true); |
||
428 | foreach ($typeSelect as $type) { |
||
429 | $this->assistant->writeLine(sprintf('<comment>- %s</comment>', $type)); |
||
430 | } |
||
431 | |||
432 | $fields = []; |
||
433 | $typeStrings = $this->getTypes(); |
||
434 | $mediaTypeSelect = $this->getMediaTypes(); |
||
435 | $generator = $this->getGenerator(); |
||
436 | $container = $this->getContainer(); |
||
437 | |||
438 | while (true) { |
||
439 | $this->assistant->writeLine(''); |
||
440 | |||
441 | $fieldName = $this->assistant->askAndValidate( |
||
442 | 'New field name (press <return> to stop adding fields)', |
||
443 | function ($name) use ($fields, $reservedFields, $generator) { |
||
444 | // The fields cannot exist in the reserved field list |
||
445 | if (in_array($name, $reservedFields)) { |
||
446 | throw new \InvalidArgumentException(sprintf('Field "%s" is already defined in the parent class', $name)); |
||
447 | } |
||
448 | |||
449 | // The fields cannot exist already |
||
450 | if (isset($fields[$name])) { |
||
451 | throw new \InvalidArgumentException(sprintf('Field "%s" is already defined', $name)); |
||
452 | } |
||
453 | |||
454 | // Check reserved words |
||
455 | if ($generator->isReservedKeyword($name)) { |
||
456 | throw new \InvalidArgumentException(sprintf('Name "%s" is a reserved word', $name)); |
||
457 | } |
||
458 | |||
459 | // Only accept a-z |
||
460 | if (!preg_match('/^[a-zA-Z][a-zA-Z_0-9]+$/', $name) && $name != '') { |
||
461 | throw new \InvalidArgumentException(sprintf('Name "%s" is invalid', $name)); |
||
462 | } |
||
463 | |||
464 | return $name; |
||
465 | } |
||
466 | ); |
||
467 | |||
468 | // When <return> is entered |
||
469 | if (!$fieldName) { |
||
470 | break; |
||
471 | } |
||
472 | |||
473 | $typeId = $this->assistant->askSelect('Field type', $typeSelect); |
||
474 | |||
475 | // If single -or multipe entity reference in chosen, we need to ask for the entity name |
||
476 | if (in_array($typeStrings[$typeId], ['single_ref', 'multi_ref'])) { |
||
477 | $bundleName = $bundle->getName(); |
||
478 | $egName = $this->isSymfony4() ? 'App\Entity\FaqItem' : "$bundleName:FaqItem, $bundleName:Blog/Comment"; |
||
479 | $question = sprintf('Reference entity name (eg. %s)', $egName); |
||
480 | $name = $this->assistant->askAndValidate( |
||
481 | $question, |
||
482 | function ($name) use ($generator, $container) { |
||
483 | /* |
||
484 | * Replace slash to backslash. Eg: CmsBundle:Blog/Comment --> CmsBundle:Blog\Comment |
||
485 | * |
||
486 | * @see \Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory::getMetadataFor() |
||
487 | * @see \Doctrine\ORM\Mapping\ClassMetadataFactory::getFqcnFromAlias() |
||
488 | */ |
||
489 | if (!$this->isSymfony4()) { |
||
490 | $name = strtr($name, '/', '\\'); |
||
491 | |||
492 | $parts = explode(':', $name); |
||
493 | |||
494 | // Should contain colon |
||
495 | if (count($parts) != 2) { |
||
496 | throw new \InvalidArgumentException(sprintf('"%s" is an invalid entity name', $name)); |
||
497 | } |
||
498 | } else { |
||
499 | $parts = explode('\\', $name); |
||
500 | } |
||
501 | |||
502 | // Check reserved words |
||
503 | if ($generator->isReservedKeyword(end($parts))) { |
||
504 | throw new \InvalidArgumentException(sprintf('"%s" contains a reserved word', $name)); |
||
505 | } |
||
506 | |||
507 | $em = $container->get('doctrine')->getManager(); |
||
508 | |||
509 | try { |
||
510 | $em->getClassMetadata($name); |
||
511 | } catch (\Exception $e) { |
||
512 | throw new \InvalidArgumentException(sprintf('Entity "%s" not found', $name)); |
||
513 | } |
||
514 | |||
515 | return $name; |
||
516 | }, |
||
517 | null, |
||
518 | [$bundleName] |
||
519 | ); |
||
520 | |||
521 | $extra = $name; |
||
522 | } else { |
||
523 | $extra = null; |
||
524 | } |
||
525 | |||
526 | // If image type, force image media filter |
||
527 | if ($typeStrings[$typeId] == 'image') { |
||
528 | $extra = 'image'; |
||
529 | } |
||
530 | |||
531 | // If media type, ask for media filter |
||
532 | if ($typeStrings[$typeId] == 'media') { |
||
533 | $mediaTypeId = $this->assistant->askSelect('Media filter', $mediaTypeSelect); |
||
534 | $extra = strtolower($mediaTypeSelect[$mediaTypeId]); |
||
535 | } |
||
536 | |||
537 | if ($typeStrings[$typeId] == 'image' || $typeStrings[$typeId] == 'media') { |
||
538 | // Ask the allowed mimetypes for the media ojbect |
||
539 | $mimeTypes = $this->assistant->ask('Do you want to limit the possible file types? Then specify a comma-seperated list of types (example: image/png,image/svg+xml), otherwise press ENTER', |
||
540 | null |
||
541 | ); |
||
542 | if (isset($mimeTypes)) { |
||
543 | $mimeTypes = explode(',', $mimeTypes); |
||
544 | } |
||
545 | $data = [ |
||
546 | 'name' => $fieldName, |
||
547 | 'type' => $typeStrings[$typeId], |
||
548 | 'extra' => $extra, |
||
549 | 'mimeTypes' => $mimeTypes, |
||
550 | 'minHeight' => null, |
||
551 | 'maxHeight' => null, |
||
552 | 'minWidth' => null, |
||
553 | 'maxWidth' => null, |
||
554 | ]; |
||
555 | |||
556 | if ($extra == 'image') { |
||
557 | $minHeight = $maxHeight = $minWidth = $maxWidth = null; |
||
558 | if ($this->assistant->askConfirmation('Do you want to add validation of the dimensions of the media object? (y/n)', |
||
559 | 'n', |
||
560 | '?', |
||
561 | false |
||
562 | )) { |
||
563 | // Ask the minimum height allowed for the image |
||
564 | $lengthValidation = function ($length) { |
||
565 | if ((is_numeric($length) && $length < 0) || (!is_numeric($length) && !empty($length))) { |
||
566 | throw new \InvalidArgumentException(sprintf('"%s" is not a valid length', $length)); |
||
567 | } else { |
||
568 | return $length; |
||
569 | } |
||
570 | }; |
||
571 | |||
572 | $minHeight = $this->assistant->askAndValidate('What is the minimum height for the media object? (in pixels)', |
||
573 | $lengthValidation |
||
574 | ); |
||
575 | |||
576 | // Ask the maximum height allowed for the image |
||
577 | $maxHeight = $this->assistant->askAndValidate('What is the maximum height for the media object? (in pixels)', |
||
578 | $lengthValidation |
||
579 | ); |
||
580 | |||
581 | // Ask the minimum width allowed for the image |
||
582 | $minWidth = $this->assistant->askAndValidate('What is the minimum width for the media object? (in pixels)', |
||
583 | $lengthValidation |
||
584 | ); |
||
585 | |||
586 | //Ask the maximum width allowed for the image |
||
587 | $maxWidth = $this->assistant->askAndValidate('What is the maximum width for the media object? (in pixels)', |
||
588 | $lengthValidation |
||
589 | ); |
||
590 | } |
||
591 | $data = [ |
||
592 | 'name' => $fieldName, |
||
593 | 'type' => 'image', |
||
594 | 'extra' => $extra, |
||
595 | 'minHeight' => $minHeight, |
||
596 | 'maxHeight' => $maxHeight, |
||
597 | 'minWidth' => $minWidth, |
||
598 | 'maxWidth' => $maxWidth, |
||
599 | 'mimeTypes' => $mimeTypes, |
||
600 | ]; |
||
601 | } |
||
602 | } else { |
||
603 | $data = [ |
||
604 | 'name' => $fieldName, |
||
605 | 'type' => $typeStrings[$typeId], |
||
606 | 'extra' => $extra, |
||
607 | 'minHeight' => null, |
||
608 | 'maxHeight' => null, |
||
609 | 'minWidth' => null, |
||
610 | 'maxWidth' => null, |
||
611 | 'mimeTypes' => null, |
||
612 | ]; |
||
613 | } |
||
614 | |||
615 | $fields[$fieldName] = $data; |
||
616 | } |
||
617 | |||
618 | return $fields; |
||
619 | } |
||
620 | |||
621 | /** |
||
622 | * Get all the available types. |
||
623 | * |
||
624 | * @param bool $niceNames |
||
625 | * |
||
626 | * @return array |
||
0 ignored issues
–
show
|
|||
627 | */ |
||
628 | private function getTypes($niceNames = false) |
||
629 | { |
||
630 | $counter = 1; |
||
631 | |||
632 | $types = []; |
||
633 | $types[$counter++] = $niceNames ? 'Single line text' : 'single_line'; |
||
634 | $types[$counter++] = $niceNames ? 'Multi line text' : 'multi_line'; |
||
635 | $types[$counter++] = $niceNames ? 'Wysiwyg' : 'wysiwyg'; |
||
636 | $types[$counter++] = $niceNames ? 'Link (url, text, new window)' : 'link'; |
||
637 | if ($this->isBundleAvailable('KunstmaanMediaPagePartBundle')) { |
||
638 | $types[$counter++] = $niceNames ? 'Image (media, alt text)' : 'image'; |
||
639 | $types[$counter++] = $niceNames ? 'Media (File or Video or Slideshow)' : 'media'; |
||
640 | } |
||
641 | $types[$counter++] = $niceNames ? 'Single entity reference' : 'single_ref'; |
||
642 | $types[$counter++] = $niceNames ? 'Multi entity reference' : 'multi_ref'; |
||
643 | $types[$counter++] = $niceNames ? 'Boolean' : 'boolean'; |
||
644 | $types[$counter++] = $niceNames ? 'Integer' : 'integer'; |
||
645 | $types[$counter++] = $niceNames ? 'Decimal number' : 'decimal'; |
||
646 | $types[$counter++] = $niceNames ? 'DateTime' : 'datetime'; |
||
647 | |||
648 | return $types; |
||
649 | } |
||
650 | |||
651 | /** |
||
652 | * Get all available media types. |
||
653 | * |
||
654 | * @return array |
||
655 | */ |
||
656 | private function getMediaTypes() |
||
657 | { |
||
658 | $counter = 1; |
||
659 | |||
660 | $types = []; |
||
661 | $types[$counter++] = 'None'; |
||
662 | $types[$counter++] = 'File'; |
||
663 | $types[$counter++] = 'Image'; |
||
664 | $types[$counter++] = 'Video'; |
||
665 | |||
666 | return $types; |
||
667 | } |
||
668 | |||
669 | /** |
||
670 | * Get all the entity fields for a specific type. |
||
671 | * |
||
672 | * @param BundleInterface $bundle |
||
673 | * @param $objectName |
||
674 | * @param $prefix |
||
675 | * @param $name |
||
676 | * @param $type |
||
677 | * @param null $extra |
||
678 | * @param bool $allNullable |
||
679 | * @param null $minHeight |
||
680 | * @param null $maxHeight |
||
681 | * @param null $minWidth |
||
682 | * @param null $maxWidth |
||
683 | * @param null $mimeTypes |
||
684 | * |
||
685 | * @return array |
||
686 | */ |
||
687 | protected function getEntityFields( |
||
688 | BundleInterface $bundle, |
||
689 | $objectName, |
||
690 | $prefix, |
||
691 | $name, |
||
692 | $type, |
||
693 | $extra = null, |
||
694 | $allNullable = false, |
||
695 | $minHeight = null, |
||
696 | $maxHeight = null, |
||
697 | $minWidth = null, |
||
698 | $maxWidth = null, |
||
699 | $mimeTypes = null |
||
700 | ) { |
||
701 | $fields = []; |
||
702 | switch ($type) { |
||
703 | View Code Duplication | case 'single_line': |
|
0 ignored issues
–
show
This code seems to be duplicated across 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.
Loading history...
|
|||
704 | $fields[$type][] = [ |
||
705 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
706 | 'type' => 'string', |
||
707 | 'length' => '255', |
||
708 | 'formType' => TextType::class, |
||
709 | 'nullable' => $allNullable, |
||
710 | ]; |
||
711 | |||
712 | break; |
||
713 | View Code Duplication | case 'multi_line': |
|
0 ignored issues
–
show
This code seems to be duplicated across 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.
Loading history...
|
|||
714 | $fields[$type][] = [ |
||
715 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
716 | 'type' => 'text', |
||
717 | 'formType' => TextareaType::class, |
||
718 | 'nullable' => $allNullable, |
||
719 | ]; |
||
720 | |||
721 | break; |
||
722 | View Code Duplication | case 'wysiwyg': |
|
723 | $fields[$type][] = [ |
||
724 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
725 | 'type' => 'text', |
||
726 | 'formType' => WysiwygType::class, |
||
727 | 'nullable' => $allNullable, |
||
728 | ]; |
||
729 | |||
730 | break; |
||
731 | case 'link': |
||
732 | foreach (['url', 'text'] as $subField) { |
||
733 | $fields[$type][$subField] = [ |
||
734 | 'fieldName' => lcfirst(Container::camelize($name.'_'.$subField)), |
||
735 | 'type' => 'string', |
||
736 | 'formType' => $subField == 'url' ? URLChooserType::class : TextType::class, |
||
737 | 'nullable' => $allNullable, |
||
738 | ]; |
||
739 | } |
||
740 | $fields[$type]['new_window'] = [ |
||
741 | 'fieldName' => lcfirst(Container::camelize($name.'_new_window')), |
||
742 | 'type' => 'boolean', |
||
743 | 'nullable' => true, |
||
744 | 'formType' => CheckboxType::class, |
||
745 | ]; |
||
746 | |||
747 | break; |
||
748 | case 'image': |
||
749 | $fields[$type]['image'] = [ |
||
750 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
751 | 'type' => 'image', |
||
752 | 'formType' => MediaType::class, |
||
753 | 'mediaType' => $extra, |
||
754 | 'minHeight' => $minHeight, |
||
755 | 'maxHeight' => $maxHeight, |
||
756 | 'minWidth' => $minWidth, |
||
757 | 'maxWidth' => $maxWidth, |
||
758 | 'mimeTypes' => $mimeTypes, |
||
759 | 'targetEntity' => 'Kunstmaan\MediaBundle\Entity\Media', |
||
760 | 'joinColumn' => [ |
||
761 | 'name' => str_replace('.', '_', Container::underscore($name.'_id')), |
||
762 | 'referencedColumnName' => 'id', |
||
763 | ], |
||
764 | 'nullable' => $allNullable, |
||
765 | ]; |
||
766 | $fields[$type]['alt_text'] = [ |
||
767 | 'fieldName' => lcfirst(Container::camelize($name.'_alt_text')), |
||
768 | 'type' => 'text', |
||
769 | 'nullable' => true, |
||
770 | 'formType' => TextType::class, |
||
771 | ]; |
||
772 | |||
773 | break; |
||
774 | case 'media': |
||
775 | $fields[$type][] = [ |
||
776 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
777 | 'type' => 'media', |
||
778 | 'formType' => MediaType::class, |
||
779 | 'mediaType' => $extra, |
||
780 | 'mimeTypes' => $mimeTypes, |
||
781 | 'targetEntity' => 'Kunstmaan\MediaBundle\Entity\Media', |
||
782 | 'joinColumn' => [ |
||
783 | 'name' => str_replace('.', '_', Container::underscore($name.'_id')), |
||
784 | 'referencedColumnName' => 'id', |
||
785 | ], |
||
786 | 'nullable' => $allNullable, |
||
787 | ]; |
||
788 | |||
789 | break; |
||
790 | case 'single_ref': |
||
791 | $em = $this->getContainer()->get('doctrine')->getManager(); |
||
792 | $entityName = $em->getClassMetadata($extra)->getName(); |
||
793 | $fields[$type][] = [ |
||
794 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
795 | 'type' => 'entity', |
||
796 | 'formType' => EntityType::class, |
||
797 | 'targetEntity' => $entityName, |
||
798 | 'joinColumn' => [ |
||
799 | 'name' => str_replace('.', '_', Container::underscore($name.'_id')), |
||
800 | 'referencedColumnName' => 'id', |
||
801 | ], |
||
802 | 'nullable' => $allNullable, |
||
803 | ]; |
||
804 | |||
805 | break; |
||
806 | case 'multi_ref': |
||
807 | $em = $this->getContainer()->get('doctrine')->getManager(); |
||
808 | $entityName = $em->getClassMetadata($extra)->getName(); |
||
809 | $parts = explode('\\', $entityName); |
||
810 | $joinTableName = strtolower( |
||
811 | $prefix.Container::underscore($objectName).'_'.Container::underscore( |
||
812 | $parts[count($parts) - 1] |
||
813 | ) |
||
814 | ); |
||
815 | $fields[$type][] = [ |
||
816 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
817 | 'type' => 'entity', |
||
818 | 'formType' => EntityType::class, |
||
819 | 'targetEntity' => $entityName, |
||
820 | 'joinTable' => [ |
||
821 | 'name' => $joinTableName, |
||
822 | 'joinColumns' => [ |
||
823 | [ |
||
824 | 'name' => strtolower(Container::underscore($objectName)).'_id', |
||
825 | 'referencedColumnName' => 'id', |
||
826 | ], |
||
827 | ], |
||
828 | 'inverseJoinColumns' => [ |
||
829 | [ |
||
830 | 'name' => strtolower( |
||
831 | Container::underscore($parts[count($parts) - 1]) |
||
832 | ).'_id', |
||
833 | 'referencedColumnName' => 'id', |
||
834 | 'unique' => true, |
||
835 | ], |
||
836 | ], |
||
837 | ], |
||
838 | 'nullable' => $allNullable, |
||
839 | ]; |
||
840 | |||
841 | break; |
||
842 | View Code Duplication | case 'boolean': |
|
0 ignored issues
–
show
This code seems to be duplicated across 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.
Loading history...
|
|||
843 | $fields[$type][] = [ |
||
844 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
845 | 'type' => 'boolean', |
||
846 | 'formType' => CheckboxType::class, |
||
847 | 'nullable' => $allNullable, |
||
848 | ]; |
||
849 | |||
850 | break; |
||
851 | View Code Duplication | case 'integer': |
|
0 ignored issues
–
show
This code seems to be duplicated across 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.
Loading history...
|
|||
852 | $fields[$type][] = [ |
||
853 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
854 | 'type' => 'integer', |
||
855 | 'formType' => IntegerType::class, |
||
856 | 'nullable' => $allNullable, |
||
857 | ]; |
||
858 | |||
859 | break; |
||
860 | View Code Duplication | case 'decimal': |
|
0 ignored issues
–
show
This code seems to be duplicated across 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.
Loading history...
|
|||
861 | $fields[$type][] = [ |
||
862 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
863 | 'type' => 'decimal', |
||
864 | 'precision' => 10, |
||
865 | 'scale' => 2, |
||
866 | 'formType' => NumberType::class, |
||
867 | 'nullable' => $allNullable, |
||
868 | ]; |
||
869 | |||
870 | break; |
||
871 | View Code Duplication | case 'datetime': |
|
0 ignored issues
–
show
This code seems to be duplicated across 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.
Loading history...
|
|||
872 | $fields[$type][] = [ |
||
873 | 'fieldName' => lcfirst(Container::camelize($name)), |
||
874 | 'type' => 'datetime', |
||
875 | 'formType' => DateTimeType::class, |
||
876 | 'nullable' => $allNullable, |
||
877 | ]; |
||
878 | |||
879 | break; |
||
880 | } |
||
881 | |||
882 | return $fields; |
||
883 | } |
||
884 | |||
885 | /** |
||
886 | * Get an array with the available page templates. |
||
887 | * |
||
888 | * @param BundleInterface $bundle The bundle for which we want to get the template configurations |
||
889 | * |
||
890 | * @return array |
||
891 | */ |
||
892 | protected function getAvailableTemplates(BundleInterface $bundle) |
||
893 | { |
||
894 | $configs = []; |
||
895 | $counter = 1; |
||
896 | |||
897 | // Get the available sections from disc |
||
898 | if (Kernel::VERSION_ID >= 40000) { |
||
899 | $dir = $this->getContainer()->getParameter('kernel.project_dir').'/config/kunstmaancms/pagetemplates/'; |
||
900 | } else { |
||
901 | $dir = $bundle->getPath().'/Resources/config/pagetemplates/'; |
||
902 | } |
||
903 | |||
904 | if (file_exists($dir) && is_dir($dir)) { |
||
905 | $finder = new Finder(); |
||
906 | $finder->files()->in($dir)->depth('== 0'); |
||
907 | foreach ($finder as $file) { |
||
908 | $info = $this->getTemplateInfo($dir, $file->getFileName()); |
||
909 | if (is_array($info)) { |
||
910 | $configs[$counter++] = $info; |
||
911 | } |
||
912 | } |
||
913 | } |
||
914 | |||
915 | return $configs; |
||
916 | } |
||
917 | |||
918 | /** |
||
919 | * Get the information about a pagepart section configuration file. |
||
920 | * |
||
921 | * @param string $dir |
||
922 | * @param string $file |
||
923 | * |
||
924 | * @return array|null |
||
925 | */ |
||
926 | protected function getTemplateInfo($dir, $file) |
||
927 | { |
||
928 | $info = null; |
||
929 | |||
930 | try { |
||
931 | $data = Yaml::parse(file_get_contents($dir.$file)); |
||
932 | |||
933 | View Code Duplication | if (array_key_exists('kunstmaan_page_part', $data)) { |
|
934 | //Get rid of the bundle config lines |
||
935 | $data = array_values(array_values(array_values($data)[0])[0])[0]; |
||
936 | } |
||
937 | |||
938 | // Parse contexts |
||
939 | $contexts = []; |
||
940 | foreach ($data['rows'] as $row) { |
||
941 | foreach ($row['regions'] as $region) { |
||
942 | $contexts[] = $region['name']; |
||
943 | } |
||
944 | } |
||
945 | $info = [ |
||
946 | 'name' => $data['name'], |
||
947 | 'contexts' => $contexts, |
||
948 | 'file' => $file, |
||
949 | ]; |
||
950 | } catch (ParseException $e) { |
||
951 | } |
||
952 | |||
953 | return $info; |
||
954 | } |
||
955 | |||
956 | /** |
||
957 | * Get an array with the available page templates. |
||
958 | * |
||
959 | * @param BundleInterface $bundle The bundle for which we want to get the template configurations |
||
960 | * |
||
961 | * @return array |
||
962 | */ |
||
963 | protected function getAvailablePages(BundleInterface $bundle) |
||
964 | { |
||
965 | $pages = []; |
||
966 | $counter = 1; |
||
967 | |||
968 | // Get the available pages from disc |
||
969 | $dir = $bundle->getPath().'/Entity/Pages/'; |
||
970 | if (file_exists($dir) && is_dir($dir)) { |
||
971 | $finder = new Finder(); |
||
972 | $finder->files()->in($dir)->depth('== 0'); |
||
973 | foreach ($finder as $file) { |
||
974 | $pages[$counter++] = [ |
||
975 | 'name' => substr($file->getFileName(), 0, strlen($file->getFileName()) - 4), |
||
976 | 'path' => $file->getPathName(), |
||
977 | ]; |
||
978 | } |
||
979 | } |
||
980 | |||
981 | return $pages; |
||
982 | } |
||
983 | |||
984 | /** |
||
985 | * Check that it is possible to generate the behat tests. |
||
986 | * |
||
987 | * @param BundleInterface $bundle |
||
988 | * |
||
989 | * @return bool |
||
990 | */ |
||
991 | protected function canGenerateBehatTests(BundleInterface $bundle) |
||
992 | { |
||
993 | $behatFile = dirname($this->getContainer()->getParameter('kernel.root_dir').'/').'/behat.yml'; |
||
994 | $pagePartContext = $bundle->getPath().'/Features/Context/PagePartContext.php'; |
||
995 | $behatTestPage = $bundle->getPath().'/Entity/Pages/BehatTestPage.php'; |
||
996 | |||
997 | // Make sure behat is configured and the PagePartContext and BehatTestPage exits |
||
998 | return file_exists($behatFile) && file_exists($pagePartContext) && file_exists($behatTestPage); |
||
999 | } |
||
1000 | |||
1001 | /** |
||
1002 | * @internal |
||
1003 | */ |
||
1004 | protected function isSymfony4() |
||
1005 | { |
||
1006 | return Kernel::VERSION_ID >= 40000; |
||
1007 | } |
||
1008 | } |
||
1009 |
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.