Implementation of table level and field level parameters support

This commit is contained in:
SkieDr 2009-09-29 19:25:42 +04:00
parent 86d0a04c8d
commit 627eff5f24
4 changed files with 208 additions and 7 deletions

View file

@ -237,6 +237,7 @@ class CakeSchema extends Object {
if (empty($tables[$Object->table])) { if (empty($tables[$Object->table])) {
$tables[$Object->table] = $this->__columns($Object); $tables[$Object->table] = $this->__columns($Object);
$tables[$Object->table]['indexes'] = $db->index($Object); $tables[$Object->table]['indexes'] = $db->index($Object);
$tables[$Object->table]['tableParameters'] = $db->readTableParameters($table);
unset($currentTables[$key]); unset($currentTables[$key]);
} }
if (!empty($Object->hasAndBelongsToMany)) { if (!empty($Object->hasAndBelongsToMany)) {
@ -250,6 +251,7 @@ class CakeSchema extends Object {
$key = array_search($table, $currentTables); $key = array_search($table, $currentTables);
$tables[$Object->$class->table] = $this->__columns($Object->$class); $tables[$Object->$class->table] = $this->__columns($Object->$class);
$tables[$Object->$class->table]['indexes'] = $db->index($Object->$class); $tables[$Object->$class->table]['indexes'] = $db->index($Object->$class);
$tables[$Object->$class->table]['tableParameters'] = $db->readTableParameters($table);
unset($currentTables[$key]); unset($currentTables[$key]);
} }
} }
@ -279,12 +281,15 @@ class CakeSchema extends Object {
if (in_array($table, $systemTables)) { if (in_array($table, $systemTables)) {
$tables[$Object->table] = $this->__columns($Object); $tables[$Object->table] = $this->__columns($Object);
$tables[$Object->table]['indexes'] = $db->index($Object); $tables[$Object->table]['indexes'] = $db->index($Object);
$tables[$Object->table]['tableParameters'] = $db->readTableParameters($table);
} elseif ($models === false) { } elseif ($models === false) {
$tables[$table] = $this->__columns($Object); $tables[$table] = $this->__columns($Object);
$tables[$table]['indexes'] = $db->index($Object); $tables[$table]['indexes'] = $db->index($Object);
$tables[$table]['tableParameters'] = $db->readTableParameters($table);
} else { } else {
$tables['missing'][$table] = $this->__columns($Object); $tables['missing'][$table] = $this->__columns($Object);
$tables['missing'][$table]['indexes'] = $db->index($Object); $tables['missing'][$table]['indexes'] = $db->index($Object);
$tables['missing'][$table]['tableParameters'] = $db->readTableParameters($table);
} }
} }
} }

View file

@ -75,6 +75,30 @@ class DboMysqlBase extends DboSource {
'rollback' => 'ROLLBACK' 'rollback' => 'ROLLBACK'
); );
/**
* List of engine specific additional field parameters used on table creating
*
* @var array
* @access public
*/
var $fieldParameters = array(
'charset' => array('value' => 'CHARACTER SET', 'quote' => false, 'join' => ' ', 'column' => false, 'position' => 'beforeDefault'),
'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => ' ', 'column' => 'Collation', 'position' => 'beforeDefault'),
'comment' => array('value' => 'COMMENT', 'quote' => true, 'join' => ' ', 'column' => 'Comment', 'position' => 'afterDefault')
);
/**
* List of table engine specific parameters used on table creating
*
* @var array
* @access public
*/
var $tableParameters = array(
'charset' => array('value' => 'DEFAULT CHARSET', 'quote' => false, 'join' => '=', 'column' => 'charset'),
'collate' => array('value' => 'COLLATE', 'quote' => false, 'join' => '=', 'column' => 'Collation'),
'engine' => array('value' => 'ENGINE', 'quote' => false, 'join' => '=', 'column' => 'Engine')
);
/** /**
* MySQL column definition * MySQL column definition
* *
@ -457,6 +481,38 @@ class DboMysql extends DboMysqlBase {
} }
} }
/**
* Returns an detailed array of sources (tables) in the database.
*
* @param string $name Table name to get parameters
* @return array Array of tablenames in the database
*/
function listDetailedSources($name = null) {
$condition = '';
if (is_string($name)) {
$condition = ' WHERE Name=' . $this->value($name);
}
$result = $this->query('SHOW TABLE STATUS FROM ' . $this->name($this->config['database']) . $condition . ';');
if (!$result) {
return array();
} else {
$tables = array();
foreach ($result as $row) {
$tables[$row['TABLES']['Name']] = $row['TABLES'];
if (!empty($row['TABLES']['Collation'])) {
$charset = $this->getCharsetName($row['TABLES']['Collation']);
if ($charset) {
$tables[$row['TABLES']['Name']]['charset'] = $charset;
}
}
}
if (is_string($name)) {
return $tables[$name];
}
return $tables;
}
}
/** /**
* Returns an array of the fields in given table name. * Returns an array of the fields in given table name.
* *
@ -469,7 +525,7 @@ class DboMysql extends DboMysqlBase {
return $cache; return $cache;
} }
$fields = false; $fields = false;
$cols = $this->query('DESCRIBE ' . $this->fullTableName($model)); $cols = $this->query('SHOW FULL COLUMNS FROM ' . $this->fullTableName($model));
foreach ($cols as $column) { foreach ($cols as $column) {
$colKey = array_keys($column); $colKey = array_keys($column);
@ -486,12 +542,37 @@ class DboMysql extends DboMysqlBase {
if (!empty($column[0]['Key']) && isset($this->index[$column[0]['Key']])) { if (!empty($column[0]['Key']) && isset($this->index[$column[0]['Key']])) {
$fields[$column[0]['Field']]['key'] = $this->index[$column[0]['Key']]; $fields[$column[0]['Field']]['key'] = $this->index[$column[0]['Key']];
} }
foreach ($this->fieldParameters as $name => $value) {
if (!empty($column[0][$value['column']])) {
$fields[$column[0]['Field']][$name] = $column[0][$value['column']];
}
}
if (isset($fields[$column[0]['Field']]['collate'])) {
$charset = $this->getCharsetName($fields[$column[0]['Field']]['collate']);
if ($charset) {
$fields[$column[0]['Field']]['charset'] = $charset;
}
}
} }
} }
$this->__cacheDescription($this->fullTableName($model, false), $fields); $this->__cacheDescription($this->fullTableName($model, false), $fields);
return $fields; return $fields;
} }
/**
* Query charset by collation
*
* @param string $name Collation name
* @return string Character set name
*/
function getCharsetName($name) {
$cols = $this->query('SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS WHERE COLLATION_NAME= ' . $this->value($name) . ';');
if (isset($cols[0]['COLLATIONS']['CHARACTER_SET_NAME'])) {
return $cols[0]['COLLATIONS']['CHARACTER_SET_NAME'];
}
return false;
}
/** /**
* Returns a quoted and escaped string of $data for use in an SQL statement. * Returns a quoted and escaped string of $data for use in an SQL statement.
* *

View file

@ -91,6 +91,22 @@ class DboSource extends DataSource {
'rollback' => 'ROLLBACK' 'rollback' => 'ROLLBACK'
); );
/**
* List of table engine specific parameters used on table creating
*
* @var array
* @access protected
*/
var $tableParameters = array();
/**
* List of engine specific additional field parameters used on table creating
*
* @var array
* @access protected
*/
var $fieldParameters = array();
/** /**
* Constructor * Constructor
*/ */
@ -1370,15 +1386,17 @@ class DboSource extends DataSource {
return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}"; return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}";
break; break;
case 'schema': case 'schema':
foreach (array('columns', 'indexes') as $var) { foreach (array('columns', 'indexes', 'tableParameters') as $var) {
if (is_array(${$var})) { if (is_array(${$var})) {
${$var} = "\t" . join(",\n\t", array_filter(${$var})); ${$var} = "\t" . join(",\n\t", array_filter(${$var}));
} else {
${$var} = '';
} }
} }
if (trim($indexes) != '') { if (trim($indexes) != '') {
$columns .= ','; $columns .= ',';
} }
return "CREATE TABLE {$table} (\n{$columns}{$indexes});"; return "CREATE TABLE {$table} (\n{$columns}{$indexes}){$tableParameters};";
break; break;
case 'alter': case 'alter':
break; break;
@ -2334,7 +2352,7 @@ class DboSource extends DataSource {
foreach ($schema->tables as $curTable => $columns) { foreach ($schema->tables as $curTable => $columns) {
if (!$tableName || $tableName == $curTable) { if (!$tableName || $tableName == $curTable) {
$cols = $colList = $indexes = array(); $cols = $colList = $indexes = $tableParameters = array();
$primary = null; $primary = null;
$table = $this->fullTableName($curTable); $table = $this->fullTableName($curTable);
@ -2345,14 +2363,16 @@ class DboSource extends DataSource {
if (isset($col['key']) && $col['key'] == 'primary') { if (isset($col['key']) && $col['key'] == 'primary') {
$primary = $name; $primary = $name;
} }
if ($name !== 'indexes') { if ($name !== 'indexes' && $name !== 'tableParameters') {
$col['name'] = $name; $col['name'] = $name;
if (!isset($col['type'])) { if (!isset($col['type'])) {
$col['type'] = 'string'; $col['type'] = 'string';
} }
$cols[] = $this->buildColumn($col); $cols[] = $this->buildColumn($col);
} else { } elseif ($name == 'indexes') {
$indexes = array_merge($indexes, $this->buildIndex($col, $table)); $indexes = array_merge($indexes, $this->buildIndex($col, $table));
} elseif ($name == 'tableParameters') {
$tableParameters = array_merge($tableParameters, $this->buildTableParameters($col, $table));
} }
} }
if (empty($indexes) && !empty($primary)) { if (empty($indexes) && !empty($primary)) {
@ -2360,7 +2380,7 @@ class DboSource extends DataSource {
$indexes = array_merge($indexes, $this->buildIndex($col, $table)); $indexes = array_merge($indexes, $this->buildIndex($col, $table));
} }
$columns = $cols; $columns = $cols;
$out .= $this->renderStatement('schema', compact('table', 'columns', 'indexes')) . "\n\n"; $out .= $this->renderStatement('schema', compact('table', 'columns', 'indexes', 'tableParameters')) . "\n\n";
} }
} }
return $out; return $out;
@ -2440,6 +2460,16 @@ class DboSource extends DataSource {
$column['default'] = null; $column['default'] = null;
} }
foreach ($this->fieldParameters as $paramName => $value) {
if (isset($column[$paramName]) && $value['position'] == 'beforeDefault') {
$val = $column[$paramName];
if ($value['quote']) {
$val = $this->value($val);
}
$out .= ' ' . $value['value'] . $value['join'] . $val;
}
}
if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') { if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') {
$out .= ' ' . $this->columns['primary_key']['name']; $out .= ' ' . $this->columns['primary_key']['name'];
} elseif (isset($column['key']) && $column['key'] == 'primary') { } elseif (isset($column['key']) && $column['key'] == 'primary') {
@ -2453,6 +2483,17 @@ class DboSource extends DataSource {
} elseif (isset($column['null']) && $column['null'] == false) { } elseif (isset($column['null']) && $column['null'] == false) {
$out .= ' NOT NULL'; $out .= ' NOT NULL';
} }
foreach ($this->fieldParameters as $paramName => $value) {
if (isset($column[$paramName]) && $value['position'] == 'afterDefault') {
$val = $column[$paramName];
if ($value['quote']) {
$val = $this->value($val);
}
$out .= ' ' . $value['value'] . $value['join'] . $val;
}
}
return $out; return $out;
} }
@ -2486,6 +2527,46 @@ class DboSource extends DataSource {
return $join; return $join;
} }
/**
* Read additional table parameters
*
* @param array $parameters
* @param string $table
* @return array
*/
function readTableParameters($name) {
$parameters = array();
if ($this->isInterfaceSupported('listDetailedSources')) {
$currentTableDetails = $this->listDetailedSources($name);
foreach ($this->tableParameters as $paramName => $parameter) {
if (!empty($parameter['column']) && !empty($currentTableDetails[$parameter['column']])) {
$parameters[$paramName] = $currentTableDetails[$parameter['column']];
}
}
}
return $parameters;
}
/**
* Format parameters for create table
*
* @param array $parameters
* @param string $table
* @return array
*/
function buildTableParameters($parameters, $table = null) {
$result = array();
foreach ($parameters as $name => $value) {
if (isset($this->tableParameters[$name])) {
if ($this->tableParameters[$name]['quote']) {
$value = $this->value($value);
}
$result[] = $this->tableParameters[$name]['value'] . $this->tableParameters[$name]['join'] . $value;
}
}
return $result;
}
/** /**
* Guesses the data type of an array * Guesses the data type of an array
* *

View file

@ -385,6 +385,40 @@ class DboMysqlTest extends CakeTestCase {
$this->db->query('DROP TABLE ' . $name); $this->db->query('DROP TABLE ' . $name);
} }
/**
* testBuildColumn method
*
* @access public
* @return void
*/
function testBuildColumn() {
$this->db->columns = array('varchar(255)' => 1);
$data = array(
'name' => 'testName',
'type' => 'varchar(255)',
'default',
'null' => true,
'key',
'comment' => 'test'
);
$result = $this->db->buildColumn($data);
$expected = '`testName` DEFAULT NULL COMMENT \'test\'';
$this->assertEqual($result, $expected);
$data = array(
'name' => 'testName',
'type' => 'varchar(255)',
'default',
'null' => true,
'key',
'charset' => 'utf8',
'collate' => 'utf8_unicode_ci'
);
$result = $this->db->buildColumn($data);
$expected = '`testName` CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL';
$this->assertEqual($result, $expected);
}
/** /**
* MySQL 4.x returns index data in a different format, * MySQL 4.x returns index data in a different format,
* Using a mock ensure that MySQL 4.x output is properly parsed. * Using a mock ensure that MySQL 4.x output is properly parsed.