Completed
Push — master ( 06c1ce...67d37c )
by Jeroen
06:20
created

Command/GenerateAdminListCommand.php (1 issue)

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
namespace Kunstmaan\GeneratorBundle\Command;
4
5
use Kunstmaan\GeneratorBundle\Generator\AdminListGenerator;
6
use Kunstmaan\GeneratorBundle\Helper\EntityValidator;
7
use Kunstmaan\GeneratorBundle\Helper\GeneratorUtils;
8
use Kunstmaan\GeneratorBundle\Helper\Sf4AppBundle;
9
use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCommand;
10
use Sensio\Bundle\GeneratorBundle\Command\Helper\QuestionHelper;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputOption;
13
use Symfony\Component\Console\Output\OutputInterface;
14
use Symfony\Component\Console\Question\ConfirmationQuestion;
15
use Symfony\Component\Console\Question\Question;
16
use Symfony\Component\HttpKernel\Bundle\Bundle;
17
use Symfony\Component\HttpKernel\Kernel;
18
19
/**
20
 * Generates a KunstmaanAdminList
21
 */
22
class GenerateAdminListCommand extends GenerateDoctrineCommand
23
{
24
    /**
25
     * @see Command
26
     */
27
    protected function configure()
28
    {
29
        $this
30
            ->setDefinition(
31
                array(
32
                    new InputOption(
33
                        'entity',
34
                        '',
35
                        InputOption::VALUE_REQUIRED,
36
                        'The entity class name to create an admin list for (shortcut notation)'
37
                    ),
38
                    new InputOption(
39
                        'sortfield',
40
                        '',
41
                        InputOption::VALUE_OPTIONAL,
42
                        'The name of the sort field if entity needs to be sortable'
43
                    ),
44
                )
45
            )
46
            ->setDescription('Generates a KunstmaanAdminList')
47
            ->setHelp(
48
                <<<'EOT'
49
                The <info>kuma:generate:adminlist</info> command generates an AdminList for a Doctrine ORM entity.
50
51
<info>php bin/console kuma:generate:adminlist Bundle:Entity</info>
52
EOT
53
            )
54
            ->setName('kuma:generate:adminlist');
55
    }
56
57
    /**
58
     * Executes the command.
59
     *
60
     * @param InputInterface  $input  An InputInterface instance
61
     * @param OutputInterface $output An OutputInterface instance
62
     *
63
     * @throws \RuntimeException
64
     *
65
     * @return int|null|void
66
     */
67
    protected function execute(InputInterface $input, OutputInterface $output)
68
    {
69
        $questionHelper = $this->getQuestionHelper();
70
71
        GeneratorUtils::ensureOptionsProvided($input, array('entity'));
72
73
        $entity = EntityValidator::validate($input->getOption('entity'));
74
        if (Kernel::VERSION_ID < 40000) {
75
            list($bundle, $entity) = $this->parseShortcutNotation($entity);
76
77
            $entityClass = $this->getContainer()->get('doctrine')->getAliasNamespace($bundle) . '\\' . $entity;
78
            $metadata = $this->getEntityMetadata($entityClass)[0];
79
            $bundle = $this->getContainer()->get('kernel')->getBundle($bundle);
80
        } else {
81
            $entityClass = $entity;
82
            $em = $this->getContainer()->get('doctrine')->getManager();
83
84
            $metadata = $em->getClassMetadata($entityClass);
85
            $bundle = new Sf4AppBundle($this->getContainer()->getParameter('kernel.project_dir'));
86
        }
87
88
        $questionHelper->writeSection($output, 'AdminList Generation');
89
90
        $generator = $this->getGenerator($this->getApplication()->getKernel()->getBundle('KunstmaanGeneratorBundle'));
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

  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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
91
        $generator->setQuestion($questionHelper);
92
        $generator->generate($bundle, $entityClass, $metadata, $output, $input->getOption('sortfield'));
93
94
        if (Kernel::VERSION_ID >= 40000) {
95
            return;
96
        }
97
98
        $parts = explode('\\', $entity);
99
        $entityClass = array_pop($parts);
100
101
        $this->updateRouting($questionHelper, $input, $output, $bundle, $entityClass);
102
103
        return 0;
104
    }
105
106
    /**
107
     * Interacts with the user.
108
     *
109
     * @param InputInterface  $input  An InputInterface instance
110
     * @param OutputInterface $output An OutputInterface instance
111
     */
112
    protected function interact(InputInterface $input, OutputInterface $output)
113
    {
114
        $questionHelper = $this->getQuestionHelper();
115
        $questionHelper->writeSection($output, 'Welcome to the Kunstmaan admin list generator');
116
117
        // entity
118
        $entity = null;
119
120
        try {
121
            $entity = $input->getOption('entity') ? EntityValidator::validate($input->getOption('entity')) : null;
122
        } catch (\Exception $error) {
123
            $output->writeln(
124
                $questionHelper->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error')
125
            );
126
        }
127
128
        if (Kernel::VERSION_ID < 40000) {
129
            $message = 'You must use the shortcut notation like <comment>AcmeBlogBundle:Post</comment>.';
130
        } else {
131
            $message = 'You must use the FQCN like <comment>\App\Entity\Post</comment>.';
132
        }
133
134
        if (is_null($entity)) {
135
            $output->writeln(
136
                array(
137
                    '',
138
                    'This command helps you to generate an admin list for your entity.',
139
                    '',
140
                    $message,
141
                    '',
142
                )
143
            );
144
145
            if (Kernel::VERSION_ID < 40000) {
146
                $message = 'The entity shortcut name';
147
            } else {
148
                $message = 'The entity FQCN';
149
            }
150
151
            $question = new Question($questionHelper->getQuestion($message, $entity), $entity);
152
            $question->setValidator(['\Kunstmaan\GeneratorBundle\Helper\EntityValidator', 'validate']);
153
            $entity = $questionHelper->ask($input, $output, $question);
154
            $input->setOption('entity', $entity);
155
156
            $question = new Question($questionHelper->getQuestion('The name of the sort field if entity needs to be sortable', false, '?'), false);
157
            $sortfield = $questionHelper->ask($input, $output, $question);
158
            $input->setOption('sortfield', $sortfield);
159
        }
160
    }
161
162
    /**
163
     * @param QuestionHelper  $questionHelper The question helper
164
     * @param InputInterface  $input          The command input
165
     * @param OutputInterface $output         The command output
166
     * @param Bundle          $bundle         The bundle
167
     * @param string          $entityClass    The classname of the entity
168
     */
169
    protected function updateRouting(
170
        QuestionHelper $questionHelper,
171
        InputInterface $input,
172
        OutputInterface $output,
173
        Bundle $bundle,
174
        $entityClass
175
    ) {
176
        $adminKey = $this->getContainer()->getParameter('kunstmaan_admin.admin_prefix');
177
        $auto = true;
178
        $multilang = false;
179
        if ($input->isInteractive()) {
180
            $confirmationQuestion = new ConfirmationQuestion(
181
                $questionHelper->getQuestion('Is it a multilanguage site', 'yes', '?'), true
182
            );
183
            $multilang = $questionHelper->ask($input, $output, $confirmationQuestion);
184
            $confirmationQuestion = new ConfirmationQuestion(
185
                $questionHelper->getQuestion('Do you want to update the routing automatically', 'yes', '?'), true
186
            );
187
            $auto = $questionHelper->ask($input, $output, $confirmationQuestion);
188
        }
189
190
        $prefix = $multilang ? '/{_locale}' : '';
191
192
        $code = sprintf("%s:\n", strtolower($bundle->getName()) . '_' . strtolower($entityClass) . '_admin_list');
193
        $code .= sprintf("    resource: '@%s/Controller/%sAdminListController.php'\n", $bundle->getName(), $entityClass, "'");
194
        $code .= "    type:     annotation\n";
195
        $code .= sprintf("    prefix:   %s/%s/%s/\n", $prefix, $adminKey, strtolower($entityClass));
196
        if ($multilang) {
197
            $code .= "    requirements:\n";
198
            $code .= "         _locale: \"%requiredlocales%\"\n";
199
        }
200
201
        if ($auto) {
202
            $file = $bundle->getPath() . '/Resources/config/routing.yml';
203
            $content = '';
204
205
            if (file_exists($file)) {
206
                $content = file_get_contents($file);
207
            } elseif (!is_dir($dir = dirname($file))) {
208
                mkdir($dir, 0777, true);
209
            }
210
211
            $content .= "\n";
212
            $content .= $code;
213
214
            if (false === file_put_contents($file, $content)) {
215
                $output->writeln(
216
                    $questionHelper->getHelperSet()->get('formatter')->formatBlock(
217
                        'Failed adding the content automatically',
218
                        'error'
219
                    )
220
                );
221
            } else {
222
                return;
223
            }
224
        }
225
226
        $output->writeln('Add the following to your routing.yml');
227
        $output->writeln('/*******************************/');
228
        $output->write($code);
229
        $output->writeln('/*******************************/');
230
    }
231
232
    /**
233
     * KunstmaanTestBundle_TestEntity:
234
     * resource: "@KunstmaanTestBundle/Controller/TestEntityAdminListController.php"
235
     * type:     annotation
236
     * prefix:   /{_locale}/%kunstmaan_admin.admin_prefix%/testentity/
237
     * requirements:
238
     * _locale: "%requiredlocales%"
239
     */
240
    protected function createGenerator()
241
    {
242
        return new AdminListGenerator(GeneratorUtils::getFullSkeletonPath('adminlist'));
243
    }
244
}
245