Passed
Branch coverage (8ea179)
by Fabian
03:11
created

ExceptionGeneratorCommand::execute()   C

Complexity

Conditions 11
Paths 24

Size

Total Lines 94
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 64
CRAP Score 11.0004

Importance

Changes 0
Metric Value
eloc 61
dl 0
loc 94
ccs 64
cts 65
cp 0.9846
rs 6.7042
c 0
b 0
f 0
cc 11
nc 24
nop 2
crap 11.0004

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Fabiang\ExceptionGenerator\Cli\Command;
6
7
use Fabiang\ExceptionGenerator\Generator\CreateException;
8
use Fabiang\ExceptionGenerator\Generator\RecursiveNamespaceResolver;
9
use Fabiang\ExceptionGenerator\Generator\RecursiveParentExceptionResolver;
10
use Fabiang\ExceptionGenerator\Generator\TemplateRenderer;
11
use Fabiang\ExceptionGenerator\Listener\CreateExceptionListener;
12
use Fabiang\ExceptionGenerator\TemplateResolver\TemplatePathMatcher;
13
use Fabiang\ExceptionGenerator\TemplateResolver\TemplateResolver;
14
use Symfony\Component\Console\Command\Command;
15
use Symfony\Component\Console\Helper\QuestionHelper;
16
use Symfony\Component\Console\Input\InputArgument;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Input\InputOption;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Console\Question\Question;
21
use Symfony\Component\EventDispatcher\EventDispatcher;
22
23
use function array_reverse;
24
use function getcwd;
25
use function is_array;
26
use function realpath;
27
use function substr;
28
29
class ExceptionGeneratorCommand extends Command
30
{
31
    /**
32
     * {@inheritDoc}
33
     */
34
    protected function configure(): void
35
    {
36
        $this->setName('exception-generator')
37
            ->setDescription('Generates Exception Classes for php files in current dir.')
38
            ->addArgument(
39
                'path',
40
                InputArgument::OPTIONAL,
41
                'Basepath for generating exception class.'
42
            )
43
            ->addOption(
44
                'overwrite',
45
                'o',
46
                InputOption::VALUE_NONE,
47
                'Force overwriting existing exception classes.'
48
            )
49
            ->addOption(
50
                'template-path',
51
                't',
52
                InputOption::VALUE_REQUIRED,
53
                'Set path for templates you want to use.'
54
            )
55
            ->addOption(
56
                'no-parents',
57
                'p',
58
                InputOption::VALUE_NONE,
59
                'Disable searching for parent exceptions.'
60
            );
61
    }
62
63
    /**
64
     * {@inheritDoc}
65
     */
66 2
    protected function execute(InputInterface $input, OutputInterface $output): int
67
    {
68 2
        if ($input->getArgument('path')) {
69 2
            $path = $this->realpath($input->getArgument('path'));
70
        } else {
71
            $path = getcwd();
72
        }
73
74
        /** @var QuestionHelper $questionHelper */
75 2
        $questionHelper = $this->getHelper('question');
76
77 2
        $eventDispatcher = new EventDispatcher();
78 2
        $eventDispatcher->addSubscriber(new CreateExceptionListener($output, $input, $questionHelper));
79 2
        $namespaceResolver = new RecursiveNamespaceResolver($eventDispatcher);
80
81 2
        $namespace           = $namespaceResolver->resolveNamespace($path);
82 2
        $templatePathMatcher = new TemplatePathMatcher($path, $this->getApplication()->getHome());
0 ignored issues
show
Bug introduced by
The method getHome() does not exist on Symfony\Component\Console\Application. It seems like you code against a sub-type of Symfony\Component\Console\Application such as Fabiang\ExceptionGenerator\Cli\Console\Application. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

82
        $templatePathMatcher = new TemplatePathMatcher($path, $this->getApplication()->/** @scrutinizer ignore-call */ getHome());
Loading history...
83
84 2
        $templatePath     = $this->realpath($input->getOption('template-path')) ?: null;
85 2
        $templateResolver = new TemplateResolver($templatePath, $templatePathMatcher);
86
87 2
        $exceptionTemplate = $templateResolver->resolve('exception.phtml');
88 2
        $interfaceTemplate = $templateResolver->resolve('interface.phtml');
89
90 2
        $useParents = $input->getOption('no-parents') ? false : true;
91
92 2
        $output->writeln('Using path for templates: "' . $templatePath . '"', OutputInterface::VERBOSITY_VERY_VERBOSE);
93 2
        $output->writeln('Exception-Path: "' . $exceptionTemplate . '"', OutputInterface::VERBOSITY_VERY_VERBOSE);
94 2
        $output->writeln('Interface-Path: "' . $interfaceTemplate . '"', OutputInterface::VERBOSITY_VERY_VERBOSE);
95
96 2
        $templateRenderer = new TemplateRenderer();
97 2
        $templateRenderer->addPath('exception', $exceptionTemplate);
98 2
        $templateRenderer->addPath('interface', $interfaceTemplate);
99
100 2
        $parentExceptionNamespace = null;
101
102 2
        if (false !== $useParents) {
103 1
            $parentExceptionResolver = new RecursiveParentExceptionResolver($eventDispatcher);
104 1
            $parentExceptionDirs     = $parentExceptionResolver->resolveExceptionDirs($path);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $parentExceptionDirs is correct as $parentExceptionResolver...lveExceptionDirs($path) targeting Fabiang\ExceptionGenerat...:resolveExceptionDirs() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
105
106 1
            if (is_array($parentExceptionDirs)) {
0 ignored issues
show
introduced by
The condition is_array($parentExceptionDirs) is always false.
Loading history...
107 1
                $parentExceptionDirs = array_reverse($parentExceptionDirs);
108 1
                foreach ($parentExceptionDirs as $parentExceptionDir) {
109 1
                    $prevParentNamespace      = $parentExceptionNamespace;
110 1
                    $parentExceptionNamespace = $namespaceResolver->resolveNamespace($parentExceptionDir);
111
112 1
                    $output->writeln(
113 1
                        'BaseExceptionPath: "' . $parentExceptionDir . '"',
114 1
                        OutputInterface::VERBOSITY_VERY_VERBOSE
115 1
                    );
116 1
                    $output->writeln(
117 1
                        'BaseExceptionNamespace: "' . $parentExceptionNamespace . '"',
118 1
                        OutputInterface::VERBOSITY_VERY_VERBOSE
119 1
                    );
120
121 1
                    $parentExceptionCreator = new CreateException(
122 1
                        $eventDispatcher,
123 1
                        $templateRenderer,
124 1
                        false,
125 1
                        $output,
126 1
                        $input
127 1
                    );
128
129 1
                    $parentExceptionCreator->create(
130 1
                        $parentExceptionNamespace,
131 1
                        $parentExceptionDir,
132 1
                        $prevParentNamespace
133 1
                    );
134
                }
135
            }
136
        }
137
138
        if (
139 2
            $parentExceptionNamespace && false === $useParents ||
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($parentExceptionNamespa...& false !== $useParents, Probably Intended Meaning: $parentExceptionNamespac... false !== $useParents)
Loading history...
introduced by
$parentExceptionNamespace is of type null, thus it always evaluated to false.
Loading history...
140 2
            ($parentExceptionNamespace && false !== $useParents)
0 ignored issues
show
introduced by
$parentExceptionNamespace is of type null, thus it always evaluated to false.
Loading history...
141
        ) {
142 1
            $output->writeln('BaseExceptionPath: not found/used', OutputInterface::VERBOSITY_VERY_VERBOSE);
143
        }
144
145 2
        $namespaceQuestion = new Question("Is this the correct namespace: [$namespace]?", $namespace);
146 2
        $inputNamespace    = $questionHelper->ask($input, $output, $namespaceQuestion);
147 2
        $output->writeln('Namespace set to "' . $inputNamespace . '"');
148
149 2
        $exceptionCreator = new CreateException(
150 2
            $eventDispatcher,
151 2
            $templateRenderer,
152 2
            $input->getOption('overwrite'),
153 2
            $output,
0 ignored issues
show
Unused Code introduced by
The call to Fabiang\ExceptionGenerat...xception::__construct() has too many arguments starting with $output. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

153
        $exceptionCreator = /** @scrutinizer ignore-call */ new CreateException(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
154 2
            $input
155 2
        );
156
157 2
        $exceptionCreator->create($inputNamespace, $path . '/Exception', $parentExceptionNamespace);
158
159 2
        return 0;
160
    }
161
162
    /**
163
     * Realpath.
164
     */
165 2
    private function realpath(?string $path): string|bool
166
    {
167 2
        if (null === $path) {
168
            return '';
169
        }
170
171
        // extra check for virtual file system since vfsstream can't handle realpath()
172 2
        if (substr($path, 0, 6) === 'vfs://') {
173 2
            return $path;
174
        }
175
176
        return realpath($path);
177
    }
178
}
179