CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Team
    • Issues (Github)
    • YouTube Channel
    • Get Involved
    • Bakery
    • Featured Resources
    • Newsletter
    • Certification
    • My CakePHP
    • CakeFest
    • Facebook
    • Twitter
    • Help & Support
    • Forum
    • Stack Overflow
    • IRC
    • Slack
    • Paid Support
CakePHP

C CakePHP 3.8 Red Velvet API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 3.8
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Namespaces

  • Cake
    • Auth
      • Storage
    • Cache
      • Engine
    • Collection
      • Iterator
    • Command
    • Console
      • Exception
    • Controller
      • Component
      • Exception
    • Core
      • Configure
        • Engine
      • Exception
      • Retry
    • Database
      • Driver
      • Exception
      • Expression
      • Schema
      • Statement
      • Type
    • Datasource
      • Exception
    • Error
      • Middleware
    • Event
      • Decorator
    • Filesystem
    • Form
    • Http
      • Client
        • Adapter
        • Auth
      • Cookie
      • Exception
      • Middleware
      • Session
    • I18n
      • Formatter
      • Middleware
      • Parser
    • Log
      • Engine
    • Mailer
      • Exception
      • Transport
    • Network
      • Exception
    • ORM
      • Association
      • Behavior
        • Translate
      • Exception
      • Locator
      • Rule
    • Routing
      • Exception
      • Filter
      • Middleware
      • Route
    • Shell
      • Helper
      • Task
    • TestSuite
      • Fixture
      • Stub
    • Utility
      • Exception
    • Validation
    • View
      • Exception
      • Form
      • Helper
      • Widget
  • None

Classes

  • Arguments
  • Command
  • CommandCollection
  • CommandFactory
  • CommandRunner
  • ConsoleErrorHandler
  • ConsoleInput
  • ConsoleInputArgument
  • ConsoleInputOption
  • ConsoleInputSubcommand
  • ConsoleIo
  • ConsoleOptionParser
  • ConsoleOutput
  • Helper
  • HelperRegistry
  • HelpFormatter
  • Shell
  • ShellDispatcher
  • TaskRegistry

Interfaces

  • CommandCollectionAwareInterface
  • CommandFactoryInterface
   1: <?php
   2: /**
   3:  * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
   4:  * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
   5:  *
   6:  * Licensed under The MIT License
   7:  * For full copyright and license information, please see the LICENSE.txt
   8:  * Redistributions of files must retain the above copyright notice.
   9:  *
  10:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11:  * @link          https://cakephp.org CakePHP(tm) Project
  12:  * @since         2.0.0
  13:  * @license       https://opensource.org/licenses/mit-license.php MIT License
  14:  */
  15: namespace Cake\Console;
  16: 
  17: use Cake\Console\Exception\ConsoleException;
  18: use Cake\Utility\Inflector;
  19: use LogicException;
  20: 
  21: /**
  22:  * Handles parsing the ARGV in the command line and provides support
  23:  * for GetOpt compatible option definition. Provides a builder pattern implementation
  24:  * for creating shell option parsers.
  25:  *
  26:  * ### Options
  27:  *
  28:  * Named arguments come in two forms, long and short. Long arguments are preceded
  29:  * by two - and give a more verbose option name. i.e. `--version`. Short arguments are
  30:  * preceded by one - and are only one character long. They usually match with a long option,
  31:  * and provide a more terse alternative.
  32:  *
  33:  * ### Using Options
  34:  *
  35:  * Options can be defined with both long and short forms. By using `$parser->addOption()`
  36:  * you can define new options. The name of the option is used as its long form, and you
  37:  * can supply an additional short form, with the `short` option. Short options should
  38:  * only be one letter long. Using more than one letter for a short option will raise an exception.
  39:  *
  40:  * Calling options can be done using syntax similar to most *nix command line tools. Long options
  41:  * cane either include an `=` or leave it out.
  42:  *
  43:  * `cake myshell command --connection default --name=something`
  44:  *
  45:  * Short options can be defined singly or in groups.
  46:  *
  47:  * `cake myshell command -cn`
  48:  *
  49:  * Short options can be combined into groups as seen above. Each letter in a group
  50:  * will be treated as a separate option. The previous example is equivalent to:
  51:  *
  52:  * `cake myshell command -c -n`
  53:  *
  54:  * Short options can also accept values:
  55:  *
  56:  * `cake myshell command -c default`
  57:  *
  58:  * ### Positional arguments
  59:  *
  60:  * If no positional arguments are defined, all of them will be parsed. If you define positional
  61:  * arguments any arguments greater than those defined will cause exceptions. Additionally you can
  62:  * declare arguments as optional, by setting the required param to false.
  63:  *
  64:  * ```
  65:  * $parser->addArgument('model', ['required' => false]);
  66:  * ```
  67:  *
  68:  * ### Providing Help text
  69:  *
  70:  * By providing help text for your positional arguments and named arguments, the ConsoleOptionParser
  71:  * can generate a help display for you. You can view the help for shells by using the `--help` or `-h` switch.
  72:  */
  73: class ConsoleOptionParser
  74: {
  75:     /**
  76:      * Description text - displays before options when help is generated
  77:      *
  78:      * @see \Cake\Console\ConsoleOptionParser::description()
  79:      * @var string
  80:      */
  81:     protected $_description;
  82: 
  83:     /**
  84:      * Epilog text - displays after options when help is generated
  85:      *
  86:      * @see \Cake\Console\ConsoleOptionParser::epilog()
  87:      * @var string
  88:      */
  89:     protected $_epilog;
  90: 
  91:     /**
  92:      * Option definitions.
  93:      *
  94:      * @see \Cake\Console\ConsoleOptionParser::addOption()
  95:      * @var \Cake\Console\ConsoleInputOption[]
  96:      */
  97:     protected $_options = [];
  98: 
  99:     /**
 100:      * Map of short -> long options, generated when using addOption()
 101:      *
 102:      * @var array
 103:      */
 104:     protected $_shortOptions = [];
 105: 
 106:     /**
 107:      * Positional argument definitions.
 108:      *
 109:      * @see \Cake\Console\ConsoleOptionParser::addArgument()
 110:      * @var \Cake\Console\ConsoleInputArgument[]
 111:      */
 112:     protected $_args = [];
 113: 
 114:     /**
 115:      * Subcommands for this Shell.
 116:      *
 117:      * @see \Cake\Console\ConsoleOptionParser::addSubcommand()
 118:      * @var \Cake\Console\ConsoleInputSubcommand[]
 119:      */
 120:     protected $_subcommands = [];
 121: 
 122:     /**
 123:      * Subcommand sorting option
 124:      *
 125:      * @var bool
 126:      */
 127:     protected $_subcommandSort = true;
 128: 
 129:     /**
 130:      * Command name.
 131:      *
 132:      * @var string
 133:      */
 134:     protected $_command = '';
 135: 
 136:     /**
 137:      * Array of args (argv).
 138:      *
 139:      * @var array
 140:      */
 141:     protected $_tokens = [];
 142: 
 143:     /**
 144:      * Root alias used in help output
 145:      *
 146:      * @see \Cake\Console\HelpFormatter::setAlias()
 147:      * @var string
 148:      */
 149:     protected $rootName = 'cake';
 150: 
 151:     /**
 152:      * Construct an OptionParser so you can define its behavior
 153:      *
 154:      * @param string|null $command The command name this parser is for. The command name is used for generating help.
 155:      * @param bool $defaultOptions Whether you want the verbose and quiet options set. Setting
 156:      *  this to false will prevent the addition of `--verbose` & `--quiet` options.
 157:      */
 158:     public function __construct($command = null, $defaultOptions = true)
 159:     {
 160:         $this->setCommand($command);
 161: 
 162:         $this->addOption('help', [
 163:             'short' => 'h',
 164:             'help' => 'Display this help.',
 165:             'boolean' => true
 166:         ]);
 167: 
 168:         if ($defaultOptions) {
 169:             $this->addOption('verbose', [
 170:                 'short' => 'v',
 171:                 'help' => 'Enable verbose output.',
 172:                 'boolean' => true
 173:             ])->addOption('quiet', [
 174:                 'short' => 'q',
 175:                 'help' => 'Enable quiet output.',
 176:                 'boolean' => true
 177:             ]);
 178:         }
 179:     }
 180: 
 181:     /**
 182:      * Static factory method for creating new OptionParsers so you can chain methods off of them.
 183:      *
 184:      * @param string|null $command The command name this parser is for. The command name is used for generating help.
 185:      * @param bool $defaultOptions Whether you want the verbose and quiet options set.
 186:      * @return static
 187:      */
 188:     public static function create($command, $defaultOptions = true)
 189:     {
 190:         return new static($command, $defaultOptions);
 191:     }
 192: 
 193:     /**
 194:      * Build a parser from an array. Uses an array like
 195:      *
 196:      * ```
 197:      * $spec = [
 198:      *      'description' => 'text',
 199:      *      'epilog' => 'text',
 200:      *      'arguments' => [
 201:      *          // list of arguments compatible with addArguments.
 202:      *      ],
 203:      *      'options' => [
 204:      *          // list of options compatible with addOptions
 205:      *      ],
 206:      *      'subcommands' => [
 207:      *          // list of subcommands to add.
 208:      *      ]
 209:      * ];
 210:      * ```
 211:      *
 212:      * @param array $spec The spec to build the OptionParser with.
 213:      * @param bool $defaultOptions Whether you want the verbose and quiet options set.
 214:      * @return static
 215:      */
 216:     public static function buildFromArray($spec, $defaultOptions = true)
 217:     {
 218:         $parser = new static($spec['command'], $defaultOptions);
 219:         if (!empty($spec['arguments'])) {
 220:             $parser->addArguments($spec['arguments']);
 221:         }
 222:         if (!empty($spec['options'])) {
 223:             $parser->addOptions($spec['options']);
 224:         }
 225:         if (!empty($spec['subcommands'])) {
 226:             $parser->addSubcommands($spec['subcommands']);
 227:         }
 228:         if (!empty($spec['description'])) {
 229:             $parser->setDescription($spec['description']);
 230:         }
 231:         if (!empty($spec['epilog'])) {
 232:             $parser->setEpilog($spec['epilog']);
 233:         }
 234: 
 235:         return $parser;
 236:     }
 237: 
 238:     /**
 239:      * Returns an array representation of this parser.
 240:      *
 241:      * @return array
 242:      */
 243:     public function toArray()
 244:     {
 245:         $result = [
 246:             'command' => $this->_command,
 247:             'arguments' => $this->_args,
 248:             'options' => $this->_options,
 249:             'subcommands' => $this->_subcommands,
 250:             'description' => $this->_description,
 251:             'epilog' => $this->_epilog
 252:         ];
 253: 
 254:         return $result;
 255:     }
 256: 
 257:     /**
 258:      * Get or set the command name for shell/task.
 259:      *
 260:      * @param array|\Cake\Console\ConsoleOptionParser $spec ConsoleOptionParser or spec to merge with.
 261:      * @return $this
 262:      */
 263:     public function merge($spec)
 264:     {
 265:         if ($spec instanceof ConsoleOptionParser) {
 266:             $spec = $spec->toArray();
 267:         }
 268:         if (!empty($spec['arguments'])) {
 269:             $this->addArguments($spec['arguments']);
 270:         }
 271:         if (!empty($spec['options'])) {
 272:             $this->addOptions($spec['options']);
 273:         }
 274:         if (!empty($spec['subcommands'])) {
 275:             $this->addSubcommands($spec['subcommands']);
 276:         }
 277:         if (!empty($spec['description'])) {
 278:             $this->setDescription($spec['description']);
 279:         }
 280:         if (!empty($spec['epilog'])) {
 281:             $this->setEpilog($spec['epilog']);
 282:         }
 283: 
 284:         return $this;
 285:     }
 286: 
 287:     /**
 288:      * Sets the command name for shell/task.
 289:      *
 290:      * @param string $text The text to set.
 291:      * @return $this
 292:      */
 293:     public function setCommand($text)
 294:     {
 295:         $this->_command = Inflector::underscore($text);
 296: 
 297:         return $this;
 298:     }
 299: 
 300:     /**
 301:      * Gets the command name for shell/task.
 302:      *
 303:      * @return string The value of the command.
 304:      */
 305:     public function getCommand()
 306:     {
 307:         return $this->_command;
 308:     }
 309: 
 310:     /**
 311:      * Gets or sets the command name for shell/task.
 312:      *
 313:      * @deprecated 3.4.0 Use setCommand()/getCommand() instead.
 314:      * @param string|null $text The text to set, or null if you want to read
 315:      * @return string|$this If reading, the value of the command. If setting $this will be returned.
 316:      */
 317:     public function command($text = null)
 318:     {
 319:         deprecationWarning(
 320:             'ConsoleOptionParser::command() is deprecated. ' .
 321:             'Use ConsoleOptionParser::setCommand()/getCommand() instead.'
 322:         );
 323:         if ($text !== null) {
 324:             return $this->setCommand($text);
 325:         }
 326: 
 327:         return $this->getCommand();
 328:     }
 329: 
 330:     /**
 331:      * Sets the description text for shell/task.
 332:      *
 333:      * @param string|array $text The text to set. If an array the
 334:      *   text will be imploded with "\n".
 335:      * @return $this
 336:      */
 337:     public function setDescription($text)
 338:     {
 339:         if (is_array($text)) {
 340:             $text = implode("\n", $text);
 341:         }
 342:         $this->_description = $text;
 343: 
 344:         return $this;
 345:     }
 346: 
 347:     /**
 348:      * Gets the description text for shell/task.
 349:      *
 350:      * @return string The value of the description
 351:      */
 352:     public function getDescription()
 353:     {
 354:         return $this->_description;
 355:     }
 356: 
 357:     /**
 358:      * Get or set the description text for shell/task.
 359:      *
 360:      * @deprecated 3.4.0 Use setDescription()/getDescription() instead.
 361:      * @param string|array|null $text The text to set, or null if you want to read. If an array the
 362:      *   text will be imploded with "\n".
 363:      * @return string|$this If reading, the value of the description. If setting $this will be returned.
 364:      */
 365:     public function description($text = null)
 366:     {
 367:         deprecationWarning(
 368:             'ConsoleOptionParser::description() is deprecated. ' .
 369:             'Use ConsoleOptionParser::setDescription()/getDescription() instead.'
 370:         );
 371:         if ($text !== null) {
 372:             return $this->setDescription($text);
 373:         }
 374: 
 375:         return $this->getDescription();
 376:     }
 377: 
 378:     /**
 379:      * Sets an epilog to the parser. The epilog is added to the end of
 380:      * the options and arguments listing when help is generated.
 381:      *
 382:      * @param string|array $text The text to set. If an array the text will
 383:      *   be imploded with "\n".
 384:      * @return $this
 385:      */
 386:     public function setEpilog($text)
 387:     {
 388:         if (is_array($text)) {
 389:             $text = implode("\n", $text);
 390:         }
 391:         $this->_epilog = $text;
 392: 
 393:         return $this;
 394:     }
 395: 
 396:     /**
 397:      * Gets the epilog.
 398:      *
 399:      * @return string The value of the epilog.
 400:      */
 401:     public function getEpilog()
 402:     {
 403:         return $this->_epilog;
 404:     }
 405: 
 406:     /**
 407:      * Gets or sets an epilog to the parser. The epilog is added to the end of
 408:      * the options and arguments listing when help is generated.
 409:      *
 410:      * @deprecated 3.4.0 Use setEpilog()/getEpilog() instead.
 411:      * @param string|array|null $text Text when setting or null when reading. If an array the text will
 412:      *   be imploded with "\n".
 413:      * @return string|$this If reading, the value of the epilog. If setting $this will be returned.
 414:      */
 415:     public function epilog($text = null)
 416:     {
 417:         deprecationWarning(
 418:             'ConsoleOptionParser::epliog() is deprecated. ' .
 419:             'Use ConsoleOptionParser::setEpilog()/getEpilog() instead.'
 420:         );
 421:         if ($text !== null) {
 422:             return $this->setEpilog($text);
 423:         }
 424: 
 425:         return $this->getEpilog();
 426:     }
 427: 
 428:     /**
 429:      * Enables sorting of subcommands
 430:      *
 431:      * @param bool $value Whether or not to sort subcommands
 432:      * @return $this
 433:      */
 434:     public function enableSubcommandSort($value = true)
 435:     {
 436:         $this->_subcommandSort = (bool)$value;
 437: 
 438:         return $this;
 439:     }
 440: 
 441:     /**
 442:      * Checks whether or not sorting is enabled for subcommands.
 443:      *
 444:      * @return bool
 445:      */
 446:     public function isSubcommandSortEnabled()
 447:     {
 448:         return $this->_subcommandSort;
 449:     }
 450: 
 451:     /**
 452:      * Add an option to the option parser. Options allow you to define optional or required
 453:      * parameters for your console application. Options are defined by the parameters they use.
 454:      *
 455:      * ### Options
 456:      *
 457:      * - `short` - The single letter variant for this option, leave undefined for none.
 458:      * - `help` - Help text for this option. Used when generating help for the option.
 459:      * - `default` - The default value for this option. Defaults are added into the parsed params when the
 460:      *    attached option is not provided or has no value. Using default and boolean together will not work.
 461:      *    are added into the parsed parameters when the option is undefined. Defaults to null.
 462:      * - `boolean` - The option uses no value, it's just a boolean switch. Defaults to false.
 463:      *    If an option is defined as boolean, it will always be added to the parsed params. If no present
 464:      *    it will be false, if present it will be true.
 465:      * - `multiple` - The option can be provided multiple times. The parsed option
 466:      *   will be an array of values when this option is enabled.
 467:      * - `choices` A list of valid choices for this option. If left empty all values are valid..
 468:      *   An exception will be raised when parse() encounters an invalid value.
 469:      *
 470:      * @param \Cake\Console\ConsoleInputOption|string $name The long name you want to the value to be parsed out as when options are parsed.
 471:      *   Will also accept an instance of ConsoleInputOption
 472:      * @param array $options An array of parameters that define the behavior of the option
 473:      * @return $this
 474:      */
 475:     public function addOption($name, array $options = [])
 476:     {
 477:         if ($name instanceof ConsoleInputOption) {
 478:             $option = $name;
 479:             $name = $option->name();
 480:         } else {
 481:             $defaults = [
 482:                 'name' => $name,
 483:                 'short' => null,
 484:                 'help' => '',
 485:                 'default' => null,
 486:                 'boolean' => false,
 487:                 'choices' => []
 488:             ];
 489:             $options += $defaults;
 490:             $option = new ConsoleInputOption($options);
 491:         }
 492:         $this->_options[$name] = $option;
 493:         asort($this->_options);
 494:         if ($option->short() !== null) {
 495:             $this->_shortOptions[$option->short()] = $name;
 496:             asort($this->_shortOptions);
 497:         }
 498: 
 499:         return $this;
 500:     }
 501: 
 502:     /**
 503:      * Remove an option from the option parser.
 504:      *
 505:      * @param string $name The option name to remove.
 506:      * @return $this
 507:      */
 508:     public function removeOption($name)
 509:     {
 510:         unset($this->_options[$name]);
 511: 
 512:         return $this;
 513:     }
 514: 
 515:     /**
 516:      * Add a positional argument to the option parser.
 517:      *
 518:      * ### Params
 519:      *
 520:      * - `help` The help text to display for this argument.
 521:      * - `required` Whether this parameter is required.
 522:      * - `index` The index for the arg, if left undefined the argument will be put
 523:      *   onto the end of the arguments. If you define the same index twice the first
 524:      *   option will be overwritten.
 525:      * - `choices` A list of valid choices for this argument. If left empty all values are valid..
 526:      *   An exception will be raised when parse() encounters an invalid value.
 527:      *
 528:      * @param \Cake\Console\ConsoleInputArgument|string $name The name of the argument.
 529:      *   Will also accept an instance of ConsoleInputArgument.
 530:      * @param array $params Parameters for the argument, see above.
 531:      * @return $this
 532:      */
 533:     public function addArgument($name, array $params = [])
 534:     {
 535:         if ($name instanceof ConsoleInputArgument) {
 536:             $arg = $name;
 537:             $index = count($this->_args);
 538:         } else {
 539:             $defaults = [
 540:                 'name' => $name,
 541:                 'help' => '',
 542:                 'index' => count($this->_args),
 543:                 'required' => false,
 544:                 'choices' => []
 545:             ];
 546:             $options = $params + $defaults;
 547:             $index = $options['index'];
 548:             unset($options['index']);
 549:             $arg = new ConsoleInputArgument($options);
 550:         }
 551:         foreach ($this->_args as $k => $a) {
 552:             if ($a->isEqualTo($arg)) {
 553:                 return $this;
 554:             }
 555:             if (!empty($options['required']) && !$a->isRequired()) {
 556:                 throw new LogicException('A required argument cannot follow an optional one');
 557:             }
 558:         }
 559:         $this->_args[$index] = $arg;
 560:         ksort($this->_args);
 561: 
 562:         return $this;
 563:     }
 564: 
 565:     /**
 566:      * Add multiple arguments at once. Take an array of argument definitions.
 567:      * The keys are used as the argument names, and the values as params for the argument.
 568:      *
 569:      * @param array $args Array of arguments to add.
 570:      * @see \Cake\Console\ConsoleOptionParser::addArgument()
 571:      * @return $this
 572:      */
 573:     public function addArguments(array $args)
 574:     {
 575:         foreach ($args as $name => $params) {
 576:             if ($params instanceof ConsoleInputArgument) {
 577:                 $name = $params;
 578:                 $params = [];
 579:             }
 580:             $this->addArgument($name, $params);
 581:         }
 582: 
 583:         return $this;
 584:     }
 585: 
 586:     /**
 587:      * Add multiple options at once. Takes an array of option definitions.
 588:      * The keys are used as option names, and the values as params for the option.
 589:      *
 590:      * @param array $options Array of options to add.
 591:      * @see \Cake\Console\ConsoleOptionParser::addOption()
 592:      * @return $this
 593:      */
 594:     public function addOptions(array $options)
 595:     {
 596:         foreach ($options as $name => $params) {
 597:             if ($params instanceof ConsoleInputOption) {
 598:                 $name = $params;
 599:                 $params = [];
 600:             }
 601:             $this->addOption($name, $params);
 602:         }
 603: 
 604:         return $this;
 605:     }
 606: 
 607:     /**
 608:      * Append a subcommand to the subcommand list.
 609:      * Subcommands are usually methods on your Shell, but can also be used to document Tasks.
 610:      *
 611:      * ### Options
 612:      *
 613:      * - `help` - Help text for the subcommand.
 614:      * - `parser` - A ConsoleOptionParser for the subcommand. This allows you to create method
 615:      *    specific option parsers. When help is generated for a subcommand, if a parser is present
 616:      *    it will be used.
 617:      *
 618:      * @param \Cake\Console\ConsoleInputSubcommand|string $name Name of the subcommand. Will also accept an instance of ConsoleInputSubcommand
 619:      * @param array $options Array of params, see above.
 620:      * @return $this
 621:      */
 622:     public function addSubcommand($name, array $options = [])
 623:     {
 624:         if ($name instanceof ConsoleInputSubcommand) {
 625:             $command = $name;
 626:             $name = $command->name();
 627:         } else {
 628:             $name = Inflector::underscore($name);
 629:             $defaults = [
 630:                 'name' => $name,
 631:                 'help' => '',
 632:                 'parser' => null
 633:             ];
 634:             $options += $defaults;
 635: 
 636:             $command = new ConsoleInputSubcommand($options);
 637:         }
 638:         $this->_subcommands[$name] = $command;
 639:         if ($this->_subcommandSort) {
 640:             asort($this->_subcommands);
 641:         }
 642: 
 643:         return $this;
 644:     }
 645: 
 646:     /**
 647:      * Remove a subcommand from the option parser.
 648:      *
 649:      * @param string $name The subcommand name to remove.
 650:      * @return $this
 651:      */
 652:     public function removeSubcommand($name)
 653:     {
 654:         unset($this->_subcommands[$name]);
 655: 
 656:         return $this;
 657:     }
 658: 
 659:     /**
 660:      * Add multiple subcommands at once.
 661:      *
 662:      * @param array $commands Array of subcommands.
 663:      * @return $this
 664:      */
 665:     public function addSubcommands(array $commands)
 666:     {
 667:         foreach ($commands as $name => $params) {
 668:             if ($params instanceof ConsoleInputSubcommand) {
 669:                 $name = $params;
 670:                 $params = [];
 671:             }
 672:             $this->addSubcommand($name, $params);
 673:         }
 674: 
 675:         return $this;
 676:     }
 677: 
 678:     /**
 679:      * Gets the arguments defined in the parser.
 680:      *
 681:      * @return \Cake\Console\ConsoleInputArgument[]
 682:      */
 683:     public function arguments()
 684:     {
 685:         return $this->_args;
 686:     }
 687: 
 688:     /**
 689:      * Get the list of argument names.
 690:      *
 691:      * @return string[]
 692:      */
 693:     public function argumentNames()
 694:     {
 695:         $out = [];
 696:         foreach ($this->_args as $arg) {
 697:             $out[] = $arg->name();
 698:         }
 699: 
 700:         return $out;
 701:     }
 702: 
 703:     /**
 704:      * Get the defined options in the parser.
 705:      *
 706:      * @return \Cake\Console\ConsoleInputOption[]
 707:      */
 708:     public function options()
 709:     {
 710:         return $this->_options;
 711:     }
 712: 
 713:     /**
 714:      * Get the array of defined subcommands
 715:      *
 716:      * @return \Cake\Console\ConsoleInputSubcommand[]
 717:      */
 718:     public function subcommands()
 719:     {
 720:         return $this->_subcommands;
 721:     }
 722: 
 723:     /**
 724:      * Parse the argv array into a set of params and args. If $command is not null
 725:      * and $command is equal to a subcommand that has a parser, that parser will be used
 726:      * to parse the $argv
 727:      *
 728:      * @param array $argv Array of args (argv) to parse.
 729:      * @return array [$params, $args]
 730:      * @throws \Cake\Console\Exception\ConsoleException When an invalid parameter is encountered.
 731:      */
 732:     public function parse($argv)
 733:     {
 734:         $command = isset($argv[0]) ? Inflector::underscore($argv[0]) : null;
 735:         if (isset($this->_subcommands[$command])) {
 736:             array_shift($argv);
 737:         }
 738:         if (isset($this->_subcommands[$command]) && $this->_subcommands[$command]->parser()) {
 739:             return $this->_subcommands[$command]->parser()->parse($argv);
 740:         }
 741:         $params = $args = [];
 742:         $this->_tokens = $argv;
 743:         while (($token = array_shift($this->_tokens)) !== null) {
 744:             if (isset($this->_subcommands[$token])) {
 745:                 continue;
 746:             }
 747:             if (substr($token, 0, 2) === '--') {
 748:                 $params = $this->_parseLongOption($token, $params);
 749:             } elseif (substr($token, 0, 1) === '-') {
 750:                 $params = $this->_parseShortOption($token, $params);
 751:             } else {
 752:                 $args = $this->_parseArg($token, $args);
 753:             }
 754:         }
 755:         foreach ($this->_args as $i => $arg) {
 756:             if ($arg->isRequired() && !isset($args[$i]) && empty($params['help'])) {
 757:                 throw new ConsoleException(
 758:                     sprintf('Missing required arguments. %s is required.', $arg->name())
 759:                 );
 760:             }
 761:         }
 762:         foreach ($this->_options as $option) {
 763:             $name = $option->name();
 764:             $isBoolean = $option->isBoolean();
 765:             $default = $option->defaultValue();
 766: 
 767:             if ($default !== null && !isset($params[$name]) && !$isBoolean) {
 768:                 $params[$name] = $default;
 769:             }
 770:             if ($isBoolean && !isset($params[$name])) {
 771:                 $params[$name] = false;
 772:             }
 773:         }
 774: 
 775:         return [$params, $args];
 776:     }
 777: 
 778:     /**
 779:      * Gets formatted help for this parser object.
 780:      *
 781:      * Generates help text based on the description, options, arguments, subcommands and epilog
 782:      * in the parser.
 783:      *
 784:      * @param string|null $subcommand If present and a valid subcommand that has a linked parser.
 785:      *    That subcommands help will be shown instead.
 786:      * @param string $format Define the output format, can be text or xml
 787:      * @param int $width The width to format user content to. Defaults to 72
 788:      * @return string Generated help.
 789:      */
 790:     public function help($subcommand = null, $format = 'text', $width = 72)
 791:     {
 792:         if ($subcommand === null) {
 793:             $formatter = new HelpFormatter($this);
 794:             $formatter->setAlias($this->rootName);
 795: 
 796:             if ($format === 'text') {
 797:                 return $formatter->text($width);
 798:             }
 799:             if ($format === 'xml') {
 800:                 return (string)$formatter->xml();
 801:             }
 802:         }
 803: 
 804:         if (isset($this->_subcommands[$subcommand])) {
 805:             $command = $this->_subcommands[$subcommand];
 806:             $subparser = $command->parser();
 807: 
 808:             // Generate a parser as the subcommand didn't define one.
 809:             if (!($subparser instanceof self)) {
 810:                 // $subparser = clone $this;
 811:                 $subparser = new self($subcommand);
 812:                 $subparser
 813:                     ->setDescription($command->getRawHelp())
 814:                     ->addOptions($this->options())
 815:                     ->addArguments($this->arguments());
 816:             }
 817:             if (strlen($subparser->getDescription()) === 0) {
 818:                 $subparser->setDescription($command->getRawHelp());
 819:             }
 820:             $subparser->setCommand($this->getCommand() . ' ' . $subcommand);
 821:             $subparser->setRootName($this->rootName);
 822: 
 823:             return $subparser->help(null, $format, $width);
 824:         }
 825: 
 826:         return $this->getCommandError($subcommand);
 827:     }
 828: 
 829:     /**
 830:      * Set the alias used in the HelpFormatter
 831:      *
 832:      * @param string $alias The alias
 833:      * @return void
 834:      * @deprecated 3.5.0 Use setRootName() instead.
 835:      */
 836:     public function setHelpAlias($alias)
 837:     {
 838:         deprecationWarning(
 839:             'ConsoleOptionParser::setHelpAlias() is deprecated. ' .
 840:             'Use ConsoleOptionParser::setRootName() instead.'
 841:         );
 842:         $this->rootName = $alias;
 843:     }
 844: 
 845:     /**
 846:      * Set the root name used in the HelpFormatter
 847:      *
 848:      * @param string $name The root command name
 849:      * @return $this
 850:      */
 851:     public function setRootName($name)
 852:     {
 853:         $this->rootName = (string)$name;
 854: 
 855:         return $this;
 856:     }
 857: 
 858:     /**
 859:      * Get the message output in the console stating that the command can not be found and tries to guess what the user
 860:      * wanted to say. Output a list of available subcommands as well.
 861:      *
 862:      * @param string $command Unknown command name trying to be dispatched.
 863:      * @return string The message to be displayed in the console.
 864:      */
 865:     protected function getCommandError($command)
 866:     {
 867:         $rootCommand = $this->getCommand();
 868:         $subcommands = array_keys((array)$this->subcommands());
 869:         $bestGuess = $this->findClosestItem($command, $subcommands);
 870: 
 871:         $out = [
 872:             sprintf(
 873:                 'Unable to find the `%s %s` subcommand. See `bin/%s %s --help`.',
 874:                 $rootCommand,
 875:                 $command,
 876:                 $this->rootName,
 877:                 $rootCommand
 878:             ),
 879:             ''
 880:         ];
 881: 
 882:         if ($bestGuess !== null) {
 883:             $out[] = sprintf('Did you mean : `%s %s` ?', $rootCommand, $bestGuess);
 884:             $out[] = '';
 885:         }
 886:         $out[] = sprintf('Available subcommands for the `%s` command are : ', $rootCommand);
 887:         $out[] = '';
 888:         foreach ($subcommands as $subcommand) {
 889:             $out[] = ' - ' . $subcommand;
 890:         }
 891: 
 892:         return implode("\n", $out);
 893:     }
 894: 
 895:     /**
 896:      * Get the message output in the console stating that the option can not be found and tries to guess what the user
 897:      * wanted to say. Output a list of available options as well.
 898:      *
 899:      * @param string $option Unknown option name trying to be used.
 900:      * @return string The message to be displayed in the console.
 901:      */
 902:     protected function getOptionError($option)
 903:     {
 904:         $availableOptions = array_keys($this->_options);
 905:         $bestGuess = $this->findClosestItem($option, $availableOptions);
 906:         $out = [
 907:             sprintf('Unknown option `%s`.', $option),
 908:             ''
 909:         ];
 910: 
 911:         if ($bestGuess !== null) {
 912:             $out[] = sprintf('Did you mean `%s` ?', $bestGuess);
 913:             $out[] = '';
 914:         }
 915: 
 916:         $out[] = 'Available options are :';
 917:         $out[] = '';
 918:         foreach ($availableOptions as $availableOption) {
 919:             $out[] = ' - ' . $availableOption;
 920:         }
 921: 
 922:         return implode("\n", $out);
 923:     }
 924: 
 925:     /**
 926:      * Get the message output in the console stating that the short option can not be found. Output a list of available
 927:      * short options and what option they refer to as well.
 928:      *
 929:      * @param string $option Unknown short option name trying to be used.
 930:      * @return string The message to be displayed in the console.
 931:      */
 932:     protected function getShortOptionError($option)
 933:     {
 934:         $out = [sprintf('Unknown short option `%s`', $option)];
 935:         $out[] = '';
 936:         $out[] = 'Available short options are :';
 937:         $out[] = '';
 938: 
 939:         foreach ($this->_shortOptions as $short => $long) {
 940:             $out[] = sprintf(' - `%s` (short for `--%s`)', $short, $long);
 941:         }
 942: 
 943:         return implode("\n", $out);
 944:     }
 945: 
 946:     /**
 947:      * Tries to guess the item name the user originally wanted using the some regex pattern and the levenshtein
 948:      * algorithm.
 949:      *
 950:      * @param string $needle Unknown item (either a subcommand name or an option for instance) trying to be used.
 951:      * @param string[] $haystack List of items available for the type $needle belongs to.
 952:      * @return string|null The closest name to the item submitted by the user.
 953:      */
 954:     protected function findClosestItem($needle, $haystack)
 955:     {
 956:         $bestGuess = null;
 957:         foreach ($haystack as $item) {
 958:             if (preg_match('/^' . $needle . '/', $item)) {
 959:                 return $item;
 960:             }
 961:         }
 962: 
 963:         foreach ($haystack as $item) {
 964:             if (preg_match('/' . $needle . '/', $item)) {
 965:                 return $item;
 966:             }
 967: 
 968:             $score = levenshtein($needle, $item);
 969: 
 970:             if (!isset($bestScore) || $score < $bestScore) {
 971:                 $bestScore = $score;
 972:                 $bestGuess = $item;
 973:             }
 974:         }
 975: 
 976:         return $bestGuess;
 977:     }
 978: 
 979:     /**
 980:      * Parse the value for a long option out of $this->_tokens. Will handle
 981:      * options with an `=` in them.
 982:      *
 983:      * @param string $option The option to parse.
 984:      * @param array $params The params to append the parsed value into
 985:      * @return array Params with $option added in.
 986:      */
 987:     protected function _parseLongOption($option, $params)
 988:     {
 989:         $name = substr($option, 2);
 990:         if (strpos($name, '=') !== false) {
 991:             list($name, $value) = explode('=', $name, 2);
 992:             array_unshift($this->_tokens, $value);
 993:         }
 994: 
 995:         return $this->_parseOption($name, $params);
 996:     }
 997: 
 998:     /**
 999:      * Parse the value for a short option out of $this->_tokens
1000:      * If the $option is a combination of multiple shortcuts like -otf
1001:      * they will be shifted onto the token stack and parsed individually.
1002:      *
1003:      * @param string $option The option to parse.
1004:      * @param array $params The params to append the parsed value into
1005:      * @return array Params with $option added in.
1006:      * @throws \Cake\Console\Exception\ConsoleException When unknown short options are encountered.
1007:      */
1008:     protected function _parseShortOption($option, $params)
1009:     {
1010:         $key = substr($option, 1);
1011:         if (strlen($key) > 1) {
1012:             $flags = str_split($key);
1013:             $key = $flags[0];
1014:             for ($i = 1, $len = count($flags); $i < $len; $i++) {
1015:                 array_unshift($this->_tokens, '-' . $flags[$i]);
1016:             }
1017:         }
1018:         if (!isset($this->_shortOptions[$key])) {
1019:             throw new ConsoleException($this->getShortOptionError($key));
1020:         }
1021:         $name = $this->_shortOptions[$key];
1022: 
1023:         return $this->_parseOption($name, $params);
1024:     }
1025: 
1026:     /**
1027:      * Parse an option by its name index.
1028:      *
1029:      * @param string $name The name to parse.
1030:      * @param array $params The params to append the parsed value into
1031:      * @return array Params with $option added in.
1032:      * @throws \Cake\Console\Exception\ConsoleException
1033:      */
1034:     protected function _parseOption($name, $params)
1035:     {
1036:         if (!isset($this->_options[$name])) {
1037:             throw new ConsoleException($this->getOptionError($name));
1038:         }
1039:         $option = $this->_options[$name];
1040:         $isBoolean = $option->isBoolean();
1041:         $nextValue = $this->_nextToken();
1042:         $emptyNextValue = (empty($nextValue) && $nextValue !== '0');
1043:         if (!$isBoolean && !$emptyNextValue && !$this->_optionExists($nextValue)) {
1044:             array_shift($this->_tokens);
1045:             $value = $nextValue;
1046:         } elseif ($isBoolean) {
1047:             $value = true;
1048:         } else {
1049:             $value = $option->defaultValue();
1050:         }
1051:         if ($option->validChoice($value)) {
1052:             if ($option->acceptsMultiple()) {
1053:                 $params[$name][] = $value;
1054:             } else {
1055:                 $params[$name] = $value;
1056:             }
1057: 
1058:             return $params;
1059:         }
1060: 
1061:         return [];
1062:     }
1063: 
1064:     /**
1065:      * Check to see if $name has an option (short/long) defined for it.
1066:      *
1067:      * @param string $name The name of the option.
1068:      * @return bool
1069:      */
1070:     protected function _optionExists($name)
1071:     {
1072:         if (substr($name, 0, 2) === '--') {
1073:             return isset($this->_options[substr($name, 2)]);
1074:         }
1075:         if ($name[0] === '-' && $name[1] !== '-') {
1076:             return isset($this->_shortOptions[$name[1]]);
1077:         }
1078: 
1079:         return false;
1080:     }
1081: 
1082:     /**
1083:      * Parse an argument, and ensure that the argument doesn't exceed the number of arguments
1084:      * and that the argument is a valid choice.
1085:      *
1086:      * @param string $argument The argument to append
1087:      * @param array $args The array of parsed args to append to.
1088:      * @return string[] Args
1089:      * @throws \Cake\Console\Exception\ConsoleException
1090:      */
1091:     protected function _parseArg($argument, $args)
1092:     {
1093:         if (empty($this->_args)) {
1094:             $args[] = $argument;
1095: 
1096:             return $args;
1097:         }
1098:         $next = count($args);
1099:         if (!isset($this->_args[$next])) {
1100:             throw new ConsoleException('Too many arguments.');
1101:         }
1102: 
1103:         if ($this->_args[$next]->validChoice($argument)) {
1104:             $args[] = $argument;
1105: 
1106:             return $args;
1107:         }
1108:     }
1109: 
1110:     /**
1111:      * Find the next token in the argv set.
1112:      *
1113:      * @return string next token or ''
1114:      */
1115:     protected function _nextToken()
1116:     {
1117:         return isset($this->_tokens[0]) ? $this->_tokens[0] : '';
1118:     }
1119: }
1120: 
Follow @CakePHP
#IRC
OpenHub
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Logos & Trademarks
  • Community
  • Team
  • Issues (Github)
  • YouTube Channel
  • Get Involved
  • Bakery
  • Featured Resources
  • Newsletter
  • Certification
  • My CakePHP
  • CakeFest
  • Facebook
  • Twitter
  • Help & Support
  • Forum
  • Stack Overflow
  • IRC
  • Slack
  • Paid Support

Generated using CakePHP API Docs