File indexing completed on 2025-01-19 05:21:35
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Tool 0017 * @subpackage Framework 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_Console_GetOpt 0025 */ 0026 // require_once 'Zend/Console/Getopt.php'; 0027 0028 /** 0029 * @see Zend_Tool_Framework_Registry_EnabledInterface 0030 */ 0031 // require_once 'Zend/Tool/Framework/Registry/EnabledInterface.php'; 0032 0033 /** 0034 * @category Zend 0035 * @package Zend_Tool 0036 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0037 * @license http://framework.zend.com/license/new-bsd New BSD License 0038 */ 0039 class Zend_Tool_Framework_Client_Console_ArgumentParser implements Zend_Tool_Framework_Registry_EnabledInterface 0040 { 0041 0042 /** 0043 * @var Zend_Tool_Framework_Registry_Interface 0044 */ 0045 protected $_registry = null; 0046 0047 /** 0048 * Holds the manifest repository taken from the registry. 0049 * 0050 * @var Zend_Tool_Framework_Manifest_Repository 0051 */ 0052 protected $_manifestRepository = null; 0053 0054 /** 0055 * @var Zend_Tool_Framework_Client_Request 0056 */ 0057 protected $_request = null; 0058 0059 /** 0060 * @var Zend_Tool_Framework_Client_Response 0061 */ 0062 protected $_response = null; 0063 0064 /**#@+ 0065 * @var array 0066 */ 0067 protected $_argumentsOriginal = null; 0068 protected $_argumentsWorking = null; 0069 /**#@-*/ 0070 0071 /** 0072 * @var bool 0073 */ 0074 protected $_help = false; 0075 protected $_helpKnownAction = false; 0076 protected $_helpKnownProvider = false; 0077 protected $_helpKnownSpecialty = false; 0078 0079 0080 /** 0081 * setArguments 0082 * 0083 * @param array $arguments 0084 * @return Zend_Tool_Framework_Client_Console_ArgumentParser 0085 */ 0086 public function setArguments(Array $arguments) 0087 { 0088 $this->_argumentsOriginal = $this->_argumentsWorking = $arguments; 0089 return $this; 0090 } 0091 0092 /** 0093 * setRegistry() 0094 * 0095 * @param Zend_Tool_Framework_Registry_Interface $registry 0096 * @return Zend_Tool_Framework_Client_Console_ArgumentParser 0097 */ 0098 public function setRegistry(Zend_Tool_Framework_Registry_Interface $registry) 0099 { 0100 // get the client registry 0101 $this->_registry = $registry; 0102 0103 // set manifest repository, request, response for easy access 0104 $this->_manifestRepository = $this->_registry->getManifestRepository(); 0105 $this->_request = $this->_registry->getRequest(); 0106 $this->_response = $this->_registry->getResponse(); 0107 return $this; 0108 } 0109 0110 /** 0111 * Parse() - This method does the work of parsing the arguments into the enpooint request, 0112 * this will also (during help operations) fill the response in with information as needed 0113 * 0114 * @return null 0115 */ 0116 public function parse() 0117 { 0118 0119 if ($this->_request == null || $this->_response == null) { 0120 // require_once 'Zend/Tool/Framework/Client/Exception.php'; 0121 throw new Zend_Tool_Framework_Client_Exception('The client registry must have both a request and response registered.'); 0122 } 0123 0124 // setup the help options 0125 $helpResponseOptions = array(); 0126 0127 // check to see if the first cli arg is the script name 0128 if ($this->_argumentsWorking[0] == $_SERVER['SCRIPT_NAME' ]) { 0129 array_shift($this->_argumentsWorking); 0130 } 0131 0132 // process global options 0133 try { 0134 $this->_parseGlobalPart(); 0135 } catch (Zend_Tool_Framework_Client_Exception $exception) { 0136 $this->_createHelpResponse(array('error' => $exception->getMessage())); 0137 return; 0138 } 0139 0140 // ensure there are arguments left 0141 if (count($this->_argumentsWorking) == 0) { 0142 $this->_request->setDispatchable(false); // at this point request is not dispatchable 0143 0144 // check to see if this was a help request 0145 if ($this->_help) { 0146 $this->_createHelpResponse(); 0147 } else { 0148 $this->_createHelpResponse(array('error' => 'An action and provider is required.')); 0149 } 0150 return; 0151 } 0152 0153 // process the action part of the command line 0154 try { 0155 $this->_parseActionPart(); 0156 } catch (Zend_Tool_Framework_Client_Exception $exception) { 0157 $this->_request->setDispatchable(false); 0158 $this->_createHelpResponse(array('error' => $exception->getMessage())); 0159 return; 0160 } 0161 0162 if ($this->_helpKnownAction) { 0163 $helpResponseOptions = array_merge( 0164 $helpResponseOptions, 0165 array('actionName' => $this->_request->getActionName()) 0166 ); 0167 } 0168 0169 /* @TODO Action Parameter Requirements */ 0170 0171 // make sure there are more "words" on the command line 0172 if (count($this->_argumentsWorking) == 0) { 0173 $this->_request->setDispatchable(false); // at this point request is not dispatchable 0174 0175 // check to see if this is a help request 0176 if ($this->_help) { 0177 $this->_createHelpResponse($helpResponseOptions); 0178 } else { 0179 $this->_createHelpResponse(array_merge($helpResponseOptions, array('error' => 'A provider is required.'))); 0180 } 0181 return; 0182 } 0183 0184 0185 // process the provider part of the command line 0186 try { 0187 $this->_parseProviderPart(); 0188 } catch (Zend_Tool_Framework_Client_Exception $exception) { 0189 $this->_request->setDispatchable(false); 0190 $this->_createHelpResponse(array('error' => $exception->getMessage())); 0191 return; 0192 } 0193 0194 if ($this->_helpKnownProvider) { 0195 $helpResponseOptions = array_merge( 0196 $helpResponseOptions, 0197 array('providerName' => $this->_request->getProviderName()) 0198 ); 0199 } 0200 0201 if ($this->_helpKnownSpecialty) { 0202 $helpResponseOptions = array_merge( 0203 $helpResponseOptions, 0204 array('specialtyName' => $this->_request->getSpecialtyName()) 0205 ); 0206 } 0207 0208 // if there are arguments on the command line, lets process them as provider options 0209 if (count($this->_argumentsWorking) != 0) { 0210 $this->_parseProviderOptionsPart(); 0211 } 0212 0213 // if there is still arguments lingering around, we can assume something is wrong 0214 if (count($this->_argumentsWorking) != 0) { 0215 $this->_request->setDispatchable(false); // at this point request is not dispatchable 0216 if ($this->_help) { 0217 $this->_createHelpResponse($helpResponseOptions); 0218 } else { 0219 $this->_createHelpResponse(array_merge( 0220 $helpResponseOptions, 0221 array('error' => 'Unknown arguments left on the command line: ' . implode(' ', $this->_argumentsWorking)) 0222 )); 0223 } 0224 return; 0225 } 0226 0227 // everything was processed and this is a request for help information 0228 if ($this->_help) { 0229 $this->_request->setDispatchable(false); // at this point request is not dispatchable 0230 $this->_createHelpResponse($helpResponseOptions); 0231 } 0232 0233 return; 0234 } 0235 0236 /** 0237 * Internal routine for parsing global options from the command line 0238 * 0239 * @return null 0240 */ 0241 protected function _parseGlobalPart() 0242 { 0243 $getoptOptions = array(); 0244 $getoptOptions['help|h'] = 'HELP'; 0245 $getoptOptions['verbose|v'] = 'VERBOSE'; 0246 $getoptOptions['pretend|p'] = 'PRETEND'; 0247 $getoptOptions['debug|d'] = 'DEBUG'; 0248 $getoptParser = new Zend_Console_Getopt($getoptOptions, $this->_argumentsWorking, array('parseAll' => false)); 0249 0250 // @todo catch any exceptions here 0251 $getoptParser->parse(); 0252 0253 foreach ($getoptParser->getOptions() as $option) { 0254 if ($option == 'pretend') { 0255 $this->_request->setPretend(true); 0256 } elseif ($option == 'debug') { 0257 $this->_request->setDebug(true); 0258 } elseif ($option == 'verbose') { 0259 $this->_request->setVerbose(true); 0260 } else { 0261 $property = '_'.$option; 0262 $this->{$property} = true; 0263 } 0264 } 0265 0266 $this->_argumentsWorking = $getoptParser->getRemainingArgs(); 0267 0268 return; 0269 } 0270 0271 /** 0272 * Internal routine for parsing the action name from the arguments 0273 * 0274 * @return null 0275 */ 0276 protected function _parseActionPart() 0277 { 0278 // the next "word" should be the action name 0279 $consoleActionName = array_shift($this->_argumentsWorking); 0280 0281 if ($consoleActionName == '?') { 0282 $this->_help = true; 0283 return; 0284 } 0285 0286 $actionSearchCriteria = array( 0287 'type' => 'Tool', 0288 'name' => 'actionName', 0289 'value' => $consoleActionName, 0290 'clientName' => 'console' 0291 ); 0292 0293 // is the action name valid? 0294 $actionMetadata = $this->_manifestRepository->getMetadata($actionSearchCriteria); 0295 0296 // check for normalized names as well (all lower, no separators) 0297 if (!$actionMetadata) { 0298 $actionSearchCriteria['name'] = 'normalizedActionName'; 0299 $actionSearchCriteria['value'] = strtolower(str_replace(array('-', '_'), '', $consoleActionName)); 0300 $actionSearchCriteria['clientName'] = 'all'; 0301 $actionMetadata = $this->_manifestRepository->getMetadata($actionSearchCriteria); 0302 } 0303 0304 // if no action, handle error 0305 if (!$actionMetadata) { 0306 // require_once 'Zend/Tool/Framework/Client/Exception.php'; 0307 throw new Zend_Tool_Framework_Client_Exception('Action \'' . $consoleActionName . '\' is not a valid action.'); 0308 } 0309 0310 // prepare action request name 0311 $this->_helpKnownAction = true; 0312 $this->_request->setActionName($actionMetadata->getActionName()); 0313 return; 0314 } 0315 0316 /** 0317 * Internal routine for parsing the provider part of the command line arguments 0318 * 0319 * @return null 0320 */ 0321 protected function _parseProviderPart() 0322 { 0323 // get the cli "word" as the provider name from command line 0324 $consoleProviderFull = array_shift($this->_argumentsWorking); 0325 $consoleSpecialtyName = '_global'; 0326 0327 // if there is notation for specialties? If so, break them up 0328 if (strstr($consoleProviderFull, '.')) { 0329 list($consoleProviderName, $consoleSpecialtyName) = explode('.', $consoleProviderFull); 0330 } else { 0331 $consoleProviderName = $consoleProviderFull; 0332 } 0333 0334 if ($consoleProviderName == '?') { 0335 $this->_help = true; 0336 return; 0337 } 0338 0339 $providerSearchCriteria = array( 0340 'type' => 'Tool', 0341 'name' => 'providerName', 0342 'value' => $consoleProviderName, 0343 'clientName' => 'console' 0344 ); 0345 0346 // get the cli provider names from the manifest 0347 $providerMetadata = $this->_manifestRepository->getMetadata($providerSearchCriteria); 0348 0349 // check for normalized names as well (all lower, no separators) 0350 if (!$providerMetadata) { 0351 $providerSearchCriteria['name'] = 'normalizedProviderName'; 0352 $providerSearchCriteria['value'] = strtolower(str_replace(array('-', '_'), '', $consoleProviderName)); 0353 $providerSearchCriteria['clientName'] = 'all'; 0354 $providerMetadata = $this->_manifestRepository->getMetadata($providerSearchCriteria); 0355 } 0356 0357 if (!$providerMetadata) { 0358 // require_once 'Zend/Tool/Framework/Client/Exception.php'; 0359 throw new Zend_Tool_Framework_Client_Exception( 0360 'Provider \'' . $consoleProviderFull . '\' is not a valid provider.' 0361 ); 0362 } 0363 0364 $this->_helpKnownProvider = true; 0365 $this->_request->setProviderName($providerMetadata->getProviderName()); 0366 0367 if ($consoleSpecialtyName == '?') { 0368 $this->_help = true; 0369 return; 0370 } 0371 0372 $providerSpecialtySearchCriteria = array( 0373 'type' => 'Tool', 0374 'name' => 'specialtyName', 0375 'value' => $consoleSpecialtyName, 0376 'providerName' => $providerMetadata->getProviderName(), 0377 'clientName' => 'console' 0378 ); 0379 0380 $providerSpecialtyMetadata = $this->_manifestRepository->getMetadata($providerSpecialtySearchCriteria); 0381 0382 if (!$providerSpecialtyMetadata) { 0383 $providerSpecialtySearchCriteria['name'] = 'normalizedSpecialtyName'; 0384 $providerSpecialtySearchCriteria['value'] = strtolower(str_replace(array('-', '_'), '', $consoleSpecialtyName)); 0385 $providerSpecialtySearchCriteria['clientName'] = 'all'; 0386 $providerSpecialtyMetadata = $this->_manifestRepository->getMetadata($providerSpecialtySearchCriteria); 0387 } 0388 0389 if (!$providerSpecialtyMetadata) { 0390 // require_once 'Zend/Tool/Framework/Client/Exception.php'; 0391 throw new Zend_Tool_Framework_Client_Exception( 0392 'Provider \'' . $consoleSpecialtyName . '\' is not a valid specialty.' 0393 ); 0394 } 0395 0396 $this->_helpKnownSpecialty = true; 0397 $this->_request->setSpecialtyName($providerSpecialtyMetadata->getSpecialtyName()); 0398 return; 0399 } 0400 0401 /** 0402 * Internal routine for parsing the provider options from the command line 0403 * 0404 * @return null 0405 */ 0406 protected function _parseProviderOptionsPart() 0407 { 0408 if (current($this->_argumentsWorking) == '?') { 0409 $this->_help = true; 0410 return; 0411 } 0412 0413 $searchParams = array( 0414 'type' => 'Tool', 0415 'providerName' => $this->_request->getProviderName(), 0416 'actionName' => $this->_request->getActionName(), 0417 'specialtyName' => $this->_request->getSpecialtyName(), 0418 'clientName' => 'console' 0419 ); 0420 0421 $actionableMethodLongParamsMetadata = $this->_manifestRepository->getMetadata( 0422 array_merge($searchParams, array('name' => 'actionableMethodLongParams')) 0423 ); 0424 0425 $actionableMethodShortParamsMetadata = $this->_manifestRepository->getMetadata( 0426 array_merge($searchParams, array('name' => 'actionableMethodShortParams')) 0427 ); 0428 0429 $paramNameShortValues = $actionableMethodShortParamsMetadata->getValue(); 0430 0431 $getoptOptions = array(); 0432 $wordArguments = array(); 0433 $longParamCanonicalNames = array(); 0434 0435 $actionableMethodLongParamsMetadataReference = $actionableMethodLongParamsMetadata->getReference(); 0436 foreach ($actionableMethodLongParamsMetadata->getValue() as $parameterNameLong => $consoleParameterNameLong) { 0437 $optionConfig = $consoleParameterNameLong . '|'; 0438 0439 $parameterInfo = $actionableMethodLongParamsMetadataReference['parameterInfo'][$parameterNameLong]; 0440 0441 // process ParameterInfo into array for command line option matching 0442 if ($parameterInfo['type'] == 'string' || $parameterInfo['type'] == 'bool') { 0443 $optionConfig .= $paramNameShortValues[$parameterNameLong] 0444 . (($parameterInfo['optional']) ? '-' : '=') . 's'; 0445 } elseif (in_array($parameterInfo['type'], array('int', 'integer', 'float'))) { 0446 $optionConfig .= $paramNameShortValues[$parameterNameLong] 0447 . (($parameterInfo['optional']) ? '-' : '=') . 'i'; 0448 } else { 0449 $optionConfig .= $paramNameShortValues[$parameterNameLong] . '-s'; 0450 } 0451 0452 $getoptOptions[$optionConfig] = ($parameterInfo['description'] != '') ? $parameterInfo['description'] : 'No description available.'; 0453 0454 0455 // process ParameterInfo into array for command line WORD (argument) matching 0456 $wordArguments[$parameterInfo['position']]['parameterName'] = $parameterInfo['name']; 0457 $wordArguments[$parameterInfo['position']]['optional'] = $parameterInfo['optional']; 0458 $wordArguments[$parameterInfo['position']]['type'] = $parameterInfo['type']; 0459 0460 // keep a translation of console to canonical names 0461 $longParamCanonicalNames[$consoleParameterNameLong] = $parameterNameLong; 0462 } 0463 0464 0465 if (!$getoptOptions) { 0466 // no options to parse here, return 0467 return; 0468 } 0469 0470 // if non-option arguments exist, attempt to process them before processing options 0471 $wordStack = array(); 0472 while (($wordOnTop = array_shift($this->_argumentsWorking))) { 0473 if (substr($wordOnTop, 0, 1) != '-') { 0474 array_push($wordStack, $wordOnTop); 0475 } else { 0476 // put word back on stack and move on 0477 array_unshift($this->_argumentsWorking, $wordOnTop); 0478 break; 0479 } 0480 0481 if (count($wordStack) == count($wordArguments)) { 0482 // when we get at most the number of arguments we are expecting 0483 // then break out. 0484 break; 0485 } 0486 0487 } 0488 0489 if ($wordStack && $wordArguments) { 0490 for ($wordIndex = 1; $wordIndex <= count($wordArguments); $wordIndex++) { 0491 if (!array_key_exists($wordIndex-1, $wordStack) || !array_key_exists($wordIndex, $wordArguments)) { 0492 break; 0493 } 0494 $this->_request->setProviderParameter($wordArguments[$wordIndex]['parameterName'], $wordStack[$wordIndex-1]); 0495 unset($wordStack[$wordIndex-1]); 0496 } 0497 } 0498 0499 $getoptParser = new Zend_Console_Getopt($getoptOptions, $this->_argumentsWorking, array('parseAll' => false)); 0500 $getoptParser->parse(); 0501 foreach ($getoptParser->getOptions() as $option) { 0502 $value = $getoptParser->getOption($option); 0503 $providerParamOption = $longParamCanonicalNames[$option]; 0504 $this->_request->setProviderParameter($providerParamOption, $value); 0505 } 0506 0507 $this->_argumentsWorking = $getoptParser->getRemainingArgs(); 0508 0509 return; 0510 } 0511 0512 /** 0513 * _createHelpResponse 0514 * 0515 * @param unknown_type $options 0516 */ 0517 protected function _createHelpResponse($options = array()) 0518 { 0519 // require_once 'Zend/Tool/Framework/Client/Console/HelpSystem.php'; 0520 $helpSystem = new Zend_Tool_Framework_Client_Console_HelpSystem(); 0521 $helpSystem->setRegistry($this->_registry); 0522 0523 if (isset($options['error'])) { 0524 $helpSystem->respondWithErrorMessage($options['error']); 0525 } 0526 0527 if (isset($options['actionName']) && isset($options['providerName'])) { 0528 $helpSystem->respondWithSpecialtyAndParamHelp($options['providerName'], $options['actionName']); 0529 } elseif (isset($options['actionName'])) { 0530 $helpSystem->respondWithActionHelp($options['actionName']); 0531 } elseif (isset($options['providerName'])) { 0532 $helpSystem->respondWithProviderHelp($options['providerName']); 0533 } else { 0534 $helpSystem->respondWithGeneralHelp(); 0535 } 0536 0537 } 0538 0539 }