Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-1698

Inconsistent proxy file name & namespace result in __PHP_Incomplete_Class when unserializing entities

    Details

    • Type: Improvement Improvement
    • Status: Reopened
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.2, 2.2.1, 2.3, 2.4
    • Fix Version/s: None
    • Component/s: ORM
    • Security Level: All
    • Labels:

      Description

      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_Incomplete_Class 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.

        Activity

        Benjamin Morel created issue -
        Benjamin Morel made changes -
        Field Original Value New Value
        Description 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 gets a proxy file named:
        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the autoloader assumes the class to be located in:
        {code}
        Application\Proxy\__CG__\Application\Model\User.php
        {code}
        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the autoloader expects the class to be located in:
        {code}
        Application\Proxy\__CG__\Application\Model\User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Hide
        Benjamin Morel added a comment - - edited

        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.

        Show
        Benjamin Morel added a comment - - edited 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.
        Benjamin Morel made changes -
        Affects Version/s 2.2 [ 10157 ]
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the autoloader expects the class to be located in:
        {code}
        Application\Proxy\__CG__\Application\Model\User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:

        {code}

        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:

        {code}

        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:


        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:


        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:

        {code}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {code}
        But the proxy class created is:
        {code}
        Application\Proxy\__CG__\Application\Model\User
        {code}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {code}
        Application/Proxy/__CG__/Application/Model/User.php
        {code}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:

        {noformat}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {noformat}
        But the proxy class created is:
        {noformat}
        Application\Proxy\__CG__\Application\Model\User
        {noformat}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {noformat}
        Application/Proxy/__CG__/Application/Model/User.php
        {noformat}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:

        {noformat}
        Application/Proxy/__CG__ApplicationModelUser.php file.
        {noformat}
        But the proxy class created is:
        {noformat}
        Application\Proxy\__CG__\Application\Model\User
        {noformat}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {noformat}
        Application/Proxy/__CG__/Application/Model/User.php
        {noformat}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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 gets a proxy file named:

        {noformat}
        Application/Proxy/__CG__ApplicationModelUser.php
        {noformat}
        But the proxy class created is:
        {noformat}
        Application\Proxy\__CG__\Application\Model\User
        {noformat}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {noformat}
        Application/Proxy/__CG__/Application/Model/User.php
        {noformat}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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 gets a proxy file named:

        {noformat}
        Application/Proxy/__CG__ApplicationModelUser.php
        {noformat}
        But the proxy class created is:
        {noformat}
        Application\Proxy\__CG__\Application\Model\User
        {noformat}
        When we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:
        {noformat}
        Application/Proxy/__CG__/Application/Model/User.php
        {noformat}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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:

        {noformat}
        Application\Proxy\__CG__\Application\Model\User
        {noformat}

        This class is located in the following file:

        {noformat}
        Application/Proxy/__CG__ApplicationModelUser.php
        {noformat}

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

        {noformat}
        Application/Proxy/__CG__/Application/Model/User.php
        {noformat}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Benjamin Morel made changes -
        Description 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:

        {noformat}
        Application\Proxy\__CG__\Application\Model\User
        {noformat}

        This class is located in the following file:

        {noformat}
        Application/Proxy/__CG__ApplicationModelUser.php
        {noformat}

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

        {noformat}
        Application/Proxy/__CG__/Application/Model/User.php
        {noformat}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        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:

        {noformat}
        Application\Proxy\__CG__\Application\Model\User
        {noformat}

        This class is located in the following file:

        {noformat}
        Application/Proxy/__CG__ApplicationModelUser.php
        {noformat}

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

        {noformat}
        Application/Proxy/__CG__/Application/Model/User.php
        {noformat}

        But it is not.
        As a result, a __PHP_Incomplete_Class 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.
        Hide
        Benjamin Eberlei added a comment -

        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

        Show
        Benjamin Eberlei added a comment - 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
        Show
        Benjamin Eberlei added a comment - See https://github.com/doctrine/doctrine2/commit/9b4d60897dfc7e9b165712428539e694ec596c80 and https://github.com/doctrine/orm-documentation/commit/01381fae1ff3d4944086c7cfe46721925bf6ca15
        Benjamin Eberlei made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Fix Version/s 2.2.2 [ 10195 ]
        Resolution Fixed [ 1 ]
        Hide
        Benjamin Morel added a comment -

        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?

        Show
        Benjamin Morel added a comment - 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?
        Hide
        Benjamin Eberlei added a comment -

        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.

        Show
        Benjamin Eberlei added a comment - 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.
        Benjamin Eberlei made changes -
        Workflow jira [ 13521 ] jira-feedback [ 15271 ]
        Benjamin Eberlei made changes -
        Workflow jira-feedback [ 15271 ] jira-feedback2 [ 17135 ]
        Benjamin Eberlei made changes -
        Workflow jira-feedback2 [ 17135 ] jira-feedback3 [ 19388 ]
        Hide
        Benjamin Morel added a comment -

        @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?

        Show
        Benjamin Morel added a comment - @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?
        Benjamin Morel made changes -
        Resolution Fixed [ 1 ]
        Status Resolved [ 5 ] Reopened [ 4 ]
        Hide
        Benjamin Eberlei added a comment -

        Benjamin Morel 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.

        Show
        Benjamin Eberlei added a comment - Benjamin Morel 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.
        Benjamin Eberlei made changes -
        Issue Type Bug [ 1 ] Documentation [ 6 ]
        Hide
        Benjamin Morel added a comment -

        Ok, thanks for your answer!

        Show
        Benjamin Morel added a comment - Ok, thanks for your answer!
        Hide
        Matthieu Napoli added a comment -

        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

        Show
        Matthieu Napoli added a comment - 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
        Marco Pivetta made changes -
        Fix Version/s 2.2.2 [ 10195 ]
        Marco Pivetta made changes -
        Affects Version/s 2.4 [ 10321 ]
        Affects Version/s 2.3 [ 10185 ]
        Marco Pivetta made changes -
        Issue Type Documentation [ 6 ] Improvement [ 4 ]
        Marco Pivetta made changes -
        Labels proxy
        Marco Pivetta made changes -
        Environment Irrelevant
        Marco Pivetta made changes -
        Assignee Benjamin Eberlei [ beberlei ] Marco Pivetta [ ocramius ]
        Hide
        Chris Hawkins added a comment - - edited

        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' );
        	}
        }
        
        Show
        Chris Hawkins added a comment - - edited 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' ); } }

        This list may be incomplete, as errors occurred whilst retrieving source from linked applications:

        • Request to http://www.doctrine-project.org/fisheye/ failed: Error in remote call to 'FishEye 0 (http://www.doctrine-project.org/fisheye/)' (http://www.doctrine-project.org/fisheye) [AbstractRestCommand{path='/rest-service-fe/search-v1/crossRepositoryQuery', params={query=DDC-1698, expand=changesets[0:20].revisions[0:29],reviews}, methodType=GET}] : Received status code 503 (Service Temporarily Unavailable)

          People

          • Assignee:
            Marco Pivetta
            Reporter:
            Benjamin Morel
          • Votes:
            2 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

            • Created:
              Updated: