[SOLVED] ReflectionService - getMethodsAnnotatedWith doesn't work in Production Context


(Eric Szperlinski) #1

Hi there,

I have a problem with the ReflectionService (Flow 4.3.3). I try to find all methods in a class that are annotated with an own annotation.

$reflectionService = $this->objectManager->get(\Neos\Flow\Reflection\ReflectionService::class);
    $methods = $reflectionService->getMethodsAnnotatedWith(Application::class, FestimanBase\TakeForMD5::class);

In Development Context I get an array with 2 methods (true result). In Production Context I get an empty array (false result).

But when I call the following in Production Context:

$reflectionService->getMethodAnnotation(Application::class, 'getTextValues', FestimanBase\TakeForMD5::class);

I get the full annotation classname as result (and this is right). So it seems, that the framework recognizes the annotation but only getMethodsAnnotatedWith() doesn’t work!?

Do you have an idea what it could be?

Thanks and kind regards
Eric


(Christian Müller) #2

The ReflectionService should generally not be used for Production use. You might want to use the CompileStatic annotation and functionality to render the list of annotated methods during compilation of proxies. That should work just fine and avoid using the reflection service in production.


(Eric Szperlinski) #3

Hi @christianm,

thanks a lot! I didn’t know this annotation and the way it works. Because of your reply and the Flow documentation I’m a little bit wiser now.

Thanks!
Eric


(Soren Malling) #4

For other having the same issue a great example can be found in the EventSourcing package

Inside the EventListenerLocator, the initializeObject method call a method with the objectmanager as parameter

And this compiles a list in the detectListeners method

Purely for reference to other searching for examples


(Leif Hartmann) #5

Thanks!

I had exactly the same problem and I noticed that the ReflectionService does not cache the array classesByMethodAnnotations. I was able to solve this using CompileStatic.

Here is another example saving all methods annotated with a specific annotation (in this case CallbackTransformer) in an array:

class SomeService
{
    /**
     * @Flow\Inject
     * @var ObjectManagerInterface
     */
    protected $objectManager;

    protected $callbackTransformMethods = [];

    public function initializeObject()
    {
        $this->callbackTransformMethods = static::initializeCallbackTransformMethods($this->objectManager);
    }

    public function addIndexableClassProperties($object, ?array $data): ?array
    {
        if ($data === null) {
            $data = [];
        }

        $className = TypeHandling::getTypeForValue($object);

        if (isset($this->callbackTransformMethods[$className])) {
            foreach($this->callbackTransformMethods[$className] as $method) {
                $data = array_merge($data, $object->$method($data));
            }
        }

        return $data;
    }

    /**
     * @Flow\CompileStatic
     * @param ObjectManagerInterface $objectManager
     */
    protected static function initializeCallbackTransformMethods($objectManager): array
    {
        $methods = [];

        $reflectionService = $objectManager->get(ReflectionService::class);

        $classNames = $reflectionService->getClassesContainingMethodsAnnotatedWith(CallbackTransform::class);

        foreach($classNames as $className) {
            $methods[$className] = $reflectionService->getMethodsAnnotatedWith($className, CallbackTransform::class);
        }

        return $methods;
    }
}