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
bb6e54fb
Commit
bb6e54fb
authored
Oct 09, 2009
by
romanb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[2.0][DDC-21] Fixed.
parent
204b6d71
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
248 additions
and
79 deletions
+248
-79
ObjectHydrator.php
lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
+104
-71
AnnotationDriver.php
lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
+1
-1
UnitOfWork.php
lib/Doctrine/ORM/UnitOfWork.php
+4
-6
AllTests.php
tests/Doctrine/Tests/ORM/Functional/AllTests.php
+1
-0
IdentityMapTest.php
tests/Doctrine/Tests/ORM/Functional/IdentityMapTest.php
+137
-0
StandardEntityPersisterTest.php
...rine/Tests/ORM/Functional/StandardEntityPersisterTest.php
+1
-1
No files found.
lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
View file @
bb6e54fb
...
@@ -31,6 +31,7 @@ use Doctrine\ORM\PersistentCollection,
...
@@ -31,6 +31,7 @@ use Doctrine\ORM\PersistentCollection,
*
*
* @author Roman Borschel <roman@code-factory.org>
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @since 2.0
* @internal Highly performance-sensitive code.
*/
*/
class
ObjectHydrator
extends
AbstractHydrator
class
ObjectHydrator
extends
AbstractHydrator
{
{
...
@@ -49,7 +50,10 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -49,7 +50,10 @@ class ObjectHydrator extends AbstractHydrator
private
$_fetchedAssociations
;
private
$_fetchedAssociations
;
private
$_rootAliases
=
array
();
private
$_rootAliases
=
array
();
private
$_initializedCollections
=
array
();
private
$_initializedCollections
=
array
();
private
$_existingCollections
=
array
();
private
$_proxyFactory
;
private
$_proxyFactory
;
//private $_createdEntities;
/** @override */
/** @override */
protected
function
_prepare
()
protected
function
_prepare
()
...
@@ -57,9 +61,7 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -57,9 +61,7 @@ class ObjectHydrator extends AbstractHydrator
$this
->
_allowPartialObjects
=
$this
->
_em
->
getConfiguration
()
->
getAllowPartialObjects
()
$this
->
_allowPartialObjects
=
$this
->
_em
->
getConfiguration
()
->
getAllowPartialObjects
()
||
isset
(
$this
->
_hints
[
Query
::
HINT_FORCE_PARTIAL_LOAD
]);
||
isset
(
$this
->
_hints
[
Query
::
HINT_FORCE_PARTIAL_LOAD
]);
if
(
!
$this
->
_allowPartialObjects
)
{
$this
->
_proxyFactory
=
$this
->
_em
->
getProxyFactory
();
$this
->
_proxyFactory
=
$this
->
_em
->
getProxyFactory
();
}
$this
->
_identifierMap
=
$this
->
_identifierMap
=
$this
->
_resultPointers
=
$this
->
_resultPointers
=
...
@@ -81,7 +83,7 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -81,7 +83,7 @@ class ObjectHydrator extends AbstractHydrator
// collection stubs or proxies and where not.
// collection stubs or proxies and where not.
if
(
isset
(
$this
->
_rsm
->
relationMap
[
$dqlAlias
]))
{
if
(
isset
(
$this
->
_rsm
->
relationMap
[
$dqlAlias
]))
{
$targetClassName
=
$this
->
_rsm
->
aliasMap
[
$this
->
_rsm
->
parentAliasMap
[
$dqlAlias
]];
$targetClassName
=
$this
->
_rsm
->
aliasMap
[
$this
->
_rsm
->
parentAliasMap
[
$dqlAlias
]];
$targetClass
=
$this
->
_
em
->
getClassMetadata
(
$targetClassName
);
$targetClass
=
$this
->
_getClassMetadata
(
$targetClassName
);
$this
->
_ce
[
$targetClassName
]
=
$targetClass
;
$this
->
_ce
[
$targetClassName
]
=
$targetClass
;
$assoc
=
$targetClass
->
associationMappings
[
$this
->
_rsm
->
relationMap
[
$dqlAlias
]];
$assoc
=
$targetClass
->
associationMappings
[
$this
->
_rsm
->
relationMap
[
$dqlAlias
]];
$this
->
_fetchedAssociations
[
$assoc
->
sourceEntityName
][
$assoc
->
sourceFieldName
]
=
true
;
$this
->
_fetchedAssociations
[
$assoc
->
sourceEntityName
][
$assoc
->
sourceFieldName
]
=
true
;
...
@@ -99,22 +101,20 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -99,22 +101,20 @@ class ObjectHydrator extends AbstractHydrator
/**
/**
* {@inheritdoc}
* {@inheritdoc}
*
* @override
*/
*/
protected
function
_cleanup
()
/*@override*/
protected
function
_cleanup
()
{
{
parent
::
_cleanup
();
parent
::
_cleanup
();
$this
->
_identifierMap
=
$this
->
_identifierMap
=
$this
->
_initializedCollections
=
$this
->
_existingCollections
=
$this
->
_resultPointers
=
array
();
$this
->
_resultPointers
=
array
();
}
}
/**
/**
* {@inheritdoc}
* {@inheritdoc}
*
* @override
*/
*/
protected
function
_hydrateAll
()
/*@override*/
protected
function
_hydrateAll
()
{
{
$result
=
array
();
$result
=
array
();
$cache
=
array
();
$cache
=
array
();
...
@@ -122,11 +122,10 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -122,11 +122,10 @@ class ObjectHydrator extends AbstractHydrator
$this
->
_hydrateRow
(
$data
,
$cache
,
$result
);
$this
->
_hydrateRow
(
$data
,
$cache
,
$result
);
}
}
// Take snapshots from all initialized collections
// Take snapshots from all
newly
initialized collections
foreach
(
$this
->
_initializedCollections
as
$coll
)
{
foreach
(
$this
->
_initializedCollections
as
$coll
)
{
$coll
->
takeSnapshot
();
$coll
->
takeSnapshot
();
}
}
$this
->
_initializedCollections
=
array
();
return
$result
;
return
$result
;
}
}
...
@@ -155,17 +154,20 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -155,17 +154,20 @@ class ObjectHydrator extends AbstractHydrator
$value
$value
);
);
$value
->
setOwner
(
$entity
,
$relation
);
$value
->
setOwner
(
$entity
,
$relation
);
}
else
{
$class
->
reflFields
[
$name
]
->
setValue
(
$entity
,
$value
);
// Is already PersistentCollection.
$this
->
_uow
->
setOriginalEntityProperty
(
$oid
,
$name
,
$value
);
$this
->
_initializedCollections
[
$oid
.
$name
]
=
$value
;
}
else
if
(
isset
(
$this
->
_hints
[
Query
::
HINT_REFRESH
]))
{
// Is already PersistentCollection, but REFRESH
$value
->
clear
();
$value
->
clear
();
$value
->
setDirty
(
false
);
$value
->
setDirty
(
false
);
$value
->
setInitialized
(
true
);
$value
->
setInitialized
(
true
);
$this
->
_initializedCollections
[
$oid
.
$name
]
=
$value
;
}
else
{
// Is already PersistentCollection, and DONT REFRESH
$this
->
_existingCollections
[
$oid
.
$name
]
=
$value
;
}
}
$class
->
reflFields
[
$name
]
->
setValue
(
$entity
,
$value
);
$this
->
_uow
->
setOriginalEntityProperty
(
$oid
,
$name
,
$value
);
$this
->
_initializedCollections
[
$oid
.
$name
]
=
$value
;
return
$value
;
return
$value
;
}
}
...
@@ -187,6 +189,7 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -187,6 +189,7 @@ class ObjectHydrator extends AbstractHydrator
$entity
=
$this
->
_uow
->
createEntity
(
$className
,
$data
,
$this
->
_hints
);
$entity
=
$this
->
_uow
->
createEntity
(
$className
,
$data
,
$this
->
_hints
);
//FIXME: If $entity comes from the identity map there is no need to do this!
// Properly initialize any unfetched associations, if partial objects are not allowed.
// Properly initialize any unfetched associations, if partial objects are not allowed.
if
(
!
$this
->
_allowPartialObjects
)
{
if
(
!
$this
->
_allowPartialObjects
)
{
$oid
=
spl_object_hash
(
$entity
);
$oid
=
spl_object_hash
(
$entity
);
...
@@ -232,6 +235,23 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -232,6 +235,23 @@ class ObjectHydrator extends AbstractHydrator
return
$entity
;
return
$entity
;
}
}
private
function
_getEntityFromIdentityMap
(
$className
,
array
$data
)
{
$class
=
$this
->
_ce
[
$className
];
if
(
$class
->
isIdentifierComposite
)
{
$idHash
=
''
;
foreach
(
$class
->
identifier
as
$fieldName
)
{
$idHash
.=
$data
[
$fieldName
]
.
' '
;
}
$idHash
=
rtrim
(
$idHash
);
}
else
{
$idHash
=
$data
[
$class
->
identifier
[
0
]];
}
return
$this
->
_uow
->
tryGetByIdHash
(
$idHash
,
$class
->
rootEntityName
);
}
/**
/**
* Gets a ClassMetadata instance from the local cache.
* Gets a ClassMetadata instance from the local cache.
* If the instance is not yet in the local cache, it is loaded into the
* If the instance is not yet in the local cache, it is loaded into the
...
@@ -250,10 +270,8 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -250,10 +270,8 @@ class ObjectHydrator extends AbstractHydrator
/**
/**
* {@inheritdoc}
* {@inheritdoc}
*
* @override
*/
*/
protected
function
_hydrateRow
(
array
&
$data
,
array
&
$cache
,
array
&
$result
)
/*@override*/
protected
function
_hydrateRow
(
array
&
$data
,
array
&
$cache
,
array
&
$result
)
{
{
// Initialize
// Initialize
$id
=
$this
->
_idTemplate
;
// initialize the id-memory
$id
=
$this
->
_idTemplate
;
// initialize the id-memory
...
@@ -266,7 +284,7 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -266,7 +284,7 @@ class ObjectHydrator extends AbstractHydrator
unset
(
$rowData
[
'scalars'
]);
unset
(
$rowData
[
'scalars'
]);
}
}
// Hydrate the
entity
data found in the current row.
// Hydrate the data found in the current row.
foreach
(
$rowData
as
$dqlAlias
=>
$data
)
{
foreach
(
$rowData
as
$dqlAlias
=>
$data
)
{
$index
=
false
;
$index
=
false
;
$entityName
=
$this
->
_rsm
->
aliasMap
[
$dqlAlias
];
$entityName
=
$this
->
_rsm
->
aliasMap
[
$dqlAlias
];
...
@@ -274,31 +292,34 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -274,31 +292,34 @@ class ObjectHydrator extends AbstractHydrator
if
(
isset
(
$this
->
_rsm
->
parentAliasMap
[
$dqlAlias
]))
{
if
(
isset
(
$this
->
_rsm
->
parentAliasMap
[
$dqlAlias
]))
{
// It's a joined result
// It's a joined result
$parent
=
$this
->
_rsm
->
parentAliasMap
[
$dqlAlias
];
$parent
Alias
=
$this
->
_rsm
->
parentAliasMap
[
$dqlAlias
];
// Get a reference to the
right object to which the joined resul
t belongs.
// Get a reference to the
parent object to which the joined elemen
t belongs.
if
(
$this
->
_rsm
->
isMixed
&&
isset
(
$this
->
_rootAliases
[
$parent
]))
{
if
(
$this
->
_rsm
->
isMixed
&&
isset
(
$this
->
_rootAliases
[
$parent
Alias
]))
{
$first
=
reset
(
$this
->
_resultPointers
);
$first
=
reset
(
$this
->
_resultPointers
);
$
baseElement
=
$this
->
_resultPointers
[
$parent
][
key
(
$first
)];
$
parentObject
=
$this
->
_resultPointers
[
$parentAlias
][
key
(
$first
)];
}
else
if
(
isset
(
$this
->
_resultPointers
[
$parent
]))
{
}
else
if
(
isset
(
$this
->
_resultPointers
[
$parent
Alias
]))
{
$
baseElement
=
$this
->
_resultPointers
[
$parent
];
$
parentObject
=
$this
->
_resultPointers
[
$parentAlias
];
}
else
{
}
else
{
throw
HydrationException
::
parentObjectOfRelationNotFound
(
$dqlAlias
,
$parent
);
// Parent object of relation not found, so skip it.
continue
;
}
}
$parentClass
=
get_class
(
$
baseElemen
t
);
$parentClass
=
get_class
(
$
parentObjec
t
);
$oid
=
spl_object_hash
(
$
baseElemen
t
);
$oid
=
spl_object_hash
(
$
parentObjec
t
);
$relationField
=
$this
->
_rsm
->
relationMap
[
$dqlAlias
];
$relationField
=
$this
->
_rsm
->
relationMap
[
$dqlAlias
];
$relation
=
$this
->
_ce
[
$parentClass
]
->
associationMappings
[
$relationField
];
$relation
=
$this
->
_ce
[
$parentClass
]
->
associationMappings
[
$relationField
];
$reflField
=
$this
->
_ce
[
$parentClass
]
->
reflFields
[
$relationField
];
$reflField
=
$this
->
_ce
[
$parentClass
]
->
reflFields
[
$relationField
];
$reflFieldValue
=
$reflField
->
getValue
(
$baseElement
);
// Check the type of the relation (many or single-valued)
// Check the type of the relation (many or single-valued)
if
(
!
$relation
->
isOneToOne
())
{
if
(
!
$relation
->
isOneToOne
())
{
// Collection-valued association
// Collection-valued association
if
(
isset
(
$nonemptyComponents
[
$dqlAlias
]))
{
if
(
isset
(
$nonemptyComponents
[
$dqlAlias
]))
{
if
(
!
isset
(
$this
->
_initializedCollections
[
$oid
.
$relationField
]))
{
$collKey
=
$oid
.
$relationField
;
$reflFieldValue
=
$this
->
_initRelatedCollection
(
$baseElement
,
$relationField
);
if
(
isset
(
$this
->
_initializedCollections
[
$collKey
]))
{
$reflFieldValue
=
$this
->
_initializedCollections
[
$collKey
];
}
else
if
(
!
isset
(
$this
->
_existingCollections
[
$collKey
]))
{
$reflFieldValue
=
$this
->
_initRelatedCollection
(
$parentObject
,
$relationField
);
}
}
$indexExists
=
isset
(
$this
->
_identifierMap
[
$dqlAlias
][
$id
[
$dqlAlias
]]);
$indexExists
=
isset
(
$this
->
_identifierMap
[
$dqlAlias
][
$id
[
$dqlAlias
]]);
...
@@ -306,66 +327,78 @@ class ObjectHydrator extends AbstractHydrator
...
@@ -306,66 +327,78 @@ class ObjectHydrator extends AbstractHydrator
$indexIsValid
=
$index
!==
false
?
isset
(
$reflFieldValue
[
$index
])
:
false
;
$indexIsValid
=
$index
!==
false
?
isset
(
$reflFieldValue
[
$index
])
:
false
;
if
(
!
$indexExists
||
!
$indexIsValid
)
{
if
(
!
$indexExists
||
!
$indexIsValid
)
{
$element
=
$this
->
_getEntity
(
$data
,
$dqlAlias
);
if
(
isset
(
$this
->
_existingCollections
[
$collKey
]))
{
// Collection exists, only look for $element in identity map.
// If it's a bi-directional many-to-many, also initialize the reverse collection.
if
(
$element
=
$this
->
_getEntityFromIdentityMap
(
$entityName
,
$data
))
{
if
(
$relation
->
isManyToMany
())
{
$this
->
_resultPointers
[
$dqlAlias
]
=
$element
;
if
(
$relation
->
isOwningSide
&&
isset
(
$this
->
_ce
[
$entityName
]
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]))
{
}
else
{
$inverseFieldName
=
$this
->
_ce
[
$entityName
]
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]
->
sourceFieldName
;
unset
(
$this
->
_resultPointers
[
$dqlAlias
]);
// Only initialize reverse collection if it is not yet initialized.
if
(
!
isset
(
$this
->
_initializedCollections
[
spl_object_hash
(
$element
)
.
$inverseFieldName
]))
{
$this
->
_initRelatedCollection
(
$element
,
$inverseFieldName
);
}
}
else
if
(
$relation
->
mappedByFieldName
)
{
// Only initialize reverse collection if it is not yet initialized.
if
(
!
isset
(
$this
->
_initializedCollections
[
spl_object_hash
(
$element
)
.
$relation
->
mappedByFieldName
]))
{
$this
->
_initRelatedCollection
(
$element
,
$relation
->
mappedByFieldName
);
}
}
}
}
if
(
isset
(
$this
->
_rsm
->
indexByMap
[
$dqlAlias
]))
{
$field
=
$this
->
_rsm
->
indexByMap
[
$dqlAlias
];
$indexValue
=
$this
->
_ce
[
$entityName
]
->
reflFields
[
$field
]
->
getValue
(
$element
);
$reflFieldValue
->
hydrateSet
(
$indexValue
,
$element
);
$this
->
_identifierMap
[
$dqlAlias
][
$id
[
$dqlAlias
]]
=
$indexValue
;
}
else
{
}
else
{
$reflFieldValue
->
hydrateAdd
(
$element
);
$element
=
$this
->
_getEntity
(
$data
,
$dqlAlias
);
$reflFieldValue
->
last
();
$this
->
_identifierMap
[
$dqlAlias
][
$id
[
$dqlAlias
]]
=
$reflFieldValue
->
key
();
// If it's a bi-directional many-to-many, also initialize the reverse collection.
if
(
$relation
->
isManyToMany
())
{
if
(
$relation
->
isOwningSide
&&
isset
(
$this
->
_ce
[
$entityName
]
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]))
{
$inverseFieldName
=
$this
->
_ce
[
$entityName
]
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]
->
sourceFieldName
;
// Only initialize reverse collection if it is not yet initialized.
if
(
!
isset
(
$this
->
_initializedCollections
[
spl_object_hash
(
$element
)
.
$inverseFieldName
]))
{
$this
->
_initRelatedCollection
(
$element
,
$inverseFieldName
);
}
}
else
if
(
$relation
->
mappedByFieldName
)
{
// Only initialize reverse collection if it is not yet initialized.
if
(
!
isset
(
$this
->
_initializedCollections
[
spl_object_hash
(
$element
)
.
$relation
->
mappedByFieldName
]))
{
$this
->
_initRelatedCollection
(
$element
,
$relation
->
mappedByFieldName
);
}
}
}
if
(
isset
(
$this
->
_rsm
->
indexByMap
[
$dqlAlias
]))
{
$field
=
$this
->
_rsm
->
indexByMap
[
$dqlAlias
];
$indexValue
=
$this
->
_ce
[
$entityName
]
->
reflFields
[
$field
]
->
getValue
(
$element
);
$reflFieldValue
->
hydrateSet
(
$indexValue
,
$element
);
$this
->
_identifierMap
[
$dqlAlias
][
$id
[
$dqlAlias
]]
=
$indexValue
;
}
else
{
$reflFieldValue
->
hydrateAdd
(
$element
);
$reflFieldValue
->
last
();
$this
->
_identifierMap
[
$dqlAlias
][
$id
[
$dqlAlias
]]
=
$reflFieldValue
->
key
();
}
// Update result pointer
$this
->
_resultPointers
[
$dqlAlias
]
=
$element
;
}
}
}
else
{
// Update result pointer
$this
->
_resultPointers
[
$dqlAlias
]
=
$reflFieldValue
[
$index
];
}
}
}
else
if
(
!
$reflField
->
getValue
(
$parentObject
))
{
// Update result pointer
$this
->
_resultPointers
[
$dqlAlias
]
=
$index
===
false
?
$element
:
$reflFieldValue
[
$index
];
}
else
if
(
!
$reflFieldValue
)
{
$coll
=
new
PersistentCollection
(
$this
->
_em
,
$this
->
_ce
[
$entityName
],
new
ArrayCollection
);
$coll
=
new
PersistentCollection
(
$this
->
_em
,
$this
->
_ce
[
$entityName
],
new
ArrayCollection
);
$reflField
->
setValue
(
$
baseElemen
t
,
$coll
);
$reflField
->
setValue
(
$
parentObjec
t
,
$coll
);
$this
->
_uow
->
setOriginalEntityProperty
(
$oid
,
$relationField
,
$coll
);
$this
->
_uow
->
setOriginalEntityProperty
(
$oid
,
$relationField
,
$coll
);
}
}
}
else
{
}
else
{
// Single-valued association
// Single-valued association
$reflFieldValue
=
$reflField
->
getValue
(
$
baseElemen
t
);
$reflFieldValue
=
$reflField
->
getValue
(
$
parentObjec
t
);
if
(
!
$reflFieldValue
/* || doctrine.refresh hint set */
)
{
if
(
!
$reflFieldValue
||
isset
(
$this
->
_hints
[
Query
::
HINT_REFRESH
])
)
{
if
(
isset
(
$nonemptyComponents
[
$dqlAlias
]))
{
if
(
isset
(
$nonemptyComponents
[
$dqlAlias
]))
{
$element
=
$this
->
_getEntity
(
$data
,
$dqlAlias
);
$element
=
$this
->
_getEntity
(
$data
,
$dqlAlias
);
$reflField
->
setValue
(
$
baseElemen
t
,
$element
);
$reflField
->
setValue
(
$
parentObjec
t
,
$element
);
$this
->
_uow
->
setOriginalEntityProperty
(
$oid
,
$relationField
,
$element
);
$this
->
_uow
->
setOriginalEntityProperty
(
$oid
,
$relationField
,
$element
);
$targetClass
=
$this
->
_ce
[
$relation
->
targetEntityName
];
$targetClass
=
$this
->
_ce
[
$relation
->
targetEntityName
];
if
(
$relation
->
isOwningSide
)
{
if
(
$relation
->
isOwningSide
)
{
// If there is an inverse mapping on the target class its bidirectional
// If there is an inverse mapping on the target class its bidirectional
if
(
isset
(
$targetClass
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]))
{
if
(
isset
(
$targetClass
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]))
{
$sourceProp
=
$targetClass
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]
->
sourceFieldName
;
$sourceProp
=
$targetClass
->
inverseMappings
[
$relation
->
sourceEntityName
][
$relationField
]
->
sourceFieldName
;
$targetClass
->
reflFields
[
$sourceProp
]
->
setValue
(
$element
,
$
baseElemen
t
);
$targetClass
->
reflFields
[
$sourceProp
]
->
setValue
(
$element
,
$
parentObjec
t
);
}
else
if
(
$this
->
_ce
[
$parentClass
]
===
$targetClass
&&
$relation
->
mappedByFieldName
)
{
}
else
if
(
$this
->
_ce
[
$parentClass
]
===
$targetClass
&&
$relation
->
mappedByFieldName
)
{
// Special case: bi-directional self-referencing one-one on the same class
// Special case: bi-directional self-referencing one-one on the same class
$targetClass
->
reflFields
[
$relationField
]
->
setValue
(
$element
,
$
baseElemen
t
);
$targetClass
->
reflFields
[
$relationField
]
->
setValue
(
$element
,
$
parentObjec
t
);
}
}
}
else
{
}
else
{
// For sure bidirectional, as there is no inverse side in unidirectional mappings
// For sure bidirectional, as there is no inverse side in unidirectional mappings
$targetClass
->
reflFields
[
$relation
->
mappedByFieldName
]
->
setValue
(
$element
,
$
baseElemen
t
);
$targetClass
->
reflFields
[
$relation
->
mappedByFieldName
]
->
setValue
(
$element
,
$
parentObjec
t
);
}
}
// Update result pointer
$this
->
_resultPointers
[
$dqlAlias
]
=
$element
;
}
}
// else leave $reflFieldValue null for single-valued associations
// else leave $reflFieldValue null for single-valued associations
}
else
{
}
else
{
...
...
lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
View file @
bb6e54fb
...
@@ -273,7 +273,7 @@ class AnnotationDriver implements Driver
...
@@ -273,7 +273,7 @@ class AnnotationDriver implements Driver
$mapping
[
'mappedBy'
]
=
$manyToManyAnnot
->
mappedBy
;
$mapping
[
'mappedBy'
]
=
$manyToManyAnnot
->
mappedBy
;
$mapping
[
'cascade'
]
=
$manyToManyAnnot
->
cascade
;
$mapping
[
'cascade'
]
=
$manyToManyAnnot
->
cascade
;
$metadata
->
mapManyToMany
(
$mapping
);
$metadata
->
mapManyToMany
(
$mapping
);
}
}
}
}
// Evaluate HasLifecycleCallbacks annotation
// Evaluate HasLifecycleCallbacks annotation
...
...
lib/Doctrine/ORM/UnitOfWork.php
View file @
bb6e54fb
...
@@ -1080,10 +1080,8 @@ class UnitOfWork implements PropertyChangedListener
...
@@ -1080,10 +1080,8 @@ class UnitOfWork implements PropertyChangedListener
*/
*/
public
function
tryGetByIdHash
(
$idHash
,
$rootClassName
)
public
function
tryGetByIdHash
(
$idHash
,
$rootClassName
)
{
{
if
(
$this
->
containsIdHash
(
$idHash
,
$rootClassName
))
{
return
isset
(
$this
->
_identityMap
[
$rootClassName
][
$idHash
])
?
return
$this
->
getByIdHash
(
$idHash
,
$rootClassName
);
$this
->
_identityMap
[
$rootClassName
][
$idHash
]
:
false
;
}
return
false
;
}
}
/**
/**
...
@@ -1656,8 +1654,7 @@ class UnitOfWork implements PropertyChangedListener
...
@@ -1656,8 +1654,7 @@ class UnitOfWork implements PropertyChangedListener
* @param string $className The name of the entity class.
* @param string $className The name of the entity class.
* @param array $data The data for the entity.
* @param array $data The data for the entity.
* @return object The created entity instance.
* @return object The created entity instance.
* @internal Highly performance-sensitive method. Run the performance test suites when
* @internal Highly performance-sensitive method.
* making modifications.
*/
*/
public
function
createEntity
(
$className
,
array
$data
,
$hints
=
array
())
public
function
createEntity
(
$className
,
array
$data
,
$hints
=
array
())
{
{
...
@@ -1703,6 +1700,7 @@ class UnitOfWork implements PropertyChangedListener
...
@@ -1703,6 +1700,7 @@ class UnitOfWork implements PropertyChangedListener
}
}
}
}
//TODO: These should be invoked later, because associations are not yet loaded here.
if
(
isset
(
$class
->
lifecycleCallbacks
[
Events
::
postLoad
]))
{
if
(
isset
(
$class
->
lifecycleCallbacks
[
Events
::
postLoad
]))
{
$class
->
invokeLifecycleCallbacks
(
Events
::
postLoad
,
$entity
);
$class
->
invokeLifecycleCallbacks
(
Events
::
postLoad
,
$entity
);
}
}
...
...
tests/Doctrine/Tests/ORM/Functional/AllTests.php
View file @
bb6e54fb
...
@@ -40,6 +40,7 @@ class AllTests
...
@@ -40,6 +40,7 @@ class AllTests
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\StandardEntityPersisterTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\StandardEntityPersisterTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\MappedSuperclassTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\MappedSuperclassTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\EntityRepositoryTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\EntityRepositoryTest'
);
$suite
->
addTestSuite
(
'Doctrine\Tests\ORM\Functional\IdentityMapTest'
);
$suite
->
addTest
(
Locking\AllTests
::
suite
());
$suite
->
addTest
(
Locking\AllTests
::
suite
());
$suite
->
addTest
(
SchemaTool\AllTests
::
suite
());
$suite
->
addTest
(
SchemaTool\AllTests
::
suite
());
...
...
tests/Doctrine/Tests/ORM/Functional/IdentityMapTest.php
0 → 100644
View file @
bb6e54fb
<?php
namespace
Doctrine\Tests\ORM\Functional
;
use
Doctrine\Tests\Models\CMS\CmsUser
,
Doctrine\Tests\Models\CMS\CmsAddress
,
Doctrine\Tests\Models\CMS\CmsPhonenumber
,
Doctrine\ORM\Query
;
require_once
__DIR__
.
'/../../TestInit.php'
;
/**
* IdentityMapTest
*
* Tests correct behavior and usage of the identity map. Local values and associations
* that are already fetched always prevail, unless explicitly refreshed.
*
* @author Roman Borschel <roman@code-factory.org>
*/
class
IdentityMapTest
extends
\Doctrine\Tests\OrmFunctionalTestCase
{
protected
function
setUp
()
{
$this
->
useModelSet
(
'cms'
);
parent
::
setUp
();
}
public
function
testSingleValuedAssociationIdentityMapBehavior
()
{
$address
=
new
CmsAddress
;
$address
->
country
=
'de'
;
$address
->
zip
=
'12345'
;
$address
->
city
=
'Berlin'
;
$user1
=
new
CmsUser
;
$user1
->
status
=
'dev'
;
$user1
->
username
=
'romanb'
;
$user1
->
name
=
'Roman B.'
;
$user2
=
new
CmsUser
;
$user2
->
status
=
'dev'
;
$user2
->
username
=
'gblanco'
;
$user2
->
name
=
'Guilherme Blanco'
;
$address
->
setUser
(
$user1
);
$this
->
_em
->
persist
(
$address
);
$this
->
_em
->
persist
(
$user1
);
$this
->
_em
->
persist
(
$user2
);
$this
->
_em
->
flush
();
$this
->
assertSame
(
$user1
,
$address
->
user
);
//external update to CmsAddress
$this
->
_em
->
getConnection
()
->
executeUpdate
(
'update cms_addresses set user_id = ?'
,
array
(
$user2
->
getId
()));
//select
$q
=
$this
->
_em
->
createQuery
(
'select a, u from Doctrine\Tests\Models\CMS\CmsAddress a join a.user u'
);
$address2
=
$q
->
getSingleResult
();
$this
->
assertSame
(
$address
,
$address2
);
// Should still be $user1
$this
->
assertSame
(
$user1
,
$address2
->
user
);
$this
->
assertTrue
(
$user2
->
address
===
null
);
// But we want to have this external change!
// Solution 1: refresh(), broken atm!
//$this->_em->refresh($address2);
// Solution 2: Alternatively, a refresh query should work
$q
=
$this
->
_em
->
createQuery
(
'select a, u from Doctrine\Tests\Models\CMS\CmsAddress a join a.user u'
);
$q
->
setHint
(
Query
::
HINT_REFRESH
,
true
);
$address3
=
$q
->
getSingleResult
();
$this
->
assertSame
(
$address
,
$address3
);
// should still be the same, always from identity map
// Now the association should be "correct", referencing $user2
$this
->
assertSame
(
$user2
,
$address2
->
user
);
$this
->
assertSame
(
$user2
->
address
,
$address2
);
// check back reference also
// Attention! refreshes can result in broken bidirectional associations! this is currently expected!
// $user1 still points to $address2!
$this
->
assertSame
(
$user1
->
address
,
$address2
);
}
public
function
testCollectionValuedAssociationIdentityMapBehavior
()
{
$user
=
new
CmsUser
;
$user
->
status
=
'dev'
;
$user
->
username
=
'romanb'
;
$user
->
name
=
'Roman B.'
;
$phone1
=
new
CmsPhonenumber
;
$phone1
->
phonenumber
=
123
;
$phone2
=
new
CmsPhonenumber
;
$phone2
->
phonenumber
=
234
;
$phone3
=
new
CmsPhonenumber
;
$phone3
->
phonenumber
=
345
;
$user
->
addPhonenumber
(
$phone1
);
$user
->
addPhonenumber
(
$phone2
);
$user
->
addPhonenumber
(
$phone3
);
$this
->
_em
->
persist
(
$user
);
// cascaded to phone numbers
$this
->
_em
->
flush
();
$this
->
assertEquals
(
3
,
count
(
$user
->
getPhonenumbers
()));
//external update to CmsAddress
$this
->
_em
->
getConnection
()
->
executeUpdate
(
'insert into cms_phonenumbers (phonenumber, user_id) VALUES (?,?)'
,
array
(
999
,
$user
->
getId
()));
//select
$q
=
$this
->
_em
->
createQuery
(
'select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p'
);
$user2
=
$q
->
getSingleResult
();
$this
->
assertSame
(
$user
,
$user2
);
// Should still be the same 3 phonenumbers
$this
->
assertEquals
(
3
,
count
(
$user2
->
getPhonenumbers
()));
// But we want to have this external change!
// Solution 1: refresh().
//$this->_em->refresh($user2); broken atm!
// Solution 2: Alternatively, a refresh query should work
$q
=
$this
->
_em
->
createQuery
(
'select u, p from Doctrine\Tests\Models\CMS\CmsUser u join u.phonenumbers p'
);
$q
->
setHint
(
Query
::
HINT_REFRESH
,
true
);
$user3
=
$q
->
getSingleResult
();
$this
->
assertSame
(
$user
,
$user3
);
// should still be the same, always from identity map
// Now the collection should be refreshed with correct count
$this
->
assertEquals
(
4
,
count
(
$user3
->
getPhonenumbers
()));
}
}
tests/Doctrine/Tests/ORM/Functional/StandardEntityPersisterTest.php
View file @
bb6e54fb
...
@@ -88,7 +88,7 @@ class StandardEntityPersisterTest extends \Doctrine\Tests\OrmFunctionalTestCase
...
@@ -88,7 +88,7 @@ class StandardEntityPersisterTest extends \Doctrine\Tests\OrmFunctionalTestCase
// (change from ArrayCollection to PersistentCollection)
// (change from ArrayCollection to PersistentCollection)
$f3
=
new
ECommerceFeature
();
$f3
=
new
ECommerceFeature
();
$f3
->
setDescription
(
'XVID'
);
$f3
->
setDescription
(
'XVID'
);
$p
->
add
f
eature
(
$f3
);
$p
->
add
F
eature
(
$f3
);
// Now we persist the Feature #3
// Now we persist the Feature #3
$this
->
_em
->
persist
(
$p
);
$this
->
_em
->
persist
(
$p
);
...
...
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