Base for a static organization website

Shell.php 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  1. <?php
  2. /**
  3. * Base class for Shells
  4. *
  5. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  6. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  7. *
  8. * Licensed under The MIT License
  9. * For full copyright and license information, please see the LICENSE.txt
  10. * Redistributions of files must retain the above copyright notice.
  11. *
  12. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  13. * @link http://cakephp.org CakePHP(tm) Project
  14. * @since CakePHP(tm) v 1.2.0.5012
  15. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  16. */
  17. App::uses('TaskCollection', 'Console');
  18. App::uses('ConsoleOutput', 'Console');
  19. App::uses('ConsoleInput', 'Console');
  20. App::uses('ConsoleInputSubcommand', 'Console');
  21. App::uses('ConsoleOptionParser', 'Console');
  22. App::uses('ClassRegistry', 'Utility');
  23. App::uses('File', 'Utility');
  24. /**
  25. * Base class for command-line utilities for automating programmer chores.
  26. *
  27. * @package Cake.Console
  28. */
  29. class Shell extends Object {
  30. /**
  31. * Output constant making verbose shells.
  32. *
  33. * @var int
  34. */
  35. const VERBOSE = 2;
  36. /**
  37. * Output constant for making normal shells.
  38. *
  39. * @var int
  40. */
  41. const NORMAL = 1;
  42. /**
  43. * Output constants for making quiet shells.
  44. *
  45. * @var int
  46. */
  47. const QUIET = 0;
  48. /**
  49. * An instance of ConsoleOptionParser that has been configured for this class.
  50. *
  51. * @var ConsoleOptionParser
  52. */
  53. public $OptionParser;
  54. /**
  55. * If true, the script will ask for permission to perform actions.
  56. *
  57. * @var bool
  58. */
  59. public $interactive = true;
  60. /**
  61. * Contains command switches parsed from the command line.
  62. *
  63. * @var array
  64. */
  65. public $params = array();
  66. /**
  67. * The command (method/task) that is being run.
  68. *
  69. * @var string
  70. */
  71. public $command;
  72. /**
  73. * Contains arguments parsed from the command line.
  74. *
  75. * @var array
  76. */
  77. public $args = array();
  78. /**
  79. * The name of the shell in camelized.
  80. *
  81. * @var string
  82. */
  83. public $name = null;
  84. /**
  85. * The name of the plugin the shell belongs to.
  86. * Is automatically set by ShellDispatcher when a shell is constructed.
  87. *
  88. * @var string
  89. */
  90. public $plugin = null;
  91. /**
  92. * Contains tasks to load and instantiate
  93. *
  94. * @var array
  95. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::$tasks
  96. */
  97. public $tasks = array();
  98. /**
  99. * Contains the loaded tasks
  100. *
  101. * @var array
  102. */
  103. public $taskNames = array();
  104. /**
  105. * Contains models to load and instantiate
  106. *
  107. * @var array
  108. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::$uses
  109. */
  110. public $uses = array();
  111. /**
  112. * This shell's primary model class name, the first model in the $uses property
  113. *
  114. * @var string
  115. */
  116. public $modelClass = null;
  117. /**
  118. * Task Collection for the command, used to create Tasks.
  119. *
  120. * @var TaskCollection
  121. */
  122. public $Tasks;
  123. /**
  124. * Normalized map of tasks.
  125. *
  126. * @var string
  127. */
  128. protected $_taskMap = array();
  129. /**
  130. * stdout object.
  131. *
  132. * @var ConsoleOutput
  133. */
  134. public $stdout;
  135. /**
  136. * stderr object.
  137. *
  138. * @var ConsoleOutput
  139. */
  140. public $stderr;
  141. /**
  142. * stdin object
  143. *
  144. * @var ConsoleInput
  145. */
  146. public $stdin;
  147. /**
  148. * The number of bytes last written to the output stream
  149. * used when overwriting the previous message.
  150. *
  151. * @var int
  152. */
  153. protected $_lastWritten = 0;
  154. /**
  155. * Constructs this Shell instance.
  156. *
  157. * @param ConsoleOutput $stdout A ConsoleOutput object for stdout.
  158. * @param ConsoleOutput $stderr A ConsoleOutput object for stderr.
  159. * @param ConsoleInput $stdin A ConsoleInput object for stdin.
  160. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell
  161. */
  162. public function __construct($stdout = null, $stderr = null, $stdin = null) {
  163. if (!$this->name) {
  164. $this->name = Inflector::camelize(str_replace(array('Shell', 'Task'), '', get_class($this)));
  165. }
  166. $this->Tasks = new TaskCollection($this);
  167. $this->stdout = $stdout ? $stdout : new ConsoleOutput('php://stdout');
  168. $this->stderr = $stderr ? $stderr : new ConsoleOutput('php://stderr');
  169. $this->stdin = $stdin ? $stdin : new ConsoleInput('php://stdin');
  170. $this->_useLogger();
  171. $parent = get_parent_class($this);
  172. if ($this->tasks !== null && $this->tasks !== false) {
  173. $this->_mergeVars(array('tasks'), $parent, true);
  174. }
  175. if (!empty($this->uses)) {
  176. $this->_mergeVars(array('uses'), $parent, false);
  177. }
  178. }
  179. /**
  180. * Initializes the Shell
  181. * acts as constructor for subclasses
  182. * allows configuration of tasks prior to shell execution
  183. *
  184. * @return void
  185. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::initialize
  186. */
  187. public function initialize() {
  188. $this->_loadModels();
  189. $this->loadTasks();
  190. }
  191. /**
  192. * Starts up the Shell and displays the welcome message.
  193. * Allows for checking and configuring prior to command or main execution
  194. *
  195. * Override this method if you want to remove the welcome information,
  196. * or otherwise modify the pre-command flow.
  197. *
  198. * @return void
  199. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup
  200. */
  201. public function startup() {
  202. $this->_welcome();
  203. }
  204. /**
  205. * Displays a header for the shell
  206. *
  207. * @return void
  208. */
  209. protected function _welcome() {
  210. $this->out();
  211. $this->out(__d('cake_console', '<info>Welcome to CakePHP %s Console</info>', 'v' . Configure::version()));
  212. $this->hr();
  213. $this->out(__d('cake_console', 'App : %s', APP_DIR));
  214. $this->out(__d('cake_console', 'Path: %s', APP));
  215. $this->hr();
  216. }
  217. /**
  218. * If $uses is an array load each of the models in the array
  219. *
  220. * @return bool
  221. */
  222. protected function _loadModels() {
  223. if (is_array($this->uses)) {
  224. list(, $this->modelClass) = pluginSplit(current($this->uses));
  225. foreach ($this->uses as $modelClass) {
  226. $this->loadModel($modelClass);
  227. }
  228. }
  229. return true;
  230. }
  231. /**
  232. * Lazy loads models using the loadModel() method if declared in $uses
  233. *
  234. * @param string $name The name of the model to look for.
  235. * @return void
  236. */
  237. public function __isset($name) {
  238. if (is_array($this->uses)) {
  239. foreach ($this->uses as $modelClass) {
  240. list(, $class) = pluginSplit($modelClass);
  241. if ($name === $class) {
  242. return $this->loadModel($modelClass);
  243. }
  244. }
  245. }
  246. }
  247. /**
  248. * Loads and instantiates models required by this shell.
  249. *
  250. * @param string $modelClass Name of model class to load
  251. * @param mixed $id Initial ID the instanced model class should have
  252. * @return mixed true when single model found and instance created, error returned if model not found.
  253. * @throws MissingModelException if the model class cannot be found.
  254. */
  255. public function loadModel($modelClass = null, $id = null) {
  256. if ($modelClass === null) {
  257. $modelClass = $this->modelClass;
  258. }
  259. $this->uses = ($this->uses) ? (array)$this->uses : array();
  260. if (!in_array($modelClass, $this->uses)) {
  261. $this->uses[] = $modelClass;
  262. }
  263. list($plugin, $modelClass) = pluginSplit($modelClass, true);
  264. if (!isset($this->modelClass)) {
  265. $this->modelClass = $modelClass;
  266. }
  267. $this->{$modelClass} = ClassRegistry::init(array(
  268. 'class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id
  269. ));
  270. if (!$this->{$modelClass}) {
  271. throw new MissingModelException($modelClass);
  272. }
  273. return true;
  274. }
  275. /**
  276. * Loads tasks defined in public $tasks
  277. *
  278. * @return bool
  279. */
  280. public function loadTasks() {
  281. if ($this->tasks === true || empty($this->tasks) || empty($this->Tasks)) {
  282. return true;
  283. }
  284. $this->_taskMap = TaskCollection::normalizeObjectArray((array)$this->tasks);
  285. $this->taskNames = array_merge($this->taskNames, array_keys($this->_taskMap));
  286. return true;
  287. }
  288. /**
  289. * Check to see if this shell has a task with the provided name.
  290. *
  291. * @param string $task The task name to check.
  292. * @return bool Success
  293. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasTask
  294. */
  295. public function hasTask($task) {
  296. return isset($this->_taskMap[Inflector::camelize($task)]);
  297. }
  298. /**
  299. * Check to see if this shell has a callable method by the given name.
  300. *
  301. * @param string $name The method name to check.
  302. * @return bool
  303. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hasMethod
  304. */
  305. public function hasMethod($name) {
  306. try {
  307. $method = new ReflectionMethod($this, $name);
  308. if (!$method->isPublic() || substr($name, 0, 1) === '_') {
  309. return false;
  310. }
  311. if ($method->getDeclaringClass()->name === 'Shell') {
  312. return false;
  313. }
  314. return true;
  315. } catch (ReflectionException $e) {
  316. return false;
  317. }
  318. }
  319. /**
  320. * Dispatch a command to another Shell. Similar to Object::requestAction()
  321. * but intended for running shells from other shells.
  322. *
  323. * ### Usage:
  324. *
  325. * With a string command:
  326. *
  327. * `return $this->dispatchShell('schema create DbAcl');`
  328. *
  329. * Avoid using this form if you have string arguments, with spaces in them.
  330. * The dispatched will be invoked incorrectly. Only use this form for simple
  331. * command dispatching.
  332. *
  333. * With an array command:
  334. *
  335. * `return $this->dispatchShell('schema', 'create', 'i18n', '--dry');`
  336. *
  337. * @return mixed The return of the other shell.
  338. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::dispatchShell
  339. */
  340. public function dispatchShell() {
  341. $args = func_get_args();
  342. if (is_string($args[0]) && count($args) === 1) {
  343. $args = explode(' ', $args[0]);
  344. }
  345. $Dispatcher = new ShellDispatcher($args, false);
  346. return $Dispatcher->dispatch();
  347. }
  348. /**
  349. * Runs the Shell with the provided argv.
  350. *
  351. * Delegates calls to Tasks and resolves methods inside the class. Commands are looked
  352. * up with the following order:
  353. *
  354. * - Method on the shell.
  355. * - Matching task name.
  356. * - `main()` method.
  357. *
  358. * If a shell implements a `main()` method, all missing method calls will be sent to
  359. * `main()` with the original method name in the argv.
  360. *
  361. * @param string $command The command name to run on this shell. If this argument is empty,
  362. * and the shell has a `main()` method, that will be called instead.
  363. * @param array $argv Array of arguments to run the shell with. This array should be missing the shell name.
  364. * @return void
  365. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::runCommand
  366. */
  367. public function runCommand($command, $argv) {
  368. $isTask = $this->hasTask($command);
  369. $isMethod = $this->hasMethod($command);
  370. $isMain = $this->hasMethod('main');
  371. if ($isTask || $isMethod && $command !== 'execute') {
  372. array_shift($argv);
  373. }
  374. $this->OptionParser = $this->getOptionParser();
  375. try {
  376. list($this->params, $this->args) = $this->OptionParser->parse($argv, $command);
  377. } catch (ConsoleException $e) {
  378. $this->out($this->OptionParser->help($command));
  379. return false;
  380. }
  381. if (!empty($this->params['quiet'])) {
  382. $this->_useLogger(false);
  383. }
  384. if (!empty($this->params['plugin'])) {
  385. CakePlugin::load($this->params['plugin']);
  386. }
  387. $this->command = $command;
  388. if (!empty($this->params['help'])) {
  389. return $this->_displayHelp($command);
  390. }
  391. if (($isTask || $isMethod || $isMain) && $command !== 'execute') {
  392. $this->startup();
  393. }
  394. if ($isTask) {
  395. $command = Inflector::camelize($command);
  396. return $this->{$command}->runCommand('execute', $argv);
  397. }
  398. if ($isMethod) {
  399. return $this->{$command}();
  400. }
  401. if ($isMain) {
  402. return $this->main();
  403. }
  404. $this->out($this->OptionParser->help($command));
  405. return false;
  406. }
  407. /**
  408. * Display the help in the correct format
  409. *
  410. * @param string $command The command to get help for.
  411. * @return void
  412. */
  413. protected function _displayHelp($command) {
  414. $format = 'text';
  415. if (!empty($this->args[0]) && $this->args[0] === 'xml') {
  416. $format = 'xml';
  417. $this->stdout->outputAs(ConsoleOutput::RAW);
  418. } else {
  419. $this->_welcome();
  420. }
  421. return $this->out($this->OptionParser->help($command, $format));
  422. }
  423. /**
  424. * Gets the option parser instance and configures it.
  425. *
  426. * By overriding this method you can configure the ConsoleOptionParser before returning it.
  427. *
  428. * @return ConsoleOptionParser
  429. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::getOptionParser
  430. */
  431. public function getOptionParser() {
  432. $name = ($this->plugin ? $this->plugin . '.' : '') . $this->name;
  433. $parser = new ConsoleOptionParser($name);
  434. return $parser;
  435. }
  436. /**
  437. * Overload get for lazy building of tasks
  438. *
  439. * @param string $name The property name to access.
  440. * @return Shell Object of Task
  441. */
  442. public function __get($name) {
  443. if (empty($this->{$name}) && in_array($name, $this->taskNames)) {
  444. $properties = $this->_taskMap[$name];
  445. $this->{$name} = $this->Tasks->load($properties['class'], $properties['settings']);
  446. $this->{$name}->args =& $this->args;
  447. $this->{$name}->params =& $this->params;
  448. $this->{$name}->initialize();
  449. $this->{$name}->loadTasks();
  450. }
  451. return $this->{$name};
  452. }
  453. /**
  454. * Safely access the values in $this->params.
  455. *
  456. * @param string $name The name of the parameter to get.
  457. * @return string|bool|null Value. Will return null if it doesn't exist.
  458. */
  459. public function param($name) {
  460. if (!isset($this->params[$name])) {
  461. return null;
  462. }
  463. return $this->params[$name];
  464. }
  465. /**
  466. * Prompts the user for input, and returns it.
  467. *
  468. * @param string $prompt Prompt text.
  469. * @param string|array $options Array or string of options.
  470. * @param string $default Default input value.
  471. * @return mixed Either the default value, or the user-provided input.
  472. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::in
  473. */
  474. public function in($prompt, $options = null, $default = null) {
  475. if (!$this->interactive) {
  476. return $default;
  477. }
  478. $originalOptions = $options;
  479. $in = $this->_getInput($prompt, $originalOptions, $default);
  480. if ($options && is_string($options)) {
  481. if (strpos($options, ',')) {
  482. $options = explode(',', $options);
  483. } elseif (strpos($options, '/')) {
  484. $options = explode('/', $options);
  485. } else {
  486. $options = array($options);
  487. }
  488. }
  489. if (is_array($options)) {
  490. $options = array_merge(
  491. array_map('strtolower', $options),
  492. array_map('strtoupper', $options),
  493. $options
  494. );
  495. while ($in === '' || !in_array($in, $options)) {
  496. $in = $this->_getInput($prompt, $originalOptions, $default);
  497. }
  498. }
  499. return $in;
  500. }
  501. /**
  502. * Prompts the user for input, and returns it.
  503. *
  504. * @param string $prompt Prompt text.
  505. * @param string|array $options Array or string of options.
  506. * @param string $default Default input value.
  507. * @return Either the default value, or the user-provided input.
  508. */
  509. protected function _getInput($prompt, $options, $default) {
  510. if (!is_array($options)) {
  511. $printOptions = '';
  512. } else {
  513. $printOptions = '(' . implode('/', $options) . ')';
  514. }
  515. if ($default === null) {
  516. $this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . '> ', 0);
  517. } else {
  518. $this->stdout->write('<question>' . $prompt . '</question>' . " $printOptions \n" . "[$default] > ", 0);
  519. }
  520. $result = $this->stdin->read();
  521. if ($result === false) {
  522. return $this->_stop(1);
  523. }
  524. $result = trim($result);
  525. if ($default !== null && ($result === '' || $result === null)) {
  526. return $default;
  527. }
  528. return $result;
  529. }
  530. /**
  531. * Wrap a block of text.
  532. * Allows you to set the width, and indenting on a block of text.
  533. *
  534. * ### Options
  535. *
  536. * - `width` The width to wrap to. Defaults to 72
  537. * - `wordWrap` Only wrap on words breaks (spaces) Defaults to true.
  538. * - `indent` Indent the text with the string provided. Defaults to null.
  539. *
  540. * @param string $text Text the text to format.
  541. * @param string|int|array $options Array of options to use, or an integer to wrap the text to.
  542. * @return string Wrapped / indented text
  543. * @see CakeText::wrap()
  544. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::wrapText
  545. */
  546. public function wrapText($text, $options = array()) {
  547. return CakeText::wrap($text, $options);
  548. }
  549. /**
  550. * Outputs a single or multiple messages to stdout. If no parameters
  551. * are passed outputs just a newline.
  552. *
  553. * ### Output levels
  554. *
  555. * There are 3 built-in output level. Shell::QUIET, Shell::NORMAL, Shell::VERBOSE.
  556. * The verbose and quiet output levels, map to the `verbose` and `quiet` output switches
  557. * present in most shells. Using Shell::QUIET for a message means it will always display.
  558. * While using Shell::VERBOSE means it will only display when verbose output is toggled.
  559. *
  560. * @param string|array $message A string or an array of strings to output
  561. * @param int $newlines Number of newlines to append
  562. * @param int $level The message's output level, see above.
  563. * @return int|bool Returns the number of bytes returned from writing to stdout.
  564. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::out
  565. */
  566. public function out($message = null, $newlines = 1, $level = Shell::NORMAL) {
  567. $currentLevel = Shell::NORMAL;
  568. if (!empty($this->params['verbose'])) {
  569. $currentLevel = Shell::VERBOSE;
  570. }
  571. if (!empty($this->params['quiet'])) {
  572. $currentLevel = Shell::QUIET;
  573. }
  574. if ($level <= $currentLevel) {
  575. $this->_lastWritten = $this->stdout->write($message, $newlines);
  576. return $this->_lastWritten;
  577. }
  578. return true;
  579. }
  580. /**
  581. * Overwrite some already output text.
  582. *
  583. * Useful for building progress bars, or when you want to replace
  584. * text already output to the screen with new text.
  585. *
  586. * **Warning** You cannot overwrite text that contains newlines.
  587. *
  588. * @param array|string $message The message to output.
  589. * @param int $newlines Number of newlines to append.
  590. * @param int $size The number of bytes to overwrite. Defaults to the
  591. * length of the last message output.
  592. * @return int|bool Returns the number of bytes returned from writing to stdout.
  593. */
  594. public function overwrite($message, $newlines = 1, $size = null) {
  595. $size = $size ? $size : $this->_lastWritten;
  596. // Output backspaces.
  597. $this->out(str_repeat("\x08", $size), 0);
  598. $newBytes = $this->out($message, 0);
  599. // Fill any remaining bytes with spaces.
  600. $fill = $size - $newBytes;
  601. if ($fill > 0) {
  602. $this->out(str_repeat(' ', $fill), 0);
  603. }
  604. if ($newlines) {
  605. $this->out($this->nl($newlines), 0);
  606. }
  607. }
  608. /**
  609. * Outputs a single or multiple error messages to stderr. If no parameters
  610. * are passed outputs just a newline.
  611. *
  612. * @param string|array $message A string or an array of strings to output
  613. * @param int $newlines Number of newlines to append
  614. * @return void
  615. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::err
  616. */
  617. public function err($message = null, $newlines = 1) {
  618. $this->stderr->write($message, $newlines);
  619. }
  620. /**
  621. * Returns a single or multiple linefeeds sequences.
  622. *
  623. * @param int $multiplier Number of times the linefeed sequence should be repeated
  624. * @return string
  625. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::nl
  626. */
  627. public function nl($multiplier = 1) {
  628. return str_repeat(ConsoleOutput::LF, $multiplier);
  629. }
  630. /**
  631. * Outputs a series of minus characters to the standard output, acts as a visual separator.
  632. *
  633. * @param int $newlines Number of newlines to pre- and append
  634. * @param int $width Width of the line, defaults to 63
  635. * @return void
  636. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::hr
  637. */
  638. public function hr($newlines = 0, $width = 63) {
  639. $this->out(null, $newlines);
  640. $this->out(str_repeat('-', $width));
  641. $this->out(null, $newlines);
  642. }
  643. /**
  644. * Displays a formatted error message
  645. * and exits the application with status code 1
  646. *
  647. * @param string $title Title of the error
  648. * @param string $message An optional error message
  649. * @return void
  650. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::error
  651. */
  652. public function error($title, $message = null) {
  653. $this->err(__d('cake_console', '<error>Error:</error> %s', $title));
  654. if (!empty($message)) {
  655. $this->err($message);
  656. }
  657. return $this->_stop(1);
  658. }
  659. /**
  660. * Clear the console
  661. *
  662. * @return void
  663. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::clear
  664. */
  665. public function clear() {
  666. if (empty($this->params['noclear'])) {
  667. if (DS === '/') {
  668. passthru('clear');
  669. } else {
  670. passthru('cls');
  671. }
  672. }
  673. }
  674. /**
  675. * Creates a file at given path
  676. *
  677. * @param string $path Where to put the file.
  678. * @param string $contents Content to put in the file.
  679. * @return bool Success
  680. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::createFile
  681. */
  682. public function createFile($path, $contents) {
  683. $path = str_replace(DS . DS, DS, $path);
  684. $this->out();
  685. if (is_file($path) && empty($this->params['force']) && $this->interactive === true) {
  686. $this->out(__d('cake_console', '<warning>File `%s` exists</warning>', $path));
  687. $key = $this->in(__d('cake_console', 'Do you want to overwrite?'), array('y', 'n', 'q'), 'n');
  688. if (strtolower($key) === 'q') {
  689. $this->out(__d('cake_console', '<error>Quitting</error>.'), 2);
  690. return $this->_stop();
  691. } elseif (strtolower($key) !== 'y') {
  692. $this->out(__d('cake_console', 'Skip `%s`', $path), 2);
  693. return false;
  694. }
  695. } else {
  696. $this->out(__d('cake_console', 'Creating file %s', $path));
  697. }
  698. $File = new File($path, true);
  699. if ($File->exists() && $File->writable()) {
  700. $data = $File->prepare($contents);
  701. $File->write($data);
  702. $this->out(__d('cake_console', '<success>Wrote</success> `%s`', $path));
  703. return true;
  704. }
  705. $this->err(__d('cake_console', '<error>Could not write to `%s`</error>.', $path), 2);
  706. return false;
  707. }
  708. /**
  709. * Action to create a Unit Test
  710. *
  711. * @return bool Success
  712. */
  713. protected function _checkUnitTest() {
  714. if (class_exists('PHPUnit_Framework_TestCase')) {
  715. return true;
  716. //@codingStandardsIgnoreStart
  717. } elseif (@include 'PHPUnit' . DS . 'Autoload.php') {
  718. //@codingStandardsIgnoreEnd
  719. return true;
  720. } elseif (App::import('Vendor', 'phpunit', array('file' => 'PHPUnit' . DS . 'Autoload.php'))) {
  721. return true;
  722. }
  723. $prompt = __d('cake_console', 'PHPUnit is not installed. Do you want to bake unit test files anyway?');
  724. $unitTest = $this->in($prompt, array('y', 'n'), 'y');
  725. $result = strtolower($unitTest) === 'y' || strtolower($unitTest) === 'yes';
  726. if ($result) {
  727. $this->out();
  728. $this->out(__d('cake_console', 'You can download PHPUnit from %s', 'http://phpunit.de'));
  729. }
  730. return $result;
  731. }
  732. /**
  733. * Makes absolute file path easier to read
  734. *
  735. * @param string $file Absolute file path
  736. * @return string short path
  737. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::shortPath
  738. */
  739. public function shortPath($file) {
  740. $shortPath = str_replace(ROOT, null, $file);
  741. $shortPath = str_replace('..' . DS, '', $shortPath);
  742. return str_replace(DS . DS, DS, $shortPath);
  743. }
  744. /**
  745. * Creates the proper controller path for the specified controller class name
  746. *
  747. * @param string $name Controller class name
  748. * @return string Path to controller
  749. */
  750. protected function _controllerPath($name) {
  751. return Inflector::underscore($name);
  752. }
  753. /**
  754. * Creates the proper controller plural name for the specified controller class name
  755. *
  756. * @param string $name Controller class name
  757. * @return string Controller plural name
  758. */
  759. protected function _controllerName($name) {
  760. return Inflector::pluralize(Inflector::camelize($name));
  761. }
  762. /**
  763. * Creates the proper model camelized name (singularized) for the specified name
  764. *
  765. * @param string $name Name
  766. * @return string Camelized and singularized model name
  767. */
  768. protected function _modelName($name) {
  769. return Inflector::camelize(Inflector::singularize($name));
  770. }
  771. /**
  772. * Creates the proper underscored model key for associations
  773. *
  774. * @param string $name Model class name
  775. * @return string Singular model key
  776. */
  777. protected function _modelKey($name) {
  778. return Inflector::underscore($name) . '_id';
  779. }
  780. /**
  781. * Creates the proper model name from a foreign key
  782. *
  783. * @param string $key Foreign key
  784. * @return string Model name
  785. */
  786. protected function _modelNameFromKey($key) {
  787. return Inflector::camelize(str_replace('_id', '', $key));
  788. }
  789. /**
  790. * creates the singular name for use in views.
  791. *
  792. * @param string $name The plural underscored value.
  793. * @return string name
  794. */
  795. protected function _singularName($name) {
  796. return Inflector::variable(Inflector::singularize($name));
  797. }
  798. /**
  799. * Creates the plural name for views
  800. *
  801. * @param string $name Name to use
  802. * @return string Plural name for views
  803. */
  804. protected function _pluralName($name) {
  805. return Inflector::variable(Inflector::pluralize($name));
  806. }
  807. /**
  808. * Creates the singular human name used in views
  809. *
  810. * @param string $name Controller name
  811. * @return string Singular human name
  812. */
  813. protected function _singularHumanName($name) {
  814. return Inflector::humanize(Inflector::underscore(Inflector::singularize($name)));
  815. }
  816. /**
  817. * Creates the plural human name used in views
  818. *
  819. * @param string $name Controller name
  820. * @return string Plural human name
  821. */
  822. protected function _pluralHumanName($name) {
  823. return Inflector::humanize(Inflector::underscore($name));
  824. }
  825. /**
  826. * Find the correct path for a plugin. Scans $pluginPaths for the plugin you want.
  827. *
  828. * @param string $pluginName Name of the plugin you want ie. DebugKit
  829. * @return string path path to the correct plugin.
  830. */
  831. protected function _pluginPath($pluginName) {
  832. if (CakePlugin::loaded($pluginName)) {
  833. return CakePlugin::path($pluginName);
  834. }
  835. return current(App::path('plugins')) . $pluginName . DS;
  836. }
  837. /**
  838. * Used to enable or disable logging stream output to stdout and stderr
  839. * If you don't wish to see in your stdout or stderr everything that is logged
  840. * through CakeLog, call this function with first param as false
  841. *
  842. * @param bool $enable whether to enable CakeLog output or not
  843. * @return void
  844. */
  845. protected function _useLogger($enable = true) {
  846. if (!$enable) {
  847. CakeLog::drop('stdout');
  848. CakeLog::drop('stderr');
  849. return;
  850. }
  851. CakeLog::config('stdout', array(
  852. 'engine' => 'Console',
  853. 'types' => array('notice', 'info'),
  854. 'stream' => $this->stdout,
  855. ));
  856. CakeLog::config('stderr', array(
  857. 'engine' => 'Console',
  858. 'types' => array('emergency', 'alert', 'critical', 'error', 'warning', 'debug'),
  859. 'stream' => $this->stderr,
  860. ));
  861. }
  862. }