[Solar-svn] Revision 2579
pmjones at solarphp.com
pmjones at solarphp.com
Tue Jul 10 14:05:59 CDT 2007
moved Solar_Console_Getopt to Solar_Getopt
Deleted: trunk/Solar/Console/Getopt.php
===================================================================
--- trunk/Solar/Console/Getopt.php 2007-07-10 19:05:25 UTC (rev 2578)
+++ trunk/Solar/Console/Getopt.php 2007-07-10 19:05:59 UTC (rev 2579)
@@ -1,673 +0,0 @@
-<?php
-/**
- *
- * Retrieves and validates command-line options and parameter values.
- *
- * @category Solar
- *
- * @package Solar_Console_Getopt
- *
- * @author Clay Loveless <clay at killersoft.com>
- *
- * @author Paul M. Jones <pmjones at solarphp.com>
- *
- * @license http://opensource.org/licenses/bsd-license.php BSD
- *
- * @version $Id$
- *
- */
-
-/**
- *
- * Retrieves and validates command-line options and parameter values.
- *
- * @category Solar
- *
- * @package Solar_Console_Getopt
- *
- * @todo Add load() method similar to Solar_Form::load(), for loading from
- * external XML, PHP array, etc. files.
- *
- * @todo Config to stop processing options after first numeric? This would
- * force options to come before the numeric params, making the invocation more
- * strict (and cleaner-looking).
- *
- */
-class Solar_Console_Getopt extends Solar_Base {
-
- /**
- *
- * User-defined configuration values.
- *
- * Keys are:
- *
- * `request`
- * : (dependency) A Solar_Request dependency injection. Default is
- * 'request'.
- *
- * `datafilter_class`
- * : (string) The data-filter class to use when validating and sanitizing
- * parameter values. Default is 'Solar_DataFilter'.
- *
- * `strict`
- * : (bool) If true, will not process any more options after the first
- * non-option-related parameter. This forces all numeric parameters to
- * come after the last option. If false, numeric parameters unrelated to
- * any particular option can be mixed in with the options.
- *
- * @var array
- *
- */
- protected $_Solar_Console_Getopt = array(
- 'request' => 'request',
- 'datafilter_class' => 'Solar_DataFilter',
- 'strict' => true,
- );
-
- /**
- *
- * The array of acceptable options.
- *
- * The `$options` array contains all options accepted by the
- * application, including their types, default values, descriptions,
- * requirements, and validation callbacks.
- *
- * In general, you should not try to set $options yourself;
- * instead, use [[Solar_Console_Getopt::setOption()]] and/or
- * [[Solar_Console_Getopt::setOptions()]].
- *
- */
- public $options = array();
-
- /**
- *
- * Default option settings.
- *
- * Keys are ...
- *
- * `long`
- * : (string) The long-form of the option name (e.g., "--foo-bar" would
- * be "foo-bar").
- *
- * `short`
- * : (string) The short-form of the option, if any (e.g., "-f" would be
- * "f").
- *
- * `descr`
- * : (string) A description of the option (used in "help" output).
- *
- * `param`
- * : (string) When the option is present, does it take a parameter? If so,
- * the param can be "required" every time, or be "optional". If empty, no
- * parameter for the option will be recognized (the option's value will be
- * boolean true when the option is present). Default is 'optional'.
- *
- * `value`
- * : (mixed) The default value for the option parameter, if any. This way,
- * options not specified in the arguments can have a default value.
- *
- * `require`
- * : (bool) At validation time, the option must have a non-blank value
- * of some sort.
- *
- * `filters`
- * : (array) An array of filters to apply to the parameter value. This can
- * be a single filter (`array('validateInt')`), or a series of filters
- * (`array('validateInt', array('validateRange', -10, +10)`).
- *
- * @var array
- *
- */
- protected $_default = array(
- 'long' => null,
- 'short' => null,
- 'param' => 'optional',
- 'value' => null,
- 'descr' => null,
- 'require' => false,
- 'filters' => array(),
- );
-
- /**
- *
- * The arguments passed in from the command line.
- *
- * @var array
- *
- * @see populate()
- *
- */
- protected $_argv;
-
- /**
- *
- * List of names for invalid option values, and error messages.
- *
- * @var array
- *
- */
- protected $_invalid = array();
-
- /**
- *
- * List of filters to apply to option values.
- *
- * @var array
- *
- */
- protected $_filters = array();
-
- /**
- *
- * Option values parsed from the arguments, as well as remaining (numeric)
- * arguments.
- *
- * @var array
- *
- */
- protected $_values;
-
- /**
- *
- * Constructor.
- *
- * @param array $config User-provided configuration values.
- *
- */
- public function __construct($config = null)
- {
- // "real" contruction
- parent::__construct($config);
-
- // inject the request dependency
- $this->_request = Solar::dependency(
- 'Solar_Request',
- $this->_config['request']
- );
-
- // set up the data-filter class
- $this->_datafilter = Solar::factory($this->_config['datafilter_class']);
- }
-
- // -----------------------------------------------------------------
- //
- // Option-management methods
- //
- // -----------------------------------------------------------------
-
- /**
- *
- * Sets one option for recognition.
- *
- * @param string $name The option name to set or add; overrides
- * $info['short'] if 1 character long, otherwise overrides $info['long'].
- *
- * @param array $info Option information using the same keys
- * as [[Solar_Console_Getopt::$_default]].
- *
- * @return void
- *
- */
- public function setOption($name, $info)
- {
- // prepare the option info
- $info = array_merge($this->_default, $info);
-
- // override the short- or long-form of the option
- if (strlen($name) == 1) {
- $info['short'] = $name;
- } else {
- $info['long'] = $name;
- }
-
- // normalize the "param" setting
- $param = strtolower($info['param']);
- if ($param == 'r' || substr($param, 0, 3) == 'req') {
- $info['param'] = 'required';
- } elseif ($param == 'o' || substr($param, 0, 3) == 'opt') {
- $info['param'] = 'optional';
- } else {
- $info['param'] = null;
- }
-
- // forcibly cast each of the keys in the options array
- $this->options[$name] = array(
- 'long' => $info['long'],
- 'short' => substr($info['short'], 0, 1),
- 'param' => $info['param'],
- 'value' => $info['value'],
- 'descr' => $info['descr'],
- 'require' => (bool) $info['require']
- );
-
- // retain and fix any filters for the option value
- if ($info['filters']) {
-
- // make sure filters are an array
- settype($info['filters'], 'array');
-
- // make sure that strings are converted to arrays so that
- // validate() works properly.
- foreach ($info['filters'] as $key => $list) {
- if (is_string($list)) {
- $info['filters'][$key] = array($list);
- }
- }
-
- // save the filters
- $this->_filters[$name] = $info['filters'];
- }
- }
-
- /**
- *
- * Sets multiple acceptable options. Appends if they do not exist.
- *
- * @param array $list Argument information as array(name => info), where
- * each info value is an array like Solar_Console_Getopt::$_default.
- *
- * @return void
- *
- */
- public function setOptions($list)
- {
- if (! empty($list)) {
- foreach ($list as $name => $info) {
- $this->setOption($name, $info);
- }
- }
- }
-
- /**
- *
- * Populates the options with values from $argv.
- *
- * For a given option on the command line, these values will result:
- *
- * `--foo-bar`
- * : `'foo-bar' => true`
- *
- * `--foo-bar=baz`
- * : `'foo-bar' => 'baz'`
- *
- * `--foo-bar="baz dib zim"`
- * : `'foo-bar' => 'baz dib zim'`
- *
- * `-s`
- * : `'s' => true`
- *
- * `-s dib`
- * : `'s' => 'dib'`
- *
- * `-s "dib zim gir"`
- * : `'s' => 'dib zim gir'`
- *
- * Short-option clusters are parsed as well, so that `-fbz` will result
- * in `array('f' => true, 'b' => true, 'z' => true)`. Note that you cannot
- * pass parameters to an option in a cluster.
- *
- * If an option is not defined, it will not be populated.
- *
- * Options values are stored under the option key name, not
- * the short- or long-format version of the option. For example, an option
- * named 'foo-bar' with a short-form of 'f' will be stored under 'foo-bar'.
- * This helps deconflict between long- and short-form aliases.
- *
- * @param array $argv The argument values passed on the command line. If
- * empty, will use $_SERVER['argv'] after shifting off its first element.
- *
- * @return void
- *
- */
- public function populate($argv = null)
- {
- // get the command-line arguments
- if ($argv === null) {
- $argv = $this->_request->server['argv'];
- array_shift($argv);
- } else {
- $argv = (array) $argv;
- }
-
- // hold onto the argv source
- $this->_argv = $argv;
-
- // reset values to defaults
- $this->_values = array();
- foreach ($this->options as $name => $info) {
- $this->_values[$name] = $info['value'];
- }
-
- // flag to say when we've reached the end of options
- $done = false;
-
- // shift each element from the top of the $argv source
- while (true) {
-
- // get the next argument
- $arg = array_shift($this->_argv);
- if ($arg === null) {
- // no more args, we're done
- break;
- }
-
- // after a plain double-dash, all values are numeric (not options)
- if ($arg == '--') {
- $done = true;
- continue;
- }
-
- // if we're reached the end of options, just add to the numeric
- // values.
- if ($done) {
- $this->_values[] = $arg;
- continue;
- }
-
- // long, short, or numeric?
- if (substr($arg, 0, 2) == '--') {
- // long
- $this->_values = array_merge(
- $this->_values,
- (array) $this->_parseLong($arg)
- );
- } elseif (substr($arg, 0, 1) == '-') {
- // short
- $this->_values = array_merge(
- $this->_values,
- (array) $this->_parseShort($arg)
- );
- } else {
- // numeric
- $this->_values[] = $arg;
- // in strict mode, this indicates that no more options
- // should be procesed.
- if ($this->_config['strict']) {
- $done = true;
- }
- }
- }
- }
-
- /**
- *
- * Applies validation and sanitizing filters to the values.
- *
- * @return bool True if all values are valid, false if not.
- *
- */
- public function validate()
- {
- // reset previous invalidations
- $this->_invalid = array();
-
- // note that we use &$val here, which allows sanitizing methods to
- // work directly with the value.
- foreach ($this->_values as $key => &$val) {
-
- // does the option name exist? (might not for numeric options)
- if (empty($this->options[$key])) {
- continue;
- }
-
- // setup for 'require' on parameter values
- $require = $this->options[$key]['require'];
- $this->_datafilter->setRequire($require);
-
- // is a value required for the option?
- if ($require && ! $this->_datafilter->validateNotBlank($val)) {
- // value was blank, that means it is invalid.
- // other validations will also be processed, meaning that their
- // messages will override this one.
- $this->_invalid[$key] = $this->locale('VALIDATE_NOT_BLANK');
- }
-
- // are there other filters for this option?
- if (empty($this->_filters[$key])) {
- // no filters, skip it
- continue;
- }
-
- // apply other filters
- foreach ($this->_filters[$key] as $params) {
-
- // take the method name off the top of the params ...
- $method = array_shift($params);
-
- // ... and put the value in its place.
- array_unshift($params, $val);
-
- // call the filtering method
- $result = call_user_func_array(
- array($this->_datafilter, $method),
- $params
- );
-
- // did the filter sanitize, or did it validate?
- $type = strtolower(substr($method, 0, 8));
-
- // what to do with the result?
- if ($type == 'sanitize') {
- // retain the sanitized value
- $val = $result;
- } elseif ($type == 'validate' && ! $result) {
- // a validation method failed; use the method name as
- // the locale translation key, converting from camelCase
- // to camel_Case, then to CAMEL_CASE.
- $tmp = preg_replace('/([a-z])([A-Z])/', '$1_$2', $method);
- $tmp = strtoupper($tmp);
- $this->_invalid[$key] = $this->_datafilter->locale($tmp);
- // no more validations on this key
- break;
- }
- }
- }
-
- // if there were any invalids, keep them and return false
- if ($this->_invalid) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- *
- * Returns a list of invalid options and their error messages (if any).
- *
- * @return array
- *
- */
- public function getInvalid()
- {
- return $this->_invalid;
- }
-
- /**
- *
- * Returns the populated option values.
- *
- * @return array
- *
- */
- public function values()
- {
- return $this->_values;
- }
-
- /**
- *
- * Parse a long-form option.
- *
- * @param string $arg The $argv element, e.g. "--foo" or "--bar=baz".
- *
- * @return array An associative array where the key is the option name and
- * the value is the option value.
- *
- * @todo Support param without equals, e.g. "--bar baz".
- *
- */
- protected function _parseLong($arg)
- {
- // strip the leading "--"
- $arg = substr($arg, 2);
-
- // find the first = sign
- $pos = strpos($arg, '=');
-
- // get the key for name lookup
- if ($pos === false) {
- $key = $arg;
- $value = null;
- } else {
- $key = substr($arg, 0, $pos);
- $value = substr($arg, $pos+1);
- }
-
- // is this a recognized option?
- $name = $this->_getOptionName('long', $key);
- if (! $name) {
- return;
- }
-
- // parse the value for the option param
- return $this->_parseParam($name, $value);
- }
-
- /**
- *
- * Parse the parameter value for a named option.
- *
- * @param string $name The option name.
- *
- * @param string $value The parameter.
- *
- * @return array An associative array where the option name is the key,
- * and the parsed parameter is the value.
- *
- */
- protected function _parseParam($name, $value)
- {
- // get info about the option
- $info = $this->options[$name];
-
- // is the value blank?
- if (trim($value) == '') {
- // value is blank. was it required for the option?
- if ($info['param'] == 'required') {
- // required but blank.
- return array($name => null);
- } else {
- // optional but blank, treat as a flag.
- return array($name => true);
- }
- }
-
- // param was present and not blank.
- return array($name => $value);
- }
-
- /**
- *
- * Parse a short-form option (or cluster of options).
- *
- * @param string $arg The $argv element, e.g. "-f" or "-fbz".
- *
- * @param bool $cluster This option is part of a cluster.
- *
- * @return array An associative array where the key is the option name and
- * the value is the option value.
- *
- */
- protected function _parseShort($arg, $cluster = false)
- {
- // strip the leading "-"
- $arg = substr($arg, 1);
-
- // re-process as a cluster?
- if (strlen($arg) > 1) {
- $data = array();
- foreach (str_split($arg) as $key) {
- $data = array_merge(
- $data,
- (array) $this->_parseShort("-$key", true)
- );
- }
- return $data;
- }
-
- // is the option defined?
- $name = $this->_getOptionName('short', $arg);
- if (! $name) {
- // not defined
- return;
- } else {
- // keep the option info
- $info = $this->options[$name];
- }
-
- // are we processing as part of a cluster?
- if ($cluster) {
- // is a param required for the option?
- if ($info['param'] == 'required') {
- // can't get params when in a cluster.
- return array($name => null);
- } else {
- // param was optional or not needed, treat as a flag.
- return array($name => true);
- }
- }
-
- // not processing as part of a cluster.
- // does the option need a param?
- if (! $info['param']) {
- // defined as not-needing a param, treat as a flag.
- return array($name => true);
- }
-
- // the option was defined as needing a param (required or optional).
- // get the next element from $argv to see if it's a param.
- $value = array_shift($this->_argv);
-
- // make sure the element not an option itself.
- if (substr($value, 0, 1) == '-') {
-
- // the next element is an option, not a param.
- // this means no param is present.
- // put the element back into $argv.
- array_unshift($this->_argv, $value);
-
- // was the missing param required?
- if ($info['param'] == 'required') {
- // required but not present
- return array($name => null);
- } else {
- // optional but not present, treat as a flag
- return array($name => true);
- }
- }
-
- // parse the parameter for a required or optional value
- return $this->_parseParam($name, $value);
- }
-
- /**
- *
- * Gets an option name from its short or long format.
- *
- * @param string $type Look in the 'long' or 'short' key for option names.
- *
- * @param string $value The long or short format of the option name.
- *
- * @return string
- *
- */
- protected function _getOptionName($type, $value)
- {
- foreach ($this->options as $name => $info) {
- if ($info[$type] == $value) {
- return $name;
- }
- }
- }
-}
\ No newline at end of file
Copied: trunk/Solar/Getopt.php (from rev 2578, trunk/Solar/Console/Getopt.php)
===================================================================
--- trunk/Solar/Getopt.php (rev 0)
+++ trunk/Solar/Getopt.php 2007-07-10 19:05:59 UTC (rev 2579)
@@ -0,0 +1,673 @@
+<?php
+/**
+ *
+ * Retrieves and validates command-line options and parameter values.
+ *
+ * @category Solar
+ *
+ * @package Solar_Console_Getopt
+ *
+ * @author Clay Loveless <clay at killersoft.com>
+ *
+ * @author Paul M. Jones <pmjones at solarphp.com>
+ *
+ * @license http://opensource.org/licenses/bsd-license.php BSD
+ *
+ * @version $Id$
+ *
+ */
+
+/**
+ *
+ * Retrieves and validates command-line options and parameter values.
+ *
+ * @category Solar
+ *
+ * @package Solar_Console_Getopt
+ *
+ * @todo Add load() method similar to Solar_Form::load(), for loading from
+ * external XML, PHP array, etc. files.
+ *
+ * @todo Config to stop processing options after first numeric? This would
+ * force options to come before the numeric params, making the invocation more
+ * strict (and cleaner-looking).
+ *
+ */
+class Solar_Console_Getopt extends Solar_Base {
+
+ /**
+ *
+ * User-defined configuration values.
+ *
+ * Keys are:
+ *
+ * `request`
+ * : (dependency) A Solar_Request dependency injection. Default is
+ * 'request'.
+ *
+ * `datafilter_class`
+ * : (string) The data-filter class to use when validating and sanitizing
+ * parameter values. Default is 'Solar_DataFilter'.
+ *
+ * `strict`
+ * : (bool) If true, will not process any more options after the first
+ * non-option-related parameter. This forces all numeric parameters to
+ * come after the last option. If false, numeric parameters unrelated to
+ * any particular option can be mixed in with the options.
+ *
+ * @var array
+ *
+ */
+ protected $_Solar_Console_Getopt = array(
+ 'request' => 'request',
+ 'datafilter_class' => 'Solar_DataFilter',
+ 'strict' => true,
+ );
+
+ /**
+ *
+ * The array of acceptable options.
+ *
+ * The `$options` array contains all options accepted by the
+ * application, including their types, default values, descriptions,
+ * requirements, and validation callbacks.
+ *
+ * In general, you should not try to set $options yourself;
+ * instead, use [[Solar_Console_Getopt::setOption()]] and/or
+ * [[Solar_Console_Getopt::setOptions()]].
+ *
+ */
+ public $options = array();
+
+ /**
+ *
+ * Default option settings.
+ *
+ * Keys are ...
+ *
+ * `long`
+ * : (string) The long-form of the option name (e.g., "--foo-bar" would
+ * be "foo-bar").
+ *
+ * `short`
+ * : (string) The short-form of the option, if any (e.g., "-f" would be
+ * "f").
+ *
+ * `descr`
+ * : (string) A description of the option (used in "help" output).
+ *
+ * `param`
+ * : (string) When the option is present, does it take a parameter? If so,
+ * the param can be "required" every time, or be "optional". If empty, no
+ * parameter for the option will be recognized (the option's value will be
+ * boolean true when the option is present). Default is 'optional'.
+ *
+ * `value`
+ * : (mixed) The default value for the option parameter, if any. This way,
+ * options not specified in the arguments can have a default value.
+ *
+ * `require`
+ * : (bool) At validation time, the option must have a non-blank value
+ * of some sort.
+ *
+ * `filters`
+ * : (array) An array of filters to apply to the parameter value. This can
+ * be a single filter (`array('validateInt')`), or a series of filters
+ * (`array('validateInt', array('validateRange', -10, +10)`).
+ *
+ * @var array
+ *
+ */
+ protected $_default = array(
+ 'long' => null,
+ 'short' => null,
+ 'param' => 'optional',
+ 'value' => null,
+ 'descr' => null,
+ 'require' => false,
+ 'filters' => array(),
+ );
+
+ /**
+ *
+ * The arguments passed in from the command line.
+ *
+ * @var array
+ *
+ * @see populate()
+ *
+ */
+ protected $_argv;
+
+ /**
+ *
+ * List of names for invalid option values, and error messages.
+ *
+ * @var array
+ *
+ */
+ protected $_invalid = array();
+
+ /**
+ *
+ * List of filters to apply to option values.
+ *
+ * @var array
+ *
+ */
+ protected $_filters = array();
+
+ /**
+ *
+ * Option values parsed from the arguments, as well as remaining (numeric)
+ * arguments.
+ *
+ * @var array
+ *
+ */
+ protected $_values;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param array $config User-provided configuration values.
+ *
+ */
+ public function __construct($config = null)
+ {
+ // "real" contruction
+ parent::__construct($config);
+
+ // inject the request dependency
+ $this->_request = Solar::dependency(
+ 'Solar_Request',
+ $this->_config['request']
+ );
+
+ // set up the data-filter class
+ $this->_datafilter = Solar::factory($this->_config['datafilter_class']);
+ }
+
+ // -----------------------------------------------------------------
+ //
+ // Option-management methods
+ //
+ // -----------------------------------------------------------------
+
+ /**
+ *
+ * Sets one option for recognition.
+ *
+ * @param string $name The option name to set or add; overrides
+ * $info['short'] if 1 character long, otherwise overrides $info['long'].
+ *
+ * @param array $info Option information using the same keys
+ * as [[Solar_Console_Getopt::$_default]].
+ *
+ * @return void
+ *
+ */
+ public function setOption($name, $info)
+ {
+ // prepare the option info
+ $info = array_merge($this->_default, $info);
+
+ // override the short- or long-form of the option
+ if (strlen($name) == 1) {
+ $info['short'] = $name;
+ } else {
+ $info['long'] = $name;
+ }
+
+ // normalize the "param" setting
+ $param = strtolower($info['param']);
+ if ($param == 'r' || substr($param, 0, 3) == 'req') {
+ $info['param'] = 'required';
+ } elseif ($param == 'o' || substr($param, 0, 3) == 'opt') {
+ $info['param'] = 'optional';
+ } else {
+ $info['param'] = null;
+ }
+
+ // forcibly cast each of the keys in the options array
+ $this->options[$name] = array(
+ 'long' => $info['long'],
+ 'short' => substr($info['short'], 0, 1),
+ 'param' => $info['param'],
+ 'value' => $info['value'],
+ 'descr' => $info['descr'],
+ 'require' => (bool) $info['require']
+ );
+
+ // retain and fix any filters for the option value
+ if ($info['filters']) {
+
+ // make sure filters are an array
+ settype($info['filters'], 'array');
+
+ // make sure that strings are converted to arrays so that
+ // validate() works properly.
+ foreach ($info['filters'] as $key => $list) {
+ if (is_string($list)) {
+ $info['filters'][$key] = array($list);
+ }
+ }
+
+ // save the filters
+ $this->_filters[$name] = $info['filters'];
+ }
+ }
+
+ /**
+ *
+ * Sets multiple acceptable options. Appends if they do not exist.
+ *
+ * @param array $list Argument information as array(name => info), where
+ * each info value is an array like Solar_Console_Getopt::$_default.
+ *
+ * @return void
+ *
+ */
+ public function setOptions($list)
+ {
+ if (! empty($list)) {
+ foreach ($list as $name => $info) {
+ $this->setOption($name, $info);
+ }
+ }
+ }
+
+ /**
+ *
+ * Populates the options with values from $argv.
+ *
+ * For a given option on the command line, these values will result:
+ *
+ * `--foo-bar`
+ * : `'foo-bar' => true`
+ *
+ * `--foo-bar=baz`
+ * : `'foo-bar' => 'baz'`
+ *
+ * `--foo-bar="baz dib zim"`
+ * : `'foo-bar' => 'baz dib zim'`
+ *
+ * `-s`
+ * : `'s' => true`
+ *
+ * `-s dib`
+ * : `'s' => 'dib'`
+ *
+ * `-s "dib zim gir"`
+ * : `'s' => 'dib zim gir'`
+ *
+ * Short-option clusters are parsed as well, so that `-fbz` will result
+ * in `array('f' => true, 'b' => true, 'z' => true)`. Note that you cannot
+ * pass parameters to an option in a cluster.
+ *
+ * If an option is not defined, it will not be populated.
+ *
+ * Options values are stored under the option key name, not
+ * the short- or long-format version of the option. For example, an option
+ * named 'foo-bar' with a short-form of 'f' will be stored under 'foo-bar'.
+ * This helps deconflict between long- and short-form aliases.
+ *
+ * @param array $argv The argument values passed on the command line. If
+ * empty, will use $_SERVER['argv'] after shifting off its first element.
+ *
+ * @return void
+ *
+ */
+ public function populate($argv = null)
+ {
+ // get the command-line arguments
+ if ($argv === null) {
+ $argv = $this->_request->server['argv'];
+ array_shift($argv);
+ } else {
+ $argv = (array) $argv;
+ }
+
+ // hold onto the argv source
+ $this->_argv = $argv;
+
+ // reset values to defaults
+ $this->_values = array();
+ foreach ($this->options as $name => $info) {
+ $this->_values[$name] = $info['value'];
+ }
+
+ // flag to say when we've reached the end of options
+ $done = false;
+
+ // shift each element from the top of the $argv source
+ while (true) {
+
+ // get the next argument
+ $arg = array_shift($this->_argv);
+ if ($arg === null) {
+ // no more args, we're done
+ break;
+ }
+
+ // after a plain double-dash, all values are numeric (not options)
+ if ($arg == '--') {
+ $done = true;
+ continue;
+ }
+
+ // if we're reached the end of options, just add to the numeric
+ // values.
+ if ($done) {
+ $this->_values[] = $arg;
+ continue;
+ }
+
+ // long, short, or numeric?
+ if (substr($arg, 0, 2) == '--') {
+ // long
+ $this->_values = array_merge(
+ $this->_values,
+ (array) $this->_parseLong($arg)
+ );
+ } elseif (substr($arg, 0, 1) == '-') {
+ // short
+ $this->_values = array_merge(
+ $this->_values,
+ (array) $this->_parseShort($arg)
+ );
+ } else {
+ // numeric
+ $this->_values[] = $arg;
+ // in strict mode, this indicates that no more options
+ // should be procesed.
+ if ($this->_config['strict']) {
+ $done = true;
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * Applies validation and sanitizing filters to the values.
+ *
+ * @return bool True if all values are valid, false if not.
+ *
+ */
+ public function validate()
+ {
+ // reset previous invalidations
+ $this->_invalid = array();
+
+ // note that we use &$val here, which allows sanitizing methods to
+ // work directly with the value.
+ foreach ($this->_values as $key => &$val) {
+
+ // does the option name exist? (might not for numeric options)
+ if (empty($this->options[$key])) {
+ continue;
+ }
+
+ // setup for 'require' on parameter values
+ $require = $this->options[$key]['require'];
+ $this->_datafilter->setRequire($require);
+
+ // is a value required for the option?
+ if ($require && ! $this->_datafilter->validateNotBlank($val)) {
+ // value was blank, that means it is invalid.
+ // other validations will also be processed, meaning that their
+ // messages will override this one.
+ $this->_invalid[$key] = $this->locale('VALIDATE_NOT_BLANK');
+ }
+
+ // are there other filters for this option?
+ if (empty($this->_filters[$key])) {
+ // no filters, skip it
+ continue;
+ }
+
+ // apply other filters
+ foreach ($this->_filters[$key] as $params) {
+
+ // take the method name off the top of the params ...
+ $method = array_shift($params);
+
+ // ... and put the value in its place.
+ array_unshift($params, $val);
+
+ // call the filtering method
+ $result = call_user_func_array(
+ array($this->_datafilter, $method),
+ $params
+ );
+
+ // did the filter sanitize, or did it validate?
+ $type = strtolower(substr($method, 0, 8));
+
+ // what to do with the result?
+ if ($type == 'sanitize') {
+ // retain the sanitized value
+ $val = $result;
+ } elseif ($type == 'validate' && ! $result) {
+ // a validation method failed; use the method name as
+ // the locale translation key, converting from camelCase
+ // to camel_Case, then to CAMEL_CASE.
+ $tmp = preg_replace('/([a-z])([A-Z])/', '$1_$2', $method);
+ $tmp = strtoupper($tmp);
+ $this->_invalid[$key] = $this->_datafilter->locale($tmp);
+ // no more validations on this key
+ break;
+ }
+ }
+ }
+
+ // if there were any invalids, keep them and return false
+ if ($this->_invalid) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ *
+ * Returns a list of invalid options and their error messages (if any).
+ *
+ * @return array
+ *
+ */
+ public function getInvalid()
+ {
+ return $this->_invalid;
+ }
+
+ /**
+ *
+ * Returns the populated option values.
+ *
+ * @return array
+ *
+ */
+ public function values()
+ {
+ return $this->_values;
+ }
+
+ /**
+ *
+ * Parse a long-form option.
+ *
+ * @param string $arg The $argv element, e.g. "--foo" or "--bar=baz".
+ *
+ * @return array An associative array where the key is the option name and
+ * the value is the option value.
+ *
+ * @todo Support param without equals, e.g. "--bar baz".
+ *
+ */
+ protected function _parseLong($arg)
+ {
+ // strip the leading "--"
+ $arg = substr($arg, 2);
+
+ // find the first = sign
+ $pos = strpos($arg, '=');
+
+ // get the key for name lookup
+ if ($pos === false) {
+ $key = $arg;
+ $value = null;
+ } else {
+ $key = substr($arg, 0, $pos);
+ $value = substr($arg, $pos+1);
+ }
+
+ // is this a recognized option?
+ $name = $this->_getOptionName('long', $key);
+ if (! $name) {
+ return;
+ }
+
+ // parse the value for the option param
+ return $this->_parseParam($name, $value);
+ }
+
+ /**
+ *
+ * Parse the parameter value for a named option.
+ *
+ * @param string $name The option name.
+ *
+ * @param string $value The parameter.
+ *
+ * @return array An associative array where the option name is the key,
+ * and the parsed parameter is the value.
+ *
+ */
+ protected function _parseParam($name, $value)
+ {
+ // get info about the option
+ $info = $this->options[$name];
+
+ // is the value blank?
+ if (trim($value) == '') {
+ // value is blank. was it required for the option?
+ if ($info['param'] == 'required') {
+ // required but blank.
+ return array($name => null);
+ } else {
+ // optional but blank, treat as a flag.
+ return array($name => true);
+ }
+ }
+
+ // param was present and not blank.
+ return array($name => $value);
+ }
+
+ /**
+ *
+ * Parse a short-form option (or cluster of options).
+ *
+ * @param string $arg The $argv element, e.g. "-f" or "-fbz".
+ *
+ * @param bool $cluster This option is part of a cluster.
+ *
+ * @return array An associative array where the key is the option name and
+ * the value is the option value.
+ *
+ */
+ protected function _parseShort($arg, $cluster = false)
+ {
+ // strip the leading "-"
+ $arg = substr($arg, 1);
+
+ // re-process as a cluster?
+ if (strlen($arg) > 1) {
+ $data = array();
+ foreach (str_split($arg) as $key) {
+ $data = array_merge(
+ $data,
+ (array) $this->_parseShort("-$key", true)
+ );
+ }
+ return $data;
+ }
+
+ // is the option defined?
+ $name = $this->_getOptionName('short', $arg);
+ if (! $name) {
+ // not defined
+ return;
+ } else {
+ // keep the option info
+ $info = $this->options[$name];
+ }
+
+ // are we processing as part of a cluster?
+ if ($cluster) {
+ // is a param required for the option?
+ if ($info['param'] == 'required') {
+ // can't get params when in a cluster.
+ return array($name => null);
+ } else {
+ // param was optional or not needed, treat as a flag.
+ return array($name => true);
+ }
+ }
+
+ // not processing as part of a cluster.
+ // does the option need a param?
+ if (! $info['param']) {
+ // defined as not-needing a param, treat as a flag.
+ return array($name => true);
+ }
+
+ // the option was defined as needing a param (required or optional).
+ // get the next element from $argv to see if it's a param.
+ $value = array_shift($this->_argv);
+
+ // make sure the element not an option itself.
+ if (substr($value, 0, 1) == '-') {
+
+ // the next element is an option, not a param.
+ // this means no param is present.
+ // put the element back into $argv.
+ array_unshift($this->_argv, $value);
+
+ // was the missing param required?
+ if ($info['param'] == 'required') {
+ // required but not present
+ return array($name => null);
+ } else {
+ // optional but not present, treat as a flag
+ return array($name => true);
+ }
+ }
+
+ // parse the parameter for a required or optional value
+ return $this->_parseParam($name, $value);
+ }
+
+ /**
+ *
+ * Gets an option name from its short or long format.
+ *
+ * @param string $type Look in the 'long' or 'short' key for option names.
+ *
+ * @param string $value The long or short format of the option name.
+ *
+ * @return string
+ *
+ */
+ protected function _getOptionName($type, $value)
+ {
+ foreach ($this->options as $name => $info) {
+ if ($info[$type] == $value) {
+ return $name;
+ }
+ }
+ }
+}
\ No newline at end of file
More information about the Solar-svn
mailing list