DDC-1698: Inconsistent proxy file name & namespace result in __PHP_Incomplete_Class when unserializing entities #2345

Open
doctrinebot opened this Issue Mar 13, 2012 · 10 comments

2 participants

@doctrinebot

Jira issue originally created by user benjamin:

Starting with Doctrine 2.2, the Proxy classes have inconsistent naming with their file name, which raises problems with class autoloading.
For example, a class named Application\Model\User creates the following proxy class:

Application\Proxy\*_CG_*\Application\Model\User

This class is located in the following file:

Application/Proxy/*_CG_*ApplicationModelUser.php

But whe we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:

Application/Proxy/*_CG_*/Application/Model/User.php

But it is not.
As a result, a _PHP_IncompleteClass is created instead of the expected proxy class.

I'm not sure whether this is an intended behavior, but I would assume this is a bug.

@doctrinebot

Comment created by benjamin:

It looks like there is an even broader problem with the new CG prefix; the PSR-0 standard for autoloading states that the underscores should be handled this way:

\namespace\package\Class_Name => {...}/namespace/package/Class/Name.php

Which means that in the above example, it could even expect the file to be located in:

Application/Proxy///CG///Application/Model/User.php

... which is far away from the actual location.
Upgrade to 2.2 broke this code, for us.

@doctrinebot

Comment created by @beberlei:

Proxy classes do not follow PSR-0. For the case unserializing objects we should provide an extra autoloader i guess.

See here how symfony does it https://github.com/doctrine/DoctrineBundle/blob/master/DoctrineBundle.php#L57

@doctrinebot

Comment created by benjamin:

Thanks for the quick fix, Benjamin.
However, I have to admit that I'm not fully happy with the fix, as we (and probably many others) are not using the Doctrine autoloader.
I supposed that the purpose of PSR-0 was precisely not to be tied to a particular autoloader implementation, and this benefit is lost with this version of Doctrine.

You mentioned in the doc that the proxies are not PSR-0 compliant "for implementation reasons"; as this was working fine before 2.2, could you please explain what requirement prevents Doctrine from keeping the previous naming convention?

@doctrinebot

Comment created by @beberlei:

In 2.1 the proxies are not PSR-0 compatible themselves, however their class naming is simpler.

In 2.2 we changed proxy names so that you can derive the original name of the proxy by searching for the CG_ flag. This flag obviously contains the _ chars that some PSR autoloaders detect as directory seperators. I agree this is an unfortunate decision, but it was done this way.

I do think however that we can automatically register the proxy atuoloader (if not yet done) in EntityManager#create(). This would hide this fact from developers automatically.

@doctrinebot

Comment created by benjamin:

@Benjamin Eberlei
In 2.3 we still have to manually call Autoloader::register() before unserializing entities that may contain proxies.
So EntityManager::create() still doesn't register it. Is there a plan to add this feature?

@doctrinebot

Comment created by @beberlei:

[~benjamin] Not at the moment, seems too dangerous for me since it might produce race conditions. This should really be done in the bootstrap of the system.

We need to document this though.

@doctrinebot

Comment created by benjamin:

Ok, thanks for your answer!

@doctrinebot

Comment created by mnapoli:

Sorry to be a pain, but can the description of the task be updated:

  • Affects Version/s: should show all versions (or none) but not just 2.2, 2.2.1
  • Fix Version/s: should be blank

This is to make it clear that this bug is not resolved (since we are way past v2.2.2).

Thanks

@doctrinebot

Comment created by chawkinsuf:

Some additional documentation about this would be useful. I just spent some considerable time diagnosing an error related to restoring an entity from a cache. I wasn't able to find a mention of the need to call Autoloader::register until I found this page. It was resolved fairly quickly after I found this. For reference, I added this to my bootstrap:

ini*set('unserialize_callback*func', 'proxymissing');
function proxymissing( $name ) {
    if ( preg_match( '/^DoctrineProxies/', $name ) ) {
        \Doctrine\ORM\Proxy\Autoloader::register( PROXYPATH, 'DoctrineProxies' );
    }
}
@Ocramius Ocramius was assigned by doctrinebot Dec 6, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment