CommandConfig::getSubCommandConfig()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4285
cc 3
eloc 5
nc 3
nop 1
crap 3
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\Config;
13
14
use Webmozart\Assert\Assert;
15
use Webmozart\Console\Api\Args\Format\ArgsFormat;
16
use Webmozart\Console\Api\Args\Format\CommandName;
17
use Webmozart\Console\Api\Command\NoSuchCommandException;
18
19
/**
20
 * The configuration of a console command.
21
 *
22
 * There are two different ways of creating a command configuration:
23
 *
24
 *  * Call {@link create()} or {@link ApplicationConfig::beginCommand()} and use
25
 *    the fluent interface:
26
 *
27
 *    ```php
28
 *    $config = CommandConfig::create()
29
 *        ->setName('server')
30
 *        ->setDescription('List and manage servers')
31
 *
32
 *        ->beginSubCommand('add')
33
 *            ->setDescription('Add a new server')
34
 *            ->addArgument('host', Argument::REQUIRED)
35
 *            ->addOption('port', 'p', Option::VALUE_OPTIONAL, null, 80)
36
 *        ->end()
37
 *
38
 *        // ...
39
 *    ;
40
 *    ```
41
 *
42
 *  * Extend the class and implement the {@link configure()} method:
43
 *
44
 *    ```php
45
 *    class ServerCommandConfig extends CommandConfig
46
 *    {
47
 *        protected function configure()
48
 *        {
49
 *            $this
50
 *                ->setName('server')
51
 *                ->setDescription('List and manage servers')
52
 *
53
 *                ->beginSubCommand('add')
54
 *                    ->setDescription('Add a new server')
55
 *                    ->addArgument('host', Argument::REQUIRED)
56
 *                    ->addOption('port', 'p', Option::VALUE_OPTIONAL, null, 80)
57
 *                ->end()
58
 *
59
 *                // ...
60
 *            ;
61
 *        }
62
 *    }
63
 *    ```
64
 *
65
 * You can choose between two different ways of executing a command:
66
 *
67
 *  * You can register a callback with {@link setCallback()}. The callback
68
 *    receives the input, the standard output and the error output as
69
 *    arguments:
70
 *
71
 *    ```php
72
 *    $config->setCallback(
73
 *        function (InputInterface $input, OutputInterface $output, OutputInterface $errorOutput) {
74
 *            // ...
75
 *        }
76
 *    );
77
 *    ```
78
 *
79
 *  * You can implement a custom command handler and return the handler from
80
 *    {@link getHandler()}. Since the command handler is separated, it can be
81
 *    easily tested:
82
 *
83
 *    ```php
84
 *    class ServerConfig extends CommandConfig
85
 *    {
86
 *        public function getHandler()
87
 *        {
88
 *            return new ServerHandler();
89
 *        }
90
 *    }
91
 *    ```
92
 *
93
 * @since  1.0
94
 *
95
 * @author Bernhard Schussek <[email protected]>
96
 */
97
class CommandConfig extends Config
98
{
99
    /**
100
     * @var string
101
     */
102
    private $name;
103
104
    /**
105
     * @var ApplicationConfig
106
     */
107
    private $applicationConfig;
108
109
    /**
110
     * @var string[]
111
     */
112
    private $aliases = array();
113
114
    /**
115
     * @var string
116
     */
117
    private $description;
118
119
    /**
120
     * @var string
121
     */
122
    private $help;
123
124
    /**
125
     * @var bool
126
     */
127
    private $enabled = true;
128
129
    /**
130
     * @var string
131
     */
132
    private $processTitle;
133
134
    /**
135
     * @var bool
136
     */
137
    private $default = false;
138
139
    /**
140
     * @var bool
141
     */
142
    private $anonymous = false;
143
144
    /**
145
     * @var SubCommandConfig[]
146
     */
147
    private $subCommandConfigs = array();
148
149
    /**
150
     * Creates a new configuration.
151
     *
152
     * @param string            $name              The name of the command.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $name not be string|null?

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...
153
     * @param ApplicationConfig $applicationConfig The application configuration.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $applicationConfig not be null|ApplicationConfig?

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...
154
     *
155
     * @return static The created configuration.
156
     */
157 31
    public static function create($name = null, ApplicationConfig $applicationConfig = null)
158
    {
159 31
        return new static($name, $applicationConfig);
160
    }
161
162
    /**
163
     * Creates a new configuration.
164
     *
165
     * @param string            $name              The name of the command.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $name not be string|null?

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...
166
     * @param ApplicationConfig $applicationConfig The application configuration.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $applicationConfig not be null|ApplicationConfig?

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...
167
     */
168 359
    public function __construct($name = null, ApplicationConfig $applicationConfig = null)
169
    {
170 359
        $this->applicationConfig = $applicationConfig;
171
172 359
        parent::__construct();
173
174 359
        if ($name) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $name of type string|null 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...
175 322
            $this->setName($name);
176
        }
177 359
    }
178
179
    /**
180
     * Returns the name of the command.
181
     *
182
     * @return string The name of the command.
183
     */
184 256
    public function getName()
185
    {
186 256
        return $this->name;
187
    }
188
189
    /**
190
     * Sets the name of the command.
191
     *
192
     * @param string $name The name of the command.
193
     *
194
     * @return static The current instance.
195
     */
196 329
    public function setName($name)
197
    {
198 329
        if (null !== $name) {
199 329
            Assert::string($name, 'The command name must be a string or null. Got: %s');
200 329
            Assert::notEmpty($name, 'The command name must not be empty.');
201 329
            Assert::regex($name, '~^[a-zA-Z0-9\-]+$~', 'The command name should contain letters, digits and hyphens only. Got: %s');
202
        }
203
204 329
        $this->name = $name;
205
206 329
        return $this;
207
    }
208
209
    /**
210
     * Returns the application configuration.
211
     *
212
     * @return ApplicationConfig The application configuration.
213
     */
214 55
    public function getApplicationConfig()
215
    {
216 55
        return $this->applicationConfig;
217
    }
218
219
    /**
220
     * Sets the application configuration.
221
     *
222
     * @param ApplicationConfig $applicationConfig The application configuration.
223
     */
224 30
    public function setApplicationConfig($applicationConfig)
225
    {
226 30
        $this->applicationConfig = $applicationConfig;
227 30
    }
228
229
    /**
230
     * Ends the block when dynamically configuring a command configuration.
231
     *
232
     * This method is usually used together with
233
     * {@link ApplicationConfig::beginCommand()}:
234
     *
235
     * ```php
236
     * $config
237
     *     ->beginCommand('command')
238
     *         // ...
239
     *     ->end()
240
     *
241
     *     // ...
242
     * ;
243
     * ```
244
     *
245
     * @return ApplicationConfig The application configuration.
246
     */
247 109
    public function end()
248
    {
249 109
        return $this->applicationConfig;
250
    }
251
252
    /**
253
     * Returns the alias names of the command.
254
     *
255
     * @return string[] An array of alias names of the command.
256
     *
257
     * @see addAlias(), setAliases()
258
     */
259 241
    public function getAliases()
260
    {
261 241
        return $this->aliases;
262
    }
263
264
    /**
265
     * Adds an alias name.
266
     *
267
     * An alias is an alternative name that can be used when calling the
268
     * command. Aliases are a useful way for migrating a command from one name
269
     * to another.
270
     *
271
     * Existing alias names are preserved.
272
     *
273
     * @param string $alias The alias name to add.
274
     *
275
     * @return static The current instance.
276
     *
277
     * @see addAliases(), setAliases(), getAlias()
278
     */
279 58
    public function addAlias($alias)
280
    {
281 58
        Assert::string($alias, 'The command alias must be a string. Got: %s');
282 49
        Assert::notEmpty($alias, 'The command alias must not be empty.');
283 45
        Assert::regex($alias, '~^[a-zA-Z0-9\-]+$~', 'The command alias should contain letters, digits and hyphens only. Got: %s');
284
285 41
        $this->aliases[] = $alias;
286
287 41
        return $this;
288
    }
289
290
    /**
291
     * Adds a list of alias names.
292
     *
293
     * Existing alias names are preserved.
294
     *
295
     * @param array $aliases The alias names to add.
296
     *
297
     * @return static The current instance.
298
     *
299
     * @see addAlias(), setAliases(), getAlias()
300
     */
301 12
    public function addAliases(array $aliases)
302
    {
303 12
        foreach ($aliases as $alias) {
304 12
            $this->addAlias($alias);
305
        }
306
307 6
        return $this;
308
    }
309
310
    /**
311
     * Sets the alias names of the command.
312
     *
313
     * Existing alias names are replaced.
314
     *
315
     * @param array $aliases The alias names.
316
     *
317
     * @return static The current instance.
318
     *
319
     * @see addAlias(), addAliases(), getAlias()
320
     */
321 8
    public function setAliases(array $aliases)
322
    {
323 8
        $this->aliases = array();
324
325 8
        $this->addAliases($aliases);
326
327 5
        return $this;
328
    }
329
330
    /**
331
     * Returns the description of the command.
332
     *
333
     * @return string The description of the command.
334
     *
335
     * @see setDescription()
336
     */
337 40
    public function getDescription()
338
    {
339 40
        return $this->description;
340
    }
341
342
    /**
343
     * Sets the description of the command.
344
     *
345
     * The description is a short one-liner that describes the command in the
346
     * command listing. The description should be written in imperative form
347
     * rather than in descriptive form. So:
348
     *
349
     * > List the contents of a directory.
350
     *
351
     * should be preferred over
352
     *
353
     * > Lists the contents of a directory.
354
     *
355
     * @param string $description The description.
356
     *
357
     * @return static The current instance.
358
     *
359
     * @see getDescription()
360
     */
361 92 View Code Duplication
    public function setDescription($description)
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...
362
    {
363 92
        if (null !== $description) {
364 91
            Assert::string($description, 'The command description must be a string or null. Got: %s');
365 90
            Assert::notEmpty($description, 'The command description must not be empty.');
366
        }
367
368 90
        $this->description = $description;
369
370 90
        return $this;
371
    }
372
373
    /**
374
     * Returns the help text of the command.
375
     *
376
     * The help text provides additional information about a command that is
377
     * displayed in the help view.
378
     *
379
     * @return string The help text of the command.
380
     *
381
     * @see setHelp()
382
     */
383 46
    public function getHelp()
384
    {
385 46
        return $this->help;
386
    }
387
388
    /**
389
     * Sets the help text of the command.
390
     *
391
     * The help text provides additional information about a command that is
392
     * displayed in the help view.
393
     *
394
     * @param string $help The help text of the command.
395
     *
396
     * @return static The current instance.
397
     *
398
     * @see getHelp()
399
     */
400 6 View Code Duplication
    public function setHelp($help)
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...
401
    {
402 6
        if (null !== $help) {
403 5
            Assert::string($help, 'The help text must be a string or null. Got: %s');
404 4
            Assert::notEmpty($help, 'The help text must not be empty.');
405
        }
406
407 4
        $this->help = $help;
408
409 4
        return $this;
410
    }
411
412
    /**
413
     * Returns whether the command is enabled or not in the current environment.
414
     *
415
     * @return bool Returns `true` if the command is currently enabled and
416
     *              `false` otherwise.
417
     *
418
     * @see enable(), disable(), enableIf(), disableIf()
419
     */
420 147
    public function isEnabled()
421
    {
422 147
        return $this->enabled;
423
    }
424
425
    /**
426
     * Enables the command.
427
     *
428
     * @return static The current instance.
429
     *
430
     * @see enableIf(), disable(), isEnabled()
431
     */
432 3
    public function enable()
433
    {
434 3
        $this->enabled = true;
435
436 3
        return $this;
437
    }
438
439
    /**
440
     * Enables the command if a condition holds and disables it otherwise.
441
     *
442
     * @param bool $condition The condition under which to enable the command.
443
     *
444
     * @return static The current instance.
445
     *
446
     * @see enable(), disable(), isEnabled()
447
     */
448 1
    public function enableIf($condition)
449
    {
450 1
        $this->enabled = (bool) $condition;
451
452 1
        return $this;
453
    }
454
455
    /**
456
     * Disables the command.
457
     *
458
     * @return static The current instance.
459
     *
460
     * @see disableIf(), enable(), isEnabled()
461
     */
462 5
    public function disable()
463
    {
464 5
        $this->enabled = false;
465
466 5
        return $this;
467
    }
468
469
    /**
470
     * Disables the command if a condition holds and enables it otherwise.
471
     *
472
     * @param bool $condition The condition under which to disable the command.
473
     *
474
     * @return static The current instance.
475
     *
476
     * @see disable(), enable(), isEnabled()
477
     */
478 1
    public function disableIf($condition)
479
    {
480 1
        $this->enabled = !$condition;
481
482 1
        return $this;
483
    }
484
485
    /**
486
     * Returns the title of the command process.
487
     *
488
     * @return string|null The process title or `null` if no title should be
489
     *                     set.
490
     *
491
     * @see setProcessTitle()
492
     */
493 54
    public function getProcessTitle()
494
    {
495 54
        return $this->processTitle;
496
    }
497
498
    /**
499
     * Sets the title of the command process.
500
     *
501
     * @param string|null $processTitle The process title or `null` if no title
502
     *                                  should be set.
503
     *
504
     * @return static The current instance.
505
     *
506
     * @see getProcessTitle()
507
     */
508 4
    public function setProcessTitle($processTitle)
509
    {
510 4
        if (null !== $processTitle) {
511 3
            Assert::string($processTitle, 'The command process title must be a string or null. Got: %s');
512 2
            Assert::notEmpty($processTitle, 'The command process title must not be empty.');
513
        }
514
515 2
        $this->processTitle = $processTitle;
516
517 2
        return $this;
518
    }
519
520
    /**
521
     * Marks the command as default command.
522
     *
523
     * The names of default commands can be omitted when calling the command.
524
     * For example, the following command can be called in two ways:
525
     *
526
     * ```php
527
     * protected function configure()
528
     * {
529
     *     $this
530
     *         ->beginCommand('add')
531
     *             ->markDefault()
532
     *             ->addArgument('host', Argument::REQUIRED)
533
     *         ->end()
534
     *
535
     *         // ...
536
     *     ;
537
     * }
538
     * ```
539
     *
540
     * The first way is to call the command regularly. The second way is to
541
     * omit the name of the command:
542
     *
543
     * ```php
544
     * $ ./console add localhost
545
     * $ ./console localhost
546
     * ```
547
     *
548
     * @return static The current instance.
549
     *
550
     * @see markAnonymous(), markNoDefault()
551
     */
552 90
    public function markDefault()
553
    {
554 90
        $this->default = true;
555 90
        $this->anonymous = false;
556
557 90
        return $this;
558
    }
559
560
    /**
561
     * Marks the command as anonymous command.
562
     *
563
     * Anonymous commands cannot be called by name:
564
     *
565
     * ```php
566
     * protected function configure()
567
     * {
568
     *     $this
569
     *         ->beginCommand('add')
570
     *             ->markAnonymous()
571
     *             ->addArgument('host', Argument::REQUIRED)
572
     *         ->end()
573
     *
574
     *         // ...
575
     *     ;
576
     * }
577
     * ```
578
     *
579
     * The name "add" is given to the command only to access the command later
580
     * on. Since the command is anonymous, the name cannot be passed when
581
     * when calling the command:
582
     *
583
     * ```php
584
     * $ ./console add localhost
585
     * ```
586
     *
587
     * Instead, the command should be called without name:
588
     *
589
     * ```php
590
     * $ ./console localhost
591
     * ```
592
     *
593
     * @return static The current instance.
594
     *
595
     * @see markDefault(), markNoDefault()
596
     */
597 10
    public function markAnonymous()
598
    {
599 10
        $this->default = true;
600 10
        $this->anonymous = true;
601
602 10
        return $this;
603
    }
604
605
    /**
606
     * Marks the command as neither anonymous nor default.
607
     *
608
     * @return static The current instance.
609
     *
610
     * @see markDefault(), markAnonymous()
611
     */
612 1
    public function markNoDefault()
613
    {
614 1
        $this->default = false;
615 1
        $this->anonymous = false;
616
617 1
        return $this;
618
    }
619
620
    /**
621
     * Returns whether the command is a default command.
622
     *
623
     * @return bool Returns `true` if either {@link markDefault()} or
624
     *              {@link markAnonymous()} was called and `false` otherwise.
625
     */
626 140
    public function isDefault()
627
    {
628 140
        return $this->default;
629
    }
630
631
    /**
632
     * Returns whether the command is anonymous.
633
     *
634
     * @return bool Returns `true` if {@link markAnonymous()} was called and
635
     *              `false` otherwise.
636
     */
637 147
    public function isAnonymous()
638
    {
639 147
        return $this->anonymous;
640
    }
641
642
    /**
643
     * Builds an {@link ArgsFormat} instance with the given base format.
644
     *
645
     * @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...
646
     *
647
     * @return ArgsFormat The built format for the console arguments.
648
     */
649 227
    public function buildArgsFormat(ArgsFormat $baseFormat = null)
650
    {
651 227
        $formatBuilder = ArgsFormat::build($baseFormat);
652
653 227
        if (!$this->anonymous) {
654 225
            $formatBuilder->addCommandName(new CommandName($this->name, $this->aliases));
655
        }
656
657 227
        $formatBuilder->addOptions($this->getOptions());
658 227
        $formatBuilder->addArguments($this->getArguments());
659
660 227
        return $formatBuilder->getFormat();
661
    }
662
663
    /**
664
     * Starts a configuration block for a sub-command.
665
     *
666
     * A sub-command is executed if the name of the command is passed after the
667
     * name of the containing command. For example, if the command "server" has
668
     * a sub-command command named "add", that command can be called with:
669
     *
670
     * ```
671
     * $ console server add ...
672
     * ```
673
     *
674
     * The configuration of the sub-command is returned by this method. You can
675
     * use the fluent interface to configure the sub-command before jumping back
676
     * to this configuration with {@link SubCommandConfig::end()}:
677
     *
678
     * ```php
679
     * protected function configure()
680
     * {
681
     *     $this
682
     *         ->beginCommand('server')
683
     *             ->setDescription('List and manage servers')
684
     *
685
     *             ->beginSubCommand('add')
686
     *                 ->setDescription('Add a server')
687
     *                 ->addArgument('host', Argument::REQUIRED)
688
     *                 ->addOption('port', 'p', Option::VALUE_OPTIONAL, null, 80)
689
     *             ->end()
690
     *         ->end()
691
     *
692
     *         // ...
693
     *     ;
694
     * }
695
     * ```
696
     *
697
     * @param string $name The name of the sub-command.
698
     *
699
     * @return SubCommandConfig The sub-command configuration.
700
     *
701
     * @see editSubCommand()
702
     */
703 7
    public function beginSubCommand($name)
704
    {
705 7
        $config = new SubCommandConfig($name, $this);
706
707
        // The name is dynamic, so don't store by name
708 7
        $this->subCommandConfigs[] = $config;
709
710 7
        return $config;
711
    }
712
713
    /**
714
     * Alias for {@link getSubCommandConfig()}.
715
     *
716
     * This method can be used to nicely edit a sub-command inherited from a
717
     * parent configuration using the fluent API:
718
     *
719
     * ```php
720
     * protected function configure()
721
     * {
722
     *     parent::configure();
723
     *
724
     *     $this
725
     *         ->editCommand('server')
726
     *             ->editSubCommand('add')
727
     *                 // ...
728
     *             ->end()
729
     *         ->end()
730
     *
731
     *         // ...
732
     *     ;
733
     * }
734
     * ```
735
     *
736
     * @param string $name The name of the sub-command to edit.
737
     *
738
     * @return SubCommandConfig The sub-command configuration.
739
     *
740
     * @see beginSubCommand()
741
     */
742 1
    public function editSubCommand($name)
743
    {
744 1
        return $this->getSubCommandConfig($name);
745
    }
746
747
    /**
748
     * Starts a configuration block for an option command.
749
     *
750
     * An option command is executed if the corresponding option is passed after
751
     * the command name. For example, if the command "server" has an option
752
     * command named "--add" with the short name "-a", that command can be
753
     * called with:
754
     *
755
     * ```
756
     * $ console server --add ...
757
     * $ console server -a ...
758
     * ```
759
     *
760
     * The configuration of the option command is returned by this method.
761
     * You can use the fluent interface to configure the option command
762
     * before jumping back to this configuration with
763
     * {@link SubCommandConfig::end()}:
764
     *
765
     * ```php
766
     * protected function configure()
767
     * {
768
     *     $this
769
     *         ->beginCommand('server')
770
     *             ->setDescription('List and manage servers')
771
     *
772
     *             ->beginOptionCommand('add', 'a')
773
     *                 ->setDescription('Add a server')
774
     *                 ->addArgument('host', Argument::REQUIRED)
775
     *                 ->addOption('port', 'p', Option::VALUE_OPTIONAL, null, 80)
776
     *             ->end()
777
     *         ->end()
778
     *
779
     *         // ...
780
     *     ;
781
     * }
782
     * ```
783
     *
784
     * @param string $name      The name of the option command.
785
     * @param string $shortName The short name of the option command.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $shortName not be string|null?

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...
786
     *
787
     * @return OptionCommandConfig The option command configuration.
788
     *
789
     * @see editOptionCommand()
790
     */
791 7
    public function beginOptionCommand($name, $shortName = null)
792
    {
793 7
        $config = new OptionCommandConfig($name, $shortName, $this);
794
795
        // The name is dynamic, so don't store by name
796 7
        $this->subCommandConfigs[] = $config;
797
798 7
        return $config;
799
    }
800
801
    /**
802
     * Alias for {@link getSubCommandConfig()}.
803
     *
804
     * This method can be used to nicely edit an option command inherited from a
805
     * parent configuration using the fluent API:
806
     *
807
     * ```php
808
     * protected function configure()
809
     * {
810
     *     parent::configure();
811
     *
812
     *     $this
813
     *         ->editCommand('server')
814
     *             ->editOptionCommand('add')
815
     *                 // ...
816
     *             ->end()
817
     *         ->end()
818
     *
819
     *         // ...
820
     *     ;
821
     * }
822
     * ```
823
     *
824
     * @param string $name The name of the option command to edit.
825
     *
826
     * @return OptionCommandConfig The option command configuration.
827
     *
828
     * @see beginOptionCommand()
829
     */
830 1
    public function editOptionCommand($name)
831
    {
832 1
        return $this->getSubCommandConfig($name);
833
    }
834
835
    /**
836
     * Adds configuration for a sub-command.
837
     *
838
     * @param SubCommandConfig $config The sub-command configuration.
839
     *
840
     * @return static The current instance.
841
     *
842
     * @see beginSubCommand()
843
     */
844 28
    public function addSubCommandConfig(SubCommandConfig $config)
845
    {
846
        // The name is dynamic, so don't store by name
847 28
        $this->subCommandConfigs[] = $config;
848
849 28
        $config->setParentConfig($this);
850
851 28
        return $this;
852
    }
853
854
    /**
855
     * Adds sub-command configurations to the command.
856
     *
857
     * @param SubCommandConfig[] $configs The sub-command configurations.
858
     *
859
     * @return static The current instance.
860
     *
861
     * @see beginSubCommand()
862
     */
863 2
    public function addSubCommandConfigs(array $configs)
864
    {
865 2
        foreach ($configs as $command) {
866 2
            $this->addSubCommandConfig($command);
867
        }
868
869 2
        return $this;
870
    }
871
872
    /**
873
     * Sets the sub-command configurations of the command.
874
     *
875
     * @param SubCommandConfig[] $configs The sub-command configurations.
876
     *
877
     * @return static The current instance.
878
     *
879
     * @see beginSubCommand()
880
     */
881 1
    public function setSubCommandConfigs(array $configs)
882
    {
883 1
        $this->subCommandConfigs = array();
884
885 1
        $this->addSubCommandConfigs($configs);
886
887 1
        return $this;
888
    }
889
890
    /**
891
     * Returns the sub-command configuration for a given name.
892
     *
893
     * @param string $name The name of the sub-command.
894
     *
895
     * @return SubCommandConfig The sub-command configuration.
896
     *
897
     * @throws NoSuchCommandException If the sub-command configuration is not
898
     *                                found.
899
     *
900
     * @see beginSubCommand()
901
     */
902 4
    public function getSubCommandConfig($name)
903
    {
904 4
        foreach ($this->subCommandConfigs as $commandConfig) {
905 3
            if ($name === $commandConfig->getName()) {
906 3
                return $commandConfig;
907
            }
908
        }
909
910 1
        throw NoSuchCommandException::forCommandName($name);
911
    }
912
913
    /**
914
     * Returns the configurations of all sub-commands.
915
     *
916
     * @return SubCommandConfig[] The sub-command configurations.
917
     *
918
     * @see beginSubCommand()
919
     */
920 236
    public function getSubCommandConfigs()
921
    {
922 236
        return $this->subCommandConfigs;
923
    }
924
925
    /**
926
     * Returns whether the command has a sub-command with a given name.
927
     *
928
     * @param string $name The name of the sub-command.
929
     *
930
     * @return bool Returns `true` if the sub-command configuration with the
931
     *              given name exists and `false` otherwise.
932
     *
933
     * @see beginSubCommand()
934
     */
935 1
    public function hasSubCommandConfig($name)
936
    {
937 1
        foreach ($this->subCommandConfigs as $commandConfig) {
938 1
            if ($name === $commandConfig->getName()) {
939 1
                return true;
940
            }
941
        }
942
943 1
        return false;
944
    }
945
946
    /**
947
     * Returns whether the command has any registered sub-command configurations.
948
     *
949
     * @return bool Returns `true` if sub-command configurations were added to
950
     *              the command and `false` otherwise.
951
     *
952
     * @see beginSubCommand()
953
     */
954 1
    public function hasSubCommandConfigs()
955
    {
956 1
        return count($this->subCommandConfigs) > 0;
957
    }
958
959
    /**
960
     * {@inheritdoc}
961
     */
962 15
    protected function getDefaultHelperSet()
963
    {
964 15
        return $this->applicationConfig
965 14
            ? $this->applicationConfig->getHelperSet()
966 15
            : parent::getDefaultHelperSet();
967
    }
968
969
    /**
970
     * {@inheritdoc}
971
     */
972 1
    protected function getDefaultHandler()
973
    {
974 1
        return $this->applicationConfig
975 1
            ? $this->applicationConfig->getHandler()
976 1
            : parent::getDefaultHandler();
977
    }
978
979
    /**
980
     * {@inheritdoc}
981
     */
982 45
    protected function getDefaultHandlerMethod()
983
    {
984 45
        return $this->applicationConfig
985 38
            ? $this->applicationConfig->getHandlerMethod()
986 45
            : parent::getDefaultHandlerMethod();
987
    }
988
989
    /**
990
     * {@inheritdoc}
991
     */
992 266
    protected function getDefaultArgsParser()
993
    {
994 266
        return $this->applicationConfig
995 266
            ? $this->applicationConfig->getArgsParser()
996 266
            : parent::getDefaultArgsParser();
997
    }
998
999
    /**
1000
     * {@inheritdoc}
1001
     */
1002 259
    protected function getDefaultLenientArgsParsing()
1003
    {
1004 259
        return $this->applicationConfig
1005 257
            ? $this->applicationConfig->isLenientArgsParsingEnabled()
1006 259
            : parent::getDefaultLenientArgsParsing();
1007
    }
1008
}
1009