Bug #27088

initializeObject() is called too early when reconstructing entities

Added by Andreas Förthner over 9 years ago. Updated almost 8 years ago.

Status:
On Hold
Priority:
Should have
Assignee:
-
Category:
Object
Target version:
-
Start date:
2011-05-27
Due date:
% Done:

0%

Estimated time:
PHP Version:
Has patch:
No
Complexity:

Description

As it is called in __wakeup(), Doctrine did not yet inject the persisted properties, this is not what we want. The object should be fully initialized (DI and Persistence) when initializeObject() ist called. The same is true for objects fetched from persistence.

#1

Updated by Karsten Dambekalns over 9 years ago

  • Assignee set to Karsten Dambekalns
#2

Updated by Karsten Dambekalns over 9 years ago

  • Status changed from New to Needs Feedback

Well, looking at one of the proxies it seems the data should be loaded before the initializeObject() call:

    /**
     * Fetches the identifier from the set content object. If that
     * is not using automatically introduced UUIDs by FLOW3 it tries
     * to call persistAll() and fetch the identifier again. If it still
     * fails, an exception is thrown.
     *
     * @return void
     */
    public function initializeObject()
    {
        $this->__load();
        return parent::initializeObject();
    }

Can you provide sample code that shows the error?

#3

Updated by Karsten Dambekalns over 9 years ago

The above is the Doctrine proxy, here is the FLOW3 proxy:

    /**
     * Autogenerated Proxy Method
     */
     public function __wakeup() {
        $this->FLOW3_AOP_Proxy_buildMethodsAndAdvicesArray();

    if (property_exists($this, 'FLOW3_Persistence_RelatedEntities') && is_array($this->FLOW3_Persistence_RelatedEntities)) {
        $persistenceManager = \F3\FLOW3\Core\Bootstrap::$staticObjectManager->get('F3\FLOW3\Persistence\PersistenceManagerInterface');
        foreach ($this->FLOW3_Persistence_RelatedEntities as $entityInformation) {
            $this->$entityInformation['propertyName'] = $persistenceManager->getObjectByIdentifier($entityInformation['identifier'], $entityInformation['entityType']);
        }
        unset($this->FLOW3_Persistence_RelatedEntities);
    }
                $this->FLOW3_Proxy_injectProperties();
        $result = NULL;
        if (is_callable('parent::__wakeup')) parent::__wakeup();

        $this->initializeObject(2);
        return $result;
    }
#4

Updated by Sebastian Kurfuerst over 9 years ago

  • Priority changed from Must have to Should have

Andreas Förthner: can you provide feedback here? Else, I'll defer it to beta2...

#5

Updated by Lienhart Woitok over 9 years ago

At least one case where this happens is when reconstituting objects from db. Not with lazy loading, but completely create them at once. Doctrine creates the class by unserializing an empty object of the entity class and then fills it with the properties. But unserialize does call __wakeup() and therefore initializeObject(). I think this changed at some point in Doctrine, when Andi reported this I believe Doctrine unserialized every new instance, but in current version I find that the unserialized instance is cached in Doctrine (which might lead to even more unpredictable behavior in this context). Hope this clears it up a bit.

Currently, I work around this by defining initializeObject() as a PostLoad lifecycle callback and check that everything I need is there before doing anything.

#6

Updated by Robert Lemke over 9 years ago

  • Target version changed from 1.0 beta 1 to 1.0 beta 2
#7

Updated by Robert Lemke over 9 years ago

  • Target version changed from 1.0 beta 2 to 1.0.0
#8

Updated by Karsten Dambekalns over 9 years ago

  • Assignee deleted (Karsten Dambekalns)
#9

Updated by Karsten Dambekalns over 9 years ago

  • Target version changed from 1.0.0 to 1.0.1
#11

Updated by Karsten Dambekalns about 9 years ago

  • Target version changed from 1.0.1 to 1.0.2
#12

Updated by Karsten Dambekalns about 9 years ago

  • Target version changed from 1.0.2 to 1.0.3
#13

Updated by Karsten Dambekalns almost 9 years ago

  • Target version changed from 1.0.3 to 1.0.4
#14

Updated by Karsten Dambekalns almost 9 years ago

  • Target version changed from 1.0.4 to 1.0.5
#15

Updated by Karsten Dambekalns over 8 years ago

  • Target version changed from 1.0.5 to 1.1 RC1
#16

Updated by Karsten Dambekalns over 8 years ago

  • Status changed from Needs Feedback to On Hold
  • Target version deleted (1.1 RC1)
  • Has patch set to No
#17

Updated by Adrian Föder almost 8 years ago

Also stumbled upon that behavior currently.
Note #5 boils it down; in \Doctrine\ORM\Mapping\ClassMetadataInfo::newInstance you can find

    /**
     * Creates a new instance of the mapped class, without invoking the constructor.
     *
     * @return object
     */
    public function newInstance()
    {
        if ($this->_prototype === null) {
            $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
        }

        return clone $this->_prototype;
    }

Line 9 in that example calls, e.g., unserialize("O:52:"Acme\Acme\Domain\Model\Foo\Bar":0:{}"), which invokes __wakeup and immediately after that, initializeObject(), but with obviously no data to work on (see what has been unserialized...)

Also available in: Atom PDF