From 43e216df2b7837d5a732c242f4034311446f3828 Mon Sep 17 00:00:00 2001 From: Chris Gedrim Date: Wed, 18 Sep 2013 13:17:39 +0100 Subject: [PATCH 01/13] Add default return value for request data Allow overloading of the default return value of NULL when requesting request data. Example: http://host/action?foo=bar&abc=123 $app->request->get('foo') -- [bar] $app->request->get('bar') -- [NULL] $app->request->get('bar', false) -- [FALSE] --- Slim/Http/Request.php | 25 +++++++++++++++---------- tests/Http/RequestTest.php | 7 +++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Slim/Http/Request.php b/Slim/Http/Request.php index b7d32f985..1e4e1ca0e 100644 --- a/Slim/Http/Request.php +++ b/Slim/Http/Request.php @@ -209,9 +209,10 @@ public function params($key = null) * the value of the array key if requested; if the array key does not exist, NULL is returned. * * @param string $key + * @param mixed $default Default return value when key does not exist * @return array|mixed|null */ - public function get($key = null) + public function get($key = null, $default = null) { if (!isset($this->env['slim.request.query_hash'])) { $output = array(); @@ -226,7 +227,7 @@ public function get($key = null) if (isset($this->env['slim.request.query_hash'][$key])) { return $this->env['slim.request.query_hash'][$key]; } else { - return null; + return $default; } } else { return $this->env['slim.request.query_hash']; @@ -240,10 +241,11 @@ public function get($key = null) * the value of a hash key if requested; if the array key does not exist, NULL is returned. * * @param string $key + * @param mixed $default Default return value when key does not exist * @return array|mixed|null * @throws \RuntimeException If environment input is not available */ - public function post($key = null) + public function post($key = null, $default = null) { if (!isset($this->env['slim.input'])) { throw new \RuntimeException('Missing slim.input in environment variables'); @@ -266,7 +268,7 @@ public function post($key = null) if (isset($this->env['slim.request.form_hash'][$key])) { return $this->env['slim.request.form_hash'][$key]; } else { - return null; + return $default; } } else { return $this->env['slim.request.form_hash']; @@ -276,31 +278,34 @@ public function post($key = null) /** * Fetch PUT data (alias for \Slim\Http\Request::post) * @param string $key + * @param mixed $default Default return value when key does not exist * @return array|mixed|null */ - public function put($key = null) + public function put($key = null, $default = null) { - return $this->post($key); + return $this->post($key, $default); } /** * Fetch PATCH data (alias for \Slim\Http\Request::post) * @param string $key + * @param mixed $default Default return value when key does not exist * @return array|mixed|null */ - public function patch($key = null) + public function patch($key = null, $default = null) { - return $this->post($key); + return $this->post($key, $default); } /** * Fetch DELETE data (alias for \Slim\Http\Request::post) * @param string $key + * @param mixed $default Default return value when key does not exist * @return array|mixed|null */ - public function delete($key = null) + public function delete($key = null, $default = null) { - return $this->post($key); + return $this->post($key, $default); } /** diff --git a/tests/Http/RequestTest.php b/tests/Http/RequestTest.php index 7a837a7d0..da1de9ed1 100644 --- a/tests/Http/RequestTest.php +++ b/tests/Http/RequestTest.php @@ -221,6 +221,7 @@ public function testGet() $this->assertEquals(3, count($req->get())); $this->assertEquals('1', $req->get('one')); $this->assertNull($req->get('foo')); + $this->assertFalse($req->get('foo', false)); } /** @@ -236,6 +237,7 @@ public function testGetWithoutMultibyte() $this->assertEquals(3, count($req->get())); $this->assertEquals('1', $req->get('one')); $this->assertNull($req->get('foo')); + $this->assertFalse($req->get('foo', false)); } /** @@ -253,6 +255,7 @@ public function testPost() $this->assertEquals(2, count($req->post())); $this->assertEquals('bar', $req->post('foo')); $this->assertNull($req->post('xyz')); + $this->assertFalse($req->post('xyz', false)); } /** @@ -271,6 +274,7 @@ public function testPostWithoutMultibyte() $this->assertEquals(2, count($req->post())); $this->assertEquals('bar', $req->post('foo')); $this->assertNull($req->post('xyz')); + $this->assertFalse($req->post('xyz', false)); } /** @@ -319,6 +323,7 @@ public function testPut() $this->assertEquals('bar', $req->put('foo')); $this->assertEquals('bar', $req->params('foo')); $this->assertNull($req->put('xyz')); + $this->assertFalse($req->put('xyz', false)); } /** @@ -337,6 +342,7 @@ public function testPatch() $this->assertEquals('bar', $req->patch('foo')); $this->assertEquals('bar', $req->params('foo')); $this->assertNull($req->patch('xyz')); + $this->assertFalse($req->patch('xyz', false)); } /** @@ -355,6 +361,7 @@ public function testDelete() $this->assertEquals('bar', $req->delete('foo')); $this->assertEquals('bar', $req->params('foo')); $this->assertNull($req->delete('xyz')); + $this->assertFalse($req->delete('xyz', false)); } /** From 3ae6c73b68035fa41b60145aacf0fabe13c1eec4 Mon Sep 17 00:00:00 2001 From: rbilalov Date: Sat, 19 Oct 2013 03:24:25 +0600 Subject: [PATCH 02/13] Controller as \class::method --- Slim/Route.php | 5 +++++ tests/RouteTest.php | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/Slim/Route.php b/Slim/Route.php index f3ff026c9..799c38a2f 100644 --- a/Slim/Route.php +++ b/Slim/Route.php @@ -154,6 +154,11 @@ public function getCallable() */ public function setCallable($callable) { + $matches = []; + if(is_string($callable) && preg_match('!^([^\:]+)\:\:(.+)$!', $callable, $matches)) { + $callable = [new $matches[1], $matches[2]]; + } + if (!is_callable($callable)) { throw new \InvalidArgumentException('Route callable must be callable'); } diff --git a/tests/RouteTest.php b/tests/RouteTest.php index dae792ad4..ed376c0db 100644 --- a/tests/RouteTest.php +++ b/tests/RouteTest.php @@ -67,6 +67,15 @@ public function testGetCallable() $this->assertSame($callable, $route->getCallable()); } + public function testGetCallableAsClass() + { + $route = new \Slim\Route('/foo', '\Slim\Router::getCurrentRoute'); + + $callable = $route->getCallable(); + $this->assertInstanceOf('\Slim\Router', $callable[0]); + $this->assertEquals('getCurrentRoute', $callable[1]); + } + public function testSetCallable() { $callable = function () { From ef56f5bb6cd42b62775d084a2556c4ad3543a61e Mon Sep 17 00:00:00 2001 From: rbilalov Date: Sat, 19 Oct 2013 12:48:09 +0600 Subject: [PATCH 03/13] [] -> array() --- Slim/Route.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Slim/Route.php b/Slim/Route.php index 799c38a2f..b58a2dcb1 100644 --- a/Slim/Route.php +++ b/Slim/Route.php @@ -156,7 +156,7 @@ public function setCallable($callable) { $matches = []; if(is_string($callable) && preg_match('!^([^\:]+)\:\:(.+)$!', $callable, $matches)) { - $callable = [new $matches[1], $matches[2]]; + $callable = array(new $matches[1], $matches[2]); } if (!is_callable($callable)) { From 444e2f110514789a448c6704e0b9e2e4f78053f8 Mon Sep 17 00:00:00 2001 From: kazusuke sasezaki Date: Sat, 2 Nov 2013 12:57:03 +0900 Subject: [PATCH 04/13] .travis.yml - add PHP 5.5 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e5f88b347..ac79ecea1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,6 @@ language: php php: - 5.3 - 5.4 + - 5.5 script: phpunit --coverage-text From e697ff20e2016e27b38ca6ec2503e67b8b899210 Mon Sep 17 00:00:00 2001 From: Don Gilbert Date: Wed, 6 Nov 2013 15:27:54 -0600 Subject: [PATCH 05/13] Add property typehints for proper IDE support. --- Slim/Slim.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Slim/Slim.php b/Slim/Slim.php index 2a68b6c89..070497571 100644 --- a/Slim/Slim.php +++ b/Slim/Slim.php @@ -40,9 +40,14 @@ /** * Slim - * @package Slim - * @author Josh Lockhart - * @since 1.0.0 + * @package Slim + * @author Josh Lockhart + * @since 1.0.0 + * + * @property $environment \Slim\Environment + * @property $response \Slim\Http\Response + * @property $request \Slim\Http\Request + * @property $router \Slim\Router */ class Slim { From a0776e726be7a1c6072160d45df4294769cc98b7 Mon Sep 17 00:00:00 2001 From: Don Gilbert Date: Wed, 6 Nov 2013 15:46:32 -0600 Subject: [PATCH 06/13] Fix ordering --- Slim/Slim.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Slim/Slim.php b/Slim/Slim.php index 070497571..db44e3aed 100644 --- a/Slim/Slim.php +++ b/Slim/Slim.php @@ -44,10 +44,10 @@ * @author Josh Lockhart * @since 1.0.0 * - * @property $environment \Slim\Environment - * @property $response \Slim\Http\Response - * @property $request \Slim\Http\Request - * @property $router \Slim\Router + * @property \Slim\Environment $environment + * @property \Slim\Http\Response $response + * @property \Slim\Http\Request $request + * @property \Slim\Router $router */ class Slim { From e0fb710f06030d39fd15127e2bc380300ab0e2c2 Mon Sep 17 00:00:00 2001 From: ptarjan Date: Wed, 20 Nov 2013 12:52:31 -0800 Subject: [PATCH 07/13] Don't rely on system setting for error_reporting level --- tests/Middleware/SessionCookieTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Middleware/SessionCookieTest.php b/tests/Middleware/SessionCookieTest.php index 36ae16e22..c1e725d91 100644 --- a/tests/Middleware/SessionCookieTest.php +++ b/tests/Middleware/SessionCookieTest.php @@ -135,6 +135,7 @@ public function testUnserializeErrorsAreCaughtAndLogged() $logWriter->expects($this->once()) ->method('write'); + $oldLevel = error_reporting(E_ALL); $app = new \Slim\Slim(array( 'log.writer' => $logWriter @@ -149,6 +150,8 @@ public function testUnserializeErrorsAreCaughtAndLogged() $mw->setNextMiddleware($app); $mw->call(); $this->assertEquals(array(), $_SESSION); + + error_reporting($oldLevel); } /** From fe32e2ca3e3ee54af638b4add75875d254b61fa6 Mon Sep 17 00:00:00 2001 From: trax Date: Thu, 21 Nov 2013 11:11:54 +0100 Subject: [PATCH 08/13] add 418 HTTP status code See RFC 2324 https://tools.ietf.org/html/rfc2324 --- Slim/Http/Response.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Slim/Http/Response.php b/Slim/Http/Response.php index c7a6499ed..0e5b8bb21 100644 --- a/Slim/Http/Response.php +++ b/Slim/Http/Response.php @@ -113,6 +113,7 @@ class Response implements \ArrayAccess, \Countable, \IteratorAggregate 415 => '415 Unsupported Media Type', 416 => '416 Requested Range Not Satisfiable', 417 => '417 Expectation Failed', + 418 => '418 I\'m a teapot', 422 => '422 Unprocessable Entity', 423 => '423 Locked', //Server Error 5xx From 3dd72ecd5fb1ad3f6d1d4132217ca1b088a1cd3a Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 18 Nov 2013 21:42:02 -0700 Subject: [PATCH 09/13] Remove redundant call to setTemplatesDirector method. --- Slim/Slim.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Slim/Slim.php b/Slim/Slim.php index 2a68b6c89..6f9256658 100644 --- a/Slim/Slim.php +++ b/Slim/Slim.php @@ -739,7 +739,6 @@ public function render($template, $data = array(), $status = null) if (!is_null($status)) { $this->response->status($status); } - $this->view->setTemplatesDirectory($this->config('templates.path')); $this->view->appendData($data); $this->view->display($template); } From 8f123ec1786d0b1b03b0d0142b4dc5ea1db1de88 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Mon, 18 Nov 2013 12:49:03 -0700 Subject: [PATCH 10/13] Pass through 'templates.path' to view object singleton. --- Slim/Slim.php | 5 ++++- tests/SlimTest.php | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Slim/Slim.php b/Slim/Slim.php index 6f9256658..6fdc9f50b 100644 --- a/Slim/Slim.php +++ b/Slim/Slim.php @@ -172,8 +172,11 @@ public function __construct(array $userSettings = array()) // Default view $this->container->singleton('view', function ($c) { $viewClass = $c['settings']['view']; + $templatesPath = $c['settings']['templates.path']; - return ($viewClass instanceOf \Slim\View) ? $viewClass : new $viewClass; + $view = ($viewClass instanceOf \Slim\View) ? $viewClass : new $viewClass; + $view->setTemplatesDirectory($templatesPath); + return $view; }); // Default log writer diff --git a/tests/SlimTest.php b/tests/SlimTest.php index 26f2ec603..90cf65aee 100644 --- a/tests/SlimTest.php +++ b/tests/SlimTest.php @@ -551,6 +551,16 @@ public function testViewDataTransfer() * RENDERING ************************************************/ + /** + * Test template path is passed to view + */ + public function testViewGetsTemplatesPath() + { + $path = dirname(__FILE__) . '/templates'; + $s = new \Slim\Slim(array('templates.path' => $path)); + $this->assertEquals($s->view->getTemplatesDirectory(), $path); + } + /** * Test render with template and data */ From 8e3b1fcc303eb9964c08a62404bc415ccb1189a6 Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 18 Nov 2013 22:17:40 -0700 Subject: [PATCH 11/13] Allow local data to be passed into a template during rendering. --- Slim/View.php | 24 +++++++++++++++--------- tests/SlimTest.php | 2 +- tests/ViewTest.php | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Slim/View.php b/Slim/View.php index c6c435a7f..816e886a4 100644 --- a/Slim/View.php +++ b/Slim/View.php @@ -236,20 +236,23 @@ public function getTemplatePathname($file) * This method echoes the rendered template to the current output buffer * * @param string $template Pathname of template file relative to templates directory + * @param array $data Any additonal data to be passed to the template. */ - public function display($template) + public function display($template, $data = null) { - echo $this->fetch($template); + echo $this->fetch($template, $data); } /** * Return the contents of a rendered template file - * @var string $template The template pathname, relative to the template base directory - * @return string The rendered template + * + * @param string $template The template pathname, relative to the template base directory + * @param array $data Any additonal data to be passed to the template. + * @return string The rendered template */ - public function fetch($template) + public function fetch($template, $data = null) { - return $this->render($template); + return $this->render($template, $data); } /** @@ -257,17 +260,20 @@ public function fetch($template) * * NOTE: This method should be overridden by custom view subclasses * - * @var string $template The template pathname, relative to the template base directory + * @param string $template The template pathname, relative to the template base directory + * @param array $data Any additonal data to be passed to the template. * @return string The rendered template * @throws \RuntimeException If resolved template pathname is not a valid file */ - protected function render($template) + protected function render($template, $data = null) { $templatePathname = $this->getTemplatePathname($template); if (!is_file($templatePathname)) { throw new \RuntimeException("View cannot render `$template` because the template does not exist"); } - extract($this->data->all()); + + $data = array_merge($this->data->all(), (array) $data); + extract($data); ob_start(); require $templatePathname; diff --git a/tests/SlimTest.php b/tests/SlimTest.php index 90cf65aee..1c520dc2b 100644 --- a/tests/SlimTest.php +++ b/tests/SlimTest.php @@ -33,7 +33,7 @@ //Mock custom view class CustomView extends \Slim\View { - public function render($template) { echo "Custom view"; } + public function render($template, $data = null) { echo "Custom view"; } } //Echo Logger diff --git a/tests/ViewTest.php b/tests/ViewTest.php index 6f9f2c351..e04ce8644 100644 --- a/tests/ViewTest.php +++ b/tests/ViewTest.php @@ -115,6 +115,21 @@ public function testAppendData() $this->assertEquals(array('foo' => 'bar'), $prop->getValue($view)->all()); } + public function testLocalData() + { + $view = new \Slim\View(); + $prop1 = new \ReflectionProperty($view, 'data'); + $prop1->setAccessible(true); + $prop1->setValue($view, new \Slim\Helper\Set(array('foo' => 'bar'))); + + $prop2 = new \ReflectionProperty($view, 'templatesDirectory'); + $prop2->setAccessible(true); + $prop2->setValue($view, dirname(__FILE__) . '/templates'); + + $output = $view->fetch('test.php', array('foo' => 'baz')); + $this->assertEquals('test output baz', $output); + } + public function testAppendDataOverwrite() { $view = new \Slim\View(); From a5a9a29f9569122f02357258a3f272d3a1db1c30 Mon Sep 17 00:00:00 2001 From: Josh Lockhart Date: Sat, 23 Nov 2013 15:10:49 -0500 Subject: [PATCH 12/13] Remove mcrypt dependency --- composer.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 656de3297..0becfe687 100644 --- a/composer.json +++ b/composer.json @@ -13,8 +13,10 @@ } ], "require": { - "php": ">=5.3.0", - "ext-mcrypt": "*" + "php": ">=5.3.0" + }, + "suggest": { + "ext-mcrypt": "Required for HTTP cookie encryption" }, "autoload": { "psr-0": { "Slim": "." } From fc816fb2aa166168a25dbda4061509da1531008d Mon Sep 17 00:00:00 2001 From: Renat Bilalov Date: Mon, 25 Nov 2013 20:04:05 +0600 Subject: [PATCH 13/13] fix [] -> array() change separator "::" -> ":" --- Slim/Route.php | 34 +++++++++++++++++----------------- tests/RouteTest.php | 10 +++++++++- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Slim/Route.php b/Slim/Route.php index b58a2dcb1..8ac53f240 100644 --- a/Slim/Route.php +++ b/Slim/Route.php @@ -92,8 +92,8 @@ class Route /** * Constructor - * @param string $pattern The URL pattern (e.g. "/books/:id") - * @param mixed $callable Anything that returns TRUE for is_callable() + * @param string $pattern The URL pattern (e.g. "/books/:id") + * @param mixed $callable Anything that returns TRUE for is_callable() */ public function __construct($pattern, $callable) { @@ -154,8 +154,8 @@ public function getCallable() */ public function setCallable($callable) { - $matches = []; - if(is_string($callable) && preg_match('!^([^\:]+)\:\:(.+)$!', $callable, $matches)) { + $matches = array(); + if (is_string($callable) && preg_match('!^([^\:]+)\:([[:alnum:]]+)$!', $callable, $matches)) { $callable = array(new $matches[1], $matches[2]); } @@ -199,7 +199,7 @@ public function getName() */ public function setName($name) { - $this->name = (string) $name; + $this->name = (string)$name; } /** @@ -222,7 +222,7 @@ public function setParams($params) /** * Get route parameter value - * @param string $index Name of URL parameter + * @param string $index Name of URL parameter * @return string * @throws \InvalidArgumentException If route parameter does not exist at index */ @@ -237,8 +237,8 @@ public function getParam($index) /** * Set route parameter value - * @param string $index Name of URL parameter - * @param mixed $value The new parameter value + * @param string $index Name of URL parameter + * @param mixed $value The new parameter value * @throws \InvalidArgumentException If route parameter does not exist at index */ public function setParam($index, $value) @@ -356,7 +356,7 @@ public function matches($resourceUri) $patternAsRegex = preg_replace_callback( '#:([\w]+)\+?#', array($this, 'matchesCallback'), - str_replace(')', ')?', (string) $this->pattern) + str_replace(')', ')?', (string)$this->pattern) ); if (substr($this->pattern, -1) === '/') { $patternAsRegex .= '?'; @@ -368,7 +368,7 @@ public function matches($resourceUri) } foreach ($this->paramNames as $name) { if (isset($paramValues[$name])) { - if (isset($this->paramNamesPath[ $name ])) { + if (isset($this->paramNamesPath[$name])) { $this->params[$name] = explode('/', urldecode($paramValues[$name])); } else { $this->params[$name] = urldecode($paramValues[$name]); @@ -381,17 +381,17 @@ public function matches($resourceUri) /** * Convert a URL parameter (e.g. ":id", ":id+") into a regular expression - * @param array $m URL parameters + * @param array $m URL parameters * @return string Regular expression for URL parameter */ protected function matchesCallback($m) { $this->paramNames[] = $m[1]; - if (isset($this->conditions[ $m[1] ])) { - return '(?P<' . $m[1] . '>' . $this->conditions[ $m[1] ] . ')'; + if (isset($this->conditions[$m[1]])) { + return '(?P<' . $m[1] . '>' . $this->conditions[$m[1]] . ')'; } if (substr($m[0], -1) === '+') { - $this->paramNamesPath[ $m[1] ] = 1; + $this->paramNamesPath[$m[1]] = 1; return '(?P<' . $m[1] . '>.+)'; } @@ -401,7 +401,7 @@ protected function matchesCallback($m) /** * Set route name - * @param string $name The name of the route + * @param string $name The name of the route * @return \Slim\Route */ public function name($name) @@ -413,7 +413,7 @@ public function name($name) /** * Merge route conditions - * @param array $conditions Key-value array of URL parameter conditions + * @param array $conditions Key-value array of URL parameter conditions * @return \Slim\Route */ public function conditions(array $conditions) @@ -439,6 +439,6 @@ public function dispatch() } $return = call_user_func_array($this->getCallable(), array_values($this->getParams())); - return ($return === false)? false : true; + return ($return === false) ? false : true; } } diff --git a/tests/RouteTest.php b/tests/RouteTest.php index ed376c0db..bcd2bb31f 100644 --- a/tests/RouteTest.php +++ b/tests/RouteTest.php @@ -69,13 +69,21 @@ public function testGetCallable() public function testGetCallableAsClass() { - $route = new \Slim\Route('/foo', '\Slim\Router::getCurrentRoute'); + $route = new \Slim\Route('/foo', '\Slim\Router:getCurrentRoute'); $callable = $route->getCallable(); $this->assertInstanceOf('\Slim\Router', $callable[0]); $this->assertEquals('getCurrentRoute', $callable[1]); } + public function testGetCallableAsStaticMethod() + { + $route = new \Slim\Route('/bar', '\Slim\Slim::getInstance'); + + $callable = $route->getCallable(); + $this->assertEquals('\Slim\Slim::getInstance', $callable); + } + public function testSetCallable() { $callable = function () {