Commit 6bddf29e authored by Dave Marshall's avatar Dave Marshall

Add ViewListenerWrapper and tests

parent 86c02016
......@@ -422,9 +422,7 @@ class Application extends \Pimple implements HttpKernelInterface, TerminableInte
*/
public function view($callback, $priority = 0)
{
$this->on(KernelEvents::VIEW, function (GetResponseForControllerResultEvent $event) use ($callback) {
call_user_func($callback, $event);
}, $priority);
$this->on(KernelEvents::VIEW, new ViewListenerWrapper($this, $callback), $priority);
}
/**
......
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Silex;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
/**
* Wraps view listeners.
*
* @author Dave Marshall <dave@atst.io>
*/
class ViewListenerWrapper
{
protected $app;
protected $callback;
/**
* Constructor.
*
* @param Application $app An Application instance
* @param callable $callback
*/
public function __construct(Application $app, $callback)
{
$this->app = $app;
$this->callback = $callback;
}
public function __invoke(GetResponseForControllerResultEvent $event)
{
$controllerResult = $event->getControllerResult();
$this->callback = $this->app['callback_resolver']->resolveCallback($this->callback);
if (!$this->shouldRun($controllerResult)) {
return;
}
$response = call_user_func($this->callback, $controllerResult, $event->getRequest());
if ($response instanceof Response) {
$event->setResponse($response);
} else {
$event->setControllerResult($response);
}
}
protected function shouldRun($controllerResult)
{
if (is_array($this->callback)) {
$callbackReflection = new \ReflectionMethod($this->callback[0], $this->callback[1]);
} elseif (is_object($this->callback) && !$this->callback instanceof \Closure) {
$callbackReflection = new \ReflectionObject($this->callback);
$callbackReflection = $callbackReflection->getMethod('__invoke');
} else {
$callbackReflection = new \ReflectionFunction($this->callback);
}
if ($callbackReflection->getNumberOfParameters() > 0) {
$parameters = $callbackReflection->getParameters();
$expectedControllerResult = $parameters[0];
if ($expectedControllerResult->getClass() && (!is_object($controllerResult) || !$expectedControllerResult->getClass()->isInstance($controllerResult))) {
return false;
}
if ($expectedControllerResult->isArray() && !is_array($controllerResult)) {
return false;
}
if (method_exists($expectedControllerResult, 'isCallable') && $expectedControllerResult->isCallable() && !is_callable($controllerResult)) {
return false;
}
}
return true;
}
}
......@@ -572,14 +572,25 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('ok', $response->getContent());
}
public function testViewListener()
public function testViewListenerWithPrimitive()
{
$app = new Application();
$app->get('/foo', function() { return array('ok'); });
$app->view(function ($event) {
$view = $event->getControllerResult();
$app->get('/foo', function() { return 123; });
$app->view(function ($view) {
return new Response($view);
});
$response = $app->handle(Request::create('/foo'));
$event->setResponse(new Response($view[0]));
$this->assertEquals('123', $response->getContent());
}
public function testViewListenerWithArrayTypeHint()
{
$app = new Application();
$app->get('/foo', function() { return array('ok'); });
$app->view(function (array $view) {
return new Response($view[0]);
});
$response = $app->handle(Request::create('/foo'));
......@@ -587,43 +598,77 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('ok', $response->getContent());
}
public function testDefaultPriorityStringResponseTriggerViewListener()
public function testViewListenerWithObjectTypeHint()
{
$app = new Application();
$app->get('/foo', function() { return 'not ok'; });
$app->view(function ($event) {
$event->setResponse(new Response('ok'));
$app->get('/foo', function() { return (object) array('name' => 'world'); });
$app->view(function (\stdClass $view) {
return new Response('Hello '.$view->name);
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('ok', $response->getContent());
$this->assertEquals('Hello world', $response->getContent());
}
public function testLowPriorityStringResponseDoesNotTriggerViewListener()
public function testViewListenerWithCallableTypeHint()
{
if (version_compare(phpversion(), '5.4.0', '<')) {
$this->markTestSkipped('Requires PHP >= 5.4.0');
}
$app = new Application();
$app->get('/foo', function() { return 'ok'; });
$app->view(function ($event) {
$event->setResponse(new Response('not ok'));
}, -100);
$app->get('/foo', function() { return function() { return 'world'; }; });
$app->view(function (callable $view) {
return new Response('Hello '.$view());
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('ok', $response->getContent());
$this->assertEquals('Hello world', $response->getContent());
}
public function testViewListenersCanBeChained()
{
$app = new Application();
$app->get('/foo', function() { return function() { return 'world'; }; });
$app->view(function (callable $view) {
return (object) array('name' => $view());
});
$app->view(function (\stdClass $view) {
return array('msg' => 'Hello '.$view->name);
});
$app->view(function (array $view) {
return $view['msg'];
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('Hello world', $response->getContent());
}
public function testResponseInstanceResponseDoesNotTriggerViewListener()
public function testViewListenersAreIgnoredIfNotSuitable()
{
$app = new Application();
$app->get('/foo', function() { return new Response('ok'); });
$app->view(function ($event) {
$event->setResponse(new Response('not ok'));
$app->get('/foo', function() { return 'Hello world'; });
$app->view(function (callable $view) {
throw new \Exception("View listener was called");
});
$app->view(function (\stdClass $view) {
throw new \Exception("View listener was called");
});
$app->view(function (array $view) {
throw new \Exception("View listener was called");
});
$response = $app->handle(Request::create('/foo'));
$this->assertEquals('ok', $response->getContent());
$this->assertEquals('Hello world', $response->getContent());
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment