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

/lib/Zend/Service/Console/Command.php

https://gitlab.com/blingbang2016/shop
PHP | 413 lines | 250 code | 45 blank | 118 comment | 41 complexity | c94204e49bc285a615c281253cb41641 MD5 | raw file
  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_Service_Console
  17. * @version $Id$
  18. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
  21. * @license http://phpazure.codeplex.com/license
  22. */
  23. /**
  24. * @category Zend
  25. * @package Zend_Service_Console
  26. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  27. * @license http://framework.zend.com/license/new-bsd New BSD License
  28. * @copyright Copyright (c) 2009 - 2011, RealDolmen (http://www.realdolmen.com)
  29. * @license http://phpazure.codeplex.com/license
  30. */
  31. class Zend_Service_Console_Command
  32. {
  33. /**
  34. * The handler.
  35. *
  36. * @var array
  37. */
  38. protected $_handler;
  39. /**
  40. * Gets the handler.
  41. *
  42. * @return array
  43. */
  44. public function getHandler()
  45. {
  46. return $this->_handler;
  47. }
  48. /**
  49. * Sets the handler.
  50. *
  51. * @param array $handler
  52. * @return Zend_Service_Console_Command
  53. */
  54. public function setHandler($handler)
  55. {
  56. $this->_handler = $handler;
  57. return $this;
  58. }
  59. /**
  60. * Replaces PHP's error handler
  61. *
  62. * @param mixed $errno
  63. * @param mixed $errstr
  64. * @param mixed $errfile
  65. * @param mixed $errline
  66. */
  67. public static function phpstderr($errno, $errstr, $errfile, $errline)
  68. {
  69. self::stderr($errno . ': Error in ' . $errfile . ':' . $errline . ' - ' . $errstr);
  70. }
  71. /**
  72. * Replaces PHP's exception handler
  73. *
  74. * @param Exception $exception
  75. */
  76. public static function phpstdex($exception)
  77. {
  78. self::stderr('Error: ' . $exception->getMessage());
  79. }
  80. /**
  81. * Writes output to STDERR, followed by a newline (optional)
  82. *
  83. * @param string $errorMessage
  84. * @param string $newLine
  85. */
  86. public static function stderr($errorMessage, $newLine = true)
  87. {
  88. if (error_reporting() === 0) {
  89. return;
  90. }
  91. file_put_contents('php://stderr', $errorMessage . ($newLine ? "\r\n" : ''));
  92. }
  93. /**
  94. * Bootstrap the shell command.
  95. *
  96. * @param array $argv PHP argument values.
  97. */
  98. public static function bootstrap($argv)
  99. {
  100. // Abort bootstrapping depending on the MICROSOFT_CONSOLE_COMMAND_HOST constant.
  101. if (defined('MICROSOFT_CONSOLE_COMMAND_HOST') && strtolower(MICROSOFT_CONSOLE_COMMAND_HOST) != 'console') {
  102. return;
  103. }
  104. // Replace error handler
  105. set_error_handler(array('Zend_Service_Console_Command', 'phpstderr'));
  106. set_exception_handler(array('Zend_Service_Console_Command', 'phpstdex'));
  107. // Build the application model
  108. $model = self::_buildModel();
  109. // Find a class that corresponds to the $argv[0] script name
  110. $requiredHandlerName = str_replace('.bat', '', str_replace('.sh', '', str_replace('.php', '', strtolower(basename($argv[0])))));
  111. $handler = null;
  112. foreach ($model as $possibleHandler) {
  113. if ($possibleHandler->handler == strtolower($requiredHandlerName)) {
  114. $handler = $possibleHandler;
  115. break;
  116. }
  117. }
  118. if (is_null($handler)) {
  119. self::stderr("No class found that implements handler '" . $requiredHandlerName . "'. Create a class that is named '" . $requiredHandlerName . "' and extends Zend_Service_Console_Command or is decorated with a docblock comment '@command-handler " . $requiredHandlerName . "'. Make sure it is loaded either through an autoloader or explicitly using #require_once().");
  120. die();
  121. }
  122. // Find a method that matches the command name
  123. $command = null;
  124. foreach ($handler->commands as $possibleCommand) {
  125. if (in_array(strtolower(isset($argv[1]) ? $argv[1] : '<default>'), $possibleCommand->aliases)) {
  126. $command = $possibleCommand;
  127. break;
  128. }
  129. }
  130. if (is_null($command)) {
  131. $commandName = (isset($argv[1]) ? $argv[1] : '<default>');
  132. self::stderr("No method found that implements command " . $commandName . ". Create a method in class '" . $handler->class . "' that is named '" . strtolower($commandName) . "Command' or is decorated with a docblock comment '@command-name " . $commandName . "'.");
  133. die();
  134. }
  135. // Parse parameter values
  136. $parameterValues = array();
  137. $missingParameterValues = array();
  138. $parameterInputs = array_splice($argv, 2);
  139. foreach ($command->parameters as $parameter) {
  140. // Default value: null
  141. $value = null;
  142. // Consult value providers for value. First one wins.
  143. foreach ($parameter->valueproviders as $valueProviderName) {
  144. if (!class_exists($valueProviderName)) {
  145. $valueProviderName = 'Zend_Service_Console_Command_ParameterSource_' . $valueProviderName;
  146. }
  147. $valueProvider = new $valueProviderName();
  148. $value = $valueProvider->getValueForParameter($parameter, $parameterInputs);
  149. if (!is_null($value)) {
  150. break;
  151. }
  152. }
  153. if (is_null($value) && $parameter->required) {
  154. $missingParameterValues[] = $parameter->aliases[0];
  155. } else if (is_null($value)) {
  156. $value = $parameter->defaultvalue;
  157. }
  158. // Set value
  159. $parameterValues[] = $value;
  160. $argvValues[$parameter->aliases[0]] = $value;
  161. }
  162. // Mising parameters?
  163. if (count($missingParameterValues) > 0) {
  164. self::stderr("Some parameters are missing:\r\n" . implode("\r\n", $missingParameterValues));
  165. die();
  166. }
  167. // Supply argv in a nice way
  168. $parameterValues['argv'] = $parameterInputs;
  169. // Run the command
  170. $className = $handler->class;
  171. $classInstance = new $className();
  172. $classInstance->setHandler($handler);
  173. call_user_func_array(array($classInstance, $command->method), $parameterValues);
  174. // Restore error handler
  175. restore_exception_handler();
  176. restore_error_handler();
  177. }
  178. /**
  179. * Builds the handler model.
  180. *
  181. * @return array
  182. */
  183. protected static function _buildModel()
  184. {
  185. $model = array();
  186. $classes = get_declared_classes();
  187. foreach ($classes as $class) {
  188. $type = new ReflectionClass($class);
  189. $handlers = self::_findValueForDocComment('@command-handler', $type->getDocComment());
  190. if (count($handlers) == 0 && $type->isSubclassOf('Zend_Service_Console_Command')) {
  191. // Fallback: if the class extends Zend_Service_Console_Command, register it as
  192. // a command handler.
  193. $handlers[] = $class;
  194. }
  195. $handlerDescriptions = self::_findValueForDocComment('@command-handler-description', $type->getDocComment());
  196. $handlerHeaders = self::_findValueForDocComment('@command-handler-header', $type->getDocComment());
  197. $handlerFooters = self::_findValueForDocComment('@command-handler-footer', $type->getDocComment());
  198. for ($hi = 0; $hi < count($handlers); $hi++) {
  199. $handler = $handlers[$hi];
  200. $handlerDescription = isset($handlerDescriptions[$hi]) ? $handlerDescriptions[$hi] : isset($handlerDescriptions[0]) ? $handlerDescriptions[0] : '';
  201. $handlerDescription = str_replace('\r\n', "\r\n", $handlerDescription);
  202. $handlerDescription = str_replace('\n', "\n", $handlerDescription);
  203. $handlerModel = (object)array(
  204. 'handler' => strtolower($handler),
  205. 'description' => $handlerDescription,
  206. 'headers' => $handlerHeaders,
  207. 'footers' => $handlerFooters,
  208. 'class' => $class,
  209. 'commands' => array()
  210. );
  211. $methods = $type->getMethods();
  212. foreach ($methods as $method) {
  213. $commands = self::_findValueForDocComment('@command-name', $method->getDocComment());
  214. if (substr($method->getName(), -7) == 'Command' && !in_array(substr($method->getName(), 0, -7), $commands)) {
  215. // Fallback: if the method is named <commandname>Command,
  216. // register it as a command.
  217. $commands[] = substr($method->getName(), 0, -7);
  218. }
  219. for ($x = 0; $x < count($commands); $x++) {
  220. $commands[$x] = strtolower($commands[$x]);
  221. }
  222. $commands = array_unique($commands);
  223. $commandDescriptions = self::_findValueForDocComment('@command-description', $method->getDocComment());
  224. $commandExamples = self::_findValueForDocComment('@command-example', $method->getDocComment());
  225. if (count($commands) > 0) {
  226. $command = $commands[0];
  227. $commandDescription = isset($commandDescriptions[0]) ? $commandDescriptions[0] : '';
  228. $commandModel = (object)array(
  229. 'command' => $command,
  230. 'aliases' => $commands,
  231. 'description' => $commandDescription,
  232. 'examples' => $commandExamples,
  233. 'class' => $class,
  234. 'method' => $method->getName(),
  235. 'parameters' => array()
  236. );
  237. $parameters = $method->getParameters();
  238. $parametersFor = self::_findValueForDocComment('@command-parameter-for', $method->getDocComment());
  239. for ($pi = 0; $pi < count($parameters); $pi++) {
  240. // Initialize
  241. $parameter = $parameters[$pi];
  242. $parameterFor = null;
  243. $parameterForDefaultValue = null;
  244. // Is it a "catch-all" parameter?
  245. if ($parameter->getName() == 'argv') {
  246. continue;
  247. }
  248. // Find the $parametersFor with the same name defined
  249. foreach ($parametersFor as $possibleParameterFor) {
  250. $possibleParameterFor = explode(' ', $possibleParameterFor, 4);
  251. if ($possibleParameterFor[0] == '$' . $parameter->getName()) {
  252. $parameterFor = $possibleParameterFor;
  253. break;
  254. }
  255. }
  256. if (is_null($parameterFor)) {
  257. die('@command-parameter-for missing for parameter $' . $parameter->getName());
  258. }
  259. if (is_null($parameterForDefaultValue) && $parameter->isOptional()) {
  260. $parameterForDefaultValue = $parameter->getDefaultValue();
  261. }
  262. $parameterModel = (object)array(
  263. 'name' => '$' . $parameter->getName(),
  264. 'defaultvalue' => $parameterForDefaultValue,
  265. 'valueproviders' => explode('|', $parameterFor[1]),
  266. 'aliases' => explode('|', $parameterFor[2]),
  267. 'description' => (isset($parameterFor[3]) ? $parameterFor[3] : ''),
  268. 'required' => (isset($parameterFor[3]) ? strpos(strtolower($parameterFor[3]), 'required') !== false && strpos(strtolower($parameterFor[3]), 'required if') === false : false),
  269. );
  270. // Add to model
  271. $commandModel->parameters[] = $parameterModel;
  272. }
  273. // Add to model
  274. $handlerModel->commands[] = $commandModel;
  275. }
  276. }
  277. // Add to model
  278. $model[] = $handlerModel;
  279. }
  280. }
  281. return $model;
  282. }
  283. /**
  284. * Finds the value for a specific docComment.
  285. *
  286. * @param string $docCommentName Comment name
  287. * @param unknown_type $docComment Comment object
  288. * @return array
  289. */
  290. protected static function _findValueForDocComment($docCommentName, $docComment)
  291. {
  292. $returnValue = array();
  293. $commentLines = explode("\n", $docComment);
  294. foreach ($commentLines as $commentLine) {
  295. if (strpos($commentLine, $docCommentName . ' ') !== false) {
  296. $returnValue[] = trim(substr($commentLine, strpos($commentLine, $docCommentName) + strlen($docCommentName) + 1));
  297. }
  298. }
  299. return $returnValue;
  300. }
  301. /**
  302. * Display information on an object
  303. *
  304. * @param object $object Object
  305. * @param array $propertiesToDump Property names to display
  306. */
  307. protected function _displayObjectInformation($object, $propertiesToDump = array())
  308. {
  309. foreach ($propertiesToDump as $property) {
  310. printf('%-16s: %s' . "\r\n", $property, $object->$property);
  311. }
  312. printf("\r\n");
  313. }
  314. /**
  315. * Displays the help information.
  316. *
  317. * @command-name <default>
  318. * @command-name -h
  319. * @command-name -help
  320. * @command-description Displays the current help information.
  321. */
  322. public function helpCommand() {
  323. $handler = $this->getHandler();
  324. $newline = "\r\n";
  325. if (count($handler->headers) > 0) {
  326. foreach ($handler->headers as $header) {
  327. printf('%s%s', $header, $newline);
  328. }
  329. printf($newline);
  330. }
  331. printf('%s%s', $handler->description, $newline);
  332. printf($newline);
  333. printf('Available commands:%s', $newline);
  334. foreach ($handler->commands as $command) {
  335. $description = str_split($command->description, 50);
  336. printf(' %-25s %s%s', implode(', ', $command->aliases), $description[0], $newline);
  337. for ($di = 1; $di < count($description); $di++) {
  338. printf(' %-25s %s%s', '', $description[$di], $newline);
  339. }
  340. printf($newline);
  341. if (count($command->parameters) > 0) {
  342. foreach ($command->parameters as $parameter) {
  343. $description = str_split($parameter->description, 50);
  344. printf(' %-23s %s%s', implode(', ', $parameter->aliases), $description[0], $newline);
  345. for ($di = 1; $di < count($description); $di++) {
  346. printf(' %-23s %s%s', '', $description[$di], $newline);
  347. }
  348. printf($newline);
  349. }
  350. }
  351. printf($newline);
  352. if (count($command->examples) > 0) {
  353. printf(' Example usage:%s', $newline);
  354. foreach ($command->examples as $example) {
  355. printf(' %s%s', $example, $newline);
  356. }
  357. printf($newline);
  358. }
  359. }
  360. if (count($handler->footers) > 0) {
  361. printf($newline);
  362. foreach ($handler->footers as $footer) {
  363. printf('%s%s', $footer, $newline);
  364. }
  365. printf($newline);
  366. }
  367. }
  368. }