CConsoleApplication.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <?php
  2. /**
  3. * CConsoleApplication class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright 2008-2013 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CConsoleApplication represents a console application.
  12. *
  13. * CConsoleApplication extends {@link CApplication} by providing functionalities
  14. * specific to console requests. In particular, it deals with console requests
  15. * through a command-based approach:
  16. * <ul>
  17. * <li>A console application consists of one or several possible user commands;</li>
  18. * <li>Each user command is implemented as a class extending {@link CConsoleCommand};</li>
  19. * <li>User specifies which command to run on the command line;</li>
  20. * <li>The command processes the user request with the specified parameters.</li>
  21. * </ul>
  22. *
  23. * The command classes reside in the directory {@link getCommandPath commandPath}.
  24. * The name of the class follows the pattern: &lt;command-name&gt;Command, and its
  25. * file name is the same as the class name. For example, the 'ShellCommand' class defines
  26. * a 'shell' command and the class file name is 'ShellCommand.php'.
  27. *
  28. * To run the console application, enter the following on the command line:
  29. * <pre>
  30. * php path/to/entry_script.php <command name> [param 1] [param 2] ...
  31. * </pre>
  32. *
  33. * You may use the following to see help instructions about a command:
  34. * <pre>
  35. * php path/to/entry_script.php help <command name>
  36. * </pre>
  37. *
  38. * @property string $commandPath The directory that contains the command classes. Defaults to 'protected/commands'.
  39. * @property CConsoleCommandRunner $commandRunner The command runner.
  40. * @property CConsoleCommand $command The currently active command.
  41. *
  42. * @author Qiang Xue <qiang.xue@gmail.com>
  43. * @package system.console
  44. * @since 1.0
  45. */
  46. class CConsoleApplication extends CApplication
  47. {
  48. /**
  49. * @var array mapping from command name to command configurations.
  50. * Each command configuration can be either a string or an array.
  51. * If the former, the string should be the file path of the command class.
  52. * If the latter, the array must contain a 'class' element which specifies
  53. * the command's class name or {@link YiiBase::getPathOfAlias class path alias}.
  54. * The rest name-value pairs in the array are used to initialize
  55. * the corresponding command properties. For example,
  56. * <pre>
  57. * array(
  58. * 'email'=>array(
  59. * 'class'=>'path.to.Mailer',
  60. * 'interval'=>3600,
  61. * ),
  62. * 'log'=>'path/to/LoggerCommand.php',
  63. * )
  64. * </pre>
  65. */
  66. public $commandMap=array();
  67. private $_commandPath;
  68. private $_runner;
  69. /**
  70. * Initializes the application by creating the command runner.
  71. */
  72. protected function init()
  73. {
  74. parent::init();
  75. if(empty($_SERVER['argv']))
  76. die('This script must be run from the command line.');
  77. $this->_runner=$this->createCommandRunner();
  78. $this->_runner->commands=$this->commandMap;
  79. $this->_runner->addCommands($this->getCommandPath());
  80. }
  81. /**
  82. * Processes the user request.
  83. * This method uses a console command runner to handle the particular user command.
  84. * Since version 1.1.11 this method will exit application with an exit code if one is returned by the user command.
  85. */
  86. public function processRequest()
  87. {
  88. $exitCode=$this->_runner->run($_SERVER['argv']);
  89. if(is_int($exitCode))
  90. $this->end($exitCode);
  91. }
  92. /**
  93. * Creates the command runner instance.
  94. * @return CConsoleCommandRunner the command runner
  95. */
  96. protected function createCommandRunner()
  97. {
  98. return new CConsoleCommandRunner;
  99. }
  100. /**
  101. * Displays the captured PHP error.
  102. * This method displays the error in console mode when there is
  103. * no active error handler.
  104. * @param integer $code error code
  105. * @param string $message error message
  106. * @param string $file error file
  107. * @param string $line error line
  108. */
  109. public function displayError($code,$message,$file,$line)
  110. {
  111. echo "PHP Error[$code]: $message\n";
  112. echo " in file $file at line $line\n";
  113. $trace=debug_backtrace();
  114. // skip the first 4 stacks as they do not tell the error position
  115. if(count($trace)>4)
  116. $trace=array_slice($trace,4);
  117. foreach($trace as $i=>$t)
  118. {
  119. if(!isset($t['file']))
  120. $t['file']='unknown';
  121. if(!isset($t['line']))
  122. $t['line']=0;
  123. if(!isset($t['function']))
  124. $t['function']='unknown';
  125. echo "#$i {$t['file']}({$t['line']}): ";
  126. if(isset($t['object']) && is_object($t['object']))
  127. echo get_class($t['object']).'->';
  128. echo "{$t['function']}()\n";
  129. }
  130. }
  131. /**
  132. * Displays the uncaught PHP exception.
  133. * This method displays the exception in console mode when there is
  134. * no active error handler.
  135. * @param Exception $exception the uncaught exception
  136. */
  137. public function displayException($exception)
  138. {
  139. echo $exception;
  140. }
  141. /**
  142. * @return string the directory that contains the command classes. Defaults to 'protected/commands'.
  143. */
  144. public function getCommandPath()
  145. {
  146. $applicationCommandPath = $this->getBasePath().DIRECTORY_SEPARATOR.'commands';
  147. if($this->_commandPath===null && file_exists($applicationCommandPath))
  148. $this->setCommandPath($applicationCommandPath);
  149. return $this->_commandPath;
  150. }
  151. /**
  152. * @param string $value the directory that contains the command classes.
  153. * @throws CException if the directory is invalid
  154. */
  155. public function setCommandPath($value)
  156. {
  157. if(($this->_commandPath=realpath($value))===false || !is_dir($this->_commandPath))
  158. throw new CException(Yii::t('yii','The command path "{path}" is not a valid directory.',
  159. array('{path}'=>$value)));
  160. }
  161. /**
  162. * Returns the command runner.
  163. * @return CConsoleCommandRunner the command runner.
  164. */
  165. public function getCommandRunner()
  166. {
  167. return $this->_runner;
  168. }
  169. /**
  170. * Returns the currently running command.
  171. * This is shortcut method for {@link CConsoleCommandRunner::getCommand()}.
  172. * @return CConsoleCommand|null the currently active command.
  173. * @since 1.1.14
  174. */
  175. public function getCommand()
  176. {
  177. return $this->getCommandRunner()->getCommand();
  178. }
  179. /**
  180. * This is shortcut method for {@link CConsoleCommandRunner::setCommand()}.
  181. * @param CConsoleCommand $value the currently active command.
  182. * @since 1.1.14
  183. */
  184. public function setCommand($value)
  185. {
  186. $this->getCommandRunner()->setCommand($value);
  187. }
  188. }