PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/cake/console/libs/console.php

https://github.com/fektor/cakephp
PHP | 361 lines | 279 code | 16 blank | 66 comment | 14 complexity | 90b6bab580d458ca3642017a0e81b8be MD5 | raw file
  1. <?php
  2. /**
  3. * CakePHP Console Shell
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @package cake
  16. * @subpackage cake.cake.console.libs
  17. * @since CakePHP(tm) v 1.2.0.5012
  18. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  19. */
  20. /**
  21. * @package cake
  22. * @subpackage cake.cake.console.libs
  23. */
  24. class ConsoleShell extends Shell {
  25. /**
  26. * Available binding types
  27. *
  28. * @var array
  29. * @access public
  30. */
  31. var $associations = array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany');
  32. /**
  33. * Chars that describe invalid commands
  34. *
  35. * @var array
  36. * @access public
  37. */
  38. var $badCommandChars = array('$', ';');
  39. /**
  40. * Available models
  41. *
  42. * @var array
  43. * @access public
  44. */
  45. var $models = array();
  46. /**
  47. * Override intialize of the Shell
  48. *
  49. * @access public
  50. */
  51. function initialize() {
  52. require_once CAKE . 'dispatcher.php';
  53. $this->Dispatcher = new Dispatcher();
  54. $this->models = App::objects('model');
  55. App::import('Model', $this->models);
  56. foreach ($this->models as $model) {
  57. $class = Inflector::camelize(str_replace('.php', '', $model));
  58. $this->models[$model] = $class;
  59. $this->{$class} =& new $class();
  60. }
  61. $this->out('Model classes:');
  62. $this->out('--------------');
  63. foreach ($this->models as $model) {
  64. $this->out(" - {$model}");
  65. }
  66. $this->_loadRoutes();
  67. }
  68. /**
  69. * Prints the help message
  70. *
  71. * @access public
  72. */
  73. function help() {
  74. $out = 'Console help:';
  75. $out .= '-------------';
  76. $out .= 'The interactive console is a tool for testing parts of your app before you';
  77. $out .= 'write code.';
  78. $out .= "\n";
  79. $out .= 'Model testing:';
  80. $out .= 'To test model results, use the name of your model without a leading $';
  81. $out .= 'e.g. Foo->find("all")';
  82. $out .= "\n";
  83. $out .= 'To dynamically set associations, you can do the following:';
  84. $out .= "\tModelA bind <association> ModelB";
  85. $out .= "where the supported assocations are hasOne, hasMany, belongsTo, hasAndBelongsToMany";
  86. $out .= "\n";
  87. $out .= 'To dynamically remove associations, you can do the following:';
  88. $out .= "\t ModelA unbind <association> ModelB";
  89. $out .= "where the supported associations are the same as above";
  90. $out .= "\n";
  91. $out .= "To save a new field in a model, you can do the following:";
  92. $out .= "\tModelA->save(array('foo' => 'bar', 'baz' => 0))";
  93. $out .= "where you are passing a hash of data to be saved in the format";
  94. $out .= "of field => value pairs";
  95. $out .= "\n";
  96. $out .= "To get column information for a model, use the following:";
  97. $out .= "\tModelA columns";
  98. $out .= "which returns a list of columns and their type";
  99. $out .= "\n";
  100. $out .= "\n";
  101. $out .= 'Route testing:';
  102. $out .= "\n";
  103. $out .= 'To test URLs against your app\'s route configuration, type:';
  104. $out .= "\n";
  105. $out .= "\tRoute <url>";
  106. $out .= "\n";
  107. $out .= "where url is the path to your your action plus any query parameters,";
  108. $out .= "minus the application's base path. For example:";
  109. $out .= "\n";
  110. $out .= "\tRoute /posts/view/1";
  111. $out .= "\n";
  112. $out .= "will return something like the following:";
  113. $out .= "\n";
  114. $out .= "\tarray (";
  115. $out .= "\t [...]";
  116. $out .= "\t 'controller' => 'posts',";
  117. $out .= "\t 'action' => 'view',";
  118. $out .= "\t [...]";
  119. $out .= "\t)";
  120. $out .= "\n";
  121. $out .= 'Alternatively, you can use simple array syntax to test reverse';
  122. $out .= 'To reload your routes config (config/routes.php), do the following:';
  123. $out .= "\n";
  124. $out .= "\tRoutes reload";
  125. $out .= "\n";
  126. $out .= 'To show all connected routes, do the following:';
  127. $out .= "\tRoutes show";
  128. $this->out($out);
  129. }
  130. /**
  131. * Override main() to handle action
  132. *
  133. * @access public
  134. */
  135. function main($command = null) {
  136. while (true) {
  137. if (empty($command)) {
  138. $command = trim($this->in(''));
  139. }
  140. switch ($command) {
  141. case 'help':
  142. $this->help();
  143. break;
  144. case 'quit':
  145. case 'exit':
  146. return true;
  147. break;
  148. case 'models':
  149. $this->out('Model classes:');
  150. $this->hr();
  151. foreach ($this->models as $model) {
  152. $this->out(" - {$model}");
  153. }
  154. break;
  155. case (preg_match("/^(\w+) bind (\w+) (\w+)/", $command, $tmp) == true):
  156. foreach ($tmp as $data) {
  157. $data = strip_tags($data);
  158. $data = str_replace($this->badCommandChars, "", $data);
  159. }
  160. $modelA = $tmp[1];
  161. $association = $tmp[2];
  162. $modelB = $tmp[3];
  163. if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations)) {
  164. $this->{$modelA}->bindModel(array($association => array($modelB => array('className' => $modelB))), false);
  165. $this->out("Created $association association between $modelA and $modelB");
  166. } else {
  167. $this->out("Please verify you are using valid models and association types");
  168. }
  169. break;
  170. case (preg_match("/^(\w+) unbind (\w+) (\w+)/", $command, $tmp) == true):
  171. foreach ($tmp as $data) {
  172. $data = strip_tags($data);
  173. $data = str_replace($this->badCommandChars, "", $data);
  174. }
  175. $modelA = $tmp[1];
  176. $association = $tmp[2];
  177. $modelB = $tmp[3];
  178. // Verify that there is actually an association to unbind
  179. $currentAssociations = $this->{$modelA}->getAssociated();
  180. $validCurrentAssociation = false;
  181. foreach ($currentAssociations as $model => $currentAssociation) {
  182. if ($model == $modelB && $association == $currentAssociation) {
  183. $validCurrentAssociation = true;
  184. }
  185. }
  186. if ($this->_isValidModel($modelA) && $this->_isValidModel($modelB) && in_array($association, $this->associations) && $validCurrentAssociation) {
  187. $this->{$modelA}->unbindModel(array($association => array($modelB)));
  188. $this->out("Removed $association association between $modelA and $modelB");
  189. } else {
  190. $this->out("Please verify you are using valid models, valid current association, and valid association types");
  191. }
  192. break;
  193. case (strpos($command, "->find") > 0):
  194. // Remove any bad info
  195. $command = strip_tags($command);
  196. $command = str_replace($this->badCommandChars, "", $command);
  197. // Do we have a valid model?
  198. list($modelToCheck, $tmp) = explode('->', $command);
  199. if ($this->_isValidModel($modelToCheck)) {
  200. $findCommand = "\$data = \$this->$command;";
  201. @eval($findCommand);
  202. if (is_array($data)) {
  203. foreach ($data as $idx => $results) {
  204. if (is_numeric($idx)) { // findAll() output
  205. foreach ($results as $modelName => $result) {
  206. $this->out("$modelName");
  207. foreach ($result as $field => $value) {
  208. if (is_array($value)) {
  209. foreach ($value as $field2 => $value2) {
  210. $this->out("\t$field2: $value2");
  211. }
  212. $this->out();
  213. } else {
  214. $this->out("\t$field: $value");
  215. }
  216. }
  217. }
  218. } else { // find() output
  219. $this->out($idx);
  220. foreach ($results as $field => $value) {
  221. if (is_array($value)) {
  222. foreach ($value as $field2 => $value2) {
  223. $this->out("\t$field2: $value2");
  224. }
  225. $this->out();
  226. } else {
  227. $this->out("\t$field: $value");
  228. }
  229. }
  230. }
  231. }
  232. } else {
  233. $this->out("\nNo result set found");
  234. }
  235. } else {
  236. $this->out("$modelToCheck is not a valid model");
  237. }
  238. break;
  239. case (strpos($command, '->save') > 0):
  240. // Validate the model we're trying to save here
  241. $command = strip_tags($command);
  242. $command = str_replace($this->badCommandChars, "", $command);
  243. list($modelToSave, $tmp) = explode("->", $command);
  244. if ($this->_isValidModel($modelToSave)) {
  245. // Extract the array of data we are trying to build
  246. list($foo, $data) = explode("->save", $command);
  247. $data = preg_replace('/^\(*(array)?\(*(.+?)\)*$/i', '\\2', $data);
  248. $saveCommand = "\$this->{$modelToSave}->save(array('{$modelToSave}' => array({$data})));";
  249. @eval($saveCommand);
  250. $this->out('Saved record for ' . $modelToSave);
  251. }
  252. break;
  253. case (preg_match("/^(\w+) columns/", $command, $tmp) == true):
  254. $modelToCheck = strip_tags(str_replace($this->badCommandChars, "", $tmp[1]));
  255. if ($this->_isValidModel($modelToCheck)) {
  256. // Get the column info for this model
  257. $fieldsCommand = "\$data = \$this->{$modelToCheck}->getColumnTypes();";
  258. @eval($fieldsCommand);
  259. if (is_array($data)) {
  260. foreach ($data as $field => $type) {
  261. $this->out("\t{$field}: {$type}");
  262. }
  263. }
  264. } else {
  265. $this->out("Please verify that you selected a valid model");
  266. }
  267. break;
  268. case (preg_match("/^routes\s+reload/i", $command, $tmp) == true):
  269. $router =& Router::getInstance();
  270. if (!$this->_loadRoutes()) {
  271. $this->out("There was an error loading the routes config. Please check that the file");
  272. $this->out("exists and is free of parse errors.");
  273. break;
  274. }
  275. $this->out("Routes configuration reloaded, " . count($router->routes) . " routes connected");
  276. break;
  277. case (preg_match("/^routes\s+show/i", $command, $tmp) == true):
  278. $router =& Router::getInstance();
  279. $this->out(implode("\n", Set::extract($router->routes, '{n}.0')));
  280. break;
  281. case (preg_match("/^route\s+(\(.*\))$/i", $command, $tmp) == true):
  282. if ($url = eval('return array' . $tmp[1] . ';')) {
  283. $this->out(Router::url($url));
  284. }
  285. break;
  286. case (preg_match("/^route\s+(.*)/i", $command, $tmp) == true):
  287. $this->out(var_export(Router::parse($tmp[1]), true));
  288. break;
  289. default:
  290. $this->out("Invalid command\n");
  291. break;
  292. }
  293. $command = '';
  294. }
  295. }
  296. /**
  297. * Tells if the specified model is included in the list of available models
  298. *
  299. * @param string $modelToCheck
  300. * @return boolean true if is an available model, false otherwise
  301. * @access protected
  302. */
  303. function _isValidModel($modelToCheck) {
  304. return in_array($modelToCheck, $this->models);
  305. }
  306. /**
  307. * Reloads the routes configuration from config/routes.php, and compiles
  308. * all routes found
  309. *
  310. * @return boolean True if config reload was a success, otherwise false
  311. * @access protected
  312. */
  313. function _loadRoutes() {
  314. $router =& Router::getInstance();
  315. $router->reload();
  316. extract($router->getNamedExpressions());
  317. if (!@include(CONFIGS . 'routes.php')) {
  318. return false;
  319. }
  320. $router->parse('/');
  321. foreach (array_keys($router->getNamedExpressions()) as $var) {
  322. unset(${$var});
  323. }
  324. for ($i = 0, $len = count($router->routes); $i < $len; $i++) {
  325. $router->routes[$i]->compile();
  326. }
  327. return true;
  328. }
  329. }