Bug #27088

initializeObject() is called too early when reconstructing entities

Added by Andreas Förthner almost 2 years ago. Updated about 1 month ago.

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

0%

Category:Object
Target version:-
PHP Version: Complexity:
Has patch:No FLOW3 version affected:FLOW3 1.0.0
Votes: 3 (View)

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

Updated by Karsten Dambekalns almost 2 years ago

  • Assignee set to Karsten Dambekalns

Updated by Karsten Dambekalns almost 2 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?

Updated by Karsten Dambekalns almost 2 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;
    }

Updated by Sebastian Kurfuerst almost 2 years ago

  • Priority changed from Must have to Should have

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

Updated by Lienhart Woitok almost 2 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.

Updated by Robert Lemke over 1 year ago

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

Updated by Robert Lemke over 1 year ago

  • Target version changed from 1.0 beta 2 to 1.0.0

Updated by Karsten Dambekalns over 1 year ago

  • Assignee deleted (Karsten Dambekalns)

Updated by Karsten Dambekalns over 1 year ago

  • Target version changed from 1.0.0 to 1.0.1

Updated by Karsten Dambekalns over 1 year ago

  • FLOW3 version affected set to FLOW3 1.0.0

Updated by Karsten Dambekalns over 1 year ago

  • Target version changed from 1.0.1 to 1.0.2

Updated by Karsten Dambekalns over 1 year ago

  • Target version changed from 1.0.2 to 1.0.3

Updated by Karsten Dambekalns about 1 year ago

  • Target version changed from 1.0.3 to 1.0.4

Updated by Karsten Dambekalns about 1 year ago

  • Target version changed from 1.0.4 to 1.0.5

Updated by Karsten Dambekalns 12 months ago

  • Target version changed from 1.0.5 to 1.1 RC1

Updated by Karsten Dambekalns 11 months ago

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

Updated by Adrian Föder about 1 month 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