GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

CrudGeneratorCommand   C
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 335
Duplicated Lines 5.97 %

Coupling/Cohesion

Components 1
Dependencies 21

Test Coverage

Coverage 87.14%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 27
c 1
b 0
f 0
lcom 1
cbo 21
dl 20
loc 335
ccs 183
cts 210
cp 0.8714
rs 6.1111

10 Methods

Rating   Name   Duplication   Size   Complexity  
A configure() 0 51 1
A createGenerator() 0 4 1
A getSkeletonDirs() 0 16 4
C interact() 0 117 7
C execute() 0 86 7
A generateFilter() 0 4 1
A getFilterGenerator() 10 10 2
A getFormGenerator() 10 10 2
A setFilterGenerator() 0 4 1
A setFormCrudGenerator() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/*
4
 * This file is part of the PetkoparaCrudGeneratorBundle
5
 *
6
 * (c) Petko Petkov <[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 Petkopara\CrudGeneratorBundle\Command;
13
14
use Doctrine\Bundle\DoctrineBundle\Mapping\DisconnectedMetadataFactory;
15
use Petkopara\CrudGeneratorBundle\Configuration\ConfigurationBuilder;
16
use Petkopara\CrudGeneratorBundle\Generator\Guesser\MetadataGuesser;
17
use Petkopara\CrudGeneratorBundle\Generator\PetkoparaCrudGenerator;
18
use Petkopara\CrudGeneratorBundle\Generator\PetkoparaFilterGenerator;
19
use Petkopara\CrudGeneratorBundle\Generator\PetkoparaFormGenerator;
20
use Sensio\Bundle\GeneratorBundle\Command\AutoComplete\EntitiesAutoCompleter;
21
use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand;
22
use Sensio\Bundle\GeneratorBundle\Command\Validators;
23
use Symfony\Component\Config\Definition\Exception\Exception;
24
use Symfony\Component\Console\Input\InputArgument;
25
use Symfony\Component\Console\Input\InputInterface;
26
use Symfony\Component\Console\Input\InputOption;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\Console\Question\ConfirmationQuestion;
29
use Symfony\Component\Console\Question\Question;
30
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
31
use Symfony\Component\Yaml\Exception\RuntimeException;
32
33
class CrudGeneratorCommand extends GenerateDoctrineCrudCommand
34
{
35
36
    const FILTER_TYPE_FORM = 'form';
37
    const FILTER_TYPE_INPUT = 'input';
38
    const FILTER_TYPE_NONE = 'none';
39
40
    protected $generator;
41
    protected $formGenerator;
42
    private $filterGenerator;
43
44 15
    protected function configure()
45
    {
46
47 15
        $this
48 15
                ->setName('petkopara:generate:crud')
49 15
                ->setDescription('A CRUD generator with pagination, filters, bulk delete and bootstrap markdown.')
50 15
                ->setDefinition(array(
51 15
                    new InputArgument('entity', InputArgument::OPTIONAL, 'The entity class name to initialize (shortcut notation)'),
52 15
                    new InputOption('entity', '', InputOption::VALUE_REQUIRED, 'The entity class name to initialize (shortcut notation)'),
53 15
                    new InputOption('route-prefix', 'r', InputOption::VALUE_REQUIRED, 'The route prefix'),
54 15
                    new InputOption('template', 't', InputOption::VALUE_REQUIRED, 'The base template which will be extended by the templates', 'PetkoparaCrudGeneratorBundle::base.html.twig'),
55 15
                    new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'The format used for configuration files (php, xml, yml, or annotation)', 'annotation'),
56 15
                    new InputOption('overwrite', 'o', InputOption::VALUE_NONE, 'Overwrite any existing controller or form class when generating the CRUD contents'),
57 15
                    new InputOption('bundle-views', 'b', InputOption::VALUE_NONE, 'Whether or not to store the view files in app/Resources/views/ or in bundle dir'),
58 15
                    new InputOption('without-sorting', 'wsr', InputOption::VALUE_NONE, 'Whether or not have sorting in the index'),
59 15
                    new InputOption('without-page-size', 'wps', InputOption::VALUE_NONE, 'Whether or not to show items per page select in the index'),
60 15
                    new InputOption('without-write', 'ww', InputOption::VALUE_NONE, 'Whether or not to generate create, new and delete actions'),
61 15
                    new InputOption('without-show', 'ws', InputOption::VALUE_NONE, 'Whether or not to generate create, new and delete actions'),
62 15
                    new InputOption('without-bulk', 'wb', InputOption::VALUE_NONE, 'Whether or not to generate bulk actions'),
63 15
                    new InputOption('filter-type', 'ft', InputOption::VALUE_REQUIRED, 'What type of filtrations to be used. Multi search input, Form filter or none', 'form'),
64 15
                ))
65 15
                ->setHelp(<<<EOT
66
The <info>%command.name%</info> command generates a CRUD based on a Doctrine entity.
67
68
The default command only generates the list and show actions.
69
70
<info>php %command.full_name% --entity=AcmeBlogBundle:Post --route-prefix=post_admin</info>
71
72
Using the --without-write to not generate the new, edit, bulk and delete actions.
73
                
74
Using the --bundle-views option store the view files in the bundles dir.
75
                
76
Using the --without-bulk  use this option tp not generate bulk actions code.
77
                
78
Using the --template option allows to set base template from which the crud views to overide.
79
                
80
<info>php %command.full_name% doctrine:generate:crud --entity=AcmeBlogBundle:Post --route-prefix=post_admin </info>
81
82
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:
83
84
<info>BUNDLE_PATH/Resources/PetkoparaCrudGeneratorBundle/skeleton/crud
85
APP_PATH/Resources/PetkoparaCrudGeneratorBundle/skeleton/crud</info>
86
87
And
88
89
<info>BUNDLE_PATH/Resources/PetkoparaCrudGeneratorBundle/skeleton/form
90
APP_PATH/Resources/PetkoparaCrudGeneratorBundle/skeleton/form</info>
91
92
EOT
93 15
        );
94 15
    }
95
96
    protected function createGenerator($bundle = null)
97
    {
98
        return new PetkoparaCrudGenerator($this->getContainer()->get('filesystem'), $this->getContainer()->getParameter('kernel.root_dir'));
99
    }
100
101
    protected function getSkeletonDirs(BundleInterface $bundle = null)
102
    {
103
        $skeletonDirs = array();
104
        if (isset($bundle) && is_dir($dir = $bundle->getPath() . '/Resources/PetkoparaCrudGeneratorBundle/skeleton')) {
105
            $skeletonDirs[] = $dir;
106
        }
107
108
        if (is_dir($dir = $this->getContainer()->get('kernel')->getRootdir() . '/Resources/PetkoparaCrudGeneratorBundle/skeleton')) {
109
            $skeletonDirs[] = $dir;
110
        }
111
112
        $skeletonDirs[] = $this->getContainer()->get('kernel')->locateResource('@PetkoparaCrudGeneratorBundle/Resources/skeleton');
113
        $skeletonDirs[] = $this->getContainer()->get('kernel')->locateResource('@PetkoparaCrudGeneratorBundle/Resources');
114
115
        return $skeletonDirs;
116
    }
117
118 11
    protected function interact(InputInterface $input, OutputInterface $output)
119
    {
120
121 11
        $questionHelper = $this->getQuestionHelper();
122 11
        $questionHelper->writeSection($output, 'Welcome to the Petkopara CRUD generator');
123
124
        // namespace
125 11
        $output->writeln(array(
126 11
            '',
127 11
            'This command helps you generate CRUD controllers and templates.',
128 11
            '',
129 11
            'First, give the name of the existing entity for which you want to generate a CRUD',
130 11
            '(use the shortcut notation like <comment>AcmeBlogBundle:Post</comment>)',
131 11
            '',
132 11
        ));
133
134 11
        if ($input->hasArgument('entity') && $input->getArgument('entity') != '') {
135
            $input->setOption('entity', $input->getArgument('entity'));
136
        }
137
138 11
        $question = new Question($questionHelper->getQuestion('The Entity shortcut name', $input->getOption('entity')), $input->getOption('entity'));
139 11
        $question->setValidator(array('Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateEntityName'));
140
141
142 11
        $autocompleter = new EntitiesAutoCompleter($this->getContainer()->get('doctrine')->getManager());
143 11
        $autocompleteEntities = $autocompleter->getSuggestions();
144 11
        $question->setAutocompleterValues($autocompleteEntities);
145 11
        $entity = $questionHelper->ask($input, $output, $question);
146
147 11
        $input->setOption('entity', $entity);
148 11
        list($bundle, $entity) = $this->parseShortcutNotation($entity);
149
150
        try {
151 11
            $entityClass = $this->getContainer()->get('doctrine')->getAliasNamespace($bundle) . '\\' . $entity;
152 11
            $this->getEntityMetadata($entityClass);
153 11
        } catch (\Exception $e) {
154
            throw new \RuntimeException(sprintf('Entity "%s" does not exist in the "%s" bundle. You may have mistyped the bundle name or maybe the entity doesn\'t exist yet (create it first with the "doctrine:generate:entity" command).', $entity, $bundle));
155
        }
156
157
        // write?
158 11
        $withoutWrite = $input->getOption('without-write') ? true : false; //default false
159 11
        $output->writeln(array(
160 11
            '',
161 11
            'By default, the generator creates all actions: list and show, new, update, and delete.',
162 11
            'You can also skip it and to generate only "list and show" actions:',
163 11
            '',
164 11
        ));
165 11
        $question = new ConfirmationQuestion($questionHelper->getQuestion('Do you want to skip generating of the "write" actions', $withoutWrite ? 'yes' : 'no', '?', $withoutWrite), $withoutWrite);
166 11
        $withoutWrite = $questionHelper->ask($input, $output, $question);
167 11
        $input->setOption('without-write', $withoutWrite);
168
169
        // filters?
170 11
        $filterType = $input->getOption('filter-type');
171 11
        $output->writeln(array(
172 11
            '',
173 11
            'By default, the generator generate filter code.',
174 11
             '<comment>form</comment> to use LexikFormFilterBundle to search in the entity.',
175 11
             '<comment>input</comment> to use PetkoparaMultiSearchBundle to search only with one input in the entity.',
176 11
             '<comment>none</comment> use this to not generate any filter code.',
177 11
            '',
178 11
        ));
179 11
        $question = new Question($questionHelper->getQuestion('Filter Type (form, input, none)', $filterType), $filterType);
180 11
        $question->setValidator(array('Petkopara\CrudGeneratorBundle\Command\CrudValidators', 'validateFilterType'));
181 11
        $filterType = $questionHelper->ask($input, $output, $question);
182 11
        $input->setOption('filter-type', $filterType);
183
184
185
        // template?
186 11
        $template = $input->getOption('template');
187 11
        $output->writeln(array(
188 11
            '',
189 11
            'By default, the created views extends the CrudGeneratorBundle::base.html.twig',
190 11
            'You can also set your template which the views to extend, for example base.html.twig ',
191 11
            '',
192 11
        ));
193 11
        $question = new Question($questionHelper->getQuestion('Base template for the views', $template), $template);
194 11
        $template = $questionHelper->ask($input, $output, $question);
195 11
        $input->setOption('template', $template);
196
197
198
        // format
199 11
        $format = $input->getOption('format');
200 11
        $output->writeln(array(
201 11
            '',
202 11
            'Determine the format to use for the generated CRUD.',
203 11
            '',
204 11
        ));
205 11
        $question = new Question($questionHelper->getQuestion('Configuration format (yml, xml, php, or annotation)', $format), $format);
206 11
        $question->setValidator(array('Sensio\Bundle\GeneratorBundle\Command\Validators', 'validateFormat'));
207 11
        $format = $questionHelper->ask($input, $output, $question);
208 11
        $input->setOption('format', $format);
209
210
        // route prefix
211 11
        $prefix = $this->getRoutePrefix($input, $entity);
212 11
        $output->writeln(array(
213 11
            '',
214 11
            'Determine the routes prefix (all the routes will be "mounted" under this',
215 11
            'prefix: /prefix/, /prefix/new, ...).',
216 11
            '',
217 11
        ));
218 11
        $prefix = $questionHelper->ask($input, $output, new Question($questionHelper->getQuestion('Routes prefix', '/' . $prefix), '/' . $prefix));
219 11
        $input->setOption('route-prefix', $prefix);
220
221
        // summary
222 11
        $output->writeln(array(
223 11
            '',
224 11
            $this->getHelper('formatter')->formatBlock('Summary before generation', 'bg=blue;fg=white', true),
0 ignored issues
show
Bug introduced by
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...
225 11
            '',
226 11
            sprintf('You are going to generate a CRUD controller for "<info>%s:%s</info>"', $bundle, $entity),
227 11
            sprintf('Using the "<info>%s</info>" format.', $format),
228 11
            sprintf('Route prefix "<info>%s</info>" format.', $prefix),
229 11
            sprintf('Base template "<info>%s</info>".', $template),
230 11
            sprintf('With write "<info>%s</info>".', (!$withoutWrite) ? 'yes' : 'no'),
231 11
            sprintf('Filters "<info>%s</info>".', $filterType),
232 11
            '',
233 11
        ));
234 11
    }
235
236
    /**
237
     * @see Command
238
     */
239 15
    protected function execute(InputInterface $input, OutputInterface $output)
240
    {
241 15
        $questionHelper = $this->getQuestionHelper();
242
243 15
        if ($input->isInteractive()) {
244 11
            $question = new ConfirmationQuestion($questionHelper->getQuestion('Do you confirm generation', 'yes', '?'), true);
245 11
            if (!$questionHelper->ask($input, $output, $question)) {
246
                $output->writeln('<error>Command aborted</error>');
247
                return 1;
248
            }
249 11
        }
250
251 15
        $entity = Validators::validateEntityName($input->getOption('entity'));
252 15
        list($bundle, $entity) = $this->parseShortcutNotation($entity);
253
254
        //get the options
255 15
        $format = Validators::validateFormat($input->getOption('format'));
256 15
        $prefix = $this->getRoutePrefix($input, $entity);
257 15
        $withoutWrite = $input->getOption('without-write'); //default with write
258 15
        $filterType = CrudValidators::validateFilterType($input->getOption('filter-type'));
259 15
        $withoutBulk = $input->getOption('without-bulk');
260 15
        $withoutShow = $input->getOption('without-show');
261 15
        $withoutSorting = $input->getOption('without-sorting');
262 15
        $withoutPageSize = $input->getOption('without-page-size');
263 15
        $bundleViews = $input->getOption('bundle-views');
264 15
        $template = $input->getOption('template');
265
266 15
        $forceOverwrite = $input->getOption('overwrite');
267
268 15
        $questionHelper->writeSection($output, 'CRUD generation');
269
270
        try {
271 15
            $entityClass = $this->getContainer()->get('doctrine')->getAliasNamespace($bundle) . '\\' . $entity;
272 15
            $metadata = $this->getEntityMetadata($entityClass);
273 15
        } catch (Exception $e) {
274
            throw new RuntimeException(sprintf('Entity "%s" does not exist in the "%s" bundle. Create it with the "doctrine:generate:entity" command and then execute this command again.', $entity, $bundle));
275
        }
276
277 15
        $bundle = $this->getContainer()->get('kernel')->getBundle($bundle);
278
279
280 15
        $configBuilder = new ConfigurationBuilder();
281
        $configuration = $configBuilder
282 15
                ->setBaseTemplate($template)
283 15
                ->setBundleViews($bundleViews)
284 15
                ->setFilterType($filterType)
285 15
                ->setWithoutWrite($withoutWrite)
286 15
                ->setWithoutBulk($withoutBulk)
287 15
                ->setWithoutShow($withoutShow)
288 15
                ->setWithoutSorting($withoutSorting)
289 15
                ->setWithoutPageSize($withoutPageSize)
290 15
                ->setOverwrite($forceOverwrite)
291 15
                ->setFormat($format)
292 15
                ->setRoutePrefix($prefix)
293 15
                ->getConfiguration()
294 15
        ;
295 15
        $generator = $this->getGenerator($bundle);
296
297 15
        $generator->generateCrud($bundle, $entity, $metadata[0], $configuration);
298
299 15
        $output->writeln('Generating the CRUD code: <info>OK</info>');
300
301 15
        $errors = array();
302 15
        $runner = $questionHelper->getRunner($output, $errors);
303
304
        // form
305 15
        if ($withoutWrite === false) {
306 13
            $this->generateForm($bundle, $entity, $metadata, $forceOverwrite);
307 13
            $output->writeln('Generating the Form code: <info>OK</info>');
308 13
        }
309
310 15
        if ($filterType !== self::FILTER_TYPE_NONE) {
311
312 14
            $this->generateFilter($bundle, $entity, $metadata, $forceOverwrite, $filterType);
313 14
            $output->writeln('Generating the Filter code: <info>OK</info>');
314 14
        }
315
        // routing
316 15
        $output->write('Updating the routing: ');
317 15
        if ('annotation' != $format) {
318 4
            $runner($this->updateRouting($questionHelper, $input, $output, $bundle, $format, $entity, $prefix));
319 4
        } else {
320 11
            $runner($this->updateAnnotationRouting($bundle, $entity, $prefix));
321
        }
322
323 15
        $questionHelper->writeGeneratorSummary($output, $errors);
324 15
    }
325
326
    /**
327
     * Tries to generate filtlers if they don't exist yet and if we need write operations on entities.
328
     * @param string $entity
329
     */
330 14
    protected function generateFilter($bundle, $entity, $metadata, $forceOverwrite = false, $type = self::FILTER_TYPE_INPUT)
331
    {
332 14
        $this->getFilterGenerator($bundle)->generate($bundle, $entity, $metadata[0], $forceOverwrite, $type);
333 14
    }
334
335 14 View Code Duplication
    protected function getFilterGenerator($bundle = null)
0 ignored issues
show
Duplication introduced by
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...
336
    {
337 14
        if (null === $this->filterGenerator) {
338
            $metadataGuesser = new MetadataGuesser(new DisconnectedMetadataFactory($this->getContainer()->get('doctrine')));
339
            $this->filterGenerator = new PetkoparaFilterGenerator($metadataGuesser);
340
            $this->filterGenerator->setSkeletonDirs($this->getSkeletonDirs($bundle));
341
        }
342
343 14
        return $this->filterGenerator;
344
    }
345
346 13 View Code Duplication
    protected function getFormGenerator($bundle = null)
0 ignored issues
show
Duplication introduced by
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...
347
    {
348 13
        if (null === $this->formGenerator) {
349
            $metadataGuesser = new MetadataGuesser(new DisconnectedMetadataFactory($this->getContainer()->get('doctrine')));
350
            $this->formGenerator = new PetkoparaFormGenerator($metadataGuesser);
351
            $this->formGenerator->setSkeletonDirs($this->getSkeletonDirs($bundle));
352
        }
353
354 13
        return $this->formGenerator;
355
    }
356
357 15
    public function setFilterGenerator(PetkoparaFilterGenerator $filterGenerator)
358
    {
359 15
        $this->filterGenerator = $filterGenerator;
360 15
    }
361
362 15
    public function setFormCrudGenerator(PetkoparaFormGenerator $formGenerator)
363
    {
364 15
        $this->formGenerator = $formGenerator;
365 15
    }
366
367
}
368