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