CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 2.0 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.0
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Packages

  • Cake
    • Cache
      • Engine
    • Configure
    • Console
      • Command
        • Task
    • Controller
      • Component
        • Auth
    • Core
    • Error
    • I18n
    • Log
      • Engine
    • Model
      • Behavior
      • Datasource
        • Database
        • Session
    • Network
      • Email
      • Http
    • Routing
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper

Classes

  • BakeTask
  • ControllerTask
  • DbConfigTask
  • ExtractTask
  • FixtureTask
  • ModelTask
  • PluginTask
  • ProjectTask
  • TemplateTask
  • TestTask
  • ViewTask
  1: <?php
  2: /**
  3:  * The ModelTask handles creating and updating models files.
  4:  *
  5:  * PHP 5
  6:  *
  7:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8:  * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9:  *
 10:  * Licensed under The MIT License
 11:  * Redistributions of files must retain the above copyright notice.
 12:  *
 13:  * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 14:  * @link          http://cakephp.org CakePHP(tm) Project
 15:  * @since         CakePHP(tm) v 1.2
 16:  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 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:  * Task class for creating and updating model files.
 27:  *
 28:  * @package       Cake.Console.Command.Task
 29:  */
 30: class ModelTask extends BakeTask {
 31: 
 32: /**
 33:  * path to Model directory
 34:  *
 35:  * @var string
 36:  */
 37:     public $path = null;
 38: 
 39: /**
 40:  * tasks
 41:  *
 42:  * @var array
 43:  */
 44:     public $tasks = array('DbConfig', 'Fixture', 'Test', 'Template');
 45: 
 46: /**
 47:  * Tables to skip when running all()
 48:  *
 49:  * @var array
 50:  */
 51:     public $skipTables = array('i18n');
 52: 
 53: /**
 54:  * Holds tables found on connection.
 55:  *
 56:  * @var array
 57:  */
 58:     protected $_tables = array();
 59: 
 60: /**
 61:  * Holds the model names
 62:  *
 63:  * @var array
 64:  */
 65:     protected $_modelNames = array();
 66: 
 67: /**
 68:  * Holds validation method map.
 69:  *
 70:  * @var array
 71:  */
 72:     protected $_validations = array();
 73: 
 74: /**
 75:  * Override initialize
 76:  *
 77:  * @return void
 78:  */
 79:     public function initialize() {
 80:         $this->path = current(App::path('Model'));
 81:     }
 82: 
 83: /**
 84:  * Execution method always used for tasks
 85:  *
 86:  * @return void
 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:  * Bake all models at once.
118:  *
119:  * @return void
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:  * Get a model object for a class name.
140:  *
141:  * @param string $className Name of class you want model to be.
142:  * @param string $table Table name
143:  * @return Model Model instance
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:  * Generate a key value list of options and a prompt.
162:  *
163:  * @param array $options Array of options to use for the selections. indexes must start at 0
164:  * @param string $prompt Prompt to use for options list.
165:  * @param integer $default The default option for the given prompt.
166:  * @return integer result of user choice.
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:  * Handles interactive baking
188:  *
189:  * @return boolean
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: 
208:         if (in_array($useTable, $this->_tables)) {
209:             $tempModel = new Model(array('name' => $currentModelName, 'table' => $useTable, 'ds' => $this->connection));
210:             $fields = $tempModel->schema(true);
211:             if (!array_key_exists('id', $fields)) {
212:                 $primaryKey = $this->findPrimaryKey($fields);
213:             }
214:         } else {
215:             $this->err(__d('cake_console', 'Table %s does not exist, cannot bake a model without a table.', $useTable));
216:             $this->_stop();
217:             return false;
218:         }
219:         $displayField = $tempModel->hasField(array('name', 'title'));
220:         if (!$displayField) {
221:             $displayField = $this->findDisplayField($tempModel->schema());
222:         }
223: 
224:         $prompt = __d('cake_console', "Would you like to supply validation criteria \nfor the fields in your model?");
225:         $wannaDoValidation = $this->in($prompt, array('y', 'n'), 'y');
226:         if (array_search($useTable, $this->_tables) !== false && strtolower($wannaDoValidation) == 'y') {
227:             $validate = $this->doValidation($tempModel);
228:         }
229: 
230:         $prompt = __d('cake_console', "Would you like to define model associations\n(hasMany, hasOne, belongsTo, etc.)?");
231:         $wannaDoAssoc = $this->in($prompt, array('y', 'n'), 'y');
232:         if (strtolower($wannaDoAssoc) == 'y') {
233:             $associations = $this->doAssociations($tempModel);
234:         }
235: 
236:         $this->out();
237:         $this->hr();
238:         $this->out(__d('cake_console', 'The following Model will be created:'));
239:         $this->hr();
240:         $this->out(__d('cake_console', "Name:       %s", $currentModelName));
241: 
242:         if ($this->connection !== 'default') {
243:             $this->out(__d('cake_console', "DB Config:  %s", $this->connection));
244:         }
245:         if ($fullTableName !== Inflector::tableize($currentModelName)) {
246:             $this->out(__d('cake_console', 'DB Table:   %s', $fullTableName));
247:         }
248:         if ($primaryKey != 'id') {
249:             $this->out(__d('cake_console', 'Primary Key: %s', $primaryKey));
250:         }
251:         if (!empty($validate)) {
252:             $this->out(__d('cake_console', 'Validation: %s', print_r($validate, true)));
253:         }
254:         if (!empty($associations)) {
255:             $this->out(__d('cake_console', 'Associations:'));
256:             $assocKeys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
257:             foreach ($assocKeys as $assocKey) {
258:                 $this->_printAssociation($currentModelName, $assocKey, $associations);
259:             }
260:         }
261: 
262:         $this->hr();
263:         $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n'), 'y');
264: 
265:         if (strtolower($looksGood) == 'y') {
266:             $vars = compact('associations', 'validate', 'primaryKey', 'useTable', 'displayField');
267:             $vars['useDbConfig'] = $this->connection;
268:             if ($this->bake($currentModelName, $vars)) {
269:                 if ($this->_checkUnitTest()) {
270:                     $this->bakeFixture($currentModelName, $useTable);
271:                     $this->bakeTest($currentModelName, $useTable, $associations);
272:                 }
273:             }
274:         } else {
275:             return false;
276:         }
277:     }
278: 
279: /**
280:  * Print out all the associations of a particular type
281:  *
282:  * @param string $modelName Name of the model relations belong to.
283:  * @param string $type Name of association you want to see. i.e. 'belongsTo'
284:  * @param string $associations Collection of associations.
285:  * @return void
286:  */
287:     protected function _printAssociation($modelName, $type, $associations) {
288:         if (!empty($associations[$type])) {
289:             for ($i = 0; $i < count($associations[$type]); $i++) {
290:                 $out = "\t" . $modelName . ' ' . $type . ' ' . $associations[$type][$i]['alias'];
291:                 $this->out($out);
292:             }
293:         }
294:     }
295: 
296: /**
297:  * Finds a primary Key in a list of fields.
298:  *
299:  * @param array $fields Array of fields that might have a primary key.
300:  * @return string Name of field that is a primary key.
301:  */
302:     public function findPrimaryKey($fields) {
303:         $name = 'id';
304:         foreach ($fields as $name => $field) {
305:             if (isset($field['key']) && $field['key'] == 'primary') {
306:                 break;
307:             }
308:         }
309:         return $this->in(__d('cake_console', 'What is the primaryKey?'), null, $name);
310:     }
311: 
312: /**
313:  * interact with the user to find the displayField value for a model.
314:  *
315:  * @param array $fields Array of fields to look for and choose as a displayField
316:  * @return mixed Name of field to use for displayField or false if the user declines to choose
317:  */
318:     public function findDisplayField($fields) {
319:         $fieldNames = array_keys($fields);
320:         $prompt = __d('cake_console', "A displayField could not be automatically detected\nwould you like to choose one?");
321:         $continue = $this->in($prompt, array('y', 'n'));
322:         if (strtolower($continue) == 'n') {
323:             return false;
324:         }
325:         $prompt = __d('cake_console', 'Choose a field from the options above:');
326:         $choice = $this->inOptions($fieldNames, $prompt);
327:         return $fieldNames[$choice];
328:     }
329: 
330: /**
331:  * Handles Generation and user interaction for creating validation.
332:  *
333:  * @param Model $model Model to have validations generated for.
334:  * @return array $validate Array of user selected validations.
335:  */
336:     public function doValidation($model) {
337:         if (!is_object($model)) {
338:             return false;
339:         }
340:         $fields = $model->schema();
341: 
342:         if (empty($fields)) {
343:             return false;
344:         }
345:         $validate = array();
346:         $this->initValidations();
347:         foreach ($fields as $fieldName => $field) {
348:             $validation = $this->fieldValidation($fieldName, $field, $model->primaryKey);
349:             if (!empty($validation)) {
350:                 $validate[$fieldName] = $validation;
351:             }
352:         }
353:         return $validate;
354:     }
355: 
356: /**
357:  * Populate the _validations array
358:  *
359:  * @return void
360:  */
361:     public function initValidations() {
362:         $options = $choices = array();
363:         if (class_exists('Validation')) {
364:             $options = get_class_methods('Validation');
365:         }
366:         sort($options);
367:         $default = 1;
368:         foreach ($options as $key => $option) {
369:             if ($option{0} != '_') {
370:                 $choices[$default] = strtolower($option);
371:                 $default++;
372:             }
373:         }
374:         $choices[$default] = 'none'; // Needed since index starts at 1
375:         $this->_validations = $choices;
376:         return $choices;
377:     }
378: 
379: /**
380:  * Does individual field validation handling.
381:  *
382:  * @param string $fieldName Name of field to be validated.
383:  * @param array $metaData metadata for field
384:  * @param string $primaryKey
385:  * @return array Array of validation for the field.
386:  */
387:     public function fieldValidation($fieldName, $metaData, $primaryKey = 'id') {
388:         $defaultChoice = count($this->_validations);
389:         $validate = $alreadyChosen = array();
390: 
391:         $anotherValidator = 'y';
392:         while ($anotherValidator == 'y') {
393:             if ($this->interactive) {
394:                 $this->out();
395:                 $this->out(__d('cake_console', 'Field: %s', $fieldName));
396:                 $this->out(__d('cake_console', 'Type: %s', $metaData['type']));
397:                 $this->hr();
398:                 $this->out(__d('cake_console', 'Please select one of the following validation options:'));
399:                 $this->hr();
400:             }
401: 
402:             $prompt = '';
403:             for ($i = 1; $i < $defaultChoice; $i++) {
404:                 $prompt .= $i . ' - ' . $this->_validations[$i] . "\n";
405:             }
406:             $prompt .=  __d('cake_console', "%s - Do not do any validation on this field.\n", $defaultChoice);
407:             $prompt .= __d('cake_console', "... or enter in a valid regex validation string.\n");
408: 
409:             $methods = array_flip($this->_validations);
410:             $guess = $defaultChoice;
411:             if ($metaData['null'] != 1 && !in_array($fieldName, array($primaryKey, 'created', 'modified', 'updated'))) {
412:                 if ($fieldName == 'email') {
413:                     $guess = $methods['email'];
414:                 } elseif ($metaData['type'] == 'string' && $metaData['length'] == 36) {
415:                     $guess = $methods['uuid'];
416:                 } elseif ($metaData['type'] == 'string') {
417:                     $guess = $methods['notempty'];
418:                 } elseif ($metaData['type'] == 'integer') {
419:                     $guess = $methods['numeric'];
420:                 } elseif ($metaData['type'] == 'boolean') {
421:                     $guess = $methods['boolean'];
422:                 } elseif ($metaData['type'] == 'date') {
423:                     $guess = $methods['date'];
424:                 } elseif ($metaData['type'] == 'time') {
425:                     $guess = $methods['time'];
426:                 } elseif ($metaData['type'] == 'inet') {
427:                     $guess = $methods['ip'];
428:                 }
429:             }
430: 
431:             if ($this->interactive === true) {
432:                 $choice = $this->in($prompt, null, $guess);
433:                 if (in_array($choice, $alreadyChosen)) {
434:                     $this->out(__d('cake_console', "You have already chosen that validation rule,\nplease choose again"));
435:                     continue;
436:                 }
437:                 if (!isset($this->_validations[$choice]) && is_numeric($choice)) {
438:                     $this->out(__d('cake_console', 'Please make a valid selection.'));
439:                     continue;
440:                 }
441:                 $alreadyChosen[] = $choice;
442:             } else {
443:                 $choice = $guess;
444:             }
445: 
446:             if (isset($this->_validations[$choice])) {
447:                 $validatorName = $this->_validations[$choice];
448:             } else {
449:                 $validatorName = Inflector::slug($choice);
450:             }
451: 
452:             if ($choice != $defaultChoice) {
453:                 if (is_numeric($choice) && isset($this->_validations[$choice])) {
454:                     $validate[$validatorName] = $this->_validations[$choice];
455:                 } else {
456:                     $validate[$validatorName] = $choice;
457:                 }
458:             }
459:             if ($this->interactive == true && $choice != $defaultChoice) {
460:                 $anotherValidator = $this->in(__d('cake_console', 'Would you like to add another validation rule?'), array('y', 'n'), 'n');
461:             } else {
462:                 $anotherValidator = 'n';
463:             }
464:         }
465:         return $validate;
466:     }
467: 
468: /**
469:  * Handles associations
470:  *
471:  * @param Model $model
472:  * @return array $associations
473:  */
474:     public function doAssociations($model) {
475:         if (!is_object($model)) {
476:             return false;
477:         }
478:         if ($this->interactive === true) {
479:             $this->out(__d('cake_console', 'One moment while the associations are detected.'));
480:         }
481: 
482:         $fields = $model->schema(true);
483:         if (empty($fields)) {
484:             return array();
485:         }
486: 
487:         if (empty($this->_tables)) {
488:             $this->_tables = $this->getAllTables();
489:         }
490: 
491:         $associations = array(
492:             'belongsTo' => array(), 'hasMany' => array(), 'hasOne' => array(), 'hasAndBelongsToMany' => array()
493:         );
494: 
495:         $associations = $this->findBelongsTo($model, $associations);
496:         $associations = $this->findHasOneAndMany($model, $associations);
497:         $associations = $this->findHasAndBelongsToMany($model, $associations);
498: 
499:         if ($this->interactive !== true) {
500:             unset($associations['hasOne']);
501:         }
502: 
503:         if ($this->interactive === true) {
504:             $this->hr();
505:             if (empty($associations)) {
506:                 $this->out(__d('cake_console', 'None found.'));
507:             } else {
508:                 $this->out(__d('cake_console', 'Please confirm the following associations:'));
509:                 $this->hr();
510:                 $associations = $this->confirmAssociations($model, $associations);
511:             }
512:             $associations = $this->doMoreAssociations($model, $associations);
513:         }
514:         return $associations;
515:     }
516: 
517: /**
518:  * Find belongsTo relations and add them to the associations list.
519:  *
520:  * @param Model $model Model instance of model being generated.
521:  * @param array $associations Array of in progress associations
522:  * @return array $associations with belongsTo added in.
523:  */
524:     public function findBelongsTo($model, $associations) {
525:         $fields = $model->schema(true);
526:         foreach ($fields as $fieldName => $field) {
527:             $offset = strpos($fieldName, '_id');
528:             if ($fieldName != $model->primaryKey && $fieldName != 'parent_id' && $offset !== false) {
529:                 $tmpModelName = $this->_modelNameFromKey($fieldName);
530:                 $associations['belongsTo'][] = array(
531:                     'alias' => $tmpModelName,
532:                     'className' => $tmpModelName,
533:                     'foreignKey' => $fieldName,
534:                 );
535:             } elseif ($fieldName == 'parent_id') {
536:                 $associations['belongsTo'][] = array(
537:                     'alias' => 'Parent' . $model->name,
538:                     'className' => $model->name,
539:                     'foreignKey' => $fieldName,
540:                 );
541:             }
542:         }
543:         return $associations;
544:     }
545: 
546: /**
547:  * Find the hasOne and HasMany relations and add them to associations list
548:  *
549:  * @param Model $model Model instance being generated
550:  * @param array $associations Array of in progress associations
551:  * @return array $associations with hasOne and hasMany added in.
552:  */
553:     public function findHasOneAndMany($model, $associations) {
554:         $foreignKey = $this->_modelKey($model->name);
555:         foreach ($this->_tables as $otherTable) {
556:             $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable), $otherTable);
557:             $modelFieldsTemp = $tempOtherModel->schema(true);
558: 
559:             $pattern = '/_' . preg_quote($model->table, '/') . '|' . preg_quote($model->table, '/') . '_/';
560:             $possibleJoinTable = preg_match($pattern , $otherTable);
561:             if ($possibleJoinTable == true) {
562:                 continue;
563:             }
564:             foreach ($modelFieldsTemp as $fieldName => $field) {
565:                 $assoc = false;
566:                 if ($fieldName != $model->primaryKey && $fieldName == $foreignKey) {
567:                     $assoc = array(
568:                         'alias' => $tempOtherModel->name,
569:                         'className' => $tempOtherModel->name,
570:                         'foreignKey' => $fieldName
571:                     );
572:                 } elseif ($otherTable == $model->table && $fieldName == 'parent_id') {
573:                     $assoc = array(
574:                         'alias' => 'Child' . $model->name,
575:                         'className' => $model->name,
576:                         'foreignKey' => $fieldName
577:                     );
578:                 }
579:                 if ($assoc) {
580:                     $associations['hasOne'][] = $assoc;
581:                     $associations['hasMany'][] = $assoc;
582:                 }
583: 
584:             }
585:         }
586:         return $associations;
587:     }
588: 
589: /**
590:  * Find the hasAndBelongsToMany relations and add them to associations list
591:  *
592:  * @param Model $model Model instance being generated
593:  * @param array $associations Array of in-progress associations
594:  * @return array $associations with hasAndBelongsToMany added in.
595:  */
596:     public function findHasAndBelongsToMany($model, $associations) {
597:         $foreignKey = $this->_modelKey($model->name);
598:         foreach ($this->_tables as $otherTable) {
599:             $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable), $otherTable);
600:             $modelFieldsTemp = $tempOtherModel->schema(true);
601: 
602:             $offset = strpos($otherTable, $model->table . '_');
603:             $otherOffset = strpos($otherTable, '_' . $model->table);
604: 
605:             if ($offset !== false) {
606:                 $offset = strlen($model->table . '_');
607:                 $habtmName = $this->_modelName(substr($otherTable, $offset));
608:                 $associations['hasAndBelongsToMany'][] = array(
609:                     'alias' => $habtmName,
610:                     'className' => $habtmName,
611:                     'foreignKey' => $foreignKey,
612:                     'associationForeignKey' => $this->_modelKey($habtmName),
613:                     'joinTable' => $otherTable
614:                 );
615:             } elseif ($otherOffset !== false) {
616:                 $habtmName = $this->_modelName(substr($otherTable, 0, $otherOffset));
617:                 $associations['hasAndBelongsToMany'][] = array(
618:                     'alias' => $habtmName,
619:                     'className' => $habtmName,
620:                     'foreignKey' => $foreignKey,
621:                     'associationForeignKey' => $this->_modelKey($habtmName),
622:                     'joinTable' => $otherTable
623:                 );
624:             }
625:         }
626:         return $associations;
627:     }
628: 
629: /**
630:  * Interact with the user and confirm associations.
631:  *
632:  * @param array $model Temporary Model instance.
633:  * @param array $associations Array of associations to be confirmed.
634:  * @return array Array of confirmed associations
635:  */
636:     public function confirmAssociations($model, $associations) {
637:         foreach ($associations as $type => $settings) {
638:             if (!empty($associations[$type])) {
639:                 foreach ($associations[$type] as $i => $assoc) {
640:                     $prompt = "{$model->name} {$type} {$assoc['alias']}?";
641:                     $response = $this->in($prompt, array('y', 'n'), 'y');
642: 
643:                     if ('n' == strtolower($response)) {
644:                         unset($associations[$type][$i]);
645:                     } elseif ($type == 'hasMany') {
646:                         unset($associations['hasOne'][$i]);
647:                     }
648:                 }
649:                 $associations[$type] = array_merge($associations[$type]);
650:             }
651:         }
652:         return $associations;
653:     }
654: 
655: /**
656:  * Interact with the user and generate additional non-conventional associations
657:  *
658:  * @param Model $model Temporary model instance
659:  * @param array $associations Array of associations.
660:  * @return array Array of associations.
661:  */
662:     public function doMoreAssociations($model, $associations) {
663:         $prompt = __d('cake_console', 'Would you like to define some additional model associations?');
664:         $wannaDoMoreAssoc = $this->in($prompt, array('y', 'n'), 'n');
665:         $possibleKeys = $this->_generatePossibleKeys();
666:         while (strtolower($wannaDoMoreAssoc) == 'y') {
667:             $assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
668:             $this->out(__d('cake_console', 'What is the association type?'));
669:             $assocType = intval($this->inOptions($assocs, __d('cake_console', 'Enter a number')));
670: 
671:             $this->out(__d('cake_console', "For the following options be very careful to match your setup exactly.\nAny spelling mistakes will cause errors."));
672:             $this->hr();
673: 
674:             $alias = $this->in(__d('cake_console', 'What is the alias for this association?'));
675:             $className = $this->in(__d('cake_console', 'What className will %s use?', $alias), null, $alias );
676: 
677:             if ($assocType == 0) {
678:                 $showKeys = $possibleKeys[$model->table];
679:                 $suggestedForeignKey = $this->_modelKey($alias);
680:             } else {
681:                 $otherTable = Inflector::tableize($className);
682:                 if (in_array($otherTable, $this->_tables)) {
683:                     if ($assocType < 3) {
684:                         $showKeys = $possibleKeys[$otherTable];
685:                     } else {
686:                         $showKeys = null;
687:                     }
688:                 } else {
689:                     $otherTable = $this->in(__d('cake_console', 'What is the table for this model?'));
690:                     $showKeys = $possibleKeys[$otherTable];
691:                 }
692:                 $suggestedForeignKey = $this->_modelKey($model->name);
693:             }
694:             if (!empty($showKeys)) {
695:                 $this->out(__d('cake_console', 'A helpful List of possible keys'));
696:                 $foreignKey = $this->inOptions($showKeys, __d('cake_console', 'What is the foreignKey?'));
697:                 $foreignKey = $showKeys[intval($foreignKey)];
698:             }
699:             if (!isset($foreignKey)) {
700:                 $foreignKey = $this->in(__d('cake_console', 'What is the foreignKey? Specify your own.'), null, $suggestedForeignKey);
701:             }
702:             if ($assocType == 3) {
703:                 $associationForeignKey = $this->in(__d('cake_console', 'What is the associationForeignKey?'), null, $this->_modelKey($model->name));
704:                 $joinTable = $this->in(__d('cake_console', 'What is the joinTable?'));
705:             }
706:             $associations[$assocs[$assocType]] = array_values((array)$associations[$assocs[$assocType]]);
707:             $count = count($associations[$assocs[$assocType]]);
708:             $i = ($count > 0) ? $count : 0;
709:             $associations[$assocs[$assocType]][$i]['alias'] = $alias;
710:             $associations[$assocs[$assocType]][$i]['className'] = $className;
711:             $associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey;
712:             if ($assocType == 3) {
713:                 $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey;
714:                 $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable;
715:             }
716:             $wannaDoMoreAssoc = $this->in(__d('cake_console', 'Define another association?'), array('y', 'n'), 'y');
717:         }
718:         return $associations;
719:     }
720: 
721: /**
722:  * Finds all possible keys to use on custom associations.
723:  *
724:  * @return array array of tables and possible keys
725:  */
726:     protected function _generatePossibleKeys() {
727:         $possible = array();
728:         foreach ($this->_tables as $otherTable) {
729:             $tempOtherModel = new Model(array('table' => $otherTable, 'ds' => $this->connection));
730:             $modelFieldsTemp = $tempOtherModel->schema(true);
731:             foreach ($modelFieldsTemp as $fieldName => $field) {
732:                 if ($field['type'] == 'integer' || $field['type'] == 'string') {
733:                     $possible[$otherTable][] = $fieldName;
734:                 }
735:             }
736:         }
737:         return $possible;
738:     }
739: 
740: /**
741:  * Assembles and writes a Model file.
742:  *
743:  * @param mixed $name Model name or object
744:  * @param mixed $data if array and $name is not an object assume bake data, otherwise boolean.
745:  * @return string
746:  */
747:     public function bake($name, $data = array()) {
748:         if (is_object($name)) {
749:             if ($data == false) {
750:                 $data = array();
751:                 $data['associations'] = $this->doAssociations($name);
752:                 $data['validate'] = $this->doValidation($name);
753:             }
754:             $data['primaryKey'] = $name->primaryKey;
755:             $data['useTable'] = $name->table;
756:             $data['useDbConfig'] = $name->useDbConfig;
757:             $data['name'] = $name = $name->name;
758:         } else {
759:             $data['name'] = $name;
760:         }
761:         $defaults = array('associations' => array(), 'validate' => array(), 'primaryKey' => 'id',
762:             'useTable' => null, 'useDbConfig' => 'default', 'displayField' => null);
763:         $data = array_merge($defaults, $data);
764: 
765:         $this->Template->set($data);
766:         $this->Template->set(array(
767:             'plugin' => $this->plugin,
768:             'pluginPath' => empty($this->plugin) ? '' : $this->plugin . '.'
769:         ));
770:         $out = $this->Template->generate('classes', 'model');
771: 
772:         $path = $this->getPath();
773:         $filename = $path . $name . '.php';
774:         $this->out("\n" . __d('cake_console', 'Baking model class for %s...', $name), 1, Shell::QUIET);
775:         $this->createFile($filename, $out);
776:         ClassRegistry::flush();
777:         return $out;
778:     }
779: 
780: /**
781:  * Assembles and writes a unit test file
782:  *
783:  * @param string $className Model class name
784:  * @return string
785:  */
786:     public function bakeTest($className) {
787:         $this->Test->interactive = $this->interactive;
788:         $this->Test->plugin = $this->plugin;
789:         $this->Test->connection = $this->connection;
790:         return $this->Test->bake('Model', $className);
791:     }
792: 
793: /**
794:  * outputs the a list of possible models or controllers from database
795:  *
796:  * @param string $useDbConfig Database configuration name
797:  * @return array
798:  */
799:     public function listAll($useDbConfig = null) {
800:         $this->_tables = $this->getAllTables($useDbConfig);
801: 
802:         $this->_modelNames = array();
803:         $count = count($this->_tables);
804:         for ($i = 0; $i < $count; $i++) {
805:             $this->_modelNames[] = $this->_modelName($this->_tables[$i]);
806:         }
807:         if ($this->interactive === true) {
808:             $this->out(__d('cake_console', 'Possible Models based on your current database:'));
809:             for ($i = 0; $i < $count; $i++) {
810:                 $this->out($i + 1 . ". " . $this->_modelNames[$i]);
811:             }
812:         }
813:         return $this->_tables;
814:     }
815: 
816: /**
817:  * Interact with the user to determine the table name of a particular model
818:  *
819:  * @param string $modelName Name of the model you want a table for.
820:  * @param string $useDbConfig Name of the database config you want to get tables from.
821:  * @return string Table name
822:  */
823:     public function getTable($modelName, $useDbConfig = null) {
824:         $useTable = Inflector::tableize($modelName);
825:         if (in_array($modelName, $this->_modelNames)) {
826:             $modelNames = array_flip($this->_modelNames);
827:             $useTable = $this->_tables[$modelNames[$modelName]];
828:         }
829: 
830:         if ($this->interactive === true) {
831:             if (!isset($useDbConfig)) {
832:                 $useDbConfig = $this->connection;
833:             }
834:             $db = ConnectionManager::getDataSource($useDbConfig);
835:             $fullTableName = $db->fullTableName($useTable, false);
836:             $tableIsGood = false;
837:             if (array_search($useTable, $this->_tables) === false) {
838:                 $this->out();
839:                 $this->out(__d('cake_console', "Given your model named '%s',\nCake would expect a database table named '%s'", $modelName, $fullTableName));
840:                 $tableIsGood = $this->in(__d('cake_console', 'Do you want to use this table?'), array('y', 'n'), 'y');
841:             }
842:             if (strtolower($tableIsGood) == 'n') {
843:                 $useTable = $this->in(__d('cake_console', 'What is the name of the table?'));
844:             }
845:         }
846:         return $useTable;
847:     }
848: 
849: /**
850:  * Get an Array of all the tables in the supplied connection
851:  * will halt the script if no tables are found.
852:  *
853:  * @param string $useDbConfig Connection name to scan.
854:  * @return array Array of tables in the database.
855:  */
856:     public function getAllTables($useDbConfig = null) {
857:         if (!isset($useDbConfig)) {
858:             $useDbConfig = $this->connection;
859:         }
860: 
861:         $tables = array();
862:         $db = ConnectionManager::getDataSource($useDbConfig);
863:         $db->cacheSources = false;
864:         $usePrefix = empty($db->config['prefix']) ? '' : $db->config['prefix'];
865:         if ($usePrefix) {
866:             foreach ($db->listSources() as $table) {
867:                 if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
868:                     $tables[] = substr($table, strlen($usePrefix));
869:                 }
870:             }
871:         } else {
872:             $tables = $db->listSources();
873:         }
874:         if (empty($tables)) {
875:             $this->err(__d('cake_console', 'Your database does not have any tables.'));
876:             $this->_stop();
877:         }
878:         return $tables;
879:     }
880: 
881: /**
882:  * Forces the user to specify the model he wants to bake, and returns the selected model name.
883:  *
884:  * @param string $useDbConfig Database config name
885:  * @return string the model name
886:  */
887:     public function getName($useDbConfig = null) {
888:         $this->listAll($useDbConfig);
889: 
890:         $enteredModel = '';
891: 
892:         while ($enteredModel == '') {
893:             $enteredModel = $this->in(__d('cake_console', "Enter a number from the list above,\ntype in the name of another model, or 'q' to exit"), null, 'q');
894: 
895:             if ($enteredModel === 'q') {
896:                 $this->out(__d('cake_console', 'Exit'));
897:                 $this->_stop();
898:             }
899: 
900:             if ($enteredModel == '' || intval($enteredModel) > count($this->_modelNames)) {
901:                 $this->err(__d('cake_console', "The model name you supplied was empty,\nor the number you selected was not an option. Please try again."));
902:                 $enteredModel = '';
903:             }
904:         }
905:         if (intval($enteredModel) > 0 && intval($enteredModel) <= count($this->_modelNames)) {
906:             $currentModelName = $this->_modelNames[intval($enteredModel) - 1];
907:         } else {
908:             $currentModelName = $enteredModel;
909:         }
910:         return $currentModelName;
911:     }
912: 
913: /**
914:  * get the option parser.
915:  *
916:  * @return void
917:  */
918:     public function getOptionParser() {
919:         $parser = parent::getOptionParser();
920:         return $parser->description(
921:                 __d('cake_console', 'Bake models.')
922:             )->addArgument('name', array(
923:                 'help' => __d('cake_console', 'Name of the model to bake. Can use Plugin.name to bake plugin models.')
924:             ))->addSubcommand('all', array(
925:                 'help' => __d('cake_console', 'Bake all model files with associations and validation.')
926:             ))->addOption('plugin', array(
927:                 'short' => 'p',
928:                 'help' => __d('cake_console', 'Plugin to bake the model into.')
929:             ))->addOption('connection', array(
930:                 'short' => 'c',
931:                 'help' => __d('cake_console', 'The connection the model table is on.')
932:             ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));
933:     }
934: 
935: /**
936:  * Interact with FixtureTask to automatically bake fixtures when baking models.
937:  *
938:  * @param string $className Name of class to bake fixture for
939:  * @param string $useTable Optional table name for fixture to use.
940:  * @return void
941:  * @see FixtureTask::bake
942:  */
943:     public function bakeFixture($className, $useTable = null) {
944:         $this->Fixture->interactive = $this->interactive;
945:         $this->Fixture->connection = $this->connection;
946:         $this->Fixture->plugin = $this->plugin;
947:         $this->Fixture->bake($className, $useTable);
948:     }
949: }
950: 
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs