Bug #27088

initializeObject() is called too early when reconstructing entities

Added by Andreas Förthner about 4 years ago. Updated over 2 years ago.

Status:On Hold Start date:2011-05-27
Priority:Should have Due date:
Assigned To:- % Done:

0%

Category:Object
Target version:-
PHP Version: Complexity:
Has patch:No Affected Flow version:FLOW3 1.0.0

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.

History

#1 Updated by Karsten Dambekalns about 4 years ago

  • Assigned To set to Karsten Dambekalns

#2 Updated by Karsten Dambekalns about 4 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 about 4 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 almost 5 years ago

  • Priority changed from Must have to Should have

@Andi: can you provide feedback here? Else, I'll defer it to beta2...

#5 Updated by Lienhart Woitok almost 5 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 almost 4 years ago

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

#7 Updated by Robert Lemke almost 4 years ago

  • Target version changed from 1.0 beta 2 to 1.0.0

#8 Updated by Karsten Dambekalns almost 4 years ago

  • Assigned To deleted (Karsten Dambekalns)

#9 Updated by Karsten Dambekalns almost 4 years ago

  • Target version changed from 1.0.0 to 1.0.1

#10 Updated by Karsten Dambekalns almost 4 years ago

  • Affected Flow version set to FLOW3 1.0.0

#11 Updated by Karsten Dambekalns over 3 years ago

  • Target version changed from 1.0.1 to 1.0.2

#12 Updated by Karsten Dambekalns over 3 years ago

  • Target version changed from 1.0.2 to 1.0.3

#13 Updated by Karsten Dambekalns over 3 years ago

  • Target version changed from 1.0.3 to 1.0.4

#14 Updated by Karsten Dambekalns over 3 years ago

  • Target version changed from 1.0.4 to 1.0.5

#15 Updated by Karsten Dambekalns about 3 years ago

  • Target version changed from 1.0.5 to 1.1 RC1

#16 Updated by Karsten Dambekalns about 3 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 over 2 years ago

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

 1    /**
 2     * Creates a new instance of the mapped class, without invoking the constructor.
 3     *
 4     * @return object
 5     */
 6    public function newInstance()
 7    {
 8        if ($this->_prototype === null) {
 9            $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
10        }
11
12        return clone $this->_prototype;
13    }

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