CheckCommand::configure()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 6
nc 1
nop 0
1
<?php
2
3
namespace Koriit\PHPDeps\Commands;
4
5
use Koriit\PHPDeps\Config\Exceptions\InvalidConfig;
6
use Koriit\PHPDeps\Config\Exceptions\InvalidSchema;
7
use Koriit\PHPDeps\Console\GraphWriter;
8
use Koriit\PHPDeps\ExitCodes;
9
use Koriit\PHPDeps\Helpers\InputHelper;
10
use Koriit\PHPDeps\Helpers\ModulesHelper;
11
use Koriit\PHPDeps\Modules\Module;
12
use Koriit\PHPDeps\Modules\ModuleReader;
13
use Koriit\PHPDeps\Tokenizer\Exceptions\MalformedFile;
14
use Symfony\Component\Console\Command\Command;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Input\InputOption;
17
use Symfony\Component\Console\Output\OutputInterface;
18
use Symfony\Component\Console\Style\SymfonyStyle;
19
20
class CheckCommand extends Command
21
{
22
    /** @var ModuleReader */
23
    private $modulesReader;
24
25
    /** @var GraphWriter */
26
    private $graphWriter;
27
28
    /** @var ModulesHelper */
29
    private $modulesHelper;
30
31
    /** @var InputHelper */
32
    private $inputHelper;
33
34 View Code Duplication
    public function __construct(ModulesHelper $modulesHelper, InputHelper $inputHelper, ModuleReader $modulesReader, GraphWriter $graphWriter)
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...
35
    {
36
        parent::__construct();
37
38
        $this->modulesReader = $modulesReader;
39
        $this->graphWriter = $graphWriter;
40
        $this->modulesHelper = $modulesHelper;
41
        $this->inputHelper = $inputHelper;
42
    }
43
44
    protected function configure()
45
    {
46
        $this
47
              ->setName('check')
48
              ->setDescription('Check whether there are circular dependencies in modules.')
49
              ->addOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Custom location of configuration file', './phpdeps.xml')
50
              ->addOption('graphs', 'g', InputOption::VALUE_NONE, 'Whether to display dependency cycles as graphs(assumed with -v)');
51
    }
52
53
    /**
54
     * @param InputInterface  $input
55
     * @param OutputInterface $output
56
     *
57
     * @throws InvalidConfig
58
     * @throws InvalidSchema
59
     * @throws MalformedFile
60
     *
61
     * @return int Exit code
62
     */
63
    protected function execute(InputInterface $input, OutputInterface $output)
64
    {
65
        $io = new SymfonyStyle($input, $output);
66
67
        $config = $this->inputHelper->readConfig($input);
68
        $drawGraphs = $output->isVerbose() || $input->getOption('graphs');
69
70
        $modules = $this->modulesHelper->findModules($config);
71
        if (!$this->modulesHelper->validateModules($modules, $io)) {
72
            return ExitCodes::UNEXPECTED_ERROR;
73
        }
74
75
        $dependencyCycles = $this->findDependencyCycles($modules);
76
77
        if (empty($dependencyCycles)) {
78
            $io->success('There are no circular dependencies in your modules!');
79
80
            return ExitCodes::OK;
81
        } else {
82
            $io->warning('There are circular dependencies in your modules!');
83
84
            $this->displayDependencyCycles($dependencyCycles, $io, $drawGraphs);
85
86
            return ExitCodes::CIRCULAR_DEPENDENCIES_EXIST;
87
        }
88
    }
89
90
    /**
91
     * @param Module[][]   $dependencyCycles
92
     * @param SymfonyStyle $io
93
     * @param bool         $drawGraphs
94
     */
95
    private function displayDependencyCycles(array $dependencyCycles, SymfonyStyle $io, $drawGraphs)
96
    {
97
        $cyclesCount = \count($dependencyCycles);
98
        $io->writeln('In total there ' . ($cyclesCount > 1 ? 'are ' . $cyclesCount . ' dependency cycles' : 'is 1 dependency cycle') . ' in your modules.');
99
100
        $i = 1;
101
        foreach ($dependencyCycles as $cycle) {
102
            $graphNodes = [];
103
            $out = $i++ . '. ';
104
105
            foreach ($cycle as $module) {
106
                $out .= '<fg=white>' . $module->getName() . '</> -> ';
107
                $graphNodes[] = $module->getName() . ' [<fg=magenta>' . $module->getNamespace() . '</>]';
108
            }
109
110
            $io->section($out . '<fg=white>' . $cycle[0]->getName() . '</>');
111
            if ($drawGraphs) {
112
                $this->graphWriter->drawGraphCycle($graphNodes);
113
                if ($i <= $cyclesCount) {
114
                    $io->newLine();
115
                    $io->newLine();
116
                }
117
            }
118
        }
119
    }
120
121
    /**
122
     * @param Module[] $modules
123
     *
124
     * @throws MalformedFile
125
     *
126
     * @return Module[][]
127
     */
128
    private function findDependencyCycles($modules)
129
    {
130
        $dependenciesGraph = $this->modulesReader->generateDependenciesGraph($modules);
131
132
        return $dependenciesGraph->findAllCycles();
133
    }
134
}
135