Bug #47975

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

Added by Benno Weinzierl almost 8 years ago. Updated almost 7 years ago.

Status:
Resolved
Priority:
Must have
Assignee:
Category:
Object
Start date:
2013-05-06
Due date:
% Done:

0%

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

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

Is duplicate of TYPO3.Flow - Bug #43659: Proxy class building calls __construct and initializeObject before DI objects are presentResolvedRobert Lemke2012-12-06

Actions
#1

Updated by Alexander Berl almost 8 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 almost 8 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 almost 8 years ago

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

\Doctrine\ORM\Mapping\ClassMetadataInfo::newInstance

    public function newInstance()
    {
        if ($this->_prototype === null) {
            $this->_prototype = unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->name), $this->name));
        }

        return clone $this->_prototype;
    }

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 almost 8 years ago

  • Status changed from New to Accepted

Needs to be verified and solved for 2.0

#5

Updated by Karsten Dambekalns over 7 years ago

  • Target version changed from 2.0 to 2.0.1
#6

Updated by Robert Lemke over 7 years ago

  • Category changed from Persistence to Object
  • Assignee set to Robert Lemke
  • PHP Version set to 5.4
#7

Updated by Robert Lemke over 7 years ago

I think that this is a duplicate of #43659

#8

Updated by Robert Lemke over 7 years ago

  • Status changed from Accepted to Closed

Let's see if the fix for #43659 helps

#9

Updated by Andreas Förthner over 7 years ago

  • Status changed from Closed to New

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

#10

Updated by Robert Lemke almost 7 years ago

  • Status changed from New to Resolved

Also available in: Atom PDF