PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Tool/Framework/Client/Console/ArgumentParser.php

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