Bug #58153

Session - Scope, Property with interface annotation fails at wakeup

Added by Ferdinand Kuhl over 1 year ago. Updated over 1 year ago.

Status:New Start date:2014-04-24
Priority:Should have Due date:
Assigned To:- % Done:

0%

Category:AOP
Target version:TYPO3 Flow Base Distribution - 2.1
PHP Version:5.4 Complexity:
Has patch:No Affected Flow version:Flow 2.0.0

Description

Assume I have an Object called Vendor\Package\Service\PackageSession which has Session scope. This object has a property, which is annotated with an interface, which some of my domain objects may implement.

If this object is reconstituted the AOP Proxy crashes during wakeup with the following trace:

Uncaught exception in line 40 of Packages/Libraries/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php: Class 'Vendor\Package\Domain\Model\EntityInterface' does not exist

40 Doctrine\Common\Persistence\Mapping\MappingException::nonExistingClass("Vendor\Package\Domain\Model\EntityInterface")
39 Doctrine\Common\Persistence\Mapping\RuntimeReflectionService::getParentClasses("Vendor\Package\Domain\Model\EntityInterface")
38 Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory::getParentClasses("Vendor\Package\Domain\Model\EntityInterface")
37 Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory::loadMetadata("Vendor\Package\Domain\Model\EntityInterface")
36 Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory::getMetadataFor("Vendor\Package\Domain\Model\EntityInterface")
35 Doctrine\ORM\EntityManager::getReference("Vendor\Package\Domain\Model\EntityInterface", "072e6c49-6a9a-a791-bbc3-91a502d73e83")
34 TYPO3\Flow\Persistence\Doctrine\PersistenceManager_Original::getObjectByIdentifier("072e6c49-6a9a-a791-bbc3-91a502d73e83", "Vendor\Package\Domain\Model\EntityInterface", TRUE)
33 TYPO3\Flow\Persistence\Doctrine\PersistenceManager::getObjectByIdentifier("072e6c49-6a9a-a791-bbc3-91a502d73e83", "Vendor\Package\Domain\Model\EntityInterface", TRUE)
32 call_user_func_array(array|2|, array|3|)
31 TYPO3\Flow\Persistence\Doctrine\PersistenceManager::Flow_Aop_Proxy_invokeJoinPoint(TYPO3\Flow\Aop\JoinPoint)
30 TYPO3\Flow\Aop\Advice\AdviceChain::proceed(TYPO3\Flow\Aop\JoinPoint)
29 TYPO3\Flow\Security\Aspect\PersistenceQueryRewritingAspect_Original::checkAccessAfterFetchingAnObjectByIdentifier(TYPO3\Flow\Aop\JoinPoint)
28 TYPO3\Flow\Aop\Advice\AroundAdvice::invoke(TYPO3\Flow\Aop\JoinPoint)
27 TYPO3\Flow\Aop\Advice\AdviceChain::proceed(TYPO3\Flow\Aop\JoinPoint)
26 TYPO3\Flow\Persistence\Doctrine\PersistenceManager::getObjectByIdentifier("072e6c49-6a9a-a791-bbc3-91a502d73e83", "Vendor\Package\Domain\Model\EntityInterface", TRUE)
25 Vendor\Package\Service\PackageSession::__wakeup()
[...]

The Problem is that the proxy-class builder generates the following code:

<?php
if ($this->$propertyName instanceof \TYPO3\Flow\Persistence\Aspect\PersistenceMagicInterface && !\TYPO3\Flow\Core\Bootstrap::$staticObjectManager->get('TYPO3\Flow\Persistence\PersistenceManagerInterface')->isNewObject($this->$propertyName) || $this->$propertyName instanceof \Doctrine\ORM\Proxy\Proxy) {
    if (!property_exists($this, 'Flow_Persistence_RelatedEntities') || !is_array($this->Flow_Persistence_RelatedEntities)) {
        $this->Flow_Persistence_RelatedEntities = array();
        $this->Flow_Object_PropertiesToSerialize[] = 'Flow_Persistence_RelatedEntities';
    }
    $identifier = \TYPO3\Flow\Core\Bootstrap::$staticObjectManager->get('TYPO3\Flow\Persistence\PersistenceManagerInterface')->getIdentifierByObject($this->$propertyName);
    if (!$identifier && $this->$propertyName instanceof \Doctrine\ORM\Proxy\Proxy) {
        $identifier = current(\TYPO3\Flow\Reflection\ObjectAccess::getProperty($this->$propertyName, '_identifier', TRUE));
    }
    $this->Flow_Persistence_RelatedEntities[$propertyName] = array(
        'propertyName' => $propertyName,
        'entityType' => $className,
        'identifier' => $identifier
    );
    continue;
}
?>

Of course the interface is known to the ObjectManager, so the interface name stays in class name. Correct behaviour would be to ask the object for its class name. Interesting is, that if a doctrine-proxy is set this way, everything works as expected

History

#1 Updated by Ferdinand Kuhl over 1 year ago

Sorry, the above snippet from ProxyBuilder is the wrong snippet.

The problem is here:

<?php
/**
    * Autogenerated Proxy Method
    */
    public function __sleep() {
    [...]
foreach ($allReflectedProperties as $reflectionProperty) {
    [...]
    if (is_object($this->$propertyName) && !$this->$propertyName instanceof \Doctrine\Common\Collections\Collection) {
        if ($this->$propertyName instanceof \Doctrine\ORM\Proxy\Proxy) {
            $className = get_parent_class($this->$propertyName);
        } else {
            $varTagValues = $reflectionService->getPropertyTagValues('Vendor\Package\Service\PackageSession', $propertyName, 'var');
            if (count($varTagValues) > 0) {
                $className = trim($varTagValues[0], '\\');
            }
            if (\TYPO3\Flow\Core\Bootstrap::$staticObjectManager->isRegistered($className) === FALSE) {
                $className = \TYPO3\Flow\Core\Bootstrap::$staticObjectManager->getObjectNameByClassName(get_class($this->$propertyName));
            }
        }
        [...]
    }
    $this->Flow_Object_PropertiesToSerialize[] = $propertyName;
}
$result = $this->Flow_Object_PropertiesToSerialize;
    return $result;
}

?>
</pre

Also available in: Atom PDF