Completed
Branch 09branch (0a5c88)
by Anton
05:50
created

Command::isAvailable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * spiral
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\Console;
8
9
use Interop\Container\ContainerInterface;
10
use Spiral\Console\Helpers\AskHelper;
11
use Spiral\Core\ResolverInterface;
12
use Spiral\Core\Traits\SharedTrait;
13
use Symfony\Component\Console\Command\Command as SymfonyCommand;
14
use Symfony\Component\Console\Helper\Table;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Output\OutputInterface;
17
18
/**
19
 * Basic application command class. Implements method injections and simplified access to
20
 * container bindings.
21
 */
22
abstract class Command extends SymfonyCommand
23
{
24
    use SharedTrait;
25
26
    /**
27
     * Command name.
28
     *
29
     * @var string
30
     */
31
    const NAME = '';
32
33
    /**
34
     * Short command description.
35
     *
36
     * @var string
37
     */
38
    const DESCRIPTION = '';
39
40
    /**
41
     * Command options specified in Symphony format. For more complex definitions redefine
42
     * getOptions() method.
43
     *
44
     * @var array
45
     */
46
    const OPTIONS = [];
47
48
    /**
49
     * Command arguments specified in Symphony format. For more complex definitions redefine
50
     * getArguments() method.
51
     *
52
     * @var array
53
     */
54
    const ARGUMENTS = [];
55
56
    /**
57
     * OutputInterface is the interface implemented by all Output classes. Only exists when command
58
     * are being executed.
59
     *
60
     * @var OutputInterface
61
     */
62
    protected $output = null;
63
64
    /**
65
     * InputInterface is the interface implemented by all input classes. Only exists when command
66
     * are being executed.
67
     *
68
     * @var InputInterface
69
     */
70
    protected $input = null;
71
72
    /**
73
     * @var ContainerInterface
74
     */
75
    protected $container = null;
76
77
    /**
78
     * @param ContainerInterface $container
79
     */
80
    public function __construct(ContainerInterface $container)
81
    {
82
        $this->container = $container;
83
84
        /**
85
         * Configuring command.
86
         */
87
        parent::__construct(static::NAME);
88
        $this->setDescription(static::DESCRIPTION);
89
90
        foreach ($this->defineOptions() as $option) {
91
            call_user_func_array([$this, 'addOption'], $option);
92
        }
93
94
        foreach ($this->defineArguments() as $argument) {
95
            call_user_func_array([$this, 'addArgument'], $argument);
96
        }
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function run(InputInterface $input, OutputInterface $output)
103
    {
104
        try {
105
            list($this->input, $this->output) = [$input, $output];
106
107
            return parent::run($input, $output);
108
        } finally {
109
            //Scope end
110
            $this->input = $this->output = null;
111
        }
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     *
117
     * Pass execution to "perform" method using container to resolve method dependencies.
118
     */
119
    protected function execute(InputInterface $input, OutputInterface $output)
120
    {
121
        $reflection = new \ReflectionMethod($this, 'perform');
122
        $reflection->setAccessible(true);
123
124
        /**
125
         * @var ResolverInterface $resolver
126
         */
127
        $resolver = $this->container->get(ResolverInterface::class);
128
129
        //Executing perform method with method injection
130
        return $reflection->invokeArgs(
131
            $this,
132
            $resolver->resolveArguments($reflection, compact('input', 'output'))
133
        );
134
    }
135
136
    /**
137
     * Define command options.
138
     *
139
     * @return array
140
     */
141
    protected function defineOptions(): array
142
    {
143
        return static::OPTIONS;
144
    }
145
146
    /**
147
     * Define command arguments.
148
     *
149
     * @return array
150
     */
151
    protected function defineArguments(): array
152
    {
153
        return static::ARGUMENTS;
154
    }
155
156
    /**
157
     * @return ContainerInterface
158
     */
159
    protected function iocContainer()
160
    {
161
        //We have to always be executed in a container scope
162
        return $this->container;
163
    }
164
165
    /**
166
     * Check if verbosity level of output is higher or equal to VERBOSITY_VERBOSE.
167
     *
168
     * @return bool
169
     */
170
    protected function isVerbosity(): bool
171
    {
172
        return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
173
    }
174
175
    /**
176
     * Writes a message to the output.
177
     *
178
     * @param string|array $messages The message as an array of lines or a single string
179
     * @param bool         $newline  Whether to add a newline
180
     *
181
     * @throws \InvalidArgumentException When unknown output type is given
182
     */
183
    protected function write($messages, bool $newline = false)
184
    {
185
        return $this->output->write($messages, $newline);
186
    }
187
188
    /**
189
     * Writes a message to the output and adds a newline at the end.
190
     *
191
     * @param string|array $messages The message as an array of lines of a single string
192
     *
193
     * @throws \InvalidArgumentException When unknown output type is given
194
     */
195
    protected function writeln($messages)
196
    {
197
        return $this->output->writeln($messages);
198
    }
199
200
    /**
201
     * Input option.
202
     *
203
     * @param string $name
204
     *
205
     * @return mixed
206
     */
207
    protected function option(string $name)
208
    {
209
        return $this->input->getOption($name);
210
    }
211
212
    /**
213
     * Input argument.
214
     *
215
     * @param string $name
216
     *
217
     * @return mixed
218
     */
219
    protected function argument(string $name)
220
    {
221
        return $this->input->getArgument($name);
222
    }
223
224
    /**
225
     * Table helper instance with configured header and pre-defined set of rows.
226
     *
227
     * @param array  $headers
228
     * @param array  $rows
229
     * @param string $style
230
     *
231
     * @return Table
232
     */
233
    protected function table(array $headers, array $rows = [], string $style = 'default'): Table
234
    {
235
        $table = new Table($this->output);
236
237
        return $table->setHeaders($headers)->setRows($rows)->setStyle($style);
238
    }
239
240
    /**
241
     * Create or use cached instance of AskHelper.
242
     *
243
     * @return AskHelper
244
     */
245
    protected function ask(): AskHelper
246
    {
247
        return new AskHelper($this->getHelper('question'), $this->input, $this->output);
0 ignored issues
show
Compatibility introduced by
$this->getHelper('question') of type object<Symfony\Component...Helper\HelperInterface> is not a sub-type of object<Symfony\Component...\Helper\QuestionHelper>. It seems like you assume a concrete implementation of the interface Symfony\Component\Console\Helper\HelperInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
248
    }
249
}