[DDC-1452] ObjectHydrator bug: hydration of entity with self (cyclic) relation through ref entity Created: 24/Oct/11  Updated: 15/Nov/11  Resolved: 14/Nov/11

Status: Resolved
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.1, 2.1.1, 2.1.2
Fix Version/s: 2.2
Security Level: All

Type: Bug Priority: Critical
Reporter: Piotr Śliwa Assignee: Benjamin Eberlei
Resolution: Fixed Votes: 0
Labels: None

Attachments: File DDC1452Test.php     File DDC1452Test.php    

 Description   

ObjectHydrator has bug in hydrate entities with relation to entity of this same class throught reference entity. Example Model:

EntityA

  • id
  • title (string)
  • entitiesB (annotation: @ORM\OneToMany(targetEntity="EntityB", mappedBy="entityAFrom"))

EntityB

  • id
  • entityAFrom (annotation: @ORM\ManyToOne(targetEntity="EntityA", inversedBy="entitiesB"))
  • entityATo (annotation: @ORM\ManyToOne(targetEntity="EntityA"))
  • type (string)

Scenario:

Execution of dql query 'SELECT a, b, ba FROM EntityA AS a LEFT JOIN a.entitiesB AS b LEFT JOIN b.entityATo AS ba' with max results set to "1" and data in database:

EntityATable:
id | title
1 | a
2 | b

EntityBTable:
id | entityAFromId | entityAToId | type
1 | 1 | 2 | type

Resume:

I expected collection of EntityA object (size=1 becouse I set max results to 1) with hydrated entitiesB collection (size=1 becouse in db is only 1 record) and hydrated entityTo object. entitiesB property of entityTo object should be empty PersistCollection (ready to lazy load) but is null...

I can provide TestCase for this issue.



 Comments   
Comment by Benjamin Eberlei [ 28/Oct/11 ]

Attached a working testcase.

Please put it into tests/Doctrine/Tests/ORM/Functional/Ticket and run:

phpunit --group DDC-1452

Please make that test fail from your perspective, i think it reproduces your test-case exactly.

Comment by Piotr Śliwa [ 29/Oct/11 ]

Ok, I have fixed testcase to situation that I was talking about.

I have hardly debuged this issue, problem is in ObjectHydrator::_getEntity() method. This method delegates to UnitOfWork::createEntity() and passes $hints array. In $hints array, data about fetching associations is stored. In situation when one entity is joined throught two different associations (as in this testcase, first time DDC1452EntityA is used in from clause, second time in join clause) hydrator "minds" that objects from second association have have loaded association that is connecting entities of the same type. In testcase this is "entitiesB" association of "ba" aliased entity. That occurs, becouse $hints['fetched']['Namespace\DDC1452EntityA']['entitiesB'] has already been set on true while hydrating DDC1452EntityA objects from "FROM" clause. If in testcase had not been set limit for results, then this test would have to pass, becouse second object of DDC1452EntityA ($a2) would have to be load propertly as entity from "FROM" clause.

Comment by Benjamin Eberlei [ 29/Oct/11 ]

The explaination makes sense. I will dig into it.

Comment by Benjamin Eberlei [ 14/Nov/11 ]

This is fixed, but only in master. The code change necessary was pretty serious so i dont want to merge it into the stable branch without more people testing it.

Comment by Piotr Śliwa [ 15/Nov/11 ]

Great job, thanks!

Generated at Thu Oct 30 19:06:34 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.