Issues (82)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Command/GenerateCrudCommand.php (11 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Pgs\RestfonyBundle\Command;
13
14
use Pgs\RestfonyBundle\Generator\DoctrineCrudGenerator;
15
use Pgs\RestfonyBundle\Generator\DoctrineFormGenerator;
16
use Pgs\RestfonyBundle\Generator\DoctrineManagerGenerator;
17
use Pgs\RestfonyBundle\Generator\DoctrineRepositoryGenerator;
18
use Pgs\RestfonyBundle\Generator\DoctrineSerializationConfigGenerator;
19
use Pgs\RestfonyBundle\Manipulator\RestConfigManipulator;
20
use Pgs\RestfonyBundle\Manipulator\RoutingManipulator;
21
use Sensio\Bundle\GeneratorBundle\Command\Validators;
22
use Symfony\Component\Console\Input\InputOption;
23
use Symfony\Component\Console\Input\InputArgument;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Output\OutputInterface;
26
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
27
use Symfony\Component\Console\Question\Question;
28
use Symfony\Component\Console\Question\ConfirmationQuestion;
29
use Sensio\Bundle\GeneratorBundle\Command\Helper\QuestionHelper;
30
31
/**
32
 * Generates a Restful CRUD for a Doctrine entity.
33
 *
34
 * @author Lech Groblewicz <[email protected]>
35
 */
36
class GenerateCrudCommand extends GeneratorCommand
37
{
38
    protected $serializationConfigGenerator;
39
    protected $managerGenerator;
40
    protected $repositoryGenerator;
41
    protected $entity;
42
    protected $bundle;
43
    private $formGenerator;
44
45
    /**
46
     * @see Command
47
     */
48
    protected function configure()
49
    {
50
        $this
51
            ->setDefinition(array(
52
                new InputArgument('entity', InputArgument::OPTIONAL, 'The entity class name to initialize (shortcut notation)'),
53
                new InputOption('entity', '', InputOption::VALUE_REQUIRED, 'The entity class name to initialize (shortcut notation)'),
54
                new InputOption('route-prefix', '', InputOption::VALUE_REQUIRED, 'The route prefix'),
55
                new InputOption('with-write', '', InputOption::VALUE_NONE, 'Whether or not to generate create, new and delete actions'),
56
                new InputOption('format', '', InputOption::VALUE_REQUIRED, 'Use the format for configuration files (php, xml, yml, or annotation)', 'annotation'),
57
                new InputOption('overwrite', '', InputOption::VALUE_NONE, 'Do not stop the generation if crud controller already exist, thus overwriting all generated files'),
58
            ))
59
            ->setDescription('Generates a CRUD based on a Doctrine entity')
60
            ->setHelp(<<<EOT
61
The <info>pgs:generate:crud</info> command generates a CRUD based on a Doctrine entity.
62
63
The default command only generates the list and show actions.
64
65
<info>php app/console pgs:generate:crud --entity=AcmeBlogBundle:Post --route-prefix=post_admin</info>
66
67
Using the --with-write option allows to generate the new, edit and delete actions.
68
69
<info>php app/console pgs:generate:crud --entity=AcmeBlogBundle:Post --route-prefix=post_admin --with-write</info>
70
71
Every generated file is based on a template. There are default templates but they can be overridden by placing custom templates in one of the following locations, by order of priority:
72
73
<info>BUNDLE_PATH/Resources/SensioGeneratorBundle/skeleton/crud
74
APP_PATH/Resources/SensioGeneratorBundle/skeleton/crud</info>
75
76
And
77
78
<info>__bundle_path__/Resources/SensioGeneratorBundle/skeleton/form
79
__project_root__/app/Resources/SensioGeneratorBundle/skeleton/form</info>
80
81
You can check https://github.com/sensio/SensioGeneratorBundle/tree/master/Resources/skeleton
82
in order to know the file structure of the skeleton
83
EOT
84
            )
85
            ->setName('pgs:generate:crud')
86
        ;
87
    }
88
89
    /**
90
     * @see Command
91
     *
92
     * @param InputInterface  $input
93
     * @param OutputInterface $output
94
     *
95
     * @return int|null
96
     */
97
    protected function execute(InputInterface $input, OutputInterface $output)
98
    {
99
        $questionHelper = $this->getQuestionHelper();
100
101 View Code Duplication
        if ($input->isInteractive()) {
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...
102
            $question = new ConfirmationQuestion($questionHelper->getQuestion('Do you confirm generation', 'yes', '?'), true);
103
            if (!$questionHelper->ask($input, $output, $question)) {
104
                $output->writeln('<error>Command aborted</error>');
105
106
                return 1;
107
            }
108
        }
109
110
        $entity = Validators::validateEntityName($input->getOption('entity'));
111
        list($bundle, $entity) = $this->parseShortcutNotation($entity);
112
        $this->entity = $entity;
113
114
        $format = Validators::validateFormat($input->getOption('format'));
115
        $prefix = $this->getRoutePrefix($input, $entity);
116
        $withWrite = $input->getOption('with-write');
117
        $forceOverwrite = $input->getOption('overwrite');
118
119
        $questionHelper->writeSection($output, 'CRUD generation');
120
121
        $entityClass = $this->getContainer()->get('doctrine')->getAliasNamespace($bundle).'\\'.$entity;
122
        $metadata    = $this->getEntityMetadata($entityClass);
123
        $bundle      = $this->getContainer()->get('kernel')->getBundle($bundle);
124
        $this->bundle = $bundle;
125
126
        $generator = $this->getGenerator($bundle);
127
        $generator->generate($bundle, $entity, $metadata[0], $withWrite, $forceOverwrite);
128
129
        $output->writeln('Generating the CRUD code: <info>OK</info>');
130
131
        $errors = array();
132
        $runner = $questionHelper->getRunner($output, $errors);
133
134
        // form
135
        $output->write('Generating the Form code: ');
136
        if ($this->generateForm($bundle, $entity, $metadata, $forceOverwrite)) {
137
            $output->writeln('<info>OK</info>');
138
        } else {
139
            $output->writeln('<comment>Already exists, skipping</comment>');
140
        }
141
142
        $output->write('Generating the Repository code: ');
143
        if ($this->generateRepository($bundle, $entity, $forceOverwrite)) {
144
            $output->writeln('<info>OK</info>');
145
        } else {
146
            $output->writeln('<comment>Already exists, skipping</comment>');
147
        }
148
149
        $output->write('Generating the Manager code: ');
150
        if ($this->generateManager($bundle, $entity, $forceOverwrite)) {
151
            $output->writeln('<info>OK</info>');
152
        } else {
153
            $output->writeln('<comment>Already exists, skipping</comment>');
154
        }
155
156
        $runner($this->updateRouting($questionHelper, $input, $output, $bundle, $format, $entity, $prefix));
157
158
        $output->write('Generating the serialization config: ');
159
        if ($this->generateSerializationConfig($bundle, $entity, $metadata, $forceOverwrite)) {
160
            $output->writeln('<info>OK</info>');
161
        } else {
162
            $output->writeln('<comment>Already exists, skipping</comment>');
163
        }
164
165
        $runner($this->updateRestRouting($questionHelper, $input, $output, $bundle, $entity, $metadata));
166
167
        $questionHelper->writeGeneratorSummary($output, $errors);
168
    }
169
170
    protected function interact(InputInterface $input, OutputInterface $output)
171
    {
172
        $questionHelper = $this->getQuestionHelper();
173
        $questionHelper->writeSection($output, 'Welcome to the Doctrine2 CRUD generator');
174
175
        // namespace
176
        $output->writeln(array(
177
            '',
178
            'This command helps you generate CRUD controllers and templates.',
179
            '',
180
            'First, you need to give the entity for which you want to generate a CRUD.',
181
            'You can give an entity that does not exist yet and the wizard will help',
182
            'you defining it.',
183
            '',
184
            'You must use the shortcut notation like <comment>AcmeBlogBundle:Post</comment>.',
185
            '',
186
        ));
187
188
        if ($input->hasArgument('entity') && $input->getArgument('entity') !== '') {
189
            $input->setOption('entity', $input->getArgument('entity'));
190
        }
191
192
        $question = new Question($questionHelper->getQuestion('The Entity shortcut name', $input->getOption('entity')), $input->getOption('entity'));
193
        $question->setValidator(array('Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateEntityName'));
194
        $entity = $questionHelper->ask($input, $output, $question);
195
        $input->setOption('entity', $entity);
196
        list($bundle, $entity) = $this->parseShortcutNotation($entity);
197
198
        // write?
199
        $withWrite = (bool) $input->getOption('with-write');
200
201
        $output->writeln(array(
202
            '',
203
            'By default, the generator creates two actions: list and show.',
204
            'You can also ask it to generate "write" actions: new, update, and delete.',
205
            '',
206
        ));
207
        $question = new ConfirmationQuestion($questionHelper->getQuestion('Do you want to generate the "write" actions', $withWrite ? 'yes' : 'no', '?', $withWrite), $withWrite);
208
209
        $withWrite = $questionHelper->ask($input, $output, $question);
210
        $input->setOption('with-write', $withWrite);
211
212
        // summary
213
        $output->writeln(array(
214
            '',
215
            $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

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
216
            '',
217
            sprintf("You are going to generate a REST CRUD controller for \"<info>%s:%s</info>\"", $bundle, $entity),
218
            '',
219
        ));
220
    }
221
222
    /**
223
     * Tries to generate forms if they don't exist yet and if we need write operations on entities.
224
     */
225 View Code Duplication
    protected function generateSerializationConfig($bundle, $entity, $metadata, $forceOverwrite)
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...
226
    {
227
        try {
228
            $this->getSerializationConfigGenerator($bundle, $entity)->generate($metadata[0], $forceOverwrite);
229
        } catch (\RuntimeException $e) {
230
            return false;
231
        }
232
233
        return true;
234
    }
235
236
    /**
237
     * Tries to generate forms if they don't exist yet and if we need write operations on entities.
238
     */
239 View Code Duplication
    protected function generateForm($bundle, $entity, $metadata, $forceOverwrite)
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...
240
    {
241
        try {
242
            $this->getFormGenerator($bundle, $entity, $metadata[0])->generate($forceOverwrite);
243
        } catch (\RuntimeException $e) {
244
            return false;
245
        }
246
247
        return true;
248
    }
249
250
    protected function generateManager($bundle, $entity, $forceOverwrite)
251
    {
252
        try {
253
            $this->getManagerGenerator($bundle, $entity)->generate($forceOverwrite);
254
        } catch (\RuntimeException $e) {
255
            return false;
256
        }
257
258
        return true;
259
    }
260
261
    protected function generateRepository($bundle, $entity, $forceOverwrite)
262
    {
263
        try {
264
            $this->getRepositoryGenerator($bundle, $entity)->generate($forceOverwrite);
265
        } catch (\RuntimeException $e) {
266
            return false;
267
        }
268
269
        return true;
270
    }
271
272
    protected function updateRestRouting(QuestionHelper $questionHelper, InputInterface $input, OutputInterface $output, BundleInterface $bundle, $entity, $metadata)
0 ignored issues
show
The parameter $questionHelper is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $input is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
273
    {
274
        $output->write('Importing REST config: ');
275
        $this->getContainer()->get('filesystem')->mkdir($bundle->getPath().'/Resources/config/');
276
        $config = new RestConfigManipulator($this->getContainer()->get('kernel')->getRootDir().'/config/rest.yml');
277
        $config->addResource($bundle->getNamespace(), $entity, $metadata);
278
    }
279
280
    protected function updateRouting(QuestionHelper $questionHelper, InputInterface $input, OutputInterface $output, BundleInterface $bundle, $format, $entity, $prefix)
281
    {
282
        $auto = true;
283 View Code Duplication
        if ($input->isInteractive()) {
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...
284
            $question = new ConfirmationQuestion($questionHelper->getQuestion('Confirm automatic update of the Routing', 'yes', '?'), true);
285
            $auto = $questionHelper->ask($input, $output, $question);
286
        }
287
288
        $output->write('Importing the CRUD routes: ');
289
        $this->getContainer()->get('filesystem')->mkdir($bundle->getPath().'/Resources/config/');
290
        $routing = new RoutingManipulator($bundle->getPath().'/Resources/config/rest_routing.yml');
291
292
        $resourceAdded = false;
293
294
        if ($auto) {
295
            $resourceAdded = $routing->addResource($bundle->getName(), '/'.$prefix);
296
        }
297
298
        if (!$resourceAdded) {
299
            $help = sprintf("        <comment>resource: \"@%s/Resources/config/routing/%s.%s\"</comment>\n", $bundle->getName(), strtolower(str_replace('\\', '_', $entity)), $format);
300
            $help .= sprintf("        <comment>prefix:   /%s</comment>\n", $prefix);
301
302
            return array(
303
                '- Import the bundle\'s routing resource in the bundle routing file',
304
                sprintf('  (%s).', $bundle->getPath().'/Resources/config/rest_routing.yml'),
305
                '',
306
                sprintf('    <comment>%s:</comment>', $bundle->getName().('' !== $prefix ? '_'.str_replace('/', '_', $prefix) : '')),
307
                $help,
308
                '',
309
            );
310
        }
311
    }
312
313
    protected function getRoutePrefix(InputInterface $input, $entity)
314
    {
315
        $prefix = $input->getOption('route-prefix') ?: strtolower(str_replace(array('\\', '/'), '_', $entity));
316
317
        if ($prefix && '/' === $prefix[0]) {
318
            $prefix = substr($prefix, 1);
319
        }
320
321
        return $prefix;
322
    }
323
324
    protected function createGenerator()
325
    {
326
        return new DoctrineCrudGenerator($this->getContainer()->get('filesystem'), $this->bundle, $this->entity);
327
    }
328
329 View Code Duplication
    protected function getFormGenerator(BundleInterface $bundle, $entity, $metadata)
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...
330
    {
331
        if (null === $this->formGenerator) {
332
            $this->formGenerator = new DoctrineFormGenerator($bundle, $entity, $metadata);
333
            $this->formGenerator->setSkeletonDirs($this->getSkeletonDirs($bundle));
334
        }
335
336
        return $this->formGenerator;
337
    }
338
339 View Code Duplication
    protected function getSerializationConfigGenerator(BundleInterface $bundle, $entity)
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...
340
    {
341
        if (null === $this->serializationConfigGenerator) {
342
            $this->serializationConfigGenerator = new DoctrineSerializationConfigGenerator($bundle, $entity);
343
            $this->serializationConfigGenerator->setSkeletonDirs($this->getSkeletonDirs($bundle));
344
        }
345
346
        return $this->serializationConfigGenerator;
347
    }
348
349
    public function setFormGenerator(DoctrineFormGenerator $formGenerator)
350
    {
351
        $this->formGenerator = $formGenerator;
352
    }
353
354 View Code Duplication
    protected function getManagerGenerator(BundleInterface $bundle, $entity)
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...
355
    {
356
        if (null === $this->managerGenerator) {
357
            $this->managerGenerator = new DoctrineManagerGenerator($bundle, $entity);
358
            $this->managerGenerator->setSkeletonDirs($this->getSkeletonDirs($bundle));
359
        }
360
361
        return $this->managerGenerator;
362
    }
363
364 View Code Duplication
    protected function getRepositoryGenerator(BundleInterface $bundle, $entity)
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...
365
    {
366
        if (null === $this->repositoryGenerator) {
367
            $this->repositoryGenerator = new DoctrineRepositoryGenerator($bundle, $entity);
368
            $this->repositoryGenerator->setSkeletonDirs($this->getSkeletonDirs($bundle));
369
        }
370
371
        return $this->repositoryGenerator;
372
    }
373
}
374