1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
20:
21: 22: 23: 24: 25: 26:
27: class Shell extends Object {
28:
29: 30: 31: 32: 33: 34:
35: var $Dispatch = null;
36:
37: 38: 39: 40: 41: 42:
43: var $interactive = true;
44:
45: 46: 47: 48: 49: 50: 51:
52: var $DbConfig = null;
53:
54: 55: 56: 57: 58: 59:
60: var $params = array();
61:
62: 63: 64: 65: 66: 67:
68: var $args = array();
69:
70: 71: 72: 73: 74: 75:
76: var $shell = null;
77:
78: 79: 80: 81: 82: 83:
84: var $className = null;
85:
86: 87: 88: 89: 90: 91:
92: var $command = null;
93:
94: 95: 96: 97: 98: 99:
100: var $name = null;
101:
102: 103: 104: 105: 106: 107:
108: var $alias = null;
109:
110: 111: 112: 113: 114: 115:
116: var $tasks = array();
117:
118: 119: 120: 121: 122: 123:
124: var $taskNames = array();
125:
126: 127: 128: 129: 130: 131:
132: var $uses = array();
133:
134: 135: 136: 137:
138: function __construct(&$dispatch) {
139: $vars = array('params', 'args', 'shell', 'shellCommand' => 'command');
140:
141: foreach ($vars as $key => $var) {
142: if (is_string($key)) {
143: $this->{$var} =& $dispatch->{$key};
144: } else {
145: $this->{$var} =& $dispatch->{$var};
146: }
147: }
148:
149: if ($this->name == null) {
150: $this->name = get_class($this);
151: }
152:
153: if ($this->alias == null) {
154: $this->alias = $this->name;
155: }
156:
157: ClassRegistry::addObject($this->name, $this);
158: ClassRegistry::map($this->name, $this->alias);
159:
160: if (!PHP5 && isset($this->args[0])) {
161: if (strpos($this->name, strtolower(Inflector::camelize($this->args[0]))) !== false) {
162: $dispatch->shiftArgs();
163: }
164: if (strtolower($this->command) == strtolower(Inflector::variable($this->args[0])) && method_exists($this, $this->command)) {
165: $dispatch->shiftArgs();
166: }
167: }
168:
169: $this->Dispatch =& $dispatch;
170: }
171:
172: 173: 174: 175: 176: 177: 178:
179: function initialize() {
180: $this->_loadModels();
181: }
182:
183: 184: 185: 186: 187: 188: 189:
190: function startup() {
191: $this->_welcome();
192: }
193:
194: 195: 196: 197: 198:
199: function _welcome() {
200: $this->Dispatch->clear();
201: $this->out();
202: $this->out('Welcome to CakePHP v' . Configure::version() . ' Console');
203: $this->hr();
204: $this->out('App : '. $this->params['app']);
205: $this->out('Path: '. $this->params['working']);
206: $this->hr();
207: }
208:
209: 210: 211: 212: 213: 214: 215:
216: function _loadDbConfig() {
217: if (config('database') && class_exists('DATABASE_CONFIG')) {
218: $this->DbConfig =& new DATABASE_CONFIG();
219: return true;
220: }
221: $this->err('Database config could not be loaded.');
222: $this->out('Run `bake` to create the database configuration.');
223: return false;
224: }
225:
226: 227: 228: 229: 230: 231: 232: 233: 234:
235: function _loadModels() {
236: if ($this->uses === null || $this->uses === false) {
237: return;
238: }
239:
240: if ($this->uses === true && App::import('Model', 'AppModel')) {
241: $this->AppModel =& new AppModel(false, false, false);
242: return true;
243: }
244:
245: if ($this->uses !== true && !empty($this->uses)) {
246: $uses = is_array($this->uses) ? $this->uses : array($this->uses);
247:
248: $modelClassName = $uses[0];
249: if (strpos($uses[0], '.') !== false) {
250: list($plugin, $modelClassName) = explode('.', $uses[0]);
251: }
252: $this->modelClass = $modelClassName;
253:
254: foreach ($uses as $modelClass) {
255: list($plugin, $modelClass) = pluginSplit($modelClass, true);
256: if (PHP5) {
257: $this->{$modelClass} = ClassRegistry::init($plugin . $modelClass);
258: } else {
259: $this->{$modelClass} =& ClassRegistry::init($plugin . $modelClass);
260: }
261: }
262: return true;
263: }
264: return false;
265: }
266:
267: 268: 269: 270: 271: 272:
273: function loadTasks() {
274: if ($this->tasks === null || $this->tasks === false || $this->tasks === true || empty($this->tasks)) {
275: return true;
276: }
277:
278: $tasks = $this->tasks;
279: if (!is_array($tasks)) {
280: $tasks = array($tasks);
281: }
282:
283: foreach ($tasks as $taskName) {
284: $task = Inflector::underscore($taskName);
285: $taskClass = Inflector::camelize($taskName . 'Task');
286:
287: if (!class_exists($taskClass)) {
288: foreach ($this->Dispatch->shellPaths as $path) {
289: $taskPath = $path . 'tasks' . DS . $task . '.php';
290: if (file_exists($taskPath)) {
291: require_once $taskPath;
292: break;
293: }
294: }
295: }
296: $taskClassCheck = $taskClass;
297: if (!PHP5) {
298: $taskClassCheck = strtolower($taskClass);
299: }
300: if (ClassRegistry::isKeySet($taskClassCheck)) {
301: $this->taskNames[] = $taskName;
302: if (!PHP5) {
303: $this->{$taskName} =& ClassRegistry::getObject($taskClassCheck);
304: } else {
305: $this->{$taskName} = ClassRegistry::getObject($taskClassCheck);
306: }
307: } else {
308: $this->taskNames[] = $taskName;
309: if (!PHP5) {
310: $this->{$taskName} =& new $taskClass($this->Dispatch);
311: } else {
312: $this->{$taskName} = new $taskClass($this->Dispatch);
313: }
314: }
315:
316: if (!isset($this->{$taskName})) {
317: $this->err("Task `{$taskName}` could not be loaded");
318: $this->_stop();
319: }
320: }
321:
322: return true;
323: }
324:
325: 326: 327: 328: 329: 330: 331: 332: 333:
334: function in($prompt, $options = null, $default = null) {
335: if (!$this->interactive) {
336: return $default;
337: }
338: $in = $this->Dispatch->getInput($prompt, $options, $default);
339:
340: if ($options && is_string($options)) {
341: if (strpos($options, ',')) {
342: $options = explode(',', $options);
343: } elseif (strpos($options, '/')) {
344: $options = explode('/', $options);
345: } else {
346: $options = array($options);
347: }
348: }
349: if (is_array($options)) {
350: while ($in === '' || ($in !== '' && (!in_array(strtolower($in), $options) && !in_array(strtoupper($in), $options)) && !in_array($in, $options))) {
351: $in = $this->Dispatch->getInput($prompt, $options, $default);
352: }
353: }
354: return $in;
355: }
356:
357: 358: 359: 360: 361: 362: 363: 364: 365:
366: function out($message = null, $newlines = 1) {
367: if (is_array($message)) {
368: $message = implode($this->nl(), $message);
369: }
370: return $this->Dispatch->stdout($message . $this->nl($newlines), false);
371: }
372:
373: 374: 375: 376: 377: 378: 379: 380:
381: function err($message = null, $newlines = 1) {
382: if (is_array($message)) {
383: $message = implode($this->nl(), $message);
384: }
385: $this->Dispatch->stderr($message . $this->nl($newlines));
386: }
387:
388: 389: 390: 391: 392: 393: 394:
395: function nl($multiplier = 1) {
396: return str_repeat("\n", $multiplier);
397: }
398:
399: 400: 401: 402: 403: 404:
405: function hr($newlines = 0) {
406: $this->out(null, $newlines);
407: $this->out('---------------------------------------------------------------');
408: $this->out(null, $newlines);
409: }
410:
411: 412: 413: 414: 415: 416: 417: 418:
419: function error($title, $message = null) {
420: $this->err(sprintf(__('Error: %s', true), $title));
421:
422: if (!empty($message)) {
423: $this->err($message);
424: }
425: $this->_stop(1);
426: }
427:
428: 429: 430: 431: 432: 433: 434:
435: function _checkArgs($expectedNum, $command = null) {
436: if (!$command) {
437: $command = $this->command;
438: }
439: if (count($this->args) < $expectedNum) {
440: $message[] = "Got: " . count($this->args);
441: $message[] = "Expected: {$expectedNum}";
442: $message[] = "Please type `cake {$this->shell} help` for help";
443: $message[] = "on usage of the {$this->name} {$command}.";
444: $this->error('Wrong number of parameters', $message);
445: }
446: }
447:
448: 449: 450: 451: 452: 453: 454: 455:
456: function createFile($path, $contents) {
457: $path = str_replace(DS . DS, DS, $path);
458:
459: $this->out();
460: $this->out(sprintf(__("Creating file %s", true), $path));
461:
462: if (is_file($path) && $this->interactive === true) {
463: $prompt = sprintf(__('File `%s` exists, overwrite?', true), $path);
464: $key = $this->in($prompt, array('y', 'n', 'q'), 'n');
465:
466: if (strtolower($key) == 'q') {
467: $this->out(__('Quitting.', true), 2);
468: $this->_stop();
469: } elseif (strtolower($key) != 'y') {
470: $this->out(sprintf(__('Skip `%s`', true), $path), 2);
471: return false;
472: }
473: }
474: if (!class_exists('File')) {
475: require LIBS . 'file.php';
476: }
477:
478: if ($File = new File($path, true)) {
479: $data = $File->prepare($contents);
480: $File->write($data);
481: $this->out(sprintf(__('Wrote `%s`', true), $path));
482: return true;
483: } else {
484: $this->err(sprintf(__('Could not write to `%s`.', true), $path), 2);
485: return false;
486: }
487: }
488:
489: 490: 491: 492: 493:
494: function help() {
495: if ($this->command != null) {
496: $this->err("Unknown {$this->name} command `{$this->command}`.");
497: $this->err("For usage, try `cake {$this->shell} help`.", 2);
498: } else {
499: $this->Dispatch->help();
500: }
501: }
502:
503: 504: 505: 506: 507: 508:
509: function _checkUnitTest() {
510: if (App::import('vendor', 'simpletest' . DS . 'simpletest')) {
511: return true;
512: }
513: $prompt = 'SimpleTest is not installed. Do you want to bake unit test files anyway?';
514: $unitTest = $this->in($prompt, array('y','n'), 'y');
515: $result = strtolower($unitTest) == 'y' || strtolower($unitTest) == 'yes';
516:
517: if ($result) {
518: $this->out();
519: $this->out('You can download SimpleTest from http://simpletest.org');
520: }
521: return $result;
522: }
523:
524: 525: 526: 527: 528: 529: 530:
531: function shortPath($file) {
532: $shortPath = str_replace(ROOT, null, $file);
533: $shortPath = str_replace('..' . DS, '', $shortPath);
534: return str_replace(DS . DS, DS, $shortPath);
535: }
536:
537: 538: 539: 540: 541: 542: 543:
544: function _controllerPath($name) {
545: return strtolower(Inflector::underscore($name));
546: }
547:
548: 549: 550: 551: 552: 553: 554:
555: function _controllerName($name) {
556: return Inflector::pluralize(Inflector::camelize($name));
557: }
558:
559: 560: 561: 562: 563: 564: 565:
566: function _modelName($name) {
567: return Inflector::camelize(Inflector::singularize($name));
568: }
569:
570: 571: 572: 573: 574: 575: 576:
577: function _modelKey($name) {
578: return Inflector::underscore($name) . '_id';
579: }
580:
581: 582: 583: 584: 585: 586: 587:
588: function _modelNameFromKey($key) {
589: return Inflector::camelize(str_replace('_id', '', $key));
590: }
591:
592: 593: 594: 595: 596: 597: 598:
599: function _singularName($name) {
600: return Inflector::variable(Inflector::singularize($name));
601: }
602:
603: 604: 605: 606: 607: 608: 609:
610: function _pluralName($name) {
611: return Inflector::variable(Inflector::pluralize($name));
612: }
613:
614: 615: 616: 617: 618: 619: 620:
621: function _singularHumanName($name) {
622: return Inflector::humanize(Inflector::underscore(Inflector::singularize($name)));
623: }
624:
625: 626: 627: 628: 629: 630: 631:
632: function _pluralHumanName($name) {
633: return Inflector::humanize(Inflector::underscore($name));
634: }
635:
636: 637: 638: 639: 640: 641:
642: function _pluginPath($pluginName) {
643: return App::pluginPath($pluginName);
644: }
645: }
646: