Command::__construct()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 16
rs 10
cc 4
nc 4
nop 9

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Cli\Routing\Data;
15
16
use Override;
0 ignored issues
show
Bug introduced by
The type Override 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...
17
use Valkyrja\Cli\Interaction\Message\Contract\Message;
18
use Valkyrja\Cli\Middleware\Contract\CommandDispatchedMiddleware;
19
use Valkyrja\Cli\Middleware\Contract\CommandMatchedMiddleware;
20
use Valkyrja\Cli\Middleware\Contract\ExitedMiddleware;
21
use Valkyrja\Cli\Middleware\Contract\ThrowableCaughtMiddleware;
22
use Valkyrja\Cli\Routing\Data\Contract\ArgumentParameter;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Valkyrja\Cli\Routing\Data\ArgumentParameter. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
23
use Valkyrja\Cli\Routing\Data\Contract\Command as Contract;
24
use Valkyrja\Cli\Routing\Data\Contract\OptionParameter;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Valkyrja\Cli\Routing\Data\OptionParameter. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
25
use Valkyrja\Cli\Routing\Data\Contract\Parameter;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Valkyrja\Cli\Routing\Data\Parameter. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
26
use Valkyrja\Dispatcher\Data\Contract\MethodDispatch;
27
use Valkyrja\Dispatcher\Data\MethodDispatch as DefaultDispatch;
28
29
/**
30
 * Class Command.
31
 *
32
 * @author Melech Mizrachi
33
 */
34
class Command implements Contract
35
{
36
    /** @var ArgumentParameter[] */
37
    protected array $arguments = [];
38
39
    /** @var OptionParameter[] */
40
    protected array $options = [];
41
42
    /**
43
     * @param non-empty-string                            $name                        The name
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
44
     * @param non-empty-string                            $description                 The description
45
     * @param Message                                     $helpText                    The help text
46
     * @param class-string<CommandMatchedMiddleware>[]    $commandMatchedMiddleware    The command matched middleware
47
     * @param class-string<CommandDispatchedMiddleware>[] $commandDispatchedMiddleware The command dispatched middleware
48
     * @param class-string<ThrowableCaughtMiddleware>[]   $throwableCaughtMiddleware   The throwable caught middleware
49
     * @param class-string<ExitedMiddleware>[]            $exitedMiddleware            The exited middleware
50
     * @param Parameter[]                                 $parameters                  The parameters
51
     */
52
    public function __construct(
53
        protected string $name,
54
        protected string $description,
55
        protected Message $helpText,
56
        protected MethodDispatch $dispatch = new DefaultDispatch(self::class, '__construct'),
57
        protected array $commandMatchedMiddleware = [],
58
        protected array $commandDispatchedMiddleware = [],
59
        protected array $throwableCaughtMiddleware = [],
60
        protected array $exitedMiddleware = [],
61
        array $parameters = [],
62
    ) {
63
        foreach ($parameters as $parameter) {
64
            if ($parameter instanceof ArgumentParameter) {
65
                $this->arguments[] = $parameter;
66
            } elseif ($parameter instanceof OptionParameter) {
67
                $this->options[] = $parameter;
68
            }
69
        }
70
    }
71
72
    /**
73
     * @inheritDoc
74
     */
75
    #[Override]
76
    public function getName(): string
77
    {
78
        return $this->name;
79
    }
80
81
    /**
82
     * @inheritDoc
83
     */
84
    #[Override]
85
    public function withName(string $name): static
86
    {
87
        $new = clone $this;
88
89
        $new->name = $name;
90
91
        return $new;
92
    }
93
94
    /**
95
     * @inheritDoc
96
     */
97
    #[Override]
98
    public function getDescription(): string
99
    {
100
        return $this->description;
101
    }
102
103
    /**
104
     * @inheritDoc
105
     */
106
    #[Override]
107
    public function withDescription(string $description): static
108
    {
109
        $new = clone $this;
110
111
        $new->description = $description;
112
113
        return $new;
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119
    #[Override]
120
    public function getHelpText(): Message
121
    {
122
        return $this->helpText;
123
    }
124
125
    /**
126
     * @inheritDoc
127
     */
128
    #[Override]
129
    public function withHelpText(Message $helpText): static
130
    {
131
        $new = clone $this;
132
133
        $new->helpText = $helpText;
134
135
        return $new;
136
    }
137
138
    /**
139
     * @inheritDoc
140
     */
141
    #[Override]
142
    public function hasArguments(): bool
143
    {
144
        return $this->arguments !== [];
145
    }
146
147
    /**
148
     * @inheritDoc
149
     */
150
    #[Override]
151
    public function getArguments(): array
152
    {
153
        return $this->arguments;
154
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159
    #[Override]
160
    public function getArgument(string $name): ArgumentParameter|null
161
    {
162
        $arguments = array_filter($this->arguments, static fn (ArgumentParameter $argument) => $argument->getName() === $name);
163
164
        return reset($arguments) ?: null;
165
    }
166
167
    /**
168
     * @inheritDoc
169
     */
170
    #[Override]
171
    public function withArguments(ArgumentParameter ...$arguments): static
172
    {
173
        $new = clone $this;
174
175
        $new->arguments = $arguments;
176
177
        return $new;
178
    }
179
180
    /**
181
     * @inheritDoc
182
     */
183
    #[Override]
184
    public function withAddedArguments(ArgumentParameter ...$arguments): static
185
    {
186
        $new = clone $this;
187
188
        $new->arguments = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array($this->arguments, $arguments) of type array<integer,array|arra...act\ArgumentParameter>> is incompatible with the declared type Valkyrja\Cli\Routing\Dat...act\ArgumentParameter[] of property $arguments.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
189
            ...$this->arguments,
190
            ...$arguments,
191
        ];
192
193
        return $new;
194
    }
195
196
    /**
197
     * @inheritDoc
198
     */
199
    #[Override]
200
    public function hasOptions(): bool
201
    {
202
        return $this->options !== [];
203
    }
204
205
    /**
206
     * @inheritDoc
207
     */
208
    #[Override]
209
    public function getOptions(): array
210
    {
211
        return $this->options;
212
    }
213
214
    /**
215
     * @inheritDoc
216
     */
217
    #[Override]
218
    public function getOption(string $name): OptionParameter|null
219
    {
220
        $options = array_filter($this->options, static fn (OptionParameter $option) => $option->getName() === $name);
221
222
        return reset($options) ?: null;
223
    }
224
225
    /**
226
     * @inheritDoc
227
     */
228
    #[Override]
229
    public function withOptions(OptionParameter ...$options): static
230
    {
231
        $new = clone $this;
232
233
        $new->options = $options;
234
235
        return $new;
236
    }
237
238
    /**
239
     * @inheritDoc
240
     */
241
    #[Override]
242
    public function withAddedOptions(OptionParameter ...$options): static
243
    {
244
        $new = clone $this;
245
246
        $new->options = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array($this->options, $options) of type array<integer,array|arra...tract\OptionParameter>> is incompatible with the declared type Valkyrja\Cli\Routing\Dat...tract\OptionParameter[] of property $options.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
247
            ...$this->options,
248
            ...$options,
249
        ];
250
251
        return $new;
252
    }
253
254
    /**
255
     * Get the command matched middleware.
256
     *
257
     * @return class-string<CommandMatchedMiddleware>[]
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<CommandMatchedMiddleware>[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<CommandMatchedMiddleware>[].
Loading history...
258
     */
259
    #[Override]
260
    public function getCommandMatchedMiddleware(): array
261
    {
262
        return $this->commandMatchedMiddleware;
263
    }
264
265
    /**
266
     * Create a new command with the specified command matched middleware.
267
     *
268
     * @param class-string<CommandMatchedMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<CommandMatchedMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<CommandMatchedMiddleware>.
Loading history...
269
     *
270
     * @return static
271
     */
272
    #[Override]
273
    public function withCommandMatchedMiddleware(string ...$middleware): static
274
    {
275
        $new = clone $this;
276
277
        $new->commandMatchedMiddleware = $middleware;
278
279
        return $new;
280
    }
281
282
    /**
283
     * Create a new command with added command matched middleware.
284
     *
285
     * @param class-string<CommandMatchedMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<CommandMatchedMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<CommandMatchedMiddleware>.
Loading history...
286
     *
287
     * @return static
288
     */
289
    #[Override]
290
    public function withAddedCommandMatchedMiddleware(string ...$middleware): static
291
    {
292
        $new = clone $this;
293
294
        $new->commandMatchedMiddleware = array_merge($this->commandMatchedMiddleware, $middleware);
295
296
        return $new;
297
    }
298
299
    /**
300
     * Get the command dispatched middleware.
301
     *
302
     * @return class-string<CommandDispatchedMiddleware>[]
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<CommandDispatchedMiddleware>[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<CommandDispatchedMiddleware>[].
Loading history...
303
     */
304
    #[Override]
305
    public function getCommandDispatchedMiddleware(): array
306
    {
307
        return $this->commandDispatchedMiddleware;
308
    }
309
310
    /**
311
     * Create a new command with the specified command dispatched middleware.
312
     *
313
     * @param class-string<CommandDispatchedMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<CommandDispatchedMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<CommandDispatchedMiddleware>.
Loading history...
314
     *
315
     * @return static
316
     */
317
    #[Override]
318
    public function withCommandDispatchedMiddleware(string ...$middleware): static
319
    {
320
        $new = clone $this;
321
322
        $new->commandDispatchedMiddleware = $middleware;
323
324
        return $new;
325
    }
326
327
    /**
328
     * Create a new command with added command dispatched middleware.
329
     *
330
     * @param class-string<CommandDispatchedMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<CommandDispatchedMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<CommandDispatchedMiddleware>.
Loading history...
331
     *
332
     * @return static
333
     */
334
    #[Override]
335
    public function withAddedCommandDispatchedMiddleware(string ...$middleware): static
336
    {
337
        $new = clone $this;
338
339
        $new->commandDispatchedMiddleware = array_merge($this->commandDispatchedMiddleware, $middleware);
340
341
        return $new;
342
    }
343
344
    /**
345
     * Get the throwable caught middleware.
346
     *
347
     * @return class-string<ThrowableCaughtMiddleware>[]
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ThrowableCaughtMiddleware>[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ThrowableCaughtMiddleware>[].
Loading history...
348
     */
349
    #[Override]
350
    public function getThrowableCaughtMiddleware(): array
351
    {
352
        return $this->throwableCaughtMiddleware;
353
    }
354
355
    /**
356
     * Create a new command with the specified throwable caught middleware.
357
     *
358
     * @param class-string<ThrowableCaughtMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ThrowableCaughtMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ThrowableCaughtMiddleware>.
Loading history...
359
     *
360
     * @return static
361
     */
362
    #[Override]
363
    public function withThrowableCaughtMiddleware(string ...$middleware): static
364
    {
365
        $new = clone $this;
366
367
        $new->throwableCaughtMiddleware = $middleware;
368
369
        return $new;
370
    }
371
372
    /**
373
     * Create a new command with added throwable caught middleware.
374
     *
375
     * @param class-string<ThrowableCaughtMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ThrowableCaughtMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ThrowableCaughtMiddleware>.
Loading history...
376
     *
377
     * @return static
378
     */
379
    #[Override]
380
    public function withAddedThrowableCaughtMiddleware(string ...$middleware): static
381
    {
382
        $new = clone $this;
383
384
        $new->throwableCaughtMiddleware = array_merge($this->throwableCaughtMiddleware, $middleware);
385
386
        return $new;
387
    }
388
389
    /**
390
     * Get the exited middleware.
391
     *
392
     * @return class-string<ExitedMiddleware>[]
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ExitedMiddleware>[] at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ExitedMiddleware>[].
Loading history...
393
     */
394
    #[Override]
395
    public function getExitedMiddleware(): array
396
    {
397
        return $this->exitedMiddleware;
398
    }
399
400
    /**
401
     * Create a new command with the specified exited middleware.
402
     *
403
     * @param class-string<ExitedMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ExitedMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ExitedMiddleware>.
Loading history...
404
     *
405
     * @return static
406
     */
407
    #[Override]
408
    public function withExitedMiddleware(string ...$middleware): static
409
    {
410
        $new = clone $this;
411
412
        $new->exitedMiddleware = $middleware;
413
414
        return $new;
415
    }
416
417
    /**
418
     * Create a new command with added exited middleware.
419
     *
420
     * @param class-string<ExitedMiddleware> ...$middleware The middleware
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<ExitedMiddleware> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<ExitedMiddleware>.
Loading history...
421
     *
422
     * @return static
423
     */
424
    #[Override]
425
    public function withAddedExitedMiddleware(string ...$middleware): static
426
    {
427
        $new = clone $this;
428
429
        $new->exitedMiddleware = array_merge($this->exitedMiddleware, $middleware);
430
431
        return $new;
432
    }
433
434
    /**
435
     * @inheritDoc
436
     */
437
    #[Override]
438
    public function getDispatch(): MethodDispatch
439
    {
440
        return $this->dispatch;
441
    }
442
443
    /**
444
     * @inheritDoc
445
     */
446
    #[Override]
447
    public function withDispatch(MethodDispatch $dispatch): static
448
    {
449
        $new = clone $this;
450
451
        $new->dispatch = $dispatch;
452
453
        return $new;
454
    }
455
}
456