diff --git a/README.markdown b/README.markdown
index cad57a612..a772db216 100644
--- a/README.markdown
+++ b/README.markdown
@@ -66,7 +66,7 @@ should contain this code:
Your nginx configuration file should contain this code (along with other settings you may need) in your `location` block:
- try_files $uri $uri/ /index.php;
+ try_files $uri $uri/ /index.php?$args;
This assumes that Slim's `index.php` is in the root folder of your project (www root).
@@ -79,6 +79,28 @@ lighttpd >= 1.4.24.
This assumes that Slim's `index.php` is in the root folder of your project (www root).
+#### IIS
+
+Ensure the `Web.config` and `index.php` files are in the same public-accessible directory. The `Web.config` file should contain this code:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
## Documentation
diff --git a/Slim/Environment.php b/Slim/Environment.php
index 147d00f20..707b2dc16 100644
--- a/Slim/Environment.php
+++ b/Slim/Environment.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -87,7 +87,7 @@ public static function getInstance($refresh = false)
*/
public static function mock($userSettings = array())
{
- self::$environment = new self(array_merge(array(
+ $defaults = array(
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => '',
'PATH_INFO' => '',
@@ -102,7 +102,8 @@ public static function mock($userSettings = array())
'slim.url_scheme' => 'http',
'slim.input' => '',
'slim.errors' => @fopen('php://stderr', 'w')
- ), $userSettings));
+ );
+ self::$environment = new self(array_merge($defaults, $userSettings));
return self::$environment;
}
@@ -143,7 +144,7 @@ private function __construct($settings = null)
if (strpos($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']) === 0) {
$env['SCRIPT_NAME'] = $_SERVER['SCRIPT_NAME']; //Without URL rewrite
} else {
- $env['SCRIPT_NAME'] = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']) ); //With URL rewrite
+ $env['SCRIPT_NAME'] = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])); //With URL rewrite
}
$env['PATH_INFO'] = substr_replace($_SERVER['REQUEST_URI'], '', 0, strlen($env['SCRIPT_NAME']));
if (strpos($env['PATH_INFO'], '?') !== false) {
@@ -161,21 +162,26 @@ private function __construct($settings = null)
//Number of server port that is running the script
$env['SERVER_PORT'] = $_SERVER['SERVER_PORT'];
- //HTTP request headers
- $specialHeaders = array('CONTENT_TYPE', 'CONTENT_LENGTH', 'PHP_AUTH_USER', 'PHP_AUTH_PW', 'PHP_AUTH_DIGEST', 'AUTH_TYPE');
- foreach ($_SERVER as $key => $value) {
- $value = is_string($value) ? trim($value) : $value;
- if (strpos($key, 'HTTP_') === 0) {
- $env[substr($key, 5)] = $value;
- } elseif (strpos($key, 'X_') === 0 || in_array($key, $specialHeaders)) {
- $env[$key] = $value;
- }
+ //HTTP request headers (retains HTTP_ prefix to match $_SERVER)
+ $headers = \Slim\Http\Headers::extract($_SERVER);
+ foreach ($headers as $key => $value) {
+ $env[$key] = $value;
}
+ // $specialHeaders = array('CONTENT_TYPE', 'CONTENT_LENGTH', 'PHP_AUTH_USER', 'PHP_AUTH_PW', 'PHP_AUTH_DIGEST', 'AUTH_TYPE');
+ // foreach ($_SERVER as $key => $value) {
+ // $value = is_string($value) ? trim($value) : $value;
+ // if (strpos($key, 'HTTP_') === 0) {
+ // $env[substr($key, 5)] = $value;
+ // } elseif (strpos($key, 'X_') === 0 || in_array($key, $specialHeaders)) {
+ // $env[$key] = $value;
+ // }
+ // }
+
//Is the application running under HTTPS or HTTP protocol?
$env['slim.url_scheme'] = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https';
- //Input stream (readable one time only; not available for mutipart/form-data requests)
+ //Input stream (readable one time only; not available for multipart/form-data requests)
$rawInput = @file_get_contents('php://input');
if (!$rawInput) {
$rawInput = '';
@@ -183,7 +189,7 @@ private function __construct($settings = null)
$env['slim.input'] = $rawInput;
//Error stream
- $env['slim.errors'] = fopen('php://stderr', 'w');
+ $env['slim.errors'] = @fopen('php://stderr', 'w');
$this->properties = $env;
}
diff --git a/Slim/Exception/Pass.php b/Slim/Exception/Pass.php
index f4f25fac5..2833dd0ec 100644
--- a/Slim/Exception/Pass.php
+++ b/Slim/Exception/Pass.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -46,5 +46,4 @@
*/
class Pass extends \Exception
{
-
}
diff --git a/Slim/Exception/Stop.php b/Slim/Exception/Stop.php
index f008959a4..8667eaeaa 100644
--- a/Slim/Exception/Stop.php
+++ b/Slim/Exception/Stop.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -44,5 +44,4 @@
*/
class Stop extends \Exception
{
-
}
diff --git a/Slim/Helper/Set.php b/Slim/Helper/Set.php
new file mode 100644
index 000000000..8a8a56a03
--- /dev/null
+++ b/Slim/Helper/Set.php
@@ -0,0 +1,210 @@
+
+ * @copyright 2011 Josh Lockhart
+ * @link http://www.slimframework.com
+ * @license http://www.slimframework.com/license
+ * @version 2.3.0
+ * @package Slim
+ *
+ * MIT LICENSE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+namespace Slim\Helper;
+
+class Set implements \ArrayAccess, \Countable, \IteratorAggregate
+{
+ /**
+ * Key-value array of arbitrary data
+ * @var array
+ */
+ protected $data = array();
+
+ /**
+ * Constructor
+ * @param array $items Pre-populate set with this key-value array
+ */
+ public function __construct($items = array())
+ {
+ $this->replace($items);
+ }
+
+ /**
+ * Normalize data key
+ *
+ * Used to transform data key into the necessary
+ * key format for this set. Used in subclasses
+ * like \Slim\Http\Headers.
+ *
+ * @param string $key The data key
+ * @return mixed The transformed/normalized data key
+ */
+ protected function normalizeKey($key)
+ {
+ return $key;
+ }
+
+ /**
+ * Set data key to value
+ * @param string $key The data key
+ * @param mixed $value The data value
+ */
+ public function set($key, $value)
+ {
+ $this->data[$this->normalizeKey($key)] = $value;
+ }
+
+ /**
+ * Get data value with key
+ * @param string $key The data key
+ * @param mixed $default The value to return if data key does not exist
+ * @return mixed The data value, or the default value
+ */
+ public function get($key, $default = null)
+ {
+ if ($this->has($key)) {
+ $isInvokable = is_object($this->data[$this->normalizeKey($key)]) && method_exists($this->data[$this->normalizeKey($key)], '__invoke');
+
+ return $isInvokable ? $this->data[$this->normalizeKey($key)]($this) : $this->data[$this->normalizeKey($key)];
+ }
+
+ return $default;
+ }
+
+ /**
+ * Add data to set
+ * @param array $items Key-value array of data to append to this set
+ */
+ public function replace($items)
+ {
+ foreach ($items as $key => $value) {
+ $this->set($key, $value); // Ensure keys are normalized
+ }
+ }
+
+ /**
+ * Fetch set data
+ * @return array This set's key-value data array
+ */
+ public function all()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Fetch set data keys
+ * @return array This set's key-value data array keys
+ */
+ public function keys()
+ {
+ return array_keys($this->data);
+ }
+
+ /**
+ * Does this set contain a key?
+ * @param string $key The data key
+ * @return boolean
+ */
+ public function has($key)
+ {
+ return array_key_exists($this->normalizeKey($key), $this->data);
+ }
+
+ /**
+ * Remove value with key from this set
+ * @param string $key The data key
+ */
+ public function remove($key)
+ {
+ unset($this->data[$this->normalizeKey($key)]);
+ }
+
+ /**
+ * Clear all values
+ */
+ public function clear()
+ {
+ $this->data = array();
+ }
+
+ /**
+ * Array Access
+ */
+
+ public function offsetExists($offset)
+ {
+ return $this->has($offset);
+ }
+
+ public function offsetGet($offset)
+ {
+ return $this->get($offset);
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->set($offset, $value);
+ }
+
+ public function offsetUnset($offset)
+ {
+ $this->remove($offset);
+ }
+
+ /**
+ * Countable
+ */
+
+ public function count()
+ {
+ return count($this->data);
+ }
+
+ /**
+ * IteratorAggregate
+ */
+
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->data);
+ }
+
+ /**
+ * Ensure a value or object will remain globally unique
+ * @param string $key The value or object name
+ * @param Closure The closure that defines the object
+ * @return mixed
+ */
+ public function singleton($key, $value)
+ {
+ $this->set($key, function ($c) use ($value) {
+ static $object;
+
+ if (null === $object) {
+ $object = $value($c);
+ }
+
+ return $object;
+ });
+ }
+}
diff --git a/Slim/Http/Cookies.php b/Slim/Http/Cookies.php
new file mode 100644
index 000000000..61c70e742
--- /dev/null
+++ b/Slim/Http/Cookies.php
@@ -0,0 +1,91 @@
+
+ * @copyright 2011 Josh Lockhart
+ * @link http://www.slimframework.com
+ * @license http://www.slimframework.com/license
+ * @version 2.3.0
+ * @package Slim
+ *
+ * MIT LICENSE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+namespace Slim\Http;
+
+class Cookies extends \Slim\Helper\Set
+{
+ /**
+ * Default cookie settings
+ * @var array
+ */
+ protected $defaults = array(
+ 'value' => '',
+ 'domain' => null,
+ 'path' => null,
+ 'expires' => null,
+ 'secure' => false,
+ 'httponly' => false
+ );
+
+ /**
+ * Set cookie
+ *
+ * The second argument may be a single scalar value, in which case
+ * it will be merged with the default settings and considered the `value`
+ * of the merged result.
+ *
+ * The second argument may also be an array containing any or all of
+ * the keys shown in the default settings above. This array will be
+ * merged with the defaults shown above.
+ *
+ * @param string $key Cookie name
+ * @param mixed $value Cookie settings
+ */
+ public function set($key, $value)
+ {
+ if (is_array($value)) {
+ $cookieSettings = array_replace($this->defaults, $value);
+ } else {
+ $cookieSettings = array_replace($this->defaults, array('value' => $value));
+ }
+ parent::set($key, $cookieSettings);
+ }
+
+ /**
+ * Remove cookie
+ *
+ * Unlike \Slim\Helper\Set, this will actually *set* a cookie with
+ * an expiration date in the past. This expiration date will force
+ * the client-side cache to remove its cookie with the given name
+ * and settings.
+ *
+ * @param string $key Cookie name
+ * @param array $settings Optional cookie settings
+ */
+ public function remove($key, $settings = array())
+ {
+ $settings['value'] = '';
+ $settings['expires'] = time() - 86400;
+ $this->set($key, array_replace($this->defaults, $settings));
+ }
+}
diff --git a/Slim/Http/Headers.php b/Slim/Http/Headers.php
index 0185f086b..5e0283e6e 100644
--- a/Slim/Http/Headers.php
+++ b/Slim/Http/Headers.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -35,147 +35,70 @@
/**
* HTTP Headers
*
- * This class is an abstraction of the HTTP response headers and
- * provides array access to the header list while automatically
- * stores and retrieves headers with lowercase canonical keys regardless
- * of the input format.
- *
- * This class also implements the `Iterator` and `Countable`
- * interfaces for even more convenient usage.
- *
* @package Slim
* @author Josh Lockhart
* @since 1.6.0
*/
-class Headers implements \ArrayAccess, \Iterator, \Countable
+class Headers extends \Slim\Helper\Set
{
- /**
- * @var array HTTP headers
- */
- protected $headers;
+ /********************************************************************************
+ * Static interface
+ *******************************************************************************/
/**
- * @var array Map canonical header name to original header name
+ * Special-case HTTP headers that are otherwise unidentifiable as HTTP headers.
+ * Typically, HTTP headers in the $_SERVER array will be prefixed with
+ * `HTTP_` or `X_`. These are not so we list them here for later reference.
+ *
+ * @var array
*/
- protected $map;
-
- /**
- * Constructor
- * @param array $headers
- */
- public function __construct($headers = array())
- {
- $this->merge($headers);
- }
+ protected static $special = array(
+ 'CONTENT_TYPE',
+ 'CONTENT_LENGTH',
+ 'PHP_AUTH_USER',
+ 'PHP_AUTH_PW',
+ 'PHP_AUTH_DIGEST',
+ 'AUTH_TYPE'
+ );
/**
- * Merge Headers
- * @param array $headers
+ * Extract HTTP headers from an array of data (e.g. $_SERVER)
+ * @param array $data
+ * @return array
*/
- public function merge($headers)
+ public static function extract($data)
{
- foreach ($headers as $name => $value) {
- $this[$name] = $value;
+ $results = array();
+ foreach ($data as $key => $value) {
+ $key = strtoupper($key);
+ if (strpos($key, 'X_') === 0 || strpos($key, 'HTTP_') === 0 || in_array($key, static::$special)) {
+ if ($key === 'HTTP_CONTENT_TYPE' || $key === 'HTTP_CONTENT_LENGTH') {
+ continue;
+ }
+ $results[$key] = $value;
+ }
}
- }
-
- /**
- * Transform header name into canonical form
- * @param string $name
- * @return string
- */
- protected function canonical($name)
- {
- return strtolower(trim($name));
- }
-
- /**
- * Array Access: Offset Exists
- */
- public function offsetExists($offset)
- {
- return isset($this->headers[$this->canonical($offset)]);
- }
-
- /**
- * Array Access: Offset Get
- */
- public function offsetGet($offset)
- {
- $canonical = $this->canonical($offset);
- if (isset($this->headers[$canonical])) {
- return $this->headers[$canonical];
- } else {
- return null;
- }
- }
-
- /**
- * Array Access: Offset Set
- */
- public function offsetSet($offset, $value)
- {
- $canonical = $this->canonical($offset);
- $this->headers[$canonical] = $value;
- $this->map[$canonical] = $offset;
- }
-
- /**
- * Array Access: Offset Unset
- */
- public function offsetUnset($offset)
- {
- $canonical = $this->canonical($offset);
- unset($this->headers[$canonical], $this->map[$canonical]);
- }
- /**
- * Countable: Count
- */
- public function count()
- {
- return count($this->headers);
+ return $results;
}
- /**
- * Iterator: Rewind
- */
- public function rewind()
- {
- reset($this->headers);
- }
+ /********************************************************************************
+ * Instance interface
+ *******************************************************************************/
/**
- * Iterator: Current
- */
- public function current()
- {
- return current($this->headers);
- }
-
- /**
- * Iterator: Key
- */
- public function key()
- {
- $key = key($this->headers);
-
- return $this->map[$key];
- }
-
- /**
- * Iterator: Next
+ * Transform header name into canonical form
+ * @param string $key
+ * @return string
*/
- public function next()
+ protected function normalizeKey($key)
{
- return next($this->headers);
- }
+ $key = strtolower($key);
+ $key = str_replace(array('-', '_'), ' ', $key);
+ $key = preg_replace('#^http #', '', $key);
+ $key = ucwords($key);
+ $key = str_replace(' ', '-', $key);
- /**
- * Iterator: Valid
- */
- public function valid()
- {
- return current($this->headers) !== false;
+ return $key;
}
}
diff --git a/Slim/Http/Request.php b/Slim/Http/Request.php
index e508394ad..b7d32f985 100644
--- a/Slim/Http/Request.php
+++ b/Slim/Http/Request.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -48,6 +48,7 @@ class Request
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
const METHOD_PUT = 'PUT';
+ const METHOD_PATCH = 'PATCH';
const METHOD_DELETE = 'DELETE';
const METHOD_OPTIONS = 'OPTIONS';
const METHOD_OVERRIDE = '_METHOD';
@@ -58,18 +59,32 @@ class Request
protected static $formDataMediaTypes = array('application/x-www-form-urlencoded');
/**
- * @var array
+ * Application Environment
+ * @var \Slim\Environment
*/
protected $env;
+ /**
+ * HTTP Headers
+ * @var \Slim\Http\Headers
+ */
+ public $headers;
+
+ /**
+ * HTTP Cookies
+ * @var \Slim\Helper\Set
+ */
+ public $cookies;
+
/**
* Constructor
- * @param array $env
- * @see \Slim\Environment
+ * @param \Slim\Environment $env
*/
- public function __construct($env)
+ public function __construct(\Slim\Environment $env)
{
$this->env = $env;
+ $this->headers = new \Slim\Http\Headers(\Slim\Http\Headers::extract($env));
+ $this->cookies = new \Slim\Helper\Set(\Slim\Http\Util::parseCookieHeader($env['HTTP_COOKIE']));
}
/**
@@ -108,6 +123,15 @@ public function isPut()
return $this->getMethod() === self::METHOD_PUT;
}
+ /**
+ * Is this a PATCH request?
+ * @return bool
+ */
+ public function isPatch()
+ {
+ return $this->getMethod() === self::METHOD_PATCH;
+ }
+
/**
* Is this a DELETE request?
* @return bool
@@ -143,7 +167,7 @@ public function isAjax()
{
if ($this->params('isajax')) {
return true;
- } elseif (isset($this->env['X_REQUESTED_WITH']) && $this->env['X_REQUESTED_WITH'] === 'XMLHttpRequest') {
+ } elseif (isset($this->headers['X_REQUESTED_WITH']) && $this->headers['X_REQUESTED_WITH'] === 'XMLHttpRequest') {
return true;
} else {
return false;
@@ -172,14 +196,10 @@ public function params($key = null)
{
$union = array_merge($this->get(), $this->post());
if ($key) {
- if (isset($union[$key])) {
- return $union[$key];
- } else {
- return null;
- }
- } else {
- return $union;
+ return isset($union[$key]) ? $union[$key] : null;
}
+
+ return $union;
}
/**
@@ -263,6 +283,16 @@ public function put($key = null)
return $this->post($key);
}
+ /**
+ * Fetch PATCH data (alias for \Slim\Http\Request::post)
+ * @param string $key
+ * @return array|mixed|null
+ */
+ public function patch($key = null)
+ {
+ return $this->post($key);
+ }
+
/**
* Fetch DELETE data (alias for \Slim\Http\Request::post)
* @param string $key
@@ -284,23 +314,28 @@ public function delete($key = null)
*/
public function cookies($key = null)
{
- if (!isset($this->env['slim.request.cookie_hash'])) {
- $cookieHeader = isset($this->env['COOKIE']) ? $this->env['COOKIE'] : '';
- $this->env['slim.request.cookie_hash'] = Util::parseCookieHeader($cookieHeader);
- }
if ($key) {
- if (isset($this->env['slim.request.cookie_hash'][$key])) {
- return $this->env['slim.request.cookie_hash'][$key];
- } else {
- return null;
- }
- } else {
- return $this->env['slim.request.cookie_hash'];
+ return $this->cookies->get($key);
}
+
+ return $this->cookies;
+ // if (!isset($this->env['slim.request.cookie_hash'])) {
+ // $cookieHeader = isset($this->env['COOKIE']) ? $this->env['COOKIE'] : '';
+ // $this->env['slim.request.cookie_hash'] = Util::parseCookieHeader($cookieHeader);
+ // }
+ // if ($key) {
+ // if (isset($this->env['slim.request.cookie_hash'][$key])) {
+ // return $this->env['slim.request.cookie_hash'][$key];
+ // } else {
+ // return null;
+ // }
+ // } else {
+ // return $this->env['slim.request.cookie_hash'];
+ // }
}
/**
- * Does the Request body contain parseable form data?
+ * Does the Request body contain parsed form data?
* @return bool
*/
public function isFormData()
@@ -323,24 +358,29 @@ public function isFormData()
public function headers($key = null, $default = null)
{
if ($key) {
- $key = strtoupper($key);
- $key = str_replace('-', '_', $key);
- $key = preg_replace('@^HTTP_@', '', $key);
- if (isset($this->env[$key])) {
- return $this->env[$key];
- } else {
- return $default;
- }
- } else {
- $headers = array();
- foreach ($this->env as $key => $value) {
- if (strpos($key, 'slim.') !== 0) {
- $headers[$key] = $value;
- }
- }
-
- return $headers;
+ return $this->headers->get($key, $default);
}
+
+ return $this->headers;
+ // if ($key) {
+ // $key = strtoupper($key);
+ // $key = str_replace('-', '_', $key);
+ // $key = preg_replace('@^HTTP_@', '', $key);
+ // if (isset($this->env[$key])) {
+ // return $this->env[$key];
+ // } else {
+ // return $default;
+ // }
+ // } else {
+ // $headers = array();
+ // foreach ($this->env as $key => $value) {
+ // if (strpos($key, 'slim.') !== 0) {
+ // $headers[$key] = $value;
+ // }
+ // }
+ //
+ // return $headers;
+ // }
}
/**
@@ -354,15 +394,11 @@ public function getBody()
/**
* Get Content Type
- * @return string
+ * @return string|null
*/
public function getContentType()
{
- if (isset($this->env['CONTENT_TYPE'])) {
- return $this->env['CONTENT_TYPE'];
- } else {
- return null;
- }
+ return $this->headers->get('CONTENT_TYPE');
}
/**
@@ -376,9 +412,9 @@ public function getMediaType()
$contentTypeParts = preg_split('/\s*[;,]\s*/', $contentType);
return strtolower($contentTypeParts[0]);
- } else {
- return null;
}
+
+ return null;
}
/**
@@ -410,9 +446,9 @@ public function getContentCharset()
$mediaTypeParams = $this->getMediaTypeParams();
if (isset($mediaTypeParams['charset'])) {
return $mediaTypeParams['charset'];
- } else {
- return null;
}
+
+ return null;
}
/**
@@ -421,11 +457,7 @@ public function getContentCharset()
*/
public function getContentLength()
{
- if (isset($this->env['CONTENT_LENGTH'])) {
- return (int) $this->env['CONTENT_LENGTH'];
- } else {
- return 0;
- }
+ return $this->headers->get('CONTENT_LENGTH', 0);
}
/**
@@ -434,17 +466,17 @@ public function getContentLength()
*/
public function getHost()
{
- if (isset($this->env['HOST'])) {
- if (strpos($this->env['HOST'], ':') !== false) {
- $hostParts = explode(':', $this->env['HOST']);
+ if (isset($this->env['HTTP_HOST'])) {
+ if (strpos($this->env['HTTP_HOST'], ':') !== false) {
+ $hostParts = explode(':', $this->env['HTTP_HOST']);
return $hostParts[0];
}
- return $this->env['HOST'];
- } else {
- return $this->env['SERVER_NAME'];
+ return $this->env['HTTP_HOST'];
}
+
+ return $this->env['SERVER_NAME'];
}
/**
@@ -462,7 +494,7 @@ public function getHostWithPort()
*/
public function getPort()
{
- return (int) $this->env['SERVER_PORT'];
+ return (int)$this->env['SERVER_PORT'];
}
/**
@@ -554,11 +586,7 @@ public function getIp()
*/
public function getReferrer()
{
- if (isset($this->env['REFERER'])) {
- return $this->env['REFERER'];
- } else {
- return null;
- }
+ return $this->headers->get('HTTP_REFERER');
}
/**
@@ -576,10 +604,6 @@ public function getReferer()
*/
public function getUserAgent()
{
- if (isset($this->env['USER_AGENT'])) {
- return $this->env['USER_AGENT'];
- } else {
- return null;
- }
+ return $this->headers->get('HTTP_USER_AGENT');
}
}
diff --git a/Slim/Http/Response.php b/Slim/Http/Response.php
index 8e95b376f..1d3b729d5 100644
--- a/Slim/Http/Response.php
+++ b/Slim/Http/Response.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -51,9 +51,14 @@ class Response implements \ArrayAccess, \Countable, \IteratorAggregate
protected $status;
/**
- * @var \Slim\Http\Headers List of HTTP response headers
+ * @var \Slim\Http\Headers
*/
- protected $header;
+ public $headers;
+
+ /**
+ * @var \Slim\Http\Cookies
+ */
+ public $cookies;
/**
* @var string HTTP response body
@@ -123,21 +128,30 @@ class Response implements \ArrayAccess, \Countable, \IteratorAggregate
* Constructor
* @param string $body The HTTP response body
* @param int $status The HTTP response status
- * @param \Slim\Http\Headers|array $header The HTTP response headers
+ * @param \Slim\Http\Headers|array $headers The HTTP response headers
*/
- public function __construct($body = '', $status = 200, $header = array())
+ public function __construct($body = '', $status = 200, $headers = array())
{
- $this->status = (int) $status;
- $headers = array();
- foreach ($header as $key => $value) {
- $headers[$key] = $value;
- }
- $this->header = new Headers(array_merge(array('Content-Type' => 'text/html'), $headers));
- $this->body = '';
+ $this->setStatus($status);
+ $this->headers = new \Slim\Http\Headers(array('Content-Type' => 'text/html'));
+ $this->headers->replace($headers);
+ $this->cookies = new \Slim\Http\Cookies();
$this->write($body);
}
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ public function setStatus($status)
+ {
+ $this->status = (int)$status;
+ }
+
/**
+ * DEPRECATION WARNING! Use `getStatus` or `setStatus` instead.
+ *
* Get and set status
* @param int|null $status
* @return int
@@ -152,6 +166,8 @@ public function status($status = null)
}
/**
+ * DEPRECATION WARNING! Access `headers` property directly.
+ *
* Get and set header
* @param string $name Header name
* @param string|null $value Header value
@@ -160,22 +176,36 @@ public function status($status = null)
public function header($name, $value = null)
{
if (!is_null($value)) {
- $this[$name] = $value;
+ $this->headers->set($name, $value);
}
- return $this[$name];
+ return $this->headers->get($name);
}
/**
+ * DEPRECATION WARNING! Access `headers` property directly.
+ *
* Get headers
* @return \Slim\Http\Headers
*/
public function headers()
{
- return $this->header;
+ return $this->headers;
+ }
+
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+ public function setBody($content)
+ {
+ $this->write($content, true);
}
/**
+ * DEPRECATION WARNING! use `getBody` or `setBody` instead.
+ *
* Get and set body
* @param string|null $body Content of HTTP response body
* @return string
@@ -189,38 +219,45 @@ public function body($body = null)
return $this->body;
}
- /**
- * Get and set length
- * @param int|null $length
- * @return int
- */
- public function length($length = null)
- {
- if (!is_null($length)) {
- $this->length = (int) $length;
- }
-
- return $this->length;
- }
-
/**
* Append HTTP response body
* @param string $body Content to append to the current HTTP response body
* @param bool $replace Overwrite existing response body?
- * @return string The updated HTTP response body
+ * @return string The updated HTTP response body
*/
public function write($body, $replace = false)
{
if ($replace) {
$this->body = $body;
} else {
- $this->body .= (string) $body;
+ $this->body .= (string)$body;
}
$this->length = strlen($this->body);
return $this->body;
}
+ public function getLength()
+ {
+ return $this->length;
+ }
+
+ /**
+ * DEPRECATION WARNING! Use `getLength` or `write` or `body` instead.
+ *
+ * Get and set length
+ * @param int|null $length
+ * @return int
+ */
+ public function length($length = null)
+ {
+ if (!is_null($length)) {
+ $this->length = (int) $length;
+ }
+
+ return $this->length;
+ }
+
/**
* Finalize
*
@@ -232,16 +269,19 @@ public function write($body, $replace = false)
*/
public function finalize()
{
+ // Prepare response
if (in_array($this->status, array(204, 304))) {
- unset($this['Content-Type'], $this['Content-Length']);
-
- return array($this->status, $this->header, '');
- } else {
- return array($this->status, $this->header, $this->body);
+ $this->headers->remove('Content-Type');
+ $this->headers->remove('Content-Length');
+ $this->setBody('');
}
+
+ return array($this->status, $this->headers, $this->body);
}
/**
+ * DEPRECATION WARNING! Access `cookies` property directly.
+ *
* Set cookie
*
* Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie`
@@ -256,10 +296,13 @@ public function finalize()
*/
public function setCookie($name, $value)
{
- Util::setCookieHeader($this->header, $name, $value);
+ // Util::setCookieHeader($this->header, $name, $value);
+ $this->cookies->set($name, $value);
}
/**
+ * DEPRECATION WARNING! Access `cookies` property directly.
+ *
* Delete cookie
*
* Instead of using PHP's `setcookie()` function, Slim manually constructs the HTTP `Set-Cookie`
@@ -274,12 +317,13 @@ public function setCookie($name, $value)
* array, only the Cookie with the given name AND domain will be removed. The invalidating cookie
* sent with this response will adopt all properties of the second argument.
*
- * @param string $name The name of the cookie
- * @param array $value Properties for cookie including: value, expire, path, domain, secure, httponly
+ * @param string $name The name of the cookie
+ * @param array $settings Properties for cookie including: value, expire, path, domain, secure, httponly
*/
- public function deleteCookie($name, $value = array())
+ public function deleteCookie($name, $settings = array())
{
- Util::deleteCookieHeader($this->header, $name, $value);
+ $this->cookies->remove($name, $settings);
+ // Util::deleteCookieHeader($this->header, $name, $value);
}
/**
@@ -293,8 +337,8 @@ public function deleteCookie($name, $value = array())
*/
public function redirect ($url, $status = 302)
{
- $this->status = $status;
- $this['Location'] = $url;
+ $this->setStatus($status);
+ $this->headers->set('Location', $url);
}
/**
@@ -387,24 +431,25 @@ public function isServerError()
return $this->status >= 500 && $this->status < 600;
}
+ /**
+ * DEPRECATION WARNING! ArrayAccess interface will be removed from \Slim\Http\Response.
+ * Iterate `headers` or `cookies` properties directly.
+ */
+
/**
* Array Access: Offset Exists
*/
- public function offsetExists( $offset )
+ public function offsetExists($offset)
{
- return isset($this->header[$offset]);
+ return isset($this->headers[$offset]);
}
/**
* Array Access: Offset Get
*/
- public function offsetGet( $offset )
+ public function offsetGet($offset)
{
- if (isset($this->header[$offset])) {
- return $this->header[$offset];
- } else {
- return null;
- }
+ return $this->headers[$offset];
}
/**
@@ -412,7 +457,7 @@ public function offsetGet( $offset )
*/
public function offsetSet($offset, $value)
{
- $this->header[$offset] = $value;
+ $this->headers[$offset] = $value;
}
/**
@@ -420,18 +465,24 @@ public function offsetSet($offset, $value)
*/
public function offsetUnset($offset)
{
- unset($this->header[$offset]);
+ unset($this->headers[$offset]);
}
/**
+ * DEPRECATION WARNING! Countable interface will be removed from \Slim\Http\Response.
+ * Call `count` on `headers` or `cookies` properties directly.
+ *
* Countable: Count
*/
public function count()
{
- return count($this->header);
+ return count($this->headers);
}
/**
+ * DEPRECATION WARNING! IteratorAggreate interface will be removed from \Slim\Http\Response.
+ * Iterate `headers` or `cookies` properties directly.
+ *
* Get Iterator
*
* This returns the contained `\Slim\Http\Headers` instance which
@@ -441,11 +492,12 @@ public function count()
*/
public function getIterator()
{
- return $this->header;
+ return $this->headers->getIterator();
}
/**
* Get message for HTTP status code
+ * @param int $status
* @return string|null
*/
public static function getMessageForCode($status)
diff --git a/Slim/Http/Util.php b/Slim/Http/Util.php
index f7e99a962..b3a1f12d5 100644
--- a/Slim/Http/Util.php
+++ b/Slim/Http/Util.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -51,14 +51,15 @@ class Util
* override the magic quotes setting with either TRUE or FALSE as the send argument
* to force this method to strip or not strip slashes from its input.
*
- * @var array|string $rawData
+ * @param array|string $rawData
+ * @param bool $overrideStripSlashes
* @return array|string
*/
public static function stripSlashesIfMagicQuotes($rawData, $overrideStripSlashes = null)
{
$strip = is_null($overrideStripSlashes) ? get_magic_quotes_gpc() : $overrideStripSlashes;
if ($strip) {
- return self::_stripSlashes($rawData);
+ return self::stripSlashes($rawData);
} else {
return $rawData;
}
@@ -69,9 +70,9 @@ public static function stripSlashesIfMagicQuotes($rawData, $overrideStripSlashes
* @param array|string $rawData
* @return array|string
*/
- protected static function _stripSlashes($rawData)
+ protected static function stripSlashes($rawData)
{
- return is_array($rawData) ? array_map(array('self', '_stripSlashes'), $rawData) : stripslashes($rawData);
+ return is_array($rawData) ? array_map(array('self', 'stripSlashes'), $rawData) : stripslashes($rawData);
}
/**
@@ -95,10 +96,11 @@ public static function encrypt($data, $key, $iv, $settings = array())
}
//Merge settings with defaults
- $settings = array_merge(array(
+ $defaults = array(
'algorithm' => MCRYPT_RIJNDAEL_256,
'mode' => MCRYPT_MODE_CBC
- ), $settings);
+ );
+ $settings = array_merge($defaults, $settings);
//Get module
$module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
@@ -144,10 +146,11 @@ public static function decrypt($data, $key, $iv, $settings = array())
}
//Merge settings with defaults
- $settings = array_merge(array(
+ $defaults = array(
'algorithm' => MCRYPT_RIJNDAEL_256,
'mode' => MCRYPT_MODE_CBC
- ), $settings);
+ );
+ $settings = array_merge($defaults, $settings);
//Get module
$module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
@@ -173,6 +176,32 @@ public static function decrypt($data, $key, $iv, $settings = array())
return $res;
}
+ /**
+ * Serialize Response cookies into raw HTTP header
+ * @param \Slim\Http\Headers $headers The Response headers
+ * @param \Slim\Http\Cookies $cookies The Response cookies
+ * @param array $config The Slim app settings
+ */
+ public static function serializeCookies(\Slim\Http\Headers &$headers, \Slim\Http\Cookies $cookies, array $config)
+ {
+ if ($config['cookies.encrypt']) {
+ foreach ($cookies as $name => $settings) {
+ $settings['value'] = static::encodeSecureCookie(
+ $settings['value'],
+ $settings['expires'],
+ $config['cookies.secret_key'],
+ $config['cookies.cipher'],
+ $config['cookies.cipher_mode']
+ );
+ static::setCookieHeader($headers, $name, $settings);
+ }
+ } else {
+ foreach ($cookies as $name => $settings) {
+ static::setCookieHeader($headers, $name, $settings);
+ }
+ }
+ }
+
/**
* Encode secure cookie value
*
@@ -180,21 +209,28 @@ public static function decrypt($data, $key, $iv, $settings = array())
* cookie value is encrypted and hashed so that its value is
* secure and checked for integrity when read in subsequent requests.
*
- * @param string $value The unsecure HTTP cookie value
+ * @param string $value The insecure HTTP cookie value
* @param int $expires The UNIX timestamp at which this cookie will expire
* @param string $secret The secret key used to hash the cookie value
* @param int $algorithm The algorithm to use for encryption
* @param int $mode The algorithm mode to use for encryption
- * @param string
+ * @return string
*/
public static function encodeSecureCookie($value, $expires, $secret, $algorithm, $mode)
{
$key = hash_hmac('sha1', $expires, $secret);
- $iv = self::get_iv($expires, $secret);
- $secureString = base64_encode(self::encrypt($value, $key, $iv, array(
- 'algorithm' => $algorithm,
- 'mode' => $mode
- )));
+ $iv = self::getIv($expires, $secret);
+ $secureString = base64_encode(
+ self::encrypt(
+ $value,
+ $key,
+ $iv,
+ array(
+ 'algorithm' => $algorithm,
+ 'mode' => $mode
+ )
+ )
+ );
$verificationString = hash_hmac('sha1', $expires . $value, $key);
return implode('|', array($expires, $secureString, $verificationString));
@@ -208,11 +244,10 @@ public static function encodeSecureCookie($value, $expires, $secret, $algorithm,
* secure and checked for integrity when read in subsequent requests.
*
* @param string $value The secure HTTP cookie value
- * @param int $expires The UNIX timestamp at which this cookie will expire
* @param string $secret The secret key used to hash the cookie value
* @param int $algorithm The algorithm to use for encryption
* @param int $mode The algorithm mode to use for encryption
- * @param string
+ * @return bool|string
*/
public static function decodeSecureCookie($value, $secret, $algorithm, $mode)
{
@@ -220,11 +255,16 @@ public static function decodeSecureCookie($value, $secret, $algorithm, $mode)
$value = explode('|', $value);
if (count($value) === 3 && ((int) $value[0] === 0 || (int) $value[0] > time())) {
$key = hash_hmac('sha1', $value[0], $secret);
- $iv = self::get_iv($value[0], $secret);
- $data = self::decrypt(base64_decode($value[1]), $key, $iv, array(
- 'algorithm' => $algorithm,
- 'mode' => $mode
- ));
+ $iv = self::getIv($value[0], $secret);
+ $data = self::decrypt(
+ base64_decode($value[1]),
+ $key,
+ $iv,
+ array(
+ 'algorithm' => $algorithm,
+ 'mode' => $mode
+ )
+ );
$verificationString = hash_hmac('sha1', $value[0] . $data, $key);
if ($verificationString === $value[2]) {
return $data;
@@ -310,7 +350,7 @@ public static function setCookieHeader(&$header, $name, $value)
*
* @param array $header
* @param string $name
- * @param string $value
+ * @param array $value
*/
public static function deleteCookieHeader(&$header, $name, $value = array())
{
@@ -376,9 +416,9 @@ public static function parseCookieHeader($header)
*
* @param int $expires The UNIX timestamp at which this cookie will expire
* @param string $secret The secret key used to hash the cookie value
- * @return binary string with length 40
+ * @return string Hash
*/
- private static function get_iv($expires, $secret)
+ private static function getIv($expires, $secret)
{
$data1 = hash_hmac('sha1', 'a'.$expires.'b', $secret);
$data2 = hash_hmac('sha1', 'z'.$expires.'y', $secret);
diff --git a/Slim/Log.php b/Slim/Log.php
index 7706b2f24..1c679d07b 100644
--- a/Slim/Log.php
+++ b/Slim/Log.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -39,11 +39,15 @@
* a Log Writer in conjunction with this Log to write to various output
* destinations (e.g. a file). This class provides this interface:
*
- * debug( mixed $object )
- * info( mixed $object )
- * warn( mixed $object )
- * error( mixed $object )
- * fatal( mixed $object )
+ * debug( mixed $object, array $context )
+ * info( mixed $object, array $context )
+ * notice( mixed $object, array $context )
+ * warning( mixed $object, array $context )
+ * error( mixed $object, array $context )
+ * critical( mixed $object, array $context )
+ * alert( mixed $object, array $context )
+ * emergency( mixed $object, array $context )
+ * log( mixed $level, mixed $object, array $context )
*
* This class assumes only that your Log Writer has a public `write()` method
* that accepts any object as its one and only argument. The Log Writer
@@ -56,21 +60,28 @@
*/
class Log
{
- const FATAL = 0;
- const ERROR = 1;
- const WARN = 2;
- const INFO = 3;
- const DEBUG = 4;
+ const EMERGENCY = 1;
+ const ALERT = 2;
+ const CRITICAL = 3;
+ const FATAL = 3; //DEPRECATED replace with CRITICAL
+ const ERROR = 4;
+ const WARN = 5;
+ const NOTICE = 6;
+ const INFO = 7;
+ const DEBUG = 8;
/**
* @var array
*/
protected static $levels = array(
- self::FATAL => 'FATAL',
- self::ERROR => 'ERROR',
- self::WARN => 'WARN',
- self::INFO => 'INFO',
- self::DEBUG => 'DEBUG'
+ self::EMERGENCY => 'EMERGENCY',
+ self::ALERT => 'ALERT',
+ self::CRITICAL => 'CRITICAL',
+ self::ERROR => 'ERROR',
+ self::WARN => 'WARNING',
+ self::NOTICE => 'NOTICE',
+ self::INFO => 'INFO',
+ self::DEBUG => 'DEBUG'
);
/**
@@ -173,65 +184,166 @@ public function isEnabled()
/**
* Log debug message
* @param mixed $object
- * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
- public function debug($object)
+ public function debug($object, $context = array())
{
- return $this->write($object, self::DEBUG);
+ return $this->log(self::DEBUG, $object, $context);
}
/**
* Log info message
* @param mixed $object
- * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
- public function info($object)
+ public function info($object, $context = array())
{
- return $this->write($object, self::INFO);
+ return $this->log(self::INFO, $object, $context);
}
/**
- * Log warn message
+ * Log notice message
* @param mixed $object
- * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
- public function warn($object)
+ public function notice($object, $context = array())
{
- return $this->write($object, self::WARN);
+ return $this->log(self::NOTICE, $object, $context);
+ }
+
+ /**
+ * Log warning message
+ * @param mixed $object
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function warning($object, $context = array())
+ {
+ return $this->log(self::WARN, $object, $context);
+ }
+
+ /**
+ * DEPRECATED for function warning
+ * Log warning message
+ * @param mixed $object
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function warn($object, $context = array())
+ {
+ return $this->log(self::WARN, $object, $context);
}
/**
* Log error message
* @param mixed $object
- * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
- public function error($object)
+ public function error($object, $context = array())
{
- return $this->write($object, self::ERROR);
+ return $this->log(self::ERROR, $object, $context);
}
/**
+ * Log critical message
+ * @param mixed $object
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function critical($object, $context = array())
+ {
+ return $this->log(self::CRITICAL, $object, $context);
+ }
+
+ /**
+ * DEPRECATED for function critical
* Log fatal message
* @param mixed $object
- * @return mixed|false What the Logger returns, or false if Logger not set or not enabled
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function fatal($object, $context = array())
+ {
+ return $this->log(self::CRITICAL, $object, $context);
+ }
+
+ /**
+ * Log alert message
+ * @param mixed $object
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
+ */
+ public function alert($object, $context = array())
+ {
+ return $this->log(self::ALERT, $object, $context);
+ }
+
+ /**
+ * Log emergency message
+ * @param mixed $object
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
*/
- public function fatal($object)
+ public function emergency($object, $context = array())
{
- return $this->write($object, self::FATAL);
+ return $this->log(self::EMERGENCY, $object, $context);
}
/**
* Log message
- * @param mixed The object to log
- * @param int The message level
- * @return int|false
+ * @param mixed $level
+ * @param mixed $object
+ * @param array $context
+ * @return mixed|bool What the Logger returns, or false if Logger not set or not enabled
+ * @throws \InvalidArgumentException If invalid log level
*/
- protected function write($object, $level)
+ public function log($level, $object, $context = array())
{
- if ($this->enabled && $this->writer && $level <= $this->level) {
- return $this->writer->write($object, $level);
+ if (!isset(self::$levels[$level])) {
+ throw new \InvalidArgumentException('Invalid log level supplied to function');
+ } else if ($this->enabled && $this->writer && $level <= $this->level) {
+ $message = (string)$object;
+ if (count($context) > 0) {
+ if (isset($context['exception']) && $context['exception'] instanceof \Exception) {
+ $message .= ' - ' . $context['exception'];
+ unset($context['exception']);
+ }
+ $message = $this->interpolate($message, $context);
+ }
+ return $this->writer->write($message, $level);
} else {
return false;
}
}
+
+ /**
+ * DEPRECATED for function log
+ * Log message
+ * @param mixed $object The object to log
+ * @param int $level The message level
+ * @return int|bool
+ */
+ protected function write($object, $level)
+ {
+ return $this->log($level, $object);
+ }
+
+ /**
+ * Interpolate log message
+ * @param mixed $message The log message
+ * @param array $context An array of placeholder values
+ * @return string The processed string
+ */
+ protected function interpolate($message, $context = array())
+ {
+ $replace = array();
+ foreach ($context as $key => $value) {
+ $replace['{' . $key . '}'] = $value;
+ }
+ return strtr($message, $replace);
+ }
}
diff --git a/Slim/LogWriter.php b/Slim/LogWriter.php
index f26eb0fcb..47c1f4e40 100644
--- a/Slim/LogWriter.php
+++ b/Slim/LogWriter.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -66,7 +66,7 @@ public function __construct($resource)
* Write message
* @param mixed $message
* @param int $level
- * @return int|false
+ * @return int|bool
*/
public function write($message, $level = null)
{
diff --git a/Slim/Middleware.php b/Slim/Middleware.php
index 641226a68..09ff17767 100644
--- a/Slim/Middleware.php
+++ b/Slim/Middleware.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -42,7 +42,7 @@
abstract class Middleware
{
/**
- * @var \Slim Reference to the primary application instance
+ * @var \Slim\Slim Reference to the primary application instance
*/
protected $app;
@@ -57,7 +57,7 @@ abstract class Middleware
* This method injects the primary Slim application instance into
* this middleware.
*
- * @param \Slim $application
+ * @param \Slim\Slim $application
*/
final public function setApplication($application)
{
@@ -70,7 +70,7 @@ final public function setApplication($application)
* This method retrieves the application previously injected
* into this middleware.
*
- * @return \Slim
+ * @return \Slim\Slim
*/
final public function getApplication()
{
@@ -97,7 +97,7 @@ final public function setNextMiddleware($nextMiddleware)
* This method retrieves the next downstream middleware
* previously injected into this middleware.
*
- * @return \Slim|\Slim\Middleware
+ * @return \Slim\Slim|\Slim\Middleware
*/
final public function getNextMiddleware()
{
diff --git a/Slim/Middleware/ContentTypes.php b/Slim/Middleware/ContentTypes.php
index b11e46052..809b500c0 100644
--- a/Slim/Middleware/ContentTypes.php
+++ b/Slim/Middleware/ContentTypes.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -58,12 +58,13 @@ class ContentTypes extends \Slim\Middleware
*/
public function __construct($settings = array())
{
- $this->contentTypes = array_merge(array(
+ $defaults = array(
'application/json' => array($this, 'parseJson'),
'application/xml' => array($this, 'parseXml'),
'text/xml' => array($this, 'parseXml'),
'text/csv' => array($this, 'parseCsv')
- ), $settings);
+ );
+ $this->contentTypes = array_merge($defaults, $settings);
}
/**
diff --git a/Slim/Middleware/Flash.php b/Slim/Middleware/Flash.php
index 510bca300..a1647665b 100644
--- a/Slim/Middleware/Flash.php
+++ b/Slim/Middleware/Flash.php
@@ -59,7 +59,6 @@ class Flash extends \Slim\Middleware implements \ArrayAccess, \IteratorAggregate
/**
* Constructor
- * @param \Slim $app
* @param array $settings
*/
public function __construct($settings = array())
diff --git a/Slim/Middleware/MethodOverride.php b/Slim/Middleware/MethodOverride.php
index 6f5fffb10..f43b41f0b 100644
--- a/Slim/Middleware/MethodOverride.php
+++ b/Slim/Middleware/MethodOverride.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -36,7 +36,7 @@
* HTTP Method Override
*
* This is middleware for a Slim application that allows traditional
- * desktop browsers to submit psuedo PUT and DELETE requests by relying
+ * desktop browsers to submit pseudo PUT and DELETE requests by relying
* on a pre-determined request parameter. Without this middleware,
* desktop browsers are only able to submit GET and POST requests.
*
@@ -55,7 +55,6 @@ class MethodOverride extends \Slim\Middleware
/**
* Constructor
- * @param \Slim $app
* @param array $settings
*/
public function __construct($settings = array())
@@ -72,7 +71,6 @@ public function __construct($settings = array())
* modifies the environment settings so downstream middleware and/or the Slim
* application will treat the request with the desired HTTP method.
*
- * @param array $env
* @return array[status, header, body]
*/
public function call()
diff --git a/Slim/Middleware/PrettyExceptions.php b/Slim/Middleware/PrettyExceptions.php
index e079e30f5..b67545e19 100644
--- a/Slim/Middleware/PrettyExceptions.php
+++ b/Slim/Middleware/PrettyExceptions.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -66,6 +66,7 @@ public function call()
try {
$this->next->call();
} catch (\Exception $e) {
+ $log = $this->app->getLog(); // Force Slim to append log to env if not already
$env = $this->app->environment();
$env['slim.log']->error($e);
$this->app->contentType('text/html');
diff --git a/Slim/Middleware/SessionCookie.php b/Slim/Middleware/SessionCookie.php
index 1747a8677..d13dd94cd 100644
--- a/Slim/Middleware/SessionCookie.php
+++ b/Slim/Middleware/SessionCookie.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -51,7 +51,7 @@
* session data in a database or alternative server-side cache.
*
* Because this class stores serialized session data in an HTTP cookie,
- * you are inherently limtied to 4 Kb. If you attempt to store
+ * you are inherently limited to 4 Kb. If you attempt to store
* more than this amount, serialization will fail.
*
* @package Slim
@@ -72,7 +72,7 @@ class SessionCookie extends \Slim\Middleware
*/
public function __construct($settings = array())
{
- $this->settings = array_merge(array(
+ $defaults = array(
'expires' => '20 minutes',
'path' => '/',
'domain' => null,
@@ -82,7 +82,8 @@ public function __construct($settings = array())
'secret' => 'CHANGE_ME',
'cipher' => MCRYPT_RIJNDAEL_256,
'cipher_mode' => MCRYPT_MODE_CBC
- ), $settings);
+ );
+ $this->settings = array_merge($defaults, $settings);
if (is_string($this->settings['expires'])) {
$this->settings['expires'] = strtotime($this->settings['expires']);
}
@@ -119,7 +120,6 @@ public function call()
/**
* Load session
- * @param array $env
*/
protected function loadSession()
{
@@ -155,14 +155,17 @@ protected function saveSession()
if (strlen($value) > 4096) {
$this->app->getLog()->error('WARNING! Slim\Middleware\SessionCookie data size is larger than 4KB. Content save failed.');
} else {
- $this->app->response()->setCookie($this->settings['name'], array(
- 'value' => $value,
- 'domain' => $this->settings['domain'],
- 'path' => $this->settings['path'],
- 'expires' => $this->settings['expires'],
- 'secure' => $this->settings['secure'],
- 'httponly' => $this->settings['httponly']
- ));
+ $this->app->response()->setCookie(
+ $this->settings['name'],
+ array(
+ 'value' => $value,
+ 'domain' => $this->settings['domain'],
+ 'path' => $this->settings['path'],
+ 'expires' => $this->settings['expires'],
+ 'secure' => $this->settings['secure'],
+ 'httponly' => $this->settings['httponly']
+ )
+ );
}
session_destroy();
}
diff --git a/Slim/Route.php b/Slim/Route.php
index 445fbe9d5..d1f7fbf77 100644
--- a/Slim/Route.php
+++ b/Slim/Route.php
@@ -285,6 +285,7 @@ public function via()
/**
* Detect support for an HTTP method
+ * @param string $method
* @return bool
*/
public function supportsHttpMethod($method)
@@ -320,7 +321,7 @@ public function setMiddleware($middleware)
if (is_callable($middleware)) {
$this->middleware[] = $middleware;
} elseif (is_array($middleware)) {
- foreach($middleware as $callable) {
+ foreach ($middleware as $callable) {
if (!is_callable($callable)) {
throw new \InvalidArgumentException('All Route middleware must be callable');
}
@@ -347,8 +348,11 @@ public function setMiddleware($middleware)
public function matches($resourceUri)
{
//Convert URL params into regex patterns, construct a regex for this route, init params
- $patternAsRegex = preg_replace_callback('#:([\w]+)\+?#', array($this, 'matchesCallback'),
- str_replace(')', ')?', (string) $this->pattern));
+ $patternAsRegex = preg_replace_callback(
+ '#:([\w]+)\+?#',
+ array($this, 'matchesCallback'),
+ str_replace(')', ')?', (string) $this->pattern)
+ );
if (substr($this->pattern, -1) === '/') {
$patternAsRegex .= '?';
}
@@ -372,8 +376,8 @@ public function matches($resourceUri)
/**
* Convert a URL parameter (e.g. ":id", ":id+") into a regular expression
- * @param array URL parameters
- * @return string Regular expression for URL parameter
+ * @param array $m URL parameters
+ * @return string Regular expression for URL parameter
*/
protected function matchesCallback($m)
{
@@ -413,4 +417,23 @@ public function conditions(array $conditions)
return $this;
}
+
+ /**
+ * Dispatch route
+ *
+ * This method invokes the route object's callable. If middleware is
+ * registered for the route, each callable middleware is invoked in
+ * the order specified.
+ *
+ * @return bool
+ */
+ public function dispatch()
+ {
+ foreach ($this->middleware as $mw) {
+ call_user_func_array($mw, array($this));
+ }
+
+ $return = call_user_func_array($this->getCallable(), array_values($this->getParams()));
+ return ($return === false)? false : true;
+ }
}
diff --git a/Slim/Router.php b/Slim/Router.php
index 44979ea0a..2f47fb895 100644
--- a/Slim/Router.php
+++ b/Slim/Router.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -63,12 +63,18 @@ class Router
*/
protected $matchedRoutes;
+ /**
+ * @var array Array containing all route groups
+ */
+ protected $routeGroups;
+
/**
* Constructor
*/
public function __construct()
{
$this->routes = array();
+ $this->routeGroups = array();
}
/**
@@ -100,7 +106,7 @@ public function getMatchedRoutes($httpMethod, $resourceUri, $reload = false)
if ($reload || is_null($this->matchedRoutes)) {
$this->matchedRoutes = array();
foreach ($this->routes as $route) {
- if (!$route->supportsHttpMethod($httpMethod)) {
+ if (!$route->supportsHttpMethod($httpMethod) && !$route->supportsHttpMethod("ANY")) {
continue;
}
@@ -114,25 +120,66 @@ public function getMatchedRoutes($httpMethod, $resourceUri, $reload = false)
}
/**
- * Map a route object to a callback function
- * @param string $pattern The URL pattern (ie. "/books/:id")
- * @param mixed $callable Anything that returns TRUE for is_callable()
- * @return \Slim\Route
+ * Add a route object to the router
+ * @param \Slim\Route $route The Slim Route
*/
- public function map($pattern, $callable)
+ public function map(\Slim\Route $route)
{
- $route = new \Slim\Route($pattern, $callable);
+ list($groupPattern, $groupMiddleware) = $this->processGroups();
+
+ $route->setPattern($groupPattern . $route->getPattern());
$this->routes[] = $route;
- return $route;
+
+ foreach ($groupMiddleware as $middleware) {
+ $route->setMiddleware($middleware);
+ }
+ }
+
+ /**
+ * A helper function for processing the group's pattern and middleware
+ * @return array Returns an array with the elements: pattern, middlewareArr
+ */
+ protected function processGroups()
+ {
+ $pattern = "";
+ $middleware = array();
+ foreach ($this->routeGroups as $group) {
+ $k = key($group);
+ $pattern .= $k;
+ if (is_array($group[$k])) {
+ $middleware = array_merge($middleware, $group[$k]);
+ }
+ }
+ return array($pattern, $middleware);
+ }
+
+ /**
+ * Add a route group to the array
+ * @param string $group The group pattern (ie. "/books/:id")
+ * @param array|null $middleware Optional parameter array of middleware
+ * @return int The index of the new group
+ */
+ public function pushGroup($group, $middleware = array())
+ {
+ return array_push($this->routeGroups, array($group => $middleware));
+ }
+
+ /**
+ * Removes the last route group from the array
+ * @return bool True if successful, else False
+ */
+ public function popGroup()
+ {
+ return (array_pop($this->routeGroups) !== null);
}
/**
* Get URL for named route
* @param string $name The name of the route
- * @param array Associative array of URL parameter names and replacement values
- * @throws RuntimeException If named route not found
- * @return string The URL for the given route populated with provided replacement values
+ * @param array $params Associative array of URL parameter names and replacement values
+ * @throws \RuntimeException If named route not found
+ * @return string The URL for the given route populated with provided replacement values
*/
public function urlFor($name, $params = array())
{
@@ -140,8 +187,8 @@ public function urlFor($name, $params = array())
throw new \RuntimeException('Named route not found for name: ' . $name);
}
$search = array();
- foreach (array_keys($params) as $key) {
- $search[] = '#:' . $key . '\+?(?!\w)#';
+ foreach ($params as $key => $value) {
+ $search[] = '#:' . preg_quote($key, '#') . '\+?(?!\w)#';
}
$pattern = preg_replace($search, $params, $this->getNamedRoute($name)->getPattern());
@@ -149,36 +196,11 @@ public function urlFor($name, $params = array())
return preg_replace('#\(/?:.+\)|\(|\)#', '', $pattern);
}
- /**
- * Dispatch route
- *
- * This method invokes the route object's callable. If middleware is
- * registered for the route, each callable middleware is invoked in
- * the order specified.
- *
- * @param \Slim\Route $route The route object
- * @return bool Was route callable invoked successfully?
- */
- public function dispatch(\Slim\Route $route)
- {
- $this->currentRoute = $route;
-
- //Invoke middleware
- foreach ($route->getMiddleware() as $mw) {
- call_user_func_array($mw, array($route));
- }
-
- //Invoke callable
- call_user_func_array($route->getCallable(), array_values($route->getParams()));
-
- return true;
- }
-
/**
* Add named route
* @param string $name The route name
* @param \Slim\Route $route The route object
- * @throws \RuntimeException If a named route already exists with the same name
+ * @throws \RuntimeException If a named route already exists with the same name
*/
public function addNamedRoute($name, \Slim\Route $route)
{
diff --git a/Slim/Slim.php b/Slim/Slim.php
index 5e10c6073..86f7537cd 100644
--- a/Slim/Slim.php
+++ b/Slim/Slim.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -49,52 +49,22 @@ class Slim
/**
* @const string
*/
- const VERSION = '2.2.0';
+ const VERSION = '2.3.0';
/**
- * @var array[\Slim]
+ * @var \Slim\Helper\Set
*/
- protected static $apps = array();
-
- /**
- * @var string
- */
- protected $name;
+ public $container;
/**
- * @var array
- */
- protected $environment;
-
- /**
- * @var \Slim\Http\Request
- */
- protected $request;
-
- /**
- * @var \Slim\Http\Response
- */
- protected $response;
-
- /**
- * @var \Slim\Router
- */
- protected $router;
-
- /**
- * @var \Slim\View
- */
- protected $view;
-
- /**
- * @var array
+ * @var array[\Slim]
*/
- protected $settings;
+ protected static $apps = array();
/**
* @var string
*/
- protected $mode;
+ protected $name;
/**
* @var array
@@ -173,44 +143,98 @@ public static function registerAutoloader()
* Constructor
* @param array $userSettings Associative array of application settings
*/
- public function __construct($userSettings = array())
+ public function __construct(array $userSettings = array())
{
- // Setup Slim application
- $this->settings = array_merge(static::getDefaultSettings(), $userSettings);
- $this->environment = \Slim\Environment::getInstance();
- $this->request = new \Slim\Http\Request($this->environment);
- $this->response = new \Slim\Http\Response();
- $this->router = new \Slim\Router();
+ // Setup IoC container
+ $this->container = new \Slim\Helper\Set();
+ $this->container['settings'] = array_merge(static::getDefaultSettings(), $userSettings);
+
+ // Default environment
+ $this->container->singleton('environment', function ($c) {
+ return \Slim\Environment::getInstance();
+ });
+
+ // Default request
+ $this->container->singleton('request', function ($c) {
+ return new \Slim\Http\Request($c['environment']);
+ });
+
+ // Default response
+ $this->container->singleton('response', function ($c) {
+ return new \Slim\Http\Response();
+ });
+
+ // Default router
+ $this->container->singleton('router', function ($c) {
+ return new \Slim\Router();
+ });
+
+ // Default view
+ $this->container->singleton('view', function ($c) {
+ $viewClass = $c['settings']['view'];
+
+ return ($viewClass instanceOf \Slim\View) ? $viewClass : new $viewClass;
+ });
+
+ // Default log writer
+ $this->container->singleton('logWriter', function ($c) {
+ $logWriter = $c['settings']['log.writer'];
+
+ return is_object($logWriter) ? $logWriter : new \Slim\LogWriter($c['environment']['slim.errors']);
+ });
+
+ // Default log
+ $this->container->singleton('log', function ($c) {
+ $log = new \Slim\Log($c['logWriter']);
+ $log->setEnabled($c['settings']['log.enabled']);
+ $log->setLevel($c['settings']['log.level']);
+ $env = $c['environment'];
+ $env['slim.log'] = $log;
+
+ return $log;
+ });
+
+ // Default mode
+ $this->container['mode'] = function ($c) {
+ $mode = $c['settings']['mode'];
+
+ if (isset($_ENV['SLIM_MODE'])) {
+ $mode = $_ENV['SLIM_MODE'];
+ } else {
+ $envMode = getenv('SLIM_MODE');
+ if ($envMode !== false) {
+ $mode = $envMode;
+ }
+ }
+
+ return $mode;
+ };
+
+ // Define default middleware stack
$this->middleware = array($this);
$this->add(new \Slim\Middleware\Flash());
$this->add(new \Slim\Middleware\MethodOverride());
- // Determine application mode
- $this->getMode();
-
- // Setup view
- $this->view($this->config('view'));
-
// Make default if first instance
if (is_null(static::getInstance())) {
$this->setName('default');
}
+ }
- // Set default logger that writes to stderr (may be overridden with middleware)
- $logWriter = $this->config('log.writer');
- if (!$logWriter) {
- $logWriter = new \Slim\LogWriter($this->environment['slim.errors']);
- }
- $log = new \Slim\Log($logWriter);
- $log->setEnabled($this->config('log.enabled'));
- $log->setLevel($this->config('log.level'));
- $this->environment['slim.log'] = $log;
+ public function __get($name)
+ {
+ return $this->container[$name];
+ }
+
+ public function __set($name, $value)
+ {
+ $this->container[$name] = $value;
}
/**
* Get application instance by name
* @param string $name The name of the Slim application
- * @return \Slim|null
+ * @return \Slim\Slim|null
*/
public static function getInstance($name = 'default')
{
@@ -255,6 +279,7 @@ public static function getDefaultSettings()
'templates.path' => './templates',
'view' => '\Slim\View',
// Cookies
+ 'cookies.encrypt' => false,
'cookies.lifetime' => '20 minutes',
'cookies.path' => '/',
'cookies.domain' => null,
@@ -297,7 +322,9 @@ public function config($name, $value = null)
return isset($this->settings[$name]) ? $this->settings[$name] : null;
}
} else {
- $this->settings[$name] = $value;
+ $settings = $this->settings;
+ $settings[$name] = $value;
+ $this->settings = $settings;
}
}
@@ -316,19 +343,6 @@ public function config($name, $value = null)
*/
public function getMode()
{
- if (!isset($this->mode)) {
- if (isset($_ENV['SLIM_MODE'])) {
- $this->mode = $_ENV['SLIM_MODE'];
- } else {
- $envMode = getenv('SLIM_MODE');
- if ($envMode !== false) {
- $this->mode = $envMode;
- } else {
- $this->mode = $this->config('mode');
- }
- }
- }
-
return $this->mode;
}
@@ -361,7 +375,7 @@ public function configureMode($mode, $callable)
*/
public function getLog()
{
- return $this->environment['slim.log'];
+ return $this->log;
}
/********************************************************************************
@@ -369,7 +383,7 @@ public function getLog()
*******************************************************************************/
/**
- * Add GET|POST|PUT|DELETE route
+ * Add GET|POST|PUT|PATCH|DELETE route
*
* Adds a new route to the router with associated callable. This
* route will only be invoked when the HTTP request's method matches
@@ -402,7 +416,8 @@ protected function mapRoute($args)
{
$pattern = array_shift($args);
$callable = array_pop($args);
- $route = $this->router->map($pattern, $callable);
+ $route = new \Slim\Route($pattern, $callable);
+ $this->router->map($route);
if (count($args) > 0) {
$route->setMiddleware($args);
}
@@ -458,6 +473,18 @@ public function put()
return $this->mapRoute($args)->via(\Slim\Http\Request::METHOD_PUT);
}
+ /**
+ * Add PATCH route
+ * @see mapRoute()
+ * @return \Slim\Route
+ */
+ public function patch()
+ {
+ $args = func_get_args();
+
+ return $this->mapRoute($args)->via(\Slim\Http\Request::METHOD_PATCH);
+ }
+
/**
* Add DELETE route
* @see mapRoute()
@@ -482,6 +509,40 @@ public function options()
return $this->mapRoute($args)->via(\Slim\Http\Request::METHOD_OPTIONS);
}
+ /**
+ * Route Groups
+ *
+ * This method accepts a route pattern and a callback all Route
+ * declarations in the callback will be prepended by the group(s)
+ * that it is in
+ *
+ * Accepts the same paramters as a standard route so:
+ * (pattern, middleware1, middleware2, ..., $callback)
+ */
+ public function group()
+ {
+ $args = func_get_args();
+ $pattern = array_shift($args);
+ $callable = array_pop($args);
+ $this->router->pushGroup($pattern, $args);
+ if (is_callable($callable)) {
+ call_user_func($callable);
+ }
+ $this->router->popGroup();
+ }
+
+ /*
+ * Add route for any HTTP method
+ * @see mapRoute()
+ * @return \Slim\Route
+ */
+ public function any()
+ {
+ $args = func_get_args();
+
+ return $this->mapRoute($args)->via("ANY");
+ }
+
/**
* Not Found Handler
*
@@ -503,12 +564,13 @@ public function options()
*
* @param mixed $callable Anything that returns true for is_callable()
*/
- public function notFound( $callable = null ) {
- if ( is_callable($callable) ) {
+ public function notFound ($callable = null)
+ {
+ if (is_callable($callable)) {
$this->notFound = $callable;
} else {
ob_start();
- if ( is_callable($this->notFound) ) {
+ if (is_callable($this->notFound)) {
call_user_func($this->notFound);
} else {
call_user_func(array($this, 'defaultNotFound'));
@@ -566,7 +628,7 @@ public function error($argument = null)
protected function callErrorHandler($argument = null)
{
ob_start();
- if ( is_callable($this->error) ) {
+ if (is_callable($this->error)) {
call_user_func_array($this->error, array($argument));
} else {
call_user_func_array(array($this, 'defaultError'), array($argument));
@@ -653,7 +715,7 @@ public function view($viewClass = null)
/**
* Render a template
*
- * Call this method within a GET, POST, PUT, DELETE, NOT FOUND, or ERROR
+ * Call this method within a GET, POST, PUT, PATCH, DELETE, NOT FOUND, or ERROR
* callable to render a template whose output is appended to the
* current HTTP response body. How the template is rendered is
* delegated to the current View.
@@ -692,8 +754,8 @@ public function render($template, $data = array(), $status = null)
public function lastModified($time)
{
if (is_integer($time)) {
- $this->response['Last-Modified'] = date(DATE_RFC1123, $time);
- if ($time === strtotime($this->request->headers('IF_MODIFIED_SINCE'))) {
+ $this->response->headers->set('Last-Modified', date(DATE_RFC1123, $time));
+ if ($time === strtotime($this->request->headers->get('IF_MODIFIED_SINCE'))) {
$this->halt(304);
}
} else {
@@ -726,11 +788,13 @@ public function etag($value, $type = 'strong')
//Set etag value
$value = '"' . $value . '"';
- if ($type === 'weak') $value = 'W/'.$value;
+ if ($type === 'weak') {
+ $value = 'W/'.$value;
+ }
$this->response['ETag'] = $value;
//Check conditional GET
- if ($etagsHeader = $this->request->headers('IF_NONE_MATCH')) {
+ if ($etagsHeader = $this->request->headers->get('IF_NONE_MATCH')) {
$etags = preg_split('@\s*,\s*@', $etagsHeader);
if (in_array($value, $etags) || in_array('*', $etags)) {
$this->halt(304);
@@ -756,7 +820,7 @@ public function expires($time)
if (is_string($time)) {
$time = strtotime($time);
}
- $this->response['Expires'] = gmdate(DATE_RFC1123, $time);
+ $this->response->headers->set('Expires', gmdate(DATE_RFC1123, $time));
}
/********************************************************************************
@@ -764,7 +828,7 @@ public function expires($time)
*******************************************************************************/
/**
- * Set unencrypted HTTP cookie
+ * Set HTTP cookie to be sent with the HTTP response
*
* @param string $name The cookie name
* @param string $value The cookie value
@@ -779,18 +843,19 @@ public function expires($time)
*/
public function setCookie($name, $value, $time = null, $path = null, $domain = null, $secure = null, $httponly = null)
{
- $this->response->setCookie($name, array(
+ $settings = array(
'value' => $value,
'expires' => is_null($time) ? $this->config('cookies.lifetime') : $time,
'path' => is_null($path) ? $this->config('cookies.path') : $path,
'domain' => is_null($domain) ? $this->config('cookies.domain') : $domain,
'secure' => is_null($secure) ? $this->config('cookies.secure') : $secure,
'httponly' => is_null($httponly) ? $this->config('cookies.httponly') : $httponly
- ));
+ );
+ $this->response->cookies->set($name, $settings);
}
/**
- * Get value of unencrypted HTTP cookie
+ * Get value of HTTP cookie from the current HTTP request
*
* Return the value of a cookie from the current HTTP request,
* or return NULL if cookie does not exist. Cookies created during
@@ -799,12 +864,30 @@ public function setCookie($name, $value, $time = null, $path = null, $domain = n
* @param string $name
* @return string|null
*/
- public function getCookie($name)
+ public function getCookie($name, $deleteIfInvalid = true)
{
- return $this->request->cookies($name);
+ // Get cookie value
+ $value = $this->request->cookies->get($name);
+
+ // Decode if encrypted
+ if ($this->config('cookies.encrypt')) {
+ $value = \Slim\Http\Util::decodeSecureCookie(
+ $value,
+ $this->config('cookies.secret_key'),
+ $this->config('cookies.cipher'),
+ $this->config('cookies.cipher_mode')
+ );
+ if ($value === false && $deleteIfInvalid) {
+ $this->deleteCookie($name);
+ }
+ }
+
+ return $value;
}
/**
+ * DEPRECATION WARNING! Use `setCookie` with the `cookies.encrypt` app setting set to `true`.
+ *
* Set encrypted HTTP cookie
*
* @param string $name The cookie name
@@ -818,23 +901,14 @@ public function getCookie($name)
* HTTPS connection from the client
* @param bool $httponly When TRUE the cookie will be made accessible only through the HTTP protocol
*/
- public function setEncryptedCookie($name, $value, $expires = null, $path = null, $domain = null, $secure = null, $httponly = null)
+ public function setEncryptedCookie($name, $value, $expires = null, $path = null, $domain = null, $secure = false, $httponly = false)
{
- $expires = is_null($expires) ? $this->config('cookies.lifetime') : $expires;
- if (is_string($expires)) {
- $expires = strtotime($expires);
- }
- $secureValue = \Slim\Http\Util::encodeSecureCookie(
- $value,
- $expires,
- $this->config('cookies.secret_key'),
- $this->config('cookies.cipher'),
- $this->config('cookies.cipher_mode')
- );
- $this->setCookie($name, $secureValue, $expires, $path, $domain, $secure, $httponly);
+ $this->setCookie($name, $value, $expires, $path, $domain, $secure, $httponly);
}
/**
+ * DEPRECATION WARNING! Use `getCookie` with the `cookies.encrypt` app setting set to `true`.
+ *
* Get value of encrypted HTTP cookie
*
* Return the value of an encrypted cookie from the current HTTP request,
@@ -842,21 +916,12 @@ public function setEncryptedCookie($name, $value, $expires = null, $path = null,
* the current request will not be available until the next request.
*
* @param string $name
- * @return string|false
+ * @param bool $deleteIfInvalid
+ * @return string|bool
*/
public function getEncryptedCookie($name, $deleteIfInvalid = true)
{
- $value = \Slim\Http\Util::decodeSecureCookie(
- $this->request->cookies($name),
- $this->config('cookies.secret_key'),
- $this->config('cookies.cipher'),
- $this->config('cookies.cipher_mode')
- );
- if ($value === false && $deleteIfInvalid) {
- $this->deleteCookie($name);
- }
-
- return $value;
+ return $this->getCookie($name, $deleteIfInvalid);
}
/**
@@ -877,12 +942,13 @@ public function getEncryptedCookie($name, $deleteIfInvalid = true)
*/
public function deleteCookie($name, $path = null, $domain = null, $secure = null, $httponly = null)
{
- $this->response->deleteCookie($name, array(
+ $settings = array(
'domain' => is_null($domain) ? $this->config('cookies.domain') : $domain,
'path' => is_null($path) ? $this->config('cookies.path') : $path,
'secure' => is_null($secure) ? $this->config('cookies.secure') : $secure,
'httponly' => is_null($httponly) ? $this->config('cookies.httponly') : $httponly
- ));
+ );
+ $this->response->cookies->remove($name, $settings);
}
/********************************************************************************
@@ -968,16 +1034,16 @@ public function pass()
*/
public function contentType($type)
{
- $this->response['Content-Type'] = $type;
+ $this->response->headers->set('Content-Type', $type);
}
/**
* Set the HTTP response status code
- * @param int $status The HTTP response status code
+ * @param int $code The HTTP response status code
*/
public function status($code)
{
- $this->response->status($code);
+ $this->response->setStatus($code);
}
/**
@@ -1071,7 +1137,7 @@ public function hook($name, $callable, $priority = 10)
/**
* Invoke hook
* @param string $name The hook name
- * @param mixed $hookArgs (Optional) Argument for hooked functions
+ * @param mixed $hookArg (Optional) Argument for hooked functions
*/
public function applyHook($name, $hookArg = null)
{
@@ -1174,7 +1240,10 @@ public function run()
$this->middleware[0]->call();
//Fetch status, header, and body
- list($status, $header, $body) = $this->response->finalize();
+ list($status, $headers, $body) = $this->response->finalize();
+
+ // Serialize cookies (with optional encryption)
+ \Slim\Http\Util::serializeCookies($headers, $this->response->cookies, $this->settings);
//Send headers
if (headers_sent() === false) {
@@ -1186,7 +1255,7 @@ public function run()
}
//Send headers
- foreach ($header as $name => $value) {
+ foreach ($headers as $name => $value) {
$hValues = explode("\n", $value);
foreach ($hValues as $hVal) {
header("$name: $hVal", false);
@@ -1219,7 +1288,7 @@ public function call()
foreach ($matchedRoutes as $route) {
try {
$this->applyHook('slim.before.dispatch');
- $dispatched = $this->router->dispatch($route);
+ $dispatched = $route->dispatch();
$this->applyHook('slim.after.dispatch');
if ($dispatched) {
break;
@@ -1229,7 +1298,7 @@ public function call()
}
}
if (!$dispatched) {
- $this->notFound();
+ $this->notFound();
}
$this->applyHook('slim.after.router');
$this->stop();
@@ -1264,16 +1333,16 @@ public function call()
* @param string $errstr The error message
* @param string $errfile The absolute path to the affected file
* @param int $errline The line number of the error in the affected file
- * @return true
+ * @return bool
* @throws \ErrorException
*/
public static function handleErrors($errno, $errstr = '', $errfile = '', $errline = '')
{
- if (error_reporting() & $errno) {
- throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
+ if (!($errno & error_reporting())) {
+ return;
}
- return true;
+ throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
}
/**
diff --git a/Slim/View.php b/Slim/View.php
index 0ce956899..48f2dcb2d 100644
--- a/Slim/View.php
+++ b/Slim/View.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
* @package Slim
*
* MIT LICENSE
@@ -50,132 +50,177 @@
class View
{
/**
- * @var string Absolute or relative filesystem path to a specific template
- *
- * DEPRECATION WARNING!
- * This variable will be removed in the near future
- */
- protected $templatePath = '';
-
- /**
- * @var array Associative array of template variables
+ * Data available to the view templates
+ * @var \Slim\Helper\Set
*/
- protected $data = array();
+ protected $data;
/**
- * @var string Absolute or relative path to the application's templates directory
+ * Path to templates base directory (without trailing slash)
+ * @var string
*/
protected $templatesDirectory;
/**
* Constructor
- *
- * This is empty but may be implemented in a subclass
*/
public function __construct()
{
+ $this->data = new \Slim\Helper\Set();
+ }
+
+ /********************************************************************************
+ * Data methods
+ *******************************************************************************/
+
+ /**
+ * Does view data have value with key?
+ * @param string $key
+ * @return boolean
+ */
+ public function has($key)
+ {
+ return $this->data->has($key);
+ }
+
+ /**
+ * Return view data value with key
+ * @param string $key
+ * @return mixed
+ */
+ public function get($key)
+ {
+ return $this->data->get($key);
+ }
+
+ /**
+ * Set view data value with key
+ * @param string $key
+ * @param mixed $value
+ */
+ public function set($key, $value)
+ {
+ $this->data->set($key, $value);
+ }
+ /**
+ * Return view data
+ * @return array
+ */
+ public function all()
+ {
+ return $this->data->all();
+ }
+
+ /**
+ * Replace view data
+ * @param array $data
+ */
+ public function replace(array $data)
+ {
+ $this->data->replace($data);
}
/**
- * Get data
- * @param string|null $key
- * @return mixed If key is null, array of template data;
- * If key exists, value of datum with key;
- * If key does not exist, null;
+ * Clear view data
+ */
+ public function clear()
+ {
+ $this->data->clear();
+ }
+
+ /********************************************************************************
+ * Legacy data methods
+ *******************************************************************************/
+
+ /**
+ * DEPRECATION WARNING! This method will be removed in the next major point release
+ *
+ * Get data from view
*/
public function getData($key = null)
{
if (!is_null($key)) {
return isset($this->data[$key]) ? $this->data[$key] : null;
} else {
- return $this->data;
+ return $this->data->all();
}
}
/**
- * Set data
- *
- * If two arguments:
- * A single datum with key is assigned value;
+ * DEPRECATION WARNING! This method will be removed in the next major point release
*
- * $view->setData('color', 'red');
- *
- * If one argument:
- * Replace all data with provided array keys and values;
- *
- * $view->setData(array('color' => 'red', 'number' => 1));
- *
- * @param mixed
- * @param mixed
- * @throws InvalidArgumentException If incorrect method signature
+ * Set data for view
*/
public function setData()
{
$args = func_get_args();
if (count($args) === 1 && is_array($args[0])) {
- $this->data = $args[0];
+ $this->data->replace($args[0]);
} elseif (count($args) === 2) {
- $this->data[(string) $args[0]] = $args[1];
+ $this->data->set($args[0], $args[1]);
} else {
throw new \InvalidArgumentException('Cannot set View data with provided arguments. Usage: `View::setData( $key, $value );` or `View::setData([ key => value, ... ]);`');
}
}
/**
- * Append new data to existing template data
- * @param array
- * @throws InvalidArgumentException If not given an array argument
+ * DEPRECATION WARNING! This method will be removed in the next major point release
+ *
+ * Append data to view
+ * @param array $data
*/
public function appendData($data)
{
if (!is_array($data)) {
throw new \InvalidArgumentException('Cannot append view data. Expected array argument.');
}
- $this->data = array_merge($this->data, $data);
+ $this->data->replace($data);
}
+ /********************************************************************************
+ * Resolve template paths
+ *******************************************************************************/
+
/**
- * Get templates directory
- * @return string|null Path to templates directory without trailing slash;
- * Returns null if templates directory not set;
+ * Set the base directory that contains view templates
+ * @param string $directory
+ * @throws \InvalidArgumentException If directory is not a directory
*/
- public function getTemplatesDirectory()
+ public function setTemplatesDirectory($directory)
{
- return $this->templatesDirectory;
+ $this->templatesDirectory = rtrim($directory, DIRECTORY_SEPARATOR);
}
/**
- * Set templates directory
- * @param string $dir
+ * Get templates base directory
+ * @return string
*/
- public function setTemplatesDirectory($dir)
+ public function getTemplatesDirectory()
{
- $this->templatesDirectory = rtrim($dir, '/');
+ return $this->templatesDirectory;
}
/**
- * Set template
- * @param string $template
- * @throws RuntimeException If template file does not exist
- *
- * DEPRECATION WARNING!
- * This method will be removed in the near future.
+ * Get fully qualified path to template file using templates base directory
+ * @param string $file The template file pathname relative to templates base directory
+ * @return string
*/
- public function setTemplate($template)
+ public function getTemplatePathname($file)
{
- $this->templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/');
- if (!file_exists($this->templatePath)) {
- throw new \RuntimeException('View cannot render template `' . $this->templatePath . '`. Template does not exist.');
- }
+ return $this->templatesDirectory . DIRECTORY_SEPARATOR . ltrim($file, DIRECTORY_SEPARATOR);
}
+ /********************************************************************************
+ * Rendering
+ *******************************************************************************/
+
/**
* Display template
*
* This method echoes the rendered template to the current output buffer
*
- * @param string $template Pathname of template file relative to templates directoy
+ * @param string $template Pathname of template file relative to templates directory
*/
public function display($template)
{
@@ -183,12 +228,9 @@ public function display($template)
}
/**
- * Fetch rendered template
- *
- * This method returns the rendered template
- *
- * @param string $template Pathname of template file relative to templates directory
- * @return string
+ * 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
*/
public function fetch($template)
{
@@ -196,20 +238,23 @@ public function fetch($template)
}
/**
- * Render template
+ * Render a template file
*
- * @param string $template Pathname of template file relative to templates directory
- * @return string
+ * NOTE: This method should be overridden by custom view subclasses
*
- * DEPRECATION WARNING!
- * Use `\Slim\View::fetch` to return a rendered template instead of `\Slim\View::render`.
+ * @var string $template The template pathname, relative to the template base directory
+ * @return string The rendered template
+ * @throws \RuntimeException If resolved template pathname is not a valid file
*/
- public function render($template)
+ protected function render($template)
{
- $this->setTemplate($template);
- extract($this->data);
+ $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());
ob_start();
- require $this->templatePath;
+ require $templatePathname;
return ob_get_clean();
}
diff --git a/composer.json b/composer.json
index a49c05ec2..656de3297 100644
--- a/composer.json
+++ b/composer.json
@@ -13,7 +13,8 @@
}
],
"require": {
- "php": ">=5.3.0"
+ "php": ">=5.3.0",
+ "ext-mcrypt": "*"
},
"autoload": {
"psr-0": { "Slim": "." }
diff --git a/index.php b/index.php
index c3e67454c..9bfd62d98 100644
--- a/index.php
+++ b/index.php
@@ -26,13 +26,15 @@
*
* Here we define several Slim application routes that respond
* to appropriate HTTP request methods. In this example, the second
- * argument for `Slim::get`, `Slim::post`, `Slim::put`, and `Slim::delete`
+ * argument for `Slim::get`, `Slim::post`, `Slim::put`, `Slim::patch`, and `Slim::delete`
* is an anonymous function.
*/
// GET route
-$app->get('/', function () {
- $template = <<get(
+ '/',
+ function () {
+ $template = <<
@@ -125,23 +127,38 @@
EOT;
- echo $template;
-});
+ echo $template;
+ }
+);
// POST route
-$app->post('/post', function () {
- echo 'This is a POST route';
-});
+$app->post(
+ '/post',
+ function () {
+ echo 'This is a POST route';
+ }
+);
// PUT route
-$app->put('/put', function () {
- echo 'This is a PUT route';
+$app->put(
+ '/put',
+ function () {
+ echo 'This is a PUT route';
+ }
+);
+
+// PATCH route
+$app->patch('/patch', function () {
+ echo 'This is a PATCH route';
});
// DELETE route
-$app->delete('/delete', function () {
- echo 'This is a DELETE route';
-});
+$app->delete(
+ '/delete',
+ function () {
+ echo 'This is a DELETE route';
+ }
+);
/**
* Step 4: Run the Slim application
diff --git a/tests/EnvironmentTest.php b/tests/EnvironmentTest.php
index 91505b8ce..e86b24ac5 100644
--- a/tests/EnvironmentTest.php
+++ b/tests/EnvironmentTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -292,7 +292,7 @@ public function testSetsSpecialHeaders()
$env = \Slim\Environment::getInstance(true);
$this->assertEquals('text/csv', $env['CONTENT_TYPE']);
$this->assertEquals('100', $env['CONTENT_LENGTH']);
- $this->assertEquals('XmlHttpRequest', $env['X_REQUESTED_WITH']);
+ $this->assertEquals('XmlHttpRequest', $env['HTTP_X_REQUESTED_WITH']);
}
/**
diff --git a/tests/Helper/SetTest.php b/tests/Helper/SetTest.php
new file mode 100644
index 000000000..674e2b167
--- /dev/null
+++ b/tests/Helper/SetTest.php
@@ -0,0 +1,183 @@
+
+ * @copyright 2011 Josh Lockhart
+ * @link http://www.slimframework.com
+ * @license http://www.slimframework.com/license
+ * @version 2.3.0
+ *
+ * MIT LICENSE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+class SetTest extends PHPUnit_Framework_TestCase
+{
+ protected $bag;
+ protected $property;
+
+ public function setUp()
+ {
+ $this->bag = new \Slim\Helper\Set();
+ $this->property = new \ReflectionProperty($this->bag, 'data');
+ $this->property->setAccessible(true);
+ }
+
+ public function testSet()
+ {
+ $this->bag->set('foo', 'bar');
+ $this->assertArrayHasKey('foo', $this->property->getValue($this->bag));
+ $bag = $this->property->getValue($this->bag);
+ $this->assertEquals('bar', $bag['foo']);
+ }
+
+ public function testGet()
+ {
+ $this->property->setValue($this->bag, array('foo' => 'bar'));
+ $this->assertEquals('bar', $this->bag->get('foo'));
+ }
+
+ public function testGetNotExists()
+ {
+ $this->property->setValue($this->bag, array('foo' => 'bar'));
+ $this->assertEquals('default', $this->bag->get('abc', 'default'));
+ }
+
+ public function testAdd()
+ {
+ $this->bag->replace(array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ ));
+ $this->assertArrayHasKey('abc', $this->property->getValue($this->bag));
+ $this->assertArrayHasKey('foo', $this->property->getValue($this->bag));
+ $bag = $this->property->getValue($this->bag);
+ $this->assertEquals('123', $bag['abc']);
+ $this->assertEquals('bar', $bag['foo']);
+ }
+
+ public function testAll()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->assertEquals($data, $this->bag->all());
+ }
+
+ public function testKeys()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->assertEquals(array('abc', 'foo'), $this->bag->keys());
+ }
+
+ public function testRemove()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->bag->remove('foo');
+ $this->assertEquals(array('abc' => '123'), $this->property->getValue($this->bag));
+ }
+
+ public function testClear()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->bag->clear();
+ $this->assertEquals(array(), $this->property->getValue($this->bag));
+ }
+
+ public function testArrayAccessGet()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->assertEquals('bar', $this->bag['foo']);
+ }
+
+ public function testArrayAccessSet()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->bag['foo'] = 'changed';
+ $bag = $this->property->getValue($this->bag);
+ $this->assertEquals('changed', $bag['foo']);
+ }
+
+ public function testArrayAccessExists()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->assertTrue(isset($this->bag['foo']));
+ $this->assertFalse(isset($this->bag['bar']));
+ }
+
+ public function testArrayAccessUnset()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ unset($this->bag['foo']);
+ $this->assertEquals(array('abc' => '123'), $this->property->getValue($this->bag));
+ }
+
+ public function testCount()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->assertEquals(2, count($this->bag));
+ }
+
+ public function testGetIterator()
+ {
+ $data = array(
+ 'abc' => '123',
+ 'foo' => 'bar'
+ );
+ $this->property->setValue($this->bag, $data);
+ $this->assertInstanceOf('\ArrayIterator', $this->bag->getIterator());
+ }
+}
diff --git a/tests/Http/CookiesTest.php b/tests/Http/CookiesTest.php
new file mode 100644
index 000000000..33868cef0
--- /dev/null
+++ b/tests/Http/CookiesTest.php
@@ -0,0 +1,92 @@
+
+ * @copyright 2011 Josh Lockhart
+ * @link http://www.slimframework.com
+ * @license http://www.slimframework.com/license
+ * @version 2.3.0
+ *
+ * MIT LICENSE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+class CookiesTest extends PHPUnit_Framework_TestCase
+{
+ public function testSetWithStringValue()
+ {
+ $c = new \Slim\Http\Cookies();
+ $c->set('foo', 'bar');
+ $this->assertAttributeEquals(
+ array(
+ 'foo' => array(
+ 'value' => 'bar',
+ 'expires' => null,
+ 'domain' => null,
+ 'path' => null,
+ 'secure' => false,
+ 'httponly' => false
+ )
+ ),
+ 'data',
+ $c
+ );
+ }
+
+ public function testSetWithArrayValue()
+ {
+ $now = time();
+ $c = new \Slim\Http\Cookies();
+ $c->set('foo', array(
+ 'value' => 'bar',
+ 'expires' => $now + 86400,
+ 'domain' => '.example.com',
+ 'path' => '/',
+ 'secure' => true,
+ 'httponly' => true
+ ));
+ $this->assertAttributeEquals(
+ array(
+ 'foo' => array(
+ 'value' => 'bar',
+ 'expires' => $now + 86400,
+ 'domain' => '.example.com',
+ 'path' => '/',
+ 'secure' => true,
+ 'httponly' => true
+ )
+ ),
+ 'data',
+ $c
+ );
+ }
+
+ public function testRemove()
+ {
+ $c = new \Slim\Http\Cookies();
+ $c->remove('foo');
+ $prop = new \ReflectionProperty($c, 'data');
+ $prop->setAccessible(true);
+ $cValue = $prop->getValue($c);
+ $this->assertEquals('', $cValue['foo']['value']);
+ $this->assertLessThan(time(), $cValue['foo']['expires']);
+ }
+}
diff --git a/tests/Http/HeadersTest.php b/tests/Http/HeadersTest.php
index 0b06d3ab1..e5fe17fe1 100644
--- a/tests/Http/HeadersTest.php
+++ b/tests/Http/HeadersTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -32,112 +32,28 @@
class HeadersTest extends PHPUnit_Framework_TestCase
{
- /**
- * Test constructor without args
- */
- public function testConstructorWithoutArgs()
+ public function testNormalizesKey()
{
$h = new \Slim\Http\Headers();
- $this->assertEquals(0, count($h));
+ $h->set('Http_Content_Type', 'text/html');
+ $prop = new \ReflectionProperty($h, 'data');
+ $prop->setAccessible(true);
+ $this->assertArrayHasKey('Content-Type', $prop->getValue($h));
}
- /**
- * Test constructor with args
- */
- public function testConstructorWithArgs()
+ public function testExtractHeaders()
{
- $h = new \Slim\Http\Headers(array('Content-Type' => 'text/html'));
- $this->assertEquals(1, count($h));
- }
-
- /**
- * Test get and set header
- */
- public function testSetAndGetHeader()
- {
- $h = new \Slim\Http\Headers();
- $h['Content-Type'] = 'text/html';
- $this->assertEquals('text/html', $h['Content-Type']);
- $this->assertEquals('text/html', $h['Content-type']);
- $this->assertEquals('text/html', $h['content-type']);
- }
-
- /**
- * Test get non-existent header
- */
- public function testGetNonExistentHeader()
- {
- $h = new \Slim\Http\Headers();
- $this->assertNull($h['foo']);
- }
-
- /**
- * Test isset header
- */
- public function testHeaderIsSet()
- {
- $h = new \Slim\Http\Headers();
- $h['Content-Type'] = 'text/html';
- $this->assertTrue(isset($h['Content-Type']));
- $this->assertTrue(isset($h['Content-type']));
- $this->assertTrue(isset($h['content-type']));
- $this->assertFalse(isset($h['foo']));
- }
-
- /**
- * Test unset header
- */
- public function testUnsetHeader()
- {
- $h = new \Slim\Http\Headers();
- $h['Content-Type'] = 'text/html';
- $this->assertEquals(1, count($h));
- unset($h['Content-Type']);
- $this->assertEquals(0, count($h));
- }
-
- /**
- * Test merge headers
- */
- public function testMergeHeaders()
- {
- $h = new \Slim\Http\Headers();
- $h['Content-Type'] = 'text/html';
- $this->assertEquals(1, count($h));
- $h->merge(array('Content-type' => 'text/csv', 'content-length' => 10));
- $this->assertEquals(2, count($h));
- $this->assertEquals('text/csv', $h['content-type']);
- $this->assertEquals(10, $h['Content-length']);
- }
-
- /**
- * Test iteration
- */
- public function testIteration()
- {
- $h = new \Slim\Http\Headers();
- $h['One'] = 'Foo';
- $h['Two'] = 'Bar';
- $output = '';
- foreach ($h as $key => $value) {
- $output .= $key . $value;
- }
- $this->assertEquals('OneFooTwoBar', $output);
- }
-
- /**
- * Test outputs header name in original form, not canonical form
- */
- public function testOutputsOriginalNotCanonicalName()
- {
- $h = new \Slim\Http\Headers();
- $h['X-Powered-By'] = 'Slim';
- $h['Content-Type'] = 'text/csv';
- $keys = array();
- foreach ($h as $name => $value) {
- $keys[] = $name;
- }
- $this->assertContains('X-Powered-By', $keys);
- $this->assertContains('Content-Type', $keys);
+ $test = array(
+ 'HTTP_HOST' => 'foo.com',
+ 'SERVER_NAME' => 'foo',
+ 'CONTENT_TYPE' => 'text/html',
+ 'X_FORWARDED_FOR' => '127.0.0.1'
+ );
+ $results = \Slim\Http\Headers::extract($test);
+ $this->assertEquals(array(
+ 'HTTP_HOST' => 'foo.com',
+ 'CONTENT_TYPE' => 'text/html',
+ 'X_FORWARDED_FOR' => '127.0.0.1'
+ ), $results);
}
}
diff --git a/tests/Http/RequestTest.php b/tests/Http/RequestTest.php
index b2d3def74..7a837a7d0 100644
--- a/tests/Http/RequestTest.php
+++ b/tests/Http/RequestTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -54,11 +54,6 @@ public function testIsGet()
));
$req = new \Slim\Http\Request($env);
$this->assertTrue($req->isGet());
- $this->assertFalse($req->isPost());
- $this->assertFalse($req->isPut());
- $this->assertFalse($req->isDelete());
- $this->assertFalse($req->isOptions());
- $this->assertFalse($req->isHead());
}
/**
@@ -70,12 +65,7 @@ public function testIsPost()
'REQUEST_METHOD' => 'POST',
));
$req = new \Slim\Http\Request($env);
- $this->assertFalse($req->isGet());
$this->assertTrue($req->isPost());
- $this->assertFalse($req->isPut());
- $this->assertFalse($req->isDelete());
- $this->assertFalse($req->isOptions());
- $this->assertFalse($req->isHead());
}
/**
@@ -87,12 +77,7 @@ public function testIsPut()
'REQUEST_METHOD' => 'PUT',
));
$req = new \Slim\Http\Request($env);
- $this->assertFalse($req->isGet());
- $this->assertFalse($req->isPost());
$this->assertTrue($req->isPut());
- $this->assertFalse($req->isDelete());
- $this->assertFalse($req->isOptions());
- $this->assertFalse($req->isHead());
}
/**
@@ -104,12 +89,7 @@ public function testIsDelete()
'REQUEST_METHOD' => 'DELETE',
));
$req = new \Slim\Http\Request($env);
- $this->assertFalse($req->isGet());
- $this->assertFalse($req->isPost());
- $this->assertFalse($req->isPut());
$this->assertTrue($req->isDelete());
- $this->assertFalse($req->isOptions());
- $this->assertFalse($req->isHead());
}
/**
@@ -121,12 +101,7 @@ public function testIsOptions()
'REQUEST_METHOD' => 'OPTIONS',
));
$req = new \Slim\Http\Request($env);
- $this->assertFalse($req->isGet());
- $this->assertFalse($req->isPost());
- $this->assertFalse($req->isPut());
- $this->assertFalse($req->isDelete());
$this->assertTrue($req->isOptions());
- $this->assertFalse($req->isHead());
}
/**
@@ -138,14 +113,21 @@ public function testIsHead()
'REQUEST_METHOD' => 'HEAD',
));
$req = new \Slim\Http\Request($env);
- $this->assertFalse($req->isGet());
- $this->assertFalse($req->isPost());
- $this->assertFalse($req->isPut());
- $this->assertFalse($req->isDelete());
- $this->assertFalse($req->isOptions());
$this->assertTrue($req->isHead());
}
+ /**
+ * Test HTTP PATCH method detection
+ */
+ public function testIsPatch()
+ {
+ $env = \Slim\Environment::mock(array(
+ 'REQUEST_METHOD' => 'PATCH',
+ ));
+ $req = new \Slim\Http\Request($env);
+ $this->assertTrue($req->isPatch());
+ }
+
/**
* Test AJAX method detection w/ header
*/
@@ -165,7 +147,7 @@ public function testIsAjaxWithHeader()
public function testIsAjaxWithQueryParameter()
{
$env = \Slim\Environment::mock(array(
- 'QUERY_STRING' => 'one=1&two=2&three=3&isajax=1',
+ 'QUERY_STRING' => 'isajax=1',
));
$req = new \Slim\Http\Request($env);
$this->assertTrue($req->isAjax());
@@ -173,7 +155,7 @@ public function testIsAjaxWithQueryParameter()
}
/**
- * Test AJAX method detection wihtout header or query paramter
+ * Test AJAX method detection without header or query parameter
*/
public function testIsAjaxWithoutHeaderOrQueryParameter()
{
@@ -339,6 +321,24 @@ public function testPut()
$this->assertNull($req->put('xyz'));
}
+ /**
+ * Test fetch PATCH params
+ */
+ public function testPatch()
+ {
+ $env = \Slim\Environment::mock(array(
+ 'REQUEST_METHOD' => 'PATCH',
+ 'slim.input' => 'foo=bar&abc=123',
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
+ 'CONTENT_LENGTH' => 15
+ ));
+ $req = new \Slim\Http\Request($env);
+ $this->assertEquals(2, count($req->patch()));
+ $this->assertEquals('bar', $req->patch('foo'));
+ $this->assertEquals('bar', $req->params('foo'));
+ $this->assertNull($req->patch('xyz'));
+ }
+
/**
* Test fetch DELETE params
*/
@@ -363,7 +363,7 @@ public function testDelete()
public function testCookies()
{
$env = \Slim\Environment::mock(array(
- 'COOKIE' => 'foo=bar; abc=123'
+ 'HTTP_COOKIE' => 'foo=bar; abc=123'
));
$req = new \Slim\Http\Request($env);
$this->assertEquals(2, count($req->cookies()));
@@ -431,12 +431,11 @@ public function testIsNotFormData()
public function testHeaders()
{
$env = \Slim\Environment::mock(array(
- 'ACCEPT_ENCODING' => 'gzip'
+ 'HTTP_ACCEPT_ENCODING' => 'gzip'
));
$req = new \Slim\Http\Request($env);
$headers = $req->headers();
- $this->assertTrue(is_array($headers));
- $this->assertArrayHasKey('ACCEPT_ENCODING', $headers);
+ $this->assertInstanceOf('\Slim\Http\Headers', $headers);
$this->assertEquals('gzip', $req->headers('HTTP_ACCEPT_ENCODING'));
$this->assertEquals('gzip', $req->headers('HTTP-ACCEPT-ENCODING'));
$this->assertEquals('gzip', $req->headers('http_accept_encoding'));
@@ -632,7 +631,7 @@ public function testGetHost()
{
$env = \Slim\Environment::mock(array(
'SERVER_NAME' => 'slim',
- 'HOST' => 'slimframework.com'
+ 'HTTP_HOST' => 'slimframework.com'
));
$req = new \Slim\Http\Request($env);
$this->assertEquals('slimframework.com', $req->getHost()); //Uses HTTP_HOST if available
@@ -645,7 +644,7 @@ public function testGetHostAndStripPort()
{
$env = \Slim\Environment::mock(array(
'SERVER_NAME' => 'slim',
- 'HOST' => 'slimframework.com:80'
+ 'HTTP_HOST' => 'slimframework.com:80'
));
$req = new \Slim\Http\Request($env);
$this->assertEquals('slimframework.com', $req->getHost()); //Uses HTTP_HOST if available
@@ -658,9 +657,9 @@ public function testGetHostWhenNotExists()
{
$env = \Slim\Environment::mock(array(
'SERVER_NAME' => 'slim',
- 'HOST' => 'slimframework.com'
+ 'HTTP_HOST' => 'slimframework.com'
));
- unset($env['HOST']);
+ unset($env['HTTP_HOST']);
$req = new \Slim\Http\Request($env);
$this->assertEquals('slim', $req->getHost()); //Uses SERVER_NAME as backup
}
@@ -671,7 +670,7 @@ public function testGetHostWhenNotExists()
public function testGetHostWithPort()
{
$env = \Slim\Environment::mock(array(
- 'HOST' => 'slimframework.com',
+ 'HTTP_HOST' => 'slimframework.com',
'SERVER_NAME' => 'slim',
'SERVER_PORT' => 80,
'slim.url_scheme' => 'http'
@@ -681,12 +680,12 @@ public function testGetHostWithPort()
}
/**
- * Test get host with port doesn't dulplicate port numbers
+ * Test get host with port doesn't duplicate port numbers
*/
public function testGetHostDoesntDulplicatePort()
{
$env = \Slim\Environment::mock(array(
- 'HOST' => 'slimframework.com:80',
+ 'HTTP_HOST' => 'slimframework.com:80',
'SERVER_NAME' => 'slim',
'SERVER_PORT' => 80,
'slim.url_scheme' => 'http'
@@ -806,7 +805,7 @@ public function testAppPathsInRootDirectoryWithHtaccess()
public function testGetUrl()
{
$env = \Slim\Environment::mock(array(
- 'HOST' => 'slimframework.com',
+ 'HTTP_HOST' => 'slimframework.com',
'SERVER_NAME' => 'slim',
'SERVER_PORT' => 80,
'slim.url_scheme' => 'http'
@@ -821,7 +820,7 @@ public function testGetUrl()
public function testGetUrlWithCustomPort()
{
$env = \Slim\Environment::mock(array(
- 'HOST' => 'slimframework.com',
+ 'HTTP_HOST' => 'slimframework.com',
'SERVER_NAME' => 'slim',
'SERVER_PORT' => 8080,
'slim.url_scheme' => 'http'
@@ -836,7 +835,7 @@ public function testGetUrlWithCustomPort()
public function testGetUrlWithHttps()
{
$env = \Slim\Environment::mock(array(
- 'HOST' => 'slimframework.com',
+ 'HTTP_HOST' => 'slimframework.com',
'SERVER_NAME' => 'slim',
'SERVER_PORT' => 443,
'slim.url_scheme' => 'https'
@@ -890,7 +889,7 @@ public function testGetIpWithForwardedFor()
public function testGetReferrer()
{
$env = \Slim\Environment::mock(array(
- 'REFERER' => 'http://foo.com'
+ 'HTTP_REFERER' => 'http://foo.com'
));
$req = new \Slim\Http\Request($env);
$this->assertEquals('http://foo.com', $req->getReferrer());
@@ -914,7 +913,7 @@ public function testGetReferrerWhenNotExists()
public function testGetUserAgent()
{
$env = \Slim\Environment::mock(array(
- 'USER_AGENT' => 'user-agent-string'
+ 'HTTP_USER_AGENT' => 'user-agent-string'
));
$req = new \Slim\Http\Request($env);
$this->assertEquals('user-agent-string', $req->getUserAgent());
@@ -926,7 +925,7 @@ public function testGetUserAgent()
public function testGetUserAgentWhenNotExists()
{
$env = \Slim\Environment::mock();
- unset($env['USER_AGENT']);
+ unset($env['HTTP_USER_AGENT']);
$req = new \Slim\Http\Request($env);
$this->assertNull($req->getUserAgent());
}
diff --git a/tests/Http/ResponseTest.php b/tests/Http/ResponseTest.php
index 2321e613c..85b857f35 100644
--- a/tests/Http/ResponseTest.php
+++ b/tests/Http/ResponseTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -32,541 +32,238 @@
class ResponseTest extends PHPUnit_Framework_TestCase
{
- /**
- * Test constructor without args
- */
- public function testConstructorWithoutArgs()
- {
- $r = new \Slim\Http\Response();
- $this->assertEquals('', $r->body());
- $this->assertEquals(200, $r->status());
- $this->assertEquals(0, $r->length());
- $this->assertEquals('text/html', $r['Content-Type']);
- }
-
- /**
- * Test constructor with args
- */
- public function testConstructorWithArgs()
- {
- $r = new \Slim\Http\Response('Page Not Found', 404, array('Content-Type' => 'application/json', 'X-Created-By' => 'Slim'));
- $this->assertEquals('Page Not Found', $r->body());
- $this->assertEquals(404, $r->status());
- $this->assertEquals(14, $r->length());
- $this->assertEquals('application/json', $r['Content-Type']);
- $this->assertEquals('Slim', $r['X-Created-By']);
- }
-
- /**
- * Test get status
- */
- public function testGetStatus()
+ public function testConstructWithoutArgs()
{
- $r = new \Slim\Http\Response();
- $this->assertEquals(200, $r->status());
- }
+ $res = new \Slim\Http\Response();
- /**
- * Test set status
- */
- public function testSetStatus()
- {
- $r = new \Slim\Http\Response();
- $r->status(500);
- $this->assertEquals(500, $r->status());
+ $this->assertAttributeEquals(200, 'status', $res);
+ $this->assertAttributeEquals('', 'body', $res);
}
- /**
- * Test get headers
- */
- public function testGetHeaders()
+ public function testConstructWithArgs()
{
- $r = new \Slim\Http\Response();
- $headers = $r->headers();
- $this->assertEquals(1, count($headers));
- $this->assertEquals('text/html', $headers['Content-Type']);
- }
+ $res = new \Slim\Http\Response('Foo', 201);
- /**
- * Test get and set header (without Array Access)
- */
- public function testGetAndSetHeader()
- {
- $r = new \Slim\Http\Response();
- $r->header('X-Foo', 'Bar');
- $this->assertEquals('Bar', $r->header('X-Foo'));
+ $this->assertAttributeEquals(201, 'status', $res);
+ $this->assertAttributeEquals('Foo', 'body', $res);
}
- /**
- * Test get body
- */
- public function testGetBody()
+ public function testGetStatus()
{
- $r = new \Slim\Http\Response('Foo');
- $this->assertEquals('Foo', $r->body());
- }
+ $res = new \Slim\Http\Response();
- /**
- * Test set body
- */
- public function testSetBody()
- {
- $r = new \Slim\Http\Response();
- $r->body('Foo');
- $this->assertEquals('Foo', $r->body());
+ $this->assertEquals(200, $res->getStatus());
}
- /**
- * Test get length
- */
- public function testGetLength()
+ public function testSetStatus()
{
- $r = new \Slim\Http\Response('Foo');
- $this->assertEquals(3, $r->length());
- }
+ $res = new \Slim\Http\Response();
+ $res->setStatus(301);
- /**
- * Test set length
- */
- public function testSetLength()
- {
- $r = new \Slim\Http\Response();
- $r->length(3);
- $this->assertEquals(3, $r->length());
+ $this->assertAttributeEquals(301, 'status', $res);
}
/**
- * Test write for appending
+ * DEPRECATION WARNING!
*/
- public function testWriteAppend()
+ public function testStatusGetOld()
{
- $r = new \Slim\Http\Response('Foo');
- $r->write('Bar');
- $this->assertEquals('FooBar', $r->body());
+ $res = new \Slim\Http\Response('', 201);
+ $this->assertEquals(201, $res->status());
}
/**
- * Test write for replacing
+ * DEPRECATION WARNING!
*/
- public function testWriteReplace()
+ public function testStatusSetOld()
{
- $r = new \Slim\Http\Response('Foo');
- $r->write('Bar', true);
- $this->assertEquals('Bar', $r->body());
- }
+ $res = new \Slim\Http\Response();
+ $prop = new \ReflectionProperty($res, 'status');
+ $prop->setAccessible(true);
+ $res->status(301);
- /**
- * Test finalize
- */
- public function testFinalize()
- {
- $r = new \Slim\Http\Response();
- $r->status(404);
- $r['Content-Type'] = 'application/json';
- $r->write('Foo');
- $result = $r->finalize();
- $this->assertEquals(3, count($result));
- $this->assertEquals(404, $result[0]);
- $this->assertFalse(is_null($result[1]['Content-Type']));
+ $this->assertEquals(301, $prop->getValue($res));
}
- /**
- * Test finalize
- */
- public function testFinalizeWithoutBody()
+ public function testGetBody()
{
- $r = new \Slim\Http\Response();
- $r->status(204);
- $r['Content-Type'] = 'application/json';
- $r->write('Foo');
- $result = $r->finalize();
- $this->assertEquals(3, count($result));
- $this->assertEquals('', $result[2]);
- }
+ $res = new \Slim\Http\Response();
+ $property = new \ReflectionProperty($res, 'body');
+ $property->setAccessible(true);
+ $property->setValue($res, 'foo');
- /**
- * Test set cookie with only name and value
- */
- public function testSetCookieWithNameAndValue()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', 'bar');
- $this->assertEquals('foo=bar', $r['Set-Cookie']);
+ $this->assertEquals('foo', $res->getBody());
}
- /**
- * Test set multiple cookies with only name and value
- */
- public function testSetMultipleCookiesWithNameAndValue()
+ public function testSetBody()
{
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', 'bar');
- $r->setCookie('abc', '123');
- $this->assertEquals("foo=bar\nabc=123", $r['Set-Cookie']);
- }
+ $res = new \Slim\Http\Response('bar');
+ $res->setBody('foo'); // <-- Should replace body
- /**
- * Test set cookie only name and value and expires (as int)
- */
- public function testSetMultipleCookiesWithNameAndValueAndExpiresAsInt()
- {
- $now = time();
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'expires' => $now
- ));
- $this->assertEquals("foo=bar; expires=" . gmdate('D, d-M-Y H:i:s e', $now), $r['Set-Cookie']);
+ $this->assertAttributeEquals('foo', 'body', $res);
}
- /**
- * Test set cookie with only name and value and expires (as string)
- */
- public function testSetMultipleCookiesWithNameAndValueAndExpiresAsString()
+ public function testWrite()
{
- $expires = 'next Tuesday';
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'expires' => $expires
- ));
- $this->assertEquals("foo=bar; expires=" . gmdate('D, d-M-Y H:i:s e', strtotime($expires)), $r['Set-Cookie']);
- }
+ $res = new \Slim\Http\Response();
+ $property = new \ReflectionProperty($res, 'body');
+ $property->setAccessible(true);
+ $property->setValue($res, 'foo');
+ $res->write('bar'); // <-- Should append to body
- /**
- * Test set cookie with name, value, domain
- */
- public function testSetCookieWithNameAndValueAndDomain()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'domain' => '.slimframework.com'
- ));
- $this->assertEquals('foo=bar; domain=.slimframework.com', $r['Set-Cookie']);
+ $this->assertAttributeEquals('foobar', 'body', $res);
}
- /**
- * Test set cookie with name, value, domain, path
- */
- public function testSetCookieWithNameAndValueAndDomainAndPath()
+ public function testLength()
{
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'domain' => '.slimframework.com',
- 'path' => '/foo'
- ));
- $this->assertEquals($r['Set-Cookie'], 'foo=bar; domain=.slimframework.com; path=/foo');
- }
+ $res = new \Slim\Http\Response('foo'); // <-- Sets body and length
- /**
- * Test set cookie with only name and value and secure flag
- */
- public function testSetCookieWithNameAndValueAndSecureFlag()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'secure' => true
- ));
- $this->assertEquals('foo=bar; secure', $r['Set-Cookie']);
+ $this->assertEquals(3, $res->getLength());
}
- /**
- * Test set cookie with only name and value and secure flag (as non-truthy)
- */
- public function testSetCookieWithNameAndValueAndSecureFlagAsNonTruthy()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'secure' => 0
- ));
- $this->assertEquals('foo=bar', $r['Set-Cookie']);
- }
-
- /**
- * Test set cookie with only name and value and httponly flag
- */
- public function testSetCookieWithNameAndValueAndHttpOnlyFlag()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'httponly' => true
- ));
- $this->assertEquals('foo=bar; HttpOnly', $r['Set-Cookie']);
- }
-
- /**
- * Test set cookie with only name and value and httponly flag (as non-truthy)
- */
- public function testSetCookieWithNameAndValueAndHttpOnlyFlagAsNonTruthy()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'httponly' => 0
- ));
- $this->assertEquals('foo=bar', $r['Set-Cookie']);
- }
-
- /*
- * Test delete cookie by name
- */
- public function testDeleteCookieByName()
+ public function testFinalize()
{
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', 'bar');
- $r->setCookie('abc', '123');
- $r->deleteCookie('foo');
- $this->assertEquals(1, preg_match("@abc=123\nfoo=; expires=@", $r['Set-Cookie']));
- }
+ $res = new \Slim\Http\Response();
+ $resFinal = $res->finalize();
- /*
- * Test delete cookie by name and domain
- */
- public function testDeleteCookieByNameAndDomain1()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', 'bar'); //Note: This does not have domain associated with it
- $r->setCookie('abc', '123');
- $r->deleteCookie('foo', array('domain' => '.slimframework.com')); //This SHOULD NOT remove the `foo` cookie
- $this->assertEquals(1, preg_match("@foo=bar\nabc=123\nfoo=; domain=.slimframework.com; expires=@", $r['Set-Cookie']));
+ $this->assertTrue(is_array($resFinal));
+ $this->assertEquals(3, count($resFinal));
+ $this->assertEquals(200, $resFinal[0]);
+ $this->assertInstanceOf('\Slim\Http\Headers', $resFinal[1]);
+ $this->assertEquals('', $resFinal[2]);
}
- /*
- * Test delete cookie by name and domain
- */
- public function testDeleteCookieByNameAndDomain2()
+ public function testFinalizeWithEmptyBody()
{
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', array(
- 'value' => 'bar',
- 'domain' => '.slimframework.com' //Note: This does have domain associated with it
- ));
- $r->setCookie('abc', '123');
- $r->deleteCookie('foo', array('domain' => '.slimframework.com')); //This SHOULD remove the `foo` cookie
- $this->assertEquals(1, preg_match("@abc=123\nfoo=; domain=.slimframework.com; expires=@", $r['Set-Cookie']));
- }
+ $res = new \Slim\Http\Response('Foo', 304);
+ $resFinal = $res->finalize();
- /**
- * Test delete cookie by name and custom props
- */
- public function testDeleteCookieByNameAndCustomProps()
- {
- $r = new \Slim\Http\Response();
- $r->setCookie('foo', 'bar');
- $r->setCookie('abc', '123');
- $r->deleteCookie('foo', array(
- 'secure' => true,
- 'httponly' => true
- ));
- $this->assertEquals(1, preg_match("@abc=123\nfoo=; expires=.*; secure; HttpOnly@", $r['Set-Cookie']));
+ $this->assertEquals('', $resFinal[2]);
}
- /**
- * Test redirect
- */
public function testRedirect()
{
- $r = new \Slim\Http\Response();
- $r->redirect('/foo');
- $this->assertEquals(302, $r->status());
- $this->assertEquals('/foo', $r['Location']);
- }
+ $res = new \Slim\Http\Response();
+ $res->redirect('/foo');
- /**
- * Test redirect with custom status
- */
- public function testRedirectWithCustomStatus()
- {
- $r = new \Slim\Http\Response();
- $r->redirect('/foo', 307);
- $this->assertEquals(307, $r->status());
- $this->assertEquals('/foo', $r['Location']);
+ $pStatus = new \ReflectionProperty($res, 'status');
+ $pStatus->setAccessible(true);
+
+ $this->assertEquals(302, $pStatus->getValue($res));
+ $this->assertEquals('/foo', $res->headers['Location']);
}
- /**
- * Test isEmpty
- */
public function testIsEmpty()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(404);
- $r2->status(201);
+ $r1->setStatus(404);
+ $r2->setStatus(201);
$this->assertFalse($r1->isEmpty());
$this->assertTrue($r2->isEmpty());
}
- /**
- * Test isClientError
- */
public function testIsClientError()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(404);
- $r2->status(500);
+ $r1->setStatus(404);
+ $r2->setStatus(500);
$this->assertTrue($r1->isClientError());
$this->assertFalse($r2->isClientError());
}
- /**
- * Test isForbidden
- */
public function testIsForbidden()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(403);
- $r2->status(500);
+ $r1->setStatus(403);
+ $r2->setStatus(500);
$this->assertTrue($r1->isForbidden());
$this->assertFalse($r2->isForbidden());
}
- /**
- * Test isInformational
- */
public function testIsInformational()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(100);
- $r2->status(200);
+ $r1->setStatus(100);
+ $r2->setStatus(200);
$this->assertTrue($r1->isInformational());
$this->assertFalse($r2->isInformational());
}
- /**
- * Test isInformational
- */
public function testIsNotFound()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(404);
- $r2->status(200);
+ $r1->setStatus(404);
+ $r2->setStatus(200);
$this->assertTrue($r1->isNotFound());
$this->assertFalse($r2->isNotFound());
}
- /**
- * Test isOk
- */
public function testIsOk()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(200);
- $r2->status(201);
+ $r1->setStatus(200);
+ $r2->setStatus(201);
$this->assertTrue($r1->isOk());
$this->assertFalse($r2->isOk());
}
- /**
- * Test isSuccessful
- */
public function testIsSuccessful()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
$r3 = new \Slim\Http\Response();
- $r1->status(200);
- $r2->status(201);
- $r3->status(302);
+ $r1->setStatus(200);
+ $r2->setStatus(201);
+ $r3->setStatus(302);
$this->assertTrue($r1->isSuccessful());
$this->assertTrue($r2->isSuccessful());
$this->assertFalse($r3->isSuccessful());
}
- /**
- * Test isRedirect
- */
public function testIsRedirect()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(307);
- $r2->status(304);
+ $r1->setStatus(307);
+ $r2->setStatus(304);
$this->assertTrue($r1->isRedirect());
$this->assertFalse($r2->isRedirect());
}
- /**
- * Test isRedirection
- */
public function testIsRedirection()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
$r3 = new \Slim\Http\Response();
- $r1->status(307);
- $r2->status(304);
- $r3->status(200);
+ $r1->setStatus(307);
+ $r2->setStatus(304);
+ $r3->setStatus(200);
$this->assertTrue($r1->isRedirection());
$this->assertTrue($r2->isRedirection());
$this->assertFalse($r3->isRedirection());
}
- /**
- * Test isServerError
- */
public function testIsServerError()
{
$r1 = new \Slim\Http\Response();
$r2 = new \Slim\Http\Response();
- $r1->status(500);
- $r2->status(400);
+ $r1->setStatus(500);
+ $r2->setStatus(400);
$this->assertTrue($r1->isServerError());
$this->assertFalse($r2->isServerError());
}
- /**
- * Test offset exists and offset get
- */
- public function testOffsetExistsAndGet()
- {
- $r = new \Slim\Http\Response();
- $this->assertFalse(empty($r['Content-Type']));
- $this->assertNull($r['foo']);
- }
-
- /**
- * Test iteration
- */
- public function testIteration()
- {
- $h = new \Slim\Http\Response();
- $output = '';
- foreach ($h as $key => $value) {
- $output .= $key . $value;
- }
- $this->assertEquals('Content-Typetext/html', $output);
- }
-
- /**
- * Test countable
- */
- public function testCountable()
- {
- $r1 = new \Slim\Http\Response();
- $this->assertEquals(1, count($r1)); //Content-Type
- }
-
- /**
- * Test message for code when message exists
- */
public function testMessageForCode()
{
$this->assertEquals('200 OK', \Slim\Http\Response::getMessageForCode(200));
}
- /**
- * Test message for code when message exists
- */
public function testMessageForCodeWithInvalidCode()
{
$this->assertNull(\Slim\Http\Response::getMessageForCode(600));
diff --git a/tests/Http/UtilTest.php b/tests/Http/UtilTest.php
index 4eb0b4d30..9d665da0e 100644
--- a/tests/Http/UtilTest.php
+++ b/tests/Http/UtilTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
diff --git a/tests/LogTest.php b/tests/LogTest.php
index d390e45c4..d56299f1f 100644
--- a/tests/LogTest.php
+++ b/tests/LogTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -96,6 +96,21 @@ public function testLogInfo()
}
public function testLogInfoExcludedByLevel()
+ {
+ $log = new \Slim\Log(new MyWriter());
+ $log->setLevel(\Slim\Log::NOTICE);
+ $this->assertFalse($log->info('Info'));
+ }
+
+ public function testLogNotice()
+ {
+ $this->expectOutputString('Notice');
+ $log = new \Slim\Log(new MyWriter());
+ $result = $log->notice('Notice');
+ $this->assertTrue($result);
+ }
+
+ public function testLogNoticeExcludedByLevel()
{
$log = new \Slim\Log(new MyWriter());
$log->setLevel(\Slim\Log::WARN);
@@ -106,7 +121,7 @@ public function testLogWarn()
{
$this->expectOutputString('Warn');
$log = new \Slim\Log(new MyWriter());
- $result = $log->warn('Warn');
+ $result = $log->warning('Warn');
$this->assertTrue($result);
}
@@ -114,7 +129,7 @@ public function testLogWarnExcludedByLevel()
{
$log = new \Slim\Log(new MyWriter());
$log->setLevel(\Slim\Log::ERROR);
- $this->assertFalse($log->warn('Warn'));
+ $this->assertFalse($log->warning('Warn'));
}
public function testLogError()
@@ -128,15 +143,56 @@ public function testLogError()
public function testLogErrorExcludedByLevel()
{
$log = new \Slim\Log(new MyWriter());
- $log->setLevel(\Slim\Log::FATAL);
+ $log->setLevel(\Slim\Log::CRITICAL);
$this->assertFalse($log->error('Error'));
}
- public function testLogFatal()
+ public function testLogCritical()
+ {
+ $this->expectOutputString('Critical');
+ $log = new \Slim\Log(new MyWriter());
+ $result = $log->critical('Critical');
+ $this->assertTrue($result);
+ }
+
+ public function testLogCriticalExcludedByLevel()
+ {
+ $log = new \Slim\Log(new MyWriter());
+ $log->setLevel(\Slim\Log::ALERT);
+ $this->assertFalse($log->critical('Critical'));
+ }
+
+ public function testLogAlert()
+ {
+ $this->expectOutputString('Alert');
+ $log = new \Slim\Log(new MyWriter());
+ $result = $log->alert('Alert');
+ $this->assertTrue($result);
+ }
+
+ public function testLogAlertExcludedByLevel()
+ {
+ $log = new \Slim\Log(new MyWriter());
+ $log->setLevel(\Slim\Log::EMERGENCY);
+ $this->assertFalse($log->alert('Alert'));
+ }
+
+ public function testLogEmergency()
+ {
+ $this->expectOutputString('Emergency');
+ $log = new \Slim\Log(new MyWriter());
+ $result = $log->emergency('Emergency');
+ $this->assertTrue($result);
+ }
+
+ public function testInterpolateMessage()
{
- $this->expectOutputString('Fatal');
+ $this->expectOutputString('Hello Slim !');
$log = new \Slim\Log(new MyWriter());
- $result = $log->fatal('Fatal');
+ $result = $log->debug(
+ 'Hello {framework} !',
+ array('framework' => "Slim")
+ );
$this->assertTrue($result);
}
diff --git a/tests/LogWriterTest.php b/tests/LogWriterTest.php
index 3c30d8039..839f09f6e 100644
--- a/tests/LogWriterTest.php
+++ b/tests/LogWriterTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
diff --git a/tests/Middleware/ContentTypesTest.php b/tests/Middleware/ContentTypesTest.php
index 3857b3428..6f9fcfe87 100644
--- a/tests/Middleware/ContentTypesTest.php
+++ b/tests/Middleware/ContentTypesTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
diff --git a/tests/Middleware/FlashTest.php b/tests/Middleware/FlashTest.php
index 09da70a8a..7b8f7961d 100644
--- a/tests/Middleware/FlashTest.php
+++ b/tests/Middleware/FlashTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -86,7 +86,7 @@ public function testKeepFlashFromPreviousRequest()
}
/**
- * Test flash messages from preivous request do not persist to next request
+ * Test flash messages from previous request do not persist to next request
*/
public function testFlashMessagesFromPreviousRequestDoNotPersist()
{
diff --git a/tests/Middleware/MethodOverrideTest.php b/tests/Middleware/MethodOverrideTest.php
index 55484883c..c2c5857f3 100644
--- a/tests/Middleware/MethodOverrideTest.php
+++ b/tests/Middleware/MethodOverrideTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -98,7 +98,7 @@ public function testDoesNotOverrideMethodIfNotPost()
}
/**
- * Test does not override method if no method ovveride parameter
+ * Test does not override method if no method override parameter
*/
public function testDoesNotOverrideMethodAsPostWithoutParameter()
{
diff --git a/tests/Middleware/PrettyExceptionsTest.php b/tests/Middleware/PrettyExceptionsTest.php
index 4f41b2d52..28dabcc2f 100644
--- a/tests/Middleware/PrettyExceptionsTest.php
+++ b/tests/Middleware/PrettyExceptionsTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
diff --git a/tests/Middleware/SessionCookieTest.php b/tests/Middleware/SessionCookieTest.php
index 8ef12ef0c..472c01c01 100644
--- a/tests/Middleware/SessionCookieTest.php
+++ b/tests/Middleware/SessionCookieTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -48,7 +48,7 @@ public function setUp()
* 1) That the HTTP cookie is added to the `Set-Cookie:` response header;
* 2) That the HTTP cookie is constructed in the expected format;
*/
- public function testSessionCookieIsCreatedAndEncrypted()
+ public function testSessionCookieIsCreated()
{
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/index.php',
@@ -63,9 +63,7 @@ public function testSessionCookieIsCreatedAndEncrypted()
$mw->setNextMiddleware($app);
$mw->call();
list($status, $header, $body) = $app->response()->finalize();
- $matches = array();
- preg_match_all('@^slim_session=.+|.+|.+; expires=@', $header['Set-Cookie'], $matches, PREG_SET_ORDER);
- $this->assertEquals(1, count($matches));
+ $this->assertTrue($app->response->cookies->has('slim_session'));
}
/**
@@ -80,7 +78,7 @@ public function testSessionIsPopulatedFromCookie()
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/index.php',
'PATH_INFO' => '/foo',
- 'COOKIE' => 'slim_session=1644004961%7CLKkYPwqKIMvBK7MWl6D%2BxeuhLuMaW4quN%2F512ZAaVIY%3D%7Ce0f007fa852c7101e8224bb529e26be4d0dfbd63',
+ 'HTTP_COOKIE' => 'slim_session=1644004961%7CLKkYPwqKIMvBK7MWl6D%2BxeuhLuMaW4quN%2F512ZAaVIY%3D%7Ce0f007fa852c7101e8224bb529e26be4d0dfbd63',
));
$app = new \Slim\Slim();
$app->get('/foo', function () {
diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php
index db78918c3..a95036a12 100644
--- a/tests/MiddlewareTest.php
+++ b/tests/MiddlewareTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -30,57 +30,50 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-class My_Middleware extends \Slim\Middleware
+class MyMiddleware extends \Slim\Middleware
{
- public function call()
- {
- echo "Before";
- $this->next->call();
- echo "After";
- }
+ public function call() {}
}
-class My_Application
+class MiddlewareTest extends PHPUnit_Framework_TestCase
{
- public function call()
+ public function testSetApplication()
{
- echo "Application";
+ $app = new stdClass();
+ $mw = new MyMiddleware();
+ $mw->setApplication($app);
+
+ $this->assertAttributeSame($app, 'app', $mw);
}
-}
-class MiddlewareTest extends PHPUnit_Framework_TestCase
-{
- /**
- * Get and set application
- */
- public function testGetAndSetApplication()
+ public function testGetApplication()
{
- $app = new My_Application();
- $mw = new My_Middleware();
- $mw->setApplication($app);
+ $app = new stdClass();
+ $mw = new MyMiddleware();
+ $property = new \ReflectionProperty($mw, 'app');
+ $property->setAccessible(true);
+ $property->setValue($mw, $app);
+
$this->assertSame($app, $mw->getApplication());
}
- /**
- * Get and set next middleware
- */
- public function testGetAndSetNextMiddleware()
+ public function testSetNextMiddleware()
{
- $mw1 = new My_Middleware();
- $mw2 = new My_Middleware();
+ $mw1 = new MyMiddleware();
+ $mw2 = new MyMiddleware();
$mw1->setNextMiddleware($mw2);
- $this->assertSame($mw2, $mw1->getNextMiddleware());
+
+ $this->assertAttributeSame($mw2, 'next', $mw1);
}
- /**
- * Test call
- */
- public function testCall()
+ public function testGetNextMiddleware()
{
- $this->expectOutputString('BeforeApplicationAfter');
- $app = new My_Application();
- $mw = new My_Middleware();
- $mw->setNextMiddleware($app);
- $mw->call();
+ $mw1 = new MyMiddleware();
+ $mw2 = new MyMiddleware();
+ $property = new \ReflectionProperty($mw1, 'next');
+ $property->setAccessible(true);
+ $property->setValue($mw1, $mw2);
+
+ $this->assertSame($mw2, $mw1->getNextMiddleware());
}
}
diff --git a/tests/RouteTest.php b/tests/RouteTest.php
index decec7d4f..dec3f9efa 100644
--- a/tests/RouteTest.php
+++ b/tests/RouteTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -29,292 +29,185 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-
-// Used for passing callable via string
-function testCallable() {}
-
class RouteTest extends PHPUnit_Framework_TestCase
{
- /**
- * Route should set name
- */
- public function testRouteSetsName()
+ public function testGetPattern()
{
- $route = new \Slim\Route('/foo/bar', function () {});
- $route->name('foo');
- $this->assertEquals('foo', $route->getName());
- }
+ $route = new \Slim\Route('/foo', function () {});
- /**
- * Route should set pattern
- */
- public function testRouteSetsPattern()
- {
- $route1 = new \Slim\Route('/foo/bar', function () {});
- $this->assertEquals('/foo/bar', $route1->getPattern());
+ $this->assertEquals('/foo', $route->getPattern());
}
- /**
- * Route sets pattern with params
- */
- public function testRouteSetsPatternWithParams()
+ public function testGetName()
{
- $route = new \Slim\Route('/hello/:first/:last', function () {});
- $this->assertEquals('/hello/:first/:last', $route->getPattern());
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($route, 'name');
+ $property->setAccessible(true);
+ $property->setValue($route, 'foo');
+
+ $this->assertEquals('foo', $route->getName());
}
- /**
- * Route sets custom pattern that overrides pattern
- */
- public function testRouteSetsCustomTemplate()
+ public function testSetName()
{
- $route = new \Slim\Route('/hello/*', function () {});
- $route->setPattern('/hello/:name');
- $this->assertEquals('/hello/:name', $route->getPattern());
+ $route = new \Slim\Route('/foo', function () {});
+ $route->name('foo'); // <-- Alias for `setName()`
+
+ $this->assertAttributeEquals('foo', 'name', $route);
}
- /**
- * Route should store a reference to the callable
- * anonymous function.
- */
- public function testRouteSetsCallableAsFunction()
+ public function testGetCallable()
{
- $callable = function () { echo "Foo!"; };
- $route = new \Slim\Route('/foo/bar', $callable);
+ $callable = function () {
+ echo 'Foo';
+ };
+ $route = new \Slim\Route('/foo', $callable);
+
$this->assertSame($callable, $route->getCallable());
}
- /**
- * Route should store a reference to the callable
- * regular function (for PHP 5 < 5.3)
- */
- public function testRouteSetsCallableAsString()
+ public function testSetCallable()
{
- $route = new \Slim\Route('/foo/bar', 'testCallable');
- $this->assertEquals('testCallable', $route->getCallable());
- }
+ $callable = function () {
+ echo 'Foo';
+ };
+ $route = new \Slim\Route('/foo', $callable); // <-- Called inside __construct()
- /**
- * Route should throw exception when creating with an invalid callable
- */
- public function testRouteThrowsExecptionWithInvalidCallable()
- {
- $this->setExpectedException('InvalidArgumentException');
- $route = new \Slim\Route('/foo/bar', 'fnDoesNotExist');
+ $this->assertAttributeSame($callable, 'callable', $route);
}
- /**
- * Route should throw exception when setting an invalid callable
- */
- public function testRouteThrowsExecptionWhenSettingInvalidCallable()
+ public function testSetCallableWithInvalidArgument()
{
- $route = new \Slim\Route('/foo/bar', function () {});
- try
- {
- $route->setCallable('fnDoesNotExist');
- $this->fail('Did not catch InvalidArgumentException when setting invalid callable');
- } catch(\InvalidArgumentException $e) {}
+ $this->setExpectedException('\InvalidArgumentException');
+ $route = new \Slim\Route('/foo', 'doesNotExist'); // <-- Called inside __construct()
}
- /**
- * Test gets all params
- */
- public function testGetRouteParams()
+ public function testGetParams()
{
- // Prepare route
- $requestUri = '/hello/mr/anderson';
$route = new \Slim\Route('/hello/:first/:last', function () {});
+ $route->matches('/hello/mr/anderson'); // <-- Parses params from argument
- // Parse route params
- $this->assertTrue($route->matches($requestUri));
-
- // Get params
- $params = $route->getParams();
- $this->assertEquals(2, count($params));
- $this->assertEquals('mr', $params['first']);
- $this->assertEquals('anderson', $params['last']);
+ $this->assertEquals(array(
+ 'first' => 'mr',
+ 'last' => 'anderson'
+ ), $route->getParams());
}
- /**
- * Test sets all params
- */
- public function testSetRouteParams()
+ public function testSetParams()
{
- // Prepare route
- $requestUri = '/hello/mr/anderson';
$route = new \Slim\Route('/hello/:first/:last', function () {});
-
- // Parse route params
- $this->assertTrue($route->matches($requestUri));
-
- // Get params
- $params = $route->getParams();
- $this->assertEquals(2, count($params));
- $this->assertEquals('mr', $params['first']);
- $this->assertEquals('anderson', $params['last']);
-
- // Replace params
+ $route->matches('/hello/mr/anderson'); // <-- Parses params from argument
$route->setParams(array(
- 'first' => 'john',
+ 'first' => 'agent',
'last' => 'smith'
));
- // Get new params
- $params = $route->getParams();
- $this->assertEquals(2, count($params));
- $this->assertEquals('john', $params['first']);
- $this->assertEquals('smith', $params['last']);
+ $this->assertAttributeEquals(array(
+ 'first' => 'agent',
+ 'last' => 'smith'
+ ), 'params', $route);
}
- /**
- * Test gets param when exists
- */
- public function testGetRouteParamWhenExists()
+ public function testGetParam()
{
- // Prepare route
- $requestUri = '/hello/mr/anderson';
$route = new \Slim\Route('/hello/:first/:last', function () {});
- // Parse route params
- $this->assertTrue($route->matches($requestUri));
+ $property = new \ReflectionProperty($route, 'params');
+ $property->setAccessible(true);
+ $property->setValue($route, array(
+ 'first' => 'foo',
+ 'last' => 'bar'
+ ));
- // Get param
- $this->assertEquals('anderson', $route->getParam('last'));
+ $this->assertEquals('foo', $route->getParam('first'));
}
- /**
- * Test gets param when not exists
- */
- public function testGetRouteParamWhenNotExists()
+ public function testGetParamThatDoesNotExist()
{
- // Prepare route
- $requestUri = '/hello/mr/anderson';
+ $this->setExpectedException('InvalidArgumentException');
+
$route = new \Slim\Route('/hello/:first/:last', function () {});
- // Parse route params
- $this->assertTrue($route->matches($requestUri));
+ $property = new \ReflectionProperty($route, 'params');
+ $property->setAccessible(true);
+ $property->setValue($route, array(
+ 'first' => 'foo',
+ 'last' => 'bar'
+ ));
- // Get param
- try {
- $param = $route->getParam('foo');
- $this->fail('Did not catch expected InvalidArgumentException');
- } catch ( \InvalidArgumentException $e ) {}
+ $route->getParam('middle');
}
- /**
- * Test sets param when exists
- */
- public function testSetRouteParamWhenExists()
+ public function testSetParam()
{
- // Prepare route
- $requestUri = '/hello/mr/anderson';
$route = new \Slim\Route('/hello/:first/:last', function () {});
-
- // Parse route params
- $this->assertTrue($route->matches($requestUri));
-
- // Get param
- $this->assertEquals('anderson', $route->getParam('last'));
-
- // Set param
+ $route->matches('/hello/mr/anderson'); // <-- Parses params from argument
$route->setParam('last', 'smith');
- // Get new param
- $this->assertEquals('smith', $route->getParam('last'));
+ $this->assertAttributeEquals(array(
+ 'first' => 'mr',
+ 'last' => 'smith'
+ ), 'params', $route);
}
- /**
- * Test sets param when not exists
- */
- public function testSetRouteParamWhenNotExists()
+ public function testSetParamThatDoesNotExist()
{
- // Prepare route
- $requestUri = '/hello/mr/anderson';
- $route = new \Slim\Route('/hello/:first/:last', function () {});
-
- // Parse route params
- $this->assertTrue($route->matches($requestUri));
+ $this->setExpectedException('InvalidArgumentException');
- // Get param
- try {
- $param = $route->setParam('foo', 'bar');
- $this->fail('Did not catch expected InvalidArgumentException');
- } catch ( \InvalidArgumentException $e ) {}
+ $route = new \Slim\Route('/hello/:first/:last', function () {});
+ $route->matches('/hello/mr/anderson'); // <-- Parses params from argument
+ $route->setParam('middle', 'smith'); // <-- Should trigger InvalidArgumentException
}
- /**
- * If route matches a resource URI, param should be extracted.
- */
- public function testRouteMatchesAndParamExtracted()
+ public function testMatches()
{
- $resource = '/hello/Josh';
$route = new \Slim\Route('/hello/:name', function () {});
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('name' => 'Josh'), $route->getParams());
+
+ $this->assertTrue($route->matches('/hello/josh'));
}
- /**
- * If route matches a resource URI, multiple params should be extracted.
- */
- public function testRouteMatchesAndMultipleParamsExtracted()
+ public function testMatchesIsFalse()
{
- $resource = '/hello/Josh/and/John';
- $route = new \Slim\Route('/hello/:first/and/:second', function () {});
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('first' => 'Josh', 'second' => 'John'), $route->getParams());
+ $route = new \Slim\Route('/foo', function () {});
+
+ $this->assertFalse($route->matches('/bar'));
}
- /**
- * If route does not match a resource URI, params remain an empty array
- */
- public function testRouteDoesNotMatchAndParamsNotExtracted()
+ public function testMatchesPatternWithTrailingSlash()
{
- $resource = '/foo/bar';
- $route = new \Slim\Route('/hello/:name', function () {});
- $result = $route->matches($resource);
- $this->assertFalse($result);
- $this->assertEquals(array(), $route->getParams());
+ $route = new \Slim\Route('/foo/', function () {});
+
+ $this->assertTrue($route->matches('/foo/'));
+ $this->assertTrue($route->matches('/foo'));
}
- /**
- * Route matches URI with trailing slash
- *
- */
- public function testRouteMatchesWithTrailingSlash()
+ public function testMatchesPatternWithoutTrailingSlash()
{
- $resource1 = '/foo/bar/';
- $resource2 = '/foo/bar';
- $route = new \Slim\Route('/foo/:one/', function () {});
- $this->assertTrue($route->matches($resource1));
- $this->assertTrue($route->matches($resource2));
+ $route = new \Slim\Route('/foo', function () {});
+
+ $this->assertFalse($route->matches('/foo/'));
+ $this->assertTrue($route->matches('/foo'));
}
- /**
- * Route matches URI with conditions
- */
- public function testRouteMatchesResourceWithConditions()
+ public function testMatchesWithConditions()
{
- $resource = '/hello/Josh/and/John';
$route = new \Slim\Route('/hello/:first/and/:second', function () {});
- $route->conditions(array('first' => '[a-zA-Z]{3,}'));
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('first' => 'Josh', 'second' => 'John'), $route->getParams());
+ $route->conditions(array(
+ 'first' => '[a-zA-Z]{3,}'
+ ));
+
+ $this->assertTrue($route->matches('/hello/Josh/and/John'));
}
- /**
- * Route does not match URI with conditions
- */
- public function testRouteDoesNotMatchResourceWithConditions()
+ public function testMatchesWithConditionsIsFalse()
{
- $resource = '/hello/Josh/and/John';
$route = new \Slim\Route('/hello/:first/and/:second', function () {});
- $route->conditions(array('first' => '[a-z]{3,}'));
- $result = $route->matches($resource);
- $this->assertFalse($result);
- $this->assertEquals(array(), $route->getParams());
+ $route->conditions(array(
+ 'first' => '[a-z]{3,}'
+ ));
+
+ $this->assertFalse($route->matches('/hello/Josh/and/John'));
}
/*
@@ -324,14 +217,12 @@ public function testRouteDoesNotMatchResourceWithConditions()
*
* Excludes "+" which is valid but decodes into a space character
*/
- public function testRouteMatchesResourceWithValidRfc2396PathComponent()
+ public function testMatchesWithValidRfc2396PathComponent()
{
$symbols = ':@&=$,';
- $resource = '/rfc2386/' . $symbols;
$route = new \Slim\Route('/rfc2386/:symbols', function () {});
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('symbols' => $symbols), $route->getParams());
+
+ $this->assertTrue($route->matches('/rfc2386/' . $symbols));
}
/*
@@ -339,221 +230,289 @@ public function testRouteMatchesResourceWithValidRfc2396PathComponent()
*
* "Uniform Resource Identifiers (URI): Generic Syntax" http://www.ietf.org/rfc/rfc2396.txt
*/
- public function testRouteMatchesResourceWithUnreservedMarks()
+ public function testMatchesWithUnreservedMarks()
{
$marks = "-_.!~*'()";
- $resource = '/marks/' . $marks;
$route = new \Slim\Route('/marks/:marks', function () {});
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('marks' => $marks), $route->getParams());
+
+ $this->assertTrue($route->matches('/marks/' . $marks));
}
- /**
- * Route optional parameters
- *
- * Pre-conditions:
- * Route pattern requires :year, optionally accepts :month and :day
- *
- * Post-conditions:
- * All: Year is 2010
- * Case A: Month and day default values are used
- * Case B: Month is "05" and day default value is used
- * Case C: Month is "05" and day is "13"
- */
- public function testRouteOptionalParameters()
+ public function testMatchesOptionalParameters()
{
$pattern = '/archive/:year(/:month(/:day))';
- //Case A
- $routeA = new \Slim\Route($pattern, function () {});
- $resourceA = '/archive/2010';
- $resultA = $routeA->matches($resourceA);
- $this->assertTrue($resultA);
- $this->assertEquals(array('year' => '2010'), $routeA->getParams());
+ $route1 = new \Slim\Route($pattern, function () {});
+ $this->assertTrue($route1->matches('/archive/2010'));
+ $this->assertEquals(array('year' => '2010'), $route1->getParams());
- //Case B
- $routeB = new \Slim\Route($pattern, function () {});
- $resourceB = '/archive/2010/05';
- $resultB = $routeB->matches($resourceB);
- $this->assertTrue($resultB);
- $this->assertEquals(array('year' => '2010', 'month' => '05'), $routeB->getParams());
+ $route2 = new \Slim\Route($pattern, function () {});
+ $this->assertTrue($route2->matches('/archive/2010/05'));
+ $this->assertEquals(array('year' => '2010', 'month' => '05'), $route2->getParams());
- //Case C
- $routeC = new \Slim\Route($pattern, function () {});
- $resourceC = '/archive/2010/05/13';
- $resultC = $routeC->matches($resourceC);
- $this->assertTrue($resultC);
- $this->assertEquals(array('year' => '2010', 'month' => '05', 'day' => '13'), $routeC->getParams());
+ $route3 = new \Slim\Route($pattern, function () {});
+ $this->assertTrue($route3->matches('/archive/2010/05/13'));
+ $this->assertEquals(array('year' => '2010', 'month' => '05', 'day' => '13'), $route3->getParams());
}
- /**
- * Test route default conditions
- *
- * Pre-conditions:
- * Route class has default conditions;
- *
- * Post-conditions:
- * Case A: Route instance has default conditions;
- * Case B: Route instance has newly merged conditions;
- */
- public function testRouteDefaultConditions()
+ public function testGetConditions()
{
- \Slim\Route::setDefaultConditions(array('id' => '\d+'));
- $r = new \Slim\Route('/foo', function () {});
- //Case A
- $this->assertEquals(\Slim\Route::getDefaultConditions(), $r->getConditions());
- //Case B
- $r->conditions(array('name' => '[a-z]{2,5}'));
- $c = $r->getConditions();
- $this->assertArrayHasKey('id', $c);
- $this->assertArrayHasKey('name', $c);
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($route, 'conditions');
+ $property->setAccessible(true);
+ $property->setValue($route, array('foo' => '\d{3}'));
+
+ $this->assertEquals(array('foo' => '\d{3}'), $route->getConditions());
}
- /**
- * Route matches URI with wildcard
- */
- public function testRouteMatchesResourceWithWildcard()
+ public function testSetDefaultConditions()
+ {
+ \Slim\Route::setDefaultConditions(array(
+ 'id' => '\d+'
+ ));
+
+ $property = new \ReflectionProperty('\Slim\Route', 'defaultConditions');
+ $property->setAccessible(true);
+
+ $this->assertEquals(array(
+ 'id' => '\d+'
+ ), $property->getValue());
+ }
+
+ public function testGetDefaultConditions()
+ {
+ $property = new \ReflectionProperty('\Slim\Route', 'defaultConditions');
+ $property->setAccessible(true);
+ $property->setValue(array(
+ 'id' => '\d+'
+ ));
+
+ $this->assertEquals(array(
+ 'id' => '\d+'
+ ), \Slim\Route::getDefaultConditions());
+ }
+
+ public function testDefaultConditionsAssignedToInstance()
+ {
+ $staticProperty = new \ReflectionProperty('\Slim\Route', 'defaultConditions');
+ $staticProperty->setAccessible(true);
+ $staticProperty->setValue(array(
+ 'id' => '\d+'
+ ));
+ $route = new \Slim\Route('/foo', function () {});
+
+ $this->assertAttributeEquals(array(
+ 'id' => '\d+'
+ ), 'conditions', $route);
+ }
+
+ public function testMatchesWildcard()
{
- $resource = '/hello/foo/bar/world';
$route = new \Slim\Route('/hello/:path+/world', function () {});
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('path'=>array('foo', 'bar')), $route->getParams());
+
+ $this->assertTrue($route->matches('/hello/foo/bar/world'));
+ $this->assertAttributeEquals(array(
+ 'path' => array('foo', 'bar')
+ ), 'params', $route);
}
- /**
- * Route matches URI with more than one wildcard
- */
- public function testRouteMatchesResourceWithMultipleWildcards()
+ public function testMatchesMultipleWildcards()
{
- $resource = '/hello/foo/bar/world/2012/03/10';
$route = new \Slim\Route('/hello/:path+/world/:date+', function () {});
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('path'=>array('foo', 'bar'), 'date'=>array('2012', '03', '10')), $route->getParams());
+
+ $this->assertTrue($route->matches('/hello/foo/bar/world/2012/03/10'));
+ $this->assertAttributeEquals(array(
+ 'path' => array('foo', 'bar'),
+ 'date' => array('2012', '03', '10')
+ ), 'params', $route);
}
- /**
- * Route matches URI with wildcards and parameters
- */
- public function testRouteMatchesResourceWithWildcardsAndParams()
+ public function testMatchesParamsAndWildcards()
{
- $resource = '/hello/foo/bar/world/2012/03/10/first/second';
$route = new \Slim\Route('/hello/:path+/world/:year/:month/:day/:path2+', function () {});
- $result = $route->matches($resource);
- $this->assertTrue($result);
- $this->assertEquals(array('path'=>array('foo', 'bar'), 'year'=>'2012', 'month'=>'03', 'day'=>'10', 'path2'=>array('first', 'second')), $route->getParams());
+
+ $this->assertTrue($route->matches('/hello/foo/bar/world/2012/03/10/first/second'));
+ $this->assertAttributeEquals(array(
+ 'path' => array('foo', 'bar'),
+ 'year' => '2012',
+ 'month' => '03',
+ 'day' => '10',
+ 'path2' => array('first', 'second')
+ ), 'params', $route);
}
- /**
- * Route matches URI with optional wildcard and parameter
- */
- public function testRouteMatchesResourceWithOptionalWildcardsAndParams()
+ public function testMatchesParamsWithOptionalWildcard()
+ {
+ $route = new \Slim\Route('/hello(/:foo(/:bar+))', function () {});
+
+ $this->assertTrue($route->matches('/hello'));
+ $this->assertTrue($route->matches('/hello/world'));
+ $this->assertTrue($route->matches('/hello/world/foo'));
+ $this->assertTrue($route->matches('/hello/world/foo/bar'));
+ }
+
+ public function testSetMiddleware()
+ {
+ $route = new \Slim\Route('/foo', function () {});
+ $mw = function () {
+ echo 'Foo';
+ };
+ $route->setMiddleware($mw);
+
+ $this->assertAttributeContains($mw, 'middleware', $route);
+ }
+
+ public function testSetMiddlewareMultipleTimes()
+ {
+ $route = new \Slim\Route('/foo', function () {});
+ $mw1 = function () {
+ echo 'Foo';
+ };
+ $mw2 = function () {
+ echo 'Bar';
+ };
+ $route->setMiddleware($mw1);
+ $route->setMiddleware($mw2);
+
+ $this->assertAttributeContains($mw1, 'middleware', $route);
+ $this->assertAttributeContains($mw2, 'middleware', $route);
+ }
+
+ public function testSetMiddlewareWithArray()
{
- $resourceA = '/hello/world/foo/bar';
- $routeA = new \Slim\Route('/hello(/:world(/:path+))', function () {});
- $this->assertTrue($routeA->matches($resourceA));
- $this->assertEquals(array('world'=>'world', 'path'=>array('foo', 'bar')), $routeA->getParams());
+ $route = new \Slim\Route('/foo', function () {});
+ $mw1 = function () {
+ echo 'Foo';
+ };
+ $mw2 = function () {
+ echo 'Bar';
+ };
+ $route->setMiddleware(array($mw1, $mw2));
+
+ $this->assertAttributeContains($mw1, 'middleware', $route);
+ $this->assertAttributeContains($mw2, 'middleware', $route);
+ }
+
+ public function testSetMiddlewareWithInvalidArgument()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+
+ $route = new \Slim\Route('/foo', function () {});
+ $route->setMiddleware('doesNotExist'); // <-- Should throw InvalidArgumentException
+ }
+
+ public function testSetMiddlewareWithArrayWithInvalidArgument()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+
+ $route = new \Slim\Route('/foo', function () {});
+ $route->setMiddleware(array('doesNotExist'));
+ }
+
+ public function testGetMiddleware()
+ {
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($route, 'middleware');
+ $property->setAccessible(true);
+ $property->setValue($route, array('foo' => 'bar'));
+
+ $this->assertEquals(array('foo' => 'bar'), $route->getMiddleware());
+ }
+
+ public function testSetHttpMethods()
+ {
+ $route = new \Slim\Route('/foo', function () {});
+ $route->setHttpMethods('GET', 'POST');
+
+ $this->assertAttributeEquals(array('GET', 'POST'), 'methods', $route);
+ }
+
+ public function testGetHttpMethods()
+ {
+ $route = new \Slim\Route('/foo', function () {});
- $resourceB = '/hello/world';
- $routeB = new \Slim\Route('/hello(/:world(/:path))', function () {});
- $this->assertTrue($routeB->matches($resourceB));
- $this->assertEquals(array('world'=>'world'), $routeB->getParams());
+ $property = new \ReflectionProperty($route, 'methods');
+ $property->setAccessible(true);
+ $property->setValue($route, array('GET', 'POST'));
+
+ $this->assertEquals(array('GET', 'POST'), $route->getHttpMethods());
+ }
+
+ public function testAppendHttpMethods()
+ {
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($route, 'methods');
+ $property->setAccessible(true);
+ $property->setValue($route, array('GET', 'POST'));
+
+ $route->appendHttpMethods('PUT');
+
+ $this->assertAttributeEquals(array('GET', 'POST', 'PUT'), 'methods', $route);
+ }
+
+ public function testAppendHttpMethodsWithVia()
+ {
+ $route = new \Slim\Route('/foo', function () {});
+ $route->via('PUT');
+
+ $this->assertAttributeContains('PUT', 'methods', $route);
+ }
+
+ public function testSupportsHttpMethod()
+ {
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($route, 'methods');
+ $property->setAccessible(true);
+ $property->setValue($route, array('POST'));
+
+ $this->assertTrue($route->supportsHttpMethod('POST'));
+ $this->assertFalse($route->supportsHttpMethod('PUT'));
}
/**
- * Route does not match URI with wildcard
+ * Test dispatch with params
*/
- public function testRouteDoesNotMatchResourceWithWildcard()
+ public function testDispatch()
{
- $resource = '/hello';
- $route = new \Slim\Route('/hello/:path+', function () {});
- $result = $route->matches($resource);
- $this->assertFalse($result);
- $this->assertEquals(array(), $route->getParams());
+ $this->expectOutputString('Hello josh');
+ $route = new \Slim\Route('/hello/:name', function ($name) { echo "Hello $name"; });
+ $route->matches('/hello/josh'); //<-- Extracts params from resource URI
+ $route->dispatch();
}
/**
- * Test route sets and gets middleware
- *
- * Pre-conditions:
- * Route instantiated
- *
- * Post-conditions:
- * Case A: Middleware set as callable, not array
- * Case B: Middleware set after other middleware already set
- * Case C: Middleware set as array of callables
- * Case D: Middleware set as a callable array
- * Case E: Middleware is invalid; throws InvalidArgumentException
- * Case F: Middleware is an array with one invalid callable; throws InvalidArgumentException
+ * Test dispatch with middleware
*/
- public function testRouteMiddleware()
- {
- $callable1 = function () {};
- $callable2 = function () {};
- //Case A
- $r1 = new \Slim\Route('/foo', function () {});
- $r1->setMiddleware($callable1);
- $mw = $r1->getMiddleware();
- $this->assertInternalType('array', $mw);
- $this->assertEquals(1, count($mw));
- //Case B
- $r1->setMiddleware($callable2);
- $mw = $r1->getMiddleware();
- $this->assertEquals(2, count($mw));
- //Case C
- $r2 = new \Slim\Route('/foo', function () {});
- $r2->setMiddleware(array($callable1, $callable2));
- $mw = $r2->getMiddleware();
- $this->assertInternalType('array', $mw);
- $this->assertEquals(2, count($mw));
- //Case D
- $r3 = new \Slim\Route('/foo', function () {});
- $r3->setMiddleware(array($this, 'callableTestFunction'));
- $mw = $r3->getMiddleware();
- $this->assertInternalType('array', $mw);
- $this->assertEquals(1, count($mw));
- //Case E
- try {
- $r3->setMiddleware('sdjfsoi788');
- $this->fail('Did not catch InvalidArgumentException when setting invalid route middleware');
- } catch ( \InvalidArgumentException $e ) {}
- //Case F
- try {
- $r3->setMiddleware(array($callable1, $callable2, 'sdjfsoi788'));
- $this->fail('Did not catch InvalidArgumentException when setting an array with one invalid route middleware');
- } catch ( \InvalidArgumentException $e ) {}
- }
-
- public function callableTestFunction() {}
+ public function testDispatchWithMiddlware()
+ {
+ $this->expectOutputString('First! Second! Hello josh');
+ $route = new \Slim\Route('/hello/:name', function ($name) { echo "Hello $name"; });
+ $route->setMiddleware(function () {
+ echo "First! ";
+ });
+ $route->setMiddleware(function () {
+ echo "Second! ";
+ });
+ $route->matches('/hello/josh'); //<-- Extracts params from resource URI
+ $route->dispatch();
+ }
/**
- * Test that a Route manages the HTTP methods that it supports
- *
- * Case A: Route initially supports no HTTP methods
- * Case B: Route can set its supported HTTP methods
- * Case C: Route can append supported HTTP methods
- * Case D: Route can test if it supports an HTTP method
- * Case E: Route can lazily declare supported HTTP methods with `via`
+ * Test middleware with arguments
*/
- public function testHttpMethods()
- {
- //Case A
- $r = new \Slim\Route('/foo', function () {});
- $this->assertEmpty($r->getHttpMethods());
- //Case B
- $r->setHttpMethods('GET');
- $this->assertEquals(array('GET'), $r->getHttpMethods());
- //Case C
- $r->appendHttpMethods('POST', 'PUT');
- $this->assertEquals(array('GET', 'POST', 'PUT'), $r->getHttpMethods());
- //Case D
- $this->assertTrue($r->supportsHttpMethod('GET'));
- $this->assertFalse($r->supportsHttpMethod('DELETE'));
- //Case E
- $viaResult = $r->via('DELETE');
- $this->assertTrue($viaResult instanceof \Slim\Route);
- $this->assertTrue($r->supportsHttpMethod('DELETE'));
+ public function testRouteMiddlwareArguments()
+ {
+ $this->expectOutputString('foobar');
+ $route = new \Slim\Route('/foo', function () { echo "bar"; });
+ $route->setName('foo');
+ $route->setMiddleware(function ($route) {
+ echo $route->getName();
+ });
+ $route->matches('/foo'); //<-- Extracts params from resource URI
+ $route->dispatch();
}
}
diff --git a/tests/RouterTest.php b/tests/RouterTest.php
index cb5cc33f1..4f61c4b33 100644
--- a/tests/RouterTest.php
+++ b/tests/RouterTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -32,571 +32,211 @@
class RouterTest extends PHPUnit_Framework_TestCase
{
- protected $env;
- protected $req;
- protected $res;
-
- public function setUp()
- {
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/bar', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $this->env = \Slim\Environment::getInstance();
- $this->req = new \Slim\Http\Request($this->env);
- $this->res = new \Slim\Http\Response();
- }
-
/**
- * Router::urlFor should return a full route pattern
- * even if no params data is provided.
+ * Constructor should initialize routes as empty array
*/
- public function testUrlForNamedRouteWithoutParams()
+ public function testConstruct()
{
$router = new \Slim\Router();
- $route = $router->map('/foo/bar', function () {})->via('GET');
- $router->addNamedRoute('foo', $route);
- $this->assertEquals('/foo/bar', $router->urlFor('foo'));
- }
- /**
- * Router::urlFor should return a full route pattern if
- * param data is provided.
- */
- public function testUrlForNamedRouteWithParams()
- {
- $router = new \Slim\Router();
- $route = $router->map('/foo/:one/and/:two', function ($one, $two) {})->via('GET');
- $router->addNamedRoute('foo', $route);
- $this->assertEquals('/foo/Josh/and/John', $router->urlFor('foo', array('one' => 'Josh', 'two' => 'John')));
+ $this->assertAttributeEquals(array(), 'routes', $router);
}
/**
- * Router::urlFor should throw an exception if Route with name
- * does not exist.
- * @expectedException \RuntimeException
+ * Map should set and return instance of \Slim\Route
*/
- public function testUrlForNamedRouteThatDoesNotExist()
+ public function testMap()
{
$router = new \Slim\Router();
- $route = $router->map('/foo/bar', function () {})->via('GET');
- $router->addNamedRoute('bar', $route);
- $router->urlFor('foo');
+ $route = new \Slim\Route('/foo', function() {});
+ $router->map($route);
+
+ $this->assertAttributeContains($route, 'routes', $router);
}
/**
- * Router::addNamedRoute should throw an exception if named Route
- * with same name already exists.
+ * Named route should be added and indexed by name
*/
- public function testNamedRouteWithExistingName()
+ public function testAddNamedRoute()
{
- $this->setExpectedException('\RuntimeException');
$router = new \Slim\Router();
- $route1 = $router->map('/foo/bar', function () {})->via('GET');
- $route2 = $router->map('/foo/bar/2', function () {})->via('GET');
- $router->addNamedRoute('bar', $route1);
- $router->addNamedRoute('bar', $route2);
+ $route = new \Slim\Route('/foo', function () {});
+ $router->addNamedRoute('foo', $route);
+
+ $property = new \ReflectionProperty($router, 'namedRoutes');
+ $property->setAccessible(true);
+
+ $rV = $property->getValue($router);
+ $this->assertSame($route, $rV['foo']);
}
/**
- * Test if named route exists
- *
- * Pre-conditions:
- * Slim app instantiated;
- * Named route created;
- *
- * Post-conditions:
- * Named route found to exist;
- * Non-existant route found not to exist;
+ * Named route should have unique name
*/
- public function testHasNamedRoute()
+ public function testAddNamedRouteWithDuplicateKey()
{
+ $this->setExpectedException('RuntimeException');
+
$router = new \Slim\Router();
- $route = $router->map('/foo', function () {})->via('GET');
+ $route = new \Slim\Route('/foo', function () {});
+ $router->addNamedRoute('foo', $route);
$router->addNamedRoute('foo', $route);
- $this->assertTrue($router->hasNamedRoute('foo'));
- $this->assertFalse($router->hasNamedRoute('bar'));
}
/**
- * Test Router gets named route
- *
- * Pre-conditions;
- * Slim app instantiated;
- * Named route created;
- *
- * Post-conditions:
- * Named route fetched by named;
- * NULL is returned if named route does not exist;
+ * Router should return named route by name, or null if not found
*/
public function testGetNamedRoute()
{
$router = new \Slim\Router();
- $route1 = $router->map('/foo', function () {})->via('GET');
- $router->addNamedRoute('foo', $route1);
- $this->assertSame($route1, $router->getNamedRoute('foo'));
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($router, 'namedRoutes');
+ $property->setAccessible(true);
+ $property->setValue($router, array('foo' => $route));
+
+ $this->assertSame($route, $router->getNamedRoute('foo'));
$this->assertNull($router->getNamedRoute('bar'));
}
/**
- * Test external iterator for Router's named routes
- *
- * Pre-conditions:
- * Slim app instantiated;
- * Named routes created;
- *
- * Post-conditions:
- * Array iterator returned for named routes;
+ * Router should determine named routes and cache results
*/
public function testGetNamedRoutes()
{
$router = new \Slim\Router();
- $route1 = $router->map('/foo', function () {})->via('GET');
- $route2 = $router->map('/bar', function () {})->via('POST');
- $router->addNamedRoute('foo', $route1);
- $router->addNamedRoute('bar', $route2);
- $namedRoutesIterator = $router->getNamedRoutes();
- $this->assertInstanceOf('ArrayIterator', $namedRoutesIterator);
- $this->assertEquals(2, $namedRoutesIterator->count());
- }
+ $route1 = new \Slim\Route('/foo', function () {});
+ $route2 = new \Slim\Route('/bar', function () {});
- /**
- * Router considers HEAD requests as GET requests
- */
- public function testRouterConsidersHeadAsGet()
- {
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'HEAD',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/bar', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $this->env = \Slim\Environment::getInstance();
- $this->req = new \Slim\Http\Request($this->env);
- $this->res = new \Slim\Http\Response();
- $router = new \Slim\Router();
- $route = $router->map('/bar', function () {})->via('GET', 'HEAD');
- $numberOfMatchingRoutes = count($router->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri()));
- $this->assertEquals(1, $numberOfMatchingRoutes);
+ // Init router routes to array
+ $propertyRouterRoutes = new \ReflectionProperty($router, 'routes');
+ $propertyRouterRoutes->setAccessible(true);
+ $propertyRouterRoutes->setValue($router, array($route1, $route2));
+
+ // Init router named routes to null
+ $propertyRouterNamedRoutes = new \ReflectionProperty($router, 'namedRoutes');
+ $propertyRouterNamedRoutes->setAccessible(true);
+ $propertyRouterNamedRoutes->setValue($router, null);
+
+ // Init route name
+ $propertyRouteName = new \ReflectionProperty($route2, 'name');
+ $propertyRouteName->setAccessible(true);
+ $propertyRouteName->setValue($route2, 'bar');
+
+ $namedRoutes = $router->getNamedRoutes();
+ $this->assertCount(1, $namedRoutes);
+ $this->assertSame($route2, $namedRoutes['bar']);
}
/**
- * Router::urlFor
+ * Router should detect presence of a named route by name
*/
- public function testRouterUrlFor()
+ public function testHasNamedRoute()
{
$router = new \Slim\Router();
- $route1 = $router->map('/foo/bar', function () {})->via('GET');
- $route2 = $router->map('/foo/:one/:two', function () {})->via('GET');
- $route3 = $router->map('/foo/:one(/:two)', function () {})->via('GET');
- $route4 = $router->map('/foo/:one/(:two/)', function () {})->via('GET');
- $route5 = $router->map('/foo/:one/(:two/(:three/))', function () {})->via('GET');
- $route6 = $router->map('/foo/:path+/bar', function (){})->via('GET');
- $route7 = $router->map('/foo/:path+/:path2+/bar', function (){})->via('GET');
- $route8 = $router->map('/foo/:path+', function (){})->via('GET');
- $route9 = $router->map('/foo/:var/:var2', function (){})->via('GET');
- $route1->setName('route1');
- $route2->setName('route2');
- $route3->setName('route3');
- $route4->setName('route4');
- $route5->setName('route5');
- $route6->setName('route6');
- $route7->setName('route7');
- $route8->setName('route8');
- $route9->setName('route9');
- //Route
- $this->assertEquals('/foo/bar', $router->urlFor('route1'));
- //Route with params
- $this->assertEquals('/foo/foo/bar', $router->urlFor('route2', array('one' => 'foo', 'two' => 'bar')));
- $this->assertEquals('/foo/foo/:two', $router->urlFor('route2', array('one' => 'foo')));
- $this->assertEquals('/foo/:one/bar', $router->urlFor('route2', array('two' => 'bar')));
- //Route with params and optional segments
- $this->assertEquals('/foo/foo/bar', $router->urlFor('route3', array('one' => 'foo', 'two' => 'bar')));
- $this->assertEquals('/foo/foo', $router->urlFor('route3', array('one' => 'foo')));
- $this->assertEquals('/foo/:one/bar', $router->urlFor('route3', array('two' => 'bar')));
- $this->assertEquals('/foo/:one', $router->urlFor('route3'));
- //Route with params and optional segments
- $this->assertEquals('/foo/foo/bar/', $router->urlFor('route4', array('one' => 'foo', 'two' => 'bar')));
- $this->assertEquals('/foo/foo/', $router->urlFor('route4', array('one' => 'foo')));
- $this->assertEquals('/foo/:one/bar/', $router->urlFor('route4', array('two' => 'bar')));
- $this->assertEquals('/foo/:one/', $router->urlFor('route4'));
- //Route with params and optional segments
- $this->assertEquals('/foo/foo/bar/what/', $router->urlFor('route5', array('one' => 'foo', 'two' => 'bar', 'three' => 'what')));
- $this->assertEquals('/foo/foo/', $router->urlFor('route5', array('one' => 'foo')));
- $this->assertEquals('/foo/:one/bar/', $router->urlFor('route5', array('two' => 'bar')));
- $this->assertEquals('/foo/:one/bar/what/', $router->urlFor('route5', array('two' => 'bar', 'three' => 'what')));
- $this->assertEquals('/foo/:one/', $router->urlFor('route5'));
- //Route with wildcard params
- $this->assertEquals('/foo/bar/bar', $router->urlFor('route6', array('path'=>'bar')));
- $this->assertEquals('/foo/foo/bar/bar', $router->urlFor('route7', array('path'=>'foo', 'path2'=>'bar')));
- $this->assertEquals('/foo/bar', $router->urlFor('route8', array('path'=>'bar')));
- //Route with similar param names, test greedy matching
- $this->assertEquals('/foo/1/2', $router->urlFor('route9', array('var2'=>'2', 'var'=>'1')));
- $this->assertEquals('/foo/1/2', $router->urlFor('route9', array('var'=>'1', 'var2'=>'2')));
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($router, 'namedRoutes');
+ $property->setAccessible(true);
+ $property->setValue($router, array('foo' => $route));
+
+ $this->assertTrue($router->hasNamedRoute('foo'));
+ $this->assertFalse($router->hasNamedRoute('bar'));
}
/**
- * Test that router returns no matches when neither HTTP method nor URI match.
+ * Router should return current route if set during iteration
*/
- public function testRouterMatchesRoutesNone()
+ public function testGetCurrentRoute()
{
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $this->env = \Slim\Environment::getInstance();
- $this->req = new \Slim\Http\Request($this->env);
- $this->res = new \Slim\Http\Response();
$router = new \Slim\Router();
- $router->map('/bar', function () {})->via('POST');
- $router->map('/foo', function () {})->via('POST');
- $router->map('/foo', function () {})->via('PUT');
- $router->map('/foo/bar/xyz', function () {})->via('DELETE');
- $this->assertEquals(0, count($router->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri())));
+ $route = new \Slim\Route('/foo', function () {});
+
+ $property = new \ReflectionProperty($router, 'currentRoute');
+ $property->setAccessible(true);
+ $property->setValue($router, $route);
+
+ $this->assertSame($route, $router->getCurrentRoute());
}
/**
- * Test that router returns no matches when HTTP method matches but URI does not.
+ * Router should return first matching route if current route not set yet by iteration
*/
- public function testRouterMatchesRoutesNoneWhenMethodMatchesUriDoesNot()
+ public function testGetCurrentRouteIfMatchedRoutes()
{
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $this->env = \Slim\Environment::getInstance();
- $this->req = new \Slim\Http\Request($this->env);
- $this->res = new \Slim\Http\Response();
$router = new \Slim\Router();
- $router->map('/fooNOMATCH', function () {})->via('GET');
- $router->map('/foo', function () {})->via('POST');
- $router->map('/foo', function () {})->via('PUT');
- $router->map('/foo/bar/xyz', function () {})->via('DELETE');
- $this->assertEquals(0, count($router->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri())));
+ $route = new \Slim\Route('/foo', function () {});
+
+ $propertyMatchedRoutes = new \ReflectionProperty($router, 'matchedRoutes');
+ $propertyMatchedRoutes->setAccessible(true);
+ $propertyMatchedRoutes->setValue($router, array($route));
+
+ $propertyCurrentRoute = new \ReflectionProperty($router, 'currentRoute');
+ $propertyCurrentRoute->setAccessible(true);
+ $propertyCurrentRoute->setValue($router, null);
+
+ $this->assertSame($route, $router->getCurrentRoute());
}
/**
- * Test that router returns no matches when HTTP method does not match but URI does.
+ * Router should return `null` if current route not set yet and there are no matching routes
*/
- public function testRouterMatchesRoutesNoneWhenMethodDoesNotMatchUriMatches()
+ public function testGetCurrentRouteIfNoMatchedRoutes()
{
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $this->env = \Slim\Environment::getInstance();
- $this->req = new \Slim\Http\Request($this->env);
- $this->res = new \Slim\Http\Response();
$router = new \Slim\Router();
- $router->map('/foo', function () {})->via('OPTIONS');
- $router->map('/foo', function () {})->via('POST');
- $router->map('/foo', function () {})->via('PUT');
- $router->map('/foo/bar/xyz', function () {})->via('DELETE');
- $this->assertEquals(0, count($router->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri())));
+
+ $propertyMatchedRoutes = new \ReflectionProperty($router, 'matchedRoutes');
+ $propertyMatchedRoutes->setAccessible(true);
+ $propertyMatchedRoutes->setValue($router, array());
+
+ $propertyCurrentRoute = new \ReflectionProperty($router, 'currentRoute');
+ $propertyCurrentRoute->setAccessible(true);
+ $propertyCurrentRoute->setValue($router, null);
+
+ $this->assertNull($router->getCurrentRoute());
}
- /**
- * Test that router returns matched routes based on HTTP method and URI.
- */
- public function testRouterMatchesRoutes()
+ public function testGetMatchedRoutes()
{
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $this->env = \Slim\Environment::getInstance();
- $this->req = new \Slim\Http\Request($this->env);
- $this->res = new \Slim\Http\Response();
$router = new \Slim\Router();
- $router->map('/foo', function () {})->via('GET');
- $router->map('/foo', function () {})->via('POST');
- $router->map('/foo', function () {})->via('PUT');
- $router->map('/foo/bar/xyz', function () {})->via('DELETE');
- $this->assertEquals(1, count($router->getMatchedRoutes($this->req->getMethod(), $this->req->getResourceUri())));
- }
- /**
- * Test get current route
- */
- public function testGetCurrentRoute()
- {
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo' //<-- Virtual
- ));
- $app = new \Slim\Slim();
- $route1 = $app->get('/bar', function () {
- echo "Bar";
- });
- $route2 = $app->get('/foo', function () {
- echo "Foo";
- });
- $app->call();
- $this->assertSame($route2, $app->router()->getCurrentRoute());
- }
+ $route1 = new \Slim\Route('/foo', function () {});
+ $route1 = $route1->via('GET');
- /**
- * Test calling get current route before routing doesn't cause errors
- */
- public function testGetCurrentRouteBeforeRoutingDoesntError()
- {
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo' //<-- Virtual
- ));
- $app = new \Slim\Slim();
- $route1 = $app->get('/bar', function () {
- echo "Bar";
- });
- $route2 = $app->get('/foo', function () {
- echo "Foo";
- });
-
- $app->router()->getCurrentRoute();
-
- $app->call();
- }
+ $route2 = new \Slim\Route('/foo', function () {});
+ $route2 = $route2->via('POST');
- /**
- * Test get current route before routing returns null
- */
- public function testGetCurrentRouteBeforeRoutingReturnsNull()
- {
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo' //<-- Virtual
- ));
- $app = new \Slim\Slim();
- $route1 = $app->get('/bar', function () {
- echo "Bar";
- });
- $route2 = $app->get('/foo', function () {
- echo "Foo";
- });
-
- $this->assertSame(null, $app->router()->getCurrentRoute());
- }
+ $route3 = new \Slim\Route('/bar', function () {});
+ $route3 = $route3->via('PUT');
- /**
- * Test get current route during slim.before.dispatch hook
- */
- public function testGetCurrentRouteDuringBeforeDispatchHook()
- {
- $route = null;
-
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo' //<-- Virtual
- ));
- $app = new \Slim\Slim();
- $app->hook('slim.before.dispatch', function() use(&$route, $app) {
- $route = $app->router()->getCurrentRoute();
- });
- $route1 = $app->get('/bar', function () {
- echo "Bar";
- });
- $route2 = $app->get('/foo', function () {
- echo "Foo";
- });
-
- $app->call();
- $this->assertSame($route2, $route);
- }
+ $routes = new \ReflectionProperty($router, 'routes');
+ $routes->setAccessible(true);
+ $routes->setValue($router, array($route1, $route2, $route3));
- /**
- * Test get current route during routing
- */
- public function testGetCurrentRouteDuringRouting()
- {
- $route = null;
-
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo' //<-- Virtual
- ));
- $app = new \Slim\Slim();
- $route1 = $app->get('/bar', function () {
- echo "Bar";
- });
- $route2 = $app->get('/foo', function () use (&$route, $app) {
- echo "Foo";
- $route = $app->router()->getCurrentRoute();
- });
-
- $app->call();
- $this->assertSame($route2, $route);
+ $matchedRoutes = $router->getMatchedRoutes('GET', '/foo');
+ $this->assertSame($route1, $matchedRoutes[0]);
}
- /**
- * Test get current route after routing
- */
- public function testGetCurrentRouteAfterRouting()
- {
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo' //<-- Virtual
- ));
- $app = new \Slim\Slim();
- $route1 = $app->get('/bar', function () {
- echo "Bar";
- });
- $route2 = $app->get('/foo', function () {
- echo "Foo";
- });
- $app->call();
- $this->assertSame($route2, $app->router()->getCurrentRoute());
- }
+ // Test url for named route
- public function testDispatch()
+ public function testUrlFor()
{
- $this->expectOutputString('Hello josh');
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/hello/josh', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $env = \Slim\Environment::getInstance();
- $req = new \Slim\Http\Request($env);
$router = new \Slim\Router();
- $route = new \Slim\Route('/hello/:name', function ($name) { echo "Hello $name"; });
- $route->matches($req->getResourceUri()); //<-- Extracts params from resource URI
- $router->dispatch($route);
- }
+ $route1 = new \Slim\Route('/hello/:first/:last', function () {});
+ $route1 = $route1->via('GET')->name('hello');
- public function testDispatchWithMiddlware()
- {
- $this->expectOutputString('First! Second! Hello josh');
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/hello/josh', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $env = \Slim\Environment::getInstance();
- $req = new \Slim\Http\Request($env);
- $router = new \Slim\Router();
- $route = new \Slim\Route('/hello/:name', function ($name) { echo "Hello $name"; });
- $route->setMiddleware(function () {
- echo "First! ";
- });
- $route->setMiddleware(function () {
- echo "Second! ";
- });
- $route->matches($req->getResourceUri()); //<-- Extracts params from resource URI
- $router->dispatch($route);
- }
+ $routes = new \ReflectionProperty($router, 'namedRoutes');
+ $routes->setAccessible(true);
+ $routes->setValue($router, array('hello' => $route1));
- public function testRouteMiddlwareArguments()
- {
- $this->expectOutputString('foobar');
- \Slim\Environment::mock(array(
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/foo' //<-- Virtual
- ));
- $env = \Slim\Environment::getInstance();
- $req = new \Slim\Http\Request($env);
- $router = new \Slim\Router();
- $route = new \Slim\Route('/foo', function () { echo "bar"; });
- $route->setName('foo');
- $route->setMiddleware(function ($route) {
- echo $route->getName();
- });
- $route->matches($req->getResourceUri()); //<-- Extracts params from resource URI
- $router->dispatch($route);
+ $this->assertEquals('/hello/Josh/Lockhart', $router->urlFor('hello', array('first' => 'Josh', 'last' => 'Lockhart')));
}
- public function testDispatchWithoutCallable()
+ public function testUrlForIfNoSuchRoute()
{
- $this->setExpectedException('InvalidArgumentException');
- \Slim\Environment::mock(array(
- 'REQUEST_METHOD' => 'GET',
- 'REMOTE_ADDR' => '127.0.0.1',
- 'SCRIPT_NAME' => '', //<-- Physical
- 'PATH_INFO' => '/hello/josh', //<-- Virtual
- 'QUERY_STRING' => 'one=1&two=2&three=3',
- 'SERVER_NAME' => 'slim',
- 'SERVER_PORT' => 80,
- 'slim.url_scheme' => 'http',
- 'slim.input' => '',
- 'slim.errors' => fopen('php://stderr', 'w'),
- 'HTTP_HOST' => 'slim'
- ));
- $env = \Slim\Environment::getInstance();
- $req = new \Slim\Http\Request($env);
+ $this->setExpectedException('RuntimeException');
+
$router = new \Slim\Router();
- $route = new \Slim\Route('/hello/:name', 'foo'); // <-- Fail fast
+ $router->urlFor('foo', array('abc' => '123'));
}
}
diff --git a/tests/SlimTest.php b/tests/SlimTest.php
index a1aa3ad76..638da7c84 100644
--- a/tests/SlimTest.php
+++ b/tests/SlimTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -371,6 +371,27 @@ public function testPutRoute()
$this->assertSame($callable, $route->getCallable());
}
+ /**
+ * Test PATCH route
+ */
+ public function testPatchRoute()
+ {
+ \Slim\Environment::mock(array(
+ 'REQUEST_METHOD' => 'PATCH',
+ 'SCRIPT_NAME' => '/foo', //<-- Physical
+ 'PATH_INFO' => '/bar', //<-- Virtual
+ ));
+ $s = new \Slim\Slim();
+ $mw1 = function () { echo "foo"; };
+ $mw2 = function () { echo "bar"; };
+ $callable = function () { echo "xyz"; };
+ $route = $s->patch('/bar', $mw1, $mw2, $callable);
+ $s->call();
+ $this->assertEquals('foobarxyz', $s->response()->body());
+ $this->assertEquals('/bar', $route->getPattern());
+ $this->assertSame($callable, $route->getCallable());
+ }
+
/**
* Test DELETE route
*/
@@ -413,6 +434,51 @@ public function testOptionsRoute()
$this->assertSame($callable, $route->getCallable());
}
+ /**
+ * Test route groups
+ */
+ public function testRouteGroups()
+ {
+ \Slim\Environment::mock(array(
+ 'REQUEST_METHOD' => 'GET',
+ 'SCRIPT_NAME' => '/foo', //<-- Physical
+ 'PATH_INFO' => '/bar/baz', //<-- Virtual'
+ ));
+ $s = new \Slim\Slim();
+ $mw1 = function () { echo "foo"; };
+ $mw2 = function () { echo "bar"; };
+ $callable = function () { echo "xyz"; };
+ $s->group('/bar', $mw1, function () use ($s, $mw2, $callable) {
+ $s->get('/baz', $mw2, $callable);
+ });
+ $s->call();
+ $this->assertEquals('foobarxyz', $s->response()->body());
+ }
+
+ /*
+ * Test ANY route
+ */
+ public function testAnyRoute()
+ {
+ $mw1 = function () { echo "foo"; };
+ $mw2 = function () { echo "bar"; };
+ $callable = function () { echo "xyz"; };
+ $methods = array('GET', 'POST', 'PUT', 'DELETE', 'OPTIONS');
+ foreach ($methods as $i => $method) {
+ \Slim\Environment::mock(array(
+ 'REQUEST_METHOD' => $method,
+ 'SCRIPT_NAME' => '/foo', //<-- Physical
+ 'PATH_INFO' => '/bar', //<-- Virtual
+ ));
+ $s = new \Slim\Slim();
+ $route = $s->any('/bar', $mw1, $mw2, $callable);
+ $s->call();
+ $this->assertEquals('foobarxyz', $s->response()->body());
+ $this->assertEquals('/bar', $route->getPattern());
+ $this->assertSame($callable, $route->getCallable());
+ }
+ }
+
/**
* Test if route does NOT expect trailing slash and URL has one
*/
@@ -545,7 +611,7 @@ public function testLastModifiedMatch()
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
- 'IF_MODIFIED_SINCE' => 'Sun, 03 Oct 2010 17:00:52 -0400',
+ 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 03 Oct 2010 17:00:52 -0400',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
@@ -595,7 +661,7 @@ public function testEtagMatches()
\Slim\Environment::mock(array(
'SCRIPT_NAME' => '/foo', //<-- Physical
'PATH_INFO' => '/bar', //<-- Virtual
- 'IF_NONE_MATCH' => '"abc123"',
+ 'HTTP_IF_NONE_MATCH' => '"abc123"',
));
$s = new \Slim\Slim();
$s->get('/bar', function () use ($s) {
@@ -706,11 +772,11 @@ public function testSetCookie()
$s->setCookie('foo1', 'bar1', '2 days');
});
$s->call();
- list($status, $header, $body) = $s->response()->finalize();
- $cookies = explode("\n", $header['Set-Cookie']);
- $this->assertEquals(2, count($cookies));
- $this->assertEquals(1, preg_match('@foo=bar@', $cookies[0]));
- $this->assertEquals(1, preg_match('@foo1=bar1@', $cookies[1]));
+ $cookie1 = $s->response->cookies->get('foo');
+ $cookie2 = $s->response->cookies->get('foo1');
+ $this->assertEquals(2, count($s->response->cookies));
+ $this->assertEquals('bar', $cookie1['value']);
+ $this->assertEquals('bar1', $cookie2['value']);
}
/**
@@ -730,7 +796,7 @@ public function testGetCookie()
'QUERY_STRING' => 'one=foo&two=bar',
'SERVER_NAME' => 'slimframework.com',
'SERVER_PORT' => 80,
- 'COOKIE' => 'foo=bar; foo2=bar2',
+ 'HTTP_COOKIE' => 'foo=bar; foo2=bar2',
'slim.url_scheme' => 'http',
'slim.input' => '',
'slim.errors' => @fopen('php://stderr', 'w')
@@ -773,60 +839,10 @@ public function testDeleteCookie()
$s->deleteCookie('foo');
});
$s->call();
- list($status, $header, $body) = $s->response()->finalize();
- $cookies = explode("\n", $header['Set-Cookie']);
- $this->assertEquals(1, count($cookies));
- $this->assertEquals(1, preg_match('@^foo=;@', $cookies[0]));
- }
-
- /**
- * Test set encrypted cookie
- *
- * This method ensures that the `Set-Cookie:` HTTP request
- * header is set. The implementation is tested in a separate file.
- */
- public function testSetEncryptedCookie()
- {
- $s = new \Slim\Slim();
- $s->setEncryptedCookie('foo', 'bar');
- $r = $s->response();
- $this->assertEquals(1, preg_match("@^foo=.+%7C.+%7C.+@", $r['Set-Cookie'])); //<-- %7C is a url-encoded pipe
- }
-
- /**
- * Test get encrypted cookie
- *
- * This only tests that this method runs without error. The implementation of
- * fetching the encrypted cookie is tested separately.
- */
- public function testGetEncryptedCookieAndDeletingIt()
- {
- \Slim\Environment::mock(array(
- 'SCRIPT_NAME' => '/foo', //<-- Physical
- 'PATH_INFO' => '/bar', //<-- Virtual
- ));
- $s = new \Slim\Slim();
- $r = $s->response();
- $this->assertFalse($s->getEncryptedCookie('foo'));
- $this->assertEquals(1, preg_match("@foo=;.*@", $r['Set-Cookie']));
- }
-
- /**
- * Test get encrypted cookie WITHOUT deleting it
- *
- * This only tests that this method runs without error. The implementation of
- * fetching the encrypted cookie is tested separately.
- */
- public function testGetEncryptedCookieWithoutDeletingIt()
- {
- \Slim\Environment::mock(array(
- 'SCRIPT_NAME' => '/foo', //<-- Physical
- 'PATH_INFO' => '/bar', //<-- Virtual
- ));
- $s = new \Slim\Slim();
- $r = $s->response();
- $this->assertFalse($s->getEncryptedCookie('foo', false));
- $this->assertEquals(0, preg_match("@foo=;.*@", $r['Set-Cookie']));
+ $cookie = $s->response->cookies->get('foo');
+ $this->assertEquals(1, count($s->response->cookies));
+ $this->assertEquals('', $cookie['value']);
+ $this->assertLessThan(time(), $cookie['expires']);
}
/************************************************
@@ -1215,13 +1231,13 @@ public function testSlimError()
public function testDefaultHandlerLogsTheErrorWhenDebugIsFalse()
{
$s = new \Slim\Slim(array('debug' => false));
+ $s->container->singleton('log', function ($c) {
+ return new EchoErrorLogger();
+ });
$s->get('/bar', function () use ($s) {
throw new \InvalidArgumentException('my specific error message');
});
- $env = $s->environment();
- $env['slim.log'] = new EchoErrorLogger(); // <-- inject the fake logger
-
ob_start();
$s->run();
$output = ob_get_clean();
@@ -1323,22 +1339,20 @@ public function testHandleErrors()
{
$defaultErrorReporting = error_reporting();
- // Assert Slim ignores E_NOTICE errors
+ // Test 1
error_reporting(E_ALL ^ E_NOTICE); // <-- Report all errors EXCEPT notices
try {
- $this->assertTrue(\Slim\Slim::handleErrors(E_NOTICE, 'test error', 'Slim.php', 119));
+ \Slim\Slim::handleErrors(E_NOTICE, 'test error', 'Slim.php', 119);
} catch (\ErrorException $e) {
$this->fail('Slim::handleErrors reported a disabled error level.');
}
- // Assert Slim reports E_STRICT errors
+ // Test 2
error_reporting(E_ALL | E_STRICT); // <-- Report all errors, including E_STRICT
try {
\Slim\Slim::handleErrors(E_STRICT, 'test error', 'Slim.php', 119);
$this->fail('Slim::handleErrors didn\'t report a enabled error level');
- } catch (\ErrorException $e) {
- $this->assertEquals('test error', $e->getMessage());
- }
+ } catch (\ErrorException $e) {}
error_reporting($defaultErrorReporting);
}
diff --git a/tests/ViewTest.php b/tests/ViewTest.php
index d7f501cef..2f1b1e9e3 100644
--- a/tests/ViewTest.php
+++ b/tests/ViewTest.php
@@ -6,7 +6,7 @@
* @copyright 2011 Josh Lockhart
* @link http://www.slimframework.com
* @license http://www.slimframework.com/license
- * @version 2.2.0
+ * @version 2.3.0
*
* MIT LICENSE
*
@@ -32,164 +32,137 @@
class ViewTest extends PHPUnit_Framework_TestCase
{
- public function setUp()
+ public function testGetDataAll()
{
- $this->view = new \Slim\View();
+ $view = new \Slim\View();
+ $prop = new \ReflectionProperty($view, 'data');
+ $prop->setAccessible(true);
+ $prop->setValue($view, new \Slim\Helper\Set(array('foo' => 'bar')));
+
+ $this->assertSame(array('foo' => 'bar'), $view->getData());
}
- public function generateTestData()
+ public function testGetDataKeyExists()
{
- return array('a' => 1, 'b' => 2, 'c' => 3);
+ $view = new \Slim\View();
+ $prop = new \ReflectionProperty($view, 'data');
+ $prop->setAccessible(true);
+ $prop->setValue($view, new \Slim\Helper\Set(array('foo' => 'bar')));
+
+ $this->assertEquals('bar', $view->getData('foo'));
}
- /**
- * Test initial View data is an empty array
- *
- * Pre-conditions:
- * None
- *
- * Post-conditions:
- * The View object's data attribute is an empty array
- */
- public function testViewIsConstructedWithDataArray()
+ public function testGetDataKeyNotExists()
{
- $this->assertEquals(array(), $this->view->getData());
+ $view = new \Slim\View();
+ $prop = new \ReflectionProperty($view, 'data');
+ $prop->setAccessible(true);
+ $prop->setValue($view, new \Slim\Helper\Set(array('foo' => 'bar')));
+
+ $this->assertNull($view->getData('abc'));
}
- /**
- * Test View sets and gets data
- *
- * Pre-conditions:
- * Case A: Set view data key/value
- * Case B: Set view data as array
- * Case C: Set view data with one argument that is not an array
- *
- * Post-conditions:
- * Case A: Data key/value are set
- * Case B: Data is set to array
- * Case C: An InvalidArgumentException is thrown
- */
- public function testViewSetAndGetData()
+ public function testSetDataKeyValue()
{
- //Case A
- $this->view->setData('one', 1);
- $this->assertEquals(1, $this->view->getData('one'));
-
- //Case B
- $data = array('foo' => 'bar', 'a' => 'A');
- $this->view->setData($data);
- $this->assertSame($data, $this->view->getData());
-
- //Case C
- try {
- $this->view->setData('foo');
- $this->fail('Setting View data with non-array single argument did not throw exception');
- } catch ( \InvalidArgumentException $e ) {}
+ $view = new \Slim\View();
+ $prop = new \ReflectionProperty($view, 'data');
+ $prop->setAccessible(true);
+ $view->setData('foo', 'bar');
+
+ $this->assertEquals(array('foo' => 'bar'), $prop->getValue($view)->all());
}
- /**
- * Test View appends data
- *
- * Pre-conditions:
- * Case A: Append data to View several times
- * Case B: Append view data which is not an array
- *
- * Post-conditions:
- * Case A: The View data contains all appended data
- * Case B: An InvalidArgumentException is thrown
- */
- public function testViewAppendsData()
+ public function testSetDataArray()
{
- //Case A
- $this->view->appendData(array('a' => 'A'));
- $this->view->appendData(array('b' => 'B'));
- $this->assertEquals(array('a' => 'A', 'b' => 'B'), $this->view->getData());
+ $view = new \Slim\View();
+ $prop = new \ReflectionProperty($view, 'data');
+ $prop->setAccessible(true);
+ $view->setData(array('foo' => 'bar'));
+
+ $this->assertEquals(array('foo' => 'bar'), $prop->getValue($view)->all());
+ }
+
+ public function testSetDataInvalidArgument()
+ {
+ $this->setExpectedException('InvalidArgumentException');
+
+ $view = new \Slim\View();
+ $view->setData('foo');
+ }
+
+ public function testAppendData()
+ {
+ $view = new \Slim\View();
+ $prop = new \ReflectionProperty($view, 'data');
+ $prop->setAccessible(true);
+ $view->appendData(array('foo' => 'bar'));
+
+ $this->assertEquals(array('foo' => 'bar'), $prop->getValue($view)->all());
+ }
- //Case B
- try {
- $this->view->appendData('not an array');
- $this->fail('Appending View data with non-array argument did not throw exception');
- } catch ( \InvalidArgumentException $e ) {}
+ public function testAppendDataOverwrite()
+ {
+ $view = new \Slim\View();
+ $prop = new \ReflectionProperty($view, 'data');
+ $prop->setAccessible(true);
+ $prop->setValue($view, new \Slim\Helper\Set(array('foo' => 'bar')));
+ $view->appendData(array('foo' => '123'));
+ $this->assertEquals(array('foo' => '123'), $prop->getValue($view)->all());
}
- /**
- * Test View templates directory
- *
- * Pre-conditions:
- * View templates directory is set to an existing directory
- *
- * Post-conditions:
- * The templates directory is set correctly.
- */
- public function testSetsTemplatesDirectory()
+ public function testAppendDataInvalidArgument()
{
- $templatesDirectory = dirname(__FILE__) . '/templates';
- $this->view->setTemplatesDirectory($templatesDirectory);
- $this->assertEquals($templatesDirectory, $this->view->getTemplatesDirectory());
+ $this->setExpectedException('InvalidArgumentException');
+
+ $view = new \Slim\View();
+ $view->appendData('foo');
}
- /**
- * Test View templates directory may have a trailing slash when set
- *
- * Pre-conditions:
- * View templates directory is set to an existing directory with a trailing slash
- *
- * Post-conditions:
- * The View templates directory is set correctly without a trailing slash
- */
- public function testTemplatesDirectoryWithTrailingSlash()
+ public function testGetTemplatesDirectory()
{
- $this->view->setTemplatesDirectory(dirname(__FILE__) . '/templates/');
- $this->assertEquals(dirname(__FILE__) . '/templates', $this->view->getTemplatesDirectory());
+ $view = new \Slim\View();
+ $property = new \ReflectionProperty($view, 'templatesDirectory');
+ $property->setAccessible(true);
+ $property->setValue($view, 'templates');
+
+ $this->assertEquals('templates', $view->getTemplatesDirectory());
}
- /**
- * Test View renders template
- *
- * Pre-conditions:
- * View templates directory is set to an existing directory.
- * View data is set without errors
- * Case A: View renders an existing template
- * Case B: View renders a non-existing template
- *
- * Post-conditions:
- * Case A: The rendered template is returned as a string
- * Case B: A RuntimeException is thrown
- */
- public function testRendersTemplateWithData()
+ public function testSetTemplatesDirectory()
{
- $this->view->setTemplatesDirectory(dirname(__FILE__) . '/templates');
- $this->view->setData(array('foo' => 'bar'));
-
- //Case A
- $output = $this->view->render('test.php');
- $this->assertEquals('test output bar', $output);
-
- //Case B
- try {
- $output = $this->view->render('foo.php');
- $this->fail('Rendering non-existent template did not throw exception');
- } catch ( \RuntimeException $e ) {}
+ $view = new \Slim\View();
+ $view->setTemplatesDirectory('templates/'); // <-- Should strip trailing slash
+
+ $this->assertAttributeEquals('templates', 'templatesDirectory', $view);
}
- /**
- * Test View displays template
- *
- * Pre-conditions:
- * View templates directory is set to an existing directory.
- * View data is set without errors
- * View is displayed
- *
- * Post-conditions:
- * The output buffer contains the rendered template
- */
- public function testDisplaysTemplateWithData()
+ public function testDisplay()
{
$this->expectOutputString('test output bar');
- $this->view->setTemplatesDirectory(dirname(__FILE__) . '/templates');
- $this->view->setData(array('foo' => 'bar'));
- $this->view->display('test.php');
+
+ $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');
+
+ $view->display('test.php');
}
+ public function testDisplayTemplateThatDoesNotExist()
+ {
+ $this->setExpectedException('\RuntimeException');
+
+ $view = new \Slim\View();
+
+ $prop2 = new \ReflectionProperty($view, 'templatesDirectory');
+ $prop2->setAccessible(true);
+ $prop2->setValue($view, dirname(__FILE__) . '/templates');
+
+ $view->display('foo.php');
+ }
}