Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
d4fec7cd
Unverified
Commit
d4fec7cd
authored
Sep 22, 2016
by
Guilherme Blanco
Committed by
Sergei Morozov
Nov 24, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Decouple unique index from unique constraint
parent
9dbec4b5
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
513 additions
and
180 deletions
+513
-180
AbstractPlatform.php
lib/Doctrine/DBAL/Platforms/AbstractPlatform.php
+21
-13
SqlitePlatform.php
lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
+2
-1
AbstractSchemaManager.php
lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php
+4
-1
Index.php
lib/Doctrine/DBAL/Schema/Index.php
+2
-0
SchemaException.php
lib/Doctrine/DBAL/Schema/SchemaException.php
+17
-1
Table.php
lib/Doctrine/DBAL/Schema/Table.php
+336
-160
UniqueConstraint.php
lib/Doctrine/DBAL/Schema/UniqueConstraint.php
+121
-0
ExceptionTest.php
tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php
+1
-0
SchemaManagerFunctionalTestCase.php
...BAL/Functional/Schema/SchemaManagerFunctionalTestCase.php
+5
-2
ComparatorTest.php
tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php
+2
-0
TableTest.php
tests/Doctrine/Tests/DBAL/Schema/TableTest.php
+2
-2
No files found.
lib/Doctrine/DBAL/Platforms/AbstractPlatform.php
View file @
d4fec7cd
...
...
@@ -23,6 +23,7 @@ use Doctrine\DBAL\Schema\Index;
use
Doctrine\DBAL\Schema\Sequence
;
use
Doctrine\DBAL\Schema\Table
;
use
Doctrine\DBAL\Schema\TableDiff
;
use
Doctrine\DBAL\Schema\UniqueConstraint
;
use
Doctrine\DBAL\TransactionIsolationLevel
;
use
Doctrine\DBAL\Types
;
use
Doctrine\DBAL\Types\Type
;
...
...
@@ -1534,15 +1535,30 @@ abstract class AbstractPlatform
$options
[
'indexes'
]
=
[];
$options
[
'primary'
]
=
[];
if
((
$createFlags
&
self
::
CREATE_INDEXES
)
>
0
)
{
if
((
$createFlags
&
self
::
CREATE_INDEXES
)
>
0
)
{
foreach
(
$table
->
getIndexes
()
as
$index
)
{
/** @var $index Index */
if
(
$index
->
isPrimary
())
{
$options
[
'primary'
]
=
$index
->
getQuotedColumns
(
$this
);
$options
[
'primary_index'
]
=
$index
;
}
else
{
if
(
!
$index
->
isPrimary
())
{
$options
[
'indexes'
][
$index
->
getQuotedName
(
$this
)]
=
$index
;
continue
;
}
$options
[
'primary'
]
=
$index
->
getQuotedColumns
(
$this
);
$options
[
'primary_index'
]
=
$index
;
}
foreach
(
$table
->
getUniqueConstraints
()
as
$uniqueConstraint
)
{
/** @var UniqueConstraint $uniqueConstraint */
$options
[
'uniqueConstraints'
][
$uniqueConstraint
->
getQuotedName
(
$this
)]
=
$uniqueConstraint
;
}
}
if
((
$createFlags
&
self
::
CREATE_FOREIGNKEYS
)
>
0
)
{
$options
[
'foreignKeys'
]
=
[];
foreach
(
$table
->
getForeignKeys
()
as
$fkConstraint
)
{
$options
[
'foreignKeys'
][]
=
$fkConstraint
;
}
}
...
...
@@ -1551,7 +1567,6 @@ abstract class AbstractPlatform
foreach
(
$table
->
getColumns
()
as
$column
)
{
/** @var Column $column */
if
(
$this
->
_eventManager
!==
null
&&
$this
->
_eventManager
->
hasListeners
(
Events
::
onSchemaCreateTableColumn
))
{
$eventArgs
=
new
SchemaCreateTableColumnEventArgs
(
$column
,
$table
,
$this
);
$this
->
_eventManager
->
dispatchEvent
(
Events
::
onSchemaCreateTableColumn
,
$eventArgs
);
...
...
@@ -1579,13 +1594,6 @@ abstract class AbstractPlatform
$columns
[
$columnData
[
'name'
]]
=
$columnData
;
}
if
((
$createFlags
&
self
::
CREATE_FOREIGNKEYS
)
>
0
)
{
$options
[
'foreignKeys'
]
=
[];
foreach
(
$table
->
getForeignKeys
()
as
$fkConstraint
)
{
$options
[
'foreignKeys'
][]
=
$fkConstraint
;
}
}
if
(
$this
->
_eventManager
!==
null
&&
$this
->
_eventManager
->
hasListeners
(
Events
::
onSchemaCreateTable
))
{
$eventArgs
=
new
SchemaCreateTableEventArgs
(
$table
,
$columns
,
$options
,
$this
);
$this
->
_eventManager
->
dispatchEvent
(
Events
::
onSchemaCreateTable
,
$eventArgs
);
...
...
lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
View file @
d4fec7cd
...
...
@@ -893,10 +893,11 @@ class SqlitePlatform extends AbstractPlatform
$sql
=
[];
$tableSql
=
[];
if
(
!
$this
->
onSchemaAlterTable
(
$diff
,
$tableSql
))
{
$dataTable
=
new
Table
(
'__temp__'
.
$table
->
getName
());
$newTable
=
new
Table
(
$table
->
getQuotedName
(
$this
),
$columns
,
$this
->
getPrimaryIndexInAlteredTable
(
$diff
),
$this
->
getForeignKeysInAlteredTable
(
$diff
),
0
,
$table
->
getOptions
());
$newTable
=
new
Table
(
$table
->
getQuotedName
(
$this
),
$columns
,
$this
->
getPrimaryIndexInAlteredTable
(
$diff
),
[],
$this
->
getForeignKeysInAlteredTable
(
$diff
),
0
,
$table
->
getOptions
());
$newTable
->
addOption
(
'alter'
,
true
);
$sql
=
$this
->
getPreAlterTableIndexForeignKeySQL
(
$diff
);
...
...
lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php
View file @
d4fec7cd
...
...
@@ -263,12 +263,14 @@ abstract class AbstractSchemaManager
{
$columns
=
$this
->
listTableColumns
(
$tableName
);
$foreignKeys
=
[];
if
(
$this
->
_platform
->
supportsForeignKeyConstraints
())
{
$foreignKeys
=
$this
->
listTableForeignKeys
(
$tableName
);
}
$indexes
=
$this
->
listTableIndexes
(
$tableName
);
return
new
Table
(
$tableName
,
$columns
,
$indexes
,
$foreignKeys
,
false
,
[]);
return
new
Table
(
$tableName
,
$columns
,
$indexes
,
[],
$foreignKeys
,
false
,
[]);
}
/**
...
...
@@ -587,6 +589,7 @@ abstract class AbstractSchemaManager
public
function
alterTable
(
TableDiff
$tableDiff
)
{
$queries
=
$this
->
_platform
->
getAlterTableSQL
(
$tableDiff
);
if
(
!
is_array
(
$queries
)
||
!
count
(
$queries
))
{
return
;
}
...
...
lib/Doctrine/DBAL/Schema/Index.php
View file @
d4fec7cd
...
...
@@ -57,6 +57,7 @@ class Index extends AbstractAsset implements Constraint
$isUnique
=
$isUnique
||
$isPrimary
;
$this
->
_setName
(
$indexName
);
$this
->
_isUnique
=
$isUnique
;
$this
->
_isPrimary
=
$isPrimary
;
$this
->
options
=
$options
;
...
...
@@ -64,6 +65,7 @@ class Index extends AbstractAsset implements Constraint
foreach
(
$columns
as
$column
)
{
$this
->
_addColumn
(
$column
);
}
foreach
(
$flags
as
$flag
)
{
$this
->
addFlag
(
$flag
);
}
...
...
lib/Doctrine/DBAL/Schema/SchemaException.php
View file @
d4fec7cd
...
...
@@ -18,7 +18,8 @@ class SchemaException extends DBALException
public
const
SEQUENCE_ALREADY_EXISTS
=
80
;
public
const
INDEX_INVALID_NAME
=
90
;
public
const
FOREIGNKEY_DOESNT_EXIST
=
100
;
public
const
NAMESPACE_ALREADY_EXISTS
=
110
;
public
const
CONSTRAINT_DOESNT_EXIST
=
110
;
public
const
NAMESPACE_ALREADY_EXISTS
=
120
;
/**
* @param string $tableName
...
...
@@ -142,6 +143,21 @@ class SchemaException extends DBALException
return
new
self
(
"There exists no sequence with the name '"
.
$sequenceName
.
"'."
,
self
::
SEQUENCE_DOENST_EXIST
);
}
/**
* @param string $constraintName
* @param string $table
*
* @return self
*/
public
static
function
uniqueConstraintDoesNotExist
(
$constraintName
,
$table
)
{
return
new
self
(
sprintf
(
'There exists no unique constraint with the name "%s" on table "%s".'
,
$constraintName
,
$table
),
self
::
CONSTRAINT_DOESNT_EXIST
);
}
/**
* @param string $fkName
* @param string $table
...
...
lib/Doctrine/DBAL/Schema/Table.php
View file @
d4fec7cd
...
...
@@ -7,7 +7,9 @@ use Doctrine\DBAL\Schema\Visitor\Visitor;
use
Doctrine\DBAL\Types\Type
;
use
const
ARRAY_FILTER_USE_KEY
;
use
function
array_filter
;
use
function
array_keys
;
use
function
array_merge
;
use
function
array_unique
;
use
function
in_array
;
use
function
is_numeric
;
use
function
is_string
;
...
...
@@ -35,6 +37,9 @@ class Table extends AbstractAsset
/** @var string */
protected
$_primaryKeyName
=
false
;
/** @var UniqueConstraint[] */
protected
$_uniqueConstraints
=
[];
/** @var ForeignKeyConstraint[] */
protected
$_fkConstraints
=
[];
...
...
@@ -48,14 +53,22 @@ class Table extends AbstractAsset
* @param string $tableName
* @param Column[] $columns
* @param Index[] $indexes
* @param UniqueConstraint[] $uniqueConstraints
* @param ForeignKeyConstraint[] $fkConstraints
* @param int $idGeneratorType
* @param mixed[] $options
*
* @throws DBALException
*/
public
function
__construct
(
$tableName
,
array
$columns
=
[],
array
$indexes
=
[],
array
$fkConstraints
=
[],
$idGeneratorType
=
0
,
array
$options
=
[])
{
public
function
__construct
(
$tableName
,
array
$columns
=
[],
array
$indexes
=
[],
array
$uniqueConstraints
=
[],
array
$fkConstraints
=
[],
$idGeneratorType
=
0
,
array
$options
=
[]
)
{
if
(
strlen
(
$tableName
)
===
0
)
{
throw
DBALException
::
invalidTableName
(
$tableName
);
}
...
...
@@ -70,8 +83,12 @@ class Table extends AbstractAsset
$this
->
_addIndex
(
$idx
);
}
foreach
(
$fkConstraints
as
$constraint
)
{
$this
->
_addForeignKeyConstraint
(
$constraint
);
foreach
(
$uniqueConstraints
as
$uniqueConstraint
)
{
$this
->
_addUniqueConstraint
(
$uniqueConstraint
);
}
foreach
(
$fkConstraints
as
$fkConstraint
)
{
$this
->
_addForeignKeyConstraint
(
$fkConstraint
);
}
$this
->
_options
=
$options
;
...
...
@@ -85,18 +102,6 @@ class Table extends AbstractAsset
$this
->
_schemaConfig
=
$schemaConfig
;
}
/**
* @return int
*/
protected
function
_getMaxIdentifierLength
()
{
if
(
$this
->
_schemaConfig
instanceof
SchemaConfig
)
{
return
$this
->
_schemaConfig
->
getMaxIdentifierLength
();
}
return
63
;
}
/**
* Sets the Primary Key.
*
...
...
@@ -117,6 +122,26 @@ class Table extends AbstractAsset
return
$this
;
}
/**
* @param mixed[] $columnNames
* @param string|null $indexName
* @param mixed[] $options
*
* @return self
*/
public
function
addUniqueConstraint
(
array
$columnNames
,
$indexName
=
null
,
array
$options
=
[])
{
if
(
$indexName
===
null
)
{
$indexName
=
$this
->
_generateIdentifierName
(
array_merge
([
$this
->
getName
()],
$columnNames
),
'uniq'
,
$this
->
_getMaxIdentifierLength
()
);
}
return
$this
->
_addUniqueConstraint
(
$this
->
_createUniqueConstraint
(
$columnNames
,
$indexName
,
$options
));
}
/**
* @param mixed[][] $columnNames
* @param string|null $indexName
...
...
@@ -161,9 +186,11 @@ class Table extends AbstractAsset
public
function
dropIndex
(
$indexName
)
{
$indexName
=
$this
->
normalizeIdentifier
(
$indexName
);
if
(
!
$this
->
hasIndex
(
$indexName
))
{
throw
SchemaException
::
indexDoesNotExist
(
$indexName
,
$this
->
_name
);
}
unset
(
$this
->
_indexes
[
$indexName
]);
}
...
...
@@ -252,37 +279,6 @@ class Table extends AbstractAsset
return
false
;
}
/**
* @param mixed[][] $columnNames
* @param string $indexName
* @param bool $isUnique
* @param bool $isPrimary
* @param string[] $flags
* @param mixed[] $options
*
* @return Index
*
* @throws SchemaException
*/
private
function
_createIndex
(
array
$columnNames
,
$indexName
,
$isUnique
,
$isPrimary
,
array
$flags
=
[],
array
$options
=
[])
{
if
(
preg_match
(
'(([^a-zA-Z0-9_]+))'
,
$this
->
normalizeIdentifier
(
$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
);
}
}
return
new
Index
(
$indexName
,
$columnNames
,
$isUnique
,
$isPrimary
,
$flags
,
$options
);
}
/**
* @param string $columnName
* @param string $typeName
...
...
@@ -311,9 +307,11 @@ class Table extends AbstractAsset
*/
public
function
renameColumn
(
$oldColumnName
,
$newColumnName
)
{
throw
new
DBALException
(
'Table#renameColumn() was removed, because it drops and recreates '
.
'the column instead. There is no fix available, because a schema diff cannot reliably detect if a '
.
'column was renamed or one column was created and another one dropped.'
);
throw
new
DBALException
(
'Table#renameColumn() was removed, because it drops and recreates the column instead. '
.
'There is no fix available, because a schema diff cannot reliably detect if a column '
.
'was renamed or one column was created and another one dropped.'
);
}
/**
...
...
@@ -327,6 +325,7 @@ class Table extends AbstractAsset
public
function
changeColumn
(
$columnName
,
array
$options
)
{
$column
=
$this
->
getColumn
(
$columnName
);
$column
->
setOptions
(
$options
);
return
$this
;
...
...
@@ -342,6 +341,7 @@ class Table extends AbstractAsset
public
function
dropColumn
(
$columnName
)
{
$columnName
=
$this
->
normalizeIdentifier
(
$columnName
);
unset
(
$this
->
_columns
[
$columnName
]);
return
$this
;
...
...
@@ -362,7 +362,13 @@ class Table extends AbstractAsset
*/
public
function
addForeignKeyConstraint
(
$foreignTable
,
array
$localColumnNames
,
array
$foreignColumnNames
,
array
$options
=
[],
$constraintName
=
null
)
{
$constraintName
=
$constraintName
?:
$this
->
_generateIdentifierName
(
array_merge
((
array
)
$this
->
getName
(),
$localColumnNames
),
'fk'
,
$this
->
_getMaxIdentifierLength
());
if
(
!
$constraintName
)
{
$constraintName
=
$this
->
_generateIdentifierName
(
array_merge
((
array
)
$this
->
getName
(),
$localColumnNames
),
'fk'
,
$this
->
_getMaxIdentifierLength
()
);
}
return
$this
->
addNamedForeignKeyConstraint
(
$constraintName
,
$foreignTable
,
$localColumnNames
,
$foreignColumnNames
,
$options
);
}
...
...
@@ -424,9 +430,8 @@ class Table extends AbstractAsset
$name
,
$options
);
$this
->
_addForeignKeyConstraint
(
$constraint
);
return
$this
;
return
$this
->
_addForeignKeyConstraint
(
$constraint
)
;
}
/**
...
...
@@ -443,137 +448,95 @@ class Table extends AbstractAsset
}
/**
*
@return void
*
Returns whether this table has a foreign key constraint with the given name.
*
* @throws SchemaException
* @param string $constraintName
*
* @return bool
*/
p
rotected
function
_addColumn
(
Column
$column
)
p
ublic
function
hasForeignKey
(
$constraintName
)
{
$columnName
=
$column
->
getName
();
$columnName
=
$this
->
normalizeIdentifier
(
$columnName
);
if
(
isset
(
$this
->
_columns
[
$columnName
]))
{
throw
SchemaException
::
columnAlreadyExists
(
$this
->
getName
(),
$columnName
);
}
$constraintName
=
$this
->
normalizeIdentifier
(
$constraintName
);
$this
->
_columns
[
$columnName
]
=
$column
;
return
isset
(
$this
->
_fkConstraints
[
$constraintName
])
;
}
/**
*
Adds an index to the tabl
e.
*
Returns the foreign key constraint with the given nam
e.
*
* @
return self
* @
param string $constraintName The constraint name.
*
* @throws SchemaException
* @return ForeignKeyConstraint
*
* @throws SchemaException If the foreign key does not exist.
*/
p
rotected
function
_addIndex
(
Index
$indexCandidat
e
)
p
ublic
function
getForeignKey
(
$constraintNam
e
)
{
$indexName
=
$indexCandidate
->
getName
();
$indexName
=
$this
->
normalizeIdentifier
(
$indexName
);
$replacedImplicitIndexes
=
[];
foreach
(
$this
->
implicitIndexes
as
$name
=>
$implicitIndex
)
{
if
(
!
$implicitIndex
->
isFullfilledBy
(
$indexCandidate
)
||
!
isset
(
$this
->
_indexes
[
$name
]))
{
continue
;
}
$replacedImplicitIndexes
[]
=
$name
;
}
if
((
isset
(
$this
->
_indexes
[
$indexName
])
&&
!
in_array
(
$indexName
,
$replacedImplicitIndexes
,
true
))
||
(
$this
->
_primaryKeyName
!==
false
&&
$indexCandidate
->
isPrimary
())
)
{
throw
SchemaException
::
indexAlreadyExists
(
$indexName
,
$this
->
_name
);
}
foreach
(
$replacedImplicitIndexes
as
$name
)
{
unset
(
$this
->
_indexes
[
$name
],
$this
->
implicitIndexes
[
$name
]);
}
$constraintName
=
$this
->
normalizeIdentifier
(
$constraintName
);
if
(
$indexCandidate
->
isPrimary
(
))
{
$this
->
_primaryKeyName
=
$indexName
;
if
(
!
$this
->
hasForeignKey
(
$constraintName
))
{
throw
SchemaException
::
foreignKeyDoesNotExist
(
$constraintName
,
$this
->
_name
)
;
}
$this
->
_indexes
[
$indexName
]
=
$indexCandidate
;
return
$this
;
return
$this
->
_fkConstraints
[
$constraintName
];
}
/**
* Removes the foreign key constraint with the given name.
*
* @param string $constraintName The constraint name.
*
* @return void
*
* @throws SchemaException
*/
p
rotected
function
_addForeignKeyConstraint
(
ForeignKeyConstraint
$constraint
)
p
ublic
function
removeForeignKey
(
$constraintName
)
{
$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
=
$this
->
normalizeIdentifier
(
$name
);
$this
->
_fkConstraints
[
$name
]
=
$constraint
;
// add an explicit index on the foreign key columns. If there is already an index that fulfils 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 computation overhead in this case, however no duplicate indexes are ever added (based on columns).
$indexName
=
$this
->
_generateIdentifierName
(
array_merge
([
$this
->
getName
()],
$constraint
->
getColumns
()),
'idx'
,
$this
->
_getMaxIdentifierLength
()
);
$indexCandidate
=
$this
->
_createIndex
(
$constraint
->
getColumns
(),
$indexName
,
false
,
false
);
$constraintName
=
$this
->
normalizeIdentifier
(
$constraintName
);
foreach
(
$this
->
_indexes
as
$existingIndex
)
{
if
(
$indexCandidate
->
isFullfilledBy
(
$existingIndex
))
{
return
;
}
if
(
!
$this
->
hasForeignKey
(
$constraintName
))
{
throw
SchemaException
::
foreignKeyDoesNotExist
(
$constraintName
,
$this
->
_name
);
}
$this
->
_addIndex
(
$indexCandidate
);
$this
->
implicitIndexes
[
$this
->
normalizeIdentifier
(
$indexName
)]
=
$indexCandidate
;
unset
(
$this
->
_fkConstraints
[
$constraintName
]);
}
/**
* Returns whether this table has a
foreign key
constraint with the given name.
* Returns whether this table has a
unique
constraint with the given name.
*
* @param string $constraintName
*
* @return bool
*/
public
function
has
ForeignKey
(
$constraintName
)
public
function
has
UniqueConstraint
(
$constraintName
)
{
$constraintName
=
$this
->
normalizeIdentifier
(
$constraintName
);
return
isset
(
$this
->
_
fk
Constraints
[
$constraintName
]);
return
isset
(
$this
->
_
unique
Constraints
[
$constraintName
]);
}
/**
* Returns the
foreign key
constraint with the given name.
* Returns the
unique
constraint with the given name.
*
* @param string $constraintName The constraint name.
*
* @return
ForeignKey
Constraint
* @return
Unique
Constraint
*
* @throws SchemaException If the foreign key does not exist.
*/
public
function
get
ForeignKey
(
$constraintName
)
public
function
get
UniqueConstraint
(
$constraintName
)
{
$constraintName
=
$this
->
normalizeIdentifier
(
$constraintName
);
if
(
!
$this
->
hasForeignKey
(
$constraintName
))
{
throw
SchemaException
::
foreignKeyDoesNotExist
(
$constraintName
,
$this
->
_name
);
if
(
!
$this
->
hasUniqueConstraint
(
$constraintName
))
{
throw
SchemaException
::
uniqueConstraintDoesNotExist
(
$constraintName
,
$this
->
_name
);
}
return
$this
->
_
fk
Constraints
[
$constraintName
];
return
$this
->
_
unique
Constraints
[
$constraintName
];
}
/**
* Removes the
foreign key
constraint with the given name.
* Removes the
unique
constraint with the given name.
*
* @param string $constraintName The constraint name.
*
...
...
@@ -581,14 +544,15 @@ class Table extends AbstractAsset
*
* @throws SchemaException
*/
public
function
remove
ForeignKey
(
$constraintName
)
public
function
remove
UniqueConstraint
(
$constraintName
)
{
$constraintName
=
$this
->
normalizeIdentifier
(
$constraintName
);
if
(
!
$this
->
hasForeignKey
(
$constraintName
))
{
throw
SchemaException
::
foreignKeyDoesNotExist
(
$constraintName
,
$this
->
_name
);
if
(
!
$this
->
hasUniqueConstraint
(
$constraintName
))
{
throw
SchemaException
::
uniqueConstraintDoesNotExist
(
$constraintName
,
$this
->
_name
);
}
unset
(
$this
->
_
fk
Constraints
[
$constraintName
]);
unset
(
$this
->
_
unique
Constraints
[
$constraintName
]);
}
/**
...
...
@@ -598,27 +562,19 @@ class Table extends AbstractAsset
*/
public
function
getColumns
()
{
$primaryKeyColumns
=
[];
$pkCols
=
[];
$fkCols
=
[];
if
(
$this
->
hasPrimaryKey
())
{
$p
rimaryKeyColumn
s
=
$this
->
filterColumns
(
$this
->
getPrimaryKey
()
->
getColumns
());
$p
kCol
s
=
$this
->
filterColumns
(
$this
->
getPrimaryKey
()
->
getColumns
());
}
return
array_merge
(
$primaryKeyColumns
,
$this
->
getForeignKeyColumns
(),
$this
->
_columns
);
}
/**
* Returns foreign key columns
*
* @return Column[]
*/
private
function
getForeignKeyColumns
()
{
$foreignKeyColumns
=
[];
foreach
(
$this
->
getForeignKeys
()
as
$foreignKey
)
{
/** @var ForeignKeyConstraint $foreignKey */
$foreignKeyColumns
=
array_merge
(
$foreignKeyColumns
,
$foreignKey
->
getColumns
());
foreach
(
$this
->
getForeignKeys
()
as
$fk
)
{
/** @var ForeignKeyConstraint $fk */
$fkCols
=
array_merge
(
$fkCols
,
$fk
->
getColumns
());
}
return
$this
->
filterColumns
(
$foreignKeyColumns
);
return
array_unique
(
array_merge
(
$pkCols
,
$fkCols
,
array_keys
(
$this
->
_columns
)));
}
/**
...
...
@@ -661,6 +617,7 @@ class Table extends AbstractAsset
public
function
getColumn
(
$columnName
)
{
$columnName
=
$this
->
normalizeIdentifier
(
$columnName
);
if
(
!
$this
->
hasColumn
(
$columnName
))
{
throw
SchemaException
::
columnDoesNotExist
(
$columnName
,
$this
->
_name
);
}
...
...
@@ -675,11 +632,9 @@ class Table extends AbstractAsset
*/
public
function
getPrimaryKey
()
{
if
(
!
$this
->
hasPrimaryKey
())
{
return
null
;
}
return
$this
->
getIndex
(
$this
->
_primaryKeyName
);
return
$this
->
hasPrimaryKey
()
?
$this
->
getIndex
(
$this
->
_primaryKeyName
)
:
null
;
}
/**
...
...
@@ -733,6 +688,7 @@ class Table extends AbstractAsset
public
function
getIndex
(
$indexName
)
{
$indexName
=
$this
->
normalizeIdentifier
(
$indexName
);
if
(
!
$this
->
hasIndex
(
$indexName
))
{
throw
SchemaException
::
indexDoesNotExist
(
$indexName
,
$this
->
_name
);
}
...
...
@@ -748,6 +704,16 @@ class Table extends AbstractAsset
return
$this
->
_indexes
;
}
/**
* Returns the unique constraints.
*
* @return UniqueConstraint[]
*/
public
function
getUniqueConstraints
()
{
return
$this
->
_uniqueConstraints
;
}
/**
* Returns the foreign key constraints.
*
...
...
@@ -816,15 +782,166 @@ class Table extends AbstractAsset
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
);
}
}
/**
* @return int
*/
protected
function
_getMaxIdentifierLength
()
{
return
$this
->
_schemaConfig
instanceof
SchemaConfig
?
$this
->
_schemaConfig
->
getMaxIdentifierLength
()
:
63
;
}
/**
* @return void
*
* @throws SchemaException
*/
protected
function
_addColumn
(
Column
$column
)
{
$columnName
=
$column
->
getName
();
$columnName
=
$this
->
normalizeIdentifier
(
$columnName
);
if
(
isset
(
$this
->
_columns
[
$columnName
]))
{
throw
SchemaException
::
columnAlreadyExists
(
$this
->
getName
(),
$columnName
);
}
$this
->
_columns
[
$columnName
]
=
$column
;
}
/**
* Adds an index to the table.
*
* @return self
*
* @throws SchemaException
*/
protected
function
_addIndex
(
Index
$indexCandidate
)
{
$indexName
=
$indexCandidate
->
getName
();
$indexName
=
$this
->
normalizeIdentifier
(
$indexName
);
$replacedImplicitIndexes
=
[];
foreach
(
$this
->
implicitIndexes
as
$name
=>
$implicitIndex
)
{
if
(
!
$implicitIndex
->
isFullfilledBy
(
$indexCandidate
)
||
!
isset
(
$this
->
_indexes
[
$name
]))
{
continue
;
}
$replacedImplicitIndexes
[]
=
$name
;
}
if
((
isset
(
$this
->
_indexes
[
$indexName
])
&&
!
in_array
(
$indexName
,
$replacedImplicitIndexes
,
true
))
||
(
$this
->
_primaryKeyName
!==
false
&&
$indexCandidate
->
isPrimary
())
)
{
throw
SchemaException
::
indexAlreadyExists
(
$indexName
,
$this
->
_name
);
}
foreach
(
$replacedImplicitIndexes
as
$name
)
{
unset
(
$this
->
_indexes
[
$name
],
$this
->
implicitIndexes
[
$name
]);
}
if
(
$indexCandidate
->
isPrimary
())
{
$this
->
_primaryKeyName
=
$indexName
;
}
$this
->
_indexes
[
$indexName
]
=
$indexCandidate
;
return
$this
;
}
/**
* @return self
*/
protected
function
_addUniqueConstraint
(
UniqueConstraint
$uniqueConstraint
)
{
$name
=
strlen
(
$uniqueConstraint
->
getName
())
?
$uniqueConstraint
->
getName
()
:
$this
->
_generateIdentifierName
(
array_merge
((
array
)
$this
->
getName
(),
$uniqueConstraint
->
getLocalColumns
()),
'fk'
,
$this
->
_getMaxIdentifierLength
()
);
$name
=
$this
->
normalizeIdentifier
(
$name
);
$this
->
_uniqueConstraints
[
$name
]
=
$uniqueConstraint
;
// If there is already an index that fulfills 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 computation overhead in this case, however no duplicate indexes are ever added (column based).
$indexName
=
$this
->
_generateIdentifierName
(
array_merge
([
$this
->
getName
()],
$uniqueConstraint
->
getColumns
()),
'idx'
,
$this
->
_getMaxIdentifierLength
()
);
$indexCandidate
=
$this
->
_createIndex
(
$uniqueConstraint
->
getColumns
(),
$indexName
,
true
,
false
);
foreach
(
$this
->
_indexes
as
$existingIndex
)
{
if
(
$indexCandidate
->
isFullfilledBy
(
$existingIndex
))
{
return
$this
;
}
}
$this
->
implicitIndexes
[
$this
->
normalizeIdentifier
(
$indexName
)]
=
$indexCandidate
;
return
$this
;
}
/**
* @return self
*/
protected
function
_addForeignKeyConstraint
(
ForeignKeyConstraint
$constraint
)
{
$constraint
->
setLocalTable
(
$this
);
$name
=
strlen
(
$constraint
->
getName
())
?
$constraint
->
getName
()
:
$this
->
_generateIdentifierName
(
array_merge
((
array
)
$this
->
getName
(),
$constraint
->
getLocalColumns
()),
'fk'
,
$this
->
_getMaxIdentifierLength
()
);
$name
=
$this
->
normalizeIdentifier
(
$name
);
$this
->
_fkConstraints
[
$name
]
=
$constraint
;
// add an explicit index on the foreign key columns.
// If there is already an index that fulfills 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 computation overhead in this case, however no duplicate indexes are ever added (column based).
$indexName
=
$this
->
_generateIdentifierName
(
array_merge
([
$this
->
getName
()],
$constraint
->
getColumns
()),
'idx'
,
$this
->
_getMaxIdentifierLength
()
);
$indexCandidate
=
$this
->
_createIndex
(
$constraint
->
getColumns
(),
$indexName
,
false
,
false
);
foreach
(
$this
->
_indexes
as
$existingIndex
)
{
if
(
$indexCandidate
->
isFullfilledBy
(
$existingIndex
))
{
return
$this
;
}
}
$this
->
_addIndex
(
$indexCandidate
);
$this
->
implicitIndexes
[
$this
->
normalizeIdentifier
(
$indexName
)]
=
$indexCandidate
;
return
$this
;
}
/**
* Normalizes a given identifier.
*
...
...
@@ -838,4 +955,63 @@ class Table extends AbstractAsset
{
return
$this
->
trimQuotes
(
strtolower
(
$identifier
));
}
/**
* @param mixed[] $columnNames
* @param string $indexName
* @param mixed[] $options
*
* @return UniqueConstraint
*
* @throws SchemaException
*/
private
function
_createUniqueConstraint
(
array
$columnNames
,
$indexName
,
array
$options
=
[])
{
if
(
preg_match
(
'(([^a-zA-Z0-9_]+))'
,
$this
->
normalizeIdentifier
(
$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
);
}
}
return
new
UniqueConstraint
(
$indexName
,
$columnNames
,
$options
);
}
/**
* @param mixed[] $columnNames
* @param string $indexName
* @param bool $isUnique
* @param bool $isPrimary
* @param string[] $flags
* @param mixed[] $options
*
* @return Index
*
* @throws SchemaException
*/
private
function
_createIndex
(
array
$columnNames
,
$indexName
,
$isUnique
,
$isPrimary
,
array
$flags
=
[],
array
$options
=
[])
{
if
(
preg_match
(
'(([^a-zA-Z0-9_]+))'
,
$this
->
normalizeIdentifier
(
$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
);
}
}
return
new
Index
(
$indexName
,
$columnNames
,
$isUnique
,
$isPrimary
,
$flags
,
$options
);
}
}
lib/Doctrine/DBAL/Schema/UniqueConstraint.php
0 → 100644
View file @
d4fec7cd
<?php
namespace
Doctrine\DBAL\Schema
;
use
Doctrine\DBAL\Platforms\AbstractPlatform
;
use
InvalidArgumentException
;
use
function
array_keys
;
use
function
array_map
;
use
function
is_string
;
use
function
strtolower
;
/**
* Class for a unique constraint.
*/
class
UniqueConstraint
extends
AbstractAsset
implements
Constraint
{
/**
* Asset identifier instances of the column names the unique constraint is associated with.
* array($columnName => Identifier)
*
* @var Identifier[]
*/
protected
$columns
=
[];
/**
* Platform specific options
*
* @var mixed[]
*/
private
$options
=
[];
/**
* @param string $indexName
* @param string[] $columns
* @param mixed[] $options
*/
public
function
__construct
(
$indexName
,
array
$columns
,
array
$options
=
[])
{
$this
->
_setName
(
$indexName
);
$this
->
options
=
$options
;
foreach
(
$columns
as
$column
)
{
$this
->
_addColumn
(
$column
);
}
}
/**
* @param string $column
*
* @return void
*
* @throws InvalidArgumentException
*/
protected
function
_addColumn
(
$column
)
{
if
(
!
is_string
(
$column
))
{
throw
new
InvalidArgumentException
(
'Expecting a string as Index Column'
);
}
$this
->
_columns
[
$column
]
=
new
Identifier
(
$column
);
}
/**
* {@inheritdoc}
*/
public
function
getColumns
()
{
return
array_keys
(
$this
->
_columns
);
}
/**
* {@inheritdoc}
*/
public
function
getQuotedColumns
(
AbstractPlatform
$platform
)
{
$columns
=
[];
foreach
(
$this
->
_columns
as
$column
)
{
$columns
[]
=
$column
->
getQuotedName
(
$platform
);
}
return
$columns
;
}
/**
* @return string[]
*/
public
function
getUnquotedColumns
()
{
return
array_map
([
$this
,
'trimQuotes'
],
$this
->
getColumns
());
}
/**
* @param string $name
*
* @return bool
*/
public
function
hasOption
(
$name
)
{
return
isset
(
$this
->
options
[
strtolower
(
$name
)]);
}
/**
* @param string $name
*
* @return mixed
*/
public
function
getOption
(
$name
)
{
return
$this
->
options
[
strtolower
(
$name
)];
}
/**
* @return mixed[]
*/
public
function
getOptions
()
{
return
$this
->
options
;
}
}
tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php
View file @
d4fec7cd
...
...
@@ -314,6 +314,7 @@ class ExceptionTest extends DbalFunctionalTestCase
$table
->
addColumn
(
'id'
,
'integer'
);
$this
->
expectException
(
$exceptionClass
);
foreach
(
$schema
->
toSql
(
$conn
->
getDatabasePlatform
())
as
$sql
)
{
$conn
->
exec
(
$sql
);
}
...
...
tests/Doctrine/Tests/DBAL/Functional/Schema/SchemaManagerFunctionalTestCase.php
View file @
d4fec7cd
...
...
@@ -976,7 +976,7 @@ class SchemaManagerFunctionalTestCase extends DbalFunctionalTestCase
protected
function
getTestTable
(
$name
,
$options
=
[])
{
$table
=
new
Table
(
$name
,
[],
[],
[],
false
,
$options
);
$table
=
new
Table
(
$name
,
[],
[],
[],
[],
false
,
$options
);
$table
->
setSchemaConfig
(
$this
->
schemaManager
->
createSchemaConfig
());
$table
->
addColumn
(
'id'
,
'integer'
,
[
'notnull'
=>
true
]);
$table
->
setPrimaryKey
([
'id'
]);
...
...
@@ -987,7 +987,7 @@ class SchemaManagerFunctionalTestCase extends DbalFunctionalTestCase
protected
function
getTestCompositeTable
(
$name
)
{
$table
=
new
Table
(
$name
,
[],
[],
[],
false
,
[]);
$table
=
new
Table
(
$name
,
[],
[],
[],
[],
false
,
[]);
$table
->
setSchemaConfig
(
$this
->
schemaManager
->
createSchemaConfig
());
$table
->
addColumn
(
'id'
,
'integer'
,
[
'notnull'
=>
true
]);
$table
->
addColumn
(
'other_id'
,
'integer'
,
[
'notnull'
=>
true
]);
...
...
@@ -999,14 +999,17 @@ class SchemaManagerFunctionalTestCase extends DbalFunctionalTestCase
protected
function
assertHasTable
(
$tables
,
$tableName
)
{
$foundTable
=
false
;
foreach
(
$tables
as
$table
)
{
self
::
assertInstanceOf
(
Table
::
class
,
$table
,
'No Table instance was found in tables array.'
);
if
(
strtolower
(
$table
->
getName
())
!==
'list_tables_test_new_name'
)
{
continue
;
}
$foundTable
=
true
;
}
self
::
assertTrue
(
$foundTable
,
'Could not find new table'
);
}
...
...
tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php
View file @
d4fec7cd
...
...
@@ -1272,6 +1272,7 @@ class ComparatorTest extends TestCase
'id_table1'
=>
new
Column
(
'id_table1'
,
Type
::
getType
(
'integer'
)),
],
[],
[],
[
new
ForeignKeyConstraint
([
'id_table1'
],
'table1'
,
[
'id'
],
'fk_table2_table1'
),
]
...
...
@@ -1285,6 +1286,7 @@ class ComparatorTest extends TestCase
'id_table3'
=>
new
Column
(
'id_table3'
,
Type
::
getType
(
'integer'
)),
],
[],
[],
[
new
ForeignKeyConstraint
([
'id_table3'
],
'table3'
,
[
'id'
],
'fk_table2_table3'
),
]
...
...
tests/Doctrine/Tests/DBAL/Schema/TableTest.php
View file @
d4fec7cd
...
...
@@ -200,7 +200,7 @@ class TableTest extends DbalTestCase
{
$constraint
=
new
ForeignKeyConstraint
([],
'foo'
,
[]);
$tableA
=
new
Table
(
'foo'
,
[],
[],
[
$constraint
]);
$tableA
=
new
Table
(
'foo'
,
[],
[],
[
],
[
$constraint
]);
$constraints
=
$tableA
->
getForeignKeys
();
self
::
assertCount
(
1
,
$constraints
);
...
...
@@ -209,7 +209,7 @@ class TableTest extends DbalTestCase
public
function
testOptions
()
{
$table
=
new
Table
(
'foo'
,
[],
[],
[],
false
,
[
'foo'
=>
'bar'
]);
$table
=
new
Table
(
'foo'
,
[],
[],
[],
[],
false
,
[
'foo'
=>
'bar'
]);
self
::
assertTrue
(
$table
->
hasOption
(
'foo'
));
self
::
assertEquals
(
'bar'
,
$table
->
getOption
(
'foo'
));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment