Commit 7bf84066 authored by Taylor Otwell's avatar Taylor Otwell

refactoring. added redis drivers.

parent 8595253a
...@@ -131,7 +131,6 @@ return array( ...@@ -131,7 +131,6 @@ return array(
*/ */
'aliases' => array( 'aliases' => array(
'Arr' => 'Laravel\\Arr',
'Asset' => 'Laravel\\Asset', 'Asset' => 'Laravel\\Asset',
'Auth' => 'Laravel\\Security\\Auth', 'Auth' => 'Laravel\\Security\\Auth',
'Benchmark' => 'Laravel\\Benchmark', 'Benchmark' => 'Laravel\\Benchmark',
...@@ -150,12 +149,9 @@ return array( ...@@ -150,12 +149,9 @@ return array(
'Input' => 'Laravel\\Input', 'Input' => 'Laravel\\Input',
'IoC' => 'Laravel\\IoC', 'IoC' => 'Laravel\\IoC',
'Lang' => 'Laravel\\Lang', 'Lang' => 'Laravel\\Lang',
'Loader' => 'Laravel\\Loader',
'Messages' => 'Laravel\\Validation\\Messages',
'Package' => 'Laravel\\Facades\\Package',
'URI' => 'Laravel\\URI',
'URL' => 'Laravel\\URL', 'URL' => 'Laravel\\URL',
'Redirect' => 'Laravel\\Redirect', 'Redirect' => 'Laravel\\Redirect',
'Redis' => 'Laravel\\Redis',
'Request' => 'Laravel\\Request', 'Request' => 'Laravel\\Request',
'Response' => 'Laravel\\Response', 'Response' => 'Laravel\\Response',
'Session' => 'Laravel\\Session\\Manager', 'Session' => 'Laravel\\Session\\Manager',
......
...@@ -12,7 +12,7 @@ return array( ...@@ -12,7 +12,7 @@ return array(
| Caching can be used to increase the performance of your application | Caching can be used to increase the performance of your application
| by storing commonly accessed data in memory or in a file. | by storing commonly accessed data in memory or in a file.
| |
| Supported Drivers: 'file', 'memcached', 'apc'. | Supported Drivers: 'file', 'memcached', 'apc', 'redis'.
| |
*/ */
......
...@@ -70,4 +70,25 @@ return array( ...@@ -70,4 +70,25 @@ return array(
), ),
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store. However, it
| provides a richer set of commands than a typical key-value store such as
| APC or memcached.
|
| Here you may specify the hosts and ports for your Redis databases.
|
| For more information regarding Redis, check out: http://redis.io
|
*/
'redis' => array(
'default' => array('host' => '127.0.0.1', 'port' => 6379),
),
); );
\ No newline at end of file
...@@ -12,7 +12,7 @@ return array( ...@@ -12,7 +12,7 @@ return array(
| Since HTTP is stateless, sessions are used to maintain "state" across | Since HTTP is stateless, sessions are used to maintain "state" across
| multiple requests from the same user of your application. | multiple requests from the same user of your application.
| |
| Supported Drivers: 'cookie', 'file', 'database', 'memcached', 'apc'. | Supported Drivers: 'cookie', 'file', 'database', 'memcached', 'apc', 'redis'.
| |
*/ */
......
...@@ -5,7 +5,7 @@ define('CRLF', chr(13).chr(10)); ...@@ -5,7 +5,7 @@ define('CRLF', chr(13).chr(10));
define('EXT', '.php'); define('EXT', '.php');
/** /**
* Define a function that registers an array of constants if they * Define a function that registers an array of constants if they haven't
* haven't already been registered. This allows the constants to * haven't already been registered. This allows the constants to
* be changed from their default values when unit testing. * be changed from their default values when unit testing.
*/ */
......
...@@ -101,7 +101,6 @@ register_shutdown_function(function() use ($handler) ...@@ -101,7 +101,6 @@ register_shutdown_function(function() use ($handler)
{ {
if ( ! is_null($error = error_get_last())) if ( ! is_null($error = error_get_last()))
{ {
die('here');
extract($error, EXTR_SKIP); extract($error, EXTR_SKIP);
$handler(new \ErrorException($message, $type, 0, $file, $line)); $handler(new \ErrorException($message, $type, 0, $file, $line));
......
...@@ -68,7 +68,9 @@ class File extends Driver { ...@@ -68,7 +68,9 @@ class File extends Driver {
*/ */
public function put($key, $value, $minutes) public function put($key, $value, $minutes)
{ {
file_put_contents($this->path.$key, (time() + ($minutes * 60)).serialize($value), LOCK_EX); $value = (time() + ($minutes * 60)).serialize($value);
file_put_contents($this->path.$key, $value, LOCK_EX);
} }
/** /**
......
<?php namespace Laravel\Cache\Drivers;
class Redis extends Driver {
/**
* The Redis database instance.
*
* @var Redis
*/
protected $redis;
/**
* Create a new Redis cache driver instance.
*
* @param Redis $redis
* @return void
*/
public function __construct(\Laravel\Redis $redis)
{
$this->redis = $redis;
}
/**
* Determine if an item exists in the cache.
*
* @param string $key
* @return bool
*/
public function has($key)
{
return ( ! is_null($this->redis->get($key)));
}
/**
* Retrieve an item from the cache driver.
*
* @param string $key
* @return mixed
*/
protected function retrieve($key)
{
if ( ! is_null($cache = $this->redis->get($key)))
{
return unserialize($cache);
}
}
/**
* Write an item to the cache for a given number of minutes.
*
* <code>
* // Put an item in the cache for 15 minutes
* Cache::put('name', 'Taylor', 15);
* </code>
*
* @param string $key
* @param mixed $value
* @param int $minutes
* @return void
*/
public function put($key, $value, $minutes)
{
$this->redis->set($key, serialize($value));
$this->redis->expire($key, $minutes * 60);
}
/**
* Delete an item from the cache.
*
* @param string $key
* @return void
*/
public function forget($key)
{
$this->redis->del($key);
}
}
\ No newline at end of file
...@@ -71,11 +71,9 @@ return array( ...@@ -71,11 +71,9 @@ return array(
| Laravel Caching Components | Laravel Caching Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The following components are used by the wonderfully, simple Laravel | The following components are used by the wonderfully simple Laravel cache
| caching system. Each driver is resolved through the container. | system. Each driver is resolved through the container, so new drivers may
| | be added by simply registering them in the container.
| New cache drivers may be added to the framework by simply registering
| them into the container.
| |
*/ */
...@@ -91,6 +89,12 @@ return array( ...@@ -91,6 +89,12 @@ return array(
}), }),
'laravel.cache.redis' => array('resolver' => function()
{
return new Cache\Drivers\Redis(Redis::db());
}),
'laravel.cache.memcached' => array('resolver' => function($c) 'laravel.cache.memcached' => array('resolver' => function($c)
{ {
return new Cache\Drivers\Memcached($c->core('cache.memcache.connection'), Config::get('cache.key')); return new Cache\Drivers\Memcached($c->core('cache.memcache.connection'), Config::get('cache.key'));
...@@ -130,10 +134,6 @@ return array( ...@@ -130,10 +134,6 @@ return array(
| from the session driver, as well as examining the payload validitiy | from the session driver, as well as examining the payload validitiy
| and things like the CSRF token. | and things like the CSRF token.
| |
| Like the caching components, each session driver is resolved via the
| container and new drivers may be added by registering them into the
| container. Several session drivers are "driven" by the cache drivers.
|
*/ */
'laravel.session.transporter' => array('resolver' => function($c) 'laravel.session.transporter' => array('resolver' => function($c)
...@@ -166,6 +166,12 @@ return array( ...@@ -166,6 +166,12 @@ return array(
}), }),
'laravel.session.redis' => array('resolver' => function($c)
{
return new Session\Drivers\Redis($c->core('cache.redis'));
}),
'laravel.session.memcached' => array('resolver' => function($c) 'laravel.session.memcached' => array('resolver' => function($c)
{ {
return new Session\Drivers\Memcached($c->core('cache.memcached')); return new Session\Drivers\Memcached($c->core('cache.memcached'));
......
...@@ -17,8 +17,6 @@ class Manager { ...@@ -17,8 +17,6 @@ class Manager {
* *
* If no database name is specified, the default connection will be returned. * If no database name is specified, the default connection will be returned.
* *
* Note: Database connections are managed as singletons.
*
* <code> * <code>
* // Get the default database connection for the application * // Get the default database connection for the application
* $connection = DB::connection(); * $connection = DB::connection();
......
...@@ -611,7 +611,9 @@ class Query { ...@@ -611,7 +611,9 @@ class Query {
*/ */
protected function adjust($column, $amount, $operator) protected function adjust($column, $amount, $operator)
{ {
return $this->update(array($column => Manager::raw($this->grammar->wrap($column).$operator.$amount))); $value = Manager::raw($this->grammar->wrap($column).$operator.$amount);
return $this->update(array($column => $value));
} }
/** /**
......
...@@ -91,9 +91,9 @@ Input::$input = $input; ...@@ -91,9 +91,9 @@ Input::$input = $input;
*/ */
Routing\Filter::register(require APP_PATH.'filters'.EXT); Routing\Filter::register(require APP_PATH.'filters'.EXT);
list($uri, $method) = array(Request::uri()->get(), Request::method()); list($uri, $method, $format) = array(Request::uri()->get(), Request::method(), Request::format());
$route = IoC::container()->core('routing.router')->route($method, $uri); $route = IoC::container()->core('routing.router')->route($method, $uri, $format);
if ( ! is_null($route)) if ( ! is_null($route))
{ {
......
...@@ -3,114 +3,162 @@ ...@@ -3,114 +3,162 @@
class Redis { class Redis {
/** /**
* The name of the Redis connection. * The address for the Redis host.
* *
* @var string * @var string
*/ */
public $name; protected $host;
/** /**
* The configuration array for the Redis connection. * The port on which Redis can be accessed on the host.
* *
* @var array * @var int
*/ */
public $config = array(); protected $port;
/** /**
* The connection to the Redis database. * The connection to the Redis database.
* *
* @var resource * @var resource
*/ */
protected static $connection; protected $connection;
/** /**
* Create a new Redis connection instance. * The active Redis database instances.
* *
* @param string $name * @var array
* @param array $config
* @return void
*/ */
public function __construct($name, $config) protected static $databases = array();
{
$this->name = $name;
$this->config = $config;
}
/** /**
* Create a new Redis connection instance. * Create a new Redis connection instance.
* *
* @param string $connection * @param string $host
* @param array $config * @param string $port
* @return Redis * @return void
*/ */
public static function make($name, $config) public function __construct($host, $port)
{ {
return new static($name, $config); $this->host = $host;
$this->port = $port;
} }
/** /**
* Create a new Redis connection instance. * Get a Redis database connection instance.
* *
* The Redis connection is managed as a singleton, so if the connection has * The given name should correspond to a Redis database in the configuration file.
* already been established, that same connection instance will be returned
* on subsequent requests for the connection.
* *
* @param string $connection * <code>
* // Get the default Redis database instance
* $redis = Redis::db();
*
* // Get a specified Redis database instance
* $reids = Redis::db('redis_2');
* </code>
*
* @param string $name
* @return Redis * @return Redis
*/ */
public static function connection() public static function db($name = 'default')
{ {
if (is_null(static::$connection)) if (is_null(static::$databases[$name]))
{ {
static::$connection = static::make($name, Config::get('database.redis'))->connect(); if (is_null($config = Config::get("database.redis.{$name}")))
{
throw new \Exception("Redis database [$name] is not defined.");
}
static::$databases[$name] = new static($config['host'], $config['port']);
} }
return static::$connection; return static::$databases[$name];
} }
/** /**
* Connect to the Redis database. * Execute a command against the Redis database.
* *
* The Redis instance itself will be returned by the method. * <code>
* // Execute the GET command for the "name" key
* $name = Redis::db()->run('get', array('name'));
* *
* @return Redis * // Execute the LRANGE command for the "list" key
* $list = Redis::db()->run('lrange', array(0, 5));
* </code>
*
* @param string $method
* @param array $parameters
* @return mixed
*/ */
public function connect() public function run($method, $parameters)
{ {
static::$connection = @fsockopen($this->config['host'], $this->config['port'], $error, $message); fwrite($this->connect(), $this->command($method, (array) $parameters));
$ersponse = trim(fgets($this->connection, 512));
if (static::$connection === false) switch (substr($ersponse, 0, 1))
{ {
throw new \Exception("Error establishing Redis connection [{$this->name}]: {$error} - {$message}"); case '-':
throw new \Exception('Redis error: '.substr(trim($ersponse), 4));
case '+':
case ':':
return $this->inline($ersponse);
case '$':
return $this->bulk($ersponse);
case '*':
return $this->multibulk($ersponse);
default:
throw new \Exception("Unknown response from Redis server: ".substr($ersponse, 0, 1));
} }
return $this;
} }
/** /**
* Execute a command agaisnt the Redis database. * Establish the connection to the Redis database.
* *
* @param string $method * @return resource
* @param array $parameters
* @return mixed
*/ */
public function run($method, $parameters) protected function connect()
{ {
fwrite(static::$connection, $this->command($method, $parameters)); if ( ! is_null($this->connection)) return $this->connection;
$this->connection = @fsockopen($this->host, $this->port, $error, $message);
if ($this->connection === false)
{
throw new \Exception("Error making Redis connection: {$error} - {$message}");
}
$reply = trim(fgets(static::$connection, 512)); return $this->connection;
} }
/** /**
* Build the Redis command based from a given method and parameters. * Build the Redis command based from a given method and parameters.
* *
* Redis protocol states that a command should conform to the following format:
*
* *<number of arguments> CR LF
* $<number of bytes of argument 1> CR LF
* <argument data> CR LF
* ...
* $<number of bytes of argument N> CR LF
* <argument data> CR LF
*
* More information regarding the Redis protocol: http://redis.io/topics/protocol
*
* @param string $method * @param string $method
* @param array $parameters * @param array $parameters
* @return string * @return string
*/ */
protected function command($method, $parameters) protected function command($method, $parameters)
{ {
$command = '*'.(count($parameters) + 1).CRLF.'$'.strlen($method).CRLF.strtoupper($method).CRLF; $command = '*'.(count($parameters) + 1).CRLF;
$command .= '$'.strlen($method).CRLF;
$command .= strtoupper($method).CRLF;
foreach ($parameters as $parameter) foreach ($parameters as $parameter)
{ {
...@@ -120,6 +168,73 @@ class Redis { ...@@ -120,6 +168,73 @@ class Redis {
return $command; return $command;
} }
/**
* Parse and handle an inline response from the Redis database.
*
* @param string $response
* @return string
*/
protected function inline($response)
{
return substr(trim($response), 1);
}
/**
* Parse and handle a bulk response from the Redis database.
*
* @param string $head
* @return string
*/
protected function bulk($head)
{
if ($head == '$-1') return;
list($read, $response, $size) = array(0, '', substr($head, 1));
do
{
// Calculate and read the appropriate bytes off of the Redis response.
// We'll read off the response in 1024 byte chunks until the entire
// response has been read from the database.
$block = (($remaining = $size - $read) < 1024) ? $remaining : 1024;
$response .= fread($this->connection, $block);
$read += $block;
} while ($read < $size);
// The response ends with a trailing CRLF. So, we need to read that off
// of the end of the file stream to get it out of the way of the next
// command that is issued to the database.
fread($this->connection, 2);
return $response;
}
/**
* Parse and handle a multi-bulk reply from the Redis database.
*
* @param string $head
* @return array
*/
protected function multibulk($head)
{
if (($count = substr($head, 1)) == '-1') return;
$response = array();
// Iterate through each bulk response in the multi-bulk and parse it out
// using the "bulk" method since a multi-bulk response is just a list of
// plain old bulk responses.
for ($i = 0; $i < $count; $i++)
{
$response[] = $this->bulk(trim(fgets($this->connection, 512)));
}
return $response;
}
/** /**
* Dynamically make calls to the Redis database. * Dynamically make calls to the Redis database.
*/ */
...@@ -128,6 +243,14 @@ class Redis { ...@@ -128,6 +243,14 @@ class Redis {
return $this->run($method, $parameters); return $this->run($method, $parameters);
} }
/**
* Dynamically pass static method calls to the Redis instance.
*/
public static function __callStatic($method, $parameters)
{
return static::db()->run($method, $parameters);
}
/** /**
* Close the connection to the Redis database. * Close the connection to the Redis database.
* *
...@@ -135,7 +258,7 @@ class Redis { ...@@ -135,7 +258,7 @@ class Redis {
*/ */
public function __destruct() public function __destruct()
{ {
fclose(static::$connection); fclose($this->connection);
} }
} }
\ No newline at end of file
...@@ -150,15 +150,15 @@ class Route { ...@@ -150,15 +150,15 @@ class Route {
{ {
return call_user_func_array($this->callback, $this->parameters); return call_user_func_array($this->callback, $this->parameters);
} }
// If the route is an array we will return the first value with a // If the route is an array, we will return the first value with a
// key of "delegate", or the first instance of a Closure. If the // key of "uses", or the first instance of a Closure. If the value
// value is a string, the route is delegating the responsibility // is a string, the route is delegating the responsibility for
// for handling the request to a controller. // for handling the request to a controller.
elseif (is_array($this->callback)) elseif (is_array($this->callback))
{ {
$callback = Arr::first($this->callback, function($key, $value) $callback = Arr::first($this->callback, function($key, $value)
{ {
return $key == 'delegate' or $value instanceof Closure; return $key == 'uses' or $value instanceof Closure;
}); });
if ($callback instanceof Closure) if ($callback instanceof Closure)
......
...@@ -51,8 +51,8 @@ class Router { ...@@ -51,8 +51,8 @@ class Router {
* @var array * @var array
*/ */
protected $patterns = array( protected $patterns = array(
'(:num)' => '[0-9]+', '(:num)' => '([0-9]+)',
'(:any)' => '[a-zA-Z0-9\.\-_]+', '(:any)' => '([a-zA-Z0-9\.\-_]+)',
); );
/** /**
...@@ -104,9 +104,10 @@ class Router { ...@@ -104,9 +104,10 @@ class Router {
* *
* @param string $method * @param string $method
* @param string $uri * @param string $uri
* @param string $format
* @return Route * @return Route
*/ */
public function route($method, $uri) public function route($method, $uri, $format)
{ {
$routes = $this->loader->load($uri); $routes = $this->loader->load($uri);
...@@ -122,19 +123,18 @@ class Router { ...@@ -122,19 +123,18 @@ class Router {
foreach ($routes as $keys => $callback) foreach ($routes as $keys => $callback)
{ {
// Formats are appended to the route key as a regular expression. // We need to make sure that the requested format is provided by the
// It will look something like: "(\.(json|xml|html))?" // route. If it isn't, there is no need to continue evaluating it.
$formats = $this->provides($callback); if ( ! in_array($format, $this->provides($callback))) continue;
// Only check routes that have multiple URIs or wildcards since other // Only check routes having multiple URIs or wildcards since other
// routes would have been caught by the check for literal matches. // routes would have been caught by the check for literal matches.
// We also need to check routes with "provides" clauses. if (strpos($keys, '(') !== false or strpos($keys, ',') !== false)
if ($this->fuzzy($keys) or ! is_null($formats))
{ {
if ( ! is_null($route = $this->match($destination, $keys, $callback, $formats))) if ( ! is_null($route = $this->match($destination, $keys, $callback, $format)))
{ {
return Request::$route = $route; return Request::$route = $route;
} }
} }
} }
...@@ -142,18 +142,19 @@ class Router { ...@@ -142,18 +142,19 @@ class Router {
} }
/** /**
* Determine if the route contains elements that forbid literal matches. * Get the request formats for which the route provides responses.
*
* Any route key containing a regular expression, wildcard, or multiple
* URIs cannot be matched using a literal string check, but must be
* checked using regular expressions.
* *
* @param string $keys * @param mixed $callback
* @return bool * @return array
*/ */
protected function fuzzy($keys) protected function provides($callback)
{ {
return strpos($keys, '(') !== false or strpos($keys, ',') !== false; if (is_array($callback) and isset($callback['provides']))
{
return (is_string($provides = $callback['provides'])) ? explode('|', $provides) : $provides;
}
return array();
} }
/** /**
...@@ -166,18 +167,19 @@ class Router { ...@@ -166,18 +167,19 @@ class Router {
* @param string $destination * @param string $destination
* @param array $keys * @param array $keys
* @param mixed $callback * @param mixed $callback
* @param array $formats * @param string $format
* @return mixed * @return mixed
*/ */
protected function match($destination, $keys, $callback, $formats) protected function match($destination, $keys, $callback, $format)
{ {
// Append the provided formats to the route as an optional regular expression. // We need to remove the format from the route since formats are
// This should make the route look something like: "user(\.(json|xml|html))?" // not specified in the route URI directly, but rather through
$formats = ( ! is_null($formats)) ? '(\.('.implode('|', $formats).'))?' : ''; // the "provides" keyword on the route array.
$destination = str_replace('.'.$format, '', $destination);
foreach (explode(', ', $keys) as $key) foreach (explode(', ', $keys) as $key)
{ {
if (preg_match('#^'.$this->wildcards($key).$formats.'$#', $destination)) if (preg_match('#^'.$this->wildcards($key).'$#', $destination))
{ {
return new Route($keys, $callback, $this->parameters($destination, $key)); return new Route($keys, $callback, $this->parameters($destination, $key));
} }
...@@ -241,20 +243,6 @@ class Router { ...@@ -241,20 +243,6 @@ class Router {
} }
} }
/**
* Get the request formats for which the route provides responses.
*
* @param mixed $callback
* @return array
*/
protected function provides($callback)
{
if (is_array($callback) and isset($callback['provides']))
{
return (is_string($provides = $callback['provides'])) ? explode('|', $provides) : $provides;
}
}
/** /**
* Translate route URI wildcards into actual regular expressions. * Translate route URI wildcards into actual regular expressions.
* *
...@@ -272,8 +260,6 @@ class Router { ...@@ -272,8 +260,6 @@ class Router {
$key .= ($replacements > 0) ? str_repeat(')?', $replacements) : ''; $key .= ($replacements > 0) ? str_repeat(')?', $replacements) : '';
// After replacing all of the optional wildcards, we can replace all
// of the "regular" wildcards and return the fully regexed string.
return str_replace(array_keys($this->patterns), array_values($this->patterns), $key); return str_replace(array_keys($this->patterns), array_values($this->patterns), $key);
} }
...@@ -288,6 +274,11 @@ class Router { ...@@ -288,6 +274,11 @@ class Router {
*/ */
protected function parameters($uri, $route) protected function parameters($uri, $route)
{ {
// When gathering the parameters, we need to get the request format out
// of the destination, otherwise it could be passed in as a parameter
// to the route closure or controller, which we don't want.
$uri = str_replace('.'.Request::format(), '', $uri);
list($uri, $route) = array(explode('/', $uri), explode('/', $route)); list($uri, $route) = array(explode('/', $uri), explode('/', $route));
$count = count($route); $count = count($route);
......
<?php namespace Laravel\Session\Drivers;
class Redis implements Driver {
/**
* The Redis cache driver instance.
*
* @var Cache\Drivers\Redis
*/
protected $redis;
/**
* Create a new Redis session driver.
*
* @param Cache\Drivers\Redis $redis
* @return void
*/
public function __construct(\Laravel\Cache\Drivers\Redis $redis)
{
$this->redis = $redis;
}
/**
* Load a session from storage by a given ID.
*
* If no session is found for the ID, null will be returned.
*
* @param string $id
* @return array
*/
public function load($id)
{
return $this->redis->get($id);
}
/**
* Save a given session to storage.
*
* @param array $session
* @param array $config
* @param bool $exists
* @return void
*/
public function save($session, $config, $exists)
{
$this->redis->put($session['id'], $session, $config['lifetime']);
}
/**
* Delete a session from storage by a given ID.
*
* @param string $id
* @return void
*/
public function delete($id)
{
$this->redis->forget($id);
}
}
\ No newline at end of file
...@@ -41,9 +41,7 @@ class URI { ...@@ -41,9 +41,7 @@ class URI {
{ {
if ( ! is_null($this->uri)) return $this->uri; if ( ! is_null($this->uri)) return $this->uri;
$uri = parse_url($this->server['REQUEST_URI'], PHP_URL_PATH); return $this->uri = $this->format($this->clean($this->parse($this->server['REQUEST_URI'])));
return $this->uri = $this->format($this->clean($uri));
} }
/** /**
...@@ -54,14 +52,24 @@ class URI { ...@@ -54,14 +52,24 @@ class URI {
*/ */
protected function clean($uri) protected function clean($uri)
{ {
$uri = $this->remove($uri, parse_url(Config::$items['application']['url'], PHP_URL_PATH)); $uri = $this->remove($uri, $this->parse(Config::$items['application']['url']));
if (($index = '/'.Config::$items['application']['index']) !== '/') if (($index = '/'.Config::$items['application']['index']) !== '/')
{ {
$uri = $this->remove($uri, $index); $uri = $this->remove($uri, $index);
} }
return rtrim($uri, '.'.Request::format($uri)); return $uri;
}
/**
* Parse a given string URI using PHP_URL_PATH to remove the domain.
*
* @return string
*/
protected function parse($uri)
{
return parse_url($uri, PHP_URL_PATH);
} }
/** /**
......
...@@ -37,10 +37,19 @@ class Messages { ...@@ -37,10 +37,19 @@ class Messages {
*/ */
public function add($key, $message) public function add($key, $message)
{ {
if ( ! isset($this->messages[$key]) or array_search($message, $this->messages[$key]) === false) if ($this->unique($key, $message)) $this->messages[$key][] = $message;
{ }
$this->messages[$key][] = $message;
} /**
* Determine if a key and message combination already exists.
*
* @param string $key
* @param string $message
* @return bool
*/
protected function unique($key, $message)
{
return ! isset($this->messages[$key]) or array_search($message, $this->messages[$key]) === false;
} }
/** /**
......
...@@ -188,7 +188,7 @@ class View { ...@@ -188,7 +188,7 @@ class View {
// use the regular path to the view. // use the regular path to the view.
$view = (strpos($this->path, BLADE_EXT) !== false) ? $this->compile() : $this->path; $view = (strpos($this->path, BLADE_EXT) !== false) ? $this->compile() : $this->path;
try { include $view; } catch (Exception $e) { ob_get_clean(); throw $e; } try { include $view; } catch (\Exception $e) { ob_get_clean(); throw $e; }
return ob_get_clean(); return ob_get_clean();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment