PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Cake/Console/Command/ConsoleShell.php

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