Passed
Pull Request — master (#963)
by butschster
09:56
created

Console::configureIO()   F

Complexity

Conditions 20
Paths 180

Size

Total Lines 66
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 37
CRAP Score 21.6109

Importance

Changes 0
Metric Value
eloc 46
dl 0
loc 66
ccs 37
cts 44
cp 0.8409
rs 3.5
c 0
b 0
f 0
cc 20
nc 180
nop 2
crap 21.6109

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 Spiral\Console;
6
7
use Psr\Container\ContainerInterface;
8
use Psr\EventDispatcher\EventDispatcherInterface;
9
use Spiral\Console\Config\ConsoleConfig;
10
use Spiral\Console\Exception\LocatorException;
11
use Spiral\Core\Container;
12
use Spiral\Core\ScopeInterface;
13
use Spiral\Events\EventDispatcherAwareInterface;
14
use Symfony\Component\Console\Application;
15
use Symfony\Component\Console\Exception\CommandNotFoundException;
16
use Symfony\Component\Console\Input\ArgvInput;
17
use Symfony\Component\Console\Input\ArrayInput;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Input\StreamableInputInterface;
20
use Symfony\Component\Console\Output\BufferedOutput;
21
use Symfony\Component\Console\Output\ConsoleOutput;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as SymfonyEventDispatcherInterface;
24
25
final class Console
26
{
27
    // Undefined response code for command (errors). See below.
28
    public const CODE_NONE = 102;
29
30
    private ?Application $application = null;
31
32 97
    public function __construct(
33
        private readonly ConsoleConfig $config,
34
        private readonly ?LocatorInterface $locator = null,
35
        private readonly ContainerInterface $container = new Container(),
36
        private readonly ScopeInterface $scope = new Container(),
37
        private readonly ?EventDispatcherInterface $dispatcher = null
38
    ) {
39 97
    }
40
41
    /**
42
     * Run console application.
43
     *
44
     * @throws \Throwable
45
     */
46 5
    public function start(InputInterface $input = new ArgvInput(), OutputInterface $output = new ConsoleOutput()): int
47
    {
48 5
        return $this->scope->runScope(
49 5
            [],
50 5
            fn () => $this->run(
51 5
                $input->getFirstArgument() ?? 'list',
52 5
                $input,
53 5
                $output
54 5
            )->getCode()
55 5
        );
56
    }
57
58
    /**
59
     * Run selected command.
60
     *
61
     * @throws \Throwable
62
     * @throws CommandNotFoundException
63
     */
64 96
    public function run(
65
        ?string $command,
66
        array|InputInterface $input = [],
67
        OutputInterface $output = new BufferedOutput()
68
    ): CommandOutput {
69 96
        $input = \is_array($input) ? new ArrayInput($input) : $input;
0 ignored issues
show
introduced by
The condition is_array($input) is always true.
Loading history...
70
71 96
        $this->configureIO($input, $output);
72
73 96
        if ($command !== null) {
74 95
            $input = new InputProxy($input, ['firstArgument' => $command]);
75
        }
76
77 96
        $code = $this->scope->runScope([
78 96
            InputInterface::class => $input,
79 96
            OutputInterface::class => $output,
80 96
        ], fn () => $this->getApplication()->doRun($input, $output));
81
82 93
        return new CommandOutput($code ?? self::CODE_NONE, $output);
83
    }
84
85
    /**
86
     * Get associated Symfony Console Application.
87
     *
88
     * @throws LocatorException
89
     */
90 96
    public function getApplication(): Application
91
    {
92 96
        if ($this->application !== null) {
93 29
            return $this->application;
94
        }
95
96 96
        $this->application = new Application($this->config->getName(), $this->config->getVersion());
97 96
        $this->application->setCatchExceptions(false);
0 ignored issues
show
Bug introduced by
The method setCatchExceptions() does not exist on null. ( Ignorable by Annotation )

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

97
        $this->application->/** @scrutinizer ignore-call */ 
98
                            setCatchExceptions(false);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
98 96
        $this->application->setAutoExit(false);
99 96
        if ($this->dispatcher instanceof SymfonyEventDispatcherInterface) {
100
            $this->application->setDispatcher($this->dispatcher);
101
        }
102
103 96
        if ($this->locator !== null) {
104 26
            $this->addCommands($this->locator->locateCommands());
105
        }
106
107
        // Register user defined commands
108 96
        $static = new StaticLocator(
109 96
            $this->config->getCommands(),
110 96
            $this->config->getInterceptors(),
111 96
            $this->container
112 96
        );
113
114 96
        $this->addCommands($static->locateCommands());
115
116 96
        return $this->application;
117
    }
118
119 96
    private function addCommands(iterable $commands): void
120
    {
121 96
        $interceptors = $this->config->getInterceptors();
122
123 96
        foreach ($commands as $command) {
124 96
            if ($command instanceof Command) {
125 78
                $command->setContainer($this->container);
126 78
                $command->setInterceptors($interceptors);
127
            }
128
129 96
            if ($this->dispatcher !== null && $command instanceof EventDispatcherAwareInterface) {
130 1
                $command->setEventDispatcher($this->dispatcher);
131
            }
132
133 96
            $this->application->add($command);
134
        }
135
    }
136
137
    /**
138
     * Extracted in order to manage command lifecycle.
139
     *
140
     * @see Application::configureIO()
141
     */
142 96
    private function configureIO(InputInterface $input, OutputInterface $output): void
143
    {
144 96
        if ($input->hasParameterOption(['--ansi'], true)) {
145
            $output->setDecorated(true);
146 96
        } elseif ($input->hasParameterOption(['--no-ansi'], true)) {
147
            $output->setDecorated(false);
148
        }
149
150 96
        if ($input->hasParameterOption(['--no-interaction', '-n'], true)) {
151
            $input->setInteractive(false);
152 96
        } elseif (\function_exists('posix_isatty')) {
153 96
            $inputStream = null;
154
155 96
            if ($input instanceof StreamableInputInterface) {
156 96
                $inputStream = $input->getStream();
157
            }
158
159 96
            if (!@posix_isatty($inputStream) && false === getenv('SHELL_INTERACTIVE')) {
160
                $input->setInteractive(false);
161
            }
162
        }
163
164 96
        match ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
0 ignored issues
show
Unused Code introduced by
The assignment to $shellVerbosity is dead and can be removed.
Loading history...
165 96
            -1 => $output->setVerbosity(OutputInterface::VERBOSITY_QUIET),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $output->setVerbosity(Sy...rface::VERBOSITY_QUIET) targeting Symfony\Component\Consol...terface::setVerbosity() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
166 96
            1 => $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $output->setVerbosity(Sy...ace::VERBOSITY_VERBOSE) targeting Symfony\Component\Consol...terface::setVerbosity() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
167 96
            2 => $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $output->setVerbosity(Sy...VERBOSITY_VERY_VERBOSE) targeting Symfony\Component\Consol...terface::setVerbosity() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
168 96
            3 => $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $output->setVerbosity(Sy...rface::VERBOSITY_DEBUG) targeting Symfony\Component\Consol...terface::setVerbosity() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
169 96
            default => $shellVerbosity = 0
170 96
        };
171
172 96
        if ($input->hasParameterOption(['--quiet', '-q'], true)) {
173
            $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
174
            $shellVerbosity = -1;
175
        } else {
176
            if (
177 96
                $input->hasParameterOption('-vvv', true)
178 95
                || $input->hasParameterOption('--verbose=3', true)
179 96
                || 3 === $input->getParameterOption('--verbose', false, true)
180
            ) {
181 1
                $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
182 1
                $shellVerbosity = 3;
183
            } elseif (
184 95
                $input->hasParameterOption('-vv', true)
185 94
                || $input->hasParameterOption('--verbose=2', true)
186 95
                || 2 === $input->getParameterOption('--verbose', false, true)
187
            ) {
188 1
                $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
189 1
                $shellVerbosity = 2;
190
            } elseif (
191 94
                $input->hasParameterOption('-v', true)
192 94
                || $input->hasParameterOption('--verbose=1', true)
193 94
                || $input->hasParameterOption('--verbose', true)
194 94
                || $input->getParameterOption('--verbose', false, true)
195
            ) {
196 1
                $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
197 1
                $shellVerbosity = 1;
198
            }
199
        }
200
201 96
        if (-1 === $shellVerbosity) {
202
            $input->setInteractive(false);
203
        }
204
205 96
        \putenv('SHELL_VERBOSITY=' . $shellVerbosity);
206 96
        $_ENV['SHELL_VERBOSITY'] = $shellVerbosity;
207 96
        $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity;
208
    }
209
}
210