model.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: model.php 8260 2009-07-28 20:01:42Z DarkAngelBGE $ */
00003 /**
00004  * The ModelTask handles creating and updating models files.
00005  *
00006  * Long description for file
00007  *
00008  * PHP versions 4 and 5
00009  *
00010  * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
00011  * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00012  *
00013  * Licensed under The MIT License
00014  * Redistributions of files must retain the above copyright notice.
00015  *
00016  * @filesource
00017  * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
00018  * @link          http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00019  * @package       cake
00020  * @subpackage    cake.cake.console.libs.tasks
00021  * @since         CakePHP(tm) v 1.2
00022  * @version       $Revision: 8260 $
00023  * @modifiedby    $LastChangedBy: DarkAngelBGE $
00024  * @lastmodified  $Date: 2009-07-28 16:01:42 -0400 (Tue, 28 Jul 2009) $
00025  * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
00026  */
00027 App::import('Model', 'ConnectionManager');
00028 /**
00029  * Task class for creating and updating model files.
00030  *
00031  * @package       cake
00032  * @subpackage    cake.cake.console.libs.tasks
00033  */
00034 class ModelTask extends Shell {
00035 /**
00036  * Name of plugin
00037  *
00038  * @var string
00039  * @access public
00040  */
00041     var $plugin = null;
00042 /**
00043  * path to MODELS directory
00044  *
00045  * @var string
00046  * @access public
00047  */
00048     var $path = MODELS;
00049 /**
00050  * tasks
00051  *
00052  * @var array
00053  * @access public
00054  */
00055     var $tasks = array('DbConfig');
00056 /**
00057  * Execution method always used for tasks
00058  *
00059  * @access public
00060  */
00061     function execute() {
00062         if (empty($this->args)) {
00063             $this->__interactive();
00064         }
00065 
00066         if (!empty($this->args[0])) {
00067             $model = Inflector::camelize($this->args[0]);
00068             if ($this->bake($model)) {
00069                 if ($this->_checkUnitTest()) {
00070                     $this->bakeTest($model);
00071                 }
00072             }
00073         }
00074     }
00075 /**
00076  * Handles interactive baking
00077  *
00078  * @access private
00079  */
00080     function __interactive() {
00081         $this->hr();
00082         $this->out(sprintf("Bake Model\nPath: %s", $this->path));
00083         $this->hr();
00084         $this->interactive = true;
00085 
00086         $useTable = null;
00087         $primaryKey = 'id';
00088         $validate = array();
00089         $associations = array('belongsTo'=> array(), 'hasOne'=> array(), 'hasMany' => array(), 'hasAndBelongsToMany'=> array());
00090 
00091         $useDbConfig = 'default';
00092         $configs = get_class_vars('DATABASE_CONFIG');
00093 
00094         if (!is_array($configs)) {
00095             return $this->DbConfig->execute();
00096         }
00097 
00098         $connections = array_keys($configs);
00099         if (count($connections) > 1) {
00100             $useDbConfig = $this->in(__('Use Database Config', true) .':', $connections, 'default');
00101         }
00102 
00103         $currentModelName = $this->getName($useDbConfig);
00104         $db =& ConnectionManager::getDataSource($useDbConfig);
00105         $useTable = Inflector::tableize($currentModelName);
00106         $fullTableName = $db->fullTableName($useTable, false);
00107         $tableIsGood = false;
00108 
00109         if (array_search($useTable, $this->__tables) === false) {
00110             $this->out('');
00111             $this->out(sprintf(__("Given your model named '%s', Cake would expect a database table named %s", true), $currentModelName, $fullTableName));
00112             $tableIsGood = $this->in(__('Do you want to use this table?', true), array('y','n'), 'y');
00113         }
00114 
00115         if (strtolower($tableIsGood) == 'n' || strtolower($tableIsGood) == 'no') {
00116             $useTable = $this->in(__('What is the name of the table (enter "null" to use NO table)?', true));
00117         }
00118 
00119         while ($tableIsGood == false && strtolower($useTable) != 'null') {
00120             if (is_array($this->__tables) && !in_array($useTable, $this->__tables)) {
00121                 $fullTableName = $db->fullTableName($useTable, false);
00122                 $this->out($fullTableName . ' does not exist.');
00123                 $useTable = $this->in(__('What is the name of the table (enter "null" to use NO table)?', true));
00124                 $tableIsGood = false;
00125             } else {
00126                 $tableIsGood = true;
00127             }
00128         }
00129 
00130         $wannaDoValidation = $this->in(__('Would you like to supply validation criteria for the fields in your model?', true), array('y','n'), 'y');
00131 
00132         if (in_array($useTable, $this->__tables)) {
00133             App::import('Model');
00134             $tempModel = new Model(array('name' => $currentModelName, 'table' => $useTable, 'ds' => $useDbConfig));
00135 
00136             $fields = $tempModel->schema();
00137             if (!array_key_exists('id', $fields)) {
00138                 foreach ($fields as $name => $field) {
00139                     if (isset($field['key']) && $field['key'] == 'primary') {
00140                         break;
00141                     }
00142                 }
00143                 $primaryKey = $this->in(__('What is the primaryKey?', true), null, $name);
00144             }
00145         }
00146 
00147         if (array_search($useTable, $this->__tables) !== false && (strtolower($wannaDoValidation) == 'y' || strtolower($wannaDoValidation) == 'yes')) {
00148             $validate = $this->doValidation($tempModel);
00149         }
00150 
00151         $wannaDoAssoc = $this->in(__('Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)?', true), array('y','n'), 'y');
00152         if ((strtolower($wannaDoAssoc) == 'y' || strtolower($wannaDoAssoc) == 'yes')) {
00153             $associations = $this->doAssociations($tempModel);
00154         }
00155 
00156         $this->out('');
00157         $this->hr();
00158         $this->out(__('The following Model will be created:', true));
00159         $this->hr();
00160         $this->out("Name:       " . $currentModelName);
00161 
00162         if ($useDbConfig !== 'default') {
00163             $this->out("DB Config:  " . $useDbConfig);
00164         }
00165         if ($fullTableName !== Inflector::tableize($currentModelName)) {
00166             $this->out("DB Table:   " . $fullTableName);
00167         }
00168         if ($primaryKey != 'id') {
00169             $this->out("Primary Key: " . $primaryKey);
00170         }
00171         if (!empty($validate)) {
00172             $this->out("Validation: " . print_r($validate, true));
00173         }
00174         if (!empty($associations)) {
00175             $this->out("Associations:");
00176 
00177             if (!empty($associations['belongsTo'])) {
00178                 for ($i = 0; $i < count($associations['belongsTo']); $i++) {
00179                     $this->out("            $currentModelName belongsTo {$associations['belongsTo'][$i]['alias']}");
00180                 }
00181             }
00182 
00183             if (!empty($associations['hasOne'])) {
00184                 for ($i = 0; $i < count($associations['hasOne']); $i++) {
00185                     $this->out("            $currentModelName hasOne    {$associations['hasOne'][$i]['alias']}");
00186                 }
00187             }
00188 
00189             if (!empty($associations['hasMany'])) {
00190                 for ($i = 0; $i < count($associations['hasMany']); $i++) {
00191                     $this->out("            $currentModelName hasMany   {$associations['hasMany'][$i]['alias']}");
00192                 }
00193             }
00194 
00195             if (!empty($associations['hasAndBelongsToMany'])) {
00196                 for ($i = 0; $i < count($associations['hasAndBelongsToMany']); $i++) {
00197                     $this->out("            $currentModelName hasAndBelongsToMany {$associations['hasAndBelongsToMany'][$i]['alias']}");
00198                 }
00199             }
00200         }
00201         $this->hr();
00202         $looksGood = $this->in(__('Look okay?', true), array('y','n'), 'y');
00203 
00204         if (strtolower($looksGood) == 'y' || strtolower($looksGood) == 'yes') {
00205             if ($this->bake($currentModelName, $associations, $validate, $primaryKey, $useTable, $useDbConfig)) {
00206                 if ($this->_checkUnitTest()) {
00207                     $this->bakeTest($currentModelName, $useTable, $associations);
00208                 }
00209             }
00210         } else {
00211             return false;
00212         }
00213     }
00214 /**
00215  * Handles associations
00216  *
00217  * @param object $model
00218  * @param boolean $interactive
00219  * @return array $validate
00220  * @access public
00221  */
00222     function doValidation(&$model, $interactive = true) {
00223         if (!is_object($model)) {
00224             return false;
00225         }
00226         $fields = $model->schema();
00227 
00228         if (empty($fields)) {
00229             return false;
00230         }
00231 
00232         $validate = array();
00233 
00234         $options = array();
00235 
00236         if (class_exists('Validation')) {
00237             $parent = get_class_methods(get_parent_class('Validation'));
00238             $options = array_diff(get_class_methods('Validation'), $parent);
00239         }
00240 
00241         foreach ($fields as $fieldName => $field) {
00242             $prompt = 'Field: ' . $fieldName . "\n";
00243             $prompt .= 'Type: ' . $field['type'] . "\n";
00244             $prompt .= '---------------------------------------------------------------'."\n";
00245             $prompt .= 'Please select one of the following validation options:'."\n";
00246             $prompt .= '---------------------------------------------------------------'."\n";
00247 
00248             sort($options);
00249 
00250             $skip = 1;
00251             foreach ($options as $key => $option) {
00252                 if ($option{0} != '_' && strtolower($option) != 'getinstance') {
00253                     $prompt .= "{$skip} - {$option}\n";
00254                     $choices[$skip] = strtolower($option);
00255                     $skip++;
00256                 }
00257             }
00258 
00259             $methods = array_flip($choices);
00260 
00261             $prompt .=  "{$skip} - Do not do any validation on this field.\n";
00262             $prompt .= "... or enter in a valid regex validation string.\n";
00263 
00264             $guess = $skip;
00265             if ($field['null'] != 1 && $fieldName != $model->primaryKey && !in_array($fieldName, array('created', 'modified', 'updated'))) {
00266                 if ($fieldName == 'email') {
00267                     $guess = $methods['email'];
00268                 } elseif ($field['type'] == 'string') {
00269                     $guess = $methods['notempty'];
00270                 } elseif ($field['type'] == 'integer') {
00271                     $guess = $methods['numeric'];
00272                 } elseif ($field['type'] == 'boolean') {
00273                     $guess = $methods['numeric'];
00274                 } elseif ($field['type'] == 'datetime') {
00275                     $guess = $methods['date'];
00276                 }
00277             }
00278 
00279             if ($interactive === true) {
00280                 $this->out('');
00281                 $choice = $this->in($prompt, null, $guess);
00282             } else {
00283                 $choice = $guess;
00284             }
00285             if ($choice != $skip) {
00286                 if (is_numeric($choice) && isset($choices[$choice])) {
00287                     $validate[$fieldName] = $choices[$choice];
00288                 } else {
00289                     $validate[$fieldName] = $choice;
00290                 }
00291             }
00292         }
00293         return $validate;
00294     }
00295 
00296 /**
00297  * Handles associations
00298  *
00299  * @param object $model
00300  * @param boolean $interactive
00301  * @return array $assocaitons
00302  * @access public
00303  */
00304     function doAssociations(&$model, $interactive = true) {
00305 
00306         if (!is_object($model)) {
00307             return false;
00308         }
00309         $this->out(__('One moment while the associations are detected.', true));
00310 
00311         $fields = $model->schema();
00312 
00313         if (empty($fields)) {
00314             return false;
00315         }
00316 
00317         $primaryKey = $model->primaryKey;
00318         $foreignKey = $this->_modelKey($model->name);
00319 
00320         $associations = array('belongsTo' => array(), 'hasMany' => array(), 'hasOne'=> array(), 'hasAndBelongsToMany' => array());
00321         $possibleKeys = array();
00322 
00323         //Look for belongsTo
00324         $i = 0;
00325         foreach ($fields as $fieldName => $field) {
00326             $offset = strpos($fieldName, '_id');
00327             if ($fieldName != $model->primaryKey && $offset !== false) {
00328                 $tmpModelName = $this->_modelNameFromKey($fieldName);
00329                 $associations['belongsTo'][$i]['alias'] = $tmpModelName;
00330                 $associations['belongsTo'][$i]['className'] = $tmpModelName;
00331                 $associations['belongsTo'][$i]['foreignKey'] = $fieldName;
00332                 $i++;
00333             }
00334         }
00335         //Look for hasOne and hasMany and hasAndBelongsToMany
00336         $i = $j = 0;
00337 
00338         foreach ($this->__tables as $otherTable) {
00339             App::import('Model');
00340             $tmpModelName = $this->_modelName($otherTable);
00341             $tempOtherModel = & new Model(array('name' => $tmpModelName, 'table' => $otherTable, 'ds' => $model->useDbConfig));
00342             $modelFieldsTemp = $tempOtherModel->schema();
00343 
00344             $offset = strpos($otherTable, $model->table . '_');
00345             $otherOffset = strpos($otherTable, '_' . $model->table);
00346 
00347             foreach ($modelFieldsTemp as $fieldName => $field) {
00348                 if ($field['type'] == 'integer' || $field['type'] == 'string') {
00349                     $possibleKeys[$otherTable][] = $fieldName;
00350                 }
00351                 if ($fieldName != $model->primaryKey && $fieldName == $foreignKey && $offset === false && $otherOffset === false) {
00352                     $associations['hasOne'][$j]['alias'] = $tempOtherModel->name;
00353                     $associations['hasOne'][$j]['className'] = $tempOtherModel->name;
00354                     $associations['hasOne'][$j]['foreignKey'] = $fieldName;
00355 
00356                     $associations['hasMany'][$j]['alias'] = $tempOtherModel->name;
00357                     $associations['hasMany'][$j]['className'] = $tempOtherModel->name;
00358                     $associations['hasMany'][$j]['foreignKey'] = $fieldName;
00359                     $j++;
00360                 }
00361             }
00362 
00363             if ($offset !== false) {
00364                 $offset = strlen($model->table . '_');
00365                 $tmpModelName = $this->_modelName(substr($otherTable, $offset));
00366                 $associations['hasAndBelongsToMany'][$i]['alias'] = $tmpModelName;
00367                 $associations['hasAndBelongsToMany'][$i]['className'] = $tmpModelName;
00368                 $associations['hasAndBelongsToMany'][$i]['foreignKey'] = $foreignKey;
00369                 $associations['hasAndBelongsToMany'][$i]['associationForeignKey'] = $this->_modelKey($tmpModelName);
00370                 $associations['hasAndBelongsToMany'][$i]['joinTable'] = $otherTable;
00371                 $i++;
00372             }
00373 
00374             if ($otherOffset !== false) {
00375                 $tmpModelName = $this->_modelName(substr($otherTable, 0, $otherOffset));
00376                 $associations['hasAndBelongsToMany'][$i]['alias'] = $tmpModelName;
00377                 $associations['hasAndBelongsToMany'][$i]['className'] = $tmpModelName;
00378                 $associations['hasAndBelongsToMany'][$i]['foreignKey'] = $foreignKey;
00379                 $associations['hasAndBelongsToMany'][$i]['associationForeignKey'] = $this->_modelKey($tmpModelName);
00380                 $associations['hasAndBelongsToMany'][$i]['joinTable'] = $otherTable;
00381                 $i++;
00382             }
00383         }
00384 
00385         if ($interactive !== true) {
00386             unset($associations['hasOne']);
00387         }
00388 
00389         if ($interactive === true) {
00390             $this->hr();
00391             if (empty($associations)) {
00392                 $this->out(__('None found.', true));
00393             } else {
00394                 $this->out(__('Please confirm the following associations:', true));
00395                 $this->hr();
00396                 foreach ($associations as $type => $settings) {
00397                     if (!empty($associations[$type])) {
00398                         $count = count($associations[$type]);
00399                         $response = 'y';
00400                         for ($i = 0; $i < $count; $i++) {
00401                             $prompt = "{$model->name} {$type} {$associations[$type][$i]['alias']}";
00402                             $response = $this->in("{$prompt}?", array('y','n'), 'y');
00403 
00404                             if ('n' == strtolower($response) || 'no' == strtolower($response)) {
00405                                 unset($associations[$type][$i]);
00406                             } else {
00407                                 if ($model->name === $associations[$type][$i]['alias']) {
00408                                     if ($type === 'belongsTo') {
00409                                         $alias = 'Parent' . $associations[$type][$i]['alias'];
00410                                     }
00411                                     if ($type === 'hasOne' || $type === 'hasMany') {
00412                                         $alias = 'Child' . $associations[$type][$i]['alias'];
00413                                     }
00414 
00415                                     $alternateAlias = $this->in(sprintf(__('This is a self join. Use %s as the alias', true), $alias), array('y', 'n'), 'y');
00416 
00417                                     if ('n' == strtolower($alternateAlias) || 'no' == strtolower($alternateAlias)) {
00418                                         $associations[$type][$i]['alias'] = $this->in(__('Specify an alternate alias.', true));
00419                                     } else {
00420                                         $associations[$type][$i]['alias'] = $alias;
00421                                     }
00422                                 }
00423                             }
00424                         }
00425                         $associations[$type] = array_merge($associations[$type]);
00426                     }
00427                 }
00428             }
00429 
00430             $wannaDoMoreAssoc = $this->in(__('Would you like to define some additional model associations?', true), array('y','n'), 'n');
00431 
00432             while ((strtolower($wannaDoMoreAssoc) == 'y' || strtolower($wannaDoMoreAssoc) == 'yes')) {
00433                 $assocs = array(1 => 'belongsTo', 2 => 'hasOne', 3 => 'hasMany', 4 => 'hasAndBelongsToMany');
00434                 $bad = true;
00435                 while ($bad) {
00436                     $this->out(__('What is the association type?', true));
00437                     $prompt = "1. belongsTo\n";
00438                     $prompt .= "2. hasOne\n";
00439                     $prompt .= "3. hasMany\n";
00440                     $prompt .= "4. hasAndBelongsToMany\n";
00441                     $assocType = intval($this->in($prompt, null, __("Enter a number", true)));
00442 
00443                     if (intval($assocType) < 1 || intval($assocType) > 4) {
00444                         $this->out(__('The selection you entered was invalid. Please enter a number between 1 and 4.', true));
00445                     } else {
00446                         $bad = false;
00447                     }
00448                 }
00449                 $this->out(__('For the following options be very careful to match your setup exactly. Any spelling mistakes will cause errors.', true));
00450                 $this->hr();
00451                 $alias = $this->in(__('What is the alias for this association?', true));
00452                 $className = $this->in(sprintf(__('What className will %s use?', true), $alias), null, $alias );
00453                 $suggestedForeignKey = null;
00454                 if ($assocType == '1') {
00455                     $showKeys = $possibleKeys[$model->table];
00456                     $suggestedForeignKey = $this->_modelKey($alias);
00457                 } else {
00458                     $otherTable = Inflector::tableize($className);
00459                     if (in_array($otherTable, $this->__tables)) {
00460                         if ($assocType < '4') {
00461                             $showKeys = $possibleKeys[$otherTable];
00462                         } else {
00463                             $showKeys = null;
00464                         }
00465                     } else {
00466                         $otherTable = $this->in(__('What is the table for this model?', true));
00467                         $showKeys = $possibleKeys[$otherTable];
00468                     }
00469                     $suggestedForeignKey = $this->_modelKey($model->name);
00470                 }
00471                 if (!empty($showKeys)) {
00472                     $this->out(__('A helpful List of possible keys', true));
00473                     for ($i = 0; $i < count($showKeys); $i++) {
00474                         $this->out($i + 1 . ". " . $showKeys[$i]);
00475                     }
00476                     $foreignKey = $this->in(__('What is the foreignKey?', true), null, __("Enter a number", true));
00477                     if (intval($foreignKey) > 0 && intval($foreignKey) <= $i ) {
00478                         $foreignKey = $showKeys[intval($foreignKey) - 1];
00479                     }
00480                 }
00481                 if (!isset($foreignKey)) {
00482                     $foreignKey = $this->in(__('What is the foreignKey? Specify your own.', true), null, $suggestedForeignKey);
00483                 }
00484                 if ($assocType == '4') {
00485                     $associationForeignKey = $this->in(__('What is the associationForeignKey?', true), null, $this->_modelKey($model->name));
00486                     $joinTable = $this->in(__('What is the joinTable?', true));
00487                 }
00488                 $associations[$assocs[$assocType]] = array_values((array)$associations[$assocs[$assocType]]);
00489                 $count = count($associations[$assocs[$assocType]]);
00490                 $i = ($count > 0) ? $count : 0;
00491                 $associations[$assocs[$assocType]][$i]['alias'] = $alias;
00492                 $associations[$assocs[$assocType]][$i]['className'] = $className;
00493                 $associations[$assocs[$assocType]][$i]['foreignKey'] = $foreignKey;
00494                 if ($assocType == '4') {
00495                     $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey;
00496                     $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable;
00497                 }
00498                 $wannaDoMoreAssoc = $this->in(__('Define another association?', true), array('y','n'), 'y');
00499             }
00500         }
00501         return $associations;
00502     }
00503 /**
00504  * Assembles and writes a Model file.
00505  *
00506  * @param mixed $name Model name or object
00507  * @param mixed $associations if array and $name is not an object assume Model associations array otherwise boolean interactive
00508  * @param array $validate Validation rules
00509  * @param string $primaryKey Primary key to use
00510  * @param string $useTable Table to use
00511  * @param string $useDbConfig Database configuration setting to use
00512  * @access private
00513  */
00514     function bake($name, $associations = array(),  $validate = array(), $primaryKey = 'id', $useTable = null, $useDbConfig = 'default') {
00515 
00516         if (is_object($name)) {
00517             if (!is_array($associations)) {
00518                 $associations = $this->doAssociations($name, $associations);
00519                 $validate = $this->doValidation($name, $associations);
00520             }
00521             $primaryKey = $name->primaryKey;
00522             $useTable = $name->table;
00523             $useDbConfig = $name->useDbConfig;
00524             $name = $name->name;
00525         }
00526 
00527         $out = "<?php\n";
00528         $out .= "class {$name} extends {$this->plugin}AppModel {\n\n";
00529         $out .= "\tvar \$name = '{$name}';\n";
00530 
00531         if ($useDbConfig !== 'default') {
00532             $out .= "\tvar \$useDbConfig = '$useDbConfig';\n";
00533         }
00534 
00535         if (($useTable && $useTable !== Inflector::tableize($name)) || $useTable === false) {
00536             $table = "'$useTable'";
00537             if (!$useTable) {
00538                 $table = 'false';
00539             }
00540             $out .= "\tvar \$useTable = $table;\n";
00541         }
00542 
00543         if ($primaryKey !== 'id') {
00544             $out .= "\tvar \$primaryKey = '$primaryKey';\n";
00545         }
00546 
00547         $validateCount = count($validate);
00548         if (is_array($validate) && $validateCount > 0) {
00549             $out .= "\tvar \$validate = array(\n";
00550             $keys = array_keys($validate);
00551             for ($i = 0; $i < $validateCount; $i++) {
00552                 $val = "'" . $validate[$keys[$i]] . "'";
00553                 $out .= "\t\t'" . $keys[$i] . "' => array({$val})";
00554                 if ($i + 1 < $validateCount) {
00555                     $out .= ",";
00556                 }
00557                 $out .= "\n";
00558             }
00559             $out .= "\t);\n";
00560         }
00561         $out .= "\n";
00562 
00563         if (!empty($associations)) {
00564             if (!empty($associations['belongsTo']) || !empty($associations['hasOne']) || !empty($associations['hasMany']) || !empty($associations['hasAndBelongsToMany'])) {
00565                 $out.= "\t//The Associations below have been created with all possible keys, those that are not needed can be removed\n";
00566             }
00567 
00568             if (!empty($associations['belongsTo'])) {
00569                 $out .= "\tvar \$belongsTo = array(\n";
00570                 $belongsToCount = count($associations['belongsTo']);
00571 
00572                 for ($i = 0; $i < $belongsToCount; $i++) {
00573                     $out .= "\t\t'{$associations['belongsTo'][$i]['alias']}' => array(\n";
00574                     $out .= "\t\t\t'className' => '{$associations['belongsTo'][$i]['className']}',\n";
00575                     $out .= "\t\t\t'foreignKey' => '{$associations['belongsTo'][$i]['foreignKey']}',\n";
00576                     $out .= "\t\t\t'conditions' => '',\n";
00577                     $out .= "\t\t\t'fields' => '',\n";
00578                     $out .= "\t\t\t'order' => ''\n";
00579                     $out .= "\t\t)";
00580                     if ($i + 1 < $belongsToCount) {
00581                         $out .= ",";
00582                     }
00583                     $out .= "\n";
00584 
00585                 }
00586                 $out .= "\t);\n\n";
00587             }
00588 
00589             if (!empty($associations['hasOne'])) {
00590                 $out .= "\tvar \$hasOne = array(\n";
00591                 $hasOneCount = count($associations['hasOne']);
00592 
00593                 for ($i = 0; $i < $hasOneCount; $i++) {
00594                     $out .= "\t\t'{$associations['hasOne'][$i]['alias']}' => array(\n";
00595                     $out .= "\t\t\t'className' => '{$associations['hasOne'][$i]['className']}',\n";
00596                     $out .= "\t\t\t'foreignKey' => '{$associations['hasOne'][$i]['foreignKey']}',\n";
00597                     $out .= "\t\t\t'dependent' => false,\n";
00598                     $out .= "\t\t\t'conditions' => '',\n";
00599                     $out .= "\t\t\t'fields' => '',\n";
00600                     $out .= "\t\t\t'order' => ''\n";
00601                     $out .= "\t\t)";
00602                     if ($i + 1 < $hasOneCount) {
00603                         $out .= ",";
00604                     }
00605                     $out .= "\n";
00606 
00607                 }
00608                 $out .= "\t);\n\n";
00609             }
00610 
00611             if (!empty($associations['hasMany'])) {
00612                 $out .= "\tvar \$hasMany = array(\n";
00613                 $hasManyCount = count($associations['hasMany']);
00614 
00615                 for ($i = 0; $i < $hasManyCount; $i++) {
00616                     $out .= "\t\t'{$associations['hasMany'][$i]['alias']}' => array(\n";
00617                     $out .= "\t\t\t'className' => '{$associations['hasMany'][$i]['className']}',\n";
00618                     $out .= "\t\t\t'foreignKey' => '{$associations['hasMany'][$i]['foreignKey']}',\n";
00619                     $out .= "\t\t\t'dependent' => false,\n";
00620                     $out .= "\t\t\t'conditions' => '',\n";
00621                     $out .= "\t\t\t'fields' => '',\n";
00622                     $out .= "\t\t\t'order' => '',\n";
00623                     $out .= "\t\t\t'limit' => '',\n";
00624                     $out .= "\t\t\t'offset' => '',\n";
00625                     $out .= "\t\t\t'exclusive' => '',\n";
00626                     $out .= "\t\t\t'finderQuery' => '',\n";
00627                     $out .= "\t\t\t'counterQuery' => ''\n";
00628                     $out .= "\t\t)";
00629                     if ($i + 1 < $hasManyCount) {
00630                         $out .= ",";
00631                     }
00632                     $out .= "\n";
00633                 }
00634                 $out .= "\t);\n\n";
00635             }
00636 
00637             if (!empty($associations['hasAndBelongsToMany'])) {
00638                 $out .= "\tvar \$hasAndBelongsToMany = array(\n";
00639                 $hasAndBelongsToManyCount = count($associations['hasAndBelongsToMany']);
00640 
00641                 for ($i = 0; $i < $hasAndBelongsToManyCount; $i++) {
00642                     $out .= "\t\t'{$associations['hasAndBelongsToMany'][$i]['alias']}' => array(\n";
00643                     $out .= "\t\t\t'className' => '{$associations['hasAndBelongsToMany'][$i]['className']}',\n";
00644                     $out .= "\t\t\t'joinTable' => '{$associations['hasAndBelongsToMany'][$i]['joinTable']}',\n";
00645                     $out .= "\t\t\t'foreignKey' => '{$associations['hasAndBelongsToMany'][$i]['foreignKey']}',\n";
00646                     $out .= "\t\t\t'associationForeignKey' => '{$associations['hasAndBelongsToMany'][$i]['associationForeignKey']}',\n";
00647                     $out .= "\t\t\t'unique' => true,\n";
00648                     $out .= "\t\t\t'conditions' => '',\n";
00649                     $out .= "\t\t\t'fields' => '',\n";
00650                     $out .= "\t\t\t'order' => '',\n";
00651                     $out .= "\t\t\t'limit' => '',\n";
00652                     $out .= "\t\t\t'offset' => '',\n";
00653                     $out .= "\t\t\t'finderQuery' => '',\n";
00654                     $out .= "\t\t\t'deleteQuery' => '',\n";
00655                     $out .= "\t\t\t'insertQuery' => ''\n";
00656                     $out .= "\t\t)";
00657                     if ($i + 1 < $hasAndBelongsToManyCount) {
00658                         $out .= ",";
00659                     }
00660                     $out .= "\n";
00661                 }
00662                 $out .= "\t);\n\n";
00663             }
00664         }
00665         $out .= "}\n";
00666         $out .= "?>";
00667         $filename = $this->path . Inflector::underscore($name) . '.php';
00668         $this->out("\nBaking model class for $name...");
00669         return $this->createFile($filename, $out);
00670     }
00671 
00672 /**
00673  * Assembles and writes a unit test file
00674  *
00675  * @param string $className Model class name
00676  * @access private
00677  */
00678     function bakeTest($className, $useTable = null, $associations = array()) {
00679         $results = $this->fixture($className, $useTable);
00680 
00681         if ($results) {
00682             $fixtureInc = 'app';
00683             if ($this->plugin) {
00684                 $fixtureInc = 'plugin.'.Inflector::underscore($this->plugin);
00685             }
00686 
00687             $fixture[] = "'{$fixtureInc}." . Inflector::underscore($className) ."'";
00688 
00689             if (!empty($associations)) {
00690                 $assoc[] = Set::extract($associations, 'belongsTo.{n}.className');
00691                 $assoc[] = Set::extract($associations, 'hasOne.{n}.className');
00692                 $assoc[] = Set::extract($associations, 'hasMany.{n}.className');
00693                 foreach ($assoc as $key => $value) {
00694                     if (is_array($value)) {
00695                         foreach ($value as $class) {
00696                             $fixture[] = "'{$fixtureInc}." . Inflector::underscore($class) ."'";
00697                         }
00698                     }
00699                 }
00700             }
00701             $fixture = join(", ", $fixture);
00702 
00703             $import = $className;
00704             if (isset($this->plugin)) {
00705                 $import = $this->plugin . '.' . $className;
00706             }
00707 
00708             $out = "App::import('Model', '$import');\n\n";
00709             $out .= "class {$className}TestCase extends CakeTestCase {\n";
00710             $out .= "\tvar \${$className} = null;\n";
00711             $out .= "\tvar \$fixtures = array($fixture);\n\n";
00712             $out .= "\tfunction startTest() {\n";
00713             $out .= "\t\t\$this->{$className} =& ClassRegistry::init('{$className}');\n";
00714             $out .= "\t}\n\n";
00715             $out .= "\tfunction test{$className}Instance() {\n";
00716             $out .= "\t\t\$this->assertTrue(is_a(\$this->{$className}, '{$className}'));\n";
00717             $out .= "\t}\n\n";
00718             $out .= "\tfunction test{$className}Find() {\n";
00719             $out .= "\t\t\$this->{$className}->recursive = -1;\n";
00720             $out .= "\t\t\$results = \$this->{$className}->find('first');\n\t\t\$this->assertTrue(!empty(\$results));\n\n";
00721             $out .= "\t\t\$expected = array('$className' => array(\n$results\n\t\t));\n";
00722             $out .= "\t\t\$this->assertEqual(\$results, \$expected);\n";
00723             $out .= "\t}\n";
00724             $out .= "}\n";
00725 
00726             $path = MODEL_TESTS;
00727             if (isset($this->plugin)) {
00728                 $pluginPath = 'plugins' . DS . Inflector::underscore($this->plugin) . DS;
00729                 $path = APP . $pluginPath . 'tests' . DS . 'cases' . DS . 'models' . DS;
00730             }
00731 
00732             $filename = Inflector::underscore($className).'.test.php';
00733             $this->out("\nBaking unit test for $className...");
00734 
00735             $header = '$Id';
00736             $content = "<?php \n/* SVN FILE: $header$ */\n/* " . $className . " Test cases generated on: " . date('Y-m-d H:i:s') . " : " . time() . "*/\n{$out}?>";
00737             return $this->createFile($path . $filename, $content);
00738         }
00739         return false;
00740     }
00741 /**
00742  * outputs the a list of possible models or controllers from database
00743  *
00744  * @param string $useDbConfig Database configuration name
00745  * @access public
00746  */
00747     function listAll($useDbConfig = 'default', $interactive = true) {
00748         $db =& ConnectionManager::getDataSource($useDbConfig);
00749         $usePrefix = empty($db->config['prefix']) ? '' : $db->config['prefix'];
00750         if ($usePrefix) {
00751             $tables = array();
00752             foreach ($db->listSources() as $table) {
00753                 if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
00754                     $tables[] = substr($table, strlen($usePrefix));
00755                 }
00756             }
00757         } else {
00758             $tables = $db->listSources();
00759         }
00760         if (empty($tables)) {
00761             $this->err(__('Your database does not have any tables.', true));
00762             $this->_stop();
00763         }
00764 
00765         $this->__tables = $tables;
00766 
00767         if ($interactive === true) {
00768             $this->out(__('Possible Models based on your current database:', true));
00769             $this->_modelNames = array();
00770             $count = count($tables);
00771             for ($i = 0; $i < $count; $i++) {
00772                 $this->_modelNames[] = $this->_modelName($tables[$i]);
00773                 $this->out($i + 1 . ". " . $this->_modelNames[$i]);
00774             }
00775         }
00776     }
00777 /**
00778  * Forces the user to specify the model he wants to bake, and returns the selected model name.
00779  *
00780  * @return string the model name
00781  * @access public
00782  */
00783     function getName($useDbConfig) {
00784         $this->listAll($useDbConfig);
00785 
00786         $enteredModel = '';
00787 
00788         while ($enteredModel == '') {
00789             $enteredModel = $this->in(__("Enter a number from the list above, type in the name of another model, or 'q' to exit", true), null, 'q');
00790 
00791             if ($enteredModel === 'q') {
00792                 $this->out(__("Exit", true));
00793                 $this->_stop();
00794             }
00795 
00796             if ($enteredModel == '' || intval($enteredModel) > count($this->_modelNames)) {
00797                 $this->err(__("The model name you supplied was empty, or the number you selected was not an option. Please try again.", true));
00798                 $enteredModel = '';
00799             }
00800         }
00801 
00802         if (intval($enteredModel) > 0 && intval($enteredModel) <= count($this->_modelNames)) {
00803             $currentModelName = $this->_modelNames[intval($enteredModel) - 1];
00804         } else {
00805             $currentModelName = $enteredModel;
00806         }
00807 
00808         return $currentModelName;
00809     }
00810 /**
00811  * Displays help contents
00812  *
00813  * @access public
00814  */
00815     function help() {
00816         $this->hr();
00817         $this->out("Usage: cake bake model <arg1>");
00818         $this->hr();
00819         $this->out('Commands:');
00820         $this->out("\n\tmodel\n\t\tbakes model in interactive mode.");
00821         $this->out("\n\tmodel <name>\n\t\tbakes model file with no associations or validation");
00822         $this->out("");
00823         $this->_stop();
00824     }
00825 /**
00826  * Builds the tests fixtures for the model and create the file
00827  *
00828  * @param string $model the name of the model
00829  * @param string $useTable table name
00830  * @return array $records, used in ModelTask::bakeTest() to create $expected
00831  * @todo move this to a task
00832  */
00833     function fixture($model, $useTable = null) {
00834         if (!class_exists('CakeSchema')) {
00835             App::import('Model', 'Schema');
00836         }
00837         $out = "\nclass {$model}Fixture extends CakeTestFixture {\n";
00838         $out .= "\tvar \$name = '$model';\n";
00839 
00840         if (!$useTable) {
00841             $useTable = Inflector::tableize($model);
00842         } else {
00843             $out .= "\tvar \$table = '$useTable';\n";
00844         }
00845         $schema = new CakeSchema();
00846         $data = $schema->read(array('models' => false));
00847 
00848         if (!isset($data['tables'][$useTable])) {
00849             return false;
00850         }
00851         $tables[$model] = $data['tables'][$useTable];
00852 
00853         foreach ($tables as $table => $fields) {
00854             if (!is_numeric($table) && $table !== 'missing') {
00855                 $out .= "\tvar \$fields = array(\n";
00856                 $records = array();
00857                 if (is_array($fields)) {
00858                     $cols = array();
00859                     foreach ($fields as $field => $value) {
00860                         if ($field != 'indexes') {
00861                             if (is_string($value)) {
00862                                 $type = $value;
00863                                 $value = array('type'=> $type);
00864                             }
00865                             $col = "\t\t'{$field}' => array('type'=>'" . $value['type'] . "', ";
00866 
00867                             switch ($value['type']) {
00868                                 case 'integer':
00869                                     $insert = 1;
00870                                 break;
00871                                 case 'string';
00872                                     $insert = "Lorem ipsum dolor sit amet";
00873                                     if (!empty($value['length'])) {
00874                                         $insert = substr($insert, 0, (int)$value['length'] - 2);
00875                                     }
00876                                     $insert = "'$insert'";
00877                                 break;
00878                                 case 'datetime':
00879                                     $ts = date('Y-m-d H:i:s');
00880                                     $insert = "'$ts'";
00881                                 break;
00882                                 case 'date':
00883                                     $ts = date('Y-m-d');
00884                                     $insert = "'$ts'";
00885                                 break;
00886                                 case 'time':
00887                                     $ts = date('H:i:s');
00888                                     $insert = "'$ts'";
00889                                 break;
00890                                 case 'boolean':
00891                                     $insert = 1;
00892                                 break;
00893                                 case 'text':
00894                                     $insert =
00895                                     "'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,";
00896                                     $insert .= "phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,";
00897                                     $insert .= "vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,";
00898                                     $insert .= "feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.'";
00899                                 break;
00900                             }
00901                             $records[] = "\t\t'$field'  => $insert";
00902                             unset($value['type']);
00903                             $col .= join(', ',  $schema->__values($value));
00904                         } else {
00905                             $col = "\t\t'indexes' => array(";
00906                             $props = array();
00907                             foreach ((array)$value as $key => $index) {
00908                                 $props[] = "'{$key}' => array(" . join(', ',  $schema->__values($index)) . ")";
00909                             }
00910                             $col .= join(', ', $props);
00911                         }
00912                         $col .= ")";
00913                         $cols[] = $col;
00914                     }
00915                     $out .= join(",\n", $cols);
00916                 }
00917                 $out .= "\n\t);\n";
00918             }
00919         }
00920         $records = join(",\n", $records);
00921         $out .= "\tvar \$records = array(array(\n$records\n\t));\n";
00922         $out .= "}\n";
00923         $path = TESTS . DS . 'fixtures' . DS;
00924         if (isset($this->plugin)) {
00925             $pluginPath = 'plugins' . DS . Inflector::underscore($this->plugin) . DS;
00926             $path = APP . $pluginPath . 'tests' . DS . 'fixtures' . DS;
00927         }
00928         $filename = Inflector::underscore($model) . '_fixture.php';
00929         $header = '$Id';
00930         $content = "<?php \n/* SVN FILE: $header$ */\n/* " . $model . " Fixture generated on: " . date('Y-m-d H:i:s') . " : " . time() . "*/\n{$out}?>";
00931         $this->out("\nBaking test fixture for $model...");
00932         if ($this->createFile($path . $filename, $content)) {
00933             return str_replace("\t\t", "\t\t\t", $records);
00934         }
00935         return false;
00936     }
00937 }
00938 ?>

Generated on Sun Nov 22 00:30:51 2009 for CakePHP 1.2.x.x (v1.2.4.8284) by doxygen 1.4.7