Commit 793d249e authored by Benjamin Eberlei's avatar Benjamin Eberlei

Merge pull request #98 from doctrine/DBAL-204

[DBAL-204] Full Schema Namespacing Support
parents 087b6937 27b3c95b
...@@ -83,4 +83,31 @@ class Configuration ...@@ -83,4 +83,31 @@ class Configuration
{ {
$this->_attributes['resultCacheImpl'] = $cacheImpl; $this->_attributes['resultCacheImpl'] = $cacheImpl;
} }
}
\ No newline at end of file /**
* Filter schema assets expression.
*
* Only include tables/sequences matching the filter expression regexp in
* schema instances generated for the active connection when calling
* {AbstractSchemaManager#createSchema()}.
*
* @param string $filterExpression
*/
public function setFilterSchemaAssetsExpression($filterExpression)
{
$this->_attributes['filterSchemaAssetsExpression'] = $filterExpression;
}
/**
* Return filter schema assets expression.
*
* @return string|null
*/
public function getFilterSchemaAssetsExpression()
{
if (isset($this->_attributes['filterSchemaAssetsExpression'])) {
return $this->_attributes['filterSchemaAssetsExpression'];
}
return null;
}
}
...@@ -2239,7 +2239,7 @@ abstract class AbstractPlatform ...@@ -2239,7 +2239,7 @@ abstract class AbstractPlatform
return Connection::TRANSACTION_READ_COMMITTED; return Connection::TRANSACTION_READ_COMMITTED;
} }
/* supports*() metods */ /* supports*() methods */
/** /**
* Whether the platform supports sequences. * Whether the platform supports sequences.
...@@ -2348,6 +2348,20 @@ abstract class AbstractPlatform ...@@ -2348,6 +2348,20 @@ abstract class AbstractPlatform
return false; return false;
} }
/**
* Can this platform emulate schemas?
*
* Platforms that either support or emulate schemas don't automatically
* filter a schema for the namespaced elements in {@link
* AbstractManager#createSchema}.
*
* @return bool
*/
public function canEmulateSchemas()
{
return false;
}
/** /**
* Some databases don't allow to create and drop databases at all or only with certain tools. * Some databases don't allow to create and drop databases at all or only with certain tools.
* *
......
...@@ -501,4 +501,18 @@ class SqlitePlatform extends AbstractPlatform ...@@ -501,4 +501,18 @@ class SqlitePlatform extends AbstractPlatform
$tableName = str_replace(".", "__", $tableName); $tableName = str_replace(".", "__", $tableName);
return $tableName; return $tableName;
} }
/**
* Sqlite Platform emulates schema by underscoring each dot and generating tables
* into the default database.
*
* This hack is implemented to be able to use SQLite as testdriver when
* using schema supporting databases.
*
* @return bool
*/
public function canEmulateSchemas()
{
return true;
}
} }
...@@ -39,6 +39,16 @@ abstract class AbstractAsset ...@@ -39,6 +39,16 @@ abstract class AbstractAsset
*/ */
protected $_name; protected $_name;
/**
* Namespace of the asset. If none isset the default namespace is assumed.
*
* @var string
*/
protected $_namespace;
/**
* @var bool
*/
protected $_quoted = false; protected $_quoted = false;
/** /**
...@@ -52,9 +62,73 @@ abstract class AbstractAsset ...@@ -52,9 +62,73 @@ abstract class AbstractAsset
$this->_quoted = true; $this->_quoted = true;
$name = $this->trimQuotes($name); $name = $this->trimQuotes($name);
} }
if (strpos($name, ".") !== false) {
$parts = explode(".", $name);
$this->_namespace = $parts[0];
$name = $parts[1];
}
$this->_name = $name; $this->_name = $name;
} }
/**
* Is this asset in the default namespace?
*
* @param string $defaultNamespaceName
* @return bool
*/
public function isInDefaultNamespace($defaultNamespaceName)
{
return $this->_namespace == $defaultNamespaceName || $this->_namespace === null;
}
/**
* Get namespace name of this asset.
*
* If NULL is returned this means the default namespace is used.
*
* @return string
*/
public function getNamespaceName()
{
return $this->_namespace;
}
/**
* The shortest name is stripped of the default namespace. All other
* namespaced elements are returned as full-qualified names.
*
* @param string
* @return string
*/
public function getShortestName($defaultNamespaceName)
{
$shortestName = $this->getName();
if ($this->_namespace == $defaultNamespaceName) {
$shortestName = $this->_name;
}
return strtolower($shortestName);
}
/**
* The normalized name is full-qualified and lowerspaced. Lowerspacing is
* actually wrong, but we have to do it to keep our sanity. If you are
* using database objects that only differentiate in the casing (FOO vs
* Foo) then you will NOT be able to use Doctrine Schema abstraction.
*
* Every non-namespaced element is prefixed with the default namespace
* name which is passed as argument to this method.
*
* @return string
*/
public function getFullQualifiedName($defaultNamespaceName)
{
$name = $this->getName();
if (!$this->_namespace) {
$name = $defaultNamespaceName . "." . $name;
}
return strtolower($name);
}
/** /**
* Check if this identifier is quoted. * Check if this identifier is quoted.
* *
...@@ -84,6 +158,9 @@ abstract class AbstractAsset ...@@ -84,6 +158,9 @@ abstract class AbstractAsset
*/ */
public function getName() public function getName()
{ {
if ($this->_namespace) {
return $this->_namespace . "." . $this->_name;
}
return $this->_name; return $this->_name;
} }
...@@ -97,7 +174,7 @@ abstract class AbstractAsset ...@@ -97,7 +174,7 @@ abstract class AbstractAsset
public function getQuotedName(AbstractPlatform $platform) public function getQuotedName(AbstractPlatform $platform)
{ {
$keywords = $platform->getReservedKeywordsList(); $keywords = $platform->getReservedKeywordsList();
$parts = explode(".", $this->_name); $parts = explode(".", $this->getName());
foreach ($parts AS $k => $v) { foreach ($parts AS $k => $v) {
$parts[$k] = ($this->_quoted || $keywords->isKeyword($v)) ? $platform->quoteIdentifier($v) : $v; $parts[$k] = ($this->_quoted || $keywords->isKeyword($v)) ? $platform->quoteIdentifier($v) : $v;
} }
...@@ -124,4 +201,4 @@ abstract class AbstractAsset ...@@ -124,4 +201,4 @@ abstract class AbstractAsset
}, $columnNames)); }, $columnNames));
return substr(strtoupper($prefix . "_" . $hash), 0, $maxSize); return substr(strtoupper($prefix . "_" . $hash), 0, $maxSize);
} }
} }
\ No newline at end of file
...@@ -129,7 +129,7 @@ abstract class AbstractSchemaManager ...@@ -129,7 +129,7 @@ abstract class AbstractSchemaManager
$sequences = $this->_conn->fetchAll($sql); $sequences = $this->_conn->fetchAll($sql);
return $this->_getPortableSequencesList($sequences); return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
} }
/** /**
...@@ -188,7 +188,6 @@ abstract class AbstractSchemaManager ...@@ -188,7 +188,6 @@ abstract class AbstractSchemaManager
return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames()))); return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
} }
/** /**
* Return a list of all tables in the current database * Return a list of all tables in the current database
* *
...@@ -199,8 +198,34 @@ abstract class AbstractSchemaManager ...@@ -199,8 +198,34 @@ abstract class AbstractSchemaManager
$sql = $this->_platform->getListTablesSQL(); $sql = $this->_platform->getListTablesSQL();
$tables = $this->_conn->fetchAll($sql); $tables = $this->_conn->fetchAll($sql);
$tableNames = $this->_getPortableTablesList($tables);
return $this->filterAssetNames($tableNames);
}
return $this->_getPortableTablesList($tables); /**
* Filter asset names if they are configured to return only a subset of all
* the found elements.
*
* @param array $assetNames
* @return array
*/
protected function filterAssetNames($assetNames)
{
$filterExpr = $this->getFilterSchemaAssetsExpression();
if (!$filterExpr) {
return $assetNames;
}
return array_values (
array_filter($assetNames, function ($assetName) use ($filterExpr) {
$assetName = ($assetName instanceof AbstractAsset) ? $assetName->getName() : $assetName;
return preg_match('(' . $filterExpr . ')', $assetName);
})
);
}
protected function getFilterSchemaAssetsExpression()
{
return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression();
} }
/** /**
...@@ -817,9 +842,31 @@ abstract class AbstractSchemaManager ...@@ -817,9 +842,31 @@ abstract class AbstractSchemaManager
$schemaConfig = new SchemaConfig(); $schemaConfig = new SchemaConfig();
$schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength()); $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
$searchPaths = $this->getSchemaSearchPaths();
if (isset($searchPaths[0])) {
$schemaConfig->setName($searchPaths[0]);
}
return $schemaConfig; return $schemaConfig;
} }
/**
* The search path for namespaces in the currently connected database.
*
* The first entry is usually the default namespace in the Schema. All
* further namespaces contain tables/sequences which can also be addressed
* with a short, not full-qualified name.
*
* For databases that don't support subschema/namespaces this method
* returns the name of the currently connected database.
*
* @return array
*/
public function getSchemaSearchPaths()
{
return array($this->_conn->getDatabase());
}
/** /**
* Given a table comment this method tries to extract a typehint for Doctrine Type, or returns * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns
* the type given as default. * the type given as default.
......
...@@ -61,20 +61,24 @@ class Comparator ...@@ -61,20 +61,24 @@ class Comparator
$foreignKeysToTable = array(); $foreignKeysToTable = array();
foreach ( $toSchema->getTables() AS $tableName => $table ) { foreach ( $toSchema->getTables() AS $table ) {
if ( !$fromSchema->hasTable($tableName) ) { $tableName = $table->getShortestName($toSchema->getName());
$diff->newTables[$tableName] = $table; if ( ! $fromSchema->hasTable($tableName)) {
$diff->newTables[$tableName] = $toSchema->getTable($tableName);
} else { } else {
$tableDifferences = $this->diffTable( $fromSchema->getTable($tableName), $table ); $tableDifferences = $this->diffTable($fromSchema->getTable($tableName), $toSchema->getTable($tableName));
if ( $tableDifferences !== false ) { if ($tableDifferences !== false) {
$diff->changedTables[$tableName] = $tableDifferences; $diff->changedTables[$tableName] = $tableDifferences;
} }
} }
} }
/* Check if there are tables removed */ /* Check if there are tables removed */
foreach ( $fromSchema->getTables() AS $tableName => $table ) { foreach ($fromSchema->getTables() AS $table) {
if ( !$toSchema->hasTable($tableName) ) { $tableName = $table->getShortestName($fromSchema->getName());
$table = $fromSchema->getTable($tableName);
if ( ! $toSchema->hasTable($tableName) ) {
$diff->removedTables[$tableName] = $table; $diff->removedTables[$tableName] = $table;
} }
...@@ -94,7 +98,8 @@ class Comparator ...@@ -94,7 +98,8 @@ class Comparator
} }
} }
foreach ( $toSchema->getSequences() AS $sequenceName => $sequence) { foreach ($toSchema->getSequences() AS $sequence) {
$sequenceName = $sequence->getShortestName($toSchema->getName());
if (!$fromSchema->hasSequence($sequenceName)) { if (!$fromSchema->hasSequence($sequenceName)) {
$diff->newSequences[] = $sequence; $diff->newSequences[] = $sequence;
} else { } else {
...@@ -104,7 +109,8 @@ class Comparator ...@@ -104,7 +109,8 @@ class Comparator
} }
} }
foreach ($fromSchema->getSequences() AS $sequenceName => $sequence) { foreach ($fromSchema->getSequences() AS $sequence) {
$sequenceName = $sequence->getShortestName($fromSchema->getName());
if (!$toSchema->hasSequence($sequenceName)) { if (!$toSchema->hasSequence($sequenceName)) {
$diff->removedSequences[] = $sequence; $diff->removedSequences[] = $sequence;
} }
......
<?php <?php
/* /*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
...@@ -28,10 +26,30 @@ use Doctrine\DBAL\Schema\Visitor\Visitor; ...@@ -28,10 +26,30 @@ use Doctrine\DBAL\Schema\Visitor\Visitor;
/** /**
* Object representation of a database schema * Object representation of a database schema
* *
* Different vendors have very inconsistent naming with regard to the concept
* of a "schema". Doctrine understands a schema as the entity that conceptually
* wraps a set of database objects such as tables, sequences, indexes and
* foreign keys that belong to each other into a namespace. A Doctrine Schema
* has nothing to do with the "SCHEMA" defined as in PostgreSQL, it is more
* related to the concept of "DATABASE" that exists in MySQL and PostgreSQL.
*
* Every asset in the doctrine schema has a name. A name consists of either a
* namespace.local name pair or just a local unqualified name.
*
* The abstraction layer that covers a PostgreSQL schema is the namespace of an
* database object (asset). A schema can have a name, which will be used as
* default namespace for the unqualified database objects that are created in
* the schema.
*
* In the case of MySQL where cross-database queries are allowed this leads to
* databases being "misinterpreted" as namespaces. This is intentional, however
* the CREATE/DROP SQL visitors will just filter this queries and do not
* execute them. Only the queries for the currently connected database are
* executed.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org * @link www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de> * @author Benjamin Eberlei <kontakt@beberlei.de>
*/ */
class Schema extends AbstractAsset class Schema extends AbstractAsset
...@@ -64,6 +82,7 @@ class Schema extends AbstractAsset ...@@ -64,6 +82,7 @@ class Schema extends AbstractAsset
$schemaConfig = new SchemaConfig(); $schemaConfig = new SchemaConfig();
} }
$this->_schemaConfig = $schemaConfig; $this->_schemaConfig = $schemaConfig;
$this->_setName($schemaConfig->getName() ?: 'public');
foreach ($tables AS $table) { foreach ($tables AS $table) {
$this->_addTable($table); $this->_addTable($table);
...@@ -86,7 +105,7 @@ class Schema extends AbstractAsset ...@@ -86,7 +105,7 @@ class Schema extends AbstractAsset
*/ */
protected function _addTable(Table $table) protected function _addTable(Table $table)
{ {
$tableName = strtolower($table->getName()); $tableName = $table->getFullQualifiedName($this->getName());
if(isset($this->_tables[$tableName])) { if(isset($this->_tables[$tableName])) {
throw SchemaException::tableAlreadyExists($tableName); throw SchemaException::tableAlreadyExists($tableName);
} }
...@@ -100,7 +119,7 @@ class Schema extends AbstractAsset ...@@ -100,7 +119,7 @@ class Schema extends AbstractAsset
*/ */
protected function _addSequence(Sequence $sequence) protected function _addSequence(Sequence $sequence)
{ {
$seqName = strtolower($sequence->getName()); $seqName = $sequence->getFullQualifiedName($this->getName());
if (isset($this->_sequences[$seqName])) { if (isset($this->_sequences[$seqName])) {
throw SchemaException::sequenceAlreadyExists($seqName); throw SchemaException::sequenceAlreadyExists($seqName);
} }
...@@ -123,7 +142,7 @@ class Schema extends AbstractAsset ...@@ -123,7 +142,7 @@ class Schema extends AbstractAsset
*/ */
public function getTable($tableName) public function getTable($tableName)
{ {
$tableName = strtolower($tableName); $tableName = $this->getFullQualifiedAssetName($tableName);
if (!isset($this->_tables[$tableName])) { if (!isset($this->_tables[$tableName])) {
throw SchemaException::tableDoesNotExist($tableName); throw SchemaException::tableDoesNotExist($tableName);
} }
...@@ -131,6 +150,17 @@ class Schema extends AbstractAsset ...@@ -131,6 +150,17 @@ class Schema extends AbstractAsset
return $this->_tables[$tableName]; return $this->_tables[$tableName];
} }
/**
* @return string
*/
private function getFullQualifiedAssetName($name)
{
if (strpos($name, ".") === false) {
$name = $this->getName() . "." . $name;
}
return strtolower($name);
}
/** /**
* Does this schema have a table with the given name? * Does this schema have a table with the given name?
* *
...@@ -139,17 +169,24 @@ class Schema extends AbstractAsset ...@@ -139,17 +169,24 @@ class Schema extends AbstractAsset
*/ */
public function hasTable($tableName) public function hasTable($tableName)
{ {
$tableName = strtolower($tableName); $tableName = $this->getFullQualifiedAssetName($tableName);
return isset($this->_tables[$tableName]); return isset($this->_tables[$tableName]);
} }
/** /**
* @param string $sequenceName * Get all table names, prefixed with a schema name, even the default one
* @return bool * if present.
*
* @return array
*/ */
public function getTableNames()
{
return array_keys($this->_tables);
}
public function hasSequence($sequenceName) public function hasSequence($sequenceName)
{ {
$sequenceName = strtolower($sequenceName); $sequenceName = $this->getFullQualifiedAssetName($sequenceName);
return isset($this->_sequences[$sequenceName]); return isset($this->_sequences[$sequenceName]);
} }
...@@ -160,7 +197,7 @@ class Schema extends AbstractAsset ...@@ -160,7 +197,7 @@ class Schema extends AbstractAsset
*/ */
public function getSequence($sequenceName) public function getSequence($sequenceName)
{ {
$sequenceName = strtolower($sequenceName); $sequenceName = $this->getFullQualifiedAssetName($sequenceName);
if(!$this->hasSequence($sequenceName)) { if(!$this->hasSequence($sequenceName)) {
throw SchemaException::sequenceDoesNotExist($sequenceName); throw SchemaException::sequenceDoesNotExist($sequenceName);
} }
...@@ -213,7 +250,7 @@ class Schema extends AbstractAsset ...@@ -213,7 +250,7 @@ class Schema extends AbstractAsset
*/ */
public function dropTable($tableName) public function dropTable($tableName)
{ {
$tableName = strtolower($tableName); $tableName = $this->getFullQualifiedAssetName($tableName);
$table = $this->getTable($tableName); $table = $this->getTable($tableName);
unset($this->_tables[$tableName]); unset($this->_tables[$tableName]);
return $this; return $this;
...@@ -240,7 +277,7 @@ class Schema extends AbstractAsset ...@@ -240,7 +277,7 @@ class Schema extends AbstractAsset
*/ */
public function dropSequence($sequenceName) public function dropSequence($sequenceName)
{ {
$sequenceName = strtolower($sequenceName); $sequenceName = $this->getFullQualifiedAssetName($sequenceName);
unset($this->_sequences[$sequenceName]); unset($this->_sequences[$sequenceName]);
return $this; return $this;
} }
......
<?php <?php
/* /*
* $Id: Schema.php 6876 2009-12-06 23:11:35Z beberlei $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
...@@ -27,7 +25,6 @@ namespace Doctrine\DBAL\Schema; ...@@ -27,7 +25,6 @@ namespace Doctrine\DBAL\Schema;
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org * @link www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de> * @author Benjamin Eberlei <kontakt@beberlei.de>
*/ */
class SchemaConfig class SchemaConfig
...@@ -42,6 +39,11 @@ class SchemaConfig ...@@ -42,6 +39,11 @@ class SchemaConfig
*/ */
protected $_maxIdentifierLength = 63; protected $_maxIdentifierLength = 63;
/**
* @var string
*/
protected $_name;
/** /**
* @return bool * @return bool
*/ */
...@@ -73,4 +75,24 @@ class SchemaConfig ...@@ -73,4 +75,24 @@ class SchemaConfig
{ {
return $this->_maxIdentifierLength; return $this->_maxIdentifierLength;
} }
}
\ No newline at end of file /**
* Get default namespace of schema objects.
*
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* set default namespace name of schema objects.
*
* @param _name the value to set.
*/
public function setName($name)
{
$this->_name = $name;
}
}
...@@ -632,4 +632,4 @@ class Table extends AbstractAsset ...@@ -632,4 +632,4 @@ class Table extends AbstractAsset
$this->_fkConstraints[$k]->setLocalTable($this); $this->_fkConstraints[$k]->setLocalTable($this);
} }
} }
} }
\ No newline at end of file
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Schema\Visitor;
use Doctrine\DBAL\Platforms\AbstractPlatform,
Doctrine\DBAL\Schema\Table,
Doctrine\DBAL\Schema\Schema,
Doctrine\DBAL\Schema\Column,
Doctrine\DBAL\Schema\ForeignKeyConstraint,
Doctrine\DBAL\Schema\Constraint,
Doctrine\DBAL\Schema\Sequence,
Doctrine\DBAL\Schema\Index;
/**
* Remove assets from a schema that are not in the default namespace.
*
* Some databases such as MySQL support cross databases joins, but don't
* allow to call DDLs to a database from another connected database.
* Before a schema is serialized into SQL this visitor can cleanup schemas with
* non default namespaces.
*
* This visitor filters all these non-default namespaced tables and sequences
* and removes them from the SChema instance.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.2
*/
class RemoveNamespacedAssets implements Visitor
{
/**
* @var Schema
*/
private $schema;
/**
* @param Schema $schema
*/
public function acceptSchema(Schema $schema)
{
$this->schema = $schema;
}
/**
* @param Table $table
*/
public function acceptTable(Table $table)
{
if ( ! $table->isInDefaultNamespace($this->schema->getName()) ) {
$this->schema->dropTable($table->getName());
}
}
/**
* @param Sequence $sequence
*/
public function acceptSequence(Sequence $sequence)
{
if ( ! $sequence->isInDefaultNamespace($this->schema->getName()) ) {
$this->schema->dropSequence($sequence->getName());
}
}
/**
* @param Column $column
*/
public function acceptColumn(Table $table, Column $column)
{
}
/**
* @param Table $localTable
* @param ForeignKeyConstraint $fkConstraint
*/
public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
{
}
/**
* @param Table $table
* @param Index $index
*/
public function acceptIndex(Table $table, Index $index)
{
}
}
...@@ -10,6 +10,11 @@ require_once __DIR__ . '/../../../TestInit.php'; ...@@ -10,6 +10,11 @@ require_once __DIR__ . '/../../../TestInit.php';
class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
{ {
public function tearDown()
{
parent::tearDown();
$this->_conn->getConfiguration()->setFilterSchemaAssetsExpression(null);
}
/** /**
* @group DBAL-177 * @group DBAL-177
*/ */
...@@ -166,6 +171,27 @@ class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase ...@@ -166,6 +171,27 @@ class PostgreSqlSchemaManagerTest extends SchemaManagerFunctionalTestCase
$this->_conn->getDatabasePlatform()->getCreateTableSQL($table) $this->_conn->getDatabasePlatform()->getCreateTableSQL($table)
); );
} }
/**
* @group DBAL-204
*/
public function testFilterSchemaExpression()
{
$testTable = new \Doctrine\DBAL\Schema\Table('dbal204_test_prefix');
$column = $testTable->addColumn('id', 'integer');
$this->_sm->createTable($testTable);
$testTable = new \Doctrine\DBAL\Schema\Table('dbal204_without_prefix');
$column = $testTable->addColumn('id', 'integer');
$this->_sm->createTable($testTable);
$this->_conn->getConfiguration()->setFilterSchemaAssetsExpression('^dbal204_');
$names = $this->_sm->listTableNames();
$this->assertEquals(2, count($names));
$this->_conn->getConfiguration()->setFilterSchemaAssetsExpression('^dbal204_test');
$names = $this->_sm->listTableNames();
$this->assertEquals(1, count($names));
}
} }
class MoneyType extends Type class MoneyType extends Type
...@@ -181,4 +207,4 @@ class MoneyType extends Type ...@@ -181,4 +207,4 @@ class MoneyType extends Type
return 'MyMoney'; return 'MyMoney';
} }
} }
\ No newline at end of file
...@@ -366,7 +366,6 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest ...@@ -366,7 +366,6 @@ class SchemaManagerFunctionalTestCase extends \Doctrine\Tests\DbalFunctionalTest
$this->createTestTable('test_table'); $this->createTestTable('test_table');
$schema = $this->_sm->createSchema(); $schema = $this->_sm->createSchema();
$this->assertTrue($schema->hasTable('test_table')); $this->assertTrue($schema->hasTable('test_table'));
} }
......
...@@ -22,6 +22,7 @@ namespace Doctrine\Tests\DBAL\Schema; ...@@ -22,6 +22,7 @@ namespace Doctrine\Tests\DBAL\Schema;
require_once __DIR__ . '/../../TestInit.php'; require_once __DIR__ . '/../../TestInit.php';
use Doctrine\DBAL\Schema\Schema, use Doctrine\DBAL\Schema\Schema,
Doctrine\DBAL\Schema\SchemaConfig,
Doctrine\DBAL\Schema\Table, Doctrine\DBAL\Schema\Table,
Doctrine\DBAL\Schema\Column, Doctrine\DBAL\Schema\Column,
Doctrine\DBAL\Schema\Index, Doctrine\DBAL\Schema\Index,
...@@ -702,6 +703,62 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -702,6 +703,62 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(), $c->diffColumn($column, $column2)); $this->assertEquals(array(), $c->diffColumn($column, $column2));
} }
/**
* @group DBAL-204
*/
public function testFqnSchemaComparision()
{
$config = new SchemaConfig();
$config->setName("foo");
$oldSchema = new Schema(array(), array(), $config);
$oldSchema->createTable('bar');
$newSchema= new Schema(array(), array(), $config);
$newSchema->createTable('foo.bar');
$c = new Comparator();
$this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema));
}
/**
* @group DBAL-204
*/
public function testFqnSchemaComparisionDifferentSchemaNameButSameTableNoDiff()
{
$config = new SchemaConfig();
$config->setName("foo");
$oldSchema = new Schema(array(), array(), $config);
$oldSchema->createTable('foo.bar');
$newSchema = new Schema();
$newSchema->createTable('bar');
$c = new Comparator();
$diff = $c->compare($oldSchema, $newSchema);
$this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema));
}
/**
* @group DBAL-204
*/
public function testFqnSchemaComparisionNoSchemaSame()
{
$config = new SchemaConfig();
$config->setName("foo");
$oldSchema = new Schema(array(), array(), $config);
$oldSchema->createTable('bar');
$newSchema = new Schema();
$newSchema->createTable('bar');
$c = new Comparator();
$diff = $c->compare($oldSchema, $newSchema);
$this->assertEquals(new SchemaDiff(), $c->compare($oldSchema, $newSchema));
}
/** /**
* @param SchemaDiff $diff * @param SchemaDiff $diff
* @param int $newTableCount * @param int $newTableCount
...@@ -727,4 +784,4 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase ...@@ -727,4 +784,4 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($changeSequenceCount, count($diff->changedSequences), "Expected number of changed sequences is wrong."); $this->assertEquals($changeSequenceCount, count($diff->changedSequences), "Expected number of changed sequences is wrong.");
$this->assertEquals($removeSequenceCount, count($diff->removedSequences), "Expected number of removed sequences is wrong."); $this->assertEquals($removeSequenceCount, count($diff->removedSequences), "Expected number of removed sequences is wrong.");
} }
} }
\ No newline at end of file
...@@ -12,7 +12,7 @@ class SchemaTest extends \PHPUnit_Framework_TestCase ...@@ -12,7 +12,7 @@ class SchemaTest extends \PHPUnit_Framework_TestCase
{ {
public function testAddTable() public function testAddTable()
{ {
$tableName = "foo"; $tableName = "public.foo";
$table = new Table($tableName); $table = new Table($tableName);
$schema = new Schema(array($table)); $schema = new Schema(array($table));
...@@ -107,7 +107,7 @@ class SchemaTest extends \PHPUnit_Framework_TestCase ...@@ -107,7 +107,7 @@ class SchemaTest extends \PHPUnit_Framework_TestCase
$this->assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $schema->getSequence("a_seq")); $this->assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $schema->getSequence("a_seq"));
$sequences = $schema->getSequences(); $sequences = $schema->getSequences();
$this->assertArrayHasKey('a_seq', $sequences); $this->assertArrayHasKey('public.a_seq', $sequences);
} }
public function testSequenceAccessCaseInsensitive() public function testSequenceAccessCaseInsensitive()
...@@ -145,7 +145,7 @@ class SchemaTest extends \PHPUnit_Framework_TestCase ...@@ -145,7 +145,7 @@ class SchemaTest extends \PHPUnit_Framework_TestCase
$this->assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $schema->getSequence("a_seq")); $this->assertInstanceOf('Doctrine\DBAL\Schema\Sequence', $schema->getSequence("a_seq"));
$sequences = $schema->getSequences(); $sequences = $schema->getSequences();
$this->assertArrayHasKey('a_seq', $sequences); $this->assertArrayHasKey('public.a_seq', $sequences);
} }
public function testDropSequence() public function testDropSequence()
...@@ -208,4 +208,4 @@ class SchemaTest extends \PHPUnit_Framework_TestCase ...@@ -208,4 +208,4 @@ class SchemaTest extends \PHPUnit_Framework_TestCase
$fk = current($fk); $fk = current($fk);
$this->assertSame($schemaNew->getTable('bar'), $this->readAttribute($fk, '_localTable')); $this->assertSame($schemaNew->getTable('bar'), $this->readAttribute($fk, '_localTable'));
} }
} }
\ No newline at end of file
...@@ -483,4 +483,18 @@ class TableTest extends \Doctrine\Tests\DbalTestCase ...@@ -483,4 +483,18 @@ class TableTest extends \Doctrine\Tests\DbalTestCase
$this->assertEquals("test.test", $table->getName()); $this->assertEquals("test.test", $table->getName());
$this->assertEquals("`test`.`test`", $table->getQuotedName(new \Doctrine\DBAL\Platforms\MySqlPlatform)); $this->assertEquals("`test`.`test`", $table->getQuotedName(new \Doctrine\DBAL\Platforms\MySqlPlatform));
} }
}
\ No newline at end of file /**
* @group DBAL-204
*/
public function testFullQualifiedTableName()
{
$table = new Table("`test`.`test`");
$this->assertEquals('test.test', $table->getFullQualifiedName("test"));
$this->assertEquals('test.test', $table->getFullQualifiedName("other"));
$table = new Table("test");
$this->assertEquals('test.test', $table->getFullQualifiedName("test"));
$this->assertEquals('other.test', $table->getFullQualifiedName("other"));
}
}
<?php
namespace Doctrine\Tests\DBAL\Schema\Visitor;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaConfig;
use Doctrine\DBAL\Schema\Visitor\RemoveNamespacedAssets;
class RemoveNamespacedAssetsTest extends \PHPUnit_Framework_TestCase
{
/**
* @group DBAL-204
*/
public function testRemoveNamespacedAssets()
{
$config = new SchemaConfig;
$config->setName("test");
$schema = new Schema(array(), array(), $config);
$schema->createTable("test.test");
$schema->createTable("foo.bar");
$schema->createTable("baz");
$schema->visit(new RemoveNamespacedAssets());
$tables = $schema->getTables();
$this->assertEquals(array("test.test", "test.baz"), array_keys($tables), "Only 2 tables should be present, both in 'test' namespace.");
}
}
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