Adding ability to generate fixtures from data in app tables, with custom conditions. Test cases added.

This commit is contained in:
mark_story 2009-07-21 00:00:39 -04:00
parent 10f5ae22a9
commit 19eca9003d
2 changed files with 95 additions and 17 deletions

View file

@ -144,8 +144,8 @@ class FixtureTask extends Shell {
} }
if ($doRecords == 'n') { if ($doRecords == 'n') {
$prompt = sprintf(__("Would you like to build this fixture with data from %s's table?", true), $modelName); $prompt = sprintf(__("Would you like to build this fixture with data from %s's table?", true), $modelName);
$fromDb = $this->in($prompt, array('y', 'n'), 'n'); $fromTable = $this->in($prompt, array('y', 'n'), 'n');
if (strtolower($fromDb) == 'y') { if (strtolower($fromTable) == 'y') {
$options['fromTable'] = true; $options['fromTable'] = true;
} }
} }
@ -161,14 +161,13 @@ class FixtureTask extends Shell {
* @access private * @access private
*/ */
function bake($model, $useTable = false, $importOptions = array()) { function bake($model, $useTable = false, $importOptions = array()) {
$table = $schema = $records = $import = null; $table = $schema = $records = $import = $modelImport = $recordImport = null;
if (!$useTable) { if (!$useTable) {
$useTable = Inflector::tableize($model); $useTable = Inflector::tableize($model);
} elseif ($useTable != Inflector::tableize($model)) { } elseif ($useTable != Inflector::tableize($model)) {
$table = $useTable; $table = $useTable;
} }
$modelImport = $import = $recordImport = null;
if (!empty($importOptions)) { if (!empty($importOptions)) {
if (isset($importOptions['schema'])) { if (isset($importOptions['schema'])) {
$modelImport = "'model' => '{$importOptions['schema']}'"; $modelImport = "'model' => '{$importOptions['schema']}'";
@ -179,7 +178,9 @@ class FixtureTask extends Shell {
if ($modelImport && $recordImport) { if ($modelImport && $recordImport) {
$modelImport .= ', '; $modelImport .= ', ';
} }
$import = sprintf("array(%s%s)", $modelImport, $recordImport); if (!empty($modelImport) || !empty($recordImport)) {
$import = sprintf("array(%s%s)", $modelImport, $recordImport);
}
} }
$this->_Schema = new CakeSchema(); $this->_Schema = new CakeSchema();
@ -195,12 +196,15 @@ class FixtureTask extends Shell {
$schema = $this->_generateSchema($tableInfo); $schema = $this->_generateSchema($tableInfo);
} }
if (is_null($recordImport)) { if (!isset($importOptions['records']) && !isset($importOptions['fromTable'])) {
$recordCount = 1; $recordCount = 1;
if (isset($this->params['count'])) { if (isset($this->params['count'])) {
$recordCount = $this->params['count']; $recordCount = $this->params['count'];
} }
$records = $this->_generateRecords($tableInfo, $recordCount); $records = $this->_makeRecordString($this->_generateRecords($tableInfo, $recordCount));
}
if (isset($importOptions['fromTable'])) {
$records = $this->_makeRecordString($this->_getRecordsFromTable($model, $useTable));
} }
$out = $this->generateFixtureFile($model, compact('records', 'table', 'schema', 'import', 'fields')); $out = $this->generateFixtureFile($model, compact('records', 'table', 'schema', 'import', 'fields'));
return $out; return $out;
@ -265,13 +269,12 @@ class FixtureTask extends Shell {
* Generate String representation of Records * Generate String representation of Records
* *
* @param array $table Table schema array * @param array $table Table schema array
* @return string * @return array Array of records to use in the fixture.
**/ **/
function _generateRecords($tableInfo, $recordCount = 1) { function _generateRecords($tableInfo, $recordCount = 1) {
$out = "array(\n"; $records = array();
for ($i = 0; $i < $recordCount; $i++) { for ($i = 0; $i < $recordCount; $i++) {
$records = array(); $record = array();
foreach ($tableInfo as $field => $fieldInfo) { foreach ($tableInfo as $field => $fieldInfo) {
if (empty($fieldInfo['type'])) { if (empty($fieldInfo['type'])) {
continue; continue;
@ -281,9 +284,17 @@ class FixtureTask extends Shell {
$insert = $i + 1; $insert = $i + 1;
break; break;
case 'string'; case 'string';
$insert = "Lorem ipsum dolor sit amet"; $isPrimaryUuid = (
if (!empty($fieldInfo['length'])) { isset($fieldInfo['key']) && strtolower($fieldInfo['key']) == 'primary' &&
$insert = substr($insert, 0, (int)$fieldInfo['length'] - 2); isset($fieldInfo['length']) && $fieldInfo['length'] == 36
);
if ($isPrimaryUuid) {
$insert = String::uuid();
} else {
$insert = "Lorem ipsum dolor sit amet";
if (!empty($fieldInfo['length'])) {
$insert = substr($insert, 0, (int)$fieldInfo['length'] - 2);
}
} }
$insert = "'$insert'"; $insert = "'$insert'";
break; break;
@ -316,15 +327,64 @@ class FixtureTask extends Shell {
$insert .= " duis vestibulum nunc mattis convallis.'"; $insert .= " duis vestibulum nunc mattis convallis.'";
break; break;
} }
$records[] = "\t\t\t'$field' => $insert"; $record[$field] = $insert;
}
$records[] = $record;
}
return $records;
}
/**
* Convert a $records array into a a string.
*
* @param array $records Array of records to be converted to string
* @return string A string value of the $records array.
**/
function _makeRecordString($records) {
$out = "array(\n";
foreach ($records as $record) {
$values = array();
foreach ($record as $field => $value) {
$values[] = "\t\t\t'$field' => $value";
} }
$out .= "\t\tarray(\n"; $out .= "\t\tarray(\n";
$out .= implode(",\n", $records); $out .= implode(",\n", $values);
$out .= "\n\t\t),\n"; $out .= "\n\t\t),\n";
} }
$out .= "\t)"; $out .= "\t)";
return $out; return $out;
} }
/**
* Interact with the user to get a custom SQL condition and use that to extract data
* to build a fixture.
*
* @param string $modelName name of the model to take records from.
* @param string $useTable Name of table to use.
* @return array Array of records.
**/
function _getRecordsFromTable($modelName, $useTable = null) {
$condition = null;
$prompt = __("Please provide a SQL fragment to use as conditions\nExample: WHERE 1=1 LIMIT 10", true);
while (!$condition) {
$condition = $this->in($prompt, null, 'WHERE 1=1 LIMIT 10');
}
App::import('Core', 'Model');
$modelObject =& new Model(array('name' => $modelName, 'table' => $useTable, 'ds' => $this->connection));
$records = $modelObject->find('all', array(
'conditions' => $condition,
'recursive' => -1
));
$db =& $modelObject->getDataSource();
$schema = $modelObject->schema();
$out = array();
foreach ($records as $record) {
$row = array();
foreach ($record[$modelObject->alias] as $field => $value) {
$row[$field] = $db->value($value, $schema[$field]['type']);
}
$out[] = $row;
}
return $out;
}
/** /**
* Displays help contents * Displays help contents
* *
@ -339,7 +399,7 @@ class FixtureTask extends Shell {
$this->out("\nfixture all\n\tbakes all fixtures."); $this->out("\nfixture all\n\tbakes all fixtures.");
$this->out(""); $this->out("");
$this->out('Parameters:'); $this->out('Parameters:');
$this->out("\t-count The number of records to include in the fixture(s)."); $this->out("\t-count When using generated data, the number of records to include in the fixture(s).");
$this->out("\t-connection Which database configuration to use for baking."); $this->out("\t-connection Which database configuration to use for baking.");
$this->out("\t-plugin lowercased_underscored name of plugin to bake fixtures for."); $this->out("\t-plugin lowercased_underscored name of plugin to bake fixtures for.");
$this->out(""); $this->out("");

View file

@ -125,6 +125,24 @@ class FixtureTaskTest extends CakeTestCase {
$expected = array('fromTable' => true); $expected = array('fromTable' => true);
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
} }
/**
* test generating a fixture with database conditions.
*
* @return void
**/
function testImportRecordsFromDatabaseWithConditions() {
$this->Task->setReturnValueAt(0, 'in', 'WHERE 1=1 LIMIT 10');
$this->Task->connection = 'test_suite';
$this->Task->path = '/my/path/';
$result = $this->Task->bake('Article', false, array('fromTable' => true, 'schema' => 'Article', 'records' => false));
debug($result, true);
$this->assertPattern('/class ArticleFixture extends CakeTestFixture/', $result);
$this->assertPattern('/var \$records/', $result);
$this->assertPattern('/var \$import/', $result);
$this->assertPattern("/'title' => 'First Article'/", $result, 'Missing import data %s');
$this->assertPattern('/Second Article/', $result, 'Missing import data %s');
$this->assertPattern('/Third Article/', $result, 'Missing import data %s');
}
/** /**
* test that execute passes runs bake depending with named model. * test that execute passes runs bake depending with named model.
* *