vendor/symfony/src/Symfony/Component/Console/Input/ArgvInput.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the Symfony package.
       
     5  *
       
     6  * (c) Fabien Potencier <fabien@symfony.com>
       
     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 Symfony\Component\Console\Input;
       
    13 
       
    14 /**
       
    15  * ArgvInput represents an input coming from the CLI arguments.
       
    16  *
       
    17  * Usage:
       
    18  *
       
    19  *     $input = new ArgvInput();
       
    20  *
       
    21  * By default, the `$_SERVER['argv']` array is used for the input values.
       
    22  *
       
    23  * This can be overridden by explicitly passing the input values in the constructor:
       
    24  *
       
    25  *     $input = new ArgvInput($_SERVER['argv']);
       
    26  *
       
    27  * If you pass it yourself, don't forget that the first element of the array
       
    28  * is the name of the running program.
       
    29  *
       
    30  * When passing an argument to the constructor, be sure that it respects
       
    31  * the same rules as the argv one. It's almost always better to use the
       
    32  * `StringInput` when you want to provide your own input.
       
    33  *
       
    34  * @author Fabien Potencier <fabien@symfony.com>
       
    35  *
       
    36  * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
       
    37  * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
       
    38  *
       
    39  * @api
       
    40  */
       
    41 class ArgvInput extends Input
       
    42 {
       
    43     private $tokens;
       
    44     private $parsed;
       
    45 
       
    46     /**
       
    47      * Constructor.
       
    48      *
       
    49      * @param array           $argv An array of parameters from the CLI (in the argv format)
       
    50      * @param InputDefinition $definition A InputDefinition instance
       
    51      *
       
    52      * @api
       
    53      */
       
    54     public function __construct(array $argv = null, InputDefinition $definition = null)
       
    55     {
       
    56         if (null === $argv) {
       
    57             $argv = $_SERVER['argv'];
       
    58         }
       
    59 
       
    60         // strip the program name
       
    61         array_shift($argv);
       
    62 
       
    63         $this->tokens = $argv;
       
    64 
       
    65         parent::__construct($definition);
       
    66     }
       
    67 
       
    68     protected function setTokens(array $tokens)
       
    69     {
       
    70         $this->tokens = $tokens;
       
    71     }
       
    72 
       
    73     /**
       
    74      * Processes command line arguments.
       
    75      */
       
    76     protected function parse()
       
    77     {
       
    78         $this->parsed = $this->tokens;
       
    79         while (null !== $token = array_shift($this->parsed)) {
       
    80             if ('--' === substr($token, 0, 2)) {
       
    81                 $this->parseLongOption($token);
       
    82             } elseif ('-' === $token[0]) {
       
    83                 $this->parseShortOption($token);
       
    84             } else {
       
    85                 $this->parseArgument($token);
       
    86             }
       
    87         }
       
    88     }
       
    89 
       
    90     /**
       
    91      * Parses a short option.
       
    92      *
       
    93      * @param string $token The current token.
       
    94      */
       
    95     private function parseShortOption($token)
       
    96     {
       
    97         $name = substr($token, 1);
       
    98 
       
    99         if (strlen($name) > 1) {
       
   100             if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
       
   101                 // an option with a value (with no space)
       
   102                 $this->addShortOption($name[0], substr($name, 1));
       
   103             } else {
       
   104                 $this->parseShortOptionSet($name);
       
   105             }
       
   106         } else {
       
   107             $this->addShortOption($name, null);
       
   108         }
       
   109     }
       
   110 
       
   111     /**
       
   112      * Parses a short option set.
       
   113      *
       
   114      * @param string $name The current token
       
   115      *
       
   116      * @throws \RuntimeException When option given doesn't exist
       
   117      */
       
   118     private function parseShortOptionSet($name)
       
   119     {
       
   120         $len = strlen($name);
       
   121         for ($i = 0; $i < $len; $i++) {
       
   122             if (!$this->definition->hasShortcut($name[$i])) {
       
   123                 throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
       
   124             }
       
   125 
       
   126             $option = $this->definition->getOptionForShortcut($name[$i]);
       
   127             if ($option->acceptValue()) {
       
   128                 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
       
   129 
       
   130                 break;
       
   131             } else {
       
   132                 $this->addLongOption($option->getName(), true);
       
   133             }
       
   134         }
       
   135     }
       
   136 
       
   137     /**
       
   138      * Parses a long option.
       
   139      *
       
   140      * @param string $token The current token
       
   141      */
       
   142     private function parseLongOption($token)
       
   143     {
       
   144         $name = substr($token, 2);
       
   145 
       
   146         if (false !== $pos = strpos($name, '=')) {
       
   147             $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
       
   148         } else {
       
   149             $this->addLongOption($name, null);
       
   150         }
       
   151     }
       
   152 
       
   153     /**
       
   154      * Parses an argument.
       
   155      *
       
   156      * @param string $token The current token
       
   157      *
       
   158      * @throws \RuntimeException When too many arguments are given
       
   159      */
       
   160     private function parseArgument($token)
       
   161     {
       
   162         $c = count($this->arguments);
       
   163 
       
   164         // if input is expecting another argument, add it
       
   165         if ($this->definition->hasArgument($c)) {
       
   166             $arg = $this->definition->getArgument($c);
       
   167             $this->arguments[$arg->getName()] = $arg->isArray()? array($token) : $token;
       
   168 
       
   169         // if last argument isArray(), append token to last argument
       
   170         } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
       
   171             $arg = $this->definition->getArgument($c - 1);
       
   172             $this->arguments[$arg->getName()][] = $token;
       
   173 
       
   174         // unexpected argument
       
   175         } else {
       
   176             throw new \RuntimeException('Too many arguments.');
       
   177         }
       
   178     }
       
   179 
       
   180     /**
       
   181      * Adds a short option value.
       
   182      *
       
   183      * @param string $shortcut The short option key
       
   184      * @param mixed  $value    The value for the option
       
   185      *
       
   186      * @throws \RuntimeException When option given doesn't exist
       
   187      */
       
   188     private function addShortOption($shortcut, $value)
       
   189     {
       
   190         if (!$this->definition->hasShortcut($shortcut)) {
       
   191             throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
       
   192         }
       
   193 
       
   194         $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
       
   195     }
       
   196 
       
   197     /**
       
   198      * Adds a long option value.
       
   199      *
       
   200      * @param string $name  The long option key
       
   201      * @param mixed  $value The value for the option
       
   202      *
       
   203      * @throws \RuntimeException When option given doesn't exist
       
   204      */
       
   205     private function addLongOption($name, $value)
       
   206     {
       
   207         if (!$this->definition->hasOption($name)) {
       
   208             throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
       
   209         }
       
   210 
       
   211         $option = $this->definition->getOption($name);
       
   212 
       
   213         if (null === $value && $option->acceptValue()) {
       
   214             // if option accepts an optional or mandatory argument
       
   215             // let's see if there is one provided
       
   216             $next = array_shift($this->parsed);
       
   217             if ('-' !== $next[0]) {
       
   218                 $value = $next;
       
   219             } else {
       
   220                 array_unshift($this->parsed, $next);
       
   221             }
       
   222         }
       
   223 
       
   224         if (null === $value) {
       
   225             if ($option->isValueRequired()) {
       
   226                 throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
       
   227             }
       
   228 
       
   229             $value = $option->isValueOptional() ? $option->getDefault() : true;
       
   230         }
       
   231 
       
   232         if ($option->isArray()) {
       
   233             $this->options[$name][] = $value;
       
   234         } else {
       
   235             $this->options[$name] = $value;
       
   236         }
       
   237     }
       
   238 
       
   239     /**
       
   240      * Returns the first argument from the raw parameters (not parsed).
       
   241      *
       
   242      * @return string The value of the first argument or null otherwise
       
   243      */
       
   244     public function getFirstArgument()
       
   245     {
       
   246         foreach ($this->tokens as $token) {
       
   247             if ($token && '-' === $token[0]) {
       
   248                 continue;
       
   249             }
       
   250 
       
   251             return $token;
       
   252         }
       
   253     }
       
   254 
       
   255     /**
       
   256      * Returns true if the raw parameters (not parsed) contains a value.
       
   257      *
       
   258      * This method is to be used to introspect the input parameters
       
   259      * before it has been validated. It must be used carefully.
       
   260      *
       
   261      * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
       
   262      *
       
   263      * @return Boolean true if the value is contained in the raw parameters
       
   264      */
       
   265     public function hasParameterOption($values)
       
   266     {
       
   267         $values = (array) $values;
       
   268 
       
   269         foreach ($this->tokens as $v) {
       
   270             if (in_array($v, $values)) {
       
   271                 return true;
       
   272             }
       
   273         }
       
   274 
       
   275         return false;
       
   276     }
       
   277 
       
   278     /**
       
   279      * Returns the value of a raw option (not parsed).
       
   280      *
       
   281      * This method is to be used to introspect the input parameters
       
   282      * before it has been validated. It must be used carefully.
       
   283      *
       
   284      * @param string|array $values The value(s) to look for in the raw parameters (can be an array)
       
   285      * @param mixed $default The default value to return if no result is found
       
   286      * @return mixed The option value
       
   287      */
       
   288     public function getParameterOption($values, $default = false)
       
   289     {
       
   290         $values = (array) $values;
       
   291 
       
   292         $tokens = $this->tokens;
       
   293         while ($token = array_shift($tokens)) {
       
   294             foreach ($values as $value) {
       
   295                 if (0 === strpos($token, $value)) {
       
   296                     if (false !== $pos = strpos($token, '=')) {
       
   297                         return substr($token, $pos + 1);
       
   298                     }
       
   299 
       
   300                     return array_shift($tokens);
       
   301                 }
       
   302             }
       
   303         }
       
   304 
       
   305         return $default;
       
   306     }
       
   307 }