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
55d70248
Commit
55d70248
authored
May 21, 2009
by
romanb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[2.0] Implemented class table inheritance (no DQL bulk UPDATE/DELETE support yet)
parent
eb6c6b2d
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
669 additions
and
310 deletions
+669
-310
Connection.php
lib/Doctrine/DBAL/Connection.php
+3
-3
SqlitePlatform.php
lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
+4
-2
Type.php
lib/Doctrine/DBAL/Types/Type.php
+0
-5
ClassMetadata.php
lib/Doctrine/ORM/Mapping/ClassMetadata.php
+21
-43
ClassMetadataFactory.php
lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
+81
-6
JoinedSubclassPersister.php
lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php
+134
-141
SingleTablePersister.php
lib/Doctrine/ORM/Persisters/SingleTablePersister.php
+2
-1
StandardEntityPersister.php
lib/Doctrine/ORM/Persisters/StandardEntityPersister.php
+41
-36
SqlWalker.php
lib/Doctrine/ORM/Query/SqlWalker.php
+100
-25
SchemaTool.php
lib/Doctrine/ORM/Tools/SchemaTool.php
+71
-23
CompanyEmployee.php
tests/Doctrine/Tests/Models/Company/CompanyEmployee.php
+22
-17
CompanyManager.php
tests/Doctrine/Tests/Models/Company/CompanyManager.php
+13
-3
CompanyPerson.php
tests/Doctrine/Tests/Models/Company/CompanyPerson.php
+62
-0
AllTests.php
tests/Doctrine/Tests/ORM/Functional/AllTests.php
+1
-0
ClassTableInheritanceTest.php
...ctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php
+92
-0
OrmFunctionalTestCase.php
tests/Doctrine/Tests/OrmFunctionalTestCase.php
+22
-5
No files found.
lib/Doctrine/DBAL/Connection.php
View file @
55d70248
...
...
@@ -515,7 +515,7 @@ class Connection
{
$this
->
connect
();
try
{
//
echo "DBAL:" . $query . PHP_EOL;
echo
"DBAL:"
.
$query
.
PHP_EOL
;
if
(
!
empty
(
$params
))
{
$stmt
=
$this
->
prepare
(
$query
);
$stmt
->
execute
(
$params
);
...
...
@@ -542,9 +542,9 @@ class Connection
public
function
exec
(
$query
,
array
$params
=
array
())
{
$this
->
connect
();
try
{
//echo
$query . PHP_EOL;
echo
"DBAL:"
.
$query
.
PHP_EOL
;
if
(
!
empty
(
$params
))
{
//
var_dump($params);
var_dump
(
$params
);
$stmt
=
$this
->
prepare
(
$query
);
$stmt
->
execute
(
$params
);
return
$stmt
->
rowCount
();
...
...
lib/Doctrine/DBAL/Platforms/SqlitePlatform.php
View file @
55d70248
...
...
@@ -21,6 +21,8 @@
namespace
Doctrine\DBAL\Platforms
;
use
Doctrine\Common\DoctrineException
;
/**
* The SqlitePlatform class describes the specifics and dialects of the SQLite
* database platform.
...
...
@@ -492,11 +494,11 @@ class SqlitePlatform extends AbstractPlatform
public
function
getCreateTableSql
(
$name
,
array
$fields
,
array
$options
=
array
())
{
if
(
!
$name
)
{
throw
Connection
Exception
::
invalidTableName
(
$name
);
throw
Doctrine
Exception
::
invalidTableName
(
$name
);
}
if
(
empty
(
$fields
))
{
throw
Connection
Exception
::
noFieldsSpecifiedForTable
(
$name
);
throw
Doctrine
Exception
::
noFieldsSpecifiedForTable
(
$name
);
}
$queryFields
=
$this
->
getColumnDeclarationListSql
(
$fields
);
...
...
lib/Doctrine/DBAL/Types/Type.php
View file @
55d70248
...
...
@@ -50,11 +50,6 @@ abstract class Type
*/
public
static
function
getType
(
$name
)
{
if
(
is_object
(
$name
))
{
try
{
throw
new
\Exception
();
}
catch
(
\Exception
$e
)
{
echo
$e
->
getTraceAsString
();
}
die
();
}
if
(
!
isset
(
self
::
$_typeObjects
[
$name
]))
{
if
(
!
isset
(
self
::
$_typesMap
[
$name
]))
{
throw
DoctrineException
::
updateMe
(
"Unknown type:
$name
"
);
...
...
lib/Doctrine/ORM/Mapping/ClassMetadata.php
View file @
55d70248
...
...
@@ -297,7 +297,7 @@ final class ClassMetadata
*
* name => <tableName>
* schema => <schemaName>
* catalog => <catalogName>
* catalog => <catalogName>
//TODO: remove catalog? needed?
*
* @var array
*/
...
...
@@ -397,6 +397,15 @@ final class ClassMetadata
*/
public
$insertSql
;
/**
* A map of field names to class names, where the field names are association
* fields that have been inherited from another class and values are the names
* of the classes that define the association.
*
* @var array
*/
public
$inheritedAssociationFields
=
array
();
/**
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
...
...
@@ -1362,10 +1371,18 @@ final class ClassMetadata
* This is mainly used to add inherited association mappings to derived classes.
*
* @param AssociationMapping $mapping
* @param string $owningClassName The name of the class that defined this mapping.
* @todo Rename: addInheritedAssociationMapping
*/
public
function
addAssociationMapping
(
AssociationMapping
$mapping
)
public
function
addAssociationMapping
(
AssociationMapping
$mapping
,
$owningClassName
)
{
$this
->
_storeAssociationMapping
(
$mapping
);
$sourceFieldName
=
$mapping
->
sourceFieldName
;
if
(
isset
(
$this
->
associationMappings
[
$sourceFieldName
]))
{
throw
MappingException
::
duplicateFieldMapping
();
}
$this
->
associationMappings
[
$sourceFieldName
]
=
$mapping
;
$this
->
inheritedAssociationFields
[
$sourceFieldName
]
=
$owningClassName
;
$this
->
_registerMappingIfInverse
(
$mapping
);
}
/**
...
...
@@ -1374,6 +1391,7 @@ final class ClassMetadata
* This is mainly used to add inherited field mappings to derived classes.
*
* @param array $mapping
* @todo Rename: addInheritedFieldMapping
*/
public
function
addFieldMapping
(
array
$fieldMapping
)
{
...
...
@@ -1761,46 +1779,6 @@ final class ClassMetadata
$this
->
sequenceGeneratorDefinition
=
$definition
;
}
/**
* INTERNAL: Called by ClassMetadataFactory.
*
* Tells this class descriptor to finish the mapping definition, making any
* final adjustments, i.e. generating some SQL strings.
*/
public
function
finishMapping
()
{
$columns
=
$values
=
array
();
if
(
$this
->
inheritanceType
==
self
::
INHERITANCE_TYPE_JOINED
)
{
//TODO
}
else
{
foreach
(
$this
->
reflFields
as
$name
=>
$field
)
{
if
(
isset
(
$this
->
associationMappings
[
$name
]))
{
$assoc
=
$this
->
associationMappings
[
$name
];
if
(
$assoc
->
isOwningSide
&&
$assoc
->
isOneToOne
())
{
foreach
(
$assoc
->
targetToSourceKeyColumns
as
$sourceCol
)
{
$columns
[]
=
$sourceCol
;
$values
[]
=
'?'
;
}
}
}
else
if
(
$this
->
generatorType
!=
self
::
GENERATOR_TYPE_IDENTITY
||
$this
->
identifier
[
0
]
!=
$name
)
{
$columns
[]
=
$this
->
columnNames
[
$name
];
$values
[]
=
'?'
;
}
}
}
if
(
$this
->
discriminatorColumn
)
{
$columns
[]
=
$this
->
discriminatorColumn
[
'name'
];
$values
[]
=
'?'
;
}
$this
->
insertSql
=
'INSERT INTO '
.
$this
->
primaryTable
[
'name'
]
.
' ('
.
implode
(
', '
,
$columns
)
.
') '
.
'VALUES ('
.
implode
(
', '
,
$values
)
.
')'
;
}
/**
* Creates a string representation of this instance.
*
...
...
lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
View file @
55d70248
...
...
@@ -34,6 +34,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
* @version $Revision$
* @link www.doctrine-project.org
* @since 2.0
* @todo Support for mapped superclasses (@DoctrineMappedSuperclass)
*/
class
ClassMetadataFactory
{
...
...
@@ -43,6 +44,7 @@ class ClassMetadataFactory
private
$_driver
;
/** The used cache driver. */
private
$_cacheDriver
;
private
$_loadedMetadata
=
array
();
/**
* Creates a new factory instance that uses the given metadata driver implementation.
...
...
@@ -100,9 +102,11 @@ class ClassMetadataFactory
}
/**
* Sets the metadata descriptor for a specific class.
* This is only useful in very special cases, like when generating proxy classes.
*
* @param
<type>
$className
* @param
<type> $class
* @param
string
$className
* @param
ClassMetadata $class
*/
public
function
setMetadataFor
(
$className
,
$class
)
{
...
...
@@ -113,7 +117,7 @@ class ClassMetadataFactory
* Loads the metadata of the class in question and all it's ancestors whose metadata
* is still not loaded.
*
* @param string $name
The name of the class for which the metadata should get loaded.
* @param string $name The name of the class for which the metadata should get loaded.
* @param array $tables The metadata collection to which the loaded metadata is added.
*/
protected
function
_loadMetadata
(
$name
)
...
...
@@ -133,6 +137,12 @@ class ClassMetadataFactory
$parent
=
null
;
$visited
=
array
();
foreach
(
$parentClasses
as
$className
)
{
if
(
isset
(
$this
->
_loadedMetadata
[
$className
]))
{
$parent
=
$this
->
_loadedMetadata
[
$className
];
array_unshift
(
$visited
,
$className
);
continue
;
}
$class
=
$this
->
_newClassMetadataInstance
(
$className
);
if
(
$parent
)
{
$class
->
setInheritanceType
(
$parent
->
inheritanceType
);
...
...
@@ -167,7 +177,8 @@ class ClassMetadataFactory
}
$class
->
setParentClasses
(
$visited
);
$class
->
finishMapping
();
$this
->
_generateStaticSql
(
$class
);
$this
->
_loadedMetadata
[
$className
]
=
$class
;
...
...
@@ -200,7 +211,9 @@ class ClassMetadataFactory
$mapping
[
'inherited'
]
=
$parentClass
->
name
;
}
$subClass
->
addFieldMapping
(
$mapping
);
$subClass
->
addReflectionProperty
(
$fieldName
,
$parentClass
->
getReflectionProperty
(
$fieldName
));
}
foreach
(
$parentClass
->
reflFields
as
$name
=>
$field
)
{
$subClass
->
reflFields
[
$name
]
=
$field
;
}
}
...
...
@@ -213,8 +226,70 @@ class ClassMetadataFactory
private
function
_addInheritedRelations
(
ClassMetadata
$subClass
,
ClassMetadata
$parentClass
)
{
foreach
(
$parentClass
->
associationMappings
as
$mapping
)
{
$subClass
->
addAssociationMapping
(
$mapping
);
if
(
isset
(
$parentClass
->
inheritedAssociationFields
[
$mapping
->
sourceFieldName
]))
{
// parent class also inherited that one
$subClass
->
addAssociationMapping
(
$mapping
,
$parentClass
->
inheritedAssociationFields
[
$mapping
->
sourceFieldName
]);
}
else
{
// parent class defined that one
$subClass
->
addAssociationMapping
(
$mapping
,
$parentClass
->
name
);
}
}
}
/**
* Generates any static SQL strings for a class and stores them in the descriptor.
*
* @param ClassMetadata $class
*/
private
function
_generateStaticSql
(
$class
)
{
// Generate INSERT SQL
$columns
=
$values
=
array
();
if
(
$class
->
inheritanceType
==
ClassMetadata
::
INHERITANCE_TYPE_JOINED
)
{
foreach
(
$class
->
reflFields
as
$name
=>
$field
)
{
if
(
isset
(
$class
->
fieldMappings
[
$name
][
'inherited'
])
&&
!
isset
(
$class
->
fieldMappings
[
$name
][
'id'
])
||
isset
(
$class
->
inheritedAssociationFields
[
$name
]))
{
continue
;
}
if
(
isset
(
$class
->
associationMappings
[
$name
]))
{
$assoc
=
$class
->
associationMappings
[
$name
];
if
(
$assoc
->
isOneToOne
()
&&
$assoc
->
isOwningSide
)
{
foreach
(
$assoc
->
targetToSourceKeyColumns
as
$sourceCol
)
{
$columns
[]
=
$this
->
_targetPlatform
->
quoteIdentifier
(
$sourceCol
);
$values
[]
=
'?'
;
}
}
}
else
if
(
$class
->
name
!=
$class
->
rootEntityName
||
!
$class
->
isIdGeneratorIdentity
()
||
$class
->
identifier
[
0
]
!=
$name
)
{
$columns
[]
=
$this
->
_targetPlatform
->
quoteIdentifier
(
$class
->
columnNames
[
$name
]);
$values
[]
=
'?'
;
}
}
}
else
{
foreach
(
$class
->
reflFields
as
$name
=>
$field
)
{
if
(
isset
(
$class
->
associationMappings
[
$name
]))
{
$assoc
=
$class
->
associationMappings
[
$name
];
if
(
$assoc
->
isOwningSide
&&
$assoc
->
isOneToOne
())
{
foreach
(
$assoc
->
targetToSourceKeyColumns
as
$sourceCol
)
{
$columns
[]
=
$this
->
_targetPlatform
->
quoteIdentifier
(
$sourceCol
);
$values
[]
=
'?'
;
}
}
}
else
if
(
$class
->
generatorType
!=
ClassMetadata
::
GENERATOR_TYPE_IDENTITY
||
$class
->
identifier
[
0
]
!=
$name
)
{
$columns
[]
=
$this
->
_targetPlatform
->
quoteIdentifier
(
$class
->
columnNames
[
$name
]);
$values
[]
=
'?'
;
}
}
}
if
(
$class
->
isInheritanceTypeSingleTable
()
||
$class
->
isInheritanceTypeJoined
()
&&
$class
->
name
==
$class
->
rootEntityName
)
{
$columns
[]
=
$class
->
discriminatorColumn
[
'name'
];
$values
[]
=
'?'
;
}
$class
->
insertSql
=
'INSERT INTO '
.
$this
->
_targetPlatform
->
quoteIdentifier
(
$class
->
primaryTable
[
'name'
])
.
' ('
.
implode
(
', '
,
$columns
)
.
') '
.
'VALUES ('
.
implode
(
', '
,
$values
)
.
')'
;
}
/**
...
...
lib/Doctrine/ORM/Persisters/JoinedSubclassPersister.php
View file @
55d70248
...
...
@@ -34,129 +34,169 @@ use Doctrine\Common\DoctrineException;
* @since 2.0
* @todo Reimplement.
*/
class
JoinedSubclassPersister
extends
AbstractEntityPersister
{
class
JoinedSubclassPersister
extends
StandardEntityPersister
{
/** Map that maps column names to the table names that own them.
* This is mainly a temporary cache, used during a single request.
*/
private
$_owningTableMap
=
array
();
/**
*
Inserts an entity that is part of a Class Table Inheritance hierarchy.
*
{@inheritdoc}
*
* @param object $record record to be inserted
* @return boolean
* @override
*/
/*public function insert($entity
)
protected
function
_prepareData
(
$entity
,
array
&
$result
,
$isInsert
=
false
)
{
$class = $entity->getClass();
$dataSet = array();
$this->_prepareData($entity, $dataSet, true);
$dataSet = $this->_groupFieldsByDefiningClass($class, $dataSet);
$component = $class->name;
$classes = $class->parentClasses;
array_unshift($classes, $component);
$identifier = null;
foreach (array_reverse($classes) as $k => $parent) {
$parentClass = $this->_em->getClassMetadata($parent);
if ($k == 0) {
if ($parentClass->isIdGeneratorIdentity()) {
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
$identifier = $this->_conn->lastInsertId();
} else if ($parentClass->isIdGeneratorSequence()) {
$seq = $entity->getClassMetadata()->getTableOption('sequenceName');
if ( ! empty($seq)) {
$id = $this->_conn->getSequenceManager()->nextId($seq);
$identifierFields = $parentClass->identifier;
$dataSet[$parent][$identifierFields[0]] = $id;
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
}
parent
::
_prepareData
(
$entity
,
$result
,
$isInsert
);
// Populate the discriminator column
if
(
$isInsert
)
{
$discColumn
=
$this
->
_class
->
discriminatorColumn
;
$rootClass
=
$this
->
_em
->
getClassMetadata
(
$this
->
_class
->
rootEntityName
);
$result
[
$rootClass
->
primaryTable
[
'name'
]][
$discColumn
[
'name'
]]
=
$this
->
_class
->
discriminatorValue
;
}
}
/**
* {@inheritdoc}
*
* @override
*/
public
function
getOwningTable
(
$fieldName
)
{
if
(
!
isset
(
$this
->
_owningTableMap
[
$fieldName
]))
{
if
(
isset
(
$this
->
_class
->
associationMappings
[
$fieldName
]))
{
if
(
isset
(
$this
->
_class
->
inheritedAssociationFields
[
$fieldName
]))
{
$this
->
_owningTableMap
[
$fieldName
]
=
$this
->
_em
->
getClassMetadata
(
$this
->
_class
->
inheritedAssociationFields
[
$fieldName
])
->
primaryTable
[
'name'
];
}
else
{
throw DoctrineException::updateMe("Unsupported identifier type '$identifierType'.")
;
$this
->
_owningTableMap
[
$fieldName
]
=
$this
->
_class
->
primaryTable
[
'name'
]
;
}
$entity->_assignIdentifier($identifier);
}
else
if
(
isset
(
$this
->
_class
->
fieldMappings
[
$fieldName
][
'inherited'
]))
{
$this
->
_owningTableMap
[
$fieldName
]
=
$this
->
_em
->
getClassMetadata
(
$this
->
_class
->
fieldMappings
[
$fieldName
][
'inherited'
])
->
primaryTable
[
'name'
];
}
else
{
foreach ($entity->_identifier() as $id => $value) {
$dataSet[$parent][$parentClass->getColumnName($id)] = $value;
}
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
$this
->
_owningTableMap
[
$fieldName
]
=
$this
->
_class
->
primaryTable
[
'name'
];
}
}
return
$this
->
_owningTableMap
[
$fieldName
];
}
return true;
}*/
/**
*
Updates an entity that is part of a Class Table Inheritance hierarchy.
*
{@inheritdoc}
*
* @param Doctrine_Entity $record record to be updated
* @return boolean whether or not the update was successful
* @override
*/
/*protected function _doUpdate($entity
)
public
function
executeInserts
(
)
{
$conn = $this->_conn;
$classMetadata = $this->_classMetadata;
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $classMetadata);
$dataSet = $this->_groupFieldsByDefiningClass($record);
$component = $classMetadata->name;
$classes = $classMetadata->parentClasses;
array_unshift($classes, $component);
if
(
!
$this
->
_queuedInserts
)
{
return
;
}
$postInsertIds
=
array
();
$idGen
=
$this
->
_class
->
idGenerator
;
$isPostInsertId
=
$idGen
->
isPostInsertGenerator
();
// Prepare statements for all tables
$stmts
=
$classes
=
array
();
$stmts
[
$this
->
_class
->
primaryTable
[
'name'
]]
=
$this
->
_conn
->
prepare
(
$this
->
_class
->
insertSql
);
$classes
[
$this
->
_class
->
name
]
=
$this
->
_class
;
foreach
(
$this
->
_class
->
parentClasses
as
$parentClass
)
{
$classes
[
$parentClass
]
=
$this
->
_em
->
getClassMetadata
(
$parentClass
);
$stmts
[
$classes
[
$parentClass
]
->
primaryTable
[
'name'
]]
=
$this
->
_conn
->
prepare
(
$classes
[
$parentClass
]
->
insertSql
);
}
$rootTableName
=
$classes
[
$this
->
_class
->
rootEntityName
]
->
primaryTable
[
'name'
];
foreach
(
$this
->
_queuedInserts
as
$entity
)
{
$insertData
=
array
();
$this
->
_prepareData
(
$entity
,
$insertData
,
true
);
// Execute insert on root table
$paramIndex
=
1
;
$stmt
=
$stmts
[
$rootTableName
];
foreach
(
$insertData
[
$rootTableName
]
as
$columnName
=>
$value
)
{
$stmt
->
bindValue
(
$paramIndex
++
,
$value
/*, TODO: TYPE*/
);
}
$stmt
->
execute
();
unset
(
$insertData
[
$rootTableName
]);
if
(
$isPostInsertId
)
{
$id
=
$idGen
->
generate
(
$this
->
_em
,
$entity
);
$postInsertIds
[
$id
]
=
$entity
;
}
else
{
$id
=
$this
->
_em
->
getUnitOfWork
()
->
getEntityIdentifier
(
$entity
);
}
foreach ($record as $field => $value) {
if ($value instanceof Doctrine_ORM_Entity) {
if ( ! $value->exists()) {
$value->save();
// Execute inserts on subtables
foreach
(
$insertData
as
$tableName
=>
$data
)
{
$stmt
=
$stmts
[
$tableName
];
$paramIndex
=
1
;
foreach
((
array
)
$id
as
$idVal
)
{
$stmt
->
bindValue
(
$paramIndex
++
,
$idVal
/*, TODO: TYPE*/
);
}
foreach
(
$data
as
$columnName
=>
$value
)
{
$stmt
->
bindValue
(
$paramIndex
++
,
$value
/*, TODO: TYPE*/
);
}
$idValues = $value->identifier();
$record->set($field, $idValues[0]);
$stmt
->
execute
();
}
}
foreach (array_reverse($classes) as $class) {
$parentTable = $conn->getClassMetadata($class);
$this->_updateRow($parentTable->getTableName(), $dataSet[$class], $identifier);
foreach
(
$stmts
as
$stmt
)
$stmt
->
closeCursor
();
$this
->
_queuedInserts
=
array
();
return
$postInsertIds
;
}
/**
* Updates an entity.
*
* @param object $entity The entity to update.
* @override
*/
public
function
update
(
$entity
)
{
$updateData
=
array
();
$this
->
_prepareData
(
$entity
,
$updateData
);
$id
=
array_combine
(
$this
->
_class
->
getIdentifierFieldNames
(),
$this
->
_em
->
getUnitOfWork
()
->
getEntityIdentifier
(
$entity
)
);
foreach
(
$updateData
as
$tableName
=>
$data
)
{
$this
->
_conn
->
update
(
$tableName
,
$updateData
[
$tableName
],
$id
);
}
$record->assignIdentifier(true);
}
return true;
}*/
/**
* Deletes an entity
that is part of a Class Table Inheritance hierarchy
.
* Deletes an entity.
*
* @param object $entity The entity to delete.
* @override
*/
/*protected function _doDelete(Doctrine_ORM_Entity $record
)
public
function
delete
(
$entity
)
{
$conn = $this->_conn;
try {
$class = $this->_classMetadata;
$conn->beginInternalTransaction();
$this->_deleteComposites($record);
$record->_state(Doctrine_ORM_Entity::STATE_TDIRTY);
$id
=
array_combine
(
$this
->
_class
->
getIdentifierFieldNames
(),
$this
->
_em
->
getUnitOfWork
()
->
getEntityIdentifier
(
$entity
)
);
$identifier = $this->_convertFieldToColumnNames($record->identifier(), $class);
// run deletions, starting from the class, upwards the hierarchy
$conn->delete($class->getTableName(), $identifier);
foreach ($class->parentClasses as $parent) {
$parentClass = $conn->getClassMetadata($parent);
$this->_deleteRow($parentClass->getTableName(), $identifier);
// If the database platform supports FKs, just
// delete the row from the root table. Cascades do the rest.
if
(
$this
->
_conn
->
getDatabasePlatform
()
->
supportsForeignKeyConstraints
())
{
$this
->
_conn
->
delete
(
$this
->
_em
->
getClassMetadata
(
$this
->
_class
->
rootEntityName
)
->
primaryTable
[
'name'
],
$id
);
}
else
{
// Delete the parent tables, starting from this class' table up to the root table
$this
->
_conn
->
delete
(
$this
->
_class
->
primaryTable
[
'name'
],
$id
);
foreach
(
$this
->
_class
->
parentClasses
as
$parentClass
)
{
$this
->
_conn
->
delete
(
$this
->
_em
->
getClassMetadata
(
$parentClass
)
->
primaryTable
[
'name'
],
$id
);
}
$record->_state(Doctrine_ORM_Entity::STATE_TCLEAN);
$this->removeRecord($record); // @todo should be done in the unitofwork
$conn->commit();
} catch (Exception $e) {
$conn->rollback();
throw $e;
}
return true;
}*/
}
/**
* Adds all parent classes as INNER JOINs and subclasses as OUTER JOINs
...
...
@@ -205,21 +245,6 @@ class JoinedSubclassPersister extends AbstractEntityPersister
return array_unique($fields);
}*/
/**
*
*/
/*public function getFieldNames()
{
if ($this->_fieldNames) {
return $this->_fieldNames;
}
$fieldNames = $this->_classMetadata->fieldNames;
$this->_fieldNames = array_unique($fieldNames);
return $fieldNames;
}*/
/**
*
* @todo Looks like this better belongs into the ClassMetadata class.
...
...
@@ -248,36 +273,4 @@ class JoinedSubclassPersister extends AbstractEntityPersister
throw \Doctrine\Common\DoctrineException::updateMe("Unable to find defining class of field '$fieldName'.");
}*/
/**
* Analyzes the fields of the entity and creates a map in which the field names
* are grouped by the class names they belong to.
*
* @return array
*/
/*protected function _groupFieldsByDefiningClass(Doctrine_ClassMetadata $class, array $fields)
{
$dataSet = array();
$component = $class->name;
$classes = array_merge(array($component), $class->parentClasses);
foreach ($classes as $class) {
$dataSet[$class] = array();
$parentClassMetadata = $this->_em->getClassMetadata($class);
foreach ($parentClassMetadata->fieldMappings as $fieldName => $mapping) {
if ((isset($mapping['id']) && $mapping['id'] === true) ||
(isset($mapping['inherited']) && $mapping['inherited'] === true)) {
continue;
}
if ( ! array_key_exists($fieldName, $fields)) {
continue;
}
$columnName = $parentClassMetadata->getColumnName($fieldName);
$dataSet[$class][$columnName] = $fields[$fieldName];
}
}
return $dataSet;
}*/
}
\ No newline at end of file
lib/Doctrine/ORM/Persisters/SingleTablePersister.php
View file @
55d70248
...
...
@@ -40,7 +40,8 @@ class SingleTablePersister extends StandardEntityPersister
// Populate the discriminator column
if
(
$isInsert
)
{
$discColumn
=
$this
->
_class
->
discriminatorColumn
;
$result
[
$discColumn
[
'name'
]]
=
$this
->
_class
->
discriminatorValue
;
$result
[
$this
->
_class
->
primaryTable
[
'name'
]][
$discColumn
[
'name'
]]
=
$this
->
_class
->
discriminatorValue
;
}
}
}
\ No newline at end of file
lib/Doctrine/ORM/Persisters/StandardEntityPersister.php
View file @
55d70248
...
...
@@ -84,29 +84,6 @@ class StandardEntityPersister
$this
->
_conn
=
$em
->
getConnection
();
$this
->
_class
=
$class
;
}
/**
* Inserts an entity.
*
* @param object $entity The entity to insert.
* @return mixed If the entity uses a post-insert ID generator, the generated
* ID is returned, NULL otherwise.
*/
public
function
insert
(
$entity
)
{
$insertData
=
array
();
$this
->
_prepareData
(
$entity
,
$insertData
,
true
);
$stmt
=
$this
->
_conn
->
prepare
(
$this
->
_class
->
insertSql
);
$stmt
->
execute
(
array_values
(
$insertData
));
$stmt
->
closeCursor
();
$idGen
=
$this
->
_class
->
getIdGenerator
();
if
(
$idGen
->
isPostInsertGenerator
())
{
return
$idGen
->
generate
(
$this
->
_em
,
$entity
);
}
return
null
;
}
/**
* Adds an entity to the queued inserts.
...
...
@@ -120,6 +97,8 @@ class StandardEntityPersister
/**
* Executes all queued inserts.
*
* @return array An array of any generated post-insert IDs.
*/
public
function
executeInserts
()
{
...
...
@@ -128,14 +107,21 @@ class StandardEntityPersister
}
$postInsertIds
=
array
();
$idGen
=
$this
->
_class
->
getIdGenerator
()
;
$idGen
=
$this
->
_class
->
idGenerator
;
$isPostInsertId
=
$idGen
->
isPostInsertGenerator
();
$stmt
=
$this
->
_conn
->
prepare
(
$this
->
_class
->
insertSql
);
$primaryTableName
=
$this
->
_class
->
primaryTable
[
'name'
];
foreach
(
$this
->
_queuedInserts
as
$entity
)
{
$insertData
=
array
();
$this
->
_prepareData
(
$entity
,
$insertData
,
true
);
$stmt
->
execute
(
array_values
(
$insertData
));
$paramIndex
=
1
;
foreach
(
$insertData
[
$primaryTableName
]
as
$value
)
{
$stmt
->
bindValue
(
$paramIndex
++
,
$value
/*, TODO: TYPE */
);
}
$stmt
->
execute
();
if
(
$isPostInsertId
)
{
$postInsertIds
[
$idGen
->
generate
(
$this
->
_em
,
$entity
)]
=
$entity
;
}
...
...
@@ -157,7 +143,8 @@ class StandardEntityPersister
$this
->
_prepareData
(
$entity
,
$updateData
);
$id
=
array_combine
(
$this
->
_class
->
getIdentifierFieldNames
(),
$this
->
_em
->
getUnitOfWork
()
->
getEntityIdentifier
(
$entity
));
$this
->
_conn
->
update
(
$this
->
_class
->
getTableName
(),
$updateData
,
$id
);
$tableName
=
$this
->
_class
->
primaryTable
[
'name'
];
$this
->
_conn
->
update
(
$tableName
,
$updateData
[
$tableName
],
$id
);
}
/**
...
...
@@ -171,7 +158,7 @@ class StandardEntityPersister
$this
->
_class
->
getIdentifierFieldNames
(),
$this
->
_em
->
getUnitOfWork
()
->
getEntityIdentifier
(
$entity
)
);
$this
->
_conn
->
delete
(
$this
->
_class
->
getTableName
()
,
$id
);
$this
->
_conn
->
delete
(
$this
->
_class
->
primaryTable
[
'name'
]
,
$id
);
}
/**
...
...
@@ -229,7 +216,9 @@ class StandardEntityPersister
}
/**
* Prepares the data of an entity for an insert/update operation.
* Prepares the data changeset of an entity for database insertion.
* The array that is passed as the second parameter is filled with
* <columnName> => <value> pairs during this preparation.
*
* @param object $entity
* @param array $result The reference to the data array.
...
...
@@ -237,6 +226,7 @@ class StandardEntityPersister
*/
protected
function
_prepareData
(
$entity
,
array
&
$result
,
$isInsert
=
false
)
{
$platform
=
$this
->
_conn
->
getDatabasePlatform
();
foreach
(
$this
->
_em
->
getUnitOfWork
()
->
getEntityChangeSet
(
$entity
)
as
$field
=>
$change
)
{
$oldVal
=
$change
[
0
];
$newVal
=
$change
[
1
];
...
...
@@ -245,27 +235,41 @@ class StandardEntityPersister
if
(
isset
(
$this
->
_class
->
associationMappings
[
$field
]))
{
$assocMapping
=
$this
->
_class
->
associationMappings
[
$field
];
// Only owning side of 1-1 associations can have a FK column.
if
(
!
$assocMapping
->
isOneToOne
()
||
$assocMapping
->
isInverseSide
())
{
continue
;
}
foreach
(
$assocMapping
->
sourceToTargetKeyColumns
as
$sourceColumn
=>
$targetColumn
)
{
$otherClass
=
$this
->
_em
->
getClassMetadata
(
$assocMapping
->
targetEntityName
);
if
(
$newVal
===
null
)
{
$result
[
$sourceColumn
]
=
null
;
$result
[
$
this
->
getOwningTable
(
$field
)][
$
sourceColumn
]
=
null
;
}
else
{
$result
[
$sourceColumn
]
=
$otherClass
->
getReflectionProperty
(
$otherClass
->
getFieldName
(
$targetColumn
))
->
getValue
(
$newVal
);
$result
[
$this
->
getOwningTable
(
$field
)][
$sourceColumn
]
=
$otherClass
->
reflFields
[
$otherClass
->
fieldNames
[
$targetColumn
]]
->
getValue
(
$newVal
);
}
}
}
else
if
(
$newVal
===
null
)
{
$result
[
$columnName
]
=
null
;
$result
[
$
this
->
getOwningTable
(
$field
)][
$
columnName
]
=
null
;
}
else
{
$result
[
$columnName
]
=
Type
::
getType
(
$this
->
_class
->
getTypeOfField
(
$field
))
->
convertToDatabaseValue
(
$newVal
,
$this
->
_conn
->
getDatabasePlatform
());
$result
[
$this
->
getOwningTable
(
$field
)][
$columnName
]
=
Type
::
getType
(
$this
->
_class
->
fieldMappings
[
$field
][
'type'
])
->
convertToDatabaseValue
(
$newVal
,
$platform
);
}
}
}
/**
* Gets the name of the table that owns the column the given field is mapped to.
*
* @param string $fieldName
* @return string
*/
public
function
getOwningTable
(
$fieldName
)
{
return
$this
->
_class
->
primaryTable
[
'name'
];
}
/**
* Loads an entity by a list of field criteria.
*
...
...
@@ -292,7 +296,7 @@ class StandardEntityPersister
$this
->
_class
->
reflFields
[
$field
]
->
setValue
(
$entity
,
$value
);
}
$id
=
array
();
if
(
$this
->
_class
->
isIdentifierComposite
()
)
{
if
(
$this
->
_class
->
isIdentifierComposite
)
{
foreach
(
$this
->
_class
->
identifier
as
$fieldName
)
{
$id
[]
=
$data
[
$fieldName
];
}
...
...
@@ -329,7 +333,8 @@ class StandardEntityPersister
* Gets the SELECT SQL to select a single entity by a set of field criteria.
*
* @param array $criteria
* @return string
* @return string The SQL.
* @todo Quote identifier.
*/
protected
function
_getSelectSingleEntitySql
(
array
$criteria
)
{
...
...
lib/Doctrine/ORM/Query/SqlWalker.php
View file @
55d70248
...
...
@@ -31,7 +31,7 @@ use Doctrine\Common\DoctrineException;
* node. Therefore it is possible to only generate SQL parts by simply walking over
* certain subtrees of the AST.
*
* @author
robo
* @author
Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
class
SqlWalker
...
...
@@ -130,8 +130,9 @@ class SqlWalker
}
//if ($this->_query->getHydrationMode() == \Doctrine\ORM\Query::HYDRATE_OBJECT) {
if
(
$class
->
isInheritanceTypeSingleTable
()
||
$class
->
isInheritanceTypeJoined
())
{
$tblAlias
=
$this
->
getSqlTableAlias
(
$class
->
getTableName
()
.
$dqlAlias
);
$discrColumn
=
$class
->
discriminatorColumn
;
$rootClass
=
$this
->
_em
->
getClassMetadata
(
$class
->
rootEntityName
);
$tblAlias
=
$this
->
getSqlTableAlias
(
$rootClass
->
getTableName
()
.
$dqlAlias
);
$discrColumn
=
$rootClass
->
discriminatorColumn
;
$columnAlias
=
$this
->
getSqlColumnAlias
(
$discrColumn
[
'name'
]);
$sql
.=
",
$tblAlias
."
.
$discrColumn
[
'name'
]
.
' AS '
.
$columnAlias
;
$this
->
_resultSetMapping
->
setDiscriminatorColumn
(
$class
->
name
,
$dqlAlias
,
$columnAlias
);
...
...
@@ -156,9 +157,13 @@ class SqlWalker
$dqlAlias
=
$rangeDecl
->
getAliasIdentificationVariable
();
$this
->
_currentRootAlias
=
$dqlAlias
;
$class
=
$rangeDecl
->
getClassMetadata
();
$sql
.=
$rangeDecl
->
getClassMetadata
()
->
getTableName
()
.
' '
.
$this
->
getSqlTableAlias
(
$rangeDecl
->
getClassMetadata
()
->
getTableName
()
.
$dqlAlias
);
$sql
.=
$class
->
getTableName
()
.
' '
.
$this
->
getSqlTableAlias
(
$class
->
getTableName
()
.
$dqlAlias
);
if
(
$class
->
isInheritanceTypeJoined
())
{
$sql
.=
$this
->
_generateClassTableInheritanceJoins
(
$class
,
$dqlAlias
);
}
foreach
(
$firstIdentificationVarDecl
->
getJoinVariableDeclarations
()
as
$joinVarDecl
)
{
$sql
.=
$this
->
walkJoinVariableDeclaration
(
$joinVarDecl
);
...
...
@@ -275,7 +280,7 @@ class SqlWalker
$joinTable
=
$assoc
->
getJoinTable
();
$joinTableAlias
=
$this
->
getSqlTableAlias
(
$joinTable
[
'name'
]);
$sql
.=
$joinTable
[
'name'
]
.
' '
.
$joinTableAlias
.
' ON '
;
if
(
$targetQComp
[
'relation'
]
->
isOwningSide
()
)
{
if
(
$targetQComp
[
'relation'
]
->
isOwningSide
)
{
$sourceToRelationJoinColumns
=
$assoc
->
getSourceToRelationKeyColumns
();
foreach
(
$sourceToRelationJoinColumns
as
$sourceColumn
=>
$relationColumn
)
{
$sql
.=
"
$sourceTableAlias
.
$sourceColumn
=
$joinTableAlias
.
$relationColumn
"
;
...
...
@@ -296,7 +301,7 @@ class SqlWalker
$sql
.=
$targetTableName
.
' '
.
$targetTableAlias
.
' ON '
;
if
(
$targetQComp
[
'relation'
]
->
isOwningSide
()
)
{
if
(
$targetQComp
[
'relation'
]
->
isOwningSide
)
{
$targetToRelationJoinColumns
=
$assoc
->
getTargetToRelationKeyColumns
();
foreach
(
$targetToRelationJoinColumns
as
$targetColumn
=>
$relationColumn
)
{
$sql
.=
"
$targetTableAlias
.
$targetColumn
=
$joinTableAlias
.
$relationColumn
"
;
...
...
@@ -313,6 +318,10 @@ class SqlWalker
if
(
$discrSql
)
{
$sql
.=
' AND '
.
$discrSql
;
}
if
(
$targetQComp
[
'metadata'
]
->
isInheritanceTypeJoined
())
{
$sql
.=
$this
->
_generateClassTableInheritanceJoins
(
$targetQComp
[
'metadata'
],
$joinedDqlAlias
);
}
return
$sql
;
}
...
...
@@ -379,7 +388,7 @@ class SqlWalker
$sql
.=
$this
->
walkFunction
(
$expr
)
.
' AS '
.
$columnAlias
;
$this
->
_resultSetMapping
->
addScalarResult
(
$columnAlias
,
$resultAlias
);
}
else
{
//
$expr is an
IdentificationVariable
// IdentificationVariable
$dqlAlias
=
$expr
;
$queryComp
=
$this
->
_queryComponents
[
$dqlAlias
];
...
...
@@ -389,29 +398,54 @@ class SqlWalker
$this
->
_selectedClasses
[
$dqlAlias
]
=
$class
;
}
$sqlTableAlias
=
$this
->
getSqlTableAlias
(
$class
->
getTableName
()
.
$dqlAlias
);
$beginning
=
true
;
if
(
$class
->
isInheritanceTypeJoined
())
{
// Select all fields from the queried class
foreach
(
$class
->
fieldMappings
as
$fieldName
=>
$mapping
)
{
if
(
isset
(
$mapping
[
'inherited'
]))
{
$tableName
=
$this
->
_em
->
getClassMetadata
(
$mapping
[
'inherited'
])
->
primaryTable
[
'name'
];
}
else
{
$tableName
=
$class
->
primaryTable
[
'name'
];
}
if
(
$beginning
)
$beginning
=
false
;
else
$sql
.=
', '
;
$sqlTableAlias
=
$this
->
getSqlTableAlias
(
$tableName
.
$dqlAlias
);
$columnAlias
=
$this
->
getSqlColumnAlias
(
$mapping
[
'columnName'
]);
$sql
.=
$sqlTableAlias
.
'.'
.
$mapping
[
'columnName'
]
.
' AS '
.
$columnAlias
;
$this
->
_resultSetMapping
->
addFieldResult
(
$dqlAlias
,
$columnAlias
,
$fieldName
);
}
// Gather all fields
$fieldMappings
=
$class
->
fieldMappings
;
foreach
(
$class
->
subClasses
as
$subclassName
)
{
$fieldMappings
=
array_merge
(
// Add any additional fields of subclasses (not inherited fields)
foreach
(
$class
->
subClasses
as
$subClassName
)
{
$subClass
=
$this
->
_em
->
getClassMetadata
(
$subClassName
);
foreach
(
$subClass
->
fieldMappings
as
$fieldName
=>
$mapping
)
{
if
(
isset
(
$mapping
[
'inherited'
]))
{
continue
;
}
if
(
$beginning
)
$beginning
=
false
;
else
$sql
.=
', '
;
$sqlTableAlias
=
$this
->
getSqlTableAlias
(
$subClass
->
primaryTable
[
'name'
]
.
$dqlAlias
);
$columnAlias
=
$this
->
getSqlColumnAlias
(
$mapping
[
'columnName'
]);
$sql
.=
$sqlTableAlias
.
'.'
.
$mapping
[
'columnName'
]
.
' AS '
.
$columnAlias
;
$this
->
_resultSetMapping
->
addFieldResult
(
$dqlAlias
,
$columnAlias
,
$fieldName
);
}
}
}
else
{
$fieldMappings
=
$class
->
fieldMappings
;
foreach
(
$class
->
subClasses
as
$subclassName
)
{
$fieldMappings
=
array_merge
(
$fieldMappings
,
$this
->
_em
->
getClassMetadata
(
$subclassName
)
->
fieldMappings
);
}
$beginning
=
true
;
foreach
(
$fieldMappings
as
$fieldName
=>
$fieldMapping
)
{
if
(
$beginning
)
{
$beginning
=
false
;
}
else
{
$sql
.=
', '
;
);
}
$sqlTableAlias
=
$this
->
getSqlTableAlias
(
$class
->
getTableName
()
.
$dqlAlias
);
foreach
(
$fieldMappings
as
$fieldName
=>
$mapping
)
{
if
(
$beginning
)
$beginning
=
false
;
else
$sql
.=
', '
;
$columnAlias
=
$this
->
getSqlColumnAlias
(
$mapping
[
'columnName'
]);
$sql
.=
$sqlTableAlias
.
'.'
.
$mapping
[
'columnName'
]
.
' AS '
.
$columnAlias
;
$this
->
_resultSetMapping
->
addFieldResult
(
$dqlAlias
,
$columnAlias
,
$fieldName
);
}
$columnAlias
=
$this
->
getSqlColumnAlias
(
$fieldMapping
[
'columnName'
]);
$sql
.=
$sqlTableAlias
.
'.'
.
$fieldMapping
[
'columnName'
]
.
' AS '
.
$columnAlias
;
$this
->
_resultSetMapping
->
addFieldResult
(
$dqlAlias
,
$columnAlias
,
$fieldName
);
}
}
return
$sql
;
}
...
...
@@ -1075,4 +1109,45 @@ class SqlWalker
{
return
$columnName
.
$this
->
_aliasCounter
++
;
}
/**
* Generates the SQL JOINs, that are necessary for Class Table Inheritance,
* for the given class.
*
* @param ClassMetadata $class
* @param string $dqlAlias
*/
private
function
_generateClassTableInheritanceJoins
(
$class
,
$dqlAlias
)
{
$sql
=
''
;
$baseTableAlias
=
$this
->
getSqlTableAlias
(
$class
->
primaryTable
[
'name'
]
.
$dqlAlias
);
$idColumns
=
$class
->
getIdentifierColumnNames
();
// INNER JOIN parent class tables
foreach
(
$class
->
parentClasses
as
$parentClassName
)
{
$parentClass
=
$this
->
_em
->
getClassMetadata
(
$parentClassName
);
$tableAlias
=
$this
->
getSqlTableAlias
(
$parentClass
->
primaryTable
[
'name'
]
.
$dqlAlias
);
$sql
.=
' INNER JOIN '
.
$parentClass
->
primaryTable
[
'name'
]
.
' '
.
$tableAlias
.
' ON '
;
$first
=
true
;
foreach
(
$idColumns
as
$idColumn
)
{
if
(
$first
)
$first
=
false
;
else
$sql
.=
' AND '
;
$sql
.=
$baseTableAlias
.
'.'
.
$idColumn
.
' = '
.
$tableAlias
.
'.'
.
$idColumn
;
}
}
// LEFT JOIN subclass tables
foreach
(
$class
->
subClasses
as
$subClassName
)
{
$subClass
=
$this
->
_em
->
getClassMetadata
(
$subClassName
);
$tableAlias
=
$this
->
getSqlTableAlias
(
$subClass
->
primaryTable
[
'name'
]
.
$dqlAlias
);
$sql
.=
' LEFT JOIN '
.
$subClass
->
primaryTable
[
'name'
]
.
' '
.
$tableAlias
.
' ON '
;
$first
=
true
;
foreach
(
$idColumns
as
$idColumn
)
{
if
(
$first
)
$first
=
false
;
else
$sql
.=
' AND '
;
$sql
.=
$baseTableAlias
.
'.'
.
$idColumn
.
' = '
.
$tableAlias
.
'.'
.
$idColumn
;
}
}
return
$sql
;
}
}
\ No newline at end of file
lib/Doctrine/ORM/Tools/SchemaTool.php
View file @
55d70248
...
...
@@ -89,11 +89,12 @@ class SchemaTool
}
$options
=
array
();
// table options
$columns
=
$this
->
_gatherColumns
(
$class
,
$options
);
// table columns
$this
->
_gatherRelationsSql
(
$class
,
$sql
,
$columns
,
$foreignKeyConstraints
);
$columns
=
array
();
// table columns
if
(
$class
->
isInheritanceTypeSingleTable
())
{
$columns
=
$this
->
_gatherColumns
(
$class
,
$options
);
$this
->
_gatherRelationsSql
(
$class
,
$sql
,
$columns
,
$foreignKeyConstraints
);
// Add the discriminator column
$discrColumnDef
=
$this
->
_getDiscriminatorColumnDefinition
(
$class
);
$columns
[
$discrColumnDef
[
'name'
]]
=
$discrColumnDef
;
...
...
@@ -110,15 +111,46 @@ class SchemaTool
$processedClasses
[
$subClassName
]
=
true
;
}
}
else
if
(
$class
->
isInheritanceTypeJoined
())
{
//TODO
// Add all non-inherited fields as columns
foreach
(
$class
->
fieldMappings
as
$fieldName
=>
$mapping
)
{
if
(
!
isset
(
$mapping
[
'inherited'
]))
{
$columns
[
$mapping
[
'columnName'
]]
=
$this
->
_gatherColumn
(
$class
,
$mapping
,
$options
);
}
}
$this
->
_gatherRelationsSql
(
$class
,
$sql
,
$columns
,
$foreignKeyConstraints
);
// Add the discriminator column only to the root table
if
(
$class
->
name
==
$class
->
rootEntityName
)
{
$discrColumnDef
=
$this
->
_getDiscriminatorColumnDefinition
(
$class
);
$columns
[
$discrColumnDef
[
'name'
]]
=
$discrColumnDef
;
}
else
{
// Add an ID FK column to child tables
$idMapping
=
$class
->
fieldMappings
[
$class
->
identifier
[
0
]];
$idColumn
=
$this
->
_gatherColumn
(
$class
,
$idMapping
,
$options
);
unset
(
$idColumn
[
'autoincrement'
]);
$columns
[
$idMapping
[
'columnName'
]]
=
$idColumn
;
// Add a FK constraint on the ID column
$constraint
=
array
();
$constraint
[
'tableName'
]
=
$class
->
getTableName
();
$constraint
[
'foreignTable'
]
=
$this
->
_em
->
getClassMetadata
(
$class
->
rootEntityName
)
->
getTableName
();
$constraint
[
'local'
]
=
array
(
$idMapping
[
'columnName'
]);
$constraint
[
'foreign'
]
=
array
(
$idMapping
[
'columnName'
]);
$constraint
[
'onDelete'
]
=
'CASCADE'
;
$foreignKeyConstraints
[]
=
$constraint
;
}
}
else
if
(
$class
->
isInheritanceTypeTablePerClass
())
{
//TODO
}
else
{
$columns
=
$this
->
_gatherColumns
(
$class
,
$options
);
$this
->
_gatherRelationsSql
(
$class
,
$sql
,
$columns
,
$foreignKeyConstraints
);
}
$sql
=
array_merge
(
$sql
,
$this
->
_platform
->
getCreateTableSql
(
$class
->
getTableName
(),
$columns
,
$options
));
$processedClasses
[
$class
->
name
]
=
true
;
if
(
$class
->
isIdGeneratorSequence
())
{
if
(
$class
->
isIdGeneratorSequence
()
&&
$class
->
name
==
$class
->
rootEntityName
)
{
$seqDef
=
$class
->
getSequenceGeneratorDefinition
();
$sequences
[]
=
$this
->
_platform
->
getCreateSequenceSql
(
$seqDef
[
'sequenceName'
],
...
...
@@ -152,33 +184,49 @@ class SchemaTool
);
}
/**
* Gathers the column definitions of all field mappings found in the given class.
*
* @param ClassMetadata $class
* @param array $options
* @return array
*/
private
function
_gatherColumns
(
$class
,
array
&
$options
)
{
$columns
=
array
();
foreach
(
$class
->
fieldMappings
as
$fieldName
=>
$mapping
)
{
$column
=
array
();
$column
[
'name'
]
=
$mapping
[
'columnName'
];
$column
[
'type'
]
=
Type
::
getType
(
$mapping
[
'type'
]);
$column
[
'length'
]
=
$mapping
[
'length'
];
$column
[
'notnull'
]
=
!
$mapping
[
'nullable'
];
if
(
$class
->
isIdentifier
(
$fieldName
))
{
$column
[
'primary'
]
=
true
;
$options
[
'primary'
][]
=
$mapping
[
'columnName'
];
if
(
$class
->
isIdGeneratorIdentity
())
{
$column
[
'autoincrement'
]
=
true
;
}
}
$columns
[
$mapping
[
'columnName'
]]
=
$column
;
$columns
[
$mapping
[
'columnName'
]]
=
$this
->
_gatherColumn
(
$class
,
$mapping
,
$options
);
}
return
$columns
;
}
private
function
_gatherColumn
(
$class
,
array
$mapping
,
array
&
$options
)
{
$column
=
array
();
$column
[
'name'
]
=
$mapping
[
'columnName'
];
$column
[
'type'
]
=
Type
::
getType
(
$mapping
[
'type'
]);
$column
[
'length'
]
=
$mapping
[
'length'
];
$column
[
'notnull'
]
=
!
$mapping
[
'nullable'
];
if
(
$class
->
isIdentifier
(
$mapping
[
'fieldName'
]))
{
$column
[
'primary'
]
=
true
;
$options
[
'primary'
][]
=
$mapping
[
'columnName'
];
if
(
$class
->
isIdGeneratorIdentity
())
{
$column
[
'autoincrement'
]
=
true
;
}
}
return
$column
;
}
private
function
_gatherRelationsSql
(
$class
,
array
&
$sql
,
array
&
$columns
,
array
&
$constraints
)
{
foreach
(
$class
->
associationMappings
as
$mapping
)
{
$foreignClass
=
$this
->
_em
->
getClassMetadata
(
$mapping
->
getTargetEntityName
());
if
(
$mapping
->
isOneToOne
()
&&
$mapping
->
isOwningSide
())
{
foreach
(
$class
->
associationMappings
as
$fieldName
=>
$mapping
)
{
if
(
isset
(
$class
->
inheritedAssociationFields
[
$fieldName
]))
{
continue
;
}
$foreignClass
=
$this
->
_em
->
getClassMetadata
(
$mapping
->
targetEntityName
);
if
(
$mapping
->
isOneToOne
()
&&
$mapping
->
isOwningSide
)
{
$constraint
=
array
();
$constraint
[
'tableName'
]
=
$class
->
getTableName
();
$constraint
[
'foreignTable'
]
=
$foreignClass
->
getTableName
();
...
...
@@ -193,10 +241,10 @@ class SchemaTool
$constraint
[
'foreign'
][]
=
$joinColumn
[
'referencedColumnName'
];
}
$constraints
[]
=
$constraint
;
}
else
if
(
$mapping
->
isOneToMany
()
&&
$mapping
->
isOwningSide
()
)
{
}
else
if
(
$mapping
->
isOneToMany
()
&&
$mapping
->
isOwningSide
)
{
//... create join table, one-many through join table supported later
throw
DoctrineException
::
updateMe
(
"Not yet implemented."
);
}
else
if
(
$mapping
->
isManyToMany
()
&&
$mapping
->
isOwningSide
()
)
{
}
else
if
(
$mapping
->
isManyToMany
()
&&
$mapping
->
isOwningSide
)
{
// create join table
$joinTableColumns
=
array
();
$joinTableOptions
=
array
();
...
...
tests/Doctrine/Tests/Models/Company/CompanyEmployee.php
View file @
55d70248
...
...
@@ -4,30 +4,35 @@ namespace Doctrine\Tests\Models\Company;
/**
* @DoctrineEntity
* @DoctrineTable(name="company_employee")
* @DoctrineInheritanceType("joined")
* @DoctrineDiscriminatorColumn(name="dtype", type="string", length=20)
* @DoctrineDiscriminatorMap({
"emp" = "Doctrine\Tests\Models\Company\CompanyEmployee",
"man" = "Doctrine\Tests\Models\Company\CompanyManager"})
* @DoctrineSubclasses({"Doctrine\Tests\Models\Company\CompanyManager"})
* @DoctrineTable(name="company_employees")
* @DoctrineDiscriminatorValue("employee")
* @DoctrineSubClasses({"Doctrine\Tests\Models\Company\CompanyManager"})
*/
class
CompanyEmployee
class
CompanyEmployee
extends
CompanyPerson
{
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineGeneratedValue(strategy="auto")
*/
public
$id
;
/**
* @DoctrineColumn(type="double")
*/
public
$salary
;
private
$salary
;
/**
* @DoctrineColumn(type="string", length=255)
*/
public
$department
;
private
$department
;
public
function
getSalary
()
{
return
$this
->
salary
;
}
public
function
setSalary
(
$salary
)
{
$this
->
salary
=
$salary
;
}
public
function
getDepartment
()
{
return
$this
->
department
;
}
public
function
setDepartment
(
$dep
)
{
$this
->
department
=
$dep
;
}
}
\ No newline at end of file
tests/Doctrine/Tests/Models/Company/CompanyManager.php
View file @
55d70248
...
...
@@ -4,11 +4,21 @@ namespace Doctrine\Tests\Models\Company;
/**
* @DoctrineEntity
* @DoctrineTable(name="company_managers")
* @DoctrineDiscriminatorValue("manager")
*/
class
CompanyManager
extends
CompanyEmployee
{
/*
* @DoctrineColumn(type="string", length="25
5
")
/*
*
* @DoctrineColumn(type="string", length="25
0
")
*/
public
$title
;
private
$title
;
public
function
getTitle
()
{
return
$this
->
title
;
}
public
function
setTitle
(
$title
)
{
$this
->
title
=
$title
;
}
}
\ No newline at end of file
tests/Doctrine/Tests/Models/Company/CompanyPerson.php
0 → 100644
View file @
55d70248
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace
Doctrine\Tests\Models\Company
;
/**
* Description of CompanyPerson
*
* @author robo
* @DoctrineEntity
* @DoctrineTable(name="company_persons")
* @DoctrineDiscriminatorValue("person")
* @DoctrineInheritanceType("joined")
* @DoctrineDiscriminatorColumn(name="discr", type="string")
* @DoctrineSubClasses({"Doctrine\Tests\Models\Company\CompanyEmployee",
"Doctrine\Tests\Models\Company\CompanyManager"})
*/
class
CompanyPerson
{
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineGeneratedValue(strategy="auto")
*/
private
$id
;
/**
* @DoctrineColumn(type="string")
*/
private
$name
;
/**
* @DoctrineOneToOne(targetEntity="CompanyPerson")
* @DoctrineJoinColumn(name="spouse_id", referencedColumnName="id")
*/
private
$spouse
;
public
function
getId
()
{
return
$this
->
id
;
}
public
function
getName
()
{
return
$this
->
name
;
}
public
function
setName
(
$name
)
{
$this
->
name
=
$name
;
}
public
function
getSpouse
()
{
return
$this
->
spouse
;
}
public
function
setSpouse
(
CompanyPerson
$spouse
)
{
if
(
$spouse
!==
$this
->
spouse
)
{
$this
->
spouse
=
$spouse
;
$this
->
spouse
->
setSpouse
(
$this
);
}
}
}
tests/Doctrine/Tests/ORM/Functional/AllTests.php
View file @
55d70248
...
...
@@ -22,6 +22,7 @@ class AllTests
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\BasicFunctionalTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\NativeQueryTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\SingleTableInheritanceTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\ClassTableInheritanceTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\DetachedEntityTest'
);
return
$suite
;
...
...
tests/Doctrine/Tests/ORM/Functional/ClassTableInheritanceTest.php
0 → 100644
View file @
55d70248
<?php
namespace
Doctrine\Tests\ORM\Functional
;
require_once
__DIR__
.
'/../../TestInit.php'
;
use
Doctrine\Tests\Models\Company\CompanyPerson
;
use
Doctrine\Tests\Models\Company\CompanyEmployee
;
use
Doctrine\Tests\Models\Company\CompanyManager
;
/**
* Functional tests for the Single Table Inheritance mapping strategy.
*
* @author robo
*/
class
ClassTableInheritanceTest
extends
\Doctrine\Tests\OrmFunctionalTestCase
{
protected
function
setUp
()
{
$this
->
useModelSet
(
'company'
);
parent
::
setUp
();
}
public
function
testCRUD
()
{
$person
=
new
CompanyPerson
;
$person
->
setName
(
'Roman S. Borschel'
);
$this
->
_em
->
save
(
$person
);
$employee
=
new
CompanyEmployee
;
$employee
->
setName
(
'Roman S. Borschel'
);
$employee
->
setSalary
(
100000
);
$employee
->
setDepartment
(
'IT'
);
$this
->
_em
->
save
(
$employee
);
$employee
->
setName
(
'Guilherme Blanco'
);
$this
->
_em
->
flush
();
$this
->
_em
->
clear
();
$query
=
$this
->
_em
->
createQuery
(
"select p from Doctrine\Tests\Models\Company\CompanyPerson p order by p.id asc"
);
$entities
=
$query
->
getResultList
();
$this
->
assertEquals
(
2
,
count
(
$entities
));
$this
->
assertTrue
(
$entities
[
0
]
instanceof
CompanyPerson
);
$this
->
assertTrue
(
$entities
[
1
]
instanceof
CompanyEmployee
);
$this
->
assertTrue
(
is_numeric
(
$entities
[
0
]
->
getId
()));
$this
->
assertTrue
(
is_numeric
(
$entities
[
1
]
->
getId
()));
$this
->
assertEquals
(
'Roman S. Borschel'
,
$entities
[
0
]
->
getName
());
$this
->
assertEquals
(
'Guilherme Blanco'
,
$entities
[
1
]
->
getName
());
$this
->
assertEquals
(
100000
,
$entities
[
1
]
->
getSalary
());
$this
->
_em
->
clear
();
$query
=
$this
->
_em
->
createQuery
(
"select p from Doctrine\Tests\Models\Company\CompanyEmployee p"
);
$entities
=
$query
->
getResultList
();
$this
->
assertEquals
(
1
,
count
(
$entities
));
$this
->
assertTrue
(
$entities
[
0
]
instanceof
CompanyEmployee
);
$this
->
assertTrue
(
is_numeric
(
$entities
[
0
]
->
getId
()));
$this
->
assertEquals
(
'Guilherme Blanco'
,
$entities
[
0
]
->
getName
());
$this
->
assertEquals
(
100000
,
$entities
[
0
]
->
getSalary
());
$this
->
_em
->
clear
();
/*
$query = $this->_em->createQuery("select r,o from Doctrine\Tests\ORM\Functional\RelatedEntity r join r.owner o");
$entities = $query->getResultList();
$this->assertEquals(1, count($entities));
$this->assertTrue($entities[0] instanceof RelatedEntity);
$this->assertTrue(is_numeric($entities[0]->getId()));
$this->assertEquals('theRelatedOne', $entities[0]->getName());
$this->assertTrue($entities[0]->getOwner() instanceof ChildEntity);
$this->assertEquals('thedata', $entities[0]->getOwner()->getData());
$this->assertSame($entities[0], $entities[0]->getOwner()->getRelatedEntity());
$query = $this->_em->createQuery("update Doctrine\Tests\ORM\Functional\ChildEntity e set e.data = 'newdata'");
$affected = $query->execute();
$this->assertEquals(1, $affected);
$query = $this->_em->createQuery("delete Doctrine\Tests\ORM\Functional\ParentEntity e");
$affected = $query->execute();
$this->assertEquals(2, $affected);
*/
}
}
tests/Doctrine/Tests/OrmFunctionalTestCase.php
View file @
55d70248
...
...
@@ -34,13 +34,17 @@ class OrmFunctionalTestCase extends OrmTestCase
'Doctrine\Tests\Models\CMS\CmsArticle'
),
'forum'
=>
array
(),
'company'
=>
array
(),
'company'
=>
array
(
'Doctrine\Tests\Models\Company\CompanyPerson'
,
'Doctrine\Tests\Models\Company\CompanyEmployee'
,
'Doctrine\Tests\Models\Company\CompanyManager'
),
'ecommerce'
=>
array
()
);
protected
function
useModelSet
(
$setName
)
{
$this
->
_usedModelSets
[
]
=
$setNam
e
;
$this
->
_usedModelSets
[
$setName
]
=
tru
e
;
}
/**
...
...
@@ -49,7 +53,7 @@ class OrmFunctionalTestCase extends OrmTestCase
protected
function
tearDown
()
{
$conn
=
$this
->
sharedFixture
[
'conn'
];
if
(
i
n_array
(
'cms'
,
$this
->
_usedModelSets
))
{
if
(
i
sset
(
$this
->
_usedModelSets
[
'cms'
]
))
{
$conn
->
exec
(
'DELETE FROM cms_users_groups'
);
$conn
->
exec
(
'DELETE FROM cms_groups'
);
$conn
->
exec
(
'DELETE FROM cms_addresses'
);
...
...
@@ -57,6 +61,12 @@ class OrmFunctionalTestCase extends OrmTestCase
$conn
->
exec
(
'DELETE FROM cms_articles'
);
$conn
->
exec
(
'DELETE FROM cms_users'
);
}
if
(
isset
(
$this
->
_usedModelSets
[
'company'
]))
{
$conn
->
exec
(
'DELETE FROM company_managers'
);
$conn
->
exec
(
'DELETE FROM company_employees'
);
$conn
->
exec
(
'DELETE FROM company_persons'
);
}
$this
->
_em
->
clear
();
}
...
...
@@ -79,7 +89,7 @@ class OrmFunctionalTestCase extends OrmTestCase
}
$classes
=
array
();
foreach
(
$this
->
_usedModelSets
as
$setName
)
{
foreach
(
$this
->
_usedModelSets
as
$setName
=>
$bool
)
{
if
(
!
isset
(
self
::
$_tablesCreated
[
$setName
])
||
$forceCreateTables
)
{
foreach
(
self
::
$_modelSets
[
$setName
]
as
$className
)
{
$classes
[]
=
$this
->
_em
->
getClassMetadata
(
$className
);
...
...
@@ -88,7 +98,14 @@ class OrmFunctionalTestCase extends OrmTestCase
}
}
if
(
$classes
)
{
$this
->
_schemaTool
->
createSchema
(
$classes
);
try
{
$this
->
_schemaTool
->
createSchema
(
$classes
);
}
catch
(
\Exception
$e
)
{
// Suppress "xxx already exists" messages
if
(
stripos
(
$e
->
getMessage
(),
'already exists'
)
===
false
)
{
throw
$e
;
}
}
}
}
...
...
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