2

I have created custom annotations to generate JSON files (for NodeRed if you ask...) and i'm testing them successfully from a dummy method in a dummy controller.

I would like to port all that to a custom Sf command whose job would be to read all Controllers annotations in my bundle and achieve the same result (aka create JSON files).

How could i achieve that ? Would looping through XxxxController.php file(s) with the finder be a good option ? Or am too ambitious ? :p

Annotation example:

/**
 * @NodeRedFlows(
 *     triggerBy="testFlow", options={"interval":"45"}  
 * )
 */
 public function indexAction() { /*...*/ }

Sorry its not easy to post some more code because i have the whole reader class, the annotation class and another class creating JSON flows based on the triggerBy="testFlow" id.

Bottom line:*

I would like to be able to create my JSON flow file from a Command instead of here in my Controller (used it for tests).

Romain Bruckert
  • 2,546
  • 31
  • 50

1 Answers1

2

Load all controller actions, which have been assigned a route in Symfony (see this and this).

Then load the annotations for every found controller action:

use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\HttpFoundation\Request;

$annotationReader = new AnnotationReader();
$routes = $this->container->get('router')->getRouteCollection()->all();
$this->container->set('request', new Request(), 'request');

foreach ($routes as $route => $param) {
    $defaults = $params->getDefaults();

    if (isset($defaults['_controller'])) {
         list($controllerService, $controllerMethod) = explode(':', $defaults['_controller']);
         $controllerObject = $this->container->get($controllerService);
         $reflectedMethod = new \ReflectionMethod($controllerObject, $controllerMethod);

         // the annotations
         $annotations = $annotationReader->getMethodAnnotations($reflectedMethod );
    }
}

UPDATE:

If you need all controller methods, including those without the @Route annotation, then I would do what you suggest in your question:

// Load all registered bundles
$bundles = $this->container->getParameter('kernel.bundles');

foreach ($bundles as $name => $class) {
    // Check these are really your bundles, not the vendor bundles
    $bundlePrefix = 'MyBundle';
    if (substr($name, 0, strlen($bundlePrefix)) != $bundlePrefix) continue;

    $namespaceParts = explode('\\', $class);
    // remove class name
    array_pop($namespaceParts);
    $bundleNamespace = implode('\\', $namespaceParts);
    $rootPath = $this->container->get('kernel')->getRootDir().'/../src/';
    $controllerDir = $rootPath.$bundleNamespace.'/Controller';

    $files = scandir($controllerDir);
    foreach ($files as $file) {
        list($filename, $ext) = explode('.', $file);
        if ($ext != 'php') continue;

        $class = $bundleNamespace.'\\Controller\\'.$filename;
        $reflectedClass = new \ReflectionClass($class);

        foreach ($reflectedClass->getMethods() as $reflectedMethod) {
            // the annotations
            $annotations = $annotationReader->getMethodAnnotations($reflectedMethod);
        }
    }
}
Community
  • 1
  • 1
Genti Saliu
  • 2,643
  • 4
  • 23
  • 43
  • Thanks, but the comment don't always have a @Route annotation... Besides, the line "$controllerObject = $container->get($controllerService);" give the error: " You cannot create a service ("request") of an inactive scope ("request").". It seems this is going in the right direction thought. – Romain Bruckert May 25 '15 at 13:24
  • I updated the answer to address the `You cannot create a service ("request") of an inactive scope ("request")`. error – Genti Saliu May 25 '15 at 13:32
  • Updated the answer to include actions without `@Route` annotation too. I haven't tested the code, but it should work. – Genti Saliu May 25 '15 at 13:49
  • Thank you. I'll go with your first solution, on afterthoughts. It works well (i've change the Reflection to avoid the `You cannot create a service ("request") of an inactive scope ("request")` error but i get double annotations strangely – Romain Bruckert May 25 '15 at 14:04
  • Just do `$this->container->set('request', new Request(), 'request');` to avoid the error. – Genti Saliu May 25 '15 at 14:09
  • Got it. I got double annotations because the loop first get ALL routes. And then annotation is again an array... – Romain Bruckert May 25 '15 at 14:26
  • Warning: array_pop does not return an array but the last value. – Romain Bruckert May 26 '15 at 09:45
  • Awesome - just got it working. You just saved me headache! – MistaJase Dec 31 '15 at 09:06