From 19eca9003d09818c998070394026e75903c1fa20 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 21 Jul 2009 00:00:39 -0400 Subject: [PATCH] Adding ability to generate fixtures from data in app tables, with custom conditions. Test cases added. --- cake/console/libs/tasks/fixture.php | 94 +++++++++++++++---- .../cases/console/libs/tasks/fixture.test.php | 18 ++++ 2 files changed, 95 insertions(+), 17 deletions(-) diff --git a/cake/console/libs/tasks/fixture.php b/cake/console/libs/tasks/fixture.php index 30ef7484417..f145ee73c98 100644 --- a/cake/console/libs/tasks/fixture.php +++ b/cake/console/libs/tasks/fixture.php @@ -144,8 +144,8 @@ function importOptions($modelName) { } if ($doRecords == 'n') { $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'); - if (strtolower($fromDb) == 'y') { + $fromTable = $this->in($prompt, array('y', 'n'), 'n'); + if (strtolower($fromTable) == 'y') { $options['fromTable'] = true; } } @@ -161,14 +161,13 @@ function importOptions($modelName) { * @access private */ function bake($model, $useTable = false, $importOptions = array()) { - $table = $schema = $records = $import = null; + $table = $schema = $records = $import = $modelImport = $recordImport = null; if (!$useTable) { $useTable = Inflector::tableize($model); } elseif ($useTable != Inflector::tableize($model)) { $table = $useTable; } - $modelImport = $import = $recordImport = null; if (!empty($importOptions)) { if (isset($importOptions['schema'])) { $modelImport = "'model' => '{$importOptions['schema']}'"; @@ -179,7 +178,9 @@ function bake($model, $useTable = false, $importOptions = array()) { if ($modelImport && $recordImport) { $modelImport .= ', '; } - $import = sprintf("array(%s%s)", $modelImport, $recordImport); + if (!empty($modelImport) || !empty($recordImport)) { + $import = sprintf("array(%s%s)", $modelImport, $recordImport); + } } $this->_Schema = new CakeSchema(); @@ -195,12 +196,15 @@ function bake($model, $useTable = false, $importOptions = array()) { $schema = $this->_generateSchema($tableInfo); } - if (is_null($recordImport)) { + if (!isset($importOptions['records']) && !isset($importOptions['fromTable'])) { $recordCount = 1; if (isset($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')); return $out; @@ -265,13 +269,12 @@ function _generateSchema($tableInfo) { * Generate String representation of Records * * @param array $table Table schema array - * @return string + * @return array Array of records to use in the fixture. **/ function _generateRecords($tableInfo, $recordCount = 1) { - $out = "array(\n"; - + $records = array(); for ($i = 0; $i < $recordCount; $i++) { - $records = array(); + $record = array(); foreach ($tableInfo as $field => $fieldInfo) { if (empty($fieldInfo['type'])) { continue; @@ -281,9 +284,17 @@ function _generateRecords($tableInfo, $recordCount = 1) { $insert = $i + 1; break; case 'string'; - $insert = "Lorem ipsum dolor sit amet"; - if (!empty($fieldInfo['length'])) { - $insert = substr($insert, 0, (int)$fieldInfo['length'] - 2); + $isPrimaryUuid = ( + isset($fieldInfo['key']) && strtolower($fieldInfo['key']) == 'primary' && + 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'"; break; @@ -316,15 +327,64 @@ function _generateRecords($tableInfo, $recordCount = 1) { $insert .= " duis vestibulum nunc mattis convallis.'"; 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 .= implode(",\n", $records); + $out .= implode(",\n", $values); $out .= "\n\t\t),\n"; } $out .= "\t)"; 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 * @@ -339,7 +399,7 @@ function help() { $this->out("\nfixture all\n\tbakes all fixtures."); $this->out(""); $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-plugin lowercased_underscored name of plugin to bake fixtures for."); $this->out(""); diff --git a/cake/tests/cases/console/libs/tasks/fixture.test.php b/cake/tests/cases/console/libs/tasks/fixture.test.php index a44d4432ce5..07e37fcb11b 100644 --- a/cake/tests/cases/console/libs/tasks/fixture.test.php +++ b/cake/tests/cases/console/libs/tasks/fixture.test.php @@ -125,6 +125,24 @@ function testImportOptions() { $expected = array('fromTable' => true); $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. *