diff options
author | Arnold Daniels <arnold@jasny.net> | 2016-11-17 16:18:04 +0100 |
---|---|---|
committer | Arnold Daniels <arnold@jasny.net> | 2016-11-17 16:18:04 +0100 |
commit | cff30c5c3d529c23e40fa97df17308b8227a86c5 (patch) | |
tree | f141b8c05d75c5b86819edb63213ec8b93e281bd | |
parent | 14bc7de53fda2c44482c7cf46b896cfdd41aa68d (diff) | |
parent | 7149ef62ca11d451dadd271f5cb63233a4ac0748 (diff) | |
download | controller-cff30c5c3d529c23e40fa97df17308b8227a86c5.zip controller-cff30c5c3d529c23e40fa97df17308b8227a86c5.tar.gz controller-cff30c5c3d529c23e40fa97df17308b8227a86c5.tar.bz2 |
Merge branch 'Minstel-Flash'
-rw-r--r-- | composer.json | 9 | ||||
-rw-r--r-- | src/Controller.php | 22 | ||||
-rw-r--r-- | src/Flash.php | 109 | ||||
-rw-r--r-- | src/View/Twig.php | 178 | ||||
-rw-r--r-- | tests/ControllerTest.php | 39 | ||||
-rw-r--r-- | tests/FlashTest.php | 147 | ||||
-rw-r--r-- | tests/View/TwigTest.php | 320 |
7 files changed, 821 insertions, 3 deletions
diff --git a/composer.json b/composer.json index fab78e9..4a67d09 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,13 @@ "jasny/php-functions": "^2.0" }, "require-dev": { - "jasny/php-code-quality": "^2.0" + "jasny/php-code-quality": "^2.0", + "jasny/twig-extensions": "^1.0", + "twig/twig": "^1.26" + }, + "suggest": { + "jasny/twig-extensions": "Usefull extensions for Twig", + "twig/twig": "Needed to work with Twig templates" }, "autoload": { "psr-4": { @@ -28,4 +34,3 @@ } } } - diff --git a/src/Controller.php b/src/Controller.php index 057653e..9f69160 100644 --- a/src/Controller.php +++ b/src/Controller.php @@ -41,6 +41,12 @@ abstract class Controller 'application/x-www-form-urlencoded' => 'post', 'multipart/form-data' => 'post' ]; + + /** + * Flash + * @var Flash + */ + protected $flash = null; /** * Run the controller @@ -282,6 +288,21 @@ abstract class Controller return $errorResponse; } + + /** + * Set the flash message and/or return the flash object. + * + * @param mixed $type flash type, eg. 'error', 'notice' or 'success' + * @param mixed $message flash message + * @return Flash + */ + public function flash($type = null, $message = null) + { + if (!isset($this->flash)) $this->flash = new Flash(); + if ($type && $message) $this->flash->set($type, $message); + + return $this->flash; + } /** * Check if response is 2xx succesful, or empty @@ -516,4 +537,3 @@ abstract class Controller return $request ? $request->getMethod() : ''; } } - diff --git a/src/Flash.php b/src/Flash.php new file mode 100644 index 0000000..ad060f9 --- /dev/null +++ b/src/Flash.php @@ -0,0 +1,109 @@ +<?php + +namespace Jasny; + +/** + * Class for the flash message + */ +class Flash +{ + /** + * @var object + */ + protected static $data = null; + + /** + * Check if the flash is set. + * + * @return boolean + */ + public static function isIssued() + { + return isset($_SESSION['flash']) || isset(static::$data); + } + + /** + * Set the flash. + * + * @param mixed $type flash type, eg. 'error', 'notice' or 'success' + * @param mixed $message flash message + */ + public static function set($type, $message) + { + if (!$type) { + throw new \InvalidArgumentException("Type should not be empty"); + } + + static::$data = (object)['type'=>$type, 'message'=>$message]; + + $_SESSION['flash'] = static::$data; + } + + /** + * Get the flash. + * + * @return object + */ + public static function get() + { + if (!isset(static::$data) && isset($_SESSION['flash'])) { + static::$data = (object)$_SESSION['flash']; + unset($_SESSION['flash']); + } + + return static::$data; + } + + /** + * Reissue the flash. + */ + public static function reissue() + { + if (!isset(static::$data) && isset($_SESSION['flash'])) { + static::$data = (object)$_SESSION['flash']; + } else { + $_SESSION['flash'] = static::$data; + } + } + + /** + * Clear the flash. + */ + public static function clear() + { + self::$data = null; + unset($_SESSION['flash']); + } + + /** + * Get the flash type + * + * @return string + */ + public static function getType() + { + $data = static::get(); + return isset($data) ? $data->type : null; + } + + /** + * Get the flash message + * + * @return string + */ + public static function getMessage() + { + $data = static::get(); + return isset($data) ? $data->message : null; + } + + /** + * Cast object to string + * + * @return string + */ + public function __toString() + { + return (string)$this->getMessage(); + } +} diff --git a/src/View/Twig.php b/src/View/Twig.php new file mode 100644 index 0000000..ee5d4ce --- /dev/null +++ b/src/View/Twig.php @@ -0,0 +1,178 @@ +<?php + +namespace Jasny\Controller\View; + +use Jasny\Flash; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; + +/** + * View using Twig + */ +trait Twig +{ + /** + * Twig environment + * @var \Twig_Environment + */ + protected $twig = null; + + /** + * Get server request + * @return ServerRequestInterface + */ + abstract public function getRequest(); + + /** + * Get server response + * @return ResponseInterface + */ + abstract public function getResponse(); + + /** + * Add a global variable to the view. + * + * @param string $name Variable name + * @param mixed $value + * @return $this + */ + public function setViewVariable($name, $value) + { + if (!$name) throw new \InvalidArgumentException("Name should not be empty"); + + $this->getTwig()->addGlobal($name, $value); + + return $this; + } + + /** + * Expose a function to the view. + * + * @param string $name Variable name + * @param mixed $function + * @param string $as 'function' or 'filter' + * @return $this + */ + public function setViewFunction($name, $function = null, $as = 'function') + { + if ($as === 'function') { + $this->getTwig()->addFunction($this->createTwigFunction($name, $function)); + } elseif ($as === 'filter') { + $this->getTwig()->addFilter($this->createTwigFilter($name, $function)); + } else { + throw new \InvalidArgumentException("You should create either function or filter, not '$as'"); + } + + return $this; + } + + /** + * Add extension to view + * + * @param object $extension + * @return $this + */ + public function setViewExtension($extension) + { + $this->getTwig()->addExtension($extension); + + return $this; + } + + /** + * View rendered template + * + * @param string $name Template name + * @param array $context Template context + * @return ResponseInterface + */ + public function view($name, array $context = []) + { + if (!pathinfo($name, PATHINFO_EXTENSION)) $name .= '.html.twig'; + + $twig = $this->getTwig(); + $tmpl = $twig->loadTemplate($name); + + $response = $this->getResponse(); + $response = $response->withHeader('Content-Type', 'text/html; charset=' . $twig->getCharset()); + $response->getBody()->write($tmpl->render($context)); + + return $response; + } + + /** + * Get twig environment + * + * @return \Twig_Environment + */ + public function getTwig() + { + if ($this->twig) return $this->twig; + + $loader = $this->getTwigLoader(); + $this->twig = $this->getTwigEnvironment($loader); + + $extensions = ['DateExtension', 'PcreExtension', 'TextExtension', 'ArrayExtension']; + foreach ($extensions as $name) { + $class = "Jasny\Twig\\$name"; + + if (class_exists($class)) $this->setViewExtension(new $class()); + } + + $uri = $this->getRequest()->getUri()->getPath(); + + $this->setViewVariable('current_url', $uri); + $this->setViewVariable('flash', new Flash()); + + return $this->twig; + } + + /** + * Get twig loasder for current working directory + * + * @return \Twig_Loader_Filesystem + */ + public function getTwigLoader() + { + return new \Twig_Loader_Filesystem(getcwd()); + } + + /** + * Get twig environment instance + * + * @param \Twig_Loader_Filesystem $loader + * @return \Twig_Environment + */ + public function getTwigEnvironment(\Twig_Loader_Filesystem $loader) + { + return new \Twig_Environment($loader); + } + + /** + * Create twig function + * + * @param string $name Name of function in view + * @param callable|null $function + * @return \Twig_SimpleFunction + */ + public function createTwigFunction($name, $function) + { + if (!$name) throw new \InvalidArgumentException("Function name should not be empty"); + + return new \Twig_SimpleFunction($name, $function ?: $name); + } + + /** + * Create twig filter + * + * @param string $name Name of filter in view + * @param callable|null $function + * @return \Twig_SimpleFilter + */ + public function createTwigFilter($name, $function) + { + if (!$name) throw new \InvalidArgumentException("Filter name should not be empty"); + + return new \Twig_SimpleFilter($name, $function ?: $name); + } +} diff --git a/tests/ControllerTest.php b/tests/ControllerTest.php index e0ebdc2..3c659b2 100644 --- a/tests/ControllerTest.php +++ b/tests/ControllerTest.php @@ -1,6 +1,7 @@ <?php use Jasny\Controller; +use Jasny\Flash; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; @@ -81,6 +82,7 @@ class ControllerTest extends PHPUnit_Framework_TestCase } /** +<<<<<<< HEAD * Test functions that check request method * * @dataProvider requestMethodProvider @@ -313,6 +315,43 @@ class ControllerTest extends PHPUnit_Framework_TestCase ['forbidden', 409, false], ['badRequest', 400, true], ['badRequest', 403, false] + ]; + } + + /** + * Test setting flash + * + * @dataProvider flashProvider + * @param object $data + */ + public function testFlash($data) + { + $controller = $this->getMockBuilder(Controller::class)->disableOriginalConstructor()->getMockForAbstractClass(); + + $flash = $controller->flash(); + $this->assertInstanceOf(Flash::class, $flash, "Flash is not set"); + $this->assertEmpty($flash->get(), "Flash data should be empty"); + + $flash = $controller->flash($data->type, $data->message); + $this->assertInstanceOf(Flash::class, $flash, "Flash is not set"); + $this->assertEquals($data, $flash->get(), "Flash data is incorrect"); + + $flash = $controller->flash(); + $this->assertInstanceOf(Flash::class, $flash, "Flash is not set"); + $this->assertEquals($data, $flash->get(), "Flash data is incorrect"); + + $flash->clear(); + } + + /** + * Test setting flash + * + * @return array + */ + public function flashProvider() + { + return [ + [(object)['type' => 'test_type', 'message' => 'Test message']] ]; } diff --git a/tests/FlashTest.php b/tests/FlashTest.php new file mode 100644 index 0000000..c17c446 --- /dev/null +++ b/tests/FlashTest.php @@ -0,0 +1,147 @@ +<?php + +use Jasny\Flash; + +/** + * @covers Jasny\Flash + */ +class FlashTest extends PHPUnit_Framework_TestCase +{ + /** + * Test flash + * + * @dataProvider flashProvider + * @param object $data + */ + public function testFlash($data) + { + $flash = new Flash(); + $this->assertFlashEmpty($flash); + + //Set flash + $flash->set($data->type, $data->message); + $this->assertFlashDataCorrect($flash, $data); + $this->assertFlashIsIssued($flash, $data); + + //Get data + $setData = $flash->get(); + $this->assertFlashDataCorrect($flash, $data); + $this->assertFlashIsIssued($flash, $data); + $this->assertEquals($data, $setData, "Flash data was not got correctly"); + + //Clear + $flash->clear(); + $this->assertFlashEmpty($flash); + + //Set from session + $_SESSION['flash'] = $data; + $this->assertFlashIsIssued($flash, $data); + + //When flash is set only in session, not by 'set' method, then getting it's data removes flash from session, so they only remain in flash object + $this->assertFlashDataCorrect($flash, $data); + $this->assertFalse(isset($_SESSION['flash']), "Session flash variable should be empty"); + $this->assertTrue($flash->isIssued(), "Flash should be issued"); + + //Clear + $flash->clear(); + $this->assertFlashEmpty($flash); + + //Reissue from session + $_SESSION['flash'] = $data; + $flash->reissue(); + + $this->assertFlashDataCorrect($flash, $data); + $this->assertFlashIsIssued($flash, $data); + + //Reissue from object data + unset($_SESSION['flash']); + $flash->reissue(); + + $this->assertFlashDataCorrect($flash, $data); + $this->assertFlashIsIssued($flash, $data); + + //Clear + $flash->clear(); + $this->assertFlashEmpty($flash); + } + + /** + * Provide data for testing flash + * + * @return array + */ + public function flashProvider() + { + return [ + [(object)['type' => 'test_type', 'message' => 'Test message']], + [(object)['type' => 'test_type', 'message' => '']] + ]; + } + + /** + * Test 'set' method with wrong params + * + * @dataProvider setNegativeProvider + * @param object $data + */ + public function testSetNegative($data) + { + $flash = new Flash(); + + $this->expectException(InvalidArgumentException::class); + + $flash->set($data->type, $data->message); + } + + /** + * Provide data for testing wrong set + * + * @return array + */ + public function setNegativeProvider() + { + return [ + [(object)['type' => '', 'message' => 'Test message']] + ]; + } + + /** + * Assert that flash is not set + * + * @param Flash $flash + */ + public function assertFlashEmpty($flash) + { + $this->assertFalse(isset($_SESSION['flash']), "Session flash variable should be empty"); + $this->assertFalse($flash->isIssued(), "Flash should not be issued"); + $this->assertEmpty($flash->get(), "Flash should be empty"); + $this->assertEmpty($flash->getType(), "Flash type should not be set"); + $this->assertEmpty($flash->getMessage(), "Message should be empty"); + $this->assertEmpty((string)$flash, "Flash should be empty"); + } + + /** + * Assert that flash is issued + * + * @param Flash $flash + * @param object $data + */ + public function assertFlashIsIssued($flash, $data) + { + $this->assertEquals($data, $_SESSION['flash'], "Flash data was not set correctly"); + $this->assertTrue($flash->isIssued(), "Flash should be issued"); + } + + /** + * Assert that flash data is correct + * + * @param Flash $flash + * @param object $data + */ + public function assertFlashDataCorrect($flash, $data) + { + $this->assertEquals($data->type, $flash->getType(), "Type was not got correctly"); + $this->assertEquals($data->message, $flash->getMessage(), "Message was not got correctly"); + $this->assertEquals($data->message, (string)$flash, "Message was not got correctly when presenting flash as string"); + } +} diff --git a/tests/View/TwigTest.php b/tests/View/TwigTest.php new file mode 100644 index 0000000..662681d --- /dev/null +++ b/tests/View/TwigTest.php @@ -0,0 +1,320 @@ +<?php + +use Jasny\Flash; +use Jasny\Controller\View\Twig; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UriInterface; + +/** + * @covers Jasny\Controller\View\Twig + */ +class TwigTest extends PHPUnit_Framework_TestCase +{ + /** + * Test creating twig environment + */ + public function testGetTwig() + { + $view = $this->getView(['getTwigLoader', 'getTwigEnvironment', 'createTwigFunction', 'createTwigFilter', 'setViewExtension', 'setViewVariable']); + list($request, $response) = $this->getRequests(); + list($loader, $env) = $this->getTwigObjects(); + + $view->expects($this->once())->method('getTwigLoader')->will($this->returnValue($loader)); + $view->expects($this->once())->method('getTwigEnvironment')->with($this->equalTo($loader))->will($this->returnValue($env)); + $view->expects($this->exactly(4))->method('setViewExtension')->with($this->callback(function($ext) { + return in_array(get_class($ext), ['Jasny\Twig\DateExtension', 'Jasny\Twig\PcreExtension', 'Jasny\Twig\TextExtension', 'Jasny\Twig\ArrayExtension'], true); + }))->will($this->returnSelf()); + + $path = '/test/request/path'; + $uri = $this->createMock(UriInterface::class); + + $view->expects($this->once())->method('getRequest')->will($this->returnValue($request)); + $request->expects($this->once())->method('getUri')->will($this->returnValue($uri)); + $uri->expects($this->once())->method('getPath')->will($this->returnValue($path)); + $view->expects($this->exactly(2))->method('setViewVariable')->withConsecutive( + [$this->equalTo('current_url'), $this->equalTo($path)], + [$this->equalTo('flash'), $this->callback(function($flash) { + return $flash instanceof Flash && empty($flash->get()); + })] + ); + + $result = $view->getTwig(); + $resultSaved = $view->getTwig(); + + $this->assertEquals($env, $result, "Twig environment should be returned"); + $this->assertEquals($env, $resultSaved, "Saved twig environment should be returned"); + } + + /** + * Test getting twig loader and environment + */ + public function testGetTwigEnvironment() + { + $view = $this->getView(); + $loader = $view->getTwigLoader(); + $env = $view->getTwigEnvironment($loader); + + $this->assertInstanceOf(Twig_Environment::class, $env); + $this->assertInstanceOf(Twig_Loader_Filesystem::class, $loader); + $this->assertEquals([getcwd()], $loader->getPaths(), "Twig loader should be configured for current dir"); + } + + /** + * Test 'view' function + * + * @dataProvider viewProvider + * @param string $tmplName Name of template to render + * @param string $tmplNameFull Name of template with extension + * @param array $context Variables to render + * @param string $charset Twig sharset + * @param string $html Rendered template + */ + public function testView($tmplName, $tmplNameFull, $context, $charset, $html) + { + $view = $this->getView(['getTwig']); + list($request, $response) = $this->getRequests(); + list($loader, $env, $tmpl) = $this->getTwigObjects(); + + $stream = $this->createMock(StreamInterface::class); + + $view->expects($this->once())->method('getTwig')->will($this->returnValue($env)); + $view->expects($this->once())->method('getResponse')->will($this->returnValue($response)); + $env->expects($this->once())->method('loadTemplate')->with($this->equalTo($tmplNameFull))->will($this->returnValue($tmpl)); + $env->expects($this->once())->method('getCharset')->will($this->returnValue($charset)); + $response->expects($this->once())->method('withHeader')->with($this->equalTo('Content-Type'), $this->equalTo('text/html; charset=' . $charset ))->will($this->returnSelf()); + $response->expects($this->once())->method('getBody')->will($this->returnValue($stream)); + $tmpl->expects($this->once())->method('render')->with($this->equalTo($context))->will($this->returnValue($html)); + $stream->expects($this->once())->method('write')->with($this->equalTo($html)); + + $result = $view->view($tmplName, $context); + + $this->assertEquals($response, $result, "Response should be returned"); + } + + /** + * Provide data for testing view method + * + * @return array + */ + public function viewProvider() + { + return [ + ['test-template', 'test-template.html.twig', ['test' => 'value'], 'test-charset', 'rendered template'], + ['test-template.html.twig', 'test-template.html.twig', ['test' => 'value'], 'test-charset', 'rendered template'], + ]; + } + + /** + * Test creating twig function + * + * @dataProvider createTwigFunctionFilterProvider + * @param string $class Twig function or filter class + * @param string $createMethod + * @param string $name Created function or filter name + * @param callable $function + */ + public function testCreateTwigFunctionFilter($class, $createMethod, $name, $function) + { + if (!$name) $this->expectException(InvalidArgumentException::class); + + $view = $this->getView(); + $result = $view->createTwigFunction($name, $function); + $callback = $result->getCallable(); + + $this->assertInstanceOf(Twig_SimpleFunction::class, $result, "Result must be an instance of 'Twig_SimpleFunction'"); + $this->assertEquals($name, $result->getName(), "Function name is not set correctly"); + + if (!$function) { + $this->assertEquals($name, $callback); + } else { + $this->assertEquals(call_user_func($function), call_user_func($callback), "Function body was not set correctly"); + } + } + + /** + * Provide data for testing creating functions and filter for twig + * + * @return array + */ + public function createTwigFunctionFilterProvider() + { + return [ + [Twig_SimpleFunction::class, 'createTwigFunction', 'test_name', function() {return 'success_call';}], + [Twig_SimpleFunction::class, 'createTwigFunction', 'test_name', null], + [Twig_SimpleFilter::class, 'createTwigFilter', 'test_name', function() {return 'success_call';}], + [Twig_SimpleFilter::class, 'createTwigFilter', 'test_name', null], + [Twig_SimpleFunction::class, 'createTwigFunction', '', function() {return 'success_call';}], + [Twig_SimpleFilter::class, 'createTwigFilter', '', function() {return 'success_call';}], + ]; + } + + /** + * Test 'setViewFunction' method + * + * @dataProvider setViewFunctionFunctionProvider + * @param string $name + * @param callable $callable + * @param string $type + * @param boolean $positive + */ + public function testSetViewFunctionFunction($name, $callable, $type, $positive) + { + $view = $this->getView(['getTwig', 'createTwigFunction', 'createTwigFilter']); + $twig = $this->createMock(Twig_Environment::class); + $function = $this->createMock(Twig_SimpleFunction::class); + + if ($positive) { + $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); + $view->expects($this->once())->method('createTwigFunction')->with($this->equalTo($name), $this->equalTo($callable))->will($this->returnValue($function)); + $view->expects($this->never())->method('createTwigFilter'); + $twig->expects($this->once())->method('addFunction')->with($this->equalTo($function)); + } else { + $this->expectException(InvalidArgumentException::class); + } + + $result = $view->setViewFunction($name, $callable, $type); + + $this->assertEquals($view, $result, "Method should return \$this"); + } + + /** + * Provide data for testing 'setViewFunction' method when creating functions + * + * @return array + */ + public function setViewFunctionFunctionProvider() + { + return [ + ['test_name', function() {}, 'function', true], + ['test_name', function() {}, 'not_function_or_filter', false] + ]; + } + + /** + * Test 'setViewFunction' method + * + * @dataProvider setViewFunctionFilterProvider + * @param string $name + * @param callable $callable + */ + public function testSetViewFunctionFilter($name, $callable) + { + $view = $this->getView(['getTwig', 'createTwigFunction', 'createTwigFilter']); + $twig = $this->createMock(Twig_Environment::class); + $function = $this->createMock(Twig_SimpleFilter::class); + + $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); + $view->expects($this->once())->method('createTwigFilter')->with($this->equalTo($name), $this->equalTo($callable))->will($this->returnValue($function)); + $view->expects($this->never())->method('createTwigFunction'); + $twig->expects($this->once())->method('addFilter')->with($this->equalTo($function)); + + $result = $view->setViewFunction($name, $callable, 'filter'); + + $this->assertEquals($view, $result, "Method should return \$this"); + } + + /** + * Provide data for testing 'setViewFunction' method when creating filter + * + * @return array + */ + public function setViewFunctionFilterProvider() + { + return [ + ['test_name', function() {}] + ]; + } + + /** + * Test 'setViewVariable' method + * + * @dataProvider setViewVariableProvider + */ + public function testSetViewVariable($name, $value) + { + $view = $this->getView(['getTwig']); + $twig = $this->createMock(Twig_Environment::class); + + if (!$name) { + $this->expectException(InvalidArgumentException::class); + } else { + $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); + $twig->expects($this->once())->method('addGlobal')->with($this->equalTo($name), $this->equalTo($value)); + } + + $result = $view->setViewVariable($name, $value); + + $this->assertEquals($view, $result, "Method should return \$this"); + } + + /** + * Provide data for testing 'setViewVariable' method + * + * @return array + */ + public function setViewVariableProvider() + { + return [ + ['test_name', 'test_value'], + ['test_name', ''], + ['', 'test_value'], + ]; + } + + /** + * Test edding extension to twig + */ + public function testSetViewExtension() + { + $view = $this->getView(['getTwig']); + $twig = $this->createMock(Twig_Environment::class); + $ext = $this->createMock(Twig_ExtensionInterface::class); + + $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); + $twig->expects($this->once())->method('addExtension')->with($this->equalTo($ext)); + + $result = $view->setViewExtension($ext); + + $this->assertEquals($view, $result, "Method should return \$this"); + } + + /** + * Get mock for testing trait + * + * @param array $methods Methods to mock + * @return Twig + */ + public function getView($methods = []) + { + return $this->getMockForTrait(Twig::class, [], '', true, true, true, $methods); + } + + /** + * Get mocks representing twig objects + * + * @return array + */ + public function getTwigObjects() + { + return [ + $this->createMock(Twig_Loader_Filesystem::class), + $this->createMock(Twig_Environment::class), + $this->createMock(Twig_Template::class) + ]; + } + + /** + * Get request and response instances + * + * @return array + */ + public function getRequests() + { + return [ + $this->createMock(ServerRequestInterface::class), + $this->createMock(ResponseInterface::class) + ]; + } +} |