Przeglądaj źródła

[HttpKernel] added support for controllers as arrays and object with an __invoke method

Controllers can now be any valid PHP callable
Fabien Potencier 14 lat temu
rodzic
commit
c6818d8bf7

+ 8 - 2
src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php

@@ -60,7 +60,7 @@ class ControllerResolver implements ControllerResolverInterface
             return false;
         }
 
-        if ($controller instanceof \Closure) {
+        if (is_array($controller) || method_exists($controller, '__invoke')) {
             return $controller;
         }
 
@@ -92,15 +92,21 @@ class ControllerResolver implements ControllerResolverInterface
         if (is_array($controller)) {
             $r = new \ReflectionMethod($controller[0], $controller[1]);
             $repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]);
+        } elseif (is_object($controller)) {
+            $r = new \ReflectionObject($controller);
+            $r = $r->getMethod('__invoke');
+            $repr = get_class($controller);
         } else {
             $r = new \ReflectionFunction($controller);
-            $repr = 'Closure';
+            $repr = $controller;
         }
 
         $arguments = array();
         foreach ($r->getParameters() as $param) {
             if (array_key_exists($param->getName(), $attributes)) {
                 $arguments[] = $attributes[$param->getName()];
+            } elseif ($param->getClass() && $param->getClass()->isInstance($request)) {
+                $arguments[] = $request;
             } elseif ($param->isDefaultValueAvailable()) {
                 $arguments[] = $param->getDefaultValue();
             } else {

+ 28 - 0
tests/Symfony/Tests/Component/HttpKernel/Controller/ControllerResolverTest.php

@@ -36,6 +36,18 @@ class ControllerResolverTest extends \PHPUnit_Framework_TestCase
         $controller = $resolver->getController($request);
         $this->assertSame($lambda, $controller);
 
+        $request->attributes->set('_controller', $this);
+        $controller = $resolver->getController($request);
+        $this->assertSame($this, $controller);
+
+        $request->attributes->set('_controller', array($this, 'controllerMethod1'));
+        $controller = $resolver->getController($request);
+        $this->assertSame(array($this, 'controllerMethod1'), $controller);
+
+        $request->attributes->set('_controller', array('Symfony\Tests\Component\HttpKernel\ControllerResolverTest', 'controllerMethod4'));
+        $controller = $resolver->getController($request);
+        $this->assertSame(array('Symfony\Tests\Component\HttpKernel\ControllerResolverTest', 'controllerMethod4'), $controller);
+
         $request->attributes->set('_controller', 'foo');
         try {
             $resolver->getController($request);
@@ -98,6 +110,14 @@ class ControllerResolverTest extends \PHPUnit_Framework_TestCase
         } catch (\Exception $e) {
             $this->assertInstanceOf('\RuntimeException', $e, '->getArguments() throws a \RuntimeException exception if it cannot determine the argument value');
         }
+
+        $request = Request::create('/');
+        $controller = array(new self(), 'controllerMethod5');
+        $this->assertEquals(array($request), $resolver->getArguments($request, $controller), '->getArguments() injects the request');
+    }
+
+    public function __invoke()
+    {
     }
 
     protected function controllerMethod1($foo)
@@ -111,4 +131,12 @@ class ControllerResolverTest extends \PHPUnit_Framework_TestCase
     protected function controllerMethod3($foo, $bar = null, $foobar)
     {
     }
+
+    static protected function controllerMethod4()
+    {
+    }
+
+    protected function controllerMethod5(Request $request)
+    {
+    }
 }

+ 64 - 0
tests/Symfony/Tests/Component/HttpKernel/HttpKernelTest.php

@@ -88,6 +88,47 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase
         $kernel->handle(new Request());
     }
 
+    public function testHandleWhenNoControllerIsAClosure()
+    {
+        $response = new Response('foo');
+        $dispatcher = new EventDispatcher();
+        $kernel = new HttpKernel($dispatcher, $this->getResolver(function () use ($response) { return $response; }));
+
+        $this->assertSame($response, $kernel->handle(new Request()));
+    }
+
+    public function testHandleWhenNoControllerIsAnObjectWithInvoke()
+    {
+        $dispatcher = new EventDispatcher();
+        $kernel = new HttpKernel($dispatcher, $this->getResolver(new Controller()));
+
+        $this->assertEquals(new Response('foo'), $kernel->handle(new Request()));
+    }
+
+    public function testHandleWhenNoControllerIsAFunction()
+    {
+        $dispatcher = new EventDispatcher();
+        $kernel = new HttpKernel($dispatcher, $this->getResolver('Symfony\Tests\Component\HttpKernel\controller_func'));
+
+        $this->assertEquals(new Response('foo'), $kernel->handle(new Request()));
+    }
+
+    public function testHandleWhenNoControllerIsAnArray()
+    {
+        $dispatcher = new EventDispatcher();
+        $kernel = new HttpKernel($dispatcher, $this->getResolver(array(new Controller(), 'controller')));
+
+        $this->assertEquals(new Response('foo'), $kernel->handle(new Request()));
+    }
+
+    public function testHandleWhenNoControllerIsAStaticArray()
+    {
+        $dispatcher = new EventDispatcher();
+        $kernel = new HttpKernel($dispatcher, $this->getResolver(array('Symfony\Tests\Component\HttpKernel\Controller', 'staticcontroller')));
+
+        $this->assertEquals(new Response('foo'), $kernel->handle(new Request()));
+    }
+
     /**
      * @expectedException LogicException
      */
@@ -140,3 +181,26 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase
         return $resolver;
     }
 }
+
+class Controller
+{
+    public function __invoke()
+    {
+        return new Response('foo');
+    }
+
+    public function controller()
+    {
+        return new Response('foo');
+    }
+
+    static public function staticController()
+    {
+        return new Response('foo');
+    }
+}
+
+function controller_func()
+{
+    return new Response('foo');
+}