Test Failed
Pull Request — master (#872)
by Maxim
10:54 queued 03:52
created

Command::configureViaSignature()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 10
cc 3
nc 4
nop 1
crap 3

1 Method

Rating   Name   Duplication   Size   Complexity  
A Command::defineArguments() 0 3 1
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\Attributes\Factory;
10
use Spiral\Console\Configurator\Attribute\Parser as AttributeParser;
11
use Spiral\Console\Configurator\AttributeBasedConfigurator;
12
use Spiral\Console\Configurator\Configurator;
13
use Spiral\Console\Configurator\Signature\Parser as SignatureParser;
14
use Spiral\Console\Configurator\SignatureBasedConfigurator;
15
use Spiral\Console\Event\CommandFinished;
16
use Spiral\Console\Event\CommandStarting;
17
use Spiral\Console\Interceptor\AttributeInterceptor;
18
use Spiral\Console\Traits\HelpersTrait;
19
use Spiral\Core\CoreInterceptorInterface;
20
use Spiral\Core\CoreInterface;
21
use Spiral\Core\Exception\ScopeException;
22
use Spiral\Core\InterceptableCore;
23
use Spiral\Events\EventDispatcherAwareInterface;
24
use Symfony\Component\Console\Command\Command as SymfonyCommand;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Command\Command was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use Symfony\Component\Console\Input\InputInterface;
26
use Symfony\Component\Console\Output\OutputInterface;
27
use Symfony\Component\Console\Style\SymfonyStyle;
28
29
/**
30
 * Provides automatic command configuration and access to global container scope.
31
 */
32
abstract class Command extends SymfonyCommand implements EventDispatcherAwareInterface
33
{
34
    use HelpersTrait;
35
36
    /** Command name. */
37
    protected const NAME = '';
38
    /** Short command description. */
39
    protected const DESCRIPTION = null;
40
    /** Command signature. */
41
    protected const SIGNATURE = null;
42
    /** Command options specified in Symfony format. For more complex definitions redefine getOptions() method. */
43
    protected const OPTIONS = [];
44
    /** Command arguments specified in Symfony format. For more complex definitions redefine getArguments() method. */
45
    protected const ARGUMENTS = [];
46
47
    protected ?ContainerInterface $container = null;
48 72
    protected ?EventDispatcherInterface $eventDispatcher = null;
49
50 72
    /** @var array<class-string<CoreInterceptorInterface>> */
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string<CoreInterceptorInterface>> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string<CoreInterceptorInterface>>.
Loading history...
51
    protected array $interceptors = [];
52
53
    /** {@internal} */
54
    public function setContainer(ContainerInterface $container): void
55
    {
56
        $this->container = $container;
57 72
    }
58
59 72
    /**
60
     * {@internal}
61
     * @param array<class-string<CoreInterceptorInterface>> $interceptors
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string<CoreInterceptorInterface>> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string<CoreInterceptorInterface>>.
Loading history...
62 1
     */
63
    public function setInterceptors(array $interceptors): void
64 1
    {
65
        $this->interceptors = $interceptors;
66
    }
67
68
    public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): void
69
    {
70 71
        $this->eventDispatcher = $eventDispatcher;
71
    }
72 71
73 1
    /**
74
     * Pass execution to "perform" method using container to resolve method dependencies.
75
     */
76 70
    protected function execute(InputInterface $input, OutputInterface $output): int
77
    {
78 70
        if ($this->container === null) {
79
            throw new ScopeException('Container is not set');
80
        }
81 70
82
        $method = method_exists($this, 'perform') ? 'perform' : '__invoke';
83 70
84
        $core = $this->buildCore();
85
86 70
        try {
87 70
            [$this->input, $this->output] = [$this->prepareInput($input), $this->prepareOutput($input, $output)];
88 70
89 70
            $this->eventDispatcher?->dispatch(new CommandStarting($this, $this->input, $this->output));
0 ignored issues
show
Bug introduced by
It seems like $this->output can also be of type null; however, parameter $output of Spiral\Console\Event\Com...Starting::__construct() does only seem to accept Symfony\Component\Console\Output\OutputInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

89
            $this->eventDispatcher?->dispatch(new CommandStarting($this, $this->input, /** @scrutinizer ignore-type */ $this->output));
Loading history...
90 70
91
            // Executing perform method with method injection
92 67
            $code = (int)$core->callAction(static::class, $method, [
93
                'input' => $this->input,
94 67
                'output' => $this->output,
95
                'command' => $this,
96 70
            ]);
97
98
            $this->eventDispatcher?->dispatch(new CommandFinished($this, $code, $this->input, $this->output));
0 ignored issues
show
Bug introduced by
It seems like $this->output can also be of type null; however, parameter $output of Spiral\Console\Event\Com...Finished::__construct() does only seem to accept Symfony\Component\Console\Output\OutputInterface, maybe add an additional type check? ( Ignorable by Annotation )

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

98
            $this->eventDispatcher?->dispatch(new CommandFinished($this, $code, $this->input, /** @scrutinizer ignore-type */ $this->output));
Loading history...
99
100 70
            return $code;
101
        } finally {
102 70
            [$this->input, $this->output] = [null, null];
103
        }
104 70
    }
105
106 70
    protected function buildCore(): CoreInterface
107 1
    {
108
        $core = $this->container->get(CommandCore::class);
0 ignored issues
show
Bug introduced by
The method get() 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

108
        /** @scrutinizer ignore-call */ 
109
        $core = $this->container->get(CommandCore::class);

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...
109
110 70
        $interceptableCore = new InterceptableCore($core, $this->eventDispatcher);
111
112
        foreach ($this->interceptors as $interceptor) {
113 70
            $interceptableCore->addInterceptor($this->container->get($interceptor));
114
        }
115 70
        $interceptableCore->addInterceptor($this->container->get(AttributeInterceptor::class));
116
117
        return $interceptableCore;
118 70
    }
119
120 70
    protected function prepareInput(InputInterface $input): InputInterface
121
    {
122
        return $input;
123
    }
124
125
    protected function prepareOutput(InputInterface $input, OutputInterface $output): OutputInterface
126 73
    {
127
        return new SymfonyStyle($input, $output);
128 73
    }
129 3
130
    /**
131 70
     * Configures the command.
132
     */
133
    protected function configure(): void
134 73
    {
135
        $configurator = new Configurator([
136 73
            new SignatureBasedConfigurator(new SignatureParser()),
137 58
            new AttributeBasedConfigurator(new AttributeParser((new Factory())->create())),
138
        ]);
139
        $configurator->configure($this, new \ReflectionClass($this));
140 73
    }
141 51
142
    /**
143
     * Define command options.
144
     */
145 3
    protected function defineOptions(): array
146
    {
147 3
        return static::OPTIONS;
148
    }
149 3
150
    /**
151 3
     * Define command arguments.
152 3
     */
153
    protected function defineArguments(): array
154
    {
155 3
        return static::ARGUMENTS;
156 3
    }
157
158
    protected function interact(InputInterface $input, OutputInterface $output): void
159
    {
160
        parent::interact($input, $output);
161
162
        $this->container?->get(PromptArguments::class)->promptMissedArguments($this, $input, $output);
163 73
    }
164
}
165