web/lib/Zend/Tool/Framework/Client/Console/ArgumentParser.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Tool
       
    17  * @subpackage Framework
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: ArgumentParser.php 22877 2010-08-21 19:53:14Z ramon $
       
    21  */
       
    22 
       
    23 /**
       
    24  * @see Zend_Console_GetOpt
       
    25  */
       
    26 require_once 'Zend/Console/Getopt.php';
       
    27 
       
    28 /**
       
    29  * @see Zend_Tool_Framework_Registry_EnabledInterface
       
    30  */
       
    31 require_once 'Zend/Tool/Framework/Registry/EnabledInterface.php';
       
    32 
       
    33 /**
       
    34  * @category   Zend
       
    35  * @package    Zend_Tool
       
    36  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    37  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    38  */
       
    39 class Zend_Tool_Framework_Client_Console_ArgumentParser implements Zend_Tool_Framework_Registry_EnabledInterface
       
    40 {
       
    41 
       
    42     /**
       
    43      * @var Zend_Tool_Framework_Registry_Interface
       
    44      */
       
    45     protected $_registry = null;
       
    46 
       
    47     /**
       
    48      * Holds the manifest repository taken from the registry.
       
    49      *
       
    50      * @var Zend_Tool_Framework_Manifest_Repository
       
    51      */
       
    52       protected $_manifestRepository = null;
       
    53 
       
    54     /**
       
    55      * @var Zend_Tool_Framework_Client_Request
       
    56      */
       
    57     protected $_request = null;
       
    58 
       
    59     /**
       
    60      * @var Zend_Tool_Framework_Client_Response
       
    61      */
       
    62     protected $_response = null;
       
    63 
       
    64     /**#@+
       
    65      * @var array
       
    66      */
       
    67     protected $_argumentsOriginal = null;
       
    68     protected $_argumentsWorking  = null;
       
    69     /**#@-*/
       
    70 
       
    71     /**
       
    72      * @var bool
       
    73      */
       
    74     protected $_help = false;
       
    75     protected $_helpKnownAction = false;
       
    76     protected $_helpKnownProvider = false;
       
    77     protected $_helpKnownSpecialty = false;
       
    78 
       
    79 
       
    80     /**
       
    81      * setArguments
       
    82      *
       
    83      * @param array $arguments
       
    84      * @return Zend_Tool_Framework_Client_Console_ArgumentParser
       
    85      */
       
    86     public function setArguments(Array $arguments)
       
    87     {
       
    88         $this->_argumentsOriginal = $this->_argumentsWorking = $arguments;
       
    89         return $this;
       
    90     }
       
    91 
       
    92     /**
       
    93      * setRegistry()
       
    94      *
       
    95      * @param Zend_Tool_Framework_Registry_Interface $registry
       
    96      * @return Zend_Tool_Framework_Client_Console_ArgumentParser
       
    97      */
       
    98     public function setRegistry(Zend_Tool_Framework_Registry_Interface $registry)
       
    99     {
       
   100         // get the client registry
       
   101         $this->_registry = $registry;
       
   102 
       
   103         // set manifest repository, request, response for easy access
       
   104         $this->_manifestRepository = $this->_registry->getManifestRepository();
       
   105         $this->_request  = $this->_registry->getRequest();
       
   106         $this->_response = $this->_registry->getResponse();
       
   107         return $this;
       
   108     }
       
   109 
       
   110     /**
       
   111      * Parse() - This method does the work of parsing the arguments into the enpooint request,
       
   112      * this will also (during help operations) fill the response in with information as needed
       
   113      *
       
   114      * @return null
       
   115      */
       
   116     public function parse()
       
   117     {
       
   118 
       
   119         if ($this->_request == null || $this->_response == null) {
       
   120             require_once 'Zend/Tool/Framework/Client/Exception.php';
       
   121             throw new Zend_Tool_Framework_Client_Exception('The client registry must have both a request and response registered.');
       
   122         }
       
   123 
       
   124         // setup the help options
       
   125         $helpResponseOptions = array();
       
   126 
       
   127         // check to see if the first cli arg is the script name
       
   128         if ($this->_argumentsWorking[0] == $_SERVER['SCRIPT_NAME' ]) {
       
   129             array_shift($this->_argumentsWorking);
       
   130         }
       
   131 
       
   132         // process global options
       
   133         try {
       
   134             $this->_parseGlobalPart();
       
   135         } catch (Zend_Tool_Framework_Client_Exception $exception) {
       
   136             $this->_createHelpResponse(array('error' => $exception->getMessage()));
       
   137             return;
       
   138         }
       
   139 
       
   140         // ensure there are arguments left
       
   141         if (count($this->_argumentsWorking) == 0) {
       
   142             $this->_request->setDispatchable(false); // at this point request is not dispatchable
       
   143 
       
   144             // check to see if this was a help request
       
   145             if ($this->_help) {
       
   146                 $this->_createHelpResponse();
       
   147             } else {
       
   148                 $this->_createHelpResponse(array('error' => 'An action and provider is required.'));
       
   149             }
       
   150             return;
       
   151         }
       
   152 
       
   153         // process the action part of the command line
       
   154         try {
       
   155             $this->_parseActionPart();
       
   156         } catch (Zend_Tool_Framework_Client_Exception $exception) {
       
   157             $this->_request->setDispatchable(false);
       
   158             $this->_createHelpResponse(array('error' => $exception->getMessage()));
       
   159             return;
       
   160         }
       
   161 
       
   162         if ($this->_helpKnownAction) {
       
   163             $helpResponseOptions = array_merge(
       
   164                 $helpResponseOptions,
       
   165                 array('actionName' => $this->_request->getActionName())
       
   166                 );
       
   167         }
       
   168 
       
   169         /* @TODO Action Parameter Requirements */
       
   170 
       
   171         // make sure there are more "words" on the command line
       
   172         if (count($this->_argumentsWorking) == 0) {
       
   173             $this->_request->setDispatchable(false); // at this point request is not dispatchable
       
   174 
       
   175             // check to see if this is a help request
       
   176             if ($this->_help) {
       
   177                 $this->_createHelpResponse($helpResponseOptions);
       
   178             } else {
       
   179                 $this->_createHelpResponse(array_merge($helpResponseOptions, array('error' => 'A provider is required.')));
       
   180             }
       
   181             return;
       
   182         }
       
   183 
       
   184 
       
   185         // process the provider part of the command line
       
   186         try {
       
   187             $this->_parseProviderPart();
       
   188         } catch (Zend_Tool_Framework_Client_Exception $exception) {
       
   189             $this->_request->setDispatchable(false);
       
   190             $this->_createHelpResponse(array('error' => $exception->getMessage()));
       
   191             return;
       
   192         }
       
   193 
       
   194         if ($this->_helpKnownProvider) {
       
   195             $helpResponseOptions = array_merge(
       
   196                 $helpResponseOptions,
       
   197                 array('providerName' => $this->_request->getProviderName())
       
   198                 );
       
   199         }
       
   200 
       
   201         if ($this->_helpKnownSpecialty) {
       
   202             $helpResponseOptions = array_merge(
       
   203                 $helpResponseOptions,
       
   204                 array('specialtyName' => $this->_request->getSpecialtyName())
       
   205                 );
       
   206         }
       
   207 
       
   208         // if there are arguments on the command line, lets process them as provider options
       
   209         if (count($this->_argumentsWorking) != 0) {
       
   210             $this->_parseProviderOptionsPart();
       
   211         }
       
   212 
       
   213         // if there is still arguments lingering around, we can assume something is wrong
       
   214         if (count($this->_argumentsWorking) != 0) {
       
   215             $this->_request->setDispatchable(false); // at this point request is not dispatchable
       
   216             if ($this->_help) {
       
   217                 $this->_createHelpResponse($helpResponseOptions);
       
   218             } else {
       
   219                 $this->_createHelpResponse(array_merge(
       
   220                     $helpResponseOptions,
       
   221                     array('error' => 'Unknown arguments left on the command line: ' . implode(' ', $this->_argumentsWorking))
       
   222                     ));
       
   223             }
       
   224             return;
       
   225         }
       
   226 
       
   227         // everything was processed and this is a request for help information
       
   228         if ($this->_help) {
       
   229             $this->_request->setDispatchable(false); // at this point request is not dispatchable
       
   230             $this->_createHelpResponse($helpResponseOptions);
       
   231         }
       
   232 
       
   233         return;
       
   234     }
       
   235 
       
   236     /**
       
   237      * Internal routine for parsing global options from the command line
       
   238      *
       
   239      * @return null
       
   240      */
       
   241     protected function _parseGlobalPart()
       
   242     {
       
   243         $getoptOptions = array();
       
   244         $getoptOptions['help|h']    = 'HELP';
       
   245         $getoptOptions['verbose|v'] = 'VERBOSE';
       
   246         $getoptOptions['pretend|p'] = 'PRETEND';
       
   247         $getoptOptions['debug|d']   = 'DEBUG';
       
   248         $getoptParser = new Zend_Console_Getopt($getoptOptions, $this->_argumentsWorking, array('parseAll' => false));
       
   249 
       
   250         // @todo catch any exceptions here
       
   251         $getoptParser->parse();
       
   252 
       
   253         foreach ($getoptParser->getOptions() as $option) {
       
   254             if ($option == 'pretend') {
       
   255                 $this->_request->setPretend(true);
       
   256             } elseif ($option == 'debug') {
       
   257                 $this->_request->setDebug(true);
       
   258             } elseif ($option == 'verbose') {
       
   259                 $this->_request->setVerbose(true);
       
   260             } else {
       
   261                 $property = '_'.$option;
       
   262                 $this->{$property} = true;
       
   263             }
       
   264         }
       
   265 
       
   266         $this->_argumentsWorking = $getoptParser->getRemainingArgs();
       
   267 
       
   268         return;
       
   269     }
       
   270 
       
   271     /**
       
   272      * Internal routine for parsing the action name from the arguments
       
   273      *
       
   274      * @return null
       
   275      */
       
   276     protected function _parseActionPart()
       
   277     {
       
   278         // the next "word" should be the action name
       
   279         $consoleActionName = array_shift($this->_argumentsWorking);
       
   280 
       
   281         if ($consoleActionName == '?') {
       
   282             $this->_help = true;
       
   283             return;
       
   284         }
       
   285 
       
   286         $actionSearchCriteria = array(
       
   287             'type'       => 'Tool',
       
   288             'name'       => 'actionName',
       
   289             'value'      => $consoleActionName,
       
   290             'clientName' => 'console'
       
   291             );
       
   292 
       
   293         // is the action name valid?
       
   294         $actionMetadata = $this->_manifestRepository->getMetadata($actionSearchCriteria);
       
   295 
       
   296         // check for normalized names as well (all lower, no separators)
       
   297         if (!$actionMetadata) {
       
   298             $actionSearchCriteria['name']  = 'normalizedActionName';
       
   299             $actionSearchCriteria['value'] = strtolower(str_replace(array('-', '_'), '', $consoleActionName));
       
   300             $actionSearchCriteria['clientName'] = 'all';
       
   301             $actionMetadata = $this->_manifestRepository->getMetadata($actionSearchCriteria);
       
   302         }
       
   303 
       
   304         // if no action, handle error
       
   305         if (!$actionMetadata) {
       
   306             require_once 'Zend/Tool/Framework/Client/Exception.php';
       
   307             throw new Zend_Tool_Framework_Client_Exception('Action \'' . $consoleActionName . '\' is not a valid action.');
       
   308         }
       
   309 
       
   310         // prepare action request name
       
   311         $this->_helpKnownAction = true;
       
   312         $this->_request->setActionName($actionMetadata->getActionName());
       
   313         return;
       
   314     }
       
   315 
       
   316     /**
       
   317      * Internal routine for parsing the provider part of the command line arguments
       
   318      *
       
   319      * @return null
       
   320      */
       
   321     protected function _parseProviderPart()
       
   322     {
       
   323         // get the cli "word" as the provider name from command line
       
   324         $consoleProviderFull = array_shift($this->_argumentsWorking);
       
   325         $consoleSpecialtyName = '_global';
       
   326 
       
   327         // if there is notation for specialties? If so, break them up
       
   328         if (strstr($consoleProviderFull, '.')) {
       
   329             list($consoleProviderName, $consoleSpecialtyName) = explode('.', $consoleProviderFull);
       
   330         } else {
       
   331             $consoleProviderName = $consoleProviderFull;
       
   332         }
       
   333 
       
   334         if ($consoleProviderName == '?') {
       
   335             $this->_help = true;
       
   336             return;
       
   337         }
       
   338 
       
   339         $providerSearchCriteria = array(
       
   340             'type'       => 'Tool',
       
   341             'name'       => 'providerName',
       
   342             'value'      => $consoleProviderName,
       
   343             'clientName' => 'console'
       
   344             );
       
   345 
       
   346         // get the cli provider names from the manifest
       
   347         $providerMetadata = $this->_manifestRepository->getMetadata($providerSearchCriteria);
       
   348 
       
   349         // check for normalized names as well (all lower, no separators)
       
   350         if (!$providerMetadata) {
       
   351             $providerSearchCriteria['name']  = 'normalizedProviderName';
       
   352             $providerSearchCriteria['value'] = strtolower(str_replace(array('-', '_'), '', $consoleProviderName));
       
   353             $providerSearchCriteria['clientName'] = 'all';
       
   354             $providerMetadata = $this->_manifestRepository->getMetadata($providerSearchCriteria);
       
   355         }
       
   356 
       
   357         if (!$providerMetadata) {
       
   358             require_once 'Zend/Tool/Framework/Client/Exception.php';
       
   359             throw new Zend_Tool_Framework_Client_Exception(
       
   360                 'Provider \'' . $consoleProviderFull . '\' is not a valid provider.'
       
   361                 );
       
   362         }
       
   363 
       
   364         $this->_helpKnownProvider = true;
       
   365         $this->_request->setProviderName($providerMetadata->getProviderName());
       
   366 
       
   367         if ($consoleSpecialtyName == '?') {
       
   368             $this->_help = true;
       
   369             return;
       
   370         }
       
   371 
       
   372         $providerSpecialtySearchCriteria = array(
       
   373             'type'         => 'Tool',
       
   374             'name'         => 'specialtyName',
       
   375             'value'        => $consoleSpecialtyName,
       
   376             'providerName' => $providerMetadata->getProviderName(),
       
   377             'clientName'   => 'console'
       
   378             );
       
   379 
       
   380         $providerSpecialtyMetadata = $this->_manifestRepository->getMetadata($providerSpecialtySearchCriteria);
       
   381 
       
   382         if (!$providerSpecialtyMetadata) {
       
   383             $providerSpecialtySearchCriteria['name'] = 'normalizedSpecialtyName';
       
   384             $providerSpecialtySearchCriteria['value'] = strtolower(str_replace(array('-', '_'), '', $consoleSpecialtyName));
       
   385             $providerSpecialtySearchCriteria['clientName'] = 'all';
       
   386             $providerSpecialtyMetadata = $this->_manifestRepository->getMetadata($providerSpecialtySearchCriteria);
       
   387         }
       
   388 
       
   389         if (!$providerSpecialtyMetadata) {
       
   390             require_once 'Zend/Tool/Framework/Client/Exception.php';
       
   391             throw new Zend_Tool_Framework_Client_Exception(
       
   392                 'Provider \'' . $consoleSpecialtyName . '\' is not a valid specialty.'
       
   393                 );
       
   394         }
       
   395 
       
   396         $this->_helpKnownSpecialty = true;
       
   397         $this->_request->setSpecialtyName($providerSpecialtyMetadata->getSpecialtyName());
       
   398         return;
       
   399     }
       
   400 
       
   401     /**
       
   402      * Internal routine for parsing the provider options from the command line
       
   403      *
       
   404      * @return null
       
   405      */
       
   406     protected function _parseProviderOptionsPart()
       
   407     {
       
   408         if (current($this->_argumentsWorking) == '?') {
       
   409             $this->_help = true;
       
   410             return;
       
   411         }
       
   412 
       
   413         $searchParams = array(
       
   414             'type'          => 'Tool',
       
   415             'providerName'  => $this->_request->getProviderName(),
       
   416             'actionName'    => $this->_request->getActionName(),
       
   417             'specialtyName' => $this->_request->getSpecialtyName(),
       
   418             'clientName'    => 'console'
       
   419             );
       
   420 
       
   421         $actionableMethodLongParamsMetadata = $this->_manifestRepository->getMetadata(
       
   422             array_merge($searchParams, array('name' => 'actionableMethodLongParams'))
       
   423             );
       
   424 
       
   425         $actionableMethodShortParamsMetadata = $this->_manifestRepository->getMetadata(
       
   426             array_merge($searchParams, array('name' => 'actionableMethodShortParams'))
       
   427             );
       
   428 
       
   429         $paramNameShortValues = $actionableMethodShortParamsMetadata->getValue();
       
   430 
       
   431         $getoptOptions = array();
       
   432         $wordArguments = array();
       
   433         $longParamCanonicalNames = array();
       
   434 
       
   435         $actionableMethodLongParamsMetadataReference = $actionableMethodLongParamsMetadata->getReference();
       
   436         foreach ($actionableMethodLongParamsMetadata->getValue() as $parameterNameLong => $consoleParameterNameLong) {
       
   437             $optionConfig = $consoleParameterNameLong . '|';
       
   438 
       
   439             $parameterInfo = $actionableMethodLongParamsMetadataReference['parameterInfo'][$parameterNameLong];
       
   440 
       
   441             // process ParameterInfo into array for command line option matching
       
   442             if ($parameterInfo['type'] == 'string' || $parameterInfo['type'] == 'bool') {
       
   443                 $optionConfig .= $paramNameShortValues[$parameterNameLong]
       
   444                                . (($parameterInfo['optional']) ? '-' : '=') . 's';
       
   445             } elseif (in_array($parameterInfo['type'], array('int', 'integer', 'float'))) {
       
   446                 $optionConfig .= $paramNameShortValues[$parameterNameLong]
       
   447                                . (($parameterInfo['optional']) ? '-' : '=') . 'i';
       
   448             } else {
       
   449                 $optionConfig .= $paramNameShortValues[$parameterNameLong] . '-s';
       
   450             }
       
   451 
       
   452             $getoptOptions[$optionConfig] = ($parameterInfo['description'] != '') ? $parameterInfo['description'] : 'No description available.';
       
   453 
       
   454 
       
   455             // process ParameterInfo into array for command line WORD (argument) matching
       
   456             $wordArguments[$parameterInfo['position']]['parameterName'] = $parameterInfo['name'];
       
   457             $wordArguments[$parameterInfo['position']]['optional']      = $parameterInfo['optional'];
       
   458             $wordArguments[$parameterInfo['position']]['type']          = $parameterInfo['type'];
       
   459 
       
   460             // keep a translation of console to canonical names
       
   461             $longParamCanonicalNames[$consoleParameterNameLong] = $parameterNameLong;
       
   462         }
       
   463 
       
   464 
       
   465         if (!$getoptOptions) {
       
   466             // no options to parse here, return
       
   467             return;
       
   468         }
       
   469 
       
   470         // if non-option arguments exist, attempt to process them before processing options
       
   471         $wordStack = array();
       
   472         while (($wordOnTop = array_shift($this->_argumentsWorking))) {
       
   473             if (substr($wordOnTop, 0, 1) != '-') {
       
   474                 array_push($wordStack, $wordOnTop);
       
   475             } else {
       
   476                 // put word back on stack and move on
       
   477                 array_unshift($this->_argumentsWorking, $wordOnTop);
       
   478                 break;
       
   479             }
       
   480 
       
   481             if (count($wordStack) == count($wordArguments)) {
       
   482                 // when we get at most the number of arguments we are expecting
       
   483                 // then break out.
       
   484                 break;
       
   485             }
       
   486 
       
   487         }
       
   488 
       
   489         if ($wordStack && $wordArguments) {
       
   490             for ($wordIndex = 1; $wordIndex <= count($wordArguments); $wordIndex++) {
       
   491                 if (!array_key_exists($wordIndex-1, $wordStack) || !array_key_exists($wordIndex, $wordArguments)) {
       
   492                     break;
       
   493                 }
       
   494                 $this->_request->setProviderParameter($wordArguments[$wordIndex]['parameterName'], $wordStack[$wordIndex-1]);
       
   495                 unset($wordStack[$wordIndex-1]);
       
   496             }
       
   497         }
       
   498 
       
   499         $getoptParser = new Zend_Console_Getopt($getoptOptions, $this->_argumentsWorking, array('parseAll' => false));
       
   500         $getoptParser->parse();
       
   501         foreach ($getoptParser->getOptions() as $option) {
       
   502             $value = $getoptParser->getOption($option);
       
   503             $providerParamOption = $longParamCanonicalNames[$option];
       
   504             $this->_request->setProviderParameter($providerParamOption, $value);
       
   505         }
       
   506 
       
   507         $this->_argumentsWorking = $getoptParser->getRemainingArgs();
       
   508 
       
   509         return;
       
   510     }
       
   511 
       
   512     /**
       
   513      * _createHelpResponse
       
   514      *
       
   515      * @param unknown_type $options
       
   516      */
       
   517     protected function _createHelpResponse($options = array())
       
   518     {
       
   519         require_once 'Zend/Tool/Framework/Client/Console/HelpSystem.php';
       
   520         $helpSystem = new Zend_Tool_Framework_Client_Console_HelpSystem();
       
   521         $helpSystem->setRegistry($this->_registry);
       
   522 
       
   523         if (isset($options['error'])) {
       
   524             $helpSystem->respondWithErrorMessage($options['error']);
       
   525         }
       
   526 
       
   527         if (isset($options['actionName']) && isset($options['providerName'])) {
       
   528             $helpSystem->respondWithSpecialtyAndParamHelp($options['providerName'], $options['actionName']);
       
   529         } elseif (isset($options['actionName'])) {
       
   530             $helpSystem->respondWithActionHelp($options['actionName']);
       
   531         } elseif (isset($options['providerName'])) {
       
   532             $helpSystem->respondWithProviderHelp($options['providerName']);
       
   533         } else {
       
   534             $helpSystem->respondWithGeneralHelp();
       
   535         }
       
   536 
       
   537     }
       
   538 
       
   539 }