Bug #29449
Add safeguard preventing to reflect Doctrine Proxies
Status: | Resolved | Start date: | 2011-09-01 | |
---|---|---|---|---|
Priority: | Must have | Due date: | ||
Assigned To: | Sebastian Kurfuerst | % Done: | 100% |
|
Category: | Reflection | |||
Target version: | TYPO3 Flow Base Distribution - 1.0 beta 2 | |||
PHP Version: | Complexity: | |||
Has patch: | Affected Flow version: |
Description
In some custom application of mine, I have accidentally reflected a doctrine proxy class; which lead to the ReflectionService being called like this:
ReflectionService::reflectClass('TYPO3\FLOW3\Persistence\Doctrine\Proxies\SandstormMediaWorkflowDomainModelProcessInstanceProxy')
The ReflectionService reflected the class, returned the expected result and then saved the information about the above classname in the cache.
Unluckily, the above class implements multiple interfaces:
Doctrine\ORM\Proxy\Proxy
TYPO3\FLOW3\AOP\ProxyInterface
(as also some aspects apply to the above class)
Now, on the next FLOW3 run, the following happens:
- The
Object\Configuration\ConfigurationBuilder
iterates through all available class names, thus it will also iterate overDoctrine\ORM\Proxy\Proxy
- The
ConfigurationBuilder
then asksReflectionService::getDefaultImplementationClassNameForInterface('Doctrine\ORM\Proxy\Proxy')
- The ReflectionService returns our above initial class (....Proxies\SandstormMedia.....Proxy); because that's the only known implementation of the Proxy interface
- then, various weird things can happen... for example
ReflectionService::getMethodTagsValues(...)
might fail because the ...Proxy class could not be loaded by the autoloader.
This leads to errors like:
Uncaught Exception in FLOW3 Class TYPO3\FLOW3\Persistence\Doctrine\Proxies\SandstormMediaWorkflowDomainModelProcessInstanceProxy does not exist thrown in file Packages/Framework/TYPO3.FLOW3/Classes/Reflection/ReflectionService.php in line 595 #0 TYPO3\FLOW3\Error\DebugExceptionHandler::echoExceptionCli() Packages/Framework/TYPO3.FLOW3/Classes/Error/AbstractExceptionHandler.php:60 #1 TYPO3\FLOW3\Error\AbstractExceptionHandler::handleException()
So, the behavior is as follows:
- on first hit, everything works.
- on second hit, at compile time, the system seems to break randomly (took me quite some time to figure out what happens)
Root Cause¶
The issue was caused by some custom package of mine, calling the ReflectionService in a wrong/unspecified way. I did $reflectionService->getClassSchema(get_class($object));
where $object was a doctrine proxy. And this lead to the above behavior.
Possible Solutions¶
We somehow need to prevent the above root cause. For that, I see three possibilities, all of them adding a check to ReflectionService::reflectClass()
- fail silently when detecting that the incoming class name is a doctrine proxy
- throw an exception when detecting that the incoming class name is a doctrine proxy
- when detecting a doctrine proxy, find out the class name the user really wanted to reflect instead, and return this reflection data instead.
3) might have some side-effects; as we would need to touch most of the methods in the ReflectionService, everywhere $this->reflectClass()
is called. That's why my preferred solution is 2).
How to continue¶
I'll fix this issue; I'd just like your opinion which solution you like most.
Greets, Sebastian
Associated revisions
[BUGFIX] (Reflection): Prevent use of ReflectionService for Doctrine Proxies
When calling the ReflectionService with a class name for a doctrine proxy,
really weird side-effects can happen, as the Doctrine Proxy class is then
also stored in the Reflection Cache. On the next compilation run, really
weird side-effects can happen. See the corresponding issue for a full
description.
By throwing an exception when a doctrine class is reflected, we prevent
the issue from appearing in the first place.
Resolves: #29449
Change-Id: Ia709b70e4e31facfd88563c5836009d7cee6d7b2
History
#1 Updated by Robert Lemke almost 4 years ago
We somehow need to prevent the above root cause. For that, I see three possibilities, all of them adding a check to
ReflectionService::reflectClass()
- fail silently when detecting that the incoming class name is a doctrine proxy
- throw an exception when detecting that the incoming class name is a doctrine proxy
- when detecting a doctrine proxy, find out the class name the user really wanted to reflect instead, and return this reflection data instead.
I also opt for 2). The question is if the Doctrine Proxy should be or can be identified by an interface which is part of the FLOW3 package. But that's probably of minor importance.
#2 Updated by Karsten Dambekalns almost 4 years ago
- Status changed from New to Accepted
Definitely solution 2)
#3 Updated by Karsten Dambekalns almost 4 years ago
Robert Lemke wrote:
The question is if the Doctrine Proxy should be or can be identified by an interface which is part of the FLOW3 package.
Why? There are a number of places where code is tied to Doctrine, and if it is, this should be visible IMHO. Effectively hiding that fact in some other interface name doesn't help, does it?
#4 Updated by Mr. Hudson almost 4 years ago
- Status changed from Accepted to Under Review
Patch set 1 of change Ia709b70e4e31facfd88563c5836009d7cee6d7b2 has been pushed to the review server.
It is available at http://review.typo3.org/4738
#5 Updated by Sebastian Kurfuerst almost 4 years ago
- Status changed from Under Review to Resolved
- % Done changed from 0 to 100
Applied in changeset 98f877bb3524bff1db2c991b494d1cc10682c2ad.