Considering this test script:
Things are going wrong in the unserialization. In this test script, I manage to create two objects holding the same oid, but pointing at different object instances (but for the same database id). The output of this script after running it twice shows me:
Looking at the unserialize() code in Doctrine_Record, the problem seems to be coming from two issues in there:
- $this->_oid is generated before the data unserialization. Because of this, the generated $this->_oid is overwritten with whatever was in the serialized data (this is why in above example, the oid became 5 for the unserialized record)
- The unserialized record is not added to the table's identitymap, making it kind of invisible for the table's getRecord() code, resulting in two different objects that both represent the entity with id = 4 (as you can see in the "24 versus 23" output).
See the attached patch for a fix that I did on our code tree to make the test work.
Note that I added some extra code in the unserialize method to cleanup any existing entitymap and table repository entry for the unserialized object. This is of course not the best route, but it helps with some unit testing code where a lot of serialize/unserialize handling is going on and objects got mixed up when not doing this cleanup.
IMO, better would be to add an unserialization method to the Doctrine_Table, which would, like find(), act as a factory for turning unserialized record data into a Doctrine_Record object, possibly making use of already loaded entities that are available in the table's internal caches. With unserialize being handled directly from the Doctrine_Record, there is no way AFAICS to keep up the rule of always having exactly one object in a scope that represents a certain object in the database.
When running above script with this patch applied and with removing the $a, $b and $c assignments (just for making the oid's different between the two script runs), we get the following output:
So here, unserializing an object and then reloading the object through the table object gives use two times the same object, representing db object with id = 4;
When doing things in a different order, we still can force an issue, but this is due to the things mentioned above: to cleanly handle this, unserialization should be handled from a factory method on Table. This script shows the behavior:
The output of the second run being:
The first object that was created is still different from the unserialized object, but at least the third object that is created, is the object that was unserialized.
I hope that this makes the issue clear and that my input helps in fixing things. This issue provided us with some really unexpected behavior and we're glad that we were able to track it down to here.