Failed Conditions
Push — master ( 316c3c...bbd704 )
by Bernhard
8s
created

ModuleCommandHandler::printNotLoadableModules()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5.0031

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 34
ccs 19
cts 20
cp 0.95
rs 8.439
cc 5
eloc 19
nc 5
nop 3
crap 5.0031
1
<?php
2
3
/*
4
 * This file is part of the puli/cli package.
5
 *
6
 * (c) Bernhard Schussek <[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 Puli\Cli\Handler;
13
14
use Puli\Cli\Style\PuliTableStyle;
15
use Puli\Cli\Util\StringUtil;
16
use Puli\Manager\Api\Environment;
17
use Puli\Manager\Api\Module\Module;
18
use Puli\Manager\Api\Module\ModuleList;
19
use Puli\Manager\Api\Module\ModuleManager;
20
use Puli\Manager\Api\Module\ModuleState;
21
use RuntimeException;
22
use Webmozart\Console\Api\Args\Args;
23
use Webmozart\Console\Api\IO\IO;
24
use Webmozart\Console\UI\Component\Table;
25
use Webmozart\Expression\Expr;
26
use Webmozart\PathUtil\Path;
27
28
/**
29
 * Handles the "module" command.
30
 *
31
 * @since  1.0
32
 *
33
 * @author Bernhard Schussek <[email protected]>
34
 */
35
class ModuleCommandHandler
36
{
37
    /**
38
     * @var array
39
     */
40
    private static $stateStrings = array(
41
        ModuleState::ENABLED => 'enabled',
42
        ModuleState::NOT_FOUND => 'not-found',
43
        ModuleState::NOT_LOADABLE => 'not-loadable',
44
    );
45
46
    /**
47
     * @var ModuleManager
48
     */
49
    private $moduleManager;
50
51
    /**
52
     * Creates the handler.
53
     *
54
     * @param ModuleManager $moduleManager The module manager
55
     */
56 20
    public function __construct(ModuleManager $moduleManager)
57
    {
58 20
        $this->moduleManager = $moduleManager;
59 20
    }
60
61
    /**
62
     * Handles the "module --list" command.
63
     *
64
     * @param Args $args The console arguments
65
     * @param IO   $io   The I/O
66
     *
67
     * @return int The status code
68
     */
69 11
    public function handleList(Args $args, IO $io)
70
    {
71 11
        $modules = $this->getSelectedModules($args);
72
73 11
        if ($args->isOptionSet('format')) {
74 1
            $this->printModulesWithFormat($io, $modules, $args->getOption('format'));
75
        } else {
76 10
            $this->printModulesByState($io, $modules, $this->getSelectedStates($args));
77
        }
78
79 11
        return 0;
80
    }
81
82
    /**
83
     * Handles the "module --install" command.
84
     *
85
     * @param Args $args The console arguments
86
     *
87
     * @return int The status code
88
     */
89 5
    public function handleInstall(Args $args)
90
    {
91 5
        $moduleName = $args->getArgument('name');
92 5
        $installPath = Path::makeAbsolute($args->getArgument('path'), getcwd());
93 5
        $installer = $args->getOption('installer');
94 5
        $env = $args->isOptionSet('dev') ? Environment::DEV : Environment::PROD;
95
96 5
        $this->moduleManager->installModule($installPath, $moduleName, $installer, $env);
97
98 5
        return 0;
99
    }
100
101
    /**
102
     * Handles the "module --rename" command.
103
     *
104
     * @param Args $args The console arguments
105
     *
106
     * @return int The status code
107
     */
108 1
    public function handleRename(Args $args)
109
    {
110 1
        $moduleName = $args->getArgument('name');
111 1
        $newName = $args->getArgument('new-name');
112
113 1
        $this->moduleManager->renameModule($moduleName, $newName);
114
115 1
        return 0;
116
    }
117
118
    /**
119
     * Handles the "module --delete" command.
120
     *
121
     * @param Args $args The console arguments
122
     *
123
     * @return int The status code
124
     */
125 2
    public function handleDelete(Args $args)
126
    {
127 2
        $moduleName = $args->getArgument('name');
128
129 2
        if (!$this->moduleManager->hasModule($moduleName)) {
130 1
            throw new RuntimeException(sprintf(
131 1
                'The module "%s" is not installed.',
132
                $moduleName
133
            ));
134
        }
135
136 1
        $this->moduleManager->removeModule($moduleName);
137
138 1
        return 0;
139
    }
140
141
    /**
142
     * Handles the "module --clean" command.
143
     *
144
     * @param Args $args The console arguments
145
     * @param IO   $io   The I/O
146
     *
147
     * @return int The status code
148
     */
149 1
    public function handleClean(Args $args, IO $io)
0 ignored issues
show
Unused Code introduced by
The parameter $args 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...
150
    {
151 1
        $expr = Expr::method('getState', Expr::same(ModuleState::NOT_FOUND));
152
153 1
        foreach ($this->moduleManager->findModules($expr) as $module) {
154 1
            $io->writeLine('Removing '.$module->getName());
155 1
            $this->moduleManager->removeModule($module->getName());
156
        }
157
158 1
        return 0;
159
    }
160
161
    /**
162
     * Returns the module states that should be displayed for the given
163
     * console arguments.
164
     *
165
     * @param Args $args The console arguments
166
     *
167
     * @return int[] A list of {@link ModuleState} constants
168
     */
169 11
    private function getSelectedStates(Args $args)
170
    {
171 11
        $states = array();
172
173 11
        if ($args->isOptionSet('enabled')) {
174 3
            $states[] = ModuleState::ENABLED;
175
        }
176
177 11
        if ($args->isOptionSet('not-found')) {
178 2
            $states[] = ModuleState::NOT_FOUND;
179
        }
180
181 11
        if ($args->isOptionSet('not-loadable')) {
182 1
            $states[] = ModuleState::NOT_LOADABLE;
183
        }
184
185 11
        return $states ?: ModuleState::all();
186
    }
187
188
    /**
189
     * Returns the modules that should be displayed for the given console
190
     * arguments.
191
     *
192
     * @param Args $args The console arguments
193
     *
194
     * @return ModuleList The modules
195
     */
196 11
    private function getSelectedModules(Args $args)
197
    {
198 11
        $states = $this->getSelectedStates($args);
199 11
        $expr = Expr::true();
200 11
        $envs = array();
201
202 11
        if ($states !== ModuleState::all()) {
203 5
            $expr = $expr->andMethod('getState', Expr::in($states));
204
        }
205
206 11
        if ($args->isOptionSet('installer')) {
207 2
            $expr = $expr->andMethod('getInstallInfo', Expr::method('getInstallerName', Expr::same($args->getOption('installer'))));
208
        }
209
210 11
        if ($args->isOptionSet('prod')) {
211 2
            $envs[] = Environment::PROD;
212
        }
213
214 11
        if ($args->isOptionSet('dev')) {
215 2
            $envs[] = Environment::DEV;
216
        }
217
218 11
        if (count($envs) > 0) {
219 3
            $expr = $expr->andMethod('getInstallInfo', Expr::method('getEnvironment', Expr::in($envs)));
220
        }
221
222 11
        return $this->moduleManager->findModules($expr);
223
    }
224
225
    /**
226
     * Prints modules with intermediate headers for the module states.
227
     *
228
     * @param IO         $io      The I/O
229
     * @param ModuleList $modules The modules to print
230
     * @param int[]      $states  The states to print
231
     */
232 10
    private function printModulesByState(IO $io, ModuleList $modules, array $states)
233
    {
234 10
        $printStates = count($states) > 1;
235
236 10
        foreach ($states as $state) {
237 10
            $filteredModules = array_filter($modules->toArray(), function (Module $module) use ($state) {
238 10
                return $state === $module->getState();
239 10
            });
240
241 10
            if (0 === count($filteredModules)) {
242 2
                continue;
243
            }
244
245 10
            if ($printStates) {
246 6
                $this->printModuleState($io, $state);
247
            }
248
249 10
            if (ModuleState::NOT_LOADABLE === $state) {
250 5
                $this->printNotLoadableModules($io, $filteredModules, $printStates);
251
            } else {
252 9
                $styleTag = ModuleState::ENABLED === $state ? null : 'bad';
253 9
                $this->printModuleTable($io, $filteredModules, $styleTag, $printStates);
254
            }
255
256 10
            if ($printStates) {
257 10
                $io->writeLine('');
258
            }
259
        }
260 10
    }
261
262
    /**
263
     * Prints modules using the given format.
264
     *
265
     * @param IO         $io      The I/O
266
     * @param ModuleList $modules The modules to print
267
     * @param string     $format  The format string
268
     */
269 1
    private function printModulesWithFormat(IO $io, ModuleList $modules, $format)
270
    {
271
        /** @var Module $module */
272 1
        foreach ($modules as $module) {
273 1
            $installInfo = $module->getInstallInfo();
274
275 1
            $io->writeLine(strtr($format, array(
276 1
                '%name%' => $module->getName(),
277 1
                '%installer%' => $installInfo ? $installInfo->getInstallerName() : '',
278 1
                '%install_path%' => $module->getInstallPath(),
279 1
                '%state%' => self::$stateStrings[$module->getState()],
280 1
                '%env%' => $installInfo ? $installInfo->getEnvironment() : Environment::PROD,
281
            )));
282
        }
283 1
    }
284
285
    /**
286
     * Prints the heading for a given module state.
287
     *
288
     * @param IO  $io          The I/O
289
     * @param int $ModuleState The {@link ModuleState} constant
290
     */
291 6
    private function printModuleState(IO $io, $ModuleState)
0 ignored issues
show
Coding Style Naming introduced by
The parameter $ModuleState is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
292
    {
293 View Code Duplication
        switch ($ModuleState) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
294 6
            case ModuleState::ENABLED:
295 6
                $io->writeLine('The following modules are currently enabled:');
296 6
                $io->writeLine('');
297
298 6
                return;
299 5
            case ModuleState::NOT_FOUND:
300 4
                $io->writeLine('The following modules could not be found:');
301 4
                $io->writeLine(' (use "puli module --clean" to remove)');
302 4
                $io->writeLine('');
303
304 4
                return;
305 4
            case ModuleState::NOT_LOADABLE:
306 4
                $io->writeLine('The following modules could not be loaded:');
307 4
                $io->writeLine('');
308
309 4
                return;
310
        }
311
    }
312
313
    /**
314
     * Prints a list of modules in a table.
315
     *
316
     * @param IO          $io       The I/O
317
     * @param Module[]    $modules  The modules
318
     * @param string|null $styleTag The tag used to style the output. If `null`,
319
     *                              the default colors are used
320
     * @param bool        $indent   Whether to indent the output
321
     */
322 9
    private function printModuleTable(IO $io, array $modules, $styleTag = null, $indent = false)
323
    {
324 9
        $table = new Table(PuliTableStyle::borderless());
325 9
        $table->setHeaderRow(array('Module Name', 'Installer', 'Env', 'Install Path'));
326
327 9
        $installerTag = $styleTag ?: 'c1';
328 9
        $envTag = $styleTag ?: 'c1';
329 9
        $pathTag = $styleTag ?: 'c2';
330
331 9
        ksort($modules);
332
333 9
        foreach ($modules as $module) {
334 9
            $moduleName = $module->getName();
335 9
            $installInfo = $module->getInstallInfo();
336 9
            $installPath = $installInfo ? $installInfo->getInstallPath() : '.';
337 9
            $installer = $installInfo ? $installInfo->getInstallerName() : '';
338 9
            $env = $installInfo ? $installInfo->getEnvironment() : Environment::PROD;
339
340 9
            $table->addRow(array(
341 9
                $styleTag ? sprintf('<%s>%s</%s>', $styleTag, $moduleName, $styleTag) : $moduleName,
342 9
                $installer ? sprintf('<%s>%s</%s>', $installerTag, $installer, $installerTag) : '',
343 9
                sprintf('<%s>%s</%s>', $envTag, $env, $envTag),
344 9
                sprintf('<%s>%s</%s>', $pathTag, $installPath, $pathTag),
345
            ));
346
        }
347
348 9
        $table->render($io, $indent ? 4 : 0);
349 9
    }
350
351
    /**
352
     * Prints not-loadable modules in a table.
353
     *
354
     * @param IO       $io      The I/O
355
     * @param Module[] $modules The not-loadable modules
356
     * @param bool     $indent  Whether to indent the output
357
     */
358 5
    private function printNotLoadableModules(IO $io, array $modules, $indent = false)
359
    {
360 5
        $rootDir = $this->moduleManager->getContext()->getRootDirectory();
361 5
        $table = new Table(PuliTableStyle::borderless());
362 5
        $table->setHeaderRow(array('Module Name', 'Error'));
363
364 5
        ksort($modules);
365
366 5
        foreach ($modules as $module) {
367 5
            $moduleName = $module->getName();
368 5
            $loadErrors = $module->getLoadErrors();
369 5
            $errorMessage = '';
370
371 5
            foreach ($loadErrors as $loadError) {
372 5
                $errorMessage .= StringUtil::getShortClassName(get_class($loadError)).': '.$loadError->getMessage()."\n";
373
            }
374
375 5
            $errorMessage = rtrim($errorMessage);
376
377 5
            if (!$errorMessage) {
378
                $errorMessage = 'Unknown error.';
379
            }
380
381
            // Remove root directory
382 5
            $errorMessage = str_replace($rootDir.'/', '', $errorMessage);
383
384 5
            $table->addRow(array(
385 5
                sprintf('<bad>%s</bad>', $moduleName),
386 5
                sprintf('<bad>%s</bad>', $errorMessage),
387
            ));
388
        }
389
390 5
        $table->render($io, $indent ? 4 : 0);
391 5
    }
392
}
393