Completed
Push — master ( 61406b...1dbe37 )
by Ruud
11:21
created

GeneratorBundle/Command/InstallCommand.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\Helper\CommandAssistant;
6
use Sensio\Bundle\GeneratorBundle\Command\GeneratorCommand;
7
use Symfony\Component\Console\Input\ArrayInput;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Question\Question;
10
use Symfony\Component\Console\Style\SymfonyStyle;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputDefinition;
13
use Symfony\Component\Console\Output\OutputInterface;
14
use Sensio\Bundle\GeneratorBundle\Command\Validators;
15
use Symfony\Component\HttpKernel\Kernel;
16
use Symfony\Component\Process\Exception\RuntimeException;
17
use Sensio\Bundle\GeneratorBundle\Command\Helper\QuestionHelper;
18
19
/**
20
 * Kunstmaan installer
21
 */
22
final class InstallCommand extends GeneratorCommand
23
{
24
    /**
25
     * @var int
26
     */
27
    private $commandSteps = 0;
28
29
    /** @var CommandAssistant */
30
    private $assistant;
31
32
    /** @var string */
33
    private $projectDir;
34
35
    /** @var bool */
36
    private $shouldStop = false;
37
38
    /**
39
     * @param string $rootDir
40
     */
41
    public function __construct(string $projectDir)
42
    {
43
        $this->projectDir = $projectDir;
44
45
        parent::__construct();
46
    }
47
48
    protected function configure()
49
    {
50
        $this
51
            ->setName('kuma:install')
52
            ->setDescription('KunstmaanCMS installer.')
53
            ->setDefinition(
54
                new InputDefinition(
55
                    [
56
                        new InputOption('db-installed', '', InputOption::VALUE_NONE, 'Acknowledge that you have setup your database"'),
57
                        new InputOption('demosite', '', InputOption::VALUE_REQUIRED, 'Do you want to create a "demosite"'),
58
                        new InputOption('create-tests', '', InputOption::VALUE_REQUIRED, 'Do you want to create tests for you pages/pageparts'),
59
                        new InputOption('namespace', '', InputOption::VALUE_OPTIONAL, 'The namespace of the bundle to create (only for SF3)'),
60
                        new InputOption('dir', '', InputOption::VALUE_OPTIONAL, 'The directory where to create the bundle (only for SF3)'),
61
                        new InputOption('bundle-name', '', InputOption::VALUE_OPTIONAL, 'The optional bundle name (only for SF3)'),
62
                    ]
63
                )
64
            );
65
    }
66
67 View Code Duplication
    private function initAssistant($input, $output)
68
    {
69
        if (is_null($this->assistant)) {
70
            $this->assistant = new CommandAssistant();
71
            $this->assistant->setQuestionHelper($this->getQuestionHelper());
72
            $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

  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...
73
        }
74
        $this->assistant->setOutput($output);
75
        $this->assistant->setInput($input);
76
    }
77
78
    protected function interact(InputInterface $input, OutputInterface $output)
79
    {
80
        $this->initAssistant($input, $output);
81
82
        $questionHelper = new QuestionHelper();
83
84
        $outputStyle = new SymfonyStyle($input, $output);
85
        $outputStyle->writeln('<info>Installing KunstmaanCms...</info>');
86
        $outputStyle->writeln($this->getKunstmaanLogo());
87
88
        if (Kernel::VERSION_ID >= 40000 && null === $input->getOption('db-installed')) {
89
            $this->shouldStop = !$this->assistant->askConfirmation('We need access to your database. Are the database credentials setup properly? (y/n)', 'y');
90
            if ($this->shouldStop) {
91
                return;
92
            }
93
        }
94
95
        // Only ask namespace for Symfony 3
96
        if (Kernel::VERSION_ID < 40000 && null === $input->getOption('namespace')) {
97
            $question = new Question(
98
                $questionHelper->getQuestion('Bundle namespace', $input->getOption('namespace')),
99
                $input->getOption('namespace')
100
            );
101
            $question->setValidator([Validators::class, 'validateBundleNamespace']);
102
            $namespace = $questionHelper->ask($input, $output, $question);
103
            $input->setOption('namespace', $namespace);
104
            $input->setOption('bundle-name', strtr($namespace, ['\\Bundle\\' => '', '\\' => '']));
105
106
            $dir = $input->getOption('dir') ?: $this->projectDir . '/src';
107
            $input->setOption('dir', $dir);
108
        }
109
110 View Code Duplication
        if (null === $input->getOption('demosite')) {
111
            $demoSiteOption = $this->assistant->askConfirmation('Do you want to create a "demosite"? (y/n)', 'n');
112
            $input->setOption('demosite', $demoSiteOption === true ? 'Yes' : 'No');
113
        }
114
115 View Code Duplication
        if (null === $input->getOption('create-tests')) {
116
            $createTests = $this->assistant->askConfirmation('Do you want to create tests for you pages/pageparts? (y/n)', 'n', '?', false);
117
            $input->setOption('create-tests', $createTests === true ? 'Yes' : 'No');
118
        }
119
120
        $output->writeln('<info>Installation start</info>');
121
    }
122
123
    protected function execute(InputInterface $input, OutputInterface $output)
124
    {
125
        if ($this->shouldStop) {
126
            return;
127
        }
128
129
        $this->initAssistant($input, $output);
130
131
        $defaultSiteOptions = [];
132
        if ($input->getOption('demosite') === 'Yes') {
133
            $defaultSiteOptions['--demosite'] = true;
134
        }
135
136
        if (Kernel::VERSION_ID < 40000) {
137
            $defaultSiteOptions = ['--namespace' => $input->getOption('namespace')];
138
139
            $this->executeCommand($output, 'kuma:generate:bundle', [
140
                '--namespace' => $input->getOption('namespace'),
141
                '--dir' => $input->getOption('dir'),
142
                '--bundle-name' => $input->getOption('bundle-name'),
143
            ]);
144
        }
145
146
        if (Kernel::VERSION_ID >= 40000) {
147
            $this->executeCommand($output, 'kuma:generate:config');
148
        }
149
150
        $this
151
            ->executeCommand($output, 'kuma:generate:default-site', $defaultSiteOptions)
152
            ->executeCommand($output, 'doctrine:database:create')
153
            ->executeCommand($output, 'doctrine:schema:drop', ['--force' => true])
154
            ->executeCommand($output, 'doctrine:schema:create')
155
            ->executeCommand($output, 'doctrine:fixtures:load')
156
            ->executeCommand($output, 'assets:install')
157
        ;
158
159
        if ($input->getOption('create-tests') === 'Yes') {
160
            $adminTestOptions = [];
161
            if (Kernel::VERSION_ID < 40000) {
162
                $adminTestOptions = ['--namespace' => $input->getOption('namespace')];
163
            }
164
165
            $this->executeCommand($output, 'kuma:generate:admin-tests', $adminTestOptions);
166
        }
167
168
        $this->assistant->writeSection('Installation done. Enjoy your KunstmaanCMS', 'bg=green;fg=black');
169
        $this->assistant->writeSection('PRO TIP: If you like to use the default frontend setup, run the buildUI.sh script or run the commands separate to compile the frontend assets. ', 'bg=blue;fg=white');
170
    }
171
172
    protected function executeCommand(OutputInterface $output, $command, array $options = [])
173
    {
174
        $options = array_merge(
175
            [
176
                '--no-debug' => true,
177
            ],
178
            $options
179
        );
180
181
        ++$this->commandSteps;
182
183
        try {
184
            $updateInput = new ArrayInput($options);
185
            $updateInput->setInteractive(true);
186
            $this->getApplication()->find($command)->run($updateInput, $output);
187
            $output->writeln(sprintf('<info>Step %d: "%s" - [OK]</info>', $this->commandSteps, $command));
188
        } catch (RuntimeException $exception) {
189
            $output->writeln(sprintf('<error>Step %d: "%s" - [FAILED]</error>', $this->commandSteps, $command));
190
        } catch (\Throwable $e) {
191
            $output->writeln(sprintf('<error>Step %d: "%s" - [FAILED]</error>', $this->commandSteps, $command));
192
        }
193
194
        return $this;
195
    }
196
197
    protected function getKunstmaanLogo()
198
    {
199
        return '
200
         /$$   /$$                                 /$$                                                  /$$$$$$                         
201
        | $$  /$$/                                | $$                                                 /$$__  $$                        
202
        | $$ /$$/  /$$   /$$ /$$$$$$$   /$$$$$$$ /$$$$$$   /$$$$$$/$$$$   /$$$$$$   /$$$$$$  /$$$$$$$ | $$  \__/ /$$$$$$/$$$$   /$$$$$$$
203
        | $$$$$/  | $$  | $$| $$__  $$ /$$_____/|_  $$_/  | $$_  $$_  $$ |____  $$ |____  $$| $$__  $$| $$      | $$_  $$_  $$ /$$_____/
204
        | $$  $$  | $$  | $$| $$  \ $$|  $$$$$$   | $$    | $$ \ $$ \ $$  /$$$$$$$  /$$$$$$$| $$  \ $$| $$      | $$ \ $$ \ $$|  $$$$$$ 
205
        | $$\  $$ | $$  | $$| $$  | $$ \____  $$  | $$ /$$| $$ | $$ | $$ /$$__  $$ /$$__  $$| $$  | $$| $$    $$| $$ | $$ | $$ \____  $$
206
        | $$ \  $$|  $$$$$$/| $$  | $$ /$$$$$$$/  |  $$$$/| $$ | $$ | $$|  $$$$$$$|  $$$$$$$| $$  | $$|  $$$$$$/| $$ | $$ | $$ /$$$$$$$/
207
        |__/  \__/ \______/ |__/  |__/|_______/    \___/  |__/ |__/ |__/ \_______/ \_______/|__/  |__/ \______/ |__/ |__/ |__/|_______/ 
208
        ';
209
    }
210
211
    protected function createGenerator()
212
    {
213
        // we don't need generator here
214
    }
215
}
216