Completed
Pull Request — master (#2414)
by Ruud
15:13 queued 03:09
created

InstallCommand::execute()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 45
rs 8.5777
c 0
b 0
f 0
ccs 0
cts 38
cp 0
cc 6
nc 13
nop 2
crap 42
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
0 ignored issues
show
Bug introduced by
There is no parameter named $rootDir. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

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