diff options
author | Arnold Daniels <arnold@jasny.net> | 2017-02-09 15:17:15 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-09 15:17:15 +0100 |
commit | 72c1e618610a1246dbfba143661777ca877a6a71 (patch) | |
tree | 31c199ff91436594acc35c6484798c6319715641 | |
parent | 51c88bded1a907b19e44344de35871822ba95829 (diff) | |
parent | c6cdff29b1a56ed530f93628d18d5ab44074ae98 (diff) | |
download | controller-72c1e618610a1246dbfba143661777ca877a6a71.zip controller-72c1e618610a1246dbfba143661777ca877a6a71.tar.gz controller-72c1e618610a1246dbfba143661777ca877a6a71.tar.bz2 |
Merge pull request #13 from jasny/view-libraryv1.2.0
Moved view logic to own library
-rw-r--r-- | composer.json | 9 | ||||
-rw-r--r-- | src/Controller.php | 7 | ||||
-rw-r--r-- | src/Controller/CheckRequest.php | 2 | ||||
-rw-r--r-- | src/Controller/RouteAction.php | 2 | ||||
-rw-r--r-- | src/Controller/View.php | 94 | ||||
-rw-r--r-- | src/Controller/View/PHP.php | 40 | ||||
-rw-r--r-- | src/Controller/View/Twig.php | 171 | ||||
-rw-r--r-- | src/ControllerInterface.php | 21 | ||||
-rw-r--r-- | tests/Controller/ContentNegotiationTest.php | 108 | ||||
-rw-r--r-- | tests/Controller/RouteActionTest.php | 9 | ||||
-rw-r--r-- | tests/Controller/View/PHPTest.php | 54 | ||||
-rw-r--r-- | tests/Controller/View/TwigTest.php | 297 | ||||
-rw-r--r-- | tests/Controller/ViewTest.php | 83 | ||||
-rw-r--r-- | tests/ControllerTest.php | 4 | ||||
-rw-r--r-- | tests/support/TestHelper.php | 48 |
15 files changed, 425 insertions, 524 deletions
diff --git a/composer.json b/composer.json index bd02105..185e3dd 100644 --- a/composer.json +++ b/composer.json @@ -23,12 +23,13 @@ }, "require-dev": { "jasny/php-code-quality": "^2.0", - "jasny/twig-extensions": "^1.0", - "twig/twig": "^1.26" + "jasny/view": "^1.0.0@beta" }, "suggest": { - "jasny/twig-extensions": "Usefull extensions for Twig", - "twig/twig": "Needed to work with Twig templates" + "jasny/view": "Use Twig or PHP templates with PSR-7 support", + "jasny/http-message": "A PSR-7 implementation for handling HTTP requests", + "jasny/router": "A versatile router with PSR-7 support", + "jasny/mvc": "Meta package for Jasny Router, Controller and View" }, "autoload": { "psr-4": { diff --git a/src/Controller.php b/src/Controller.php index 764d6f7..3f400e7 100644 --- a/src/Controller.php +++ b/src/Controller.php @@ -2,13 +2,14 @@ namespace Jasny; +use Jasny\ControllerInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; /** - * Controller + * Controller base class */ -abstract class Controller +abstract class Controller implements ControllerInterface { use Controller\Input, Controller\Output, @@ -59,7 +60,7 @@ abstract class Controller /** * Get response. set for controller * - * @return ResponseInterface + * @param ResponseInterface $response */ public function setResponse(ResponseInterface $response) { diff --git a/src/Controller/CheckRequest.php b/src/Controller/CheckRequest.php index 478266a..3fe3f1e 100644 --- a/src/Controller/CheckRequest.php +++ b/src/Controller/CheckRequest.php @@ -83,4 +83,4 @@ trait CheckRequest return $referer && parse_url($referer, PHP_URL_HOST) === $host ? $referer : ''; } -}
\ No newline at end of file +} diff --git a/src/Controller/RouteAction.php b/src/Controller/RouteAction.php index e8937b0..8051686 100644 --- a/src/Controller/RouteAction.php +++ b/src/Controller/RouteAction.php @@ -153,7 +153,7 @@ trait RouteAction * @param \ReflectionFunctionAbstract $refl * @return array */ - protected function getFunctionArgs($route, \ReflectionFunctionAbstract $refl) + protected function getFunctionArgs(\stdClass $route, \ReflectionFunctionAbstract $refl) { $args = []; $params = $refl->getParameters(); diff --git a/src/Controller/View.php b/src/Controller/View.php new file mode 100644 index 0000000..b32c285 --- /dev/null +++ b/src/Controller/View.php @@ -0,0 +1,94 @@ +<?php + +namespace Jasny\Controller; + +use Jasny\ViewInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; + +/** + * View using a template engine + */ +trait View +{ + /** + * @var ViewInterface + */ + protected $viewer; + + /** + * Get server request + * + * @return ServerRequestInterface + */ + abstract public function getRequest(); + + /** + * Get server request + * + * @return ResponseInterface + */ + abstract public function getResponse(); + + /** + * Get response. set for controller + * + * @param ResponseInterface $response + */ + abstract public function setResponse(ResponseInterface $response); + + + /** + * Get the template engine abstraction + * + * @return ViewInterface + */ + public function getViewer() + { + if (!isset($this->viewer)) { + throw new \LogicException("Viewer has not been set"); + } + + return $this->viewer; + } + + /** + * Get the template engine abstraction + * + * @param ViewInterface $viewer + */ + public function setViewer(ViewInterface $viewer) + { + $this->viewer = $viewer; + } + + + /** + * Get path of the view files + * + * @return string + */ + public function getViewPath() + { + return getcwd(); + } + + /** + * View rendered template + * + * @param string $name Template name + * @param array $context Template context + */ + public function view($name, array $context = []) + { + $context += ['current_url' => $this->getRequest()->getUri()]; + + if (method_exists($this, 'flash')) { + $context += ['flash' => $this->flash()]; + } + + $response = $this->getViewer()->render($this->getResponse(), $name, $context); + + $this->setResponse($response); + } +} diff --git a/src/Controller/View/PHP.php b/src/Controller/View/PHP.php new file mode 100644 index 0000000..0f7a5b7 --- /dev/null +++ b/src/Controller/View/PHP.php @@ -0,0 +1,40 @@ +<?php + +namespace Jasny\Controller\View; + +use Jasny\Controller\View; +use Jasny\View\PHP as PHPView; + +/** + * View using PHP + */ +trait PHP +{ + use View; + + /** + * Get the template engine abstraction + * + * @return PHPView + */ + public function getViewer() + { + if (!isset($this->viewer)) { + $this->viewer = $this->createPHPView(['path' => $this->getViewPath()]); + } + + return $this->viewer; + } + + /** + * Create a twig view object. + * @ignore + * @codeCoverageIgnore + * + * @return PHPView; + */ + protected function createPHPView($options) + { + return new PHPView($options); + } +} diff --git a/src/Controller/View/Twig.php b/src/Controller/View/Twig.php index f74c05a..78df6b0 100644 --- a/src/Controller/View/Twig.php +++ b/src/Controller/View/Twig.php @@ -2,173 +2,40 @@ namespace Jasny\Controller\View; -use Psr\Http\Message\ServerRequestInterface; +use Jasny\Controller\View; +use Jasny\View\Twig as TwigView; /** * View using Twig */ trait Twig { - /** - * Twig environment - * @var \Twig_Environment - */ - protected $twig; - - - /** - * Get server request - * - * @return ServerRequestInterface - */ - abstract public function getRequest(); - - /** - * Output result - * - * @param mixed $data - * @param string $format Output format as MIME or extension - * @return void - */ - abstract public function output($data, $format = null); - - - /** - * Get path of the view files - * - * @return string - */ - protected function getViewPath() - { - return getcwd(); - } - - /** - * Assert valid variable, function and filter name - * - * @param string $name - * @throws \InvalidArgumentException - */ - protected function assertViewVariableName($name) - { - if (!is_string($name)) { - $type = (is_object($name) ? get_class($name) . ' ' : '') . gettype($name); - throw new \InvalidArgumentException("Expected name to be a string, not a $type"); - } - - if (!preg_match('/^[a-z]\w*$/i', $name)) { - throw new \InvalidArgumentException("Invalid name '$name'"); - } - } + use View; /** - * Add a global variable to the view. - * - * @param string $name Variable name - * @param mixed $value - * @return $this - */ - public function setViewVariable($name, $value) - { - $this->assertViewVariableName($name); - - $this->getTwig()->addGlobal($name, $value); - - return $this; - } - - /** - * Expose a function to the view. - * - * @param string $name Function name - * @param string|null $function - * @param string $as 'function' or 'filter' - * @return $this - */ - public function setViewFunction($name, $function = null, $as = 'function') - { - $this->assertViewVariableName($name); - - if ($as === 'function') { - $function = new \Twig_SimpleFunction($name, $function ?: $name); - $this->getTwig()->addFunction($function); - } elseif ($as === 'filter') { - $filter = new \Twig_SimpleFilter($name, $function ?: $name); - $this->getTwig()->addFilter($filter); - } else { - $not = is_string($as) ? "'$as'" : 'a ' . gettype($as); - throw new \InvalidArgumentException("You should create either a 'function' or 'filter', not $not"); - } - - return $this; - } - - /** - * Get twig environment instance - * - * @return \Twig_Environment - */ - public function createTwigEnvironment() - { - $path = $this->getViewPath(); - $loader = new \Twig_Loader_Filesystem($path); - - return new \Twig_Environment($loader); - } - - /** - * Initialize the Twig environment + * Get the template engine abstraction + * + * @return TwigView */ - protected function initTwig() + public function getViewer() { - $this->twig = $this->createTwigEnvironment(); - - $extensions = ['DateExtension', 'PcreExtension', 'TextExtension', 'ArrayExtension']; - foreach ($extensions as $name) { - $class = "Jasny\Twig\\$name"; - - if (class_exists($class)) { - $this->twig->addExtension(new $class()); - } + if (!isset($this->viewer)) { + $this->viewer = $this->createTwigView(['path' => $this->getViewPath()]); + $this->viewer->addDefaultExtensions(); } - - $this->twig->addGlobal('current_url', $this->getRequest()->getUri()); - if (method_exists($this, 'flash')) { - $this->twig->addGlobal('flash', $this->flash()); - } - } - - /** - * Get Twig environment - * - * @return \Twig_Environment - */ - public function getTwig() - { - if (!isset($this->twig)) { - $this->initTwig(); - } - - return $this->twig; + return $this->viewer; } - - + /** - * View rendered template - * - * @param string $name Template name - * @param array $context Template context + * Create a twig view object. + * @ignore + * @codeCoverageIgnore + * + * @return TwigView; */ - public function view($name, array $context = []) + protected function createTwigView($options) { - if (!pathinfo($name, PATHINFO_EXTENSION)) { - $name .= '.html.twig'; - } - - $twig = $this->getTwig(); - $tmpl = $twig->loadTemplate($name); - - $this->output($tmpl->render($context), 'text/html; charset=' . $twig->getCharset()); + return new TwigView($options); } } diff --git a/src/ControllerInterface.php b/src/ControllerInterface.php new file mode 100644 index 0000000..8225457 --- /dev/null +++ b/src/ControllerInterface.php @@ -0,0 +1,21 @@ +<?php + +namespace Jasny; + +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; + +/** + * Interface for controllers + */ +interface ControllerInterface +{ + /** + * Run the controller as function + * + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return ResponseInterface + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response); +} diff --git a/tests/Controller/ContentNegotiationTest.php b/tests/Controller/ContentNegotiationTest.php index 1a390a4..f760bcd 100644 --- a/tests/Controller/ContentNegotiationTest.php +++ b/tests/Controller/ContentNegotiationTest.php @@ -5,7 +5,7 @@ namespace Jasny\Controller; use Jasny\Controller\ContentNegotiation; use Psr\Http\Message\ServerRequestInterface; use Jasny\Controller\TestHelper; -use Negotiation\Negotiator; +use Negotiation; use Negotiation\BaseAccept; /** @@ -16,36 +16,6 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase use TestHelper; /** - * Test negotiation - * - * @dataProvider negotiateProvider - * @param string $result - * @param array $header - * @param array $priorities - */ - public function testNegotiate($method, $negotiatorClass, $type, $expected, $headerName, array $headerValue, array $priorities) - { - $request = $this->createMock(ServerRequestInterface::class); - $request->expects($this->once())->method('getHeader')->with($this->equalTo($headerName))->will($this->returnValue($headerValue)); - - $expectedObj = $this->createMock(BaseAccept::class); - $expectedObj->expects($this->once())->method('getType')->will($this->returnValue($expected)); - - $negotiator = $this->createMock($negotiatorClass); - $negotiator->expects($this->once())->method('getBest')->with($this->equalTo(join(', ', $headerValue)), $this->equalTo($priorities))->will($this->returnValue($expectedObj)); - - $trait = $this->getController(['getRequest', 'getNegotiator']); - $trait->expects($this->once())->method('getRequest')->will($this->returnValue($request)); - $trait->expects($this->once())->method('getNegotiator')->with($this->equalTo($type))->will($this->returnValue($negotiator)); - - $builtClass = $this->callProtectedMethod($trait, 'getNegotiatorName', [$type]); - $result = $trait->{$method}($priorities); - - $this->assertEquals($builtClass, $negotiatorClass, "Obtained wrong negotiator class"); - $this->assertEquals($result, $expected, "Obtained result does not match expected result"); - } - - /** * Provide data for testing negotiation * * @return array @@ -55,7 +25,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase return [ [ 'negotiateContentType', - 'Negotiation\\Negotiator', + Negotiation\Negotiator::class, '', 'text/html', 'Accept', @@ -64,7 +34,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase ], [ 'negotiateContentType', - 'Negotiation\\Negotiator', + Negotiation\Negotiator::class, '', '', 'Accept', @@ -73,7 +43,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase ], [ 'negotiateLanguage', - 'Negotiation\\LanguageNegotiator', + Negotiation\LanguageNegotiator::class, 'language', 'en', 'Accept-Language', @@ -82,7 +52,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase ], [ 'negotiateLanguage', - 'Negotiation\\LanguageNegotiator', + Negotiation\LanguageNegotiator::class, 'language', '', 'Accept-Language', @@ -91,7 +61,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase ], [ 'negotiateEncoding', - 'Negotiation\\EncodingNegotiator', + Negotiation\EncodingNegotiator::class, 'encoding', 'gzip', 'Accept-Encoding', @@ -100,7 +70,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase ], [ 'negotiateEncoding', - 'Negotiation\\EncodingNegotiator', + Negotiation\EncodingNegotiator::class, 'encoding', '', 'Accept-Encoding', @@ -109,7 +79,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase ], [ 'negotiateCharset', - 'Negotiation\\CharsetNegotiator', + Negotiation\CharsetNegotiator::class, 'charset', 'utf-8', 'Accept-Charset', @@ -118,7 +88,7 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase ], [ 'negotiateCharset', - 'Negotiation\\CharsetNegotiator', + Negotiation\CharsetNegotiator::class, 'charset', '', 'Accept-Charset', @@ -129,6 +99,66 @@ class ContentNegotiationTest extends \PHPUnit_Framework_TestCase } /** + * Test negotiation + * @dataProvider negotiateProvider + * + * @param string $method + * @param string $negotiatorClass + * @param string $type + * @param string $expected + * @param string $headerName + * @param array $headerValue + * @param array $priorities + */ + public function testNegotiate( + $method, + $negotiatorClass, + $type, + $expected, + $headerName, + array $headerValue, + array $priorities + ) { + $request = $this->createMock(ServerRequestInterface::class); + $request->expects($this->once())->method('getHeader')->with($this->equalTo($headerName)) + ->will($this->returnValue($headerValue)); + + $expectedObj = $this->createMock(BaseAccept::class); + $expectedObj->expects($this->once())->method('getType')->will($this->returnValue($expected)); + + $negotiator = $this->createMock($negotiatorClass); + $negotiator->expects($this->once())->method('getBest') + ->with($this->equalTo(join(', ', $headerValue)), $this->equalTo($priorities)) + ->will($this->returnValue($expectedObj)); + + $trait = $this->getController(['getRequest', 'getNegotiator']); + $trait->expects($this->once())->method('getRequest')->will($this->returnValue($request)); + $trait->expects($this->once())->method('getNegotiator')->with($this->equalTo($type)) + ->will($this->returnValue($negotiator)); + + $buildClass = $this->callPrivateMethod($trait, 'getNegotiatorName', [$type]); + $result = $trait->{$method}($priorities); + + $this->assertEquals($buildClass, $negotiatorClass, "Obtained wrong negotiator class"); + $this->assertEquals($result, $expected, "Obtained result does not match expected result"); + } + + /** + * Test negotiation + * @dataProvider negotiateProvider + * + * @param string $method + * @param string $negotiatorClass + * @param string $type + */ + public function testGetNegotiator($method, $negotiatorClass, $type) + { + $controller = $this->getController(); + + $this->assertInstanceOf($negotiatorClass, $this->callPrivateMethod($controller, 'getNegotiator', [$type])); + } + + /** * Get the controller class * * @return string diff --git a/tests/Controller/RouteActionTest.php b/tests/Controller/RouteActionTest.php index fcab3ed..3e42d1d 100644 --- a/tests/Controller/RouteActionTest.php +++ b/tests/Controller/RouteActionTest.php @@ -14,7 +14,10 @@ class RouteActionTest extends \PHPUnit_Framework_TestCase use TestHelper { getController as private _getController; } - + + /** + * @return string + */ protected function getControllerClass() { return RouteActionController::class; @@ -27,7 +30,7 @@ class RouteActionTest extends \PHPUnit_Framework_TestCase * @param string $className * @return RouteActionController|\PHPUnit_Framework_MockObject_MockObject */ - protected function getController($methods = array(), $className = null) + protected function getController($methods = [], $className = null) { return $this->_getController( array_merge($methods, ['getRequest', 'defaultAction', 'runTestAction', 'notFound', 'before', 'after']), @@ -41,7 +44,7 @@ class RouteActionTest extends \PHPUnit_Framework_TestCase { return [ [(object)['args' => ['woo']], 'defaultAction', ['woo']], - [(object)['action' => 'test-run'], 'testRunAction'], + [(object)['action' => 'run-test'], 'runTestAction'], [(object)['action' => 'non-existent'], 'notFound'] ]; } diff --git a/tests/Controller/View/PHPTest.php b/tests/Controller/View/PHPTest.php new file mode 100644 index 0000000..c9b8c3f --- /dev/null +++ b/tests/Controller/View/PHPTest.php @@ -0,0 +1,54 @@ +<?php + +namespace Jasny\Controller\View; + +use Jasny\Controller\View; +use Jasny\View\PHP as PHPView; +use Jasny\Controller\TestHelper; + +/** + * @covers Jasny\Controller\View\PHP + */ +class PHPTest extends \PHPUnit_Framework_TestCase +{ + use TestHelper { + getController as private _getController; + } + + /** + * @return string + */ + protected function getControllerClass() + { + return View\PHP::class; + } + + /** + * Get mock controller + * + * @param array $methods + * @param string $className + * @return RouteActionController|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getController($methods = [], $className = null) + { + $controller = $this->_getController(array_merge($methods, ['createPHPView', 'getViewPath']), $className); + $controller->method('getViewPath')->willReturn('/tmp'); + + return $controller; + } + + + public function testGetViewer() + { + $viewer = $this->createMock(PHPView::class); + + $controller = $this->getController(); + $controller->method('createPHPView')->willReturn($viewer); + + $this->assertSame($viewer, $controller->getViewer()); + + // Idempotent + $this->assertSame($viewer, $controller->getViewer()); + } +} diff --git a/tests/Controller/View/TwigTest.php b/tests/Controller/View/TwigTest.php index e46757e..566787f 100644 --- a/tests/Controller/View/TwigTest.php +++ b/tests/Controller/View/TwigTest.php @@ -3,9 +3,7 @@ namespace Jasny\Controller\View; use Jasny\Controller\View; -use Jasny\Controller\Session\Flash; -use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Message\UriInterface; +use Jasny\View\Twig as TwigView; use Jasny\Controller\TestHelper; /** @@ -13,296 +11,45 @@ use Jasny\Controller\TestHelper; */ class TwigTest extends \PHPUnit_Framework_TestCase { - use TestHelper; - - protected function getControllerClass() - { - return View\Twig::class; - } - - /** - * Test creating twig environment - */ - public function testCreateTwigEnvironment() - { - $controller = $this->getController([]); - $twig = $controller->createTwigEnvironment(); - - $this->assertInstanceOf(\Twig_Environment::class, $twig); - $this->assertInstanceOf(\Twig_Loader_Filesystem::class, $twig->getLoader()); - $this->assertEquals([getcwd()], $twig->getLoader()->getPaths()); - } - - /** - * Test intializing twig environment - */ - public function testInitTwig() - { - $uri = $this->createMock(UriInterface::class); - - $request = $this->createMock(ServerRequestInterface::class); - $request->expects($this->once())->method('getUri')->willReturn($uri); - - $twig = $this->createMock(\Twig_Environment::class); - $twig->expects($this->once())->method('addGlobal')->with('current_url', $this->identicalTo($uri)); - - $controller = $this->getController(['createTwigEnvironment']); - $controller->expects($this->any())->method('getRequest')->willReturn($request); - $controller->expects($this->once())->method('createTwigEnvironment')->willReturn($twig); - - $controller->getTwig(); - } - - /** - * Test Jasny Twig extensions when intializing twig environment - */ - public function testInitTwigWithJasnyExtensions() - { - $request = $this->createMock(ServerRequestInterface::class); - - $twig = $this->createMock(\Twig_Environment::class); - $twig->expects($this->exactly(4))->method('addExtension')->withConsecutive( - [$this->isInstanceOf('Jasny\Twig\DateExtension')], - [$this->isInstanceOf('Jasny\Twig\PcreExtension')], - [$this->isInstanceOf('Jasny\Twig\TextExtension')], - [$this->isInstanceOf('Jasny\Twig\ArrayExtension')] - ); - - $controller = $this->getController(['createTwigEnvironment']); - $controller->expects($this->any())->method('getRequest')->willReturn($request); - $controller->expects($this->once())->method('createTwigEnvironment')->willReturn($twig); - - $controller->getTwig(); + use TestHelper { + getController as private _getController; } /** - * Test session flash when intializing twig environment + * @return string */ - public function testInitTwigWithSessionFlash() - { - $request = $this->createMock(ServerRequestInterface::class); - $flash = $this->createMock(Flash::class); - - $twig = $this->createMock(\Twig_Environment::class); - $twig->expects($this->any())->method('addGlobal')->withConsecutive([], ['flash', $flash]); - - $controller = $this->getController(['createTwigEnvironment', 'flash']); - $controller->expects($this->any())->method('getRequest')->willReturn($request); - $controller->expects($this->once())->method('flash')->willReturn($flash); - $controller->expects($this->once())->method('createTwigEnvironment')->willReturn($twig); - - $controller->getTwig(); - } - - /** - * Provide data for testing 'setViewVariable' method - * - * @return array - */ - public function setViewVariableProvider() - { - return [ - ['foo', null], - ['foo', 'bar'], - ['foo', ['bar', 'zoo']], - ['foo', (object)['a' => 'bar', 'b' => 'zoo']], - ]; - } - - /** - * Test 'setViewVariable' method - * - * @dataProvider setViewVariableProvider - */ - public function testSetViewVariable($name, $value) + protected function getControllerClass() { - $twig = $this->createMock(\Twig_Environment::class); - - $controller = $this->getController(['getTwig']); - $controller->method('getTwig')->willReturn($twig); - - $twig->expects($this->once())->method('addGlobal')->with($name, $value); - - $result = $controller->setViewVariable($name, $value); - - $this->assertSame($controller, $result); + return View\Twig::class; } - /** - * Provide data for testing 'setViewFunction' method when creating functions - * - * @return array - */ - public function setViewFunctionProvider() - { - return [ - ['test_name', function() {}], - ['str_rot13'], - ['obfuscate', 'str_rot13'] - ]; - } - - /** - * Test 'setViewFunction' method for adding functions - * @dataProvider setViewFunctionProvider + * Get mock controller * - * @param string $name - * @param callable $callable + * @param array $methods + * @param string $className + * @return RouteActionController|\PHPUnit_Framework_MockObject_MockObject */ - public function testSetViewFunctionFunction($name, $callable = null) + protected function getController($methods = [], $className = null) { - $twig = $this->createMock(\Twig_Environment::class); - - $controller = $this->getController(['getTwig']); - $controller->method('getTwig')->willReturn($twig); + $controller = $this->_getController(array_merge($methods, ['createTwigView', 'getViewPath']), $className); + $controller->method('getViewPath')->willReturn('/tmp'); - $fn = $callable ?: $name; - - $twig->expects($this->once())->method('addFunction') - ->with($this->callback(function($function) use ($name, $fn) { - $this->assertInstanceOf(\Twig_SimpleFunction::class, $function); - $this->assertEquals($name, $function->getName()); - $this->assertSame($fn, $function->getCallable()); - return true; - })); - - $twig->expects($this->never())->method('addFilter'); - - $controller->setViewFunction($name, $callable, 'function'); + return $controller; } - /** - * Test 'setViewFunction' method for adding filters - * @dataProvider setViewFunctionProvider - * - * @param string $name - * @param callable $callable - */ - public function testSetViewFunctionFilter($name, $callable = null) - { - $twig = $this->createMock(\Twig_Environment::class); - - $controller = $this->getController(['getTwig']); - $controller->method('getTwig')->willReturn($twig); - - $fn = $callable ?: $name; - - $twig->expects($this->once())->method('addFilter') - ->with($this->callback(function($function) use ($name, $fn) { - $this->assertInstanceOf(\Twig_SimpleFilter::class, $function); - $this->assertEquals($name, $function->getName()); - $this->assertSame($fn, $function->getCallable()); - return true; - })); - - $twig->expects($this->never())->method('addFunction'); - - $controller->setViewFunction($name, $callable, 'filter'); - } - - public function invalidAsProvider() + public function testGetViewer() { - return [ - ['foo', "'foo'"], - [10, 'a integer'], - [['filter'], 'a array'] - ]; - } - - /** - * @dataProvider invalidAsProvider - * - * @param mixed $as - * @param string $not - */ - public function testSetViewFunctionInvalid($as, $not) - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage("You should create either a 'function' or 'filter', not $not"); - - $twig = $this->createMock(\Twig_Environment::class); - - $controller = $this->getController(['getTwig']); - $controller->method('getTwig')->willReturn($twig); - - $controller->setViewFunction('abc', null, $as); - } - - - public function assertViewVariableNameProvider() - { - return [ - ['setViewVariable'], - ['setViewFunction', 'function'], - ['setViewFunction', 'filter'] - ]; - } - - /** - * @dataProvider assertViewVariableNameProvider - * - * @expectedException InvalidArgumentException - * @expectedExceptionMessage Expected name to be a string, not a stdClass object - */ - public function testAssertViewVariableNameNonString($fn, $as = null) - { - $twig = $this->createMock(\Twig_Environment::class); - - $controller = $this->getController(['getTwig']); - $controller->method('getTwig')->willReturn($twig); - - $controller->$fn(new \stdClass(), null, $as); - } - - /** - * @dataProvider assertViewVariableNameProvider - * - * @expectedException InvalidArgumentException - * @expectedExceptionMessage Invalid name 'hello world' - */ - public function testAssertViewVariableNameInvalid($fn, $as = null) - { - $twig = $this->createMock(\Twig_Environment::class); - - $controller = $this->getController(['getTwig']); - $controller->method('getTwig')->willReturn($twig); - - $controller->$fn('hello world', null, $as); - } - - - public function viewProvider() - { - return [ - ['foo', 'foo.html.twig'], - ['foo.html.twig', 'foo.html.twig'], - ['foo.html', 'foo.html'] - ]; - } - - /** - * @dataProvider viewProvider - * - * @param string $name - * @param string $filename - */ - public function testView($name, $filename) - { - $context = ['foo' => 1, 'bar' => 2, 'zoo' => ['monkey', 'lion']]; - - $template = $this->createMock(\Twig_TemplateInterface::class); - $template->expects($this->once())->method('render')->with($context)->willReturn('hello world'); + $viewer = $this->createMock(TwigView::class); + $viewer->expects($this->once())->method('addDefaultExtensions'); - $twig = $this->createMock(\Twig_Environment::class); - $twig->expects($this->once())->method('loadTemplate')->with($filename)->willReturn($template); - $twig->expects($this->once())->method('getCharset')->willReturn('test-charset'); + $controller = $this->getController(); + $controller->method('createTwigView')->willReturn($viewer); - $controller = $this->getController(['getTwig', 'output']); - $controller->expects($this->atLeastOnce())->method('getTwig')->willReturn($twig); - $controller->expects($this->once())->method('output')->with('hello world', 'text/html; charset=test-charset'); + $this->assertSame($viewer, $controller->getViewer()); - $controller->view($name, $context); + // Idempotent + $this->assertSame($viewer, $controller->getViewer()); } } diff --git a/tests/Controller/ViewTest.php b/tests/Controller/ViewTest.php new file mode 100644 index 0000000..0473a3f --- /dev/null +++ b/tests/Controller/ViewTest.php @@ -0,0 +1,83 @@ +<?php + +namespace Jasny\Controller\View; + +use Jasny\Controller\View; +use Jasny\ViewInterface; +use Jasny\Controller\TestHelper; +use Jasny\Controller\Session\Flash; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\UriInterface; + +/** + * @covers Jasny\Controller\View + */ +class ViewTest extends \PHPUnit_Framework_TestCase +{ + use TestHelper; + + /** + * @return string + */ + protected function getControllerClass() + { + return View::class; + } + + public function testGetViewer() + { + $viewer = $this->createMock(ViewInterface::class); + + $controller = $this->getController(); + $controller->setViewer($viewer); + + $this->assertSame($viewer, $controller->getViewer()); + } + + /** + * @expectedException LogicException + * @expectedExceptionMessage Viewer has not been set + */ + public function testGetViewerNotSet() + { + $this->getController()->getViewer(); + } + + + public function testGetViewPath() + { + $this->assertSame(getcwd(), $this->getController()->getViewPath()); + } + + + public function testView() + { + $uri = $this->createMock(UriInterface::class); + + $request = $this->createMock(ServerRequestInterface::class); + $request->expects($this->once())->method('getUri')->willReturn($uri); + + $response = $this->createMock(ResponseInterface::class); + $finalResponse = $this->createMock(ResponseInterface::class); + + $flash = $this->createMock(Flash::class); + + $name = 'foo'; + $context = ['color' => 'blue', 'animal' => 'monkey']; + + $viewer = $this->createMock(ViewInterface::class); + $viewer->expects($this->once())->method('render') + ->with($response, $name, $this->identicalTo($context + ['current_url' => $uri, 'flash' => $flash])) + ->willReturn($finalResponse); + + $controller = $this->getController(['flash']); + $controller->method('getRequest')->willReturn($request); + $controller->method('getResponse')->willReturn($response); + $controller->method('flash')->willReturn($flash); + $controller->expects($this->once())->method('setResponse')->with($finalResponse); + $controller->setViewer($viewer); + + $controller->view($name, $context); + } +} diff --git a/tests/ControllerTest.php b/tests/ControllerTest.php index b980d48..b0f357f 100644 --- a/tests/ControllerTest.php +++ b/tests/ControllerTest.php @@ -5,14 +5,14 @@ namespace Jasny; use Jasny\Controller; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Jasny\Controller\TestHelper; +use Jasny\Controller\TestHelper as ControllerTestHelper; /** * @covers Jasny\Controller */ class ControllerTest extends \PHPUnit_Framework_TestCase { - use TestHelper; + use ControllerTestHelper; /** * Test running controller diff --git a/tests/support/TestHelper.php b/tests/support/TestHelper.php index 05b40d7..b48f8b0 100644 --- a/tests/support/TestHelper.php +++ b/tests/support/TestHelper.php @@ -3,20 +3,15 @@ namespace Jasny\Controller; use Jasny\Controller; +use Jasny\TestHelper as Base; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Additional test methods */ trait TestHelper { - /** - * Returns a builder object to create mock objects using a fluent interface. - * - * @param string $className - * - * @return \PHPUnit_Framework_MockObject_MockBuilder - */ - abstract public function getMockBuilder($className); + use Base; /** * Get the controller class @@ -32,7 +27,7 @@ trait TestHelper * Get mock for controller * * @param array $methods Methods to mock - * @return Controller|Controller\Session|Controller\View\Twig|\PHPUnit_Framework_MockObject_MockObject + * @return Controller|Controller\Session|Controller\View|MockObject */ public function getController($methods = [], $mockClassName = null) { @@ -50,39 +45,4 @@ trait TestHelper $getMock = trait_exists($class) ? 'getMockForTrait' : 'getMockForAbstractClass'; return $builder->$getMock(); } - - /** - * Set a private or protected property of the given object - * - * @param object $object - * @param string $property - * @param mixed $value - */ - protected function setPrivateProperty($object, $property, $value) - { - if (!is_object($object)) { - throw new \InvalidArgumentException("Excpected an object, got a " . gettype($object)); - } - - $refl = new \ReflectionProperty($object, $property); - $refl->setAccessible(true); - $refl->setValue($object, $value); - } - - /** - * Call protected method on some object - * - * @param object $object - * @param string $name Method name - * @param array $args - * @return mixed Result of method call - */ - protected function callProtectedMethod($object, $name, $args) - { - $class = new \ReflectionClass($object); - $method = $class->getMethod($name); - $method->setAccessible(true); - - return $method->invokeArgs($object, $args); - } } |