1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19:
20: App::uses('AppShell', 'Console/Command');
21: App::uses('BakeTask', 'Console/Command/Task');
22: App::uses('ConnectionManager', 'Model');
23: App::uses('Model', 'Model');
24: App::uses('Validation', 'Utility');
25:
26: 27: 28: 29: 30:
31: class ModelTask extends BakeTask {
32:
33: 34: 35: 36: 37:
38: public $path = null;
39:
40: 41: 42: 43: 44:
45: public $tasks = array('DbConfig', 'Fixture', 'Test', 'Template');
46:
47: 48: 49: 50: 51:
52: public $skipTables = array('i18n');
53:
54: 55: 56: 57: 58:
59: protected $_tables = array();
60:
61: 62: 63: 64: 65:
66: protected $_modelNames = array();
67:
68: 69: 70: 71: 72:
73: protected $_validations = array();
74:
75: 76: 77: 78: 79:
80: public function initialize() {
81: $this->path = current(App::path('Model'));
82: }
83:
84: 85: 86: 87: 88:
89: public function execute() {
90: parent::execute();
91:
92: if (empty($this->args)) {
93: $this->_interactive();
94: }
95:
96: if (!empty($this->args[0])) {
97: $this->interactive = false;
98: if (!isset($this->connection)) {
99: $this->connection = 'default';
100: }
101: if (strtolower($this->args[0]) === 'all') {
102: return $this->all();
103: }
104: $model = $this->_modelName($this->args[0]);
105: $this->listAll($this->connection);
106: $useTable = $this->getTable($model);
107: $object = $this->_getModelObject($model, $useTable);
108: if ($this->bake($object, false)) {
109: if ($this->_checkUnitTest()) {
110: $this->bakeFixture($model, $useTable);
111: $this->bakeTest($model);
112: }
113: }
114: }
115: }
116:
117: 118: 119: 120: 121:
122: public function all() {
123: $this->listAll($this->connection, false);
124: $unitTestExists = $this->_checkUnitTest();
125: foreach ($this->_tables as $table) {
126: if (in_array($table, $this->skipTables)) {
127: continue;
128: }
129: $modelClass = Inflector::classify($table);
130: $this->out(__d('cake_console', 'Baking %s', $modelClass));
131: $object = $this->_getModelObject($modelClass, $table);
132: if ($this->bake($object, false) && $unitTestExists) {
133: $this->bakeFixture($modelClass, $table);
134: $this->bakeTest($modelClass);
135: }
136: }
137: }
138:
139: 140: 141: 142: 143: 144: 145:
146: protected function _getModelObject($className, $table = null) {
147: if (!$table) {
148: $table = Inflector::tableize($className);
149: }
150: $object = new Model(array('name' => $className, 'table' => $table, 'ds' => $this->connection));
151: $fields = $object->schema(true);
152: foreach ($fields as $name => $field) {
153: if (isset($field['key']) && $field['key'] === 'primary') {
154: $object->primaryKey = $name;
155: break;
156: }
157: }
158: return $object;
159: }
160:
161: 162: 163: 164: 165: 166: 167: 168:
169: public function inOptions($options, $prompt = null, $default = null) {
170: $valid = false;
171: $max = count($options);
172: while (!$valid) {
173: $len = strlen(count($options) + 1);
174: foreach ($options as $i => $option) {
175: $this->out(sprintf("%${len}d. %s", $i + 1, $option));
176: }
177: if (empty($prompt)) {
178: $prompt = __d('cake_console', 'Make a selection from the choices above');
179: }
180: $choice = $this->in($prompt, null, $default);
181: if (intval($choice) > 0 && intval($choice) <= $max) {
182: $valid = true;
183: }
184: }
185: return $choice - 1;
186: }
187:
188: 189: 190: 191: 192:
193: protected function _interactive() {
194: $this->hr();
195: $this->out(__d('cake_console', "Bake Model\nPath: %s", $this->getPath()));
196: $this->hr();
197: $this->interactive = true;
198:
199: $primaryKey = 'id';
200: $validate = $associations = array();
201:
202: if (empty($this->connection)) {
203: $this->connection = $this->DbConfig->getConfig();
204: }
205: $currentModelName = $this->getName();
206: $useTable = $this->getTable($currentModelName);
207: $db = ConnectionManager::getDataSource($this->connection);
208: $fullTableName = $db->fullTableName($useTable);
209: if (!in_array($useTable, $this->_tables)) {
210: $prompt = __d('cake_console', "The table %s doesn't exist or could not be automatically detected\ncontinue anyway?", $useTable);
211: $continue = $this->in($prompt, array('y', 'n'));
212: if (strtolower($continue) === 'n') {
213: return false;
214: }
215: }
216:
217: $tempModel = new Model(array('name' => $currentModelName, 'table' => $useTable, 'ds' => $this->connection));
218:
219: $knownToExist = false;
220: try {
221: $fields = $tempModel->schema(true);
222: $knownToExist = true;
223: } catch (Exception $e) {
224: $fields = array($tempModel->primaryKey);
225: }
226: if (!array_key_exists('id', $fields)) {
227: $primaryKey = $this->findPrimaryKey($fields);
228: }
229:
230: if ($knownToExist) {
231: $displayField = $tempModel->hasField(array('name', 'title'));
232: if (!$displayField) {
233: $displayField = $this->findDisplayField($tempModel->schema());
234: }
235:
236: $prompt = __d('cake_console', "Would you like to supply validation criteria \nfor the fields in your model?");
237: $wannaDoValidation = $this->in($prompt, array('y', 'n'), 'y');
238: if (array_search($useTable, $this->_tables) !== false && strtolower($wannaDoValidation) === 'y') {
239: $validate = $this->doValidation($tempModel);
240: }
241:
242: $prompt = __d('cake_console', "Would you like to define model associations\n(hasMany, hasOne, belongsTo, etc.)?");
243: $wannaDoAssoc = $this->in($prompt, array('y', 'n'), 'y');
244: if (strtolower($wannaDoAssoc) === 'y') {
245: $associations = $this->doAssociations($tempModel);
246: }
247: }
248:
249: $this->out();
250: $this->hr();
251: $this->out(__d('cake_console', 'The following Model will be created:'));
252: $this->hr();
253: $this->out(__d('cake_console', "Name: %s", $currentModelName));
254:
255: if ($this->connection !== 'default') {
256: $this->out(__d('cake_console', "DB Config: %s", $this->connection));
257: }
258: if ($fullTableName !== Inflector::tableize($currentModelName)) {
259: $this->out(__d('cake_console', 'DB Table: %s', $fullTableName));
260: }
261: if ($primaryKey !== 'id') {
262: $this->out(__d('cake_console', 'Primary Key: %s', $primaryKey));
263: }
264: if (!empty($validate)) {
265: $this->out(__d('cake_console', 'Validation: %s', print_r($validate, true)));
266: }
267: if (!empty($associations)) {
268: $this->out(__d('cake_console', 'Associations:'));
269: $assocKeys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
270: foreach ($assocKeys as $assocKey) {
271: $this->_printAssociation($currentModelName, $assocKey, $associations);
272: }
273: }
274:
275: $this->hr();
276: $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
277:
278: if (strtolower($looksGood) === 'y') {
279: $vars = compact('associations', 'validate', 'primaryKey', 'useTable', 'displayField');
280: $vars['useDbConfig'] = $this->connection;
281: if ($this->bake($currentModelName, $vars)) {
282: if ($this->_checkUnitTest()) {
283: $this->bakeFixture($currentModelName, $useTable);
284: $this->bakeTest($currentModelName, $useTable, $associations);
285: }
286: }
287: } else {
288: return false;
289: }
290: }
291:
292: 293: 294: 295: 296: 297: 298: 299:
300: protected function _printAssociation($modelName, $type, $associations) {
301: if (!empty($associations[$type])) {
302: for ($i = 0, $len = count($associations[$type]); $i < $len; $i++) {
303: $out = "\t" . $modelName . ' ' . $type . ' ' . $associations[$type][$i]['alias'];
304: $this->out($out);
305: }
306: }
307: }
308:
309: 310: 311: 312: 313: 314:
315: public function findPrimaryKey($fields) {
316: $name = 'id';
317: foreach ($fields as $name => $field) {
318: if (isset($field['key']) && $field['key'] === 'primary') {
319: break;
320: }
321: }
322: return $this->in(__d('cake_console', 'What is the primaryKey?'), null, $name);
323: }
324:
325: 326: 327: 328: 329: 330:
331: public function findDisplayField($fields) {
332: $fieldNames = array_keys($fields);
333: $prompt = __d('cake_console', "A displayField could not be automatically detected\nwould you like to choose one?");
334: $continue = $this->in($prompt, array('y', 'n'));
335: if (strtolower($continue) === 'n') {
336: return false;
337: }
338: $prompt = __d('cake_console', 'Choose a field from the options above:');
339: $choice = $this->inOptions($fieldNames, $prompt);
340: return $fieldNames[$choice];
341: }
342:
343: 344: 345: 346: 347: 348:
349: public function doValidation($model) {
350: if (!is_object($model)) {
351: return false;
352: }
353: $fields = $model->schema();
354:
355: if (empty($fields)) {
356: return false;
357: }
358: $validate = array();
359: $this->initValidations();
360: foreach ($fields as $fieldName => $field) {
361: $validation = $this->fieldValidation($fieldName, $field, $model->primaryKey);
362: if (!empty($validation)) {
363: $validate[$fieldName] = $validation;
364: }
365: }
366: return $validate;
367: }
368:
369: 370: 371: 372: 373:
374: public function initValidations() {
375: $options = $choices = array();
376: if (class_exists('Validation')) {
377: $options = get_class_methods('Validation');
378: }
379: sort($options);
380: $default = 1;
381: foreach ($options as $option) {
382: if ($option{0} !== '_') {
383: $choices[$default] = strtolower($option);
384: $default++;
385: }
386: }
387: $choices[$default] = 'none';
388: $this->_validations = $choices;
389: return $choices;
390: }
391:
392: 393: 394: 395: 396: 397: 398: 399:
400: public function fieldValidation($fieldName, $metaData, $primaryKey = 'id') {
401: $defaultChoice = count($this->_validations);
402: $validate = $alreadyChosen = array();
403:
404: $anotherValidator = 'y';
405: while ($anotherValidator === 'y') {
406: if ($this->interactive) {
407: $this->out();
408: $this->out(__d('cake_console', 'Field: <info>%s</info>', $fieldName));
409: $this->out(__d('cake_console', 'Type: <info>%s</info>', $metaData['type']));
410: $this->hr();
411: $this->out(__d('cake_console', 'Please select one of the following validation options:'));
412: $this->hr();
413:
414: $optionText = '';
415: for ($i = 1, $m = $defaultChoice / 2; $i <= $m; $i++) {
416: $line = sprintf("%2d. %s", $i, $this->_validations[$i]);
417: $optionText .= $line . str_repeat(" ", 31 - strlen($line));
418: if ($m + $i !== $defaultChoice) {
419: $optionText .= sprintf("%2d. %s\n", $m + $i, $this->_validations[$m + $i]);
420: }
421: }
422: $this->out($optionText);
423: $this->out(__d('cake_console', "%s - Do not do any validation on this field.", $defaultChoice));
424: $this->hr();
425: }
426:
427: $prompt = __d('cake_console', "... or enter in a valid regex validation string.\n");
428: $methods = array_flip($this->_validations);
429: $guess = $defaultChoice;
430: if ($metaData['null'] != 1 && !in_array($fieldName, array($primaryKey, 'created', 'modified', 'updated'))) {
431: if ($fieldName === 'email') {
432: $guess = $methods['email'];
433: } elseif ($metaData['type'] === 'string' && $metaData['length'] == 36) {
434: $guess = $methods['uuid'];
435: } elseif ($metaData['type'] === 'string') {
436: $guess = $methods['notempty'];
437: } elseif ($metaData['type'] === 'text') {
438: $guess = $methods['notempty'];
439: } elseif ($metaData['type'] === 'integer') {
440: $guess = $methods['numeric'];
441: } elseif ($metaData['type'] === 'boolean') {
442: $guess = $methods['boolean'];
443: } elseif ($metaData['type'] === 'date') {
444: $guess = $methods['date'];
445: } elseif ($metaData['type'] === 'time') {
446: $guess = $methods['time'];
447: } elseif ($metaData['type'] === 'datetime') {
448: $guess = $methods['datetime'];
449: } elseif ($metaData['type'] === 'inet') {
450: $guess = $methods['ip'];
451: }
452: }
453:
454: if ($this->interactive === true) {
455: $choice = $this->in($prompt, null, $guess);
456: if (in_array($choice, $alreadyChosen)) {
457: $this->out(__d('cake_console', "You have already chosen that validation rule,\nplease choose again"));
458: continue;
459: }
460: if (!isset($this->_validations[$choice]) && is_numeric($choice)) {
461: $this->out(__d('cake_console', 'Please make a valid selection.'));
462: continue;
463: }
464: $alreadyChosen[] = $choice;
465: } else {
466: $choice = $guess;
467: }
468:
469: if (isset($this->_validations[$choice])) {
470: $validatorName = $this->_validations[$choice];
471: } else {
472: $validatorName = Inflector::slug($choice);
473: }
474:
475: if ($choice != $defaultChoice) {
476: $validate[$validatorName] = $choice;
477: if (is_numeric($choice) && isset($this->_validations[$choice])) {
478: $validate[$validatorName] = $this->_validations[$choice];
479: }
480: }
481: $anotherValidator = 'n';
482: if ($this->interactive && $choice != $defaultChoice) {
483: $anotherValidator = $this->in(__d('cake_console', 'Would you like to add another validation rule?'), array('y', 'n'), 'n');
484: }
485: }
486: return $validate;
487: }
488:
489: 490: 491: 492: 493: 494:
495: public function doAssociations($model) {
496: if (!is_object($model)) {
497: return false;
498: }
499: if ($this->interactive === true) {
500: $this->out(__d('cake_console', 'One moment while the associations are detected.'));
501: }
502:
503: $fields = $model->schema(true);
504: if (empty($fields)) {
505: return array();
506: }
507:
508: if (empty($this->_tables)) {
509: $this->_tables = (array)$this->getAllTables();
510: }
511:
512: $associations = array(
513: 'belongsTo' => array(),
514: 'hasMany' => array(),
515: 'hasOne' => array(),
516: 'hasAndBelongsToMany' => array()
517: );
518:
519: $associations = $this->findBelongsTo($model, $associations);
520: $associations = $this->findHasOneAndMany($model, $associations);
521: $associations = $this->findHasAndBelongsToMany($model, $associations);
522:
523: if ($this->interactive !== true) {
524: unset($associations['hasOne']);
525: }
526:
527: if ($this->interactive === true) {
528: $this->hr();
529: if (empty($associations)) {
530: $this->out(__d('cake_console', 'None found.'));
531: } else {
532: $this->out(__d('cake_console', 'Please confirm the following associations:'));
533: $this->hr();
534: $associations = $this->confirmAssociations($model, $associations);
535: }
536: $associations = $this->doMoreAssociations($model, $associations);
537: }
538: return $associations;
539: }
540:
541: 542: 543: 544: 545: 546: 547:
548: public function findBelongsTo(Model $model, $associations) {
549: $fieldNames = array_keys($model->schema(true));
550: foreach ($fieldNames as $fieldName) {
551: $offset = strpos($fieldName, '_id');
552: if ($fieldName != $model->primaryKey && $fieldName !== 'parent_id' && $offset !== false) {
553: $tmpModelName = $this->_modelNameFromKey($fieldName);
554: $associations['belongsTo'][] = array(
555: 'alias' => $tmpModelName,
556: 'className' => $tmpModelName,
557: 'foreignKey' => $fieldName,
558: );
559: } elseif ($fieldName === 'parent_id') {
560: $associations['belongsTo'][] = array(
561: 'alias' => 'Parent' . $model->name,
562: 'className' => $model->name,
563: 'foreignKey' => $fieldName,
564: );
565: }
566: }
567: return $associations;
568: }
569:
570: 571: 572: 573: 574: 575: 576:
577: public function findHasOneAndMany(Model $model, $associations) {
578: $foreignKey = $this->_modelKey($model->name);
579: foreach ($this->_tables as $otherTable) {
580: $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable), $otherTable);
581: $tempFieldNames = array_keys($tempOtherModel->schema(true));
582:
583: $pattern = '/_' . preg_quote($model->table, '/') . '|' . preg_quote($model->table, '/') . '_/';
584: $possibleJoinTable = preg_match($pattern, $otherTable);
585: if ($possibleJoinTable) {
586: continue;
587: }
588: foreach ($tempFieldNames as $fieldName) {
589: $assoc = false;
590: if ($fieldName != $model->primaryKey && $fieldName == $foreignKey) {
591: $assoc = array(
592: 'alias' => $tempOtherModel->name,
593: 'className' => $tempOtherModel->name,
594: 'foreignKey' => $fieldName
595: );
596: } elseif ($otherTable == $model->table && $fieldName === 'parent_id') {
597: $assoc = array(
598: 'alias' => 'Child' . $model->name,
599: 'className' => $model->name,
600: 'foreignKey' => $fieldName
601: );
602: }
603: if ($assoc) {
604: $associations['hasOne'][] = $assoc;
605: $associations['hasMany'][] = $assoc;
606: }
607:
608: }
609: }
610: return $associations;
611: }
612:
613: 614: 615: 616: 617: 618: 619:
620: public function findHasAndBelongsToMany(Model $model, $associations) {
621: $foreignKey = $this->_modelKey($model->name);
622: foreach ($this->_tables as $otherTable) {
623: $tableName = null;
624: $offset = strpos($otherTable, $model->table . '_');
625: $otherOffset = strpos($otherTable, '_' . $model->table);
626:
627: if ($offset !== false) {
628: $tableName = substr($otherTable, strlen($model->table . '_'));
629: } elseif ($otherOffset !== false) {
630: $tableName = substr($otherTable, 0, $otherOffset);
631: }
632: if ($tableName && in_array($tableName, $this->_tables)) {
633: $habtmName = $this->_modelName($tableName);
634: $associations['hasAndBelongsToMany'][] = array(
635: 'alias' => $habtmName,
636: 'className' => $habtmName,
637: 'foreignKey' => $foreignKey,
638: 'associationForeignKey' => $this->_modelKey($habtmName),
639: 'joinTable' => $otherTable
640: );
641: }
642: }
643: return $associations;
644: }
645:
646: 647: 648: 649: 650: 651: 652:
653: public function confirmAssociations(Model $model, $associations) {
654: foreach ($associations as $type => $settings) {
655: if (!empty($associations[$type])) {
656: foreach ($associations[$type] as $i => $assoc) {
657: $prompt = "{$model->name} {$type} {$assoc['alias']}?";
658: $response = $this->in($prompt, array('y', 'n'), 'y');
659:
660: if (strtolower($response) === 'n') {
661: unset($associations[$type][$i]);
662: } elseif ($type === 'hasMany') {
663: unset($associations['hasOne'][$i]);
664: }
665: }
666: $associations[$type] = array_merge($associations[$type]);
667: }
668: }
669: return $associations;
670: }
671:
672: 673: 674: 675: 676: 677: 678:
679: public function doMoreAssociations(Model $model, $associations) {
680: $prompt = __d('cake_console', 'Would you like to define some additional model associations?');
681: $wannaDoMoreAssoc = $this->in($prompt, array('y', 'n'), 'n');
682: $possibleKeys = $this->_generatePossibleKeys();
683: while (strtolower($wannaDoMoreAssoc) === 'y') {
684: $assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
685: $this->out(__d('cake_console', 'What is the association type?'));
686: $assocType = intval($this->inOptions($assocs, __d('cake_console', 'Enter a number')));
687:
688: $this->out(__d('cake_console', "For the following options be very careful to match your setup exactly.\n" .
689: "Any spelling mistakes will cause errors."));
690: $this->hr();
691:
692: $alias = $this->in(__d('cake_console', 'What is the alias for this association?'));
693: $className = $this->in(__d('cake_console', 'What className will %s use?', $alias), null, $alias);
694:
695: if ($assocType === 0) {
696: if (!empty($possibleKeys[$model->table])) {
697: $showKeys = $possibleKeys[$model->table];
698: } else {
699: $showKeys = null;
700: }
701: $suggestedForeignKey = $this->_modelKey($alias);
702: } else {
703: $otherTable = Inflector::tableize($className);
704: if (in_array($otherTable, $this->_tables)) {
705: if ($assocType < 3) {
706: if (!empty($possibleKeys[$otherTable])) {
707: $showKeys = $possibleKeys[$otherTable];
708: } else {
709: $showKeys = null;
710: }
711: } else {
712: $showKeys = null;
713: }
714: } else {
715: $otherTable = $this->in(__d('cake_console', 'What is the table for this model?'));
716: $showKeys = $possibleKeys[$otherTable];
717: }
718: $suggestedForeignKey = $this->_modelKey($model->name);
719: }
720: if (!empty($showKeys)) {
721: $this->out(__d('cake_console', 'A helpful List of possible keys'));
722: $foreignKey = $this->inOptions($showKeys, __d('cake_console', 'What is the foreignKey?'));
723: $foreignKey = $showKeys[intval($foreignKey)];
724: }
725: if (!isset($foreignKey)) {
726: $foreignKey = $this->in(__d('cake_console', 'What is the foreignKey? Specify your own.'), null, $suggestedForeignKey);
727: }
728: if ($assocType === 3) {
729: $associationForeignKey = $this->in(__d('cake_console', 'What is the associationForeignKey?'), null, $this->_modelKey($model->name));
730: $joinTable = $this->in(__d('cake_console', 'What is the joinTable?'));
731: }
732: $associations[$assocs[$assocType]] = array_values((array)$associations[$assocs[$assocType]]);
733: $count = count($associations[$assocs[$assocType]]);
734: $i = ($count > 0) ? $count : 0;
735: $associations[$assocs[$assocType]][$i]['alias'] = $alias;
736: $associations[$assocs[$assocType]][$i]['className'] = $className;
737: $associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey;
738: if ($assocType === 3) {
739: $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey;
740: $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable;
741: }
742: $wannaDoMoreAssoc = $this->in(__d('cake_console', 'Define another association?'), array('y', 'n'), 'y');
743: }
744: return $associations;
745: }
746:
747: 748: 749: 750: 751:
752: protected function _generatePossibleKeys() {
753: $possible = array();
754: foreach ($this->_tables as $otherTable) {
755: $tempOtherModel = new Model(array('table' => $otherTable, 'ds' => $this->connection));
756: $modelFieldsTemp = $tempOtherModel->schema(true);
757: foreach ($modelFieldsTemp as $fieldName => $field) {
758: if ($field['type'] === 'integer' || $field['type'] === 'string') {
759: $possible[$otherTable][] = $fieldName;
760: }
761: }
762: }
763: return $possible;
764: }
765:
766: 767: 768: 769: 770: 771: 772:
773: public function bake($name, $data = array()) {
774: if (is_object($name)) {
775: if (!$data) {
776: $data = array();
777: $data['associations'] = $this->doAssociations($name);
778: $data['validate'] = $this->doValidation($name);
779: }
780: $data['primaryKey'] = $name->primaryKey;
781: $data['useTable'] = $name->table;
782: $data['useDbConfig'] = $name->useDbConfig;
783: $data['name'] = $name = $name->name;
784: } else {
785: $data['name'] = $name;
786: }
787: $defaults = array(
788: 'associations' => array(),
789: 'validate' => array(),
790: 'primaryKey' => 'id',
791: 'useTable' => null,
792: 'useDbConfig' => 'default',
793: 'displayField' => null
794: );
795: $data = array_merge($defaults, $data);
796:
797: $pluginPath = '';
798: if ($this->plugin) {
799: $pluginPath = $this->plugin . '.';
800: }
801:
802: $this->Template->set($data);
803: $this->Template->set(array(
804: 'plugin' => $this->plugin,
805: 'pluginPath' => $pluginPath
806: ));
807: $out = $this->Template->generate('classes', 'model');
808:
809: $path = $this->getPath();
810: $filename = $path . $name . '.php';
811: $this->out("\n" . __d('cake_console', 'Baking model class for %s...', $name), 1, Shell::QUIET);
812: $this->createFile($filename, $out);
813: ClassRegistry::flush();
814: return $out;
815: }
816:
817: 818: 819: 820: 821: 822:
823: public function bakeTest($className) {
824: $this->Test->interactive = $this->interactive;
825: $this->Test->plugin = $this->plugin;
826: $this->Test->connection = $this->connection;
827: return $this->Test->bake('Model', $className);
828: }
829:
830: 831: 832: 833: 834: 835:
836: public function listAll($useDbConfig = null) {
837: $this->_tables = (array)$this->getAllTables($useDbConfig);
838:
839: $this->_modelNames = array();
840: $count = count($this->_tables);
841: for ($i = 0; $i < $count; $i++) {
842: $this->_modelNames[] = $this->_modelName($this->_tables[$i]);
843: }
844: if ($this->interactive === true) {
845: $this->out(__d('cake_console', 'Possible Models based on your current database:'));
846: $len = strlen($count + 1);
847: for ($i = 0; $i < $count; $i++) {
848: $this->out(sprintf("%${len}d. %s", $i + 1, $this->_modelNames[$i]));
849: }
850: }
851: return $this->_tables;
852: }
853:
854: 855: 856: 857: 858: 859: 860:
861: public function getTable($modelName, $useDbConfig = null) {
862: $useTable = Inflector::tableize($modelName);
863: if (in_array($modelName, $this->_modelNames)) {
864: $modelNames = array_flip($this->_modelNames);
865: $useTable = $this->_tables[$modelNames[$modelName]];
866: }
867:
868: if ($this->interactive === true) {
869: if (!isset($useDbConfig)) {
870: $useDbConfig = $this->connection;
871: }
872: $db = ConnectionManager::getDataSource($useDbConfig);
873: $fullTableName = $db->fullTableName($useTable, false);
874: $tableIsGood = false;
875: if (array_search($useTable, $this->_tables) === false) {
876: $this->out();
877: $this->out(__d('cake_console', "Given your model named '%s',\nCake would expect a database table named '%s'", $modelName, $fullTableName));
878: $tableIsGood = $this->in(__d('cake_console', 'Do you want to use this table?'), array('y', 'n'), 'y');
879: }
880: if (strtolower($tableIsGood) === 'n') {
881: $useTable = $this->in(__d('cake_console', 'What is the name of the table?'));
882: }
883: }
884: return $useTable;
885: }
886:
887: 888: 889: 890: 891: 892: 893:
894: public function getAllTables($useDbConfig = null) {
895: if (!isset($useDbConfig)) {
896: $useDbConfig = $this->connection;
897: }
898:
899: $tables = array();
900: $db = ConnectionManager::getDataSource($useDbConfig);
901: $db->cacheSources = false;
902: $usePrefix = empty($db->config['prefix']) ? '' : $db->config['prefix'];
903: if ($usePrefix) {
904: foreach ($db->listSources() as $table) {
905: if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
906: $tables[] = substr($table, strlen($usePrefix));
907: }
908: }
909: } else {
910: $tables = $db->listSources();
911: }
912: if (empty($tables)) {
913: $this->err(__d('cake_console', 'Your database does not have any tables.'));
914: return $this->_stop();
915: }
916: return $tables;
917: }
918:
919: 920: 921: 922: 923: 924:
925: public function getName($useDbConfig = null) {
926: $this->listAll($useDbConfig);
927:
928: $enteredModel = '';
929:
930: while (!$enteredModel) {
931: $enteredModel = $this->in(__d('cake_console', "Enter a number from the list above,\n" .
932: "type in the name of another model, or 'q' to exit"), null, 'q');
933:
934: if ($enteredModel === 'q') {
935: $this->out(__d('cake_console', 'Exit'));
936: return $this->_stop();
937: }
938:
939: if (!$enteredModel || intval($enteredModel) > count($this->_modelNames)) {
940: $this->err(__d('cake_console', "The model name you supplied was empty,\n" .
941: "or the number you selected was not an option. Please try again."));
942: $enteredModel = '';
943: }
944: }
945: if (intval($enteredModel) > 0 && intval($enteredModel) <= count($this->_modelNames)) {
946: return $this->_modelNames[intval($enteredModel) - 1];
947: }
948:
949: return $enteredModel;
950: }
951:
952: 953: 954: 955: 956:
957: public function getOptionParser() {
958: $parser = parent::getOptionParser();
959: return $parser->description(
960: __d('cake_console', 'Bake models.')
961: )->addArgument('name', array(
962: 'help' => __d('cake_console', 'Name of the model to bake. Can use Plugin.name to bake plugin models.')
963: ))->addSubcommand('all', array(
964: 'help' => __d('cake_console', 'Bake all model files with associations and validation.')
965: ))->addOption('plugin', array(
966: 'short' => 'p',
967: 'help' => __d('cake_console', 'Plugin to bake the model into.')
968: ))->addOption('connection', array(
969: 'short' => 'c',
970: 'help' => __d('cake_console', 'The connection the model table is on.')
971: ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
972: }
973:
974: 975: 976: 977: 978: 979: 980: 981:
982: public function bakeFixture($className, $useTable = null) {
983: $this->Fixture->interactive = $this->interactive;
984: $this->Fixture->connection = $this->connection;
985: $this->Fixture->plugin = $this->plugin;
986: $this->Fixture->bake($className, $useTable);
987: }
988:
989: }
990: