PageRenderTime 43ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/cake/console/libs/shell.php

https://github.com/mariuz/firetube
PHP | 610 lines | 302 code | 17 blank | 291 comment | 80 complexity | 0f8a764a10167b64270b5da23cec438a MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * Base class for Shells
  5. *
  6. * Long description for file
  7. *
  8. * PHP versions 4 and 5
  9. *
  10. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  11. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  12. *
  13. * Licensed under The MIT License
  14. * Redistributions of files must retain the above copyright notice.
  15. *
  16. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  17. * @link http://cakephp.org CakePHP(tm) Project
  18. * @package cake
  19. * @subpackage cake.cake.console.libs
  20. * @since CakePHP(tm) v 1.2.0.5012
  21. * @version $Revision$
  22. * @modifiedby $LastChangedBy$
  23. * @lastmodified $Date$
  24. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  25. */
  26. /**
  27. * Base class for command-line utilities for automating programmer chores.
  28. *
  29. * @package cake
  30. * @subpackage cake.cake.console.libs
  31. */
  32. class Shell extends Object {
  33. /**
  34. * An instance of the ShellDispatcher object that loaded this script
  35. *
  36. * @var ShellDispatcher
  37. * @access public
  38. */
  39. var $Dispatch = null;
  40. /**
  41. * If true, the script will ask for permission to perform actions.
  42. *
  43. * @var boolean
  44. * @access public
  45. */
  46. var $interactive = true;
  47. /**
  48. * Holds the DATABASE_CONFIG object for the app. Null if database.php could not be found,
  49. * or the app does not exist.
  50. *
  51. * @var DATABASE_CONFIG
  52. * @access public
  53. */
  54. var $DbConfig = null;
  55. /**
  56. * Contains command switches parsed from the command line.
  57. *
  58. * @var array
  59. * @access public
  60. */
  61. var $params = array();
  62. /**
  63. * Contains arguments parsed from the command line.
  64. *
  65. * @var array
  66. * @access public
  67. */
  68. var $args = array();
  69. /**
  70. * The file name of the shell that was invoked.
  71. *
  72. * @var string
  73. * @access public
  74. */
  75. var $shell = null;
  76. /**
  77. * The class name of the shell that was invoked.
  78. *
  79. * @var string
  80. * @access public
  81. */
  82. var $className = null;
  83. /**
  84. * The command called if public methods are available.
  85. *
  86. * @var string
  87. * @access public
  88. */
  89. var $command = null;
  90. /**
  91. * The name of the shell in camelized.
  92. *
  93. * @var string
  94. * @access public
  95. */
  96. var $name = null;
  97. /**
  98. * An alias for the shell
  99. *
  100. * @var string
  101. * @access public
  102. */
  103. var $alias = null;
  104. /**
  105. * Contains tasks to load and instantiate
  106. *
  107. * @var array
  108. * @access public
  109. */
  110. var $tasks = array();
  111. /**
  112. * Contains the loaded tasks
  113. *
  114. * @var array
  115. * @access public
  116. */
  117. var $taskNames = array();
  118. /**
  119. * Contains models to load and instantiate
  120. *
  121. * @var array
  122. * @access public
  123. */
  124. var $uses = array();
  125. /**
  126. * Constructs this Shell instance.
  127. *
  128. */
  129. function __construct(&$dispatch) {
  130. $vars = array('params', 'args', 'shell', 'shellCommand' => 'command');
  131. foreach ($vars as $key => $var) {
  132. if (is_string($key)) {
  133. $this->{$var} =& $dispatch->{$key};
  134. } else {
  135. $this->{$var} =& $dispatch->{$var};
  136. }
  137. }
  138. if ($this->name == null) {
  139. $this->name = get_class($this);
  140. }
  141. if ($this->alias == null) {
  142. $this->alias = $this->name;
  143. }
  144. ClassRegistry::addObject($this->name, $this);
  145. ClassRegistry::map($this->name, $this->alias);
  146. if (!PHP5 && isset($this->args[0])) {
  147. if (strpos($this->name, strtolower(Inflector::camelize($this->args[0]))) !== false) {
  148. $dispatch->shiftArgs();
  149. }
  150. if (strtolower($this->command) == strtolower(Inflector::variable($this->args[0])) && method_exists($this, $this->command)) {
  151. $dispatch->shiftArgs();
  152. }
  153. }
  154. $this->Dispatch =& $dispatch;
  155. }
  156. /**
  157. * Initializes the Shell
  158. * acts as constructor for subclasses
  159. * allows configuration of tasks prior to shell execution
  160. *
  161. * @access public
  162. */
  163. function initialize() {
  164. $this->_loadModels();
  165. }
  166. /**
  167. * Starts up the the Shell
  168. * allows for checking and configuring prior to command or main execution
  169. * can be overriden in subclasses
  170. *
  171. * @access public
  172. */
  173. function startup() {
  174. $this->_welcome();
  175. }
  176. /**
  177. * Displays a header for the shell
  178. *
  179. * @access protected
  180. */
  181. function _welcome() {
  182. $this->out("\nWelcome to CakePHP v" . Configure::version() . " Console");
  183. $this->out("---------------------------------------------------------------");
  184. $this->out('App : '. $this->params['app']);
  185. $this->out('Path: '. $this->params['working']);
  186. $this->hr();
  187. }
  188. /**
  189. * Loads database file and constructs DATABASE_CONFIG class
  190. * makes $this->DbConfig available to subclasses
  191. *
  192. * @return bool
  193. * @access protected
  194. */
  195. function _loadDbConfig() {
  196. if (config('database') && class_exists('DATABASE_CONFIG')) {
  197. $this->DbConfig =& new DATABASE_CONFIG();
  198. return true;
  199. }
  200. $this->err('Database config could not be loaded');
  201. $this->out('Run \'bake\' to create the database configuration');
  202. return false;
  203. }
  204. /**
  205. * if var $uses = true
  206. * Loads AppModel file and constructs AppModel class
  207. * makes $this->AppModel available to subclasses
  208. * if var $uses is an array of models will load those models
  209. *
  210. * @return bool
  211. * @access protected
  212. */
  213. function _loadModels() {
  214. if ($this->uses === null || $this->uses === false) {
  215. return;
  216. }
  217. if ($this->uses === true && App::import('Model', 'AppModel')) {
  218. $this->AppModel =& new AppModel(false, false, false);
  219. return true;
  220. }
  221. if ($this->uses !== true && !empty($this->uses)) {
  222. $uses = is_array($this->uses) ? $this->uses : array($this->uses);
  223. $modelClassName = $uses[0];
  224. if (strpos($uses[0], '.') !== false) {
  225. list($plugin, $modelClassName) = explode('.', $uses[0]);
  226. }
  227. $this->modelClass = $modelClassName;
  228. foreach ($uses as $modelClass) {
  229. $plugin = null;
  230. if (strpos($modelClass, '.') !== false) {
  231. list($plugin, $modelClass) = explode('.', $modelClass);
  232. $plugin = $plugin . '.';
  233. }
  234. if (PHP5) {
  235. $this->{$modelClass} = ClassRegistry::init($plugin . $modelClass);
  236. } else {
  237. $this->{$modelClass} =& ClassRegistry::init($plugin . $modelClass);
  238. }
  239. }
  240. return true;
  241. }
  242. return false;
  243. }
  244. /**
  245. * Loads tasks defined in var $tasks
  246. *
  247. * @return bool
  248. * @access public
  249. */
  250. function loadTasks() {
  251. if ($this->tasks === null || $this->tasks === false || $this->tasks === true || empty($this->tasks)) {
  252. return true;
  253. }
  254. $tasks = $this->tasks;
  255. if (!is_array($tasks)) {
  256. $tasks = array($tasks);
  257. }
  258. foreach ($tasks as $taskName) {
  259. $task = Inflector::underscore($taskName);
  260. $taskClass = Inflector::camelize($taskName . 'Task');
  261. if (!class_exists($taskClass)) {
  262. foreach ($this->Dispatch->shellPaths as $path) {
  263. $taskPath = $path . 'tasks' . DS . $task.'.php';
  264. if (file_exists($taskPath)) {
  265. require_once $taskPath;
  266. break;
  267. }
  268. }
  269. }
  270. if (ClassRegistry::isKeySet($taskClass)) {
  271. $this->taskNames[] = $taskName;
  272. if (!PHP5) {
  273. $this->{$taskName} =& ClassRegistry::getObject($taskClass);
  274. } else {
  275. $this->{$taskName} = ClassRegistry::getObject($taskClass);
  276. }
  277. } else {
  278. $this->taskNames[] = $taskName;
  279. if (!PHP5) {
  280. $this->{$taskName} =& new $taskClass($this->Dispatch);
  281. } else {
  282. $this->{$taskName} = new $taskClass($this->Dispatch);
  283. }
  284. }
  285. if (!isset($this->{$taskName})) {
  286. $this->err("Task '" . $taskName . "' could not be loaded");
  287. $this->_stop();
  288. }
  289. }
  290. return true;
  291. }
  292. /**
  293. * Prompts the user for input, and returns it.
  294. *
  295. * @param string $prompt Prompt text.
  296. * @param mixed $options Array or string of options.
  297. * @param string $default Default input value.
  298. * @return Either the default value, or the user-provided input.
  299. * @access public
  300. */
  301. function in($prompt, $options = null, $default = null) {
  302. if (!$this->interactive) {
  303. return $default;
  304. }
  305. $in = $this->Dispatch->getInput($prompt, $options, $default);
  306. if ($options && is_string($options)) {
  307. if (strpos($options, ',')) {
  308. $options = explode(',', $options);
  309. } elseif (strpos($options, '/')) {
  310. $options = explode('/', $options);
  311. } else {
  312. $options = array($options);
  313. }
  314. }
  315. if (is_array($options)) {
  316. while ($in == '' || ($in && (!in_array(strtolower($in), $options) && !in_array(strtoupper($in), $options)) && !in_array($in, $options))) {
  317. $in = $this->Dispatch->getInput($prompt, $options, $default);
  318. }
  319. }
  320. if ($in) {
  321. return $in;
  322. }
  323. }
  324. /**
  325. * Outputs to the stdout filehandle.
  326. *
  327. * @param string $string String to output.
  328. * @param boolean $newline If true, the outputs gets an added newline.
  329. * @access public
  330. */
  331. function out($string, $newline = true) {
  332. if (is_array($string)) {
  333. $string = implode("\n", $string) . "\n";
  334. }
  335. return $this->Dispatch->stdout($string, $newline);
  336. }
  337. /**
  338. * Outputs to the stderr filehandle.
  339. *
  340. * @param string $string Error text to output.
  341. * @access public
  342. */
  343. function err($string) {
  344. if (is_array($string)) {
  345. $str = '';
  346. foreach ($string as $message) {
  347. $str .= $message ."\n";
  348. }
  349. $string = $str;
  350. }
  351. return $this->Dispatch->stderr($string."\n");
  352. }
  353. /**
  354. * Outputs a series of minus characters to the standard output, acts as a visual separator.
  355. *
  356. * @param boolean $newline If true, the outputs gets an added newline.
  357. * @access public
  358. */
  359. function hr($newline = false) {
  360. if ($newline) {
  361. $this->out("\n");
  362. }
  363. $this->out('---------------------------------------------------------------');
  364. if ($newline) {
  365. $this->out("\n");
  366. }
  367. }
  368. /**
  369. * Displays a formatted error message and exits the application
  370. *
  371. * @param string $title Title of the error message
  372. * @param string $msg Error message
  373. * @access public
  374. */
  375. function error($title, $msg) {
  376. $out = "$title\n";
  377. $out .= "$msg\n";
  378. $out .= "\n";
  379. $this->err($out);
  380. $this->_stop();
  381. }
  382. /**
  383. * Will check the number args matches otherwise throw an error
  384. *
  385. * @param integer $expectedNum Expected number of paramters
  386. * @param string $command Command
  387. * @access protected
  388. */
  389. function _checkArgs($expectedNum, $command = null) {
  390. if (!$command) {
  391. $command = $this->command;
  392. }
  393. if (count($this->args) < $expectedNum) {
  394. $this->error("Wrong number of parameters: ".count($this->args), "Expected: {$expectedNum}\nPlease type 'cake {$this->shell} help' for help on usage of the {$this->name} {$command}");
  395. }
  396. }
  397. /**
  398. * Creates a file at given path
  399. *
  400. * @param string $path Where to put the file.
  401. * @param string $contents Content to put in the file.
  402. * @return boolean Success
  403. * @access public
  404. */
  405. function createFile ($path, $contents) {
  406. $path = str_replace(DS . DS, DS, $path);
  407. $this->out("\n" . sprintf(__("Creating file %s", true), $path));
  408. if (is_file($path) && $this->interactive === true) {
  409. $key = $this->in(__("File exists, overwrite?", true). " {$path}", array('y', 'n', 'q'), 'n');
  410. if (strtolower($key) == 'q') {
  411. $this->out(__("Quitting.", true) ."\n");
  412. exit;
  413. } elseif (strtolower($key) != 'y') {
  414. $this->out(__("Skip", true) ." {$path}\n");
  415. return false;
  416. }
  417. }
  418. if (!class_exists('File')) {
  419. uses('file');
  420. }
  421. if ($File = new File($path, true)) {
  422. $data = $File->prepare($contents);
  423. $File->write($data);
  424. $this->out(__("Wrote", true) ." {$path}");
  425. return true;
  426. } else {
  427. $this->err(__("Error! Could not write to", true)." {$path}.\n");
  428. return false;
  429. }
  430. }
  431. /**
  432. * Outputs usage text on the standard output. Implement it in subclasses.
  433. *
  434. * @access public
  435. */
  436. function help() {
  437. if ($this->command != null) {
  438. $this->err("Unknown {$this->name} command '$this->command'.\nFor usage, try 'cake {$this->shell} help'.\n\n");
  439. } else {
  440. $this->Dispatch->help();
  441. }
  442. }
  443. /**
  444. * Action to create a Unit Test
  445. *
  446. * @return boolean Success
  447. * @access protected
  448. */
  449. function _checkUnitTest() {
  450. if (App::import('vendor', 'simpletest' . DS . 'simpletest')) {
  451. return true;
  452. }
  453. $unitTest = $this->in('SimpleTest is not installed. Do you want to bake unit test files anyway?', array('y','n'), 'y');
  454. $result = strtolower($unitTest) == 'y' || strtolower($unitTest) == 'yes';
  455. if ($result) {
  456. $this->out("\nYou can download SimpleTest from http://simpletest.org", true);
  457. }
  458. return $result;
  459. }
  460. /**
  461. * Makes absolute file path easier to read
  462. *
  463. * @param string $file Absolute file path
  464. * @return sting short path
  465. * @access public
  466. */
  467. function shortPath($file) {
  468. $shortPath = str_replace(ROOT, null, $file);
  469. $shortPath = str_replace('..' . DS, '', $shortPath);
  470. return str_replace(DS . DS, DS, $shortPath);
  471. }
  472. /**
  473. * Checks for Configure::read('Routing.admin') and forces user to input it if not enabled
  474. *
  475. * @return string Admin route to use
  476. * @access public
  477. */
  478. function getAdmin() {
  479. $admin = '';
  480. $cakeAdmin = null;
  481. $adminRoute = Configure::read('Routing.admin');
  482. if (!empty($adminRoute)) {
  483. $cakeAdmin = $adminRoute . '_';
  484. } else {
  485. $this->out('You need to enable Configure::write(\'Routing.admin\',\'admin\') in /app/config/core.php to use admin routing.');
  486. $this->out('What would you like the admin route to be?');
  487. $this->out('Example: www.example.com/admin/controller');
  488. while ($admin == '') {
  489. $admin = $this->in("What would you like the admin route to be?", null, 'admin');
  490. }
  491. if ($this->Project->cakeAdmin($admin) !== true) {
  492. $this->out('Unable to write to /app/config/core.php.');
  493. $this->out('You need to enable Configure::write(\'Routing.admin\',\'admin\') in /app/config/core.php to use admin routing.');
  494. $this->_stop();
  495. } else {
  496. $cakeAdmin = $admin . '_';
  497. }
  498. }
  499. return $cakeAdmin;
  500. }
  501. /**
  502. * Creates the proper controller path for the specified controller class name
  503. *
  504. * @param string $name Controller class name
  505. * @return string Path to controller
  506. * @access protected
  507. */
  508. function _controllerPath($name) {
  509. return strtolower(Inflector::underscore($name));
  510. }
  511. /**
  512. * Creates the proper controller plural name for the specified controller class name
  513. *
  514. * @param string $name Controller class name
  515. * @return string Controller plural name
  516. * @access protected
  517. */
  518. function _controllerName($name) {
  519. return Inflector::pluralize(Inflector::camelize($name));
  520. }
  521. /**
  522. * Creates the proper controller camelized name (singularized) for the specified name
  523. *
  524. * @param string $name Name
  525. * @return string Camelized and singularized controller name
  526. * @access protected
  527. */
  528. function _modelName($name) {
  529. return Inflector::camelize(Inflector::singularize($name));
  530. }
  531. /**
  532. * Creates the proper singular model key for associations
  533. *
  534. * @param string $name Controller class name
  535. * @return string Singular model key
  536. * @access protected
  537. */
  538. function _modelKey($name) {
  539. return Inflector::underscore(Inflector::singularize($name)).'_id';
  540. }
  541. /**
  542. * Creates the proper model name from a foreign key
  543. *
  544. * @param string $key Foreign key
  545. * @return string Model name
  546. * @access protected
  547. */
  548. function _modelNameFromKey($key) {
  549. $name = str_replace('_id', '',$key);
  550. return Inflector::camelize($name);
  551. }
  552. /**
  553. * creates the singular name for use in views.
  554. *
  555. * @param string $name
  556. * @return string $name
  557. * @access protected
  558. */
  559. function _singularName($name) {
  560. return Inflector::variable(Inflector::singularize($name));
  561. }
  562. /**
  563. * Creates the plural name for views
  564. *
  565. * @param string $name Name to use
  566. * @return string Plural name for views
  567. * @access protected
  568. */
  569. function _pluralName($name) {
  570. return Inflector::variable(Inflector::pluralize($name));
  571. }
  572. /**
  573. * Creates the singular human name used in views
  574. *
  575. * @param string $name Controller name
  576. * @return string Singular human name
  577. * @access protected
  578. */
  579. function _singularHumanName($name) {
  580. return Inflector::humanize(Inflector::underscore(Inflector::singularize($name)));
  581. }
  582. /**
  583. * Creates the plural human name used in views
  584. *
  585. * @param string $name Controller name
  586. * @return string Plural human name
  587. * @access protected
  588. */
  589. function _pluralHumanName($name) {
  590. return Inflector::humanize(Inflector::underscore(Inflector::pluralize($name)));
  591. }
  592. }
  593. ?>