Commit 746d9bc3 authored by jwage's avatar jwage

[2.0] Adding listTableColumns() support for mysql.

parent 7426baf5
...@@ -273,6 +273,11 @@ class MySqlPlatform extends AbstractPlatform ...@@ -273,6 +273,11 @@ class MySqlPlatform extends AbstractPlatform
return 'SHOW TABLES'; return 'SHOW TABLES';
} }
public function getListTableColumnsSql($table)
{
return 'DESCRIBE ' . $this->quoteIdentifier($table);
}
/** /**
* create a new database * create a new database
* *
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
namespace Doctrine\DBAL\Schema; namespace Doctrine\DBAL\Schema;
use \Doctrine\DBAL\Types;
/** /**
* Base class for schema managers. Schema managers are used to inspect and/or * Base class for schema managers. Schema managers are used to inspect and/or
* modify the database schema/structure. * modify the database schema/structure.
...@@ -524,54 +526,134 @@ abstract class AbstractSchemaManager ...@@ -524,54 +526,134 @@ abstract class AbstractSchemaManager
protected function _getPortableDatabasesList($databases) protected function _getPortableDatabasesList($databases)
{ {
foreach ($databases as $key => $value) {
$databases[$key] = $this->_getPortableDatabaseDefinition($value);
}
return $databases; return $databases;
} }
protected function _getPortableDatabaseDefinition($database)
{
return $database;
}
protected function _getPortableFunctionsList($functions) protected function _getPortableFunctionsList($functions)
{ {
foreach ($functions as $key => $value) {
$functions[$key] = $this->_getPortableFunctionDefinition($value);
}
return $functions; return $functions;
} }
protected function _getPortableFunctionDefinition($function)
{
return $function;
}
protected function _getPortableTriggersList($triggers) protected function _getPortableTriggersList($triggers)
{ {
foreach ($triggers as $key => $value) {
$triggers[$key] = $this->_getPortableTriggerDefinition($value);
}
return $triggers; return $triggers;
} }
protected function _getPortableTriggerDefinition($trigger)
{
return $trigger;
}
protected function _getPortableSequencesList($sequences) protected function _getPortableSequencesList($sequences)
{ {
foreach ($sequences as $key => $value) {
$sequences[$key] = $this->_getPortableSequenceDefinition($value);
}
return $sequences; return $sequences;
} }
protected function _getPortableSequenceDefinition($sequence)
{
return $sequence;
}
protected function _getPortableTableConstraintsList($tableConstraints) protected function _getPortableTableConstraintsList($tableConstraints)
{ {
foreach ($tableConstraints as $key => $value) {
$tableConstraints[$key] = $this->_getPortableTableConstraintDefinition($value);
}
return $tableConstraints; return $tableConstraints;
} }
protected function _getPortableTableConstraintDefinition($tableConstraint)
{
return $tableConstraint;
}
protected function _getPortableTableColumnList($tableColumns) protected function _getPortableTableColumnList($tableColumns)
{ {
foreach ($tableColumns as $key => $value) {
$tableColumns[$key] = $this->_getPortableTableColumnDefinition($value);
}
return $tableColumns; return $tableColumns;
} }
protected function _getPortableTableColumnDefinition($tableColumn)
{
return $tableColumn;
}
protected function _getPortableTableIndexesList($tableIndexes) protected function _getPortableTableIndexesList($tableIndexes)
{ {
foreach ($tableIndexes as $key => $value) {
$tableIndexes[$key] = $this->_getPortableTableIndexDefinition($value);
}
return $tableIndexes; return $tableIndexes;
} }
protected function _getPortableTableIndexDefinition($tableIndex)
{
return $tableIndex;
}
protected function _getPortableTablesList($tables) protected function _getPortableTablesList($tables)
{ {
foreach ($tables as $key => $value) {
$tables[$key] = $this->_getPortableTableDefinition($value);
}
return $tables; return $tables;
} }
protected function _getPortableTableDefinition($table)
{
return $table;
}
protected function _getPortableUsersList($users) protected function _getPortableUsersList($users)
{ {
foreach ($users as $key => $value) {
$users[$key] = $this->_getPortableUserDefinition($value);
}
return $users; return $users;
} }
protected function _getPortableUserDefinition($user)
{
return $user;
}
protected function _getPortableViewsList($views) protected function _getPortableViewsList($views)
{ {
foreach ($views as $key => $value) {
$views[$key] = $this->_getPortableViewDefinition($value);
}
return $views; return $views;
} }
protected function _getPortableViewDefinition($view)
{
return $view;
}
protected function _executeSql($sql, $method = 'exec') protected function _executeSql($sql, $method = 'exec')
{ {
$result = true; $result = true;
......
...@@ -32,6 +32,205 @@ namespace Doctrine\DBAL\Schema; ...@@ -32,6 +32,205 @@ namespace Doctrine\DBAL\Schema;
*/ */
class MySqlSchemaManager extends AbstractSchemaManager class MySqlSchemaManager extends AbstractSchemaManager
{ {
protected function _getPortableTableColumnDefinition($tableColumn)
{
$dbType = strtolower($tableColumn['type']);
$dbType = strtok($dbType, '(), ');
if ($dbType == 'national') {
$dbType = strtok('(), ');
}
if (isset($tableColumn['length'])) {
$length = $tableColumn['length'];
$decimal = '';
} else {
$length = strtok('(), ');
$decimal = strtok('(), ') ? strtok('(), '):null;
}
$type = array();
$unsigned = $fixed = null;
if ( ! isset($tableColumn['name'])) {
$tableColumn['name'] = '';
}
$values = null;
$scale = null;
switch ($dbType) {
case 'tinyint':
$type = 'integer';
$type = 'boolean';
if (preg_match('/^(is|has)/', $tableColumn['name'])) {
$type = array_reverse($type);
}
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 1;
break;
case 'smallint':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 2;
break;
case 'mediumint':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 3;
break;
case 'int':
case 'integer':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 4;
break;
case 'bigint':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 8;
break;
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
case 'text':
case 'varchar':
$fixed = false;
case 'string':
case 'char':
$type = 'string';
if ($length == '1') {
$type = 'boolean';
if (preg_match('/^(is|has)/', $tableColumn['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type = 'clob';
if ($decimal == 'binary') {
$type = 'blob';
}
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'enum':
$type = 'enum';
preg_match_all('/\'((?:\'\'|[^\'])*)\'/', $tableColumn['type'], $matches);
$length = 0;
$fixed = false;
if (is_array($matches)) {
foreach ($matches[1] as &$value) {
$value = str_replace('\'\'', '\'', $value);
$length = max($length, strlen($value));
}
if ($length == '1' && count($matches[1]) == 2) {
$type = 'boolean';
if (preg_match('/^(is|has)/', $tableColumn['name'])) {
$type = array_reverse($type);
}
}
$values = $matches[1];
}
$type = 'integer';
break;
case 'set':
$fixed = false;
$type = 'text';
$type = 'integer';
break;
case 'date':
$type = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
$type = 'timestamp';
$length = null;
break;
case 'time':
$type = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'real':
$type = 'float';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
break;
case 'unknown':
case 'decimal':
if ($decimal !== null) {
$scale = $decimal;
}
case 'numeric':
$type = 'decimal';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
case 'binary':
case 'varbinary':
$type = 'blob';
$length = null;
break;
case 'year':
$type = 'integer';
$type = 'date';
$length = null;
break;
case 'bit':
$type = 'bit';
break;
case 'geometry':
case 'geometrycollection':
case 'point':
case 'multipoint':
case 'linestring':
case 'multilinestring':
case 'polygon':
case 'multipolygon':
$type = 'blob';
$length = null;
break;
default:
$type = 'string';
$length = null;
}
$length = ((int) $length == 0) ? null : (int) $length;
$def = array(
'type' => $type,
'length' => $length,
'unsigned' => (bool) $unsigned,
'fixed' => (bool) $fixed
);
if ($values !== null) {
$def['values'] = $values;
}
if ($scale !== null) {
$def['scale'] = $scale;
}
$values = isset($def['values']) ? $def['values'] : array();
$def['type'] = \Doctrine\DBAL\Types\Type::getType($def['type']);
$column = array(
'name' => $tableColumn['field'],
'values' => $values,
'primary' => (bool) (strtolower($tableColumn['key']) == 'pri'),
'default' => $tableColumn['default'],
'notnull' => (bool) ($tableColumn['null'] != 'YES'),
'autoincrement' => (bool) (strpos($tableColumn['extra'], 'auto_increment') !== false),
);
$column = array_merge($column, $def);
return $column;
}
/** /**
* lists all database sequences * lists all database sequences
* *
...@@ -118,48 +317,6 @@ class MySqlSchemaManager extends AbstractSchemaManager ...@@ -118,48 +317,6 @@ class MySqlSchemaManager extends AbstractSchemaManager
return $result; return $result;
} }
/**
* lists table constraints
*
* @param string $table database table name
* @return array
* @override
*/
public function listTableColumns($table)
{
$sql = 'DESCRIBE ' . $this->_conn->quoteIdentifier($table, true);
$result = $this->_conn->fetchAssoc($sql);
$description = array();
$columns = array();
foreach ($result as $key => $val) {
$val = array_change_key_case($val, CASE_LOWER);
$decl = $this->_conn->getDatabasePlatform()->getPortableDeclaration($val);
$values = isset($decl['values']) ? $decl['values'] : array();
$description = array(
'name' => $val['field'],
'type' => $decl['type'][0],
'alltypes' => $decl['type'],
'ntype' => $val['type'],
'length' => $decl['length'],
'fixed' => $decl['fixed'],
'unsigned' => $decl['unsigned'],
'values' => $values,
'primary' => (strtolower($val['key']) == 'pri'),
'default' => $val['default'],
'notnull' => (bool) ($val['null'] != 'YES'),
'autoincrement' => (bool) (strpos($val['extra'], 'auto_increment') !== false),
);
$columns[$val['field']] = $description;
}
return $columns;
}
/** /**
* lists table constraints * lists table constraints
* *
......
...@@ -33,4 +33,142 @@ namespace Doctrine\DBAL\Schema; ...@@ -33,4 +33,142 @@ namespace Doctrine\DBAL\Schema;
*/ */
class SqliteSchemaManager extends AbstractSchemaManager class SqliteSchemaManager extends AbstractSchemaManager
{ {
protected function _getPortableTableColumnDefinition($tableColumn)
{
$e = explode('(', $tableColumn['type']);
$tableColumn['type'] = $e[0];
if (isset($e[1])) {
$length = trim($e[1], ')');
$tableColumn['length'] = $length;
}
$dbType = strtolower($tableColumn['type']);
$length = isset($tableColumn['length']) ? $tableColumn['length'] : null;
$unsigned = (boolean) isset($tableColumn['unsigned']) ? $tableColumn['unsigned'] : false;
$fixed = false;
$type = null;
$default = $tableColumn['dflt_value'];
if ($default == 'NULL') {
$default = null;
}
$notnull = (bool) $tableColumn['notnull'];
if ( ! isset($tableColumn['name'])) {
$tableColumn['name'] = '';
}
switch ($dbType) {
case 'boolean':
$type = 'boolean';
break;
case 'tinyint':
if (preg_match('/^(is|has)/', $tableColumn['name'])) {
$type = 'boolean';
} else {
$type = 'integer';
}
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 1;
break;
case 'smallint':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 2;
break;
case 'mediumint':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 3;
break;
case 'int':
case 'integer':
case 'serial':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 4;
break;
case 'bigint':
case 'bigserial':
$type = 'integer';
$unsigned = preg_match('/ unsigned/i', $tableColumn['type']);
$length = 8;
break;
case 'clob':
case 'tinytext':
case 'mediumtext':
case 'longtext':
case 'text':
case 'varchar':
case 'varchar2':
case 'nvarchar':
case 'ntext':
case 'image':
case 'nchar':
$fixed = false;
case 'char':
$type = 'string';
if ($length == '1') {
$type = 'boolean';
if (preg_match('/^(is|has)/', $tableColumn['name'])) {
$type = array_reverse($type);
}
} elseif (strstr($dbType, 'text')) {
$type = 'clob';
}
if ($fixed !== false) {
$fixed = true;
}
break;
case 'date':
$type = 'date';
$length = null;
break;
case 'datetime':
case 'timestamp':
$type = 'timestamp';
$length = null;
break;
case 'time':
$type = 'time';
$length = null;
break;
case 'float':
case 'double':
case 'real':
$type = 'float';
$length = null;
break;
case 'decimal':
case 'numeric':
$type = 'decimal';
$length = null;
break;
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
$type = 'blob';
$length = null;
break;
case 'year':
$type = 'date';
$length = null;
break;
default:
$type = 'string';
$length = null;
}
$type = \Doctrine\DBAL\Types\Type::getType($type);
return array('name' => $tableColumn['name'],
'primary' => (bool) $tableColumn['pk'],
'type' => $type,
'length' => $length,
'unsigned' => (bool) $unsigned,
'fixed' => $fixed,
'notnull' => $notnull,
'default' => $default);
}
} }
\ No newline at end of file
...@@ -14,4 +14,9 @@ class TextType extends Type ...@@ -14,4 +14,9 @@ class TextType extends Type
{ {
return $platform->getClobDeclarationSql($fieldDeclaration); return $platform->getClobDeclarationSql($fieldDeclaration);
} }
public function getName()
{
return 'text';
}
} }
\ No newline at end of file
...@@ -21,7 +21,8 @@ class AllTests ...@@ -21,7 +21,8 @@ class AllTests
{ {
$suite = new \Doctrine\Tests\DbalFunctionalTestSuite('Doctrine Dbal Functional'); $suite = new \Doctrine\Tests\DbalFunctionalTestSuite('Doctrine Dbal Functional');
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schemas\SqliteSchemaTest'); $suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\SqliteSchemaTest');
$suite->addTestSuite('Doctrine\Tests\DBAL\Functional\Schema\MySqlSchemaTest');
return $suite; return $suite;
} }
......
<?php
namespace Doctrine\Tests\DBAL\Functional\Schema;
use Doctrine\Tests\TestUtil;
use Doctrine\DBAL\Schema;
require_once __DIR__ . '/../../../TestInit.php';
class MysqlSchemaTest extends \Doctrine\Tests\DbalFunctionalTestCase
{
private $_conn;
protected function setUp()
{
$this->_conn = TestUtil::getConnection();
if ($this->_conn->getDatabasePlatform()->getName() !== 'mysql')
{
$this->markTestSkipped('The MySqlSchemaTest requires the use of mysql');
}
$this->_sm = new Schema\MySqlSchemaManager($this->_conn);
}
public function testListTableColumns()
{
$columns = array(
'id' => array(
'type' => new \Doctrine\DBAL\Types\IntegerType,
'autoincrement' => true,
'primary' => true,
'notnull' => true
),
'test' => array(
'type' => new \Doctrine\DBAL\Types\StringType,
'length' => 255
)
);
$options = array();
try {
$this->_sm->dropTable('list_tables_test');
} catch (\Exception $e) {}
$this->_sm->createTable('list_tables_test', $columns, $options);
$columns = $this->_sm->listTableColumns('list_tables_test');
$this->assertEquals($columns[0]['name'], 'id');
$this->assertEquals($columns[0]['primary'], true);
$this->assertEquals(get_class($columns[0]['type']), 'Doctrine\DBAL\Types\IntegerType');
$this->assertEquals($columns[0]['length'], 4);
$this->assertEquals($columns[0]['unsigned'], false);
$this->assertEquals($columns[0]['fixed'], false);
$this->assertEquals($columns[0]['notnull'], true);
$this->assertEquals($columns[0]['default'], null);
$this->assertEquals($columns[1]['name'], 'test');
$this->assertEquals($columns[1]['primary'], false);
$this->assertEquals(get_class($columns[1]['type']), 'Doctrine\DBAL\Types\StringType');
$this->assertEquals($columns[1]['length'], 255);
$this->assertEquals($columns[1]['unsigned'], false);
$this->assertEquals($columns[1]['fixed'], false);
$this->assertEquals($columns[1]['notnull'], false);
$this->assertEquals($columns[1]['default'], null);
}
}
\ No newline at end of file
<?php <?php
namespace Doctrine\Tests\DBAL\Functional\Schemas; namespace Doctrine\Tests\DBAL\Functional\Schema;
use Doctrine\Tests\TestUtil; use Doctrine\Tests\TestUtil;
use Doctrine\DBAL\Schema; use Doctrine\DBAL\Schema;
...@@ -16,7 +16,7 @@ class SqliteSchemaTest extends \Doctrine\Tests\DbalFunctionalTestCase ...@@ -16,7 +16,7 @@ class SqliteSchemaTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->_conn = TestUtil::getConnection(); $this->_conn = TestUtil::getConnection();
if ($this->_conn->getDatabasePlatform()->getName() !== 'sqlite') if ($this->_conn->getDatabasePlatform()->getName() !== 'sqlite')
{ {
$this->markTestSkipped('The SqliteSchemaTest requires the use of the pdo_sqlite'); $this->markTestSkipped('The SqliteSchemaTest requires the use of sqlite');
} }
$this->_sm = new Schema\SqliteSchemaManager($this->_conn); $this->_sm = new Schema\SqliteSchemaManager($this->_conn);
} }
...@@ -41,7 +41,23 @@ class SqliteSchemaTest extends \Doctrine\Tests\DbalFunctionalTestCase ...@@ -41,7 +41,23 @@ class SqliteSchemaTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->_sm->createTable('list_tables_test', $columns, $options); $this->_sm->createTable('list_tables_test', $columns, $options);
$columns = $this->_sm->listTableColumns('list_tables_test'); $columns = $this->_sm->listTableColumns('list_tables_test');
$this->assertEquals($columns[0]['name'], 'id'); $this->assertEquals($columns[0]['name'], 'id');
$this->assertEquals($columns[0]['primary'], true);
$this->assertEquals(get_class($columns[0]['type']), 'Doctrine\DBAL\Types\IntegerType');
$this->assertEquals($columns[0]['length'], 4);
$this->assertEquals($columns[0]['unsigned'], false);
$this->assertEquals($columns[0]['fixed'], false);
$this->assertEquals($columns[0]['notnull'], true);
$this->assertEquals($columns[0]['default'], null);
$this->assertEquals($columns[1]['name'], 'test'); $this->assertEquals($columns[1]['name'], 'test');
$this->assertEquals($columns[1]['primary'], false);
$this->assertEquals(get_class($columns[1]['type']), 'Doctrine\DBAL\Types\StringType');
$this->assertEquals($columns[1]['length'], 255);
$this->assertEquals($columns[1]['unsigned'], false);
$this->assertEquals($columns[1]['fixed'], false);
$this->assertEquals($columns[1]['notnull'], false);
$this->assertEquals($columns[1]['default'], null);
} }
} }
\ No newline at end of file
<?php
namespace Doctrine\Tests;
class DbalFunctionalTestCase extends DbalTestCase
{
}
\ No newline at end of file
...@@ -13,11 +13,11 @@ ...@@ -13,11 +13,11 @@
--> -->
<phpunit> <phpunit>
<php> <php>
<var name="db_type" value="mysql"/> <var name="db_type" value="pdo_mysql"/>
<var name="db_host" value="localhost" /> <var name="db_host" value="localhost" />
<var name="db_username" value="foo" /> <var name="db_username" value="root" />
<var name="db_password" value="bar" /> <var name="db_password" value="" />
<var name="db_name" value="doctrinetests" /> <var name="db_name" value="doctrine_tests" />
<var name="db_port" value="3306"/> <var name="db_port" value="3306"/>
</php> </php>
</phpunit> </phpunit>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment