ArgsFormatBuilder::addArguments()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
3
/*
4
 * This file is part of the webmozart/console package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webmozart\Console\Api\Args\Format;
13
14
use Webmozart\Assert\Assert;
15
use Webmozart\Console\Api\Args\CannotAddArgumentException;
16
use Webmozart\Console\Api\Args\CannotAddOptionException;
17
use Webmozart\Console\Api\Args\NoSuchArgumentException;
18
use Webmozart\Console\Api\Args\NoSuchOptionException;
19
20
/**
21
 * A builder for {@link ArgsFormat} instances.
22
 *
23
 * Use the methods in this class to dynamically build {@link ArgsFormat}
24
 * instances. When you are done configuring the builder, call
25
 * {@link getFormat()} to build an immutable {@link ArgsFormat}.
26
 *
27
 * For convenience, you can call {@link ArgsFormat::build()} to create a new
28
 * builder and use its fluent API to configure and build a format:
29
 *
30
 * ```php
31
 * $format = ArgsFormat::build()
32
 *     ->addCommandName(new CommandName('server'))
33
 *     ->addCommandOption(new CommandOption('add', 'a'))
34
 *     ->addArgument(new Argument('host'))
35
 *     ->addOption(new Option('port', 'p'))
36
 *     ->getFormat();
37
 * ```
38
 *
39
 * You can optionally pass a base format to inherit from. The arguments of the
40
 * base format are prepended to the arguments of the built format. The options
41
 * of the base format are added to the built options:
42
 *
43
 * ```php
44
 * $baseFormat = ArgsFormat::build()
45
 *     ->addOption(new Option('verbose', 'v'))
46
 *     ->getFormat();
47
 *
48
 * $format = ArgsFormat::build($baseFormat)
49
 *     // ...
50
 *     ->getFormat();
51
 * ```
52
 *
53
 * Read {@link ArgsFormat} for a more detailed description of args formats.
54
 *
55
 * @since  1.0
56
 *
57
 * @author Bernhard Schussek <[email protected]>
58
 *
59
 * @see    ArgsFormat
60
 */
61
class ArgsFormatBuilder
62
{
63
    /**
64
     * @var ArgsFormat
65
     */
66
    private $baseFormat;
67
68
    /**
69
     * @var CommandName[]
70
     */
71
    private $commandNames = array();
72
73
    /**
74
     * @var Option[]
75
     */
76
    private $commandOptions = array();
77
78
    /**
79
     * @var Option[]
80
     */
81
    private $commandOptionsByShortName = array();
82
83
    /**
84
     * @var Argument[]
85
     */
86
    private $arguments = array();
87
88
    /**
89
     * @var Option[]
90
     */
91
    private $options = array();
92
93
    /**
94
     * @var Option[]
95
     */
96
    private $optionsByShortName = array();
97
98
    /**
99
     * @var bool
100
     */
101
    private $hasMultiValuedArg = false;
102
103
    /**
104
     * @var bool
105
     */
106
    private $hasOptionalArg = false;
107
108
    /**
109
     * Creates a new builder.
110
     *
111
     * You can optionally pass a base format. The built format inherits all the
112
     * arguments and options from the base format.
113
     *
114
     * @param ArgsFormat $baseFormat The base format.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $baseFormat not be null|ArgsFormat?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
115
     */
116 777
    public function __construct(ArgsFormat $baseFormat = null)
117
    {
118 777
        $this->baseFormat = $baseFormat;
119 777
    }
120
121
    /**
122
     * Returns the base format.
123
     *
124
     * @return ArgsFormat The base format.
125
     */
126 586
    public function getBaseFormat()
127
    {
128 586
        return $this->baseFormat;
129
    }
130
131
    /**
132
     * Sets the command names of the built format.
133
     *
134
     * @param CommandName[] $commandNames The command names.
135
     *
136
     * @return static The current instance.
137
     */
138 1
    public function setCommandNames(array $commandNames)
139
    {
140 1
        $this->commandNames = array();
141
142 1
        $this->addCommandNames($commandNames);
143
144 1
        return $this;
145
    }
146
147
    /**
148
     * Adds command names to the built format.
149
     *
150
     * @param CommandName[] $commandNames The command names to add.
151
     *
152
     * @return static The current instance.
153
     */
154 2
    public function addCommandNames(array $commandNames)
155
    {
156 2
        foreach ($commandNames as $commandName) {
157 2
            $this->addCommandName($commandName);
158
        }
159
160 2
        return $this;
161
    }
162
163
    /**
164
     * Adds a command name to the built format.
165
     *
166
     * @param CommandName $commandName The command name to add.
167
     *
168
     * @return static The current instance.
169
     */
170 277
    public function addCommandName(CommandName $commandName)
171
    {
172 277
        $this->commandNames[] = $commandName;
173
174 277
        return $this;
175
    }
176
177
    /**
178
     * Returns whether the builder contains any command names.
179
     *
180
     * @param bool $includeBase Whether to consider command names of the base
181
     *                          format.
182
     *
183
     * @return bool Returns `true` if the builder contains any command names and
184
     *              `false` otherwise.
185
     */
186 3
    public function hasCommandNames($includeBase = true)
187
    {
188 3
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
189
190 2
        if (count($this->commandNames) > 0) {
191 2
            return true;
192
        }
193
194 2
        if ($includeBase && $this->baseFormat) {
195 2
            return $this->baseFormat->hasCommandNames();
196
        }
197
198 2
        return false;
199
    }
200
201
    /**
202
     * Returns all command names added to the builder.
203
     *
204
     * @param bool $includeBase Whether to include command names of the base
205
     *                          format in the result.
206
     *
207
     * @return CommandName[] The command names.
208
     */
209 586 View Code Duplication
    public function getCommandNames($includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
210
    {
211 586
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
212
213 586
        $commandNames = $this->commandNames;
214
215 586
        if ($includeBase && $this->baseFormat) {
216 5
            $commandNames = array_merge($this->baseFormat->getCommandNames(), $commandNames);
217
        }
218
219 586
        return $commandNames;
220
    }
221
222
    /**
223
     * Sets the command options of the built format.
224
     *
225
     * Any existing command options are removed when this method is called.
226
     *
227
     * @param CommandOption[] $commandOptions The command options of the built
228
     *                                        format.
229
     *
230
     * @return static The current instance.
231
     *
232
     * @throws CannotAddOptionException If an option cannot be added.
233
     *
234
     * @see addCommandOption()
235
     */
236 1
    public function setCommandOptions(array $commandOptions)
237
    {
238 1
        $this->commandOptions = array();
239 1
        $this->commandOptionsByShortName = array();
240
241 1
        $this->addCommandOptions($commandOptions);
242
243 1
        return $this;
244
    }
245
246
    /**
247
     * Adds command options to the builder.
248
     *
249
     * The existing command options stored in the builder are preserved.
250
     *
251
     * @param CommandOption[] $commandOptions The command options to add.
252
     *
253
     * @return static The current instance.
254
     *
255
     * @throws CannotAddOptionException If an option cannot be added.
256
     *
257
     * @see addCommandOption()
258
     */
259 2
    public function addCommandOptions(array $commandOptions)
260
    {
261 2
        foreach ($commandOptions as $commandOption) {
262 2
            $this->addCommandOption($commandOption);
263
        }
264
265 2
        return $this;
266
    }
267
268
    /**
269
     * Adds a command option to the builder.
270
     *
271
     * The existing command options stored in the builder are preserved.
272
     *
273
     * @param CommandOption $commandOption The command option to add.
274
     *
275
     * @return static The current instance.
276
     *
277
     * @throws CannotAddOptionException If the option cannot be added.
278
     *
279
     * @see addCommandOptions()
280
     */
281 89
    public function addCommandOption(CommandOption $commandOption)
282
    {
283 89
        $longName = $commandOption->getLongName();
284 89
        $shortName = $commandOption->getShortName();
285 89
        $longAliases = $commandOption->getLongAliases();
286 89
        $shortAliases = $commandOption->getShortAliases();
287
288 89
        if ($this->hasOption($longName) || $this->hasCommandOption($longName)) {
289 3
            throw CannotAddOptionException::existsAlready($longName);
290
        }
291
292 87
        foreach ($longAliases as $shortAlias) {
293 4
            if ($this->hasOption($shortAlias) || $this->hasCommandOption($shortAlias)) {
294 4
                throw CannotAddOptionException::existsAlready($shortAlias);
295
            }
296
        }
297
298 86
        if ($shortName && ($this->hasOption($shortName) || $this->hasCommandOption($shortName))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $shortName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
299 3
            throw CannotAddOptionException::existsAlready($shortName);
300
        }
301
302 84
        foreach ($shortAliases as $shortAlias) {
303 3
            if ($this->hasOption($shortAlias) || $this->hasCommandOption($shortAlias)) {
304 3
                throw CannotAddOptionException::existsAlready($shortAlias);
305
            }
306
        }
307
308 83
        $this->commandOptions[$longName] = $commandOption;
309
310 83
        if ($shortName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $shortName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
311 57
            $this->commandOptionsByShortName[$shortName] = $commandOption;
312
        }
313
314 83
        foreach ($longAliases as $longAlias) {
315 3
            $this->commandOptions[$longAlias] = $commandOption;
316
        }
317
318 83
        foreach ($shortAliases as $shortAlias) {
319 2
            $this->commandOptionsByShortName[$shortAlias] = $commandOption;
320
        }
321
322 83
        return $this;
323
    }
324
325
    /**
326
     * Returns whether the builder contains a specific command option.
327
     *
328
     * You can either pass the long or the short name of the command option.
329
     *
330
     * @param string $name        The long or short option name.
331
     * @param bool   $includeBase Whether to include command options in the base
332
     *                            format in the search.
333
     *
334
     * @return bool Returns `true` if the command option with the given name
335
     *              could be found and `false` otherwise.
336
     */
337 270 View Code Duplication
    public function hasCommandOption($name, $includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
338
    {
339 270
        Assert::string($name, 'The option name must be a string or an integer. Got: %s');
340 268
        Assert::notEmpty($name, 'The option name must not be empty.');
341 267
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
342
343 266
        if (isset($this->commandOptions[$name]) || isset($this->commandOptionsByShortName[$name])) {
344 8
            return true;
345
        }
346
347 266
        if ($includeBase && $this->baseFormat) {
348 149
            return $this->baseFormat->hasCommandOption($name);
349
        }
350
351 225
        return false;
352
    }
353
354
    /**
355
     * Returns whether the builder contains any command options.
356
     *
357
     * @param bool $includeBase Whether to include command  options in the base
358
     *                          format in the search.
359
     *
360
     * @return bool Returns `true` if the builder contains command options and
361
     *              `false` otherwise.
362
     */
363 3
    public function hasCommandOptions($includeBase = true)
364
    {
365 3
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
366
367 2
        if (count($this->commandOptions) > 0) {
368 2
            return true;
369
        }
370
371 2
        if ($includeBase && $this->baseFormat) {
372 2
            return $this->baseFormat->hasCommandOptions();
373
        }
374
375 2
        return false;
376
    }
377
378
    /**
379
     * Returns a command option by its long or short name.
380
     *
381
     * @param string $name        The long or short option name.
382
     * @param bool   $includeBase Whether to include command options in the base
383
     *                            format in the search.
384
     *
385
     * @return CommandOption The command option.
386
     *
387
     * @throws NoSuchOptionException If the command  option with the given name
388
     *                               does not not exist.
389
     */
390 10 View Code Duplication
    public function getCommandOption($name, $includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
391
    {
392 10
        Assert::string($name, 'The option name must be a string. Got: %s');
393 8
        Assert::notEmpty($name, 'The option name must not be empty.');
394 7
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
395
396 6
        if (isset($this->commandOptions[$name])) {
397 1
            return $this->commandOptions[$name];
398
        }
399
400 5
        if (isset($this->commandOptionsByShortName[$name])) {
401 1
            return $this->commandOptionsByShortName[$name];
402
        }
403
404 4
        if ($includeBase && $this->baseFormat) {
405 3
            return $this->baseFormat->getCommandOption($name);
406
        }
407
408 1
        throw NoSuchOptionException::forOptionName($name);
409
    }
410
411
    /**
412
     * Returns all command options added to the builder.
413
     *
414
     * @param bool $includeBase Whether to include command options of the base
415
     *                          format in the result.
416
     *
417
     * @return CommandOption[] The command options.
0 ignored issues
show
Documentation introduced by
Should the return type not be array<CommandOption|Option>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
418
     */
419 586 View Code Duplication
    public function getCommandOptions($includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
420
    {
421 586
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
422
423 586
        $commandOptions = array_values($this->commandOptions);
424
425 586
        if ($includeBase && $this->baseFormat) {
426
            // prepend base command options
427 6
            $commandOptions = array_merge($this->baseFormat->getCommandOptions(), $commandOptions);
428
        }
429
430 586
        return $commandOptions;
431
    }
432
433
    /**
434
     * Sets the arguments of the built format.
435
     *
436
     * Any existing arguments are removed when this method is called.
437
     *
438
     * @param Argument[] $arguments The arguments of the built format.
439
     *
440
     * @return static The current instance.
441
     *
442
     * @throws CannotAddArgumentException If an argument cannot be added.
443
     *
444
     * @see addArgument()
445
     */
446 1
    public function setArguments(array $arguments)
447
    {
448 1
        $this->arguments = array();
449 1
        $this->hasOptionalArg = false;
450 1
        $this->hasMultiValuedArg = false;
451
452 1
        $this->addArguments($arguments);
453
454 1
        return $this;
455
    }
456
457
    /**
458
     * Adds arguments at the end of the argument list.
459
     *
460
     * The existing arguments stored in the builder are preserved.
461
     *
462
     * @param Argument[] $arguments The arguments to add.
463
     *
464
     * @return static The current instance.
465
     *
466
     * @throws CannotAddArgumentException If an argument cannot be added.
467
     *
468
     * @see addArgument()
469
     */
470 235
    public function addArguments(array $arguments)
471
    {
472 235
        foreach ($arguments as $argument) {
473 96
            $this->addArgument($argument);
474
        }
475
476 235
        return $this;
477
    }
478
479
    /**
480
     * Adds an argument at the end of the argument list.
481
     *
482
     * The existing arguments stored in the builder are preserved.
483
     *
484
     * You cannot add arguments after adding a multi-valued argument. If you do
485
     * so, this method throws an exception.
486
     *
487
     * Adding required arguments after optional arguments is not supported.
488
     * Also in this case an exception is thrown.
489
     *
490
     * @param Argument $argument The argument to add.
491
     *
492
     * @return static The current instance.
493
     *
494
     * @throws CannotAddArgumentException If the argument cannot be added.
495
     */
496 228
    public function addArgument(Argument $argument)
497
    {
498 228
        $name = $argument->getName();
499
500 228
        if ($this->hasArgument($name)) {
501 2
            throw CannotAddArgumentException::existsAlready($name);
502
        }
503
504 228
        if ($this->hasMultiValuedArgument()) {
505 4
            throw CannotAddArgumentException::cannotAddAfterMultiValued();
506
        }
507
508 228
        if ($argument->isRequired() && $this->hasOptionalArgument()) {
509 2
            throw CannotAddArgumentException::cannotAddRequiredAfterOptional();
510
        }
511
512 228
        if ($argument->isMultiValued()) {
513 34
            $this->hasMultiValuedArg = true;
514
        }
515
516 228
        if ($argument->isOptional()) {
517 215
            $this->hasOptionalArg = true;
518
        }
519
520 228
        $this->arguments[$name] = $argument;
521
522 228
        return $this;
523
    }
524
525
    /**
526
     * Returns whether the builder contains a specific argument.
527
     *
528
     * You can either pass the name of the argument or the 0-based position of
529
     * the argument.
530
     *
531
     * @param string|int $name        The argument name or its 0-based position
532
     *                                in the argument list.
533
     * @param bool       $includeBase Whether to include arguments in the base
534
     *                                format in the search.
535
     *
536
     * @return bool Returns `true` if the argument with the given name or
537
     *              position could be found and `false` otherwise.
538
     */
539 232 View Code Duplication
    public function hasArgument($name, $includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
540
    {
541 232
        if (!is_int($name)) {
542 232
            Assert::string($name, 'The argument name must be a string or an integer. Got: %s');
543 230
            Assert::notEmpty($name, 'The argument name must not be empty.');
544
        }
545
546 229
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
547
548 228
        $arguments = is_int($name)
549 2
            ? array_values($this->getArguments($includeBase))
550 228
            : $this->getArguments($includeBase);
551
552 228
        return isset($arguments[$name]);
553
    }
554
555
    /**
556
     * Returns whether the builder contains a multi-valued argument.
557
     *
558
     * @param bool $includeBase Whether to include arguments in the base format
559
     *                          in the search.
560
     *
561
     * @return bool Returns `true` if the builder contains a multi-valued
562
     *              argument and `false` otherwise.
563
     */
564 587
    public function hasMultiValuedArgument($includeBase = true)
565
    {
566 587
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
567
568 587
        if ($this->hasMultiValuedArg) {
569 34
            return true;
570
        }
571
572 587
        if ($includeBase && $this->baseFormat) {
573 126
            return $this->baseFormat->hasMultiValuedArgument();
574
        }
575
576 587
        return false;
577
    }
578
579
    /**
580
     * Returns whether the builder contains an optional argument.
581
     *
582
     * @param bool $includeBase Whether to include arguments in the base format
583
     *                          in the search.
584
     *
585
     * @return bool Returns `true` if the builder contains an optional argument
586
     *              and `false` otherwise.
587
     */
588 587
    public function hasOptionalArgument($includeBase = true)
589
    {
590 587
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
591
592 587
        if ($this->hasOptionalArg) {
593 200
            return true;
594
        }
595
596 517
        if ($includeBase && $this->baseFormat) {
597 7
            return $this->baseFormat->hasOptionalArgument();
598
        }
599
600 517
        return false;
601
    }
602
603
    /**
604
     * Returns whether the builder contains a required argument.
605
     *
606
     * @param bool $includeBase Whether to include arguments in the base format
607
     *                          in the search.
608
     *
609
     * @return bool Returns `true` if the builder contains a required argument
610
     *              and `false` otherwise.
611
     */
612 3 View Code Duplication
    public function hasRequiredArgument($includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
613
    {
614 3
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
615
616 2
        if (!$this->hasOptionalArg && count($this->arguments) > 0) {
617 1
            return true;
618
        }
619
620 2
        if ($includeBase && $this->baseFormat) {
621 2
            return $this->baseFormat->hasRequiredArgument();
622
        }
623
624 2
        return false;
625
    }
626
627
    /**
628
     * Returns whether the builder contains any argument.
629
     *
630
     * @param bool $includeBase Whether to include arguments in the base format
631
     *                          in the search.
632
     *
633
     * @return bool Returns `true` if the builder contains any argument and
634
     *              `false` otherwise.
635
     */
636 3
    public function hasArguments($includeBase = true)
637
    {
638 3
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
639
640 2
        if (count($this->arguments) > 0) {
641 2
            return true;
642
        }
643
644 2
        if ($includeBase && $this->baseFormat) {
645 2
            return $this->baseFormat->hasArguments();
646
        }
647
648 2
        return false;
649
    }
650
651
    /**
652
     * Returns an argument by its name or position.
653
     *
654
     * You can either pass the name of the argument or the 0-based position of
655
     * the argument.
656
     *
657
     * @param string|int $name        The argument name or its 0-based position
658
     *                                in the argument list.
659
     * @param bool       $includeBase Whether to include arguments in the base
660
     *                                format in the search.
661
     *
662
     * @return Argument The argument.
663
     *
664
     * @throws NoSuchArgumentException If the argument with the given name or
665
     *                                 position does not exist.
666
     */
667 11 View Code Duplication
    public function getArgument($name, $includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
668
    {
669 11
        if (!is_int($name)) {
670 8
            Assert::string($name, 'The argument name must be a string or integer. Got: %s');
671 6
            Assert::notEmpty($name, 'The argument name must not be empty.');
672
        }
673
674 8
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
675
676 7
        if (is_int($name)) {
677 3
            $arguments = array_values($this->getArguments($includeBase));
678
679 3
            if (!isset($arguments[$name])) {
680 3
                throw NoSuchArgumentException::forPosition($name);
681
            }
682
        } else {
683 4
            $arguments = $this->getArguments($includeBase);
684
685 4
            if (!isset($arguments[$name])) {
686 2
                throw NoSuchArgumentException::forArgumentName($name);
687
            }
688
        }
689
690 4
        return $arguments[$name];
691
    }
692
693
    /**
694
     * Returns all arguments added to the builder.
695
     *
696
     * @param bool $includeBase Whether to include arguments of the base format
697
     *                          in the result.
698
     *
699
     * @return Argument[] The arguments.
700
     */
701 589 View Code Duplication
    public function getArguments($includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
702
    {
703 589
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
704
705 589
        $arguments = $this->arguments;
706
707 589
        if ($includeBase && $this->baseFormat) {
708
            // prepend base arguments
709 130
            $arguments = array_replace($this->baseFormat->getArguments(), $arguments);
710
        }
711
712 589
        return $arguments;
713
    }
714
715
    /**
716
     * Sets the options of the built format.
717
     *
718
     * Any existing options are removed when this method is called.
719
     *
720
     * @param Option[] $options The options of the built format.
721
     *
722
     * @return static The current instance.
723
     *
724
     * @throws CannotAddOptionException If an option cannot be added.
725
     *
726
     * @see addOption()
727
     */
728 1
    public function setOptions(array $options)
729
    {
730 1
        $this->options = array();
731 1
        $this->optionsByShortName = array();
732
733 1
        $this->addOptions($options);
734
735 1
        return $this;
736
    }
737
738
    /**
739
     * Adds options at the end of the options list.
740
     *
741
     * The existing options stored in the builder are preserved.
742
     *
743
     * @param Option[] $options The options to add.
744
     *
745
     * @return static The current instance.
746
     *
747
     * @throws CannotAddOptionException If an option cannot be added.
748
     *
749
     * @see addOption()
750
     */
751 241
    public function addOptions(array $options)
752
    {
753 241
        foreach ($options as $option) {
754 102
            $this->addOption($option);
755
        }
756
757 241
        return $this;
758
    }
759
760
    /**
761
     * Adds an option at the end of the options list.
762
     *
763
     * The existing options stored in the builder are preserved.
764
     *
765
     * @param Option $option The option to add.
766
     *
767
     * @return static The current instance.
768
     *
769
     * @throws CannotAddOptionException If the option cannot be added.
770
     *
771
     * @see addOptions()
772
     */
773 200
    public function addOption(Option $option)
774
    {
775 200
        $longName = $option->getLongName();
776 200
        $shortName = $option->getShortName();
777
778 200
        if ($this->hasOption($longName) || $this->hasCommandOption($longName)) {
779 4
            throw CannotAddOptionException::existsAlready($longName);
780
        }
781
782 198
        if ($shortName && ($this->hasOption($shortName) || $this->hasCommandOption($shortName))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $shortName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
783 4
            throw CannotAddOptionException::existsAlready($shortName);
784
        }
785
786 196
        $this->options[$longName] = $option;
787
788 196
        if ($shortName) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $shortName of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
789 138
            $this->optionsByShortName[$shortName] = $option;
790
        }
791
792 196
        return $this;
793
    }
794
795
    /**
796
     * Returns whether the builder contains a specific option.
797
     *
798
     * You can either pass the long or the short name of the option.
799
     *
800
     * @param string $name        The long or short option name.
801
     * @param bool   $includeBase Whether to include options in the base format
802
     *                            in the search.
803
     *
804
     * @return bool Returns `true` if the option with the given name could be
805
     *              found and `false` otherwise.
806
     */
807 270 View Code Duplication
    public function hasOption($name, $includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
808
    {
809 270
        Assert::string($name, 'The option name must be a string or an integer. Got: %s');
810 268
        Assert::notEmpty($name, 'The option name must not be empty.');
811 267
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
812
813 266
        if (isset($this->options[$name]) || isset($this->optionsByShortName[$name])) {
814 8
            return true;
815
        }
816
817 266
        if ($includeBase && $this->baseFormat) {
818 151
            return $this->baseFormat->hasOption($name);
819
        }
820
821 225
        return false;
822
    }
823
824
    /**
825
     * Returns whether the builder contains any option.
826
     *
827
     * @param bool $includeBase Whether to include options in the base format
828
     *                          in the search.
829
     *
830
     * @return bool Returns `true` if the builder contains any option and
831
     *              `false` otherwise.
832
     */
833 3
    public function hasOptions($includeBase = true)
834
    {
835 3
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
836
837 2
        if (count($this->options) > 0) {
838 2
            return true;
839
        }
840
841 2
        if ($includeBase && $this->baseFormat) {
842 2
            return $this->baseFormat->hasOptions();
843
        }
844
845 2
        return false;
846
    }
847
848
    /**
849
     * Returns an option by its long or short name.
850
     *
851
     * @param string $name        The long or short option name.
852
     * @param bool   $includeBase Whether to include options in the base format
853
     *                            in the search.
854
     *
855
     * @return Option The option.
856
     *
857
     * @throws NoSuchOptionException If the option with the given name does not
858
     *                               not exist.
859
     */
860 10 View Code Duplication
    public function getOption($name, $includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
861
    {
862 10
        Assert::string($name, 'The option name must be a string. Got: %s');
863 8
        Assert::notEmpty($name, 'The option name must not be empty.');
864 7
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
865
866 6
        if (isset($this->options[$name])) {
867 1
            return $this->options[$name];
868
        }
869
870 5
        if (isset($this->optionsByShortName[$name])) {
871 1
            return $this->optionsByShortName[$name];
872
        }
873
874 4
        if ($includeBase && $this->baseFormat) {
875 3
            return $this->baseFormat->getOption($name);
876
        }
877
878 1
        throw NoSuchOptionException::forOptionName($name);
879
    }
880
881
    /**
882
     * Returns all options added to the builder.
883
     *
884
     * @param bool $includeBase Whether to include options of the base format
885
     *                          in the result.
886
     *
887
     * @return Option[] The options.
888
     */
889 589 View Code Duplication
    public function getOptions($includeBase = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
890
    {
891 589
        Assert::boolean($includeBase, 'The parameter $includeBase must be a boolean. Got: %s');
892
893 589
        $options = $this->options;
894
895 589
        if ($includeBase && $this->baseFormat) {
896
            // append base options
897 6
            $options = array_replace($options, $this->baseFormat->getOptions());
898
        }
899
900 589
        return $options;
901
    }
902
903
    /**
904
     * Builds a format with the arguments and options added to the builder.
905
     *
906
     * @return ArgsFormat The built format.
907
     */
908 366
    public function getFormat()
909
    {
910 366
        return new ArgsFormat($this, $this->baseFormat);
911
    }
912
}
913