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