Completed
Push — master ( b659c5...c65770 )
by Michael
10:22
created

YapealSetup::getMenuChoices()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 8
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 0
crap 6
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * Contains class YapealSetup.
5
 *
6
 * PHP version 7.0+
7
 *
8
 * LICENSE:
9
 * This file is part of Yet Another Php Eve Api Library also know as Yapeal
10
 * which can be used to access the Eve Online API data and place it into a
11
 * database.
12
 * Copyright (C) 2016-2017 Michael Cummings
13
 *
14
 * This program is free software: you can redistribute it and/or modify it
15
 * under the terms of the GNU Lesser General Public License as published by the
16
 * Free Software Foundation, either version 3 of the License, or (at your
17
 * option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful, but WITHOUT
20
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
22
 * for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public License
25
 * along with this program. If not, see
26
 * <http://spdx.org/licenses/LGPL-3.0.html>.
27
 *
28
 * You should be able to find a copy of this license in the COPYING-LESSER.md
29
 * file. A copy of the GNU GPL should also be available in the COPYING.md file.
30
 *
31
 * @author    Michael Cummings <[email protected]>
32
 * @copyright 2016-2017 Michael Cummings
33
 * @license   LGPL-3.0+
34
 */
35
namespace Yapeal\Console\Yapeal;
36
37
use Symfony\Component\Console\Command\Command;
38
use Symfony\Component\Console\Helper\QuestionHelper;
39
use Symfony\Component\Console\Input\InputInterface;
40
use Symfony\Component\Console\Input\InputOption;
41
use Symfony\Component\Console\Output\OutputInterface;
42
use Symfony\Component\Console\Question\ChoiceQuestion;
43
use Yapeal\Console\ConfigFileTrait;
44
use Yapeal\Console\VerbosityMappingTrait;
45
use Yapeal\CommonToolsTrait;
46
use Yapeal\Configuration\YamlConfigFile;
47
use Yapeal\Container\ContainerInterface;
48
use Yapeal\Event\EveApiEventEmitterTrait;
49
use Yapeal\Event\YEMAwareInterface;
50
use Yapeal\Sql\CommonSqlQueries;
51
52
/**
53
 * Class YapealSetup.
54
 */
55
class YapealSetup extends Command implements YEMAwareInterface
56
{
57
    use CommonToolsTrait, ConfigFileTrait, EveApiEventEmitterTrait, VerbosityMappingTrait;
58
    /**
59
     * @param string             $name
60
     * @param ContainerInterface $dic
61
     *
62
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
63
     * @throws \Symfony\Component\Console\Exception\LogicException
64
     */
65
    public function __construct(string $name, ContainerInterface $dic)
66
    {
67
        $this->setDescription('Used to setup Yapeal-ng after Composer require or to interactively do so any time');
68
        $this->setName($name);
69
        $this->setDic($dic);
70
        parent::__construct($name);
71
    }
72
    /**
73
     * Configures the current command.
74
     */
75
    public function configure()
76
    {
77
        $help = <<<'HELP'
78
The <info>%command.name%</info> command is an interactive command that can be used
79
to setup Yapeal-ng in an application after being add to the application's
80
`composer.json` file. It will analyze where it is being run from and then ask
81
interactive questions and use their responses to customize an yapeal.yaml file
82
with their settings. It can also be used to run some of the additional console
83
commands if desired like Schema:Creator or Schema:Update etc.
84
HELP;
85
        $this->addOption('askInteractive',
86
            'a|i',
87
            InputOption::VALUE_NONE,
88
            'Ask interactive questions instead of using multiple choice menus');
89
        $this->addConfigFileOption();
90
        $this->setHelp($help);
91
    }
92
    /** @noinspection PhpMissingParentCallCommonInspection */
93
    /**
94
     * Executes the current command.
95
     *
96
     * This method is not abstract because you can use this class
97
     * as a concrete class. In this case, instead of defining the
98
     * execute() method, you set the code to execute by passing
99
     * a Closure to the setCode() method.
100
     *
101
     * @param InputInterface  $input  An InputInterface instance
102
     * @param OutputInterface $output An OutputInterface instance
103
     *
104
     * @return int 0 if everything went fine, or an error code
105
     * @throws \DomainException
106
     * @throws \InvalidArgumentException
107
     * @throws \LogicException When this abstract method is not implemented
108
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
109
     * @throws \Symfony\Component\Console\Exception\LogicException
110
     * @throws \Symfony\Component\Console\Exception\RuntimeException
111
     * @throws \UnexpectedValueException
112
     * @see setCode()
113
     */
114
    protected function execute(InputInterface $input, OutputInterface $output): int
115
    {
116
        if (!$input->isInteractive()) {
117
            $mess = sprintf('<comment>%1$s can not be used in a non-interactive way be sure not to use'
118
                . ' the -n, --no-interaction option</comment>',
119
                $this->getName());
120
            $output->writeln($mess);
121
            return 1;
122
        }
123
        $this->applyVerbosityMap($output);
124
        $options = $input->getOptions();
125
        if (!empty($options['configFile'])) {
126
            $this->processConfigFile($options['configFile'], $this->getDic());
0 ignored issues
show
Compatibility introduced by
$this->getDic() of type object<ArrayAccess> is not a sub-type of object<Yapeal\Container\ContainerInterface>. It seems like you assume a child interface of the interface ArrayAccess to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
127
        }
128
        if (!$options['askInteractive']) {
129
            $this->mainMenu($input, $output);
130
        } else {
131
            $this->startInteractive($input, $output);
0 ignored issues
show
Unused Code introduced by
The call to the method Yapeal\Console\Yapeal\Ya...tup::startInteractive() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
132
        }
133
        return 0;
134
    }
135
    /** @noinspection PhpMissingParentCallCommonInspection */
136
    /**
137
     * @param string $option
138
     * @param string $text
139
     */
140
    private function addMenuChoice(string $option, string $text)
141
    {
142
        $this->menuChoices[$option] = $text;
143
    }
144
    /**
145
     * @return string[]
146
     * @throws \LogicException
147
     */
148
    private function getMenuChoices(): array
149
    {
150
        if (null === $this->menuChoices) {
151
            $mess = 'Trying to access menuChoices before it was set';
152
            throw new \LogicException($mess);
153
        }
154
        return $this->menuChoices;
155
    }
156
    /**
157
     * @return bool
158
     * @throws \LogicException
159
     */
160
    private function hasConfigFile(): bool
161
    {
162
        if (null === $this->configFile) {
163
            $this->configFile = false;
164
            $dic = $this->getDic();
165
            /** @noinspection PhpParamsInspection */
166
            if (array_key_exists('Yapeal.vendorParentDir', $dic)) {
167
                $appConfigFile = $dic['Yapeal.vendorParentDir'] . 'config/yapeal.yaml';
168
                $this->configFile = is_readable($appConfigFile) && is_file($appConfigFile);
169
            }
170
        }
171
        return $this->configFile;
172
    }
173
    /**
174
     * @return bool
175
     * @throws \LogicException
176
     */
177
    private function hasSchema(): bool
178
    {
179
        if (null === $this->schema) {
180
            $this->schema = true;
181
            /**
182
             * @var ContainerInterface|array        $dic
183
             * @var \Yapeal\Sql\ConnectionInterface $pdo
184
             * @var CommonSqlQueries                $csq
185
             */
186
            $dic = $this->getDic();
187
            $result = false;
188
            $sql = $this->getCsq()
189
                ->getSchemaNames();
190
            try {
191
                $pdo = $dic['Yapeal.Sql.Callable.Connection'];
192
                $result = $pdo->query($sql);
193
            } catch (\PDOException $exc) {
194
                $this->schema = false;
195
            }
196
            if (false === $result) {
197
                $this->schema = false;
198
            }
199
            $result = array_values($result->fetchAll(\PDO::FETCH_COLUMN));
200
            $schemaName = $dic['Yapeal.Sql.Platforms.' . $dic['Yapeal.Sql.platform'] . '.schema'];
201
            if (!in_array($schemaName, $result, false)) {
202
                $this->schema = false;
203
            }
204
        }
205
        return $this->schema;
206
    }
207
    /**
208
     * @param InputInterface  $input
209
     * @param OutputInterface $output
210
     *
211
     * @throws \LogicException
212
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
213
     * @throws \Symfony\Component\Console\Exception\LogicException
214
     * @throws \Symfony\Component\Console\Exception\RuntimeException
215
     */
216
    private function mainMenu(InputInterface $input, OutputInterface $output)
217
    {
218
        $this->resetMenu();
219
        $this->addMenuChoice('1', 'Switch from menus to asking interactive questions');
220
        $text = 'Create/edit application yapeal.yaml file';
221
        $this->addMenuChoice('2', $text);
222
        $text = 'Create/update Yapeal-ng schema';
223
        $this->addMenuChoice('3', $text);
224
        $this->addMenuChoice('x', 'Exit command');
225
        $prompt = 'What do you want to do?(x)';
226
        /**
227
         * @var QuestionHelper $question
228
         */
229
        $question = $this->getHelper('question');
230
        $choice = new ChoiceQuestion($prompt, $this->getMenuChoices(), 'x');
231
        $answer = $question->ask($input, $output, $choice);
232
        switch ($answer) {
233
            case 'x':
234
                break;
235
            case '1': // Switch from menus to asking interactive questions
236
                break;
237
            case '2': // Create/update yapeal.yaml file
238
                $this->yamlMenu($input, $output);
239
                break;
240
            case '3': // Create/update schema
241
                break;
242
            default:
243
                break;
244
        }
245
    }
246
    private function resetMenu()
247
    {
248
        $this->menuChoices = [];
249
    }
250
    /**
251
     * @param InputInterface  $input
252
     * @param OutputInterface $output
253
     */
254
    private function startInteractive(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Unused Code introduced by
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...
Unused Code introduced by
The parameter $output 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...
255
    {
256
    }
257
    /**
258
     * @param InputInterface  $input
259
     * @param OutputInterface $output
260
     *
261
     * @throws \LogicException
262
     */
263
    private function yamlMenu(InputInterface $input, OutputInterface $output)
0 ignored issues
show
Unused Code introduced by
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...
Unused Code introduced by
The parameter $output 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...
264
    {
265
        if ($this->hasConfigFile()) {
266
            $ycf = new YamlConfigFile($this->getDic()['Yapeal.vendorParentDir'] . 'config');
267
            $this->yamlFile = $ycf->read()
268
                ->flattenYaml();
269
        }
270
    }
271
    /**
272
     * @var bool $configFile
273
     */
274
    private $configFile;
275
    /**
276
     * @var string[] $menuChoices
277
     */
278
    private $menuChoices;
279
    /**
280
     * @var bool $schema
281
     */
282
    private $schema;
283
    /**
284
     * @var array $yamlFile
285
     */
286
    private $yamlFile;
287
}
288
289