Bug #47975

initializeObject in a Entity is called at a time where no properties are loaded

Added by Benno Weinzierl about 2 years ago. Updated about 1 year ago.

Status:Resolved Start date:2013-05-06
Priority:Must have Due date:
Assigned To:Robert Lemke % Done:

0%

Category:Object
Target version:TYPO3 Flow Base Distribution - 2.0.1
PHP Version:5.4 Complexity:
Has patch:No Affected Flow version:Git master

Description

I have an Entity which is loaded during validation of a Action Argument. (The Action Argument is another Entity with relations to the Entity in question)

When initializeObject() is called all properties are missing and have not been loaded from persistence.

Here is the Backtrace:
https://gist.github.com/anonymous/5524256


Related issues

duplicates TYPO3.Flow - Bug #43659: Proxy class building calls __construct and initializeObje... Resolved 2012-12-06

History

#1 Updated by Alexander Berl about 2 years ago

The real problem is, that the Doctrine Proxy __load() calls __wakeup() before the properties are actually loaded.

Here's a pseudo call stack for the class hierarchy of the proxies to original class, when the doctrine proxy is the entry point:

Class hierarchy:    Doctrine Proxy (DP) > Flow Proxy (FP) > Original Class (OC)

Call stack1: Doctrine Proxy gets loaded due to property access or via the GenericObjectValidator
DP->__load()
    DP->__wakeup()
        DP->__load()
        FP->__wakeup()
            OC->__wakeup()
            DP->initializeObject(2)
                DP->__load()
                OC->initializeObject()
DP->_entityPersister->load($this->_identifier, $this)

Call stack2: Doctrine Proxy gets unserialized (e.g. unserialize('O:...') hacks used both in Flow and Doctrine)
DP->__wakeup()
    DP->__load() [I think this is not really executed, since $this->_entityPersister would be empty in an empty unserialization]
    FP->__wakeup()
        OC->__wakeup()
        DP->initializeObject(2)
            DP->__load()
            OC->initializeObject()

Indentation refers to the call nesting level. As you can see, in both cases the initializeObject method gets called before the object properties are loaded. However, I'm not sure how to best deal with the premature __wakeup() in __load() and preventing empty unserialization wakeups from triggering initializeObject.

A possible check could be that if __isInitialized__ is set and true and __entityPersister is set, or if __isInitialized__ is set and false then skip the initializeObject invokation in the FlowProxy. You'd completely loose the initializeObject call in those cases though and at least in the first this is not desired I guess.

#2 Updated by rottenrice no-lastname-given about 2 years ago

I have the same problem but my call stack differs from your call stack.

My two Entities:

 /** @Flow\Entity */
 class Foo {
  public function __construct() {
   echo '__construct()';
  } 
  public function initializeObject($arg) {
   echo 'initializeObject('.$arg.')';
  }
  public function injectSettings() {
   echo 'injectSettings()';
  }
 }

 /** @Flow\Entity */
 class Bar extends Foo {
  public function __construct() {
   echo '__construct()';
   parent::__construct();
  } 
 }

Example code:

 $bar = new Bar();

Output:

 __construct()
 __construct()
 initializeObject(1)
 injectSettings()
 initializeObject(1)

Reason:
__construct() of Flow-Proxy (Foo)

 [...]

 if ('Foo' === get_class($this)) {
  $this->Flow_Proxy_injectProperties();
 }
 $this->initializeObject(1);

The injectProperties() in not executed but the initializeObject() is executed :/

#3 Updated by Adrian Föder about 2 years ago

I also had that; and I realized it's because of this gem here:

\Doctrine\ORM\Mapping\ClassMetadataInfo::newInstance

1    public function newInstance()
2    {
3        if ($this->_prototype === null) {
4            $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
5        }
6
7        return clone $this->_prototype;
8    }

This is a dummy way to get an object without the constructor being called; but unfortunately this calls __wakeup and hence initializeObject(), of course without any properties then.

At the end, I had initializeObject() being called twice, once in that erroneous case and once when it's actually intended.

#4 Updated by Robert Lemke about 2 years ago

  • Status changed from New to Accepted

Needs to be verified and solved for 2.0

#5 Updated by Karsten Dambekalns almost 2 years ago

  • Target version changed from 2.0 to 2.0.1

#6 Updated by Robert Lemke almost 2 years ago

  • Category changed from Persistence to Object
  • Assigned To set to Robert Lemke
  • PHP Version set to 5.4

#7 Updated by Robert Lemke almost 2 years ago

I think that this is a duplicate of #43659

#8 Updated by Robert Lemke almost 2 years ago

  • Status changed from Accepted to Closed

Let's see if the fix for #43659 helps

#9 Updated by Andreas Förthner almost 2 years ago

  • Status changed from Closed to New

The problem still exists, opening the issue again...

#10 Updated by Robert Lemke about 1 year ago

  • Status changed from New to Resolved

Also available in: Atom PDF