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