From f0d9be02f5b1873b4fa83d280eb42943220c2541 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 16 Dec 2012 17:36:50 +0100 Subject: [PATCH] [TwigBridge] added an extension for the HttpKernel component --- .../Twig/Extension/HttpKernelExtension.php | 95 +++++++++++++++++++ .../Extension/HttpKernelExtensionTest.php | 73 ++++++++++++++ src/Symfony/Bridge/Twig/composer.json | 2 + 3 files changed, 170 insertions(+) create mode 100644 src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php create mode 100644 src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php new file mode 100644 index 0000000000..ba249daf97 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Extension; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Provides integration with the HttpKernel component. + * + * @author Fabien Potencier + */ +class HttpKernelExtension extends \Twig_Extension implements EventSubscriberInterface +{ + private $kernel; + private $request; + + /** + * Constructor. + * + * @param HttpKernelInterface $kernel A HttpKernelInterface install + */ + public function __construct(HttpKernelInterface $kernel) + { + $this->kernel = $kernel; + } + + public function getFunctions() + { + return array( + 'render' => new \Twig_Function_Method($this, 'render', array('needs_environment' => true, 'is_safe' => array('html'))), + ); + } + + /** + * Renders a URI. + * + * @param \Twig_Environment $twig A \Twig_Environment instance + * @param string $uri The URI to render + * + * @return string The Response content + */ + public function render(\Twig_Environment $twig, $uri) + { + if (null !== $this->request) { + $cookies = $this->request->cookies->all(); + $server = $this->request->server->all(); + } else { + $cookies = array(); + $server = array(); + } + + $subRequest = Request::create($uri, 'get', array(), $cookies, array(), $server); + if (null !== $this->request && $this->request->getSession()) { + $subRequest->setSession($this->request->getSession()); + } + + $response = $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false); + + if (!$response->isSuccessful()) { + throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $subRequest->getUri(), $response->getStatusCode())); + } + + return $response->getContent(); + } + + public function onKernelRequest(GetResponseEvent $event) + { + $this->request = $event->getRequest(); + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => array('onKernelRequest'), + ); + } + + public function getName() + { + return 'http_kernel'; + } +} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php new file mode 100644 index 0000000000..f5390d31be --- /dev/null +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Extension; + +use Symfony\Bridge\Twig\Extension\HttpKernelExtension; +use Symfony\Bridge\Twig\Tests\TestCase; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\HttpKernelInterface; + +class HttpKernelExtensionTest extends TestCase +{ + protected function setUp() + { + if (!class_exists('Symfony\Component\HttpKernel\HttpKernel')) { + $this->markTestSkipped('The "HttpKernel" component is not available'); + } + + if (!class_exists('Twig_Environment')) { + $this->markTestSkipped('Twig is not available.'); + } + } + + public function testRenderWithoutMasterRequest() + { + $kernel = $this->getKernel($this->returnValue(new Response('foo'))); + + $this->assertEquals('foo', $this->renderTemplate($kernel)); + } + + /** + * @expectedException \Twig_Error_Runtime + */ + public function testRenderWithError() + { + $kernel = $this->getKernel($this->throwException(new \Exception('foo'))); + + $loader = new \Twig_Loader_Array(array('index' => '{{ render("foo") }}')); + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension(new HttpKernelExtension($kernel)); + + $this->renderTemplate($kernel); + } + + protected function getKernel($return) + { + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + $kernel + ->expects($this->once()) + ->method('handle') + ->will($return) + ; + + return $kernel; + } + + protected function renderTemplate(HttpKernelInterface $kernel, $template = '{{ render("foo") }}') + { + $loader = new \Twig_Loader_Array(array('index' => $template)); + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension(new HttpKernelExtension($kernel)); + + return $twig->render('index'); + } +} diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 4a3e09e018..885718c506 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -21,6 +21,7 @@ }, "require-dev": { "symfony/form": "2.2.*", + "symfony/http-kernel": "2.2.*", "symfony/routing": "2.2.*", "symfony/templating": "2.2.*", "symfony/translation": "2.2.*", @@ -29,6 +30,7 @@ }, "suggest": { "symfony/form": "2.2.*", + "symfony/http-kernel": "2.2.*", "symfony/routing": "2.2.*", "symfony/templating": "2.2.*", "symfony/translation": "2.2.*",