Initial commit with Symfony 2.1+Vendors

Signed-off-by: Gergely POLONKAI (W00d5t0ck) <polesz@w00d5t0ck.info>
This commit is contained in:
Polonkai Gergely
2012-07-01 09:52:20 +02:00
commit 082a0130c2
5381 changed files with 416709 additions and 0 deletions

View File

@@ -0,0 +1,204 @@
<?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;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* The abstract asset allows to reset the name of all assets without publishing this to the public userland.
*
* This encapsulation hack is necessary to keep a consistent state of the database schema. Say we have a list of tables
* array($tableName => Table($tableName)); if you want to rename the table, you have to make sure
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
abstract class AbstractAsset
{
/**
* @var string
*/
protected $_name;
/**
* Namespace of the asset. If none isset the default namespace is assumed.
*
* @var string
*/
protected $_namespace;
/**
* @var bool
*/
protected $_quoted = false;
/**
* Set name of this asset
*
* @param string $name
*/
protected function _setName($name)
{
if ($this->isQuoted($name)) {
$this->_quoted = true;
$name = $this->trimQuotes($name);
}
if (strpos($name, ".") !== false) {
$parts = explode(".", $name);
$this->_namespace = $parts[0];
$name = $parts[1];
}
$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.
*
* @param string $identifier
* @return bool
*/
protected function isQuoted($identifier)
{
return (isset($identifier[0]) && ($identifier[0] == '`' || $identifier[0] == '"'));
}
/**
* Trim quotes from the identifier.
*
* @param string $identifier
* @return string
*/
protected function trimQuotes($identifier)
{
return str_replace(array('`', '"'), '', $identifier);
}
/**
* Return name of this schema asset.
*
* @return string
*/
public function getName()
{
if ($this->_namespace) {
return $this->_namespace . "." . $this->_name;
}
return $this->_name;
}
/**
* Get the quoted representation of this asset but only if it was defined with one. Otherwise
* return the plain unquoted value as inserted.
*
* @param AbstractPlatform $platform
* @return string
*/
public function getQuotedName(AbstractPlatform $platform)
{
$keywords = $platform->getReservedKeywordsList();
$parts = explode(".", $this->getName());
foreach ($parts AS $k => $v) {
$parts[$k] = ($this->_quoted || $keywords->isKeyword($v)) ? $platform->quoteIdentifier($v) : $v;
}
return implode(".", $parts);
}
/**
* Generate an identifier from a list of column names obeying a certain string length.
*
* This is especially important for Oracle, since it does not allow identifiers larger than 30 chars,
* however building idents automatically for foreign keys, composite keys or such can easily create
* very long names.
*
* @param array $columnNames
* @param string $prefix
* @param int $maxSize
* @return string
*/
protected function _generateIdentifierName($columnNames, $prefix='', $maxSize=30)
{
$hash = implode("", array_map(function($column) {
return dechex(crc32($column));
}, $columnNames));
return substr(strtoupper($prefix . "_" . $hash), 0, $maxSize);
}
}

View File

@@ -0,0 +1,890 @@
<?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;
use Doctrine\DBAL\Events;
use Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs;
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
use Doctrine\DBAL\Types;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Base class for schema managers. Schema managers are used to inspect and/or
* modify the database schema/structure.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Roman Borschel <roman@code-factory.org>
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
*/
abstract class AbstractSchemaManager
{
/**
* Holds instance of the Doctrine connection for this schema manager
*
* @var \Doctrine\DBAL\Connection
*/
protected $_conn;
/**
* Holds instance of the database platform used for this schema manager
*
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
*/
protected $_platform;
/**
* Constructor. Accepts the Connection instance to manage the schema for
*
* @param \Doctrine\DBAL\Connection $conn
*/
public function __construct(\Doctrine\DBAL\Connection $conn)
{
$this->_conn = $conn;
$this->_platform = $this->_conn->getDatabasePlatform();
}
/**
* Return associated platform.
*
* @return \Doctrine\DBAL\Platform\AbstractPlatform
*/
public function getDatabasePlatform()
{
return $this->_platform;
}
/**
* Try any method on the schema manager. Normally a method throws an
* exception when your DBMS doesn't support it or if an error occurs.
* This method allows you to try and method on your SchemaManager
* instance and will return false if it does not work or is not supported.
*
* <code>
* $result = $sm->tryMethod('dropView', 'view_name');
* </code>
*
* @return mixed
*/
public function tryMethod()
{
$args = func_get_args();
$method = $args[0];
unset($args[0]);
$args = array_values($args);
try {
return call_user_func_array(array($this, $method), $args);
} catch (\Exception $e) {
return false;
}
}
/**
* List the available databases for this connection
*
* @return array $databases
*/
public function listDatabases()
{
$sql = $this->_platform->getListDatabasesSQL();
$databases = $this->_conn->fetchAll($sql);
return $this->_getPortableDatabasesList($databases);
}
/**
* List the available sequences for this connection
*
* @return Sequence[]
*/
public function listSequences($database = null)
{
if (is_null($database)) {
$database = $this->_conn->getDatabase();
}
$sql = $this->_platform->getListSequencesSQL($database);
$sequences = $this->_conn->fetchAll($sql);
return $this->filterAssetNames($this->_getPortableSequencesList($sequences));
}
/**
* List the columns for a given table.
*
* In contrast to other libraries and to the old version of Doctrine,
* this column definition does try to contain the 'primary' field for
* the reason that it is not portable accross different RDBMS. Use
* {@see listTableIndexes($tableName)} to retrieve the primary key
* of a table. We're a RDBMS specifies more details these are held
* in the platformDetails array.
*
* @param string $table The name of the table.
* @param string $database
* @return Column[]
*/
public function listTableColumns($table, $database = null)
{
if (!$database) {
$database = $this->_conn->getDatabase();
}
$sql = $this->_platform->getListTableColumnsSQL($table, $database);
$tableColumns = $this->_conn->fetchAll($sql);
return $this->_getPortableTableColumnList($table, $database, $tableColumns);
}
/**
* List the indexes for a given table returning an array of Index instances.
*
* Keys of the portable indexes list are all lower-cased.
*
* @param string $table The name of the table
* @return Index[] $tableIndexes
*/
public function listTableIndexes($table)
{
$sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
$tableIndexes = $this->_conn->fetchAll($sql);
return $this->_getPortableTableIndexesList($tableIndexes, $table);
}
/**
* Return true if all the given tables exist.
*
* @param array $tableNames
* @return bool
*/
public function tablesExist($tableNames)
{
$tableNames = array_map('strtolower', (array)$tableNames);
return count($tableNames) == count(\array_intersect($tableNames, array_map('strtolower', $this->listTableNames())));
}
/**
* Return a list of all tables in the current database
*
* @return array
*/
public function listTableNames()
{
$sql = $this->_platform->getListTablesSQL();
$tables = $this->_conn->fetchAll($sql);
$tableNames = $this->_getPortableTablesList($tables);
return $this->filterAssetNames($tableNames);
}
/**
* 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();
}
/**
* List the tables for this connection
*
* @return Table[]
*/
public function listTables()
{
$tableNames = $this->listTableNames();
$tables = array();
foreach ($tableNames AS $tableName) {
$tables[] = $this->listTableDetails($tableName);
}
return $tables;
}
/**
* @param string $tableName
* @return Table
*/
public function listTableDetails($tableName)
{
$columns = $this->listTableColumns($tableName);
$foreignKeys = array();
if ($this->_platform->supportsForeignKeyConstraints()) {
$foreignKeys = $this->listTableForeignKeys($tableName);
}
$indexes = $this->listTableIndexes($tableName);
return new Table($tableName, $columns, $indexes, $foreignKeys, false, array());
}
/**
* List the views this connection has
*
* @return View[]
*/
public function listViews()
{
$database = $this->_conn->getDatabase();
$sql = $this->_platform->getListViewsSQL($database);
$views = $this->_conn->fetchAll($sql);
return $this->_getPortableViewsList($views);
}
/**
* List the foreign keys for the given table
*
* @param string $table The name of the table
* @return ForeignKeyConstraint[]
*/
public function listTableForeignKeys($table, $database = null)
{
if (is_null($database)) {
$database = $this->_conn->getDatabase();
}
$sql = $this->_platform->getListTableForeignKeysSQL($table, $database);
$tableForeignKeys = $this->_conn->fetchAll($sql);
return $this->_getPortableTableForeignKeysList($tableForeignKeys);
}
/* drop*() Methods */
/**
* Drops a database.
*
* NOTE: You can not drop the database this SchemaManager is currently connected to.
*
* @param string $database The name of the database to drop
*/
public function dropDatabase($database)
{
$this->_execSql($this->_platform->getDropDatabaseSQL($database));
}
/**
* Drop the given table
*
* @param string $table The name of the table to drop
*/
public function dropTable($table)
{
$this->_execSql($this->_platform->getDropTableSQL($table));
}
/**
* Drop the index from the given table
*
* @param Index|string $index The name of the index
* @param string|Table $table The name of the table
*/
public function dropIndex($index, $table)
{
if($index instanceof Index) {
$index = $index->getQuotedName($this->_platform);
}
$this->_execSql($this->_platform->getDropIndexSQL($index, $table));
}
/**
* Drop the constraint from the given table
*
* @param Constraint $constraint
* @param string $table The name of the table
*/
public function dropConstraint(Constraint $constraint, $table)
{
$this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table));
}
/**
* Drops a foreign key from a table.
*
* @param ForeignKeyConstraint|string $table The name of the table with the foreign key.
* @param Table|string $name The name of the foreign key.
* @return boolean $result
*/
public function dropForeignKey($foreignKey, $table)
{
$this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table));
}
/**
* Drops a sequence with a given name.
*
* @param string $name The name of the sequence to drop.
*/
public function dropSequence($name)
{
$this->_execSql($this->_platform->getDropSequenceSQL($name));
}
/**
* Drop a view
*
* @param string $name The name of the view
* @return boolean $result
*/
public function dropView($name)
{
$this->_execSql($this->_platform->getDropViewSQL($name));
}
/* create*() Methods */
/**
* Creates a new database.
*
* @param string $database The name of the database to create.
*/
public function createDatabase($database)
{
$this->_execSql($this->_platform->getCreateDatabaseSQL($database));
}
/**
* Create a new table.
*
* @param Table $table
* @param int $createFlags
*/
public function createTable(Table $table)
{
$createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS;
$this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags));
}
/**
* Create a new sequence
*
* @param Sequence $sequence
* @throws Doctrine\DBAL\ConnectionException if something fails at database level
*/
public function createSequence($sequence)
{
$this->_execSql($this->_platform->getCreateSequenceSQL($sequence));
}
/**
* Create a constraint on a table
*
* @param Constraint $constraint
* @param string|Table $table
*/
public function createConstraint(Constraint $constraint, $table)
{
$this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table));
}
/**
* Create a new index on a table
*
* @param Index $index
* @param string $table name of the table on which the index is to be created
*/
public function createIndex(Index $index, $table)
{
$this->_execSql($this->_platform->getCreateIndexSQL($index, $table));
}
/**
* Create a new foreign key
*
* @param ForeignKeyConstraint $foreignKey ForeignKey instance
* @param string|Table $table name of the table on which the foreign key is to be created
*/
public function createForeignKey(ForeignKeyConstraint $foreignKey, $table)
{
$this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table));
}
/**
* Create a new view
*
* @param View $view
*/
public function createView(View $view)
{
$this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql()));
}
/* dropAndCreate*() Methods */
/**
* Drop and create a constraint
*
* @param Constraint $constraint
* @param string $table
* @see dropConstraint()
* @see createConstraint()
*/
public function dropAndCreateConstraint(Constraint $constraint, $table)
{
$this->tryMethod('dropConstraint', $constraint, $table);
$this->createConstraint($constraint, $table);
}
/**
* Drop and create a new index on a table
*
* @param string|Table $table name of the table on which the index is to be created
* @param Index $index
*/
public function dropAndCreateIndex(Index $index, $table)
{
$this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table);
$this->createIndex($index, $table);
}
/**
* Drop and create a new foreign key
*
* @param ForeignKeyConstraint $foreignKey associative array that defines properties of the foreign key to be created.
* @param string|Table $table name of the table on which the foreign key is to be created
*/
public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table)
{
$this->tryMethod('dropForeignKey', $foreignKey, $table);
$this->createForeignKey($foreignKey, $table);
}
/**
* Drop and create a new sequence
*
* @param Sequence $sequence
* @throws Doctrine\DBAL\ConnectionException if something fails at database level
*/
public function dropAndCreateSequence(Sequence $sequence)
{
$this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform));
$this->createSequence($sequence);
}
/**
* Drop and create a new table.
*
* @param Table $table
*/
public function dropAndCreateTable(Table $table)
{
$this->tryMethod('dropTable', $table->getQuotedName($this->_platform));
$this->createTable($table);
}
/**
* Drop and creates a new database.
*
* @param string $database The name of the database to create.
*/
public function dropAndCreateDatabase($database)
{
$this->tryMethod('dropDatabase', $database);
$this->createDatabase($database);
}
/**
* Drop and create a new view
*
* @param View $view
*/
public function dropAndCreateView(View $view)
{
$this->tryMethod('dropView', $view->getQuotedName($this->_platform));
$this->createView($view);
}
/* alterTable() Methods */
/**
* Alter an existing tables schema
*
* @param TableDiff $tableDiff
*/
public function alterTable(TableDiff $tableDiff)
{
$queries = $this->_platform->getAlterTableSQL($tableDiff);
if (is_array($queries) && count($queries)) {
foreach ($queries AS $ddlQuery) {
$this->_execSql($ddlQuery);
}
}
}
/**
* Rename a given table to another name
*
* @param string $name The current name of the table
* @param string $newName The new name of the table
*/
public function renameTable($name, $newName)
{
$tableDiff = new TableDiff($name);
$tableDiff->newName = $newName;
$this->alterTable($tableDiff);
}
/**
* Methods for filtering return values of list*() methods to convert
* the native DBMS data definition to a portable Doctrine definition
*/
protected function _getPortableDatabasesList($databases)
{
$list = array();
foreach ($databases as $key => $value) {
if ($value = $this->_getPortableDatabaseDefinition($value)) {
$list[] = $value;
}
}
return $list;
}
protected function _getPortableDatabaseDefinition($database)
{
return $database;
}
protected function _getPortableFunctionsList($functions)
{
$list = array();
foreach ($functions as $key => $value) {
if ($value = $this->_getPortableFunctionDefinition($value)) {
$list[] = $value;
}
}
return $list;
}
protected function _getPortableFunctionDefinition($function)
{
return $function;
}
protected function _getPortableTriggersList($triggers)
{
$list = array();
foreach ($triggers as $key => $value) {
if ($value = $this->_getPortableTriggerDefinition($value)) {
$list[] = $value;
}
}
return $list;
}
protected function _getPortableTriggerDefinition($trigger)
{
return $trigger;
}
protected function _getPortableSequencesList($sequences)
{
$list = array();
foreach ($sequences as $key => $value) {
if ($value = $this->_getPortableSequenceDefinition($value)) {
$list[] = $value;
}
}
return $list;
}
/**
* @param array $sequence
* @return Sequence
*/
protected function _getPortableSequenceDefinition($sequence)
{
throw DBALException::notSupported('Sequences');
}
/**
* Independent of the database the keys of the column list result are lowercased.
*
* The name of the created column instance however is kept in its case.
*
* @param string $table The name of the table.
* @param string $database
* @param array $tableColumns
* @return array
*/
protected function _getPortableTableColumnList($table, $database, $tableColumns)
{
$eventManager = $this->_platform->getEventManager();
$list = array();
foreach ($tableColumns as $key => $tableColumn) {
$column = null;
$defaultPrevented = false;
if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) {
$eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn);
$eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs);
$defaultPrevented = $eventArgs->isDefaultPrevented();
$column = $eventArgs->getColumn();
}
if (!$defaultPrevented) {
$column = $this->_getPortableTableColumnDefinition($tableColumn);
}
if ($column) {
$name = strtolower($column->getQuotedName($this->_platform));
$list[$name] = $column;
}
}
return $list;
}
/**
* Get Table Column Definition
*
* @param array $tableColumn
* @return Column
*/
abstract protected function _getPortableTableColumnDefinition($tableColumn);
/**
* Aggregate and group the index results according to the required data result.
*
* @param array $tableIndexRows
* @param string $tableName
* @return array
*/
protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
{
$result = array();
foreach($tableIndexRows AS $tableIndex) {
$indexName = $keyName = $tableIndex['key_name'];
if($tableIndex['primary']) {
$keyName = 'primary';
}
$keyName = strtolower($keyName);
if(!isset($result[$keyName])) {
$result[$keyName] = array(
'name' => $indexName,
'columns' => array($tableIndex['column_name']),
'unique' => $tableIndex['non_unique'] ? false : true,
'primary' => $tableIndex['primary'],
);
} else {
$result[$keyName]['columns'][] = $tableIndex['column_name'];
}
}
$eventManager = $this->_platform->getEventManager();
$indexes = array();
foreach($result AS $indexKey => $data) {
$index = null;
$defaultPrevented = false;
if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
$eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
$eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
$defaultPrevented = $eventArgs->isDefaultPrevented();
$index = $eventArgs->getIndex();
}
if (!$defaultPrevented) {
$index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
}
if ($index) {
$indexes[$indexKey] = $index;
}
}
return $indexes;
}
protected function _getPortableTablesList($tables)
{
$list = array();
foreach ($tables as $key => $value) {
if ($value = $this->_getPortableTableDefinition($value)) {
$list[] = $value;
}
}
return $list;
}
protected function _getPortableTableDefinition($table)
{
return $table;
}
protected function _getPortableUsersList($users)
{
$list = array();
foreach ($users as $key => $value) {
if ($value = $this->_getPortableUserDefinition($value)) {
$list[] = $value;
}
}
return $list;
}
protected function _getPortableUserDefinition($user)
{
return $user;
}
protected function _getPortableViewsList($views)
{
$list = array();
foreach ($views as $key => $value) {
if ($view = $this->_getPortableViewDefinition($value)) {
$viewName = strtolower($view->getQuotedName($this->_platform));
$list[$viewName] = $view;
}
}
return $list;
}
protected function _getPortableViewDefinition($view)
{
return false;
}
protected function _getPortableTableForeignKeysList($tableForeignKeys)
{
$list = array();
foreach ($tableForeignKeys as $key => $value) {
if ($value = $this->_getPortableTableForeignKeyDefinition($value)) {
$list[] = $value;
}
}
return $list;
}
protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
{
return $tableForeignKey;
}
protected function _execSql($sql)
{
foreach ((array) $sql as $query) {
$this->_conn->executeUpdate($query);
}
}
/**
* Create a schema instance for the current database.
*
* @return Schema
*/
public function createSchema()
{
$sequences = array();
if($this->_platform->supportsSequences()) {
$sequences = $this->listSequences();
}
$tables = $this->listTables();
return new Schema($tables, $sequences, $this->createSchemaConfig());
}
/**
* Create the configuration for this schema.
*
* @return SchemaConfig
*/
public function createSchemaConfig()
{
$schemaConfig = new SchemaConfig();
$schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength());
$searchPaths = $this->getSchemaSearchPaths();
if (isset($searchPaths[0])) {
$schemaConfig->setName($searchPaths[0]);
}
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
* the type given as default.
*
* @param string $comment
* @param string $currentType
* @return string
*/
public function extractDoctrineTypeFromComment($comment, $currentType)
{
if (preg_match("(\(DC2Type:([a-zA-Z0-9]+)\))", $comment, $match)) {
$currentType = $match[1];
}
return $currentType;
}
public function removeDoctrineTypeFromComment($comment, $type)
{
return str_replace('(DC2Type:'.$type.')', '', $comment);
}
}

View File

@@ -0,0 +1,423 @@
<?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;
use \Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Schema\Visitor\Visitor;
/**
* Object representation of a database column
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class Column extends AbstractAsset
{
/**
* @var \Doctrine\DBAL\Types\Type
*/
protected $_type;
/**
* @var int
*/
protected $_length = null;
/**
* @var int
*/
protected $_precision = 10;
/**
* @var int
*/
protected $_scale = 0;
/**
* @var bool
*/
protected $_unsigned = false;
/**
* @var bool
*/
protected $_fixed = false;
/**
* @var bool
*/
protected $_notnull = true;
/**
* @var string
*/
protected $_default = null;
/**
* @var bool
*/
protected $_autoincrement = false;
/**
* @var array
*/
protected $_platformOptions = array();
/**
* @var string
*/
protected $_columnDefinition = null;
/**
* @var string
*/
protected $_comment = null;
/**
* @var array
*/
protected $_customSchemaOptions = array();
/**
* Create a new Column
*
* @param string $columnName
* @param Doctrine\DBAL\Types\Type $type
* @param int $length
* @param bool $notNull
* @param mixed $default
* @param bool $unsigned
* @param bool $fixed
* @param int $precision
* @param int $scale
* @param array $platformOptions
*/
public function __construct($columnName, Type $type, array $options=array())
{
$this->_setName($columnName);
$this->setType($type);
$this->setOptions($options);
}
/**
* @param array $options
* @return Column
*/
public function setOptions(array $options)
{
foreach ($options AS $name => $value) {
$method = "set".$name;
if (method_exists($this, $method)) {
$this->$method($value);
}
}
return $this;
}
/**
* @param Type $type
* @return Column
*/
public function setType(Type $type)
{
$this->_type = $type;
return $this;
}
/**
* @param int $length
* @return Column
*/
public function setLength($length)
{
if($length !== null) {
$this->_length = (int)$length;
} else {
$this->_length = null;
}
return $this;
}
/**
* @param int $precision
* @return Column
*/
public function setPrecision($precision)
{
if (!is_numeric($precision)) {
$precision = 10; // defaults to 10 when no valid precision is given.
}
$this->_precision = (int)$precision;
return $this;
}
/**
* @param int $scale
* @return Column
*/
public function setScale($scale)
{
if (!is_numeric($scale)) {
$scale = 0;
}
$this->_scale = (int)$scale;
return $this;
}
/**
*
* @param bool $unsigned
* @return Column
*/
public function setUnsigned($unsigned)
{
$this->_unsigned = (bool)$unsigned;
return $this;
}
/**
*
* @param bool $fixed
* @return Column
*/
public function setFixed($fixed)
{
$this->_fixed = (bool)$fixed;
return $this;
}
/**
* @param bool $notnull
* @return Column
*/
public function setNotnull($notnull)
{
$this->_notnull = (bool)$notnull;
return $this;
}
/**
*
* @param mixed $default
* @return Column
*/
public function setDefault($default)
{
$this->_default = $default;
return $this;
}
/**
*
* @param array $platformOptions
* @return Column
*/
public function setPlatformOptions(array $platformOptions)
{
$this->_platformOptions = $platformOptions;
return $this;
}
/**
*
* @param string $name
* @param mixed $value
* @return Column
*/
public function setPlatformOption($name, $value)
{
$this->_platformOptions[$name] = $value;
return $this;
}
/**
*
* @param string
* @return Column
*/
public function setColumnDefinition($value)
{
$this->_columnDefinition = $value;
return $this;
}
public function getType()
{
return $this->_type;
}
public function getLength()
{
return $this->_length;
}
public function getPrecision()
{
return $this->_precision;
}
public function getScale()
{
return $this->_scale;
}
public function getUnsigned()
{
return $this->_unsigned;
}
public function getFixed()
{
return $this->_fixed;
}
public function getNotnull()
{
return $this->_notnull;
}
public function getDefault()
{
return $this->_default;
}
public function getPlatformOptions()
{
return $this->_platformOptions;
}
public function hasPlatformOption($name)
{
return isset($this->_platformOptions[$name]);
}
public function getPlatformOption($name)
{
return $this->_platformOptions[$name];
}
public function getColumnDefinition()
{
return $this->_columnDefinition;
}
public function getAutoincrement()
{
return $this->_autoincrement;
}
public function setAutoincrement($flag)
{
$this->_autoincrement = $flag;
return $this;
}
public function setComment($comment)
{
$this->_comment = $comment;
return $this;
}
public function getComment()
{
return $this->_comment;
}
/**
* @param string $name
* @param mixed $value
* @return Column
*/
public function setCustomSchemaOption($name, $value)
{
$this->_customSchemaOptions[$name] = $value;
return $this;
}
/**
* @param string $name
* @return boolean
*/
public function hasCustomSchemaOption($name)
{
return isset($this->_customSchemaOptions[$name]);
}
/**
* @param string $name
* @return mixed
*/
public function getCustomSchemaOption($name)
{
return $this->_customSchemaOptions[$name];
}
/**
* @param array $customSchemaOptions
* @return Column
*/
public function setCustomSchemaOptions(array $customSchemaOptions)
{
$this->_customSchemaOptions = $customSchemaOptions;
return $this;
}
/**
* @return array
*/
public function getCustomSchemaOptions()
{
return $this->_customSchemaOptions;
}
/**
* @param Visitor $visitor
*/
public function visit(\Doctrine\DBAL\Schema\Visitor $visitor)
{
$visitor->accept($this);
}
/**
* @return array
*/
public function toArray()
{
return array_merge(array(
'name' => $this->_name,
'type' => $this->_type,
'default' => $this->_default,
'notnull' => $this->_notnull,
'length' => $this->_length,
'precision' => $this->_precision,
'scale' => $this->_scale,
'fixed' => $this->_fixed,
'unsigned' => $this->_unsigned,
'autoincrement' => $this->_autoincrement,
'columnDefinition' => $this->_columnDefinition,
'comment' => $this->_comment,
), $this->_platformOptions, $this->_customSchemaOptions);
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* $Id$
*
* 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;
/**
* Represent the change of a column
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class ColumnDiff
{
public $oldColumnName;
/**
* @var Column
*/
public $column;
/**
* @var array
*/
public $changedProperties = array();
public function __construct($oldColumnName, Column $column, array $changedProperties = array())
{
$this->oldColumnName = $oldColumnName;
$this->column = $column;
$this->changedProperties = $changedProperties;
}
public function hasChanged($propertyName)
{
return in_array($propertyName, $this->changedProperties);
}
}

View File

@@ -0,0 +1,399 @@
<?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;
/**
* Compare to Schemas and return an instance of SchemaDiff
*
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class Comparator
{
/**
* @param Schema $fromSchema
* @param Schema $toSchema
* @return SchemaDiff
*/
static public function compareSchemas( Schema $fromSchema, Schema $toSchema )
{
$c = new self();
return $c->compare($fromSchema, $toSchema);
}
/**
* Returns a SchemaDiff object containing the differences between the schemas $fromSchema and $toSchema.
*
* The returned diferences are returned in such a way that they contain the
* operations to change the schema stored in $fromSchema to the schema that is
* stored in $toSchema.
*
* @param Schema $fromSchema
* @param Schema $toSchema
*
* @return SchemaDiff
*/
public function compare(Schema $fromSchema, Schema $toSchema)
{
$diff = new SchemaDiff();
$foreignKeysToTable = array();
foreach ( $toSchema->getTables() AS $table ) {
$tableName = $table->getShortestName($toSchema->getName());
if ( ! $fromSchema->hasTable($tableName)) {
$diff->newTables[$tableName] = $toSchema->getTable($tableName);
} else {
$tableDifferences = $this->diffTable($fromSchema->getTable($tableName), $toSchema->getTable($tableName));
if ($tableDifferences !== false) {
$diff->changedTables[$tableName] = $tableDifferences;
}
}
}
/* Check if there are tables removed */
foreach ($fromSchema->getTables() AS $table) {
$tableName = $table->getShortestName($fromSchema->getName());
$table = $fromSchema->getTable($tableName);
if ( ! $toSchema->hasTable($tableName) ) {
$diff->removedTables[$tableName] = $table;
}
// also remember all foreign keys that point to a specific table
foreach ($table->getForeignKeys() AS $foreignKey) {
$foreignTable = strtolower($foreignKey->getForeignTableName());
if (!isset($foreignKeysToTable[$foreignTable])) {
$foreignKeysToTable[$foreignTable] = array();
}
$foreignKeysToTable[$foreignTable][] = $foreignKey;
}
}
foreach ($diff->removedTables AS $tableName => $table) {
if (isset($foreignKeysToTable[$tableName])) {
$diff->orphanedForeignKeys = array_merge($diff->orphanedForeignKeys, $foreignKeysToTable[$tableName]);
}
}
foreach ($toSchema->getSequences() AS $sequence) {
$sequenceName = $sequence->getShortestName($toSchema->getName());
if (!$fromSchema->hasSequence($sequenceName)) {
$diff->newSequences[] = $sequence;
} else {
if ($this->diffSequence($sequence, $fromSchema->getSequence($sequenceName))) {
$diff->changedSequences[] = $toSchema->getSequence($sequenceName);
}
}
}
foreach ($fromSchema->getSequences() AS $sequence) {
$sequenceName = $sequence->getShortestName($fromSchema->getName());
if (!$toSchema->hasSequence($sequenceName)) {
$diff->removedSequences[] = $sequence;
}
}
return $diff;
}
/**
*
* @param Sequence $sequence1
* @param Sequence $sequence2
*/
public function diffSequence(Sequence $sequence1, Sequence $sequence2)
{
if($sequence1->getAllocationSize() != $sequence2->getAllocationSize()) {
return true;
}
if($sequence1->getInitialValue() != $sequence2->getInitialValue()) {
return true;
}
return false;
}
/**
* Returns the difference between the tables $table1 and $table2.
*
* If there are no differences this method returns the boolean false.
*
* @param Table $table1
* @param Table $table2
*
* @return bool|TableDiff
*/
public function diffTable(Table $table1, Table $table2)
{
$changes = 0;
$tableDifferences = new TableDiff($table1->getName());
$table1Columns = $table1->getColumns();
$table2Columns = $table2->getColumns();
/* See if all the fields in table 1 exist in table 2 */
foreach ( $table2Columns as $columnName => $column ) {
if ( !$table1->hasColumn($columnName) ) {
$tableDifferences->addedColumns[$columnName] = $column;
$changes++;
}
}
/* See if there are any removed fields in table 2 */
foreach ( $table1Columns as $columnName => $column ) {
if ( !$table2->hasColumn($columnName) ) {
$tableDifferences->removedColumns[$columnName] = $column;
$changes++;
}
}
foreach ( $table1Columns as $columnName => $column ) {
if ( $table2->hasColumn($columnName) ) {
$changedProperties = $this->diffColumn( $column, $table2->getColumn($columnName) );
if (count($changedProperties) ) {
$columnDiff = new ColumnDiff($column->getName(), $table2->getColumn($columnName), $changedProperties);
$tableDifferences->changedColumns[$column->getName()] = $columnDiff;
$changes++;
}
}
}
$this->detectColumnRenamings($tableDifferences);
$table1Indexes = $table1->getIndexes();
$table2Indexes = $table2->getIndexes();
foreach ($table2Indexes AS $index2Name => $index2Definition) {
foreach ($table1Indexes AS $index1Name => $index1Definition) {
if ($this->diffIndex($index1Definition, $index2Definition) === false) {
unset($table1Indexes[$index1Name]);
unset($table2Indexes[$index2Name]);
} else {
if ($index1Name == $index2Name) {
$tableDifferences->changedIndexes[$index2Name] = $table2Indexes[$index2Name];
unset($table1Indexes[$index1Name]);
unset($table2Indexes[$index2Name]);
$changes++;
}
}
}
}
foreach ($table1Indexes AS $index1Name => $index1Definition) {
$tableDifferences->removedIndexes[$index1Name] = $index1Definition;
$changes++;
}
foreach ($table2Indexes AS $index2Name => $index2Definition) {
$tableDifferences->addedIndexes[$index2Name] = $index2Definition;
$changes++;
}
$fromFkeys = $table1->getForeignKeys();
$toFkeys = $table2->getForeignKeys();
foreach ($fromFkeys AS $key1 => $constraint1) {
foreach ($toFkeys AS $key2 => $constraint2) {
if($this->diffForeignKey($constraint1, $constraint2) === false) {
unset($fromFkeys[$key1]);
unset($toFkeys[$key2]);
} else {
if (strtolower($constraint1->getName()) == strtolower($constraint2->getName())) {
$tableDifferences->changedForeignKeys[] = $constraint2;
$changes++;
unset($fromFkeys[$key1]);
unset($toFkeys[$key2]);
}
}
}
}
foreach ($fromFkeys AS $key1 => $constraint1) {
$tableDifferences->removedForeignKeys[] = $constraint1;
$changes++;
}
foreach ($toFkeys AS $key2 => $constraint2) {
$tableDifferences->addedForeignKeys[] = $constraint2;
$changes++;
}
return $changes ? $tableDifferences : false;
}
/**
* Try to find columns that only changed their name, rename operations maybe cheaper than add/drop
* however ambiguouties between different possibilites should not lead to renaming at all.
*
* @param TableDiff $tableDifferences
*/
private function detectColumnRenamings(TableDiff $tableDifferences)
{
$renameCandidates = array();
foreach ($tableDifferences->addedColumns AS $addedColumnName => $addedColumn) {
foreach ($tableDifferences->removedColumns AS $removedColumnName => $removedColumn) {
if (count($this->diffColumn($addedColumn, $removedColumn)) == 0) {
$renameCandidates[$addedColumn->getName()][] = array($removedColumn, $addedColumn, $addedColumnName);
}
}
}
foreach ($renameCandidates AS $candidate => $candidateColumns) {
if (count($candidateColumns) == 1) {
list($removedColumn, $addedColumn) = $candidateColumns[0];
$removedColumnName = strtolower($removedColumn->getName());
$addedColumnName = strtolower($addedColumn->getName());
$tableDifferences->renamedColumns[$removedColumnName] = $addedColumn;
unset($tableDifferences->addedColumns[$addedColumnName]);
unset($tableDifferences->removedColumns[$removedColumnName]);
}
}
}
/**
* @param ForeignKeyConstraint $key1
* @param ForeignKeyConstraint $key2
* @return bool
*/
public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2)
{
if (array_map('strtolower', $key1->getLocalColumns()) != array_map('strtolower', $key2->getLocalColumns())) {
return true;
}
if (array_map('strtolower', $key1->getForeignColumns()) != array_map('strtolower', $key2->getForeignColumns())) {
return true;
}
if ($key1->onUpdate() != $key2->onUpdate()) {
return true;
}
if ($key1->onDelete() != $key2->onDelete()) {
return true;
}
return false;
}
/**
* Returns the difference between the fields $field1 and $field2.
*
* If there are differences this method returns $field2, otherwise the
* boolean false.
*
* @param Column $column1
* @param Column $column2
*
* @return array
*/
public function diffColumn(Column $column1, Column $column2)
{
$changedProperties = array();
if ( $column1->getType() != $column2->getType() ) {
$changedProperties[] = 'type';
}
if ($column1->getNotnull() != $column2->getNotnull()) {
$changedProperties[] = 'notnull';
}
if ($column1->getDefault() != $column2->getDefault()) {
$changedProperties[] = 'default';
}
if ($column1->getUnsigned() != $column2->getUnsigned()) {
$changedProperties[] = 'unsigned';
}
if ($column1->getType() instanceof \Doctrine\DBAL\Types\StringType) {
// check if value of length is set at all, default value assumed otherwise.
$length1 = $column1->getLength() ?: 255;
$length2 = $column2->getLength() ?: 255;
if ($length1 != $length2) {
$changedProperties[] = 'length';
}
if ($column1->getFixed() != $column2->getFixed()) {
$changedProperties[] = 'fixed';
}
}
if ($column1->getType() instanceof \Doctrine\DBAL\Types\DecimalType) {
if (($column1->getPrecision()?:10) != ($column2->getPrecision()?:10)) {
$changedProperties[] = 'precision';
}
if ($column1->getScale() != $column2->getScale()) {
$changedProperties[] = 'scale';
}
}
if ($column1->getAutoincrement() != $column2->getAutoincrement()) {
$changedProperties[] = 'autoincrement';
}
// only allow to delete comment if its set to '' not to null.
if ($column1->getComment() !== null && $column1->getComment() != $column2->getComment()) {
$changedProperties[] = 'comment';
}
$options1 = $column1->getCustomSchemaOptions();
$options2 = $column2->getCustomSchemaOptions();
$commonKeys = array_keys(array_intersect_key($options1, $options2));
foreach ($commonKeys as $key) {
if ($options1[$key] !== $options2[$key]) {
$changedProperties[] = $key;
}
}
$diffKeys = array_keys(array_diff_key($options1, $options2) + array_diff_key($options2, $options1));
$changedProperties = array_merge($changedProperties, $diffKeys);
return $changedProperties;
}
/**
* Finds the difference between the indexes $index1 and $index2.
*
* Compares $index1 with $index2 and returns $index2 if there are any
* differences or false in case there are no differences.
*
* @param Index $index1
* @param Index $index2
* @return bool
*/
public function diffIndex(Index $index1, Index $index2)
{
if ($index1->isFullfilledBy($index2) && $index2->isFullfilledBy($index1)) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* $Id$
*
* 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;
/**
* Marker interface for contraints
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
interface Constraint
{
public function getName();
public function getColumns();
}

View File

@@ -0,0 +1,214 @@
<?php
/*
* $Id$
*
* 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;
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
/**
* IBM Db2 Schema Manager
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 1.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class DB2SchemaManager extends AbstractSchemaManager
{
/**
* Return a list of all tables in the current database
*
* Apparently creator is the schema not the user who created it:
* {@link http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.sqlref/db2z_sysibmsystablestable.htm}
*
* @return array
*/
public function listTableNames()
{
$sql = $this->_platform->getListTablesSQL();
$sql .= " AND CREATOR = UPPER('".$this->_conn->getUsername()."')";
$tables = $this->_conn->fetchAll($sql);
return $this->_getPortableTablesList($tables);
}
/**
* Get Table Column Definition
*
* @param array $tableColumn
* @return Column
*/
protected function _getPortableTableColumnDefinition($tableColumn)
{
$tableColumn = array_change_key_case($tableColumn, \CASE_LOWER);
$length = null;
$fixed = null;
$unsigned = false;
$scale = false;
$precision = false;
$type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']);
switch (strtolower($tableColumn['typename'])) {
case 'varchar':
$length = $tableColumn['length'];
$fixed = false;
break;
case 'character':
$length = $tableColumn['length'];
$fixed = true;
break;
case 'clob':
$length = $tableColumn['length'];
break;
case 'decimal':
case 'double':
case 'real':
$scale = $tableColumn['scale'];
$precision = $tableColumn['length'];
break;
}
$options = array(
'length' => $length,
'unsigned' => (bool)$unsigned,
'fixed' => (bool)$fixed,
'default' => ($tableColumn['default'] == "NULL") ? null : $tableColumn['default'],
'notnull' => (bool) ($tableColumn['nulls'] == 'N'),
'scale' => null,
'precision' => null,
'platformOptions' => array(),
);
if ($scale !== null && $precision !== null) {
$options['scale'] = $scale;
$options['precision'] = $precision;
}
return new Column($tableColumn['colname'], \Doctrine\DBAL\Types\Type::getType($type), $options);
}
protected function _getPortableTablesList($tables)
{
$tableNames = array();
foreach ($tables AS $tableRow) {
$tableRow = array_change_key_case($tableRow, \CASE_LOWER);
$tableNames[] = $tableRow['name'];
}
return $tableNames;
}
protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
{
$eventManager = $this->_platform->getEventManager();
$tableIndexRows = array();
$indexes = array();
foreach($tableIndexes AS $indexKey => $data) {
$data = array_change_key_case($data, \CASE_LOWER);
$unique = ($data['uniquerule'] == "D") ? false : true;
$primary = ($data['uniquerule'] == "P");
$indexName = strtolower($data['name']);
if ($primary) {
$keyName = 'primary';
} else {
$keyName = $indexName;
}
$data = array(
'name' => $indexName,
'columns' => explode("+", ltrim($data['colnames'], '+')),
'unique' => $unique,
'primary' => $primary
);
$index = null;
$defaultPrevented = false;
if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
$eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
$eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
$defaultPrevented = $eventArgs->isDefaultPrevented();
$index = $eventArgs->getIndex();
}
if (!$defaultPrevented) {
$index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
}
if ($index) {
$indexes[$indexKey] = $index;
}
}
return $indexes;
}
protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
{
$tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER);
$tableForeignKey['deleterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['deleterule']);
$tableForeignKey['updaterule'] = $this->_getPortableForeignKeyRuleDef($tableForeignKey['updaterule']);
return new ForeignKeyConstraint(
array_map('trim', (array)$tableForeignKey['fkcolnames']),
$tableForeignKey['reftbname'],
array_map('trim', (array)$tableForeignKey['pkcolnames']),
$tableForeignKey['relname'],
array(
'onUpdate' => $tableForeignKey['updaterule'],
'onDelete' => $tableForeignKey['deleterule'],
)
);
}
protected function _getPortableForeignKeyRuleDef($def)
{
if ($def == "C") {
return "CASCADE";
} else if ($def == "N") {
return "SET NULL";
}
return null;
}
protected function _getPortableViewDefinition($view)
{
$view = array_change_key_case($view, \CASE_LOWER);
// sadly this still segfaults on PDO_IBM, see http://pecl.php.net/bugs/bug.php?id=17199
//$view['text'] = (is_resource($view['text']) ? stream_get_contents($view['text']) : $view['text']);
if (!is_resource($view['text'])) {
$pos = strpos($view['text'], ' AS ');
$sql = substr($view['text'], $pos+4);
} else {
$sql = '';
}
return new View($view['name'], $sql);
}
}

View File

@@ -0,0 +1,164 @@
<?php
/*
* $Id$
*
* 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;
use Doctrine\DBAL\Schema\Visitor\Visitor;
class ForeignKeyConstraint extends AbstractAsset implements Constraint
{
/**
* @var Table
*/
protected $_localTable;
/**
* @var array
*/
protected $_localColumnNames;
/**
* @var string
*/
protected $_foreignTableName;
/**
* @var array
*/
protected $_foreignColumnNames;
/**
* @var string
*/
protected $_cascade = '';
/**
* @var array
*/
protected $_options;
/**
*
* @param array $localColumnNames
* @param string $foreignTableName
* @param array $foreignColumnNames
* @param string $cascade
* @param string|null $name
*/
public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name=null, array $options=array())
{
$this->_setName($name);
$this->_localColumnNames = $localColumnNames;
$this->_foreignTableName = $foreignTableName;
$this->_foreignColumnNames = $foreignColumnNames;
$this->_options = $options;
}
/**
* @return string
*/
public function getLocalTableName()
{
return $this->_localTable->getName();
}
/**
* @param Table $table
*/
public function setLocalTable(Table $table)
{
$this->_localTable = $table;
}
/**
* @return array
*/
public function getLocalColumns()
{
return $this->_localColumnNames;
}
public function getColumns()
{
return $this->_localColumnNames;
}
/**
* @return string
*/
public function getForeignTableName()
{
return $this->_foreignTableName;
}
/**
* @return array
*/
public function getForeignColumns()
{
return $this->_foreignColumnNames;
}
public function hasOption($name)
{
return isset($this->_options[$name]);
}
public function getOption($name)
{
return $this->_options[$name];
}
/**
* Foreign Key onUpdate status
*
* @return string|null
*/
public function onUpdate()
{
return $this->_onEvent('onUpdate');
}
/**
* Foreign Key onDelete status
*
* @return string|null
*/
public function onDelete()
{
return $this->_onEvent('onDelete');
}
/**
* @param string $event
* @return string|null
*/
private function _onEvent($event)
{
if (isset($this->_options[$event])) {
$onEvent = strtoupper($this->_options[$event]);
if (!in_array($onEvent, array('NO ACTION', 'RESTRICT'))) {
return $onEvent;
}
}
return false;
}
}

View File

@@ -0,0 +1,188 @@
<?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;
use Doctrine\DBAL\Schema\Visitor\Visitor;
class Index extends AbstractAsset implements Constraint
{
/**
* @var array
*/
protected $_columns;
/**
* @var bool
*/
protected $_isUnique = false;
/**
* @var bool
*/
protected $_isPrimary = false;
/**
* @param string $indexName
* @param array $column
* @param bool $isUnique
* @param bool $isPrimary
*/
public function __construct($indexName, array $columns, $isUnique=false, $isPrimary=false)
{
$isUnique = ($isPrimary)?true:$isUnique;
$this->_setName($indexName);
$this->_isUnique = $isUnique;
$this->_isPrimary = $isPrimary;
foreach($columns AS $column) {
$this->_addColumn($column);
}
}
/**
* @param string $column
*/
protected function _addColumn($column)
{
if(is_string($column)) {
$this->_columns[] = $column;
} else {
throw new \InvalidArgumentException("Expecting a string as Index Column");
}
}
/**
* @return array
*/
public function getColumns()
{
return $this->_columns;
}
/**
* Is the index neither unique nor primary key?
*
* @return bool
*/
public function isSimpleIndex()
{
return !$this->_isPrimary && !$this->_isUnique;
}
/**
* @return bool
*/
public function isUnique()
{
return $this->_isUnique;
}
/**
* @return bool
*/
public function isPrimary()
{
return $this->_isPrimary;
}
/**
* @param string $columnName
* @param int $pos
* @return bool
*/
public function hasColumnAtPosition($columnName, $pos=0)
{
$columnName = strtolower($columnName);
$indexColumns = \array_map('strtolower', $this->getColumns());
return \array_search($columnName, $indexColumns) === $pos;
}
/**
* Check if this index exactly spans the given column names in the correct order.
*
* @param array $columnNames
* @return boolean
*/
public function spansColumns(array $columnNames)
{
$sameColumns = true;
for ($i = 0; $i < count($this->_columns); $i++) {
if (!isset($columnNames[$i]) || strtolower($this->_columns[$i]) != strtolower($columnNames[$i])) {
$sameColumns = false;
}
}
return $sameColumns;
}
/**
* Check if the other index already fullfills all the indexing and constraint needs of the current one.
*
* @param Index $other
* @return bool
*/
public function isFullfilledBy(Index $other)
{
// allow the other index to be equally large only. It being larger is an option
// but it creates a problem with scenarios of the kind PRIMARY KEY(foo,bar) UNIQUE(foo)
if (count($other->getColumns()) != count($this->getColumns())) {
return false;
}
// Check if columns are the same, and even in the same order
$sameColumns = $this->spansColumns($other->getColumns());
if ($sameColumns) {
if (!$this->isUnique() && !$this->isPrimary()) {
// this is a special case: If the current key is neither primary or unique, any uniqe or
// primary key will always have the same effect for the index and there cannot be any constraint
// overlaps. This means a primary or unique index can always fullfill the requirements of just an
// index that has no constraints.
return true;
} else if ($other->isPrimary() != $this->isPrimary()) {
return false;
} else if ($other->isUnique() != $this->isUnique()) {
return false;
}
return true;
}
return false;
}
/**
* Detect if the other index is a non-unique, non primary index that can be overwritten by this one.
*
* @param Index $other
* @return bool
*/
public function overrules(Index $other)
{
if ($other->isPrimary()) {
return false;
} else if ($this->isSimpleIndex() && $other->isUnique()) {
return false;
}
if ($this->spansColumns($other->getColumns()) && ($this->isPrimary() || $this->isUnique())) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,211 @@
<?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;
/**
* Schema manager for the MySql RDBMS.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Roman Borschel <roman@code-factory.org>
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @version $Revision$
* @since 2.0
*/
class MySqlSchemaManager extends AbstractSchemaManager
{
protected function _getPortableViewDefinition($view)
{
return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']);
}
protected function _getPortableTableDefinition($table)
{
return array_shift($table);
}
protected function _getPortableUserDefinition($user)
{
return array(
'user' => $user['User'],
'password' => $user['Password'],
);
}
protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
{
foreach($tableIndexes AS $k => $v) {
$v = array_change_key_case($v, CASE_LOWER);
if($v['key_name'] == 'PRIMARY') {
$v['primary'] = true;
} else {
$v['primary'] = false;
}
$tableIndexes[$k] = $v;
}
return parent::_getPortableTableIndexesList($tableIndexes, $tableName);
}
protected function _getPortableSequenceDefinition($sequence)
{
return end($sequence);
}
protected function _getPortableDatabaseDefinition($database)
{
return $database['Database'];
}
/**
* Gets a portable column definition.
*
* The database type is mapped to a corresponding Doctrine mapping type.
*
* @param $tableColumn
* @return array
*/
protected function _getPortableTableColumnDefinition($tableColumn)
{
$tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
$dbType = strtolower($tableColumn['type']);
$dbType = strtok($dbType, '(), ');
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'] = '';
}
$scale = null;
$precision = null;
$type = $this->_platform->getDoctrineTypeMapping($dbType);
$type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
$tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
switch ($dbType) {
case 'char':
$fixed = true;
break;
case 'float':
case 'double':
case 'real':
case 'numeric':
case 'decimal':
if(preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) {
$precision = $match[1];
$scale = $match[2];
$length = null;
}
break;
case 'tinyint':
case 'smallint':
case 'mediumint':
case 'int':
case 'integer':
case 'bigint':
case 'tinyblob':
case 'mediumblob':
case 'longblob':
case 'blob':
case 'year':
$length = null;
break;
}
$length = ((int) $length == 0) ? null : (int) $length;
$def = array(
'type' => $type,
'length' => $length,
'unsigned' => (bool) $unsigned,
'fixed' => (bool) $fixed
);
$options = array(
'length' => $length,
'unsigned' => (bool)$unsigned,
'fixed' => (bool)$fixed,
'default' => isset($tableColumn['default']) ? $tableColumn['default'] : null,
'notnull' => (bool) ($tableColumn['null'] != 'YES'),
'scale' => null,
'precision' => null,
'autoincrement' => (bool) (strpos($tableColumn['extra'], 'auto_increment') !== false),
'comment' => (isset($tableColumn['comment'])) ? $tableColumn['comment'] : null
);
if ($scale !== null && $precision !== null) {
$options['scale'] = $scale;
$options['precision'] = $precision;
}
return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
}
protected function _getPortableTableForeignKeysList($tableForeignKeys)
{
$list = array();
foreach ($tableForeignKeys as $key => $value) {
$value = array_change_key_case($value, CASE_LOWER);
if (!isset($list[$value['constraint_name']])) {
if (!isset($value['delete_rule']) || $value['delete_rule'] == "RESTRICT") {
$value['delete_rule'] = null;
}
if (!isset($value['update_rule']) || $value['update_rule'] == "RESTRICT") {
$value['update_rule'] = null;
}
$list[$value['constraint_name']] = array(
'name' => $value['constraint_name'],
'local' => array(),
'foreign' => array(),
'foreignTable' => $value['referenced_table_name'],
'onDelete' => $value['delete_rule'],
'onUpdate' => $value['update_rule'],
);
}
$list[$value['constraint_name']]['local'][] = $value['column_name'];
$list[$value['constraint_name']]['foreign'][] = $value['referenced_column_name'];
}
$result = array();
foreach($list AS $constraint) {
$result[] = new ForeignKeyConstraint(
array_values($constraint['local']), $constraint['foreignTable'],
array_values($constraint['foreign']), $constraint['name'],
array(
'onDelete' => $constraint['onDelete'],
'onUpdate' => $constraint['onUpdate'],
)
);
}
return $result;
}
}

View File

@@ -0,0 +1,286 @@
<?php
/*
* $Id$
*
* 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.phpdoctrine.org>.
*/
namespace Doctrine\DBAL\Schema;
/**
* Oracle Schema Manager
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @version $Revision$
* @since 2.0
*/
class OracleSchemaManager extends AbstractSchemaManager
{
protected function _getPortableViewDefinition($view)
{
$view = \array_change_key_case($view, CASE_LOWER);
return new View($view['view_name'], $view['text']);
}
protected function _getPortableUserDefinition($user)
{
$user = \array_change_key_case($user, CASE_LOWER);
return array(
'user' => $user['username'],
);
}
protected function _getPortableTableDefinition($table)
{
$table = \array_change_key_case($table, CASE_LOWER);
return $table['table_name'];
}
/**
* @license New BSD License
* @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
* @param array $tableIndexes
* @param string $tableName
* @return array
*/
protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
{
$indexBuffer = array();
foreach ( $tableIndexes as $tableIndex ) {
$tableIndex = \array_change_key_case($tableIndex, CASE_LOWER);
$keyName = strtolower($tableIndex['name']);
if ( strtolower($tableIndex['is_primary']) == "p" ) {
$keyName = 'primary';
$buffer['primary'] = true;
$buffer['non_unique'] = false;
} else {
$buffer['primary'] = false;
$buffer['non_unique'] = ( $tableIndex['is_unique'] == 0 ) ? true : false;
}
$buffer['key_name'] = $keyName;
$buffer['column_name'] = $tableIndex['column_name'];
$indexBuffer[] = $buffer;
}
return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
}
protected function _getPortableTableColumnDefinition($tableColumn)
{
$tableColumn = \array_change_key_case($tableColumn, CASE_LOWER);
$dbType = strtolower($tableColumn['data_type']);
if(strpos($dbType, "timestamp(") === 0) {
if (strpos($dbType, "WITH TIME ZONE")) {
$dbType = "timestamptz";
} else {
$dbType = "timestamp";
}
}
$type = array();
$length = $unsigned = $fixed = null;
if ( ! empty($tableColumn['data_length'])) {
$length = $tableColumn['data_length'];
}
if ( ! isset($tableColumn['column_name'])) {
$tableColumn['column_name'] = '';
}
if (stripos($tableColumn['data_default'], 'NULL') !== null) {
$tableColumn['data_default'] = null;
}
$precision = null;
$scale = null;
$type = $this->_platform->getDoctrineTypeMapping($dbType);
$type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type);
$tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type);
switch ($dbType) {
case 'number':
if ($tableColumn['data_precision'] == 20 && $tableColumn['data_scale'] == 0) {
$precision = 20;
$scale = 0;
$type = 'bigint';
} elseif ($tableColumn['data_precision'] == 5 && $tableColumn['data_scale'] == 0) {
$type = 'smallint';
$precision = 5;
$scale = 0;
} elseif ($tableColumn['data_precision'] == 1 && $tableColumn['data_scale'] == 0) {
$precision = 1;
$scale = 0;
$type = 'boolean';
} elseif ($tableColumn['data_scale'] > 0) {
$precision = $tableColumn['data_precision'];
$scale = $tableColumn['data_scale'];
$type = 'decimal';
}
$length = null;
break;
case 'pls_integer':
case 'binary_integer':
$length = null;
break;
case 'varchar':
case 'varchar2':
case 'nvarchar2':
$length = $tableColumn['char_length'];
$fixed = false;
break;
case 'char':
case 'nchar':
$length = $tableColumn['char_length'];
$fixed = true;
break;
case 'date':
case 'timestamp':
$length = null;
break;
case 'float':
$precision = $tableColumn['data_precision'];
$scale = $tableColumn['data_scale'];
$length = null;
break;
case 'clob':
case 'nclob':
$length = null;
break;
case 'blob':
case 'raw':
case 'long raw':
case 'bfile':
$length = null;
break;
case 'rowid':
case 'urowid':
default:
$length = null;
}
$options = array(
'notnull' => (bool) ($tableColumn['nullable'] === 'N'),
'fixed' => (bool) $fixed,
'unsigned' => (bool) $unsigned,
'default' => $tableColumn['data_default'],
'length' => $length,
'precision' => $precision,
'scale' => $scale,
'comment' => (isset($tableColumn['comments'])) ? $tableColumn['comments'] : null,
'platformDetails' => array(),
);
return new Column($tableColumn['column_name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
}
protected function _getPortableTableForeignKeysList($tableForeignKeys)
{
$list = array();
foreach ($tableForeignKeys as $key => $value) {
$value = \array_change_key_case($value, CASE_LOWER);
if (!isset($list[$value['constraint_name']])) {
if ($value['delete_rule'] == "NO ACTION") {
$value['delete_rule'] = null;
}
$list[$value['constraint_name']] = array(
'name' => $value['constraint_name'],
'local' => array(),
'foreign' => array(),
'foreignTable' => $value['references_table'],
'onDelete' => $value['delete_rule'],
);
}
$list[$value['constraint_name']]['local'][$value['position']] = $value['local_column'];
$list[$value['constraint_name']]['foreign'][$value['position']] = $value['foreign_column'];
}
$result = array();
foreach($list AS $constraint) {
$result[] = new ForeignKeyConstraint(
array_values($constraint['local']), $constraint['foreignTable'],
array_values($constraint['foreign']), $constraint['name'],
array('onDelete' => $constraint['onDelete'])
);
}
return $result;
}
protected function _getPortableSequenceDefinition($sequence)
{
$sequence = \array_change_key_case($sequence, CASE_LOWER);
return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['min_value']);
}
protected function _getPortableFunctionDefinition($function)
{
$function = \array_change_key_case($function, CASE_LOWER);
return $function['name'];
}
protected function _getPortableDatabaseDefinition($database)
{
$database = \array_change_key_case($database, CASE_LOWER);
return $database['username'];
}
public function createDatabase($database = null)
{
if (is_null($database)) {
$database = $this->_conn->getDatabase();
}
$params = $this->_conn->getParams();
$username = $database;
$password = $params['password'];
$query = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password;
$result = $this->_conn->executeUpdate($query);
$query = 'GRANT CREATE SESSION, CREATE TABLE, UNLIMITED TABLESPACE, CREATE SEQUENCE, CREATE TRIGGER TO ' . $username;
$result = $this->_conn->executeUpdate($query);
return true;
}
public function dropAutoincrement($table)
{
$sql = $this->_platform->getDropAutoincrementSql($table);
foreach ($sql as $query) {
$this->_conn->executeUpdate($query);
}
return true;
}
public function dropTable($name)
{
$this->dropAutoincrement($name);
return parent::dropTable($name);
}
}

View File

@@ -0,0 +1,359 @@
<?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;
/**
* PostgreSQL Schema Manager
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Benjamin Eberlei <kontakt@beberlei.de>
* @since 2.0
*/
class PostgreSqlSchemaManager extends AbstractSchemaManager
{
/**
* @var array
*/
private $existingSchemaPaths;
/**
* Get all the existing schema names.
*
* @return array
*/
public function getSchemaNames()
{
$rows = $this->_conn->fetchAll("SELECT nspname as schema_name FROM pg_namespace WHERE nspname !~ '^pg_.*' and nspname != 'information_schema'");
return array_map(function($v) { return $v['schema_name']; }, $rows);
}
/**
* Return an array of schema search paths
*
* This is a PostgreSQL only function.
*
* @return array
*/
public function getSchemaSearchPaths()
{
$params = $this->_conn->getParams();
$schema = explode(",", $this->_conn->fetchColumn('SHOW search_path'));
if (isset($params['user'])) {
$schema = str_replace('"$user"', $params['user'], $schema);
}
return $schema;
}
/**
* Get names of all existing schemas in the current users search path.
*
* This is a PostgreSQL only function.
*
* @return array
*/
public function getExistingSchemaSearchPaths()
{
if ($this->existingSchemaPaths === null) {
$this->determineExistingSchemaSearchPaths();
}
return $this->existingSchemaPaths;
}
/**
* Use this to set or reset the order of the existing schemas in the current search path of the user
*
* This is a PostgreSQL only function.
*
* @return type
*/
public function determineExistingSchemaSearchPaths()
{
$names = $this->getSchemaNames();
$paths = $this->getSchemaSearchPaths();
$this->existingSchemaPaths = array_filter($paths, function ($v) use ($names) {
return in_array($v, $names);
});
}
protected function _getPortableTableForeignKeyDefinition($tableForeignKey)
{
$onUpdate = null;
$onDelete = null;
if (preg_match('(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) {
$onUpdate = $match[1];
}
if (preg_match('(ON DELETE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) {
$onDelete = $match[1];
}
if (preg_match('/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', $tableForeignKey['condef'], $values)) {
// PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get
// the idea to trim them here.
$localColumns = array_map('trim', explode(",", $values[1]));
$foreignColumns = array_map('trim', explode(",", $values[3]));
$foreignTable = $values[2];
}
return new ForeignKeyConstraint(
$localColumns, $foreignTable, $foreignColumns, $tableForeignKey['conname'],
array('onUpdate' => $onUpdate, 'onDelete' => $onDelete)
);
}
public function dropDatabase($database)
{
$params = $this->_conn->getParams();
$params["dbname"] = "postgres";
$tmpPlatform = $this->_platform;
$tmpConn = $this->_conn;
$this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
$this->_platform = $this->_conn->getDatabasePlatform();
parent::dropDatabase($database);
$this->_platform = $tmpPlatform;
$this->_conn = $tmpConn;
}
public function createDatabase($database)
{
$params = $this->_conn->getParams();
$params["dbname"] = "postgres";
$tmpPlatform = $this->_platform;
$tmpConn = $this->_conn;
$this->_conn = \Doctrine\DBAL\DriverManager::getConnection($params);
$this->_platform = $this->_conn->getDatabasePlatform();
parent::createDatabase($database);
$this->_platform = $tmpPlatform;
$this->_conn = $tmpConn;
}
protected function _getPortableTriggerDefinition($trigger)
{
return $trigger['trigger_name'];
}
protected function _getPortableViewDefinition($view)
{
return new View($view['viewname'], $view['definition']);
}
protected function _getPortableUserDefinition($user)
{
return array(
'user' => $user['usename'],
'password' => $user['passwd']
);
}
protected function _getPortableTableDefinition($table)
{
$schemas = $this->getExistingSchemaSearchPaths();
$firstSchema = array_shift($schemas);
if ($table['schema_name'] == $firstSchema) {
return $table['table_name'];
} else {
return $table['schema_name'] . "." . $table['table_name'];
}
}
/**
* @license New BSD License
* @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
* @param array $tableIndexes
* @param string $tableName
* @return array
*/
protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
{
$buffer = array();
foreach ($tableIndexes AS $row) {
$colNumbers = explode(' ', $row['indkey']);
$colNumbersSql = 'IN (' . join(' ,', $colNumbers) . ' )';
$columnNameSql = "SELECT attnum, attname FROM pg_attribute
WHERE attrelid={$row['indrelid']} AND attnum $colNumbersSql ORDER BY attnum ASC;";
$stmt = $this->_conn->executeQuery($columnNameSql);
$indexColumns = $stmt->fetchAll();
// required for getting the order of the columns right.
foreach ($colNumbers AS $colNum) {
foreach ($indexColumns as $colRow) {
if ($colNum == $colRow['attnum']) {
$buffer[] = array(
'key_name' => $row['relname'],
'column_name' => trim($colRow['attname']),
'non_unique' => !$row['indisunique'],
'primary' => $row['indisprimary']
);
}
}
}
}
return parent::_getPortableTableIndexesList($buffer, $tableName);
}
protected function _getPortableDatabaseDefinition($database)
{
return $database['datname'];
}
protected function _getPortableSequenceDefinition($sequence)
{
if ($sequence['schemaname'] != 'public') {
$sequenceName = $sequence['schemaname'] . "." . $sequence['relname'];
} else {
$sequenceName = $sequence['relname'];
}
$data = $this->_conn->fetchAll('SELECT min_value, increment_by FROM ' . $sequenceName);
return new Sequence($sequenceName, $data[0]['increment_by'], $data[0]['min_value']);
}
protected function _getPortableTableColumnDefinition($tableColumn)
{
$tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
if (strtolower($tableColumn['type']) === 'varchar') {
// get length from varchar definition
$length = preg_replace('~.*\(([0-9]*)\).*~', '$1', $tableColumn['complete_type']);
$tableColumn['length'] = $length;
}
$matches = array();
$autoincrement = false;
if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) {
$tableColumn['sequence'] = $matches[1];
$tableColumn['default'] = null;
$autoincrement = true;
}
if (stripos($tableColumn['default'], 'NULL') === 0) {
$tableColumn['default'] = null;
}
$length = (isset($tableColumn['length'])) ? $tableColumn['length'] : null;
if ($length == '-1' && isset($tableColumn['atttypmod'])) {
$length = $tableColumn['atttypmod'] - 4;
}
if ((int) $length <= 0) {
$length = null;
}
$fixed = null;
if (!isset($tableColumn['name'])) {
$tableColumn['name'] = '';
}
$precision = null;
$scale = null;
$dbType = strtolower($tableColumn['type']);
if (strlen($tableColumn['domain_type']) && !$this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) {
$dbType = strtolower($tableColumn['domain_type']);
$tableColumn['complete_type'] = $tableColumn['domain_complete_type'];
}
$type = $this->_platform->getDoctrineTypeMapping($dbType);
$type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type);
$tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type);
switch ($dbType) {
case 'smallint':
case 'int2':
$length = null;
break;
case 'int':
case 'int4':
case 'integer':
$length = null;
break;
case 'bigint':
case 'int8':
$length = null;
break;
case 'bool':
case 'boolean':
$length = null;
break;
case 'text':
$fixed = false;
break;
case 'varchar':
case 'interval':
case '_varchar':
$fixed = false;
break;
case 'char':
case 'bpchar':
$fixed = true;
break;
case 'float':
case 'float4':
case 'float8':
case 'double':
case 'double precision':
case 'real':
case 'decimal':
case 'money':
case 'numeric':
if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) {
$precision = $match[1];
$scale = $match[2];
$length = null;
}
break;
case 'year':
$length = null;
break;
}
if ($tableColumn['default'] && preg_match("('([^']+)'::)", $tableColumn['default'], $match)) {
$tableColumn['default'] = $match[1];
}
$options = array(
'length' => $length,
'notnull' => (bool) $tableColumn['isnotnull'],
'default' => $tableColumn['default'],
'primary' => (bool) ($tableColumn['pri'] == 't'),
'precision' => $precision,
'scale' => $scale,
'fixed' => $fixed,
'unsigned' => false,
'autoincrement' => $autoincrement,
'comment' => $tableColumn['comment'],
);
return new Column($tableColumn['field'], \Doctrine\DBAL\Types\Type::getType($type), $options);
}
}

View File

@@ -0,0 +1,247 @@
<?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.phpdoctrine.org>.
*/
namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\Event\SchemaIndexDefinitionEventArgs;
use Doctrine\DBAL\Events;
/**
* SQL Server Schema Manager
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Juozas Kaziukenas <juozas@juokaz.com>
* @since 2.0
*/
class SQLServerSchemaManager extends AbstractSchemaManager
{
/**
* @override
*/
protected function _getPortableTableColumnDefinition($tableColumn)
{
$dbType = strtolower($tableColumn['TYPE_NAME']);
$autoincrement = false;
if (stripos($dbType, 'identity')) {
$dbType = trim(str_ireplace('identity', '', $dbType));
$autoincrement = true;
}
$type = array();
$unsigned = $fixed = null;
if (!isset($tableColumn['name'])) {
$tableColumn['name'] = '';
}
$default = $tableColumn['COLUMN_DEF'];
while ($default != ($default2 = preg_replace("/^\((.*)\)$/", '$1', $default))) {
$default = trim($default2, "'");
}
$length = (int) $tableColumn['LENGTH'];
$type = $this->_platform->getDoctrineTypeMapping($dbType);
switch ($type) {
case 'char':
if ($tableColumn['LENGTH'] == '1') {
$type = 'boolean';
if (preg_match('/^(is|has)/', $tableColumn['name'])) {
$type = array_reverse($type);
}
}
$fixed = true;
break;
case 'text':
$fixed = false;
break;
}
switch ($dbType) {
case 'nchar':
case 'nvarchar':
case 'ntext':
// Unicode data requires 2 bytes per character
$length = $length / 2;
break;
}
$options = array(
'length' => ($length == 0 || !in_array($type, array('text', 'string'))) ? null : $length,
'unsigned' => (bool) $unsigned,
'fixed' => (bool) $fixed,
'default' => $default !== 'NULL' ? $default : null,
'notnull' => (bool) ($tableColumn['IS_NULLABLE'] != 'YES'),
'scale' => $tableColumn['SCALE'],
'precision' => $tableColumn['PRECISION'],
'autoincrement' => $autoincrement,
);
return new Column($tableColumn['COLUMN_NAME'], \Doctrine\DBAL\Types\Type::getType($type), $options);
}
/**
* @override
*/
protected function _getPortableTableIndexesList($tableIndexRows, $tableName=null)
{
$result = array();
foreach ($tableIndexRows AS $tableIndex) {
$indexName = $keyName = $tableIndex['index_name'];
if (strpos($tableIndex['index_description'], 'primary key') !== false) {
$keyName = 'primary';
}
$keyName = strtolower($keyName);
$result[$keyName] = array(
'name' => $indexName,
'columns' => explode(', ', $tableIndex['index_keys']),
'unique' => strpos($tableIndex['index_description'], 'unique') !== false,
'primary' => strpos($tableIndex['index_description'], 'primary key') !== false,
);
}
$eventManager = $this->_platform->getEventManager();
$indexes = array();
foreach ($result AS $indexKey => $data) {
$index = null;
$defaultPrevented = false;
if (null !== $eventManager && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) {
$eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn);
$eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs);
$defaultPrevented = $eventArgs->isDefaultPrevented();
$index = $eventArgs->getIndex();
}
if (!$defaultPrevented) {
$index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary']);
}
if ($index) {
$indexes[$indexKey] = $index;
}
}
return $indexes;
}
/**
* @override
*/
public function _getPortableTableForeignKeyDefinition($tableForeignKey)
{
return new ForeignKeyConstraint(
(array) $tableForeignKey['ColumnName'],
$tableForeignKey['ReferenceTableName'],
(array) $tableForeignKey['ReferenceColumnName'],
$tableForeignKey['ForeignKey'],
array(
'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']),
'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']),
)
);
}
/**
* @override
*/
protected function _getPortableTableDefinition($table)
{
return $table['name'];
}
/**
* @override
*/
protected function _getPortableDatabaseDefinition($database)
{
return $database['name'];
}
/**
* @override
*/
protected function _getPortableViewDefinition($view)
{
// @todo
return new View($view['name'], null);
}
/**
* List the indexes for a given table returning an array of Index instances.
*
* Keys of the portable indexes list are all lower-cased.
*
* @param string $table The name of the table
* @return Index[] $tableIndexes
*/
public function listTableIndexes($table)
{
$sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase());
try {
$tableIndexes = $this->_conn->fetchAll($sql);
} catch(\PDOException $e) {
if ($e->getCode() == "IMSSP") {
return array();
} else {
throw $e;
}
}
return $this->_getPortableTableIndexesList($tableIndexes, $table);
}
/**
* @override
*/
public function alterTable(TableDiff $tableDiff)
{
if(count($tableDiff->removedColumns) > 0) {
foreach($tableDiff->removedColumns as $col){
$columnConstraintSql = $this->getColumnConstraintSQL($tableDiff->name, $col->getName());
foreach ($this->_conn->fetchAll($columnConstraintSql) as $constraint) {
$this->_conn->exec("ALTER TABLE $tableDiff->name DROP CONSTRAINT " . $constraint['Name']);
}
}
}
return parent::alterTable($tableDiff);
}
/**
* This function retrieves the constraints for a given column.
*/
private function getColumnConstraintSQL($table, $column)
{
return "SELECT SysObjects.[Name]
FROM SysObjects INNER JOIN (SELECT [Name],[ID] FROM SysObjects WHERE XType = 'U') AS Tab
ON Tab.[ID] = Sysobjects.[Parent_Obj]
INNER JOIN sys.default_constraints DefCons ON DefCons.[object_id] = Sysobjects.[ID]
INNER JOIN SysColumns Col ON Col.[ColID] = DefCons.[parent_column_id] AND Col.[ID] = Tab.[ID]
WHERE Col.[Name] = " . $this->_conn->quote($column) ." AND Tab.[Name] = " . $this->_conn->quote($table) . "
ORDER BY Col.[Name]";
}
}

View File

@@ -0,0 +1,367 @@
<?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;
use Doctrine\DBAL\Schema\Visitor\CreateSchemaSqlCollector;
use Doctrine\DBAL\Schema\Visitor\DropSchemaSqlCollector;
use Doctrine\DBAL\Schema\Visitor\Visitor;
/**
* 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
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class Schema extends AbstractAsset
{
/**
* @var array
*/
protected $_tables = array();
/**
* @var array
*/
protected $_sequences = array();
/**
* @var SchemaConfig
*/
protected $_schemaConfig = false;
/**
* @param array $tables
* @param array $sequences
* @param array $views
* @param array $triggers
* @param SchemaConfig $schemaConfig
*/
public function __construct(array $tables=array(), array $sequences=array(), SchemaConfig $schemaConfig=null)
{
if ($schemaConfig == null) {
$schemaConfig = new SchemaConfig();
}
$this->_schemaConfig = $schemaConfig;
$this->_setName($schemaConfig->getName() ?: 'public');
foreach ($tables AS $table) {
$this->_addTable($table);
}
foreach ($sequences AS $sequence) {
$this->_addSequence($sequence);
}
}
/**
* @return bool
*/
public function hasExplicitForeignKeyIndexes()
{
return $this->_schemaConfig->hasExplicitForeignKeyIndexes();
}
/**
* @param Table $table
*/
protected function _addTable(Table $table)
{
$tableName = $table->getFullQualifiedName($this->getName());
if(isset($this->_tables[$tableName])) {
throw SchemaException::tableAlreadyExists($tableName);
}
$this->_tables[$tableName] = $table;
$table->setSchemaConfig($this->_schemaConfig);
}
/**
* @param Sequence $sequence
*/
protected function _addSequence(Sequence $sequence)
{
$seqName = $sequence->getFullQualifiedName($this->getName());
if (isset($this->_sequences[$seqName])) {
throw SchemaException::sequenceAlreadyExists($seqName);
}
$this->_sequences[$seqName] = $sequence;
}
/**
* Get all tables of this schema.
*
* @return array
*/
public function getTables()
{
return $this->_tables;
}
/**
* @param string $tableName
* @return Table
*/
public function getTable($tableName)
{
$tableName = $this->getFullQualifiedAssetName($tableName);
if (!isset($this->_tables[$tableName])) {
throw SchemaException::tableDoesNotExist($tableName);
}
return $this->_tables[$tableName];
}
/**
* @return string
*/
private function getFullQualifiedAssetName($name)
{
if ($this->isQuoted($name)) {
$name = $this->trimQuotes($name);
}
if (strpos($name, ".") === false) {
$name = $this->getName() . "." . $name;
}
return strtolower($name);
}
/**
* Does this schema have a table with the given name?
*
* @param string $tableName
* @return Schema
*/
public function hasTable($tableName)
{
$tableName = $this->getFullQualifiedAssetName($tableName);
return isset($this->_tables[$tableName]);
}
/**
* Get all table names, prefixed with a schema name, even the default one
* if present.
*
* @return array
*/
public function getTableNames()
{
return array_keys($this->_tables);
}
public function hasSequence($sequenceName)
{
$sequenceName = $this->getFullQualifiedAssetName($sequenceName);
return isset($this->_sequences[$sequenceName]);
}
/**
* @throws SchemaException
* @param string $sequenceName
* @return Doctrine\DBAL\Schema\Sequence
*/
public function getSequence($sequenceName)
{
$sequenceName = $this->getFullQualifiedAssetName($sequenceName);
if(!$this->hasSequence($sequenceName)) {
throw SchemaException::sequenceDoesNotExist($sequenceName);
}
return $this->_sequences[$sequenceName];
}
/**
* @return Doctrine\DBAL\Schema\Sequence[]
*/
public function getSequences()
{
return $this->_sequences;
}
/**
* Create a new table
*
* @param string $tableName
* @return Table
*/
public function createTable($tableName)
{
$table = new Table($tableName);
$this->_addTable($table);
return $table;
}
/**
* Rename a table
*
* @param string $oldTableName
* @param string $newTableName
* @return Schema
*/
public function renameTable($oldTableName, $newTableName)
{
$table = $this->getTable($oldTableName);
$table->_setName($newTableName);
$this->dropTable($oldTableName);
$this->_addTable($table);
return $this;
}
/**
* Drop a table from the schema.
*
* @param string $tableName
* @return Schema
*/
public function dropTable($tableName)
{
$tableName = $this->getFullQualifiedAssetName($tableName);
$table = $this->getTable($tableName);
unset($this->_tables[$tableName]);
return $this;
}
/**
* Create a new sequence
*
* @param string $sequenceName
* @param int $allocationSize
* @param int $initialValue
* @return Sequence
*/
public function createSequence($sequenceName, $allocationSize=1, $initialValue=1)
{
$seq = new Sequence($sequenceName, $allocationSize, $initialValue);
$this->_addSequence($seq);
return $seq;
}
/**
* @param string $sequenceName
* @return Schema
*/
public function dropSequence($sequenceName)
{
$sequenceName = $this->getFullQualifiedAssetName($sequenceName);
unset($this->_sequences[$sequenceName]);
return $this;
}
/**
* Return an array of necessary sql queries to create the schema on the given platform.
*
* @param AbstractPlatform $platform
* @return array
*/
public function toSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform)
{
$sqlCollector = new CreateSchemaSqlCollector($platform);
$this->visit($sqlCollector);
return $sqlCollector->getQueries();
}
/**
* Return an array of necessary sql queries to drop the schema on the given platform.
*
* @param AbstractPlatform $platform
* @return array
*/
public function toDropSql(\Doctrine\DBAL\Platforms\AbstractPlatform $platform)
{
$dropSqlCollector = new DropSchemaSqlCollector($platform);
$this->visit($dropSqlCollector);
return $dropSqlCollector->getQueries();
}
/**
* @param Schema $toSchema
* @param AbstractPlatform $platform
*/
public function getMigrateToSql(Schema $toSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
{
$comparator = new Comparator();
$schemaDiff = $comparator->compare($this, $toSchema);
return $schemaDiff->toSql($platform);
}
/**
* @param Schema $fromSchema
* @param AbstractPlatform $platform
*/
public function getMigrateFromSql(Schema $fromSchema, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
{
$comparator = new Comparator();
$schemaDiff = $comparator->compare($fromSchema, $this);
return $schemaDiff->toSql($platform);
}
/**
* @param Visitor $visitor
*/
public function visit(Visitor $visitor)
{
$visitor->acceptSchema($this);
foreach ($this->_tables AS $table) {
$table->visit($visitor);
}
foreach ($this->_sequences AS $sequence) {
$sequence->visit($visitor);
}
}
/**
* Cloning a Schema triggers a deep clone of all related assets.
*
* @return void
*/
public function __clone()
{
foreach ($this->_tables AS $k => $table) {
$this->_tables[$k] = clone $table;
}
foreach ($this->_sequences AS $k => $sequence) {
$this->_sequences[$k] = clone $sequence;
}
}
}

View File

@@ -0,0 +1,98 @@
<?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;
/**
* Configuration for a Schema
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class SchemaConfig
{
/**
* @var bool
*/
protected $_hasExplicitForeignKeyIndexes = false;
/**
* @var int
*/
protected $_maxIdentifierLength = 63;
/**
* @var string
*/
protected $_name;
/**
* @return bool
*/
public function hasExplicitForeignKeyIndexes()
{
return $this->_hasExplicitForeignKeyIndexes;
}
/**
* @param bool $flag
*/
public function setExplicitForeignKeyIndexes($flag)
{
$this->_hasExplicitForeignKeyIndexes = (bool)$flag;
}
/**
* @param int $length
*/
public function setMaxIdentifierLength($length)
{
$this->_maxIdentifierLength = (int)$length;
}
/**
* @return int
*/
public function getMaxIdentifierLength()
{
return $this->_maxIdentifierLength;
}
/**
* 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;
}
}

View File

@@ -0,0 +1,176 @@
<?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;
use \Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Schema Diff
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class SchemaDiff
{
/**
* All added tables
*
* @var array(string=>ezcDbSchemaTable)
*/
public $newTables = array();
/**
* All changed tables
*
* @var array(string=>ezcDbSchemaTableDiff)
*/
public $changedTables = array();
/**
* All removed tables
*
* @var array(string=>Table)
*/
public $removedTables = array();
/**
* @var array
*/
public $newSequences = array();
/**
* @var array
*/
public $changedSequences = array();
/**
* @var array
*/
public $removedSequences = array();
/**
* @var array
*/
public $orphanedForeignKeys = array();
/**
* Constructs an SchemaDiff object.
*
* @param array(string=>Table) $newTables
* @param array(string=>TableDiff) $changedTables
* @param array(string=>bool) $removedTables
*/
public function __construct($newTables = array(), $changedTables = array(), $removedTables = array())
{
$this->newTables = $newTables;
$this->changedTables = $changedTables;
$this->removedTables = $removedTables;
}
/**
* The to save sql mode ensures that the following things don't happen:
*
* 1. Tables are deleted
* 2. Sequences are deleted
* 3. Foreign Keys which reference tables that would otherwise be deleted.
*
* This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all.
*
* @param AbstractPlatform $platform
* @return array
*/
public function toSaveSql(AbstractPlatform $platform)
{
return $this->_toSql($platform, true);
}
/**
* @param AbstractPlatform $platform
* @return array
*/
public function toSql(AbstractPlatform $platform)
{
return $this->_toSql($platform, false);
}
/**
* @param AbstractPlatform $platform
* @param bool $saveMode
* @return array
*/
protected function _toSql(AbstractPlatform $platform, $saveMode = false)
{
$sql = array();
if ($platform->supportsForeignKeyConstraints() && $saveMode == false) {
foreach ($this->orphanedForeignKeys AS $orphanedForeignKey) {
$sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTableName());
}
}
if ($platform->supportsSequences() == true) {
foreach ($this->changedSequences AS $sequence) {
$sql[] = $platform->getAlterSequenceSQL($sequence);
}
if ($saveMode === false) {
foreach ($this->removedSequences AS $sequence) {
$sql[] = $platform->getDropSequenceSQL($sequence);
}
}
foreach ($this->newSequences AS $sequence) {
$sql[] = $platform->getCreateSequenceSQL($sequence);
}
}
$foreignKeySql = array();
foreach ($this->newTables AS $table) {
$sql = array_merge(
$sql,
$platform->getCreateTableSQL($table, AbstractPlatform::CREATE_INDEXES)
);
if ($platform->supportsForeignKeyConstraints()) {
foreach ($table->getForeignKeys() AS $foreignKey) {
$foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table);
}
}
}
$sql = array_merge($sql, $foreignKeySql);
if ($saveMode === false) {
foreach ($this->removedTables AS $table) {
$sql[] = $platform->getDropTableSQL($table);
}
}
foreach ($this->changedTables AS $tableDiff) {
$sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff));
}
return $sql;
}
}

View File

@@ -0,0 +1,126 @@
<?php
namespace Doctrine\DBAL\Schema;
class SchemaException extends \Doctrine\DBAL\DBALException
{
const TABLE_DOESNT_EXIST = 10;
const TABLE_ALREADY_EXISTS = 20;
const COLUMN_DOESNT_EXIST = 30;
const COLUMN_ALREADY_EXISTS = 40;
const INDEX_DOESNT_EXIST = 50;
const INDEX_ALREADY_EXISTS = 60;
const SEQUENCE_DOENST_EXIST = 70;
const SEQUENCE_ALREADY_EXISTS = 80;
const INDEX_INVALID_NAME = 90;
const FOREIGNKEY_DOESNT_EXIST = 100;
/**
* @param string $tableName
* @return SchemaException
*/
static public function tableDoesNotExist($tableName)
{
return new self("There is no table with name '".$tableName."' in the schema.", self::TABLE_DOESNT_EXIST);
}
/**
* @param string $indexName
* @return SchemaException
*/
static public function indexNameInvalid($indexName)
{
return new self("Invalid index-name $indexName given, has to be [a-zA-Z0-9_]", self::INDEX_INVALID_NAME);
}
/**
* @param string $indexName
* @return SchemaException
*/
static public function indexDoesNotExist($indexName, $table)
{
return new self("Index '$indexName' does not exist on table '$table'.", self::INDEX_DOESNT_EXIST);
}
/**
* @param string $indexName
* @return SchemaException
*/
static public function indexAlreadyExists($indexName, $table)
{
return new self("An index with name '$indexName' was already defined on table '$table'.", self::INDEX_ALREADY_EXISTS);
}
/**
* @param string $columnName
* @return SchemaException
*/
static public function columnDoesNotExist($columnName, $table)
{
return new self("There is no column with name '$columnName' on table '$table'.", self::COLUMN_DOESNT_EXIST);
}
/**
*
* @param string $tableName
* @return SchemaException
*/
static public function tableAlreadyExists($tableName)
{
return new self("The table with name '".$tableName."' already exists.", self::TABLE_ALREADY_EXISTS);
}
/**
*
* @param string $tableName
* @param string $columnName
* @return SchemaException
*/
static public function columnAlreadyExists($tableName, $columnName)
{
return new self(
"The column '".$columnName."' on table '".$tableName."' already exists.", self::COLUMN_ALREADY_EXISTS
);
}
/**
* @param string $sequenceName
* @return SchemaException
*/
static public function sequenceAlreadyExists($sequenceName)
{
return new self("The sequence '".$sequenceName."' already exists.", self::SEQUENCE_ALREADY_EXISTS);
}
/**
* @param string $sequenceName
* @return SchemaException
*/
static public function sequenceDoesNotExist($sequenceName)
{
return new self("There exists no sequence with the name '".$sequenceName."'.", self::SEQUENCE_DOENST_EXIST);
}
/**
* @param string $fkName
* @return SchemaException
*/
static public function foreignKeyDoesNotExist($fkName, $table)
{
return new self("There exists no foreign key with the name '$fkName' on table '$table'.", self::FOREIGNKEY_DOESNT_EXIST);
}
static public function namedForeignKeyRequired(Table $localTable, ForeignKeyConstraint $foreignKey)
{
return new self(
"The performed schema operation on ".$localTable->getName()." requires a named foreign key, ".
"but the given foreign key from (".implode(", ", $foreignKey->getColumns()).") onto foreign table ".
"'".$foreignKey->getForeignTableName()."' (".implode(", ", $foreignKey->getForeignColumns()).") is currently ".
"unnamed."
);
}
static public function alterTableChangeNotSupported($changeName) {
return new self ("Alter table change not supported, given '$changeName'");
}
}

View File

@@ -0,0 +1,87 @@
<?php
/*
* $Id$
*
* 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;
use Doctrine\DBAL\Schema\Visitor\Visitor;
/**
* Sequence Structure
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class Sequence extends AbstractAsset
{
/**
* @var int
*/
protected $_allocationSize = 1;
/**
* @var int
*/
protected $_initialValue = 1;
/**
*
* @param string $name
* @param int $allocationSize
* @param int $initialValue
*/
public function __construct($name, $allocationSize=1, $initialValue=1)
{
$this->_setName($name);
$this->_allocationSize = (is_numeric($allocationSize))?$allocationSize:1;
$this->_initialValue = (is_numeric($initialValue))?$initialValue:1;
}
public function getAllocationSize()
{
return $this->_allocationSize;
}
public function getInitialValue()
{
return $this->_initialValue;
}
public function setAllocationSize($allocationSize)
{
$this->_allocationSize = (is_numeric($allocationSize))?$allocationSize:1;
}
public function setInitialValue($initialValue)
{
$this->_initialValue = (is_numeric($initialValue))?$initialValue:1;
}
/**
* @param Visitor $visitor
*/
public function visit(Visitor $visitor)
{
$visitor->acceptSequence($this);
}
}

View File

@@ -0,0 +1,190 @@
<?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;
/**
* SqliteSchemaManager
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @author Jonathan H. Wage <jonwage@gmail.com>
* @version $Revision$
* @since 2.0
*/
class SqliteSchemaManager extends AbstractSchemaManager
{
/**
* {@inheritdoc}
*
* @override
*/
public function dropDatabase($database)
{
if (file_exists($database)) {
unlink($database);
}
}
/**
* {@inheritdoc}
*
* @override
*/
public function createDatabase($database)
{
$params = $this->_conn->getParams();
$driver = $params['driver'];
$options = array(
'driver' => $driver,
'path' => $database
);
$conn = \Doctrine\DBAL\DriverManager::getConnection($options);
$conn->connect();
$conn->close();
}
protected function _getPortableTableDefinition($table)
{
return $table['name'];
}
/**
* @license New BSD License
* @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
* @param array $tableIndexes
* @param string $tableName
* @return array
*/
protected function _getPortableTableIndexesList($tableIndexes, $tableName=null)
{
$indexBuffer = array();
// fetch primary
$stmt = $this->_conn->executeQuery( "PRAGMA TABLE_INFO ('$tableName')" );
$indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach($indexArray AS $indexColumnRow) {
if($indexColumnRow['pk'] == "1") {
$indexBuffer[] = array(
'key_name' => 'primary',
'primary' => true,
'non_unique' => false,
'column_name' => $indexColumnRow['name']
);
}
}
// fetch regular indexes
foreach($tableIndexes AS $tableIndex) {
// Ignore indexes with reserved names, e.g. autoindexes
if (strpos($tableIndex['name'], 'sqlite_') !== 0) {
$keyName = $tableIndex['name'];
$idx = array();
$idx['key_name'] = $keyName;
$idx['primary'] = false;
$idx['non_unique'] = $tableIndex['unique']?false:true;
$stmt = $this->_conn->executeQuery( "PRAGMA INDEX_INFO ( '{$keyName}' )" );
$indexArray = $stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach ( $indexArray as $indexColumnRow ) {
$idx['column_name'] = $indexColumnRow['name'];
$indexBuffer[] = $idx;
}
}
}
return parent::_getPortableTableIndexesList($indexBuffer, $tableName);
}
protected function _getPortableTableIndexDefinition($tableIndex)
{
return array(
'name' => $tableIndex['name'],
'unique' => (bool) $tableIndex['unique']
);
}
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 = $this->_platform->getDoctrineTypeMapping($dbType);
$default = $tableColumn['dflt_value'];
if ($default == 'NULL') {
$default = null;
}
if ($default !== null) {
// SQLite returns strings wrapped in single quotes, so we need to strip them
$default = preg_replace("/^'(.*)'$/", '\1', $default);
}
$notnull = (bool) $tableColumn['notnull'];
if ( ! isset($tableColumn['name'])) {
$tableColumn['name'] = '';
}
$precision = null;
$scale = null;
switch ($dbType) {
case 'char':
$fixed = true;
break;
case 'float':
case 'double':
case 'real':
case 'decimal':
case 'numeric':
if (isset($tableColumn['length'])) {
list($precision, $scale) = array_map('trim', explode(', ', $tableColumn['length']));
}
$length = null;
break;
}
$options = array(
'length' => $length,
'unsigned' => (bool) $unsigned,
'fixed' => $fixed,
'notnull' => $notnull,
'default' => $default,
'precision' => $precision,
'scale' => $scale,
'autoincrement' => false,
);
return new Column($tableColumn['name'], \Doctrine\DBAL\Types\Type::getType($type), $options);
}
protected function _getPortableViewDefinition($view)
{
return new View($view['name'], $view['sql']);
}
}

View File

@@ -0,0 +1,645 @@
<?php
/*
* $Id$
*
* 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;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Schema\Visitor\Visitor;
use Doctrine\DBAL\DBALException;
/**
* Object Representation of a table
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class Table extends AbstractAsset
{
/**
* @var string
*/
protected $_name = null;
/**
* @var array
*/
protected $_columns = array();
/**
* @var array
*/
protected $_indexes = array();
/**
* @var string
*/
protected $_primaryKeyName = false;
/**
* @var array
*/
protected $_fkConstraints = array();
/**
* @var array
*/
protected $_options = array();
/**
* @var SchemaConfig
*/
protected $_schemaConfig = null;
/**
*
* @param string $tableName
* @param array $columns
* @param array $indexes
* @param array $fkConstraints
* @param int $idGeneratorType
* @param array $options
*/
public function __construct($tableName, array $columns=array(), array $indexes=array(), array $fkConstraints=array(), $idGeneratorType = 0, array $options=array())
{
if (strlen($tableName) == 0) {
throw DBALException::invalidTableName($tableName);
}
$this->_setName($tableName);
$this->_idGeneratorType = $idGeneratorType;
foreach ($columns AS $column) {
$this->_addColumn($column);
}
foreach ($indexes AS $idx) {
$this->_addIndex($idx);
}
foreach ($fkConstraints AS $constraint) {
$this->_addForeignKeyConstraint($constraint);
}
$this->_options = $options;
}
/**
* @param SchemaConfig $schemaConfig
*/
public function setSchemaConfig(SchemaConfig $schemaConfig)
{
$this->_schemaConfig = $schemaConfig;
}
/**
* @return int
*/
protected function _getMaxIdentifierLength()
{
if ($this->_schemaConfig instanceof SchemaConfig) {
return $this->_schemaConfig->getMaxIdentifierLength();
} else {
return 63;
}
}
/**
* Set Primary Key
*
* @param array $columns
* @param string $indexName
* @return Table
*/
public function setPrimaryKey(array $columns, $indexName = false)
{
$primaryKey = $this->_createIndex($columns, $indexName ?: "primary", true, true);
foreach ($columns AS $columnName) {
$column = $this->getColumn($columnName);
$column->setNotnull(true);
}
return $primaryKey;
}
/**
* @param array $columnNames
* @param string $indexName
* @return Table
*/
public function addIndex(array $columnNames, $indexName = null)
{
if($indexName == null) {
$indexName = $this->_generateIdentifierName(
array_merge(array($this->getName()), $columnNames), "idx", $this->_getMaxIdentifierLength()
);
}
return $this->_createIndex($columnNames, $indexName, false, false);
}
/**
*
* @param array $columnNames
* @param string $indexName
* @return Table
*/
public function addUniqueIndex(array $columnNames, $indexName = null)
{
if ($indexName === null) {
$indexName = $this->_generateIdentifierName(
array_merge(array($this->getName()), $columnNames), "uniq", $this->_getMaxIdentifierLength()
);
}
return $this->_createIndex($columnNames, $indexName, true, false);
}
/**
* Check if an index begins in the order of the given columns.
*
* @param array $columnsNames
* @return bool
*/
public function columnsAreIndexed(array $columnsNames)
{
foreach ($this->getIndexes() AS $index) {
/* @var $index Index */
if ($index->spansColumns($columnsNames)) {
return true;
}
}
return false;
}
/**
*
* @param array $columnNames
* @param string $indexName
* @param bool $isUnique
* @param bool $isPrimary
* @return Table
*/
private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary)
{
if (preg_match('(([^a-zA-Z0-9_]+))', $indexName)) {
throw SchemaException::indexNameInvalid($indexName);
}
foreach ($columnNames AS $columnName => $indexColOptions) {
if (is_numeric($columnName) && is_string($indexColOptions)) {
$columnName = $indexColOptions;
}
if ( ! $this->hasColumn($columnName)) {
throw SchemaException::columnDoesNotExist($columnName, $this->_name);
}
}
$this->_addIndex(new Index($indexName, $columnNames, $isUnique, $isPrimary));
return $this;
}
/**
* @param string $columnName
* @param string $columnType
* @param array $options
* @return Column
*/
public function addColumn($columnName, $typeName, array $options=array())
{
$column = new Column($columnName, Type::getType($typeName), $options);
$this->_addColumn($column);
return $column;
}
/**
* Rename Column
*
* @param string $oldColumnName
* @param string $newColumnName
* @return Table
*/
public function renameColumn($oldColumnName, $newColumnName)
{
$column = $this->getColumn($oldColumnName);
$this->dropColumn($oldColumnName);
$column->_setName($newColumnName);
return $this;
}
/**
* Change Column Details
*
* @param string $columnName
* @param array $options
* @return Table
*/
public function changeColumn($columnName, array $options)
{
$column = $this->getColumn($columnName);
$column->setOptions($options);
return $this;
}
/**
* Drop Column from Table
*
* @param string $columnName
* @return Table
*/
public function dropColumn($columnName)
{
$columnName = strtolower($columnName);
$column = $this->getColumn($columnName);
unset($this->_columns[$columnName]);
return $this;
}
/**
* Add a foreign key constraint
*
* Name is inferred from the local columns
*
* @param Table $foreignTable
* @param array $localColumns
* @param array $foreignColumns
* @param array $options
* @param string $constraintName
* @return Table
*/
public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array(), $constraintName = null)
{
$constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array)$this->getName(), $localColumnNames), "fk", $this->_getMaxIdentifierLength());
return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options);
}
/**
* Add a foreign key constraint
*
* Name is to be generated by the database itsself.
*
* @deprecated Use {@link addForeignKeyConstraint}
* @param Table $foreignTable
* @param array $localColumns
* @param array $foreignColumns
* @param array $options
* @return Table
*/
public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
{
return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options);
}
/**
* Add a foreign key constraint with a given name
*
* @deprecated Use {@link addForeignKeyConstraint}
* @param string $name
* @param Table $foreignTable
* @param array $localColumns
* @param array $foreignColumns
* @param array $options
* @return Table
*/
public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options=array())
{
if ($foreignTable instanceof Table) {
$foreignTableName = $foreignTable->getName();
foreach ($foreignColumnNames AS $columnName) {
if ( ! $foreignTable->hasColumn($columnName)) {
throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName());
}
}
} else {
$foreignTableName = $foreignTable;
}
foreach ($localColumnNames AS $columnName) {
if ( ! $this->hasColumn($columnName)) {
throw SchemaException::columnDoesNotExist($columnName, $this->_name);
}
}
$constraint = new ForeignKeyConstraint(
$localColumnNames, $foreignTableName, $foreignColumnNames, $name, $options
);
$this->_addForeignKeyConstraint($constraint);
return $this;
}
/**
* @param string $name
* @param string $value
* @return Table
*/
public function addOption($name, $value)
{
$this->_options[$name] = $value;
return $this;
}
/**
* @param Column $column
*/
protected function _addColumn(Column $column)
{
$columnName = $column->getName();
$columnName = strtolower($columnName);
if (isset($this->_columns[$columnName])) {
throw SchemaException::columnAlreadyExists($this->getName(), $columnName);
}
$this->_columns[$columnName] = $column;
}
/**
* Add index to table
*
* @param Index $indexCandidate
* @return Table
*/
protected function _addIndex(Index $indexCandidate)
{
// check for duplicates
foreach ($this->_indexes AS $existingIndex) {
if ($indexCandidate->isFullfilledBy($existingIndex)) {
return $this;
}
}
$indexName = $indexCandidate->getName();
$indexName = strtolower($indexName);
if (isset($this->_indexes[$indexName]) || ($this->_primaryKeyName != false && $indexCandidate->isPrimary())) {
throw SchemaException::indexAlreadyExists($indexName, $this->_name);
}
// remove overruled indexes
foreach ($this->_indexes AS $idxKey => $existingIndex) {
if ($indexCandidate->overrules($existingIndex)) {
unset($this->_indexes[$idxKey]);
}
}
if ($indexCandidate->isPrimary()) {
$this->_primaryKeyName = $indexName;
}
$this->_indexes[$indexName] = $indexCandidate;
return $this;
}
/**
* @param ForeignKeyConstraint $constraint
*/
protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint)
{
$constraint->setLocalTable($this);
if(strlen($constraint->getName())) {
$name = $constraint->getName();
} else {
$name = $this->_generateIdentifierName(
array_merge((array)$this->getName(), $constraint->getLocalColumns()), "fk", $this->_getMaxIdentifierLength()
);
}
$name = strtolower($name);
$this->_fkConstraints[$name] = $constraint;
// add an explicit index on the foreign key columns. If there is already an index that fullfils this requirements drop the request.
// In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes
// lead to duplicates. This creates compuation overhead in this case, however no duplicate indexes are ever added (based on columns).
$this->addIndex($constraint->getColumns());
}
/**
* Does Table have a foreign key constraint with the given name?
* *
* @param string $constraintName
* @return bool
*/
public function hasForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
return isset($this->_fkConstraints[$constraintName]);
}
/**
* @param string $constraintName
* @return ForeignKeyConstraint
*/
public function getForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
if(!$this->hasForeignKey($constraintName)) {
throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
}
return $this->_fkConstraints[$constraintName];
}
public function removeForeignKey($constraintName)
{
$constraintName = strtolower($constraintName);
if(!$this->hasForeignKey($constraintName)) {
throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name);
}
unset($this->_fkConstraints[$constraintName]);
}
/**
* @return Column[]
*/
public function getColumns()
{
$columns = $this->_columns;
$pkCols = array();
$fkCols = array();
if ($this->hasPrimaryKey()) {
$pkCols = $this->getPrimaryKey()->getColumns();
}
foreach ($this->getForeignKeys() AS $fk) {
/* @var $fk ForeignKeyConstraint */
$fkCols = array_merge($fkCols, $fk->getColumns());
}
$colNames = array_unique(array_merge($pkCols, $fkCols, array_keys($columns)));
uksort($columns, function($a, $b) use($colNames) {
return (array_search($a, $colNames) >= array_search($b, $colNames));
});
return $columns;
}
/**
* Does this table have a column with the given name?
*
* @param string $columnName
* @return bool
*/
public function hasColumn($columnName)
{
$columnName = $this->trimQuotes(strtolower($columnName));
return isset($this->_columns[$columnName]);
}
/**
* Get a column instance
*
* @param string $columnName
* @return Column
*/
public function getColumn($columnName)
{
$columnName = strtolower($this->trimQuotes($columnName));
if (!$this->hasColumn($columnName)) {
throw SchemaException::columnDoesNotExist($columnName, $this->_name);
}
return $this->_columns[$columnName];
}
/**
* @return Index|null
*/
public function getPrimaryKey()
{
if (!$this->hasPrimaryKey()) {
return null;
}
return $this->getIndex($this->_primaryKeyName);
}
/**
* Check if this table has a primary key.
*
* @return bool
*/
public function hasPrimaryKey()
{
return ($this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName));
}
/**
* @param string $indexName
* @return bool
*/
public function hasIndex($indexName)
{
$indexName = strtolower($indexName);
return (isset($this->_indexes[$indexName]));
}
/**
* @param string $indexName
* @return Index
*/
public function getIndex($indexName)
{
$indexName = strtolower($indexName);
if (!$this->hasIndex($indexName)) {
throw SchemaException::indexDoesNotExist($indexName, $this->_name);
}
return $this->_indexes[$indexName];
}
/**
* @return array
*/
public function getIndexes()
{
return $this->_indexes;
}
/**
* Get Constraints
*
* @return array
*/
public function getForeignKeys()
{
return $this->_fkConstraints;
}
public function hasOption($name)
{
return isset($this->_options[$name]);
}
public function getOption($name)
{
return $this->_options[$name];
}
public function getOptions()
{
return $this->_options;
}
/**
* @param Visitor $visitor
*/
public function visit(Visitor $visitor)
{
$visitor->acceptTable($this);
foreach ($this->getColumns() AS $column) {
$visitor->acceptColumn($this, $column);
}
foreach ($this->getIndexes() AS $index) {
$visitor->acceptIndex($this, $index);
}
foreach ($this->getForeignKeys() AS $constraint) {
$visitor->acceptForeignKey($this, $constraint);
}
}
/**
* Clone of a Table triggers a deep clone of all affected assets
*/
public function __clone()
{
foreach ($this->_columns AS $k => $column) {
$this->_columns[$k] = clone $column;
}
foreach ($this->_indexes AS $k => $index) {
$this->_indexes[$k] = clone $index;
}
foreach ($this->_fkConstraints AS $k => $fk) {
$this->_fkConstraints[$k] = clone $fk;
$this->_fkConstraints[$k]->setLocalTable($this);
}
}
}

View File

@@ -0,0 +1,136 @@
<?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;
/**
* Table Diff
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class TableDiff
{
/**
* @var string
*/
public $name = null;
/**
* @var string
*/
public $newName = false;
/**
* All added fields
*
* @var array(string=>Column)
*/
public $addedColumns;
/**
* All changed fields
*
* @var array(string=>Column)
*/
public $changedColumns = array();
/**
* All removed fields
*
* @var array(string=>Column)
*/
public $removedColumns = array();
/**
* Columns that are only renamed from key to column instance name.
*
* @var array(string=>Column)
*/
public $renamedColumns = array();
/**
* All added indexes
*
* @var array(string=>Index)
*/
public $addedIndexes = array();
/**
* All changed indexes
*
* @var array(string=>Index)
*/
public $changedIndexes = array();
/**
* All removed indexes
*
* @var array(string=>bool)
*/
public $removedIndexes = array();
/**
* All added foreign key definitions
*
* @var array
*/
public $addedForeignKeys = array();
/**
* All changed foreign keys
*
* @var array
*/
public $changedForeignKeys = array();
/**
* All removed foreign keys
*
* @var array
*/
public $removedForeignKeys = array();
/**
* Constructs an TableDiff object.
*
* @param array(string=>Column) $addedColumns
* @param array(string=>Column) $changedColumns
* @param array(string=>bool) $removedColumns
* @param array(string=>Index) $addedIndexes
* @param array(string=>Index) $changedIndexes
* @param array(string=>bool) $removedIndexes
*/
public function __construct($tableName, $addedColumns = array(),
$changedColumns = array(), $removedColumns = array(), $addedIndexes = array(),
$changedIndexes = array(), $removedIndexes = array())
{
$this->name = $tableName;
$this->addedColumns = $addedColumns;
$this->changedColumns = $changedColumns;
$this->removedColumns = $removedColumns;
$this->addedIndexes = $addedIndexes;
$this->changedIndexes = $changedIndexes;
$this->removedIndexes = $removedIndexes;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* $Id$
*
* 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;
/**
* Representation of a Database View
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.com
* @since 1.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class View extends AbstractAsset
{
/**
* @var string
*/
private $_sql;
public function __construct($name, $sql)
{
$this->_setName($name);
$this->_sql = $sql;
}
/**
* @return string
*/
public function getSql()
{
return $this->_sql;
}
}

View File

@@ -0,0 +1,147 @@
<?php
/*
* $Id$
*
* 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;
class CreateSchemaSqlCollector implements Visitor
{
/**
* @var array
*/
private $_createTableQueries = array();
/**
* @var array
*/
private $_createSequenceQueries = array();
/**
* @var array
*/
private $_createFkConstraintQueries = array();
/**
*
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
*/
private $_platform = null;
/**
* @param AbstractPlatform $platform
*/
public function __construct(AbstractPlatform $platform)
{
$this->_platform = $platform;
}
/**
* @param Schema $schema
*/
public function acceptSchema(Schema $schema)
{
}
/**
* Generate DDL Statements to create the accepted table with all its dependencies.
*
* @param Table $table
*/
public function acceptTable(Table $table)
{
$this->_createTableQueries = array_merge($this->_createTableQueries,
$this->_platform->getCreateTableSQL($table)
);
}
public function acceptColumn(Table $table, Column $column)
{
}
/**
* @param Table $localTable
* @param ForeignKeyConstraint $fkConstraint
*/
public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
{
// Append the foreign key constraints SQL
if ($this->_platform->supportsForeignKeyConstraints()) {
$this->_createFkConstraintQueries = array_merge($this->_createFkConstraintQueries,
(array) $this->_platform->getCreateForeignKeySQL(
$fkConstraint, $localTable
)
);
}
}
/**
* @param Table $table
* @param Index $index
*/
public function acceptIndex(Table $table, Index $index)
{
}
/**
* @param Sequence $sequence
*/
public function acceptSequence(Sequence $sequence)
{
$this->_createSequenceQueries = array_merge(
$this->_createSequenceQueries, (array)$this->_platform->getCreateSequenceSQL($sequence)
);
}
/**
* @return array
*/
public function resetQueries()
{
$this->_createTableQueries = array();
$this->_createSequenceQueries = array();
$this->_createFkConstraintQueries = array();
}
/**
* Get all queries collected so far.
*
* @return array
*/
public function getQueries()
{
return array_merge(
$this->_createTableQueries,
$this->_createSequenceQueries,
$this->_createFkConstraintQueries
);
}
}

View File

@@ -0,0 +1,159 @@
<?php
/*
* $Id$
*
* 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;
/**
* Gather SQL statements that allow to completly drop the current schema.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class DropSchemaSqlCollector implements Visitor
{
/**
* @var \SplObjectStorage
*/
private $constraints;
/**
* @var \SplObjectStorage
*/
private $sequences;
/**
* @var \SplObjectStorage
*/
private $tables;
/**
*
* @var \Doctrine\DBAL\Platforms\AbstractPlatform
*/
private $platform;
/**
* @param AbstractPlatform $platform
*/
public function __construct(AbstractPlatform $platform)
{
$this->platform = $platform;
$this->clearQueries();
}
/**
* @param Schema $schema
*/
public function acceptSchema(Schema $schema)
{
}
/**
* @param Table $table
*/
public function acceptTable(Table $table)
{
$this->tables->attach($table);
}
/**
* @param Column $column
*/
public function acceptColumn(Table $table, Column $column)
{
}
/**
* @param Table $localTable
* @param ForeignKeyConstraint $fkConstraint
*/
public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
{
if (strlen($fkConstraint->getName()) == 0) {
throw SchemaException::namedForeignKeyRequired($localTable, $fkConstraint);
}
$this->constraints->attach($fkConstraint);
$this->constraints[$fkConstraint] = $localTable;
}
/**
* @param Table $table
* @param Index $index
*/
public function acceptIndex(Table $table, Index $index)
{
}
/**
* @param Sequence $sequence
*/
public function acceptSequence(Sequence $sequence)
{
$this->sequences->attach($sequence);
}
/**
* @return void
*/
public function clearQueries()
{
$this->constraints = new \SplObjectStorage();
$this->sequences = new \SplObjectStorage();
$this->tables = new \SplObjectStorage();
}
/**
* @return array
*/
public function getQueries()
{
$sql = array();
foreach ($this->constraints AS $fkConstraint) {
$localTable = $this->constraints[$fkConstraint];
$sql[] = $this->platform->getDropForeignKeySQL($fkConstraint, $localTable);
}
foreach ($this->sequences AS $sequence) {
$sql[] = $this->platform->getDropSequenceSQL($sequence);
}
foreach ($this->tables AS $table) {
$sql[] = $this->platform->getDropTableSQL($table);
}
return $sql;
}
}

View File

@@ -0,0 +1,151 @@
<?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;
class Graphviz implements \Doctrine\DBAL\Schema\Visitor\Visitor
{
private $output = '';
public function acceptColumn(Table $table, Column $column)
{
}
public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint)
{
$this->output .= $this->createNodeRelation(
$fkConstraint->getLocalTableName() . ":col" . current($fkConstraint->getLocalColumns()).":se",
$fkConstraint->getForeignTableName() . ":col" . current($fkConstraint->getForeignColumns()).":se",
array(
'dir' => 'back',
'arrowtail' => 'dot',
'arrowhead' => 'normal',
)
);
}
public function acceptIndex(Table $table, Index $index)
{
}
public function acceptSchema(Schema $schema)
{
$this->output = 'digraph "' . sha1( mt_rand() ) . '" {' . "\n";
$this->output .= 'splines = true;' . "\n";
$this->output .= 'overlap = false;' . "\n";
$this->output .= 'outputorder=edgesfirst;'."\n";
$this->output .= 'mindist = 0.6;' . "\n";
$this->output .= 'sep = .2;' . "\n";
}
public function acceptSequence(Sequence $sequence)
{
}
public function acceptTable(Table $table)
{
$this->output .= $this->createNode(
$table->getName(),
array(
'label' => $this->createTableLabel( $table ),
'shape' => 'plaintext',
)
);
}
private function createTableLabel( Table $table )
{
// Start the table
$label = '<<TABLE CELLSPACING="0" BORDER="1" ALIGN="LEFT">';
// The title
$label .= '<TR><TD BORDER="1" COLSPAN="3" ALIGN="CENTER" BGCOLOR="#fcaf3e"><FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="12">' . $table->getName() . '</FONT></TD></TR>';
// The attributes block
foreach( $table->getColumns() as $column ) {
$columnLabel = $column->getName();
$label .= '<TR>';
$label .= '<TD BORDER="0" ALIGN="LEFT" BGCOLOR="#eeeeec">';
$label .= '<FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="12">' . $columnLabel . '</FONT>';
$label .= '</TD><TD BORDER="0" ALIGN="LEFT" BGCOLOR="#eeeeec"><FONT COLOR="#2e3436" FACE="Helvetica" POINT-SIZE="10">' . strtolower($column->getType()) . '</FONT></TD>';
$label .= '<TD BORDER="0" ALIGN="RIGHT" BGCOLOR="#eeeeec" PORT="col'.$column->getName().'">';
if ($table->hasPrimaryKey() && in_array($column->getName(), $table->getPrimaryKey()->getColumns())) {
$label .= "\xe2\x9c\xb7";
}
$label .= '</TD></TR>';
}
// End the table
$label .= '</TABLE>>';
return $label;
}
private function createNode( $name, $options )
{
$node = $name . " [";
foreach( $options as $key => $value )
{
$node .= $key . '=' . $value . ' ';
}
$node .= "]\n";
return $node;
}
private function createNodeRelation( $node1, $node2, $options )
{
$relation = $node1 . ' -> ' . $node2 . ' [';
foreach( $options as $key => $value )
{
$relation .= $key . '=' . $value . ' ';
}
$relation .= "]\n";
return $relation;
}
/**
* Write dot language output to a file. This should usually be a *.dot file.
*
* You have to convert the output into a viewable format. For example use "neato" on linux systems
* and execute:
*
* neato -Tpng -o er.png er.dot
*
* @param string $filename
* @return void
*/
public function write($filename)
{
file_put_contents($filename, $this->output . "}");
}
}

View File

@@ -0,0 +1,113 @@
<?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)
{
// The table may already be deleted in a previous
// RemoveNamespacedAssets#acceptTable call. Removing Foreign keys that
// point to nowhere.
if ( ! $this->schema->hasTable($fkConstraint->getForeignTableName())) {
$localTable->removeForeignKey($fkConstraint->getName());
return;
}
$foreignTable = $this->schema->getTable($fkConstraint->getForeignTableName());
if ( ! $foreignTable->isInDefaultNamespace($this->schema->getName()) ) {
$localTable->removeForeignKey($fkConstraint->getName());
}
}
/**
* @param Table $table
* @param Index $index
*/
public function acceptIndex(Table $table, Index $index)
{
}
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* $Id$
*
* 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;
/**
* Schema Visitor used for Validation or Generation purposes.
*
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
interface Visitor
{
/**
* @param Schema $schema
*/
public function acceptSchema(Schema $schema);
/**
* @param Table $table
*/
public function acceptTable(Table $table);
/**
* @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);
/**
* @param Sequence $sequence
*/
public function acceptSequence(Sequence $sequence);
}