Commit 1e7850d9 authored by Taylor Otwell's avatar Taylor Otwell

refactoring for dependency injection and testability.

parent 0b86c945
...@@ -19,21 +19,23 @@ return array( ...@@ -19,21 +19,23 @@ return array(
*/ */
'Asset' => 'Laravel\\Asset', 'Asset' => 'Laravel\\Asset',
'Auth' => 'Laravel\\Auth', 'Auth' => 'Laravel\\Security\\Authenticator',
'Benchmark' => 'Laravel\\Benchmark', 'Benchmark' => 'Laravel\\Benchmark',
'Cache' => 'Laravel\\Cache', 'Cache' => 'Laravel\\Cache\\Manager',
'Config' => 'Laravel\\Config', 'Config' => 'Laravel\\Config',
'Cookie' => 'Laravel\\Cookie', 'Cookie' => 'Laravel\\Cookie',
'Crypter' => 'Laravel\\Crypter', 'Crypter' => 'Laravel\\Security\\Crypter',
'DB' => 'Laravel\\DB', 'DB' => 'Laravel\\Database\\Manager',
'Download' => 'Laravel\\Download', 'Download' => 'Laravel\\Download',
'Eloquent' => 'Laravel\\DB\\Eloquent\\Model', 'Eloquent' => 'Laravel\\Database\\Eloquent\\Model',
'Error' => 'Laravel\\Error',
'File' => 'Laravel\\File', 'File' => 'Laravel\\File',
'Form' => 'Laravel\\Form', 'Form' => 'Laravel\\Form',
'Hasher' => 'Laravel\\Hasher', 'Hasher' => 'Laravel\\Security\\Hasher',
'HTML' => 'Laravel\\HTML', 'HTML' => 'Laravel\\HTML',
'Inflector' => 'Laravel\\Inflector', 'Inflector' => 'Laravel\\Inflector',
'Input' => 'Laravel\\Input', 'Input' => 'Laravel\\Input',
'IoC' => 'Laravel\\IoC',
'Lang' => 'Laravel\\Lang', 'Lang' => 'Laravel\\Lang',
'Loader' => 'Laravel\\Loader', 'Loader' => 'Laravel\\Loader',
'Package' => 'Laravel\\Package', 'Package' => 'Laravel\\Package',
...@@ -41,9 +43,9 @@ return array( ...@@ -41,9 +43,9 @@ return array(
'Redirect' => 'Laravel\\Redirect', 'Redirect' => 'Laravel\\Redirect',
'Request' => 'Laravel\\Request', 'Request' => 'Laravel\\Request',
'Response' => 'Laravel\\Response', 'Response' => 'Laravel\\Response',
'Session' => 'Laravel\\Session', 'Session' => 'Laravel\\Session\\Manager',
'Str' => 'Laravel\\Str', 'Str' => 'Laravel\\Str',
'Validator' => 'Laravel\\Validator', 'Validator' => 'Laravel\\Validation\\Validator',
'View' => 'Laravel\\View', 'View' => 'Laravel\\View',
); );
\ No newline at end of file
...@@ -52,7 +52,9 @@ return array( ...@@ -52,7 +52,9 @@ return array(
'logger' => function($severity, $message, $trace) 'logger' => function($severity, $message, $trace)
{ {
File::append(STORAGE_PATH.'log.txt', date('Y-m-d H:i:s').' '.$severity.' - '.$message.PHP_EOL); $file = IoC::resolve('laravel.file');
$file->append(STORAGE_PATH.'log.txt', date('Y-m-d H:i:s').' '.$severity.' - '.$message.PHP_EOL);
}, },
); );
\ No newline at end of file
...@@ -42,13 +42,13 @@ return array( ...@@ -42,13 +42,13 @@ return array(
| |
*/ */
'before' => function($method, $uri) 'before' => function(Laravel\Request $request)
{ {
// Do stuff before every request to your application. // Do stuff before every request to your application.
}, },
'after' => function($response, $method, $uri) 'after' => function(Laravel\Request $request, Laravel\Response $response)
{ {
// Do stuff after every request to your application. // Do stuff after every request to your application.
}, },
...@@ -62,7 +62,7 @@ return array( ...@@ -62,7 +62,7 @@ return array(
'csrf' => function() 'csrf' => function()
{ {
return (Input::get('csrf_token') !== Form::raw_token()) ? Response::error('500') : null; return (Input::get('csrf_token') !== Form::raw_token()) ? new Error('500') : null;
}, },
); );
\ No newline at end of file
<?php namespace Laravel; <?php namespace Laravel;
use Laravel\File;
use Laravel\HTML;
class Asset { class Asset {
/** /**
...@@ -36,7 +33,7 @@ class Asset { ...@@ -36,7 +33,7 @@ class Asset {
{ {
if ( ! isset(static::$containers[$container])) if ( ! isset(static::$containers[$container]))
{ {
static::$containers[$container] = new Asset_Container($container); static::$containers[$container] = new Asset_Container($container, new File);
} }
return static::$containers[$container]; return static::$containers[$container];
...@@ -81,15 +78,24 @@ class Asset_Container { ...@@ -81,15 +78,24 @@ class Asset_Container {
*/ */
public $assets = array(); public $assets = array();
/**
* The file manager instance.
*
* @var File
*/
private $file;
/** /**
* Create a new asset container instance. * Create a new asset container instance.
* *
* @param string $name * @param string $name
* @param File $file
* @return void * @return void
*/ */
public function __construct($name) public function __construct($name, File $file)
{ {
$this->name = $name; $this->name = $name;
$this->file = $file;
} }
/** /**
...@@ -119,7 +125,7 @@ class Asset_Container { ...@@ -119,7 +125,7 @@ class Asset_Container {
*/ */
public function add($name, $source, $dependencies = array(), $attributes = array()) public function add($name, $source, $dependencies = array(), $attributes = array())
{ {
$type = (File::extension($source) == 'css') ? 'style' : 'script'; $type = ($this->file->extension($source) == 'css') ? 'style' : 'script';
return call_user_func(array($this, $type), $name, $source, $dependencies, $attributes); return call_user_func(array($this, $type), $name, $source, $dependencies, $attributes);
} }
......
<?php namespace Laravel\Cache; <?php namespace Laravel\Cache;
/**
* Wrap the file functions in a class that can be injected into driver.
* Since the file functions are global, the driver is untestable without
* injecting a wrapper around them.
*/
class File_Engine {
/**
* Determine if a file exists.
*
* @param string $file
* @return bool
*/
public function exists($file)
{
return file_exists($file);
}
/**
* Get the contents of a file.
*
* @param string $file
* @return string
*/
public function get($file)
{
return file_get_contents($file);
}
/**
* Write to a file.
*
* @param string $file
* @param string $value
* @return void
*/
public function put($file, $value)
{
file_put_contents($file, $value, LOCK_EX);
}
/**
* Delete a file.
*
* @param string $file
* @return void
*/
public function forget($file)
{
@unlink($file);
}
}
class File extends Driver { class File extends Driver {
/** /**
* The File cache engine. * The file manager instance.
* *
* @var File_Engine * @var Laravel\File
*/ */
private $file; private $file;
/** /**
* Create a new File cache driver instance. * Create a new File cache driver instance.
* *
* @param File_Engine $file * @param Laravel\File $file
* @return void * @return void
*/ */
public function __construct(File_Engine $file) public function __construct(\Laravel\File $file)
{ {
$this->file = $file; $this->file = $file;
} }
...@@ -134,7 +80,7 @@ class File extends Driver { ...@@ -134,7 +80,7 @@ class File extends Driver {
*/ */
public function forget($key) public function forget($key)
{ {
$this->file->forget(CACHE_PATH.$key); $this->file->delete(CACHE_PATH.$key);
} }
} }
\ No newline at end of file
<?php namespace Laravel; <?php namespace Laravel\Cache;
class Cache { use Laravel\IoC;
use Laravel\Config;
class Manager {
/** /**
* All of the active cache drivers. * All of the active cache drivers.
...@@ -32,20 +35,12 @@ class Cache { ...@@ -32,20 +35,12 @@ class Cache {
if ( ! array_key_exists($driver, static::$drivers)) if ( ! array_key_exists($driver, static::$drivers))
{ {
switch ($driver) if ( ! in_array($driver, array('apc', 'file', 'memcached')))
{ {
case 'file':
return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.file');
case 'memcached':
return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.memcached');
case 'apc':
return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.apc');
default:
throw new \Exception("Cache driver [$driver] is not supported."); throw new \Exception("Cache driver [$driver] is not supported.");
} }
return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.'.$driver);
} }
return static::$drivers[$driver]; return static::$drivers[$driver];
......
...@@ -45,7 +45,7 @@ class Config { ...@@ -45,7 +45,7 @@ class Config {
* $timezone = Config::get('application.timezone'); * $timezone = Config::get('application.timezone');
* *
* // Get the SQLite database connection configuration * // Get the SQLite database connection configuration
* $sqlite = Config::get('db.connections.sqlite'); * $sqlite = Config::get('database.connections.sqlite');
* </code> * </code>
* *
* @param string $key * @param string $key
......
...@@ -4,76 +4,151 @@ return array( ...@@ -4,76 +4,151 @@ return array(
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Laravel URL Writer | Laravel Support Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
'laravel.url' => array('singleton' => true, 'resolver' => function() 'laravel.file' => array('singleton' => true, 'resolver' => function()
{ {
return new URL; return new File;
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Laravel File Cache Driver | Laravel View Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
'laravel.cache.file' => array('resolver' => function($container) 'laravel.composers' => array('singleton' => true, 'resolver' => function()
{ {
return new Cache\File($container->resolve('laravel.cache.file_engine')); return require APP_PATH.'composers'.EXT;
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Laravel File Cache Driver Engine | Laravel Routing Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
'laravel.cache.file_engine' => array('resolver' => function() 'laravel.routing.router' => array('singleton' => true, 'resolver' => function($container)
{ {
return new Cache\File_Engine; return new Routing\Router($container->resolve('laravel.request'), require APP_PATH.'routes'.EXT);
}),
'laravel.routing.handler' => array('resolver' => function($container)
{
return new Routing\Handler($container->resolve('laravel.request'), require APP_PATH.'filters'.EXT);
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Laravel APC Cache Driver | Laravel Security Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
'laravel.cache.apc' => array('resolver' => function($container) 'laravel.security.auth' => array('resolver' => function($container)
{ {
return new Cache\APC($container->resolve('laravel.cache.apc_engine')); $hasher = $container->resolve('laravel.security.hashing.engine');
return new Security\Auth(Session\Manager::driver(), $hasher);
}),
'laravel.security.hashing.engine' => array('resolver' => function()
{
return new Security\Hashing\BCrypt(10, false);
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Laravel APC Cache Driver Engine | Laravel Session Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
'laravel.cache.apc_engine' => array('resolver' => function() 'laravel.session.driver' => array('resolver' => function()
{ {
return new Cache\APC_Engine; return Session\Manager::driver();
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Laravel Memcached Cache Driver | Laravel Cookie Session Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
'laravel.cache.memcached' => array('resolver' => function($container) 'laravel.session.cookie' => array('resolver' => function($container)
{ {
return new Cache\Memcached($container->resolve('laravel.memcache')); return new Session\Cookie(new Crypter, $container->resolve('laravel.request')->input->cookies);
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Memcache Connection | Laravel Database Session Components
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
'laravel.session.database' => array('resolver' => function($container)
{
return new Session\Database($container->resolve('laravel.session.database.connection'));
}),
'laravel.session.database.connection' => array('resolver' => function()
{
return Database\Manager::connection();
}),
/*
|--------------------------------------------------------------------------
| Laravel File Cache & Session Components
|--------------------------------------------------------------------------
*/
'laravel.cache.file' => array('resolver' => function()
{
return new Cache\File(new File);
}),
'laravel.session.file' => array('resolver' => function()
{
return new Session\File(new File);
}),
/*
|--------------------------------------------------------------------------
| Laravel APC Cache & Session Components
|--------------------------------------------------------------------------
*/
'laravel.cache.apc' => array('resolver' => function($container)
{
return new Cache\APC($container->resolve('laravel.cache.apc_engine'));
}),
'laravel.cache.apc_engine' => array('resolver' => function()
{
return new Cache\APC_Engine;
}),
'laravel.session.apc' => array('resolver' => function($container)
{
return new Session\APC($container->resolve('laravel.cache.apc'));
}),
/*
|--------------------------------------------------------------------------
| Laravel Memcached Cache & Session Components
|--------------------------------------------------------------------------
*/
'laravel.cache.memcached' => array('resolver' => function($container)
{
return new Cache\Memcached($container->resolve('laravel.memcache'));
}),
'laravel.session.memcached' => array('resolver' => function($container)
{
return new Session\Memcached($container->resolve('laravel.cache.memcached'));
}),
'laravel.memcache' => array('singleton' => true, 'resolver' => function() 'laravel.memcache' => array('singleton' => true, 'resolver' => function()
{ {
if ( ! class_exists('Memcache')) if ( ! class_exists('Memcache'))
......
<?php namespace Laravel;
class Container {
/**
* The resolved singleton instances.
*
* @var array
*/
private $singletons = array();
/**
* The registered dependencies.
*
* @var array
*/
private $resolvers = array();
/**
* Register a dependency and its resolver.
*
* The resolver function when the registered dependency is requested.
*
* <code>
* // Register a simple dependency
* $container->register('name', function() { return 'Fred'; });
*
* // Register a dependency as a singleton
* $container->register('name', function() { return new Name; }, true);
* </code>
*
* @param string $name
* @param Closure $resolver
* @return void
*/
public function register($name, $resolver, $singleton = false)
{
$this->resolvers[$name] = compact('resolver', 'singleton');
}
/**
* Register a dependency as a singleton.
*
* Singletons will only be instantiated the first time they are resolved. On subsequent
* requests for the object, the original instance will be returned.
*
* <code>
* // Register a dependency as a singleton
* $container->singleton('user', function() { return new User; })
* </code>
*
* @param string $name
* @param Closure $resolver
* @return void
*/
public function singleton($name, $resolver)
{
$this->register($name, $resolver, true);
}
/**
* Register an instance as a singleton.
*
* This method allows you to register an already existing object instance with the
* container as a singleton instance.
*
* <code>
* // Register an object instance as a singleton in the container
* $container->instance('user', new User);
* </code>
*
* @param string $name
* @param mixed $instance
* @return void
*/
public function instance($name, $instance)
{
$this->singletons[$name] = $instance;
}
/**
* Resolve a dependency.
*
* The dependency's resolver will be called and its result will be returned.
*
* <code>
* // Resolver the "name" dependency
* $name = $container->resolve('name');
* </code>
*
* @param string $name
* @return mixed
*/
public function resolve($name)
{
if (array_key_exists($name, $this->singletons)) return $this->singletons[$name];
if ( ! array_key_exists($name, $this->resolvers))
{
throw new \Exception("Error resolving [$name]. No resolver has been registered in the container.");
}
$object = call_user_func($this->resolvers[$name]['resolver'], $this);
if ($this->resolvers[$name]['singleton']) $this->singletons[$name] = $object;
return $object;
}
}
\ No newline at end of file
<?php namespace Laravel;
abstract class Controller {
/**
* A stub method that will be called before every request to the controller.
*
* If a value is returned by the method, it will be halt the request process
* and will be considered the response to the request.
*
* @param Request $request
* @return mixed
*/
public function before(Request $request) {}
/**
* Magic Method to handle calls to undefined functions on the controller.
*/
public function __call($method, $parameters) { return new Error('404'); }
}
\ No newline at end of file
...@@ -2,15 +2,33 @@ ...@@ -2,15 +2,33 @@
class Cookie { class Cookie {
/**
* All of the cookies for the current request.
*
* @var array
*/
private $cookies;
/**
* Create a new cookie manager instance.
*
* @param array $cookies
* @return void
*/
public function __construct(&$cookies)
{
$this->cookies = &$cookies;
}
/** /**
* Determine if a cookie exists. * Determine if a cookie exists.
* *
* @param string $name * @param string $name
* @return bool * @return bool
*/ */
public static function has($name) public function has($name)
{ {
return ! is_null(static::get($name)); return ! is_null($this->get($name));
} }
/** /**
...@@ -20,9 +38,9 @@ class Cookie { ...@@ -20,9 +38,9 @@ class Cookie {
* @param mixed $default * @param mixed $default
* @return string * @return string
*/ */
public static function get($name, $default = null) public function get($name, $default = null)
{ {
return Arr::get($_COOKIE, $name, $default); return Arr::get($this->cookies, $name, $default);
} }
/** /**
...@@ -36,9 +54,9 @@ class Cookie { ...@@ -36,9 +54,9 @@ class Cookie {
* @param bool $http_only * @param bool $http_only
* @return bool * @return bool
*/ */
public static function forever($name, $value, $path = '/', $domain = null, $secure = false, $http_only = false) public function forever($name, $value, $path = '/', $domain = null, $secure = false, $http_only = false)
{ {
return static::put($name, $value, 2628000, $path, $domain, $secure, $http_only); return $this->put($name, $value, 2628000, $path, $domain, $secure, $http_only);
} }
/** /**
...@@ -54,7 +72,7 @@ class Cookie { ...@@ -54,7 +72,7 @@ class Cookie {
* @param bool $http_only * @param bool $http_only
* @return bool * @return bool
*/ */
public static function put($name, $value, $minutes = 0, $path = '/', $domain = null, $secure = false, $http_only = false) public function put($name, $value, $minutes = 0, $path = '/', $domain = null, $secure = false, $http_only = false)
{ {
if ($minutes < 0) unset($_COOKIE[$name]); if ($minutes < 0) unset($_COOKIE[$name]);
...@@ -67,9 +85,9 @@ class Cookie { ...@@ -67,9 +85,9 @@ class Cookie {
* @param string $name * @param string $name
* @return bool * @return bool
*/ */
public static function forget($name) public function forget($name)
{ {
return static::put($name, null, -60); return $this->put($name, null, -60);
} }
} }
\ No newline at end of file
<?php namespace Laravel\DB; <?php namespace Laravel\Database;
class Connection { class Connection {
......
<?php namespace Laravel\DB; <?php namespace Laravel\Database;
use PDO;
abstract class Connector { abstract class Connector {
...@@ -8,11 +10,11 @@ abstract class Connector { ...@@ -8,11 +10,11 @@ abstract class Connector {
* @var array * @var array
*/ */
public $options = array( public $options = array(
\PDO::ATTR_CASE => \PDO::CASE_LOWER, PDO::ATTR_CASE => PDO::CASE_LOWER,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL, PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
\PDO::ATTR_STRINGIFY_FETCHES => false, PDO::ATTR_STRINGIFY_FETCHES => false,
\PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_EMULATE_PREPARES => false,
); );
/** /**
......
<?php namespace Laravel\DB\Eloquent; <?php namespace Laravel\Database\Eloquent;
class Hydrator { class Hydrator {
...@@ -50,8 +50,15 @@ class Hydrator { ...@@ -50,8 +50,15 @@ class Hydrator {
$model->exists = true; $model->exists = true;
if (isset($model->attributes['id']))
{
$models[$model->id] = $model; $models[$model->id] = $model;
} }
else
{
$models[] = $model;
}
}
return $models; return $models;
} }
......
<?php namespace Laravel\DB\Eloquent; <?php namespace Laravel\Database\Eloquent;
use Laravel\DB; use Laravel\IoC;
use Laravel\Str; use Laravel\Str;
use Laravel\Config; use Laravel\Config;
use Laravel\Inflector; use Laravel\Inflector;
use Laravel\Paginator; use Laravel\Database\Manager;
abstract class Model { abstract class Model {
...@@ -135,7 +135,7 @@ abstract class Model { ...@@ -135,7 +135,7 @@ abstract class Model {
// Since this method is only used for instantiating models for querying // Since this method is only used for instantiating models for querying
// purposes, we will go ahead and set the Query instance on the model. // purposes, we will go ahead and set the Query instance on the model.
$model->query = DB::connection(static::$connection)->table(static::table($class)); $model->query = Manager::connection(static::$connection)->table(static::table($class));
return $model; return $model;
} }
...@@ -189,44 +189,24 @@ abstract class Model { ...@@ -189,44 +189,24 @@ abstract class Model {
return static::query(get_called_class())->where('id', '=', $id)->first(); return static::query(get_called_class())->where('id', '=', $id)->first();
} }
/**
* Get an array of models from the database.
*
* @return array
*/
private function _get($columns = array('*'))
{
$this->query->select($columns);
return Hydrator::hydrate($this);
}
/** /**
* Get the first model result * Get the first model result
* *
* @return mixed * @return mixed
*/ */
private function _first($columns = array('*')) private function _first()
{ {
return (count($results = $this->take(1)->_get($columns)) > 0) ? reset($results) : null; return (count($results = $this->take(1)->_get()) > 0) ? reset($results) : null;
} }
/** /**
* Get paginated model results. * Get an array of models from the database.
* *
* @param int $per_page * @return array
* @return Paginator
*/ */
private function _paginate($per_page = null, $columns = array('*')) private function _get()
{
$total = $this->query->count();
if (is_null($per_page))
{ {
$per_page = (property_exists(get_class($this), 'per_page')) ? static::$per_page : 20; return Hydrator::hydrate($this);
}
return Paginator::make($this->select($columns)->for_page(Paginator::page($total, $per_page), $per_page)->get(), $total, $per_page);
} }
/** /**
...@@ -369,7 +349,7 @@ abstract class Model { ...@@ -369,7 +349,7 @@ abstract class Model {
// Since the model was instantiated using "new", a query instance has not been set. // Since the model was instantiated using "new", a query instance has not been set.
// Only models being used for querying have their query instances set by default. // Only models being used for querying have their query instances set by default.
$this->query = DB::connection(static::$connection)->table(static::table($model)); $this->query = Manager::connection(static::$connection)->table(static::table($model));
if (property_exists($model, 'timestamps') and $model::$timestamps) if (property_exists($model, 'timestamps') and $model::$timestamps)
{ {
...@@ -418,7 +398,7 @@ abstract class Model { ...@@ -418,7 +398,7 @@ abstract class Model {
// delete statement to the query instance. // delete statement to the query instance.
if ( ! $this->exists) return $this->query->delete(); if ( ! $this->exists) return $this->query->delete();
return DB::connection(static::$connection)->table(static::table(get_class($this)))->delete($this->id); return Manager::connection(static::$connection)->table(static::table(get_class($this)))->delete($this->id);
} }
/** /**
...@@ -488,7 +468,7 @@ abstract class Model { ...@@ -488,7 +468,7 @@ abstract class Model {
// To allow the "with", "get", "first", and "paginate" methods to be called both // To allow the "with", "get", "first", and "paginate" methods to be called both
// staticly and on an instance, we need to have private, underscored versions // staticly and on an instance, we need to have private, underscored versions
// of the methods and handle them dynamically. // of the methods and handle them dynamically.
if (in_array($method, array('with', 'get', 'first', 'paginate'))) if (in_array($method, array('with', 'get', 'first')))
{ {
return call_user_func_array(array($this, '_'.$method), $parameters); return call_user_func_array(array($this, '_'.$method), $parameters);
} }
......
<?php namespace Laravel; <?php namespace Laravel\Database;
class DB { use Laravel\Config;
class Manager {
/** /**
* The established database connections. * The established database connections.
...@@ -24,22 +26,22 @@ class DB { ...@@ -24,22 +26,22 @@ class DB {
* </code> * </code>
* *
* @param string $connection * @param string $connection
* @return DB\Connection * @return Database\Connection
*/ */
public static function connection($connection = null) public static function connection($connection = null)
{ {
if (is_null($connection)) $connection = Config::get('db.default'); if (is_null($connection)) $connection = Config::get('database.default');
if ( ! array_key_exists($connection, static::$connections)) if ( ! array_key_exists($connection, static::$connections))
{ {
if (is_null($config = Config::get('db.connections.'.$connection))) if (is_null($config = Config::get('database.connections.'.$connection)))
{ {
throw new \Exception("Database connection [$connection] is not defined."); throw new \Exception("Database connection [$connection] is not defined.");
} }
$connector = DB\Connector\Factory::make($config); $connector = Connector\Factory::make($config);
static::$connections[$connection] = new DB\Connection($connection, $config, $connector); static::$connections[$connection] = new Connection($connection, $config, $connector);
} }
return static::$connections[$connection]; return static::$connections[$connection];
...@@ -63,7 +65,7 @@ class DB { ...@@ -63,7 +65,7 @@ class DB {
* *
* @param string $table * @param string $table
* @param string $connection * @param string $connection
* @return DB\Query * @return Database\Query
*/ */
public static function table($table, $connection = null) public static function table($table, $connection = null)
{ {
......
<?php namespace Laravel\DB; <?php namespace Laravel\Database;
use Laravel\IoC;
use Laravel\Str; use Laravel\Str;
use Laravel\Config; use Laravel\Config;
use Laravel\Request; use Laravel\Request;
use Laravel\Paginator;
class Query { class Query {
...@@ -505,6 +505,27 @@ class Query { ...@@ -505,6 +505,27 @@ class Query {
return $this; return $this;
} }
/**
* Set the query limit and offset for a given page and item per page count.
*
* If the given page is not an integer or is less than zero, one will be used.
*
* <code>
* // Get the the 15 users that should be displayed for page 1
* $results = DB::table('users')->for_page(1, 15);
* </code>
*
* @param int $page
* @param int $per_page
* @return Query
*/
public function for_page($page, $per_page = 15)
{
if ($page < 1 or filter_var($page, FILTER_VALIDATE_INT) === false) $page = 1;
return $this->skip(($page - 1) * $per_page)->take($per_page)
}
/** /**
* Calculate and set the limit and offset values for a given page. * Calculate and set the limit and offset values for a given page.
* *
...@@ -554,36 +575,6 @@ class Query { ...@@ -554,36 +575,6 @@ class Query {
return $result; return $result;
} }
/**
* Get paginated query results.
*
* A Paginator instance will be returned, and the results of the query will be stored
* in the "results" property of the Paginator instance.
*
* <code>
* // Paginate the "users" table
* $users = DB::table('users')->paginate(15);
*
* // Paginate the "users" table with a where clause
* $users = DB::table('users')->where('votes', '>', 100)->paginate(10);
* </code>
*
* @param int $per_page
* @param array $columns
* @param int $page
* @return Paginator
*/
public function paginate($per_page, $columns = array('*'))
{
$total = $this->count();
$paginator = new Paginator(Request::active()->input->get('page', 1), $total, $per_page);
$paginator->results = $this->skip(($paginator->page - 1) * $per_page)->take($per_page)->get($columns);
return $paginator;
}
/** /**
* Execute the query as a SELECT statement and return the first result. * Execute the query as a SELECT statement and return the first result.
* *
......
<?php namespace Laravel\DB\Query; <?php namespace Laravel\Database\Query;
use Laravel\DB\Query; use Laravel\Database\Query;
class Compiler { class Compiler {
......
<?php namespace Laravel\DB\Query\Compiler; <?php namespace Laravel\Database\Query\Compiler;
use Laravel\DB\Connection; use Laravel\Database\Connection;
use Laravel\DB\Query\Compiler; use Laravel\Database\Query\Compiler;
class Factory { class Factory {
......
<?php namespace Laravel\DB\Query\Compiler; <?php namespace Laravel\Database\Query\Compiler;
use Laravel\DB\Query\Compiler; use Laravel\Database\Query\Compiler;
class MySQL extends Compiler { class MySQL extends Compiler {
......
<?php namespace Laravel\DB\Query\Compiler; <?php namespace Laravel\Database\Query\Compiler;
use Laravel\DB\Query\Compiler; use Laravel\Database\Query\Compiler;
class Postgres extends Compiler { class Postgres extends Compiler {
......
<?php namespace Laravel\DB\Query; <?php namespace Laravel\Database\Query;
use Laravel\DB\Query; use Laravel\Database\Query;
use Laravel\DB\Connection; use Laravel\Database\Connection;
class Factory { class Factory {
......
<?php namespace Laravel\DB\Query; <?php namespace Laravel\Database\Query;
use Laravel\DB\Query; use Laravel\Database\Query;
class Postgres extends Query { class Postgres extends Query {
......
...@@ -20,16 +20,18 @@ class Download extends Response { ...@@ -20,16 +20,18 @@ class Download extends Response {
{ {
if (is_null($name)) $name = basename($path); if (is_null($name)) $name = basename($path);
parent::__construct(file_get_contents($path)); $file = IoC::container()->resolve('laravel.file');
parent::__construct($file->get($path));
$this->header('Content-Description', 'File Transfer'); $this->header('Content-Description', 'File Transfer');
$this->header('Content-Type', File::mime(File::extension($path))); $this->header('Content-Type', $file->mime($file->extension($path)));
$this->header('Content-Disposition', 'attachment; filename="'.$name.'"'); $this->header('Content-Disposition', 'attachment; filename="'.$name.'"');
$this->header('Content-Transfer-Encoding', 'binary'); $this->header('Content-Transfer-Encoding', 'binary');
$this->header('Expires', 0); $this->header('Expires', 0);
$this->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0'); $this->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
$this->header('Pragma', 'public'); $this->header('Pragma', 'public');
$this->header('Content-Length', filesize($path)); $this->header('Content-Length', $file->size($path));
} }
} }
\ No newline at end of file
<?php namespace Laravel;
class Error extends Response {
/**
* Create a new error response instance.
*
* The response status code will be set using the specified code.
*
* Note: The specified error code should correspond to a view in your views/error directory.
*
* <code>
* // Return a 404 error response
* return new Error('404');
* </code>
*
* @param int $code
* @param array $data
* @return void
*/
public function __construct($code, $data = array())
{
return parent::__construct(View::make('error/'.$code, $data), $code);
}
}
\ No newline at end of file
...@@ -11,6 +11,13 @@ class Examiner { ...@@ -11,6 +11,13 @@ class Examiner {
*/ */
public $exception; public $exception;
/**
* The file manager instance.
*
* @var File
*/
private $file;
/** /**
* Human-readable error levels and descriptions. * Human-readable error levels and descriptions.
* *
...@@ -35,12 +42,14 @@ class Examiner { ...@@ -35,12 +42,14 @@ class Examiner {
/** /**
* Create a new exception examiner instance. * Create a new exception examiner instance.
* *
* @param Exception $e * @param Exception $exception
* @param File $file
* @return void * @return void
*/ */
public function __construct($e) public function __construct($exception, File $file)
{ {
$this->exception = $e; $this->exception = $exception;
$this->file = $file;
} }
/** /**
...@@ -80,7 +89,7 @@ class Examiner { ...@@ -80,7 +89,7 @@ class Examiner {
*/ */
public function context() public function context()
{ {
return File::snapshot($this->exception->getFile(), $this->exception->getLine()); return $this->file->snapshot($this->exception->getFile(), $this->exception->getLine());
} }
/** /**
......
...@@ -11,28 +11,28 @@ class Handler { ...@@ -11,28 +11,28 @@ class Handler {
* *
* @var Examiner * @var Examiner
*/ */
public $exception; public $examiner;
/** /**
* Create a new exception handler instance. * Create a new exception handler instance.
* *
* @param Exception $e * @param Examiner $examiner
* @return void * @return void
*/ */
public function __construct($e) public function __construct(Examiner $examiner)
{ {
$this->exception = new Examiner($e); $this->examiner = $examiner;
} }
/** /**
* Create a new exception handler instance. * Create a new exception handler instance.
* *
* @param Exception $e * @param Examiner $examiner
* @return Handler * @return Handler
*/ */
public static function make($e) public static function make(Examiner $examiner)
{ {
return new static($e); return new static($examiner);
} }
/** /**
...@@ -66,11 +66,7 @@ class Handler { ...@@ -66,11 +66,7 @@ class Handler {
*/ */
private function log() private function log()
{ {
$parameters = array( $parameters = array($this->examiner->severity(), $this->examiner->message(), $this->examiner->getTraceAsString());
$this->exception->severity(),
$this->exception->message(),
$this->exception->getTraceAsString(),
);
call_user_func_array(Config::get('error.logger'), $parameters); call_user_func_array(Config::get('error.logger'), $parameters);
} }
...@@ -83,7 +79,7 @@ class Handler { ...@@ -83,7 +79,7 @@ class Handler {
*/ */
private function get_response($detailed) private function get_response($detailed)
{ {
return ($detailed) ? $this->detailed_response() : Response::error('500'); return ($detailed) ? $this->detailed_response() : new Error('500');
} }
/** /**
...@@ -94,11 +90,11 @@ class Handler { ...@@ -94,11 +90,11 @@ class Handler {
private function detailed_response() private function detailed_response()
{ {
$data = array( $data = array(
'severity' => $this->exception->severity(), 'severity' => $this->examiner->severity(),
'message' => $this->exception->message(), 'message' => $this->examiner->message(),
'line' => $this->exception->getLine(), 'line' => $this->examiner->getLine(),
'trace' => $this->exception->getTraceAsString(), 'trace' => $this->examiner->getTraceAsString(),
'contexts' => $this->exception->context(), 'contexts' => $this->examiner->context(),
); );
return Response::make(View::make('error.exception', $data), 500); return Response::make(View::make('error.exception', $data), 500);
......
...@@ -2,13 +2,24 @@ ...@@ -2,13 +2,24 @@
class File { class File {
/**
* Determine if a file exists.
*
* @param string $path
* @return bool
*/
public function exists($path)
{
return file_exists($path);
}
/** /**
* Get the contents of a file. * Get the contents of a file.
* *
* @param string $path * @param string $path
* @return string * @return string
*/ */
public static function get($path) public function get($path)
{ {
return file_get_contents($path); return file_get_contents($path);
} }
...@@ -20,7 +31,7 @@ class File { ...@@ -20,7 +31,7 @@ class File {
* @param string $data * @param string $data
* @return int * @return int
*/ */
public static function put($path, $data) public function put($path, $data)
{ {
return file_put_contents($path, $data, LOCK_EX); return file_put_contents($path, $data, LOCK_EX);
} }
...@@ -32,22 +43,66 @@ class File { ...@@ -32,22 +43,66 @@ class File {
* @param string $data * @param string $data
* @return int * @return int
*/ */
public static function append($path, $data) public function append($path, $data)
{ {
return file_put_contents($path, $data, LOCK_EX | FILE_APPEND); return file_put_contents($path, $data, LOCK_EX | FILE_APPEND);
} }
/**
* Delete a file.
*
* @param string $path
* @return void
*/
public function delete($path)
{
@unlink($path);
}
/** /**
* Extract the file extension from a file path. * Extract the file extension from a file path.
* *
* @param string $path * @param string $path
* @return string * @return string
*/ */
public static function extension($path) public function extension($path)
{ {
return pathinfo($path, PATHINFO_EXTENSION); return pathinfo($path, PATHINFO_EXTENSION);
} }
/**
* Get the file type of a given file.
*
* @param string $path
* @return string
*/
public function type($path)
{
return filetype($path);
}
/**
* Get the file size of a given file.
*
* @param string $file
* @return int
*/
public function size($path)
{
return filesize($path);
}
/**
* Get the file's last modification time.
*
* @param string $path
* @return int
*/
public function modified($path)
{
return filemtime($path);
}
/** /**
* Get the lines surrounding a given line in a file. * Get the lines surrounding a given line in a file.
* *
...@@ -55,7 +110,7 @@ class File { ...@@ -55,7 +110,7 @@ class File {
* *
* <code> * <code>
* // Get lines 10 - 20 of the "routes.php" file * // Get lines 10 - 20 of the "routes.php" file
* $lines = File::snapshot(APP_PATH.'routes'.EXT, 15, 5); * $lines = $file->snapshot(APP_PATH.'routes'.EXT, 15, 5);
* </code> * </code>
* *
* @param string $path * @param string $path
...@@ -63,7 +118,7 @@ class File { ...@@ -63,7 +118,7 @@ class File {
* @param int $padding * @param int $padding
* @return array * @return array
*/ */
public static function snapshot($path, $line, $padding = 5) public function snapshot($path, $line, $padding = 5)
{ {
if ( ! file_exists($path)) return array(); if ( ! file_exists($path)) return array();
...@@ -85,14 +140,14 @@ class File { ...@@ -85,14 +140,14 @@ class File {
* *
* <code> * <code>
* // Returns "application/x-tar" * // Returns "application/x-tar"
* $mime = File::mime('tar'); * $mime = $file->mime('tar');
* </code> * </code>
* *
* @param string $extension * @param string $extension
* @param string $default * @param string $default
* @return string * @return string
*/ */
public static function mime($extension, $default = 'application/octet-stream') public function mime($extension, $default = 'application/octet-stream')
{ {
$mimes = Config::get('mimes'); $mimes = Config::get('mimes');
...@@ -109,14 +164,14 @@ class File { ...@@ -109,14 +164,14 @@ class File {
* *
* <code> * <code>
* // Determine if the file is a JPG image * // Determine if the file is a JPG image
* $image = File::is('jpg', 'path/to/image.jpg'); * $image = $file->is('jpg', 'path/to/image.jpg');
* </code> * </code>
* *
* @param string $extension * @param string $extension
* @param string $path * @param string $path
* @return bool * @return bool
*/ */
public static function is($extension, $path) public function is($extension, $path)
{ {
$mimes = Config::get('mimes'); $mimes = Config::get('mimes');
......
...@@ -75,9 +75,9 @@ class Form { ...@@ -75,9 +75,9 @@ class Form {
*/ */
private static function action($action, $https) private static function action($action, $https)
{ {
$url = IoC::container()->resolve('laravel.url'); $request = IoC::container()->resolve('laravel.request');
return HTML::entities($url->to(((is_null($action)) ? IoC::resolve('laravel.request')->uri() : $action), $https)); return HTML::entities(URL::to(((is_null($action)) ? $request->uri() : $action), $https));
} }
/** /**
...@@ -135,14 +135,11 @@ class Form { ...@@ -135,14 +135,11 @@ class Form {
/** /**
* Generate a hidden field containing the current CSRF token. * Generate a hidden field containing the current CSRF token.
* *
* If a session driver is not provided, the default session driver will be used.
*
* @param Session\Driver $driver
* @return string * @return string
*/ */
public static function token(Session\Driver $driver = null) public static function token()
{ {
if (is_null($driver)) $driver = Session::driver(); $driver = IoC::container()->resolve('laravel.session.driver');
return static::input('hidden', 'csrf_token', static::raw_token($driver)); return static::input('hidden', 'csrf_token', static::raw_token($driver));
} }
...@@ -150,16 +147,11 @@ class Form { ...@@ -150,16 +147,11 @@ class Form {
/** /**
* Retrieve the current CSRF token. * Retrieve the current CSRF token.
* *
* If a session driver is not provided, the default session driver will be used.
*
* @param Session\Driver $driver
* @return string * @return string
*/ */
public static function raw_token(Session\Driver $driver = null) public static function raw_token()
{ {
if (is_null($driver)) $driver = Session::driver(); return IoC::container()->resolve('laravel.session.driver')->get('csrf_token');
return $driver->get('csrf_token');
} }
/** /**
...@@ -449,7 +441,7 @@ class Form { ...@@ -449,7 +441,7 @@ class Form {
*/ */
public static function image($url, $name = null, $attributes = array()) public static function image($url, $name = null, $attributes = array())
{ {
$attributes['src'] = IoC::container()->resolve('laravel.url')->to_asset($url); $attributes['src'] = URL::to_asset($url);
return static::input('image', $name, null, $attributes); return static::input('image', $name, null, $attributes);
} }
......
...@@ -24,9 +24,9 @@ class HTML { ...@@ -24,9 +24,9 @@ class HTML {
*/ */
public static function script($url, $attributes = array()) public static function script($url, $attributes = array())
{ {
$url = IoC::container()->resolve('laravel.url'); $url = static::entities(URL::to_asset($url));
return '<script type="text/javascript" src="'.static::entities($url->to_asset($url)).'"'.static::attributes($attributes).'></script>'.PHP_EOL; return '<script type="text/javascript" src="'.$url.'"'.static::attributes($attributes).'></script>'.PHP_EOL;
} }
/** /**
...@@ -42,9 +42,7 @@ class HTML { ...@@ -42,9 +42,7 @@ class HTML {
$attributes = array_merge($attributes, array('rel' => 'stylesheet', 'type' => 'text/css')); $attributes = array_merge($attributes, array('rel' => 'stylesheet', 'type' => 'text/css'));
$url = IoC::container()->resolve('laravel.url'); return '<link href="'.static::entities(URL::to_asset($url)).'"'.static::attributes($attributes).'>'.PHP_EOL;
return '<link href="'.static::entities($url->to_asset($url)).'"'.static::attributes($attributes).'>'.PHP_EOL;
} }
/** /**
...@@ -71,9 +69,9 @@ class HTML { ...@@ -71,9 +69,9 @@ class HTML {
*/ */
public static function link($url, $title, $attributes = array(), $https = false, $asset = false) public static function link($url, $title, $attributes = array(), $https = false, $asset = false)
{ {
$url = IoC::container()->resolve('laravel.url'); $url = static::entities(URL::to($url, $https, $asset));
return '<a href="'.static::entities($url->to($url, $https, $asset)).'"'.static::attributes($attributes).'>'.static::entities($title).'</a>'; return '<a href="'.$url.'"'.static::attributes($attributes).'>'.static::entities($title).'</a>';
} }
/** /**
...@@ -136,7 +134,7 @@ class HTML { ...@@ -136,7 +134,7 @@ class HTML {
*/ */
public static function link_to_route($name, $title, $parameters = array(), $attributes = array(), $https = false) public static function link_to_route($name, $title, $parameters = array(), $attributes = array(), $https = false)
{ {
return static::link(IoC::resolve('laravel.url')->to_route($name, $parameters, $https), $title, $attributes); return static::link(URL::to_route($name, $parameters, $https), $title, $attributes);
} }
/** /**
...@@ -169,7 +167,9 @@ class HTML { ...@@ -169,7 +167,9 @@ class HTML {
if (is_null($title)) $title = $email; if (is_null($title)) $title = $email;
return '<a href="&#109;&#097;&#105;&#108;&#116;&#111;&#058;'.$email.'"'.static::attributes($attributes).'>'.static::entities($title).'</a>'; $email = '&#109;&#097;&#105;&#108;&#116;&#111;&#058;'.$email;
return '<a href="'.$email.'"'.static::attributes($attributes).'>'.static::entities($title).'</a>';
} }
/** /**
...@@ -195,7 +195,7 @@ class HTML { ...@@ -195,7 +195,7 @@ class HTML {
{ {
$attributes['alt'] = static::entities($alt); $attributes['alt'] = static::entities($alt);
return '<img src="'.static::entities(IoC::resolve('laravel.url')->to_asset($url)).'"'.static::attributes($attributes).'>'; return '<img src="'.static::entities(URL::to_asset($url)).'"'.static::attributes($attributes).'>';
} }
/** /**
......
...@@ -149,7 +149,9 @@ class Inflector { ...@@ -149,7 +149,9 @@ class Inflector {
*/ */
public static function plural($value) public static function plural($value)
{ {
return static::$plural_cache[$value] = static::inflect($value, static::$plural_cache, array_flip(static::$irregular), static::$plural); $irregular = array_flip(static::$irregular);
return static::$plural_cache[$value] = static::inflect($value, static::$plural_cache, $irregular, static::$plural);
} }
/** /**
......
...@@ -24,9 +24,9 @@ class Input { ...@@ -24,9 +24,9 @@ class Input {
public $post; public $post;
/** /**
* The $_COOKIE array for the request. * The cookie manager instance.
* *
* @var array * @var Cookie
*/ */
public $cookies; public $cookies;
...@@ -40,31 +40,21 @@ class Input { ...@@ -40,31 +40,21 @@ class Input {
/** /**
* Create a new Input instance. * Create a new Input instance.
* *
* @param Request $request * @param string $method
* @param bool $spoofed
* @param array $get * @param array $get
* @param array $post * @param array $post
* @param array $cookies
* @param array $files * @param array $files
* @param Cookie $cookies
* @return void
*/ */
public function __construct(Request $request, $get, $post, $cookies, $files) public function __construct($method, $spoofed, $get, $post, $files, Cookie $cookies)
{ {
$this->get = $get; $this->get = $get;
$this->post = $post; $this->post = $post;
$this->files = $files; $this->files = $files;
$this->cookies = $cookies; $this->cookies = $cookies;
$this->hydrate($request->method(), $request->is_spoofed());
}
/**
* Hydrate the input for a given request.
*
* @param string $method
* @param bool $spoofed
* @return void
*/
private function hydrate($method, $spoofed)
{
if ($method == 'GET') if ($method == 'GET')
{ {
$this->input = $this->get; $this->input = $this->get;
...@@ -138,8 +128,6 @@ class Input { ...@@ -138,8 +128,6 @@ class Input {
/** /**
* Get input data from the previous request. * Get input data from the previous request.
* *
* If no session driver is provided, the default driver will be used.
*
* <code> * <code>
* // Get the "name" item from the old input data * // Get the "name" item from the old input data
* $name = Request::active()->input->old('name'); * $name = Request::active()->input->old('name');
...@@ -147,12 +135,11 @@ class Input { ...@@ -147,12 +135,11 @@ class Input {
* *
* @param string $key * @param string $key
* @param mixed $default * @param mixed $default
* @param Session\Driver $driver
* @return string * @return string
*/ */
public function old($key = null, $default = null, Session\Driver $driver = null) public function old($key = null, $default = null)
{ {
if (is_null($driver)) $driver = Session::driver(); $driver = IoC::container()->resolve('laravel.session.driver');
return Arr::get($driver->get('laravel_old_input', array()), $key, $default); return Arr::get($driver->get('laravel_old_input', array()), $key, $default);
} }
......
...@@ -68,3 +68,128 @@ class IoC { ...@@ -68,3 +68,128 @@ class IoC {
} }
} }
class Container {
/**
* The resolved singleton instances.
*
* @var array
*/
private $singletons = array();
/**
* The registered dependencies.
*
* @var array
*/
private $resolvers = array();
/**
* Register a dependency and its resolver.
*
* The resolver function when the registered dependency is requested.
*
* <code>
* // Register a simple dependency
* $container->register('name', function() { return 'Fred'; });
*
* // Register a dependency as a singleton
* $container->register('name', function() { return new Name; }, true);
* </code>
*
* @param string $name
* @param Closure $resolver
* @return void
*/
public function register($name, $resolver, $singleton = false)
{
$this->resolvers[$name] = array('resolver' => $resolver, 'singleton' => $singleton);
}
/**
* Determine if a dependency has been registered in the container.
*
* <code>
* // Determine if the "user" dependency is registered in the container
* $registered = $container->registered('user');
* </code>
*
* @param string $name
* @return bool
*/
public function registered($name)
{
return array_key_exists($name, $this->resolvers);
}
/**
* Register a dependency as a singleton.
*
* Singletons will only be instantiated the first time they are resolved. On subsequent
* requests for the object, the original instance will be returned.
*
* <code>
* // Register a dependency as a singleton
* $container->singleton('user', function() { return new User; })
* </code>
*
* @param string $name
* @param Closure $resolver
* @return void
*/
public function singleton($name, $resolver)
{
$this->register($name, $resolver, true);
}
/**
* Register an instance as a singleton.
*
* This method allows you to register an already existing object instance with the
* container as a singleton instance.
*
* <code>
* // Register an object instance as a singleton in the container
* $container->instance('user', new User);
* </code>
*
* @param string $name
* @param mixed $instance
* @return void
*/
public function instance($name, $instance)
{
$this->singletons[$name] = $instance;
}
/**
* Resolve a dependency.
*
* The dependency's resolver will be called and its result will be returned.
*
* <code>
* // Resolver the "name" dependency
* $name = $container->resolve('name');
* </code>
*
* @param string $name
* @return mixed
*/
public function resolve($name)
{
if (array_key_exists($name, $this->singletons)) return $this->singletons[$name];
if ( ! $this->registered($name))
{
throw new \Exception("Error resolving [$name]. No resolver has been registered in the container.");
}
$object = call_user_func($this->resolvers[$name]['resolver'], $this);
if ($this->resolvers[$name]['singleton']) $this->singletons[$name] = $object;
return $object;
}
}
\ No newline at end of file
...@@ -69,25 +69,6 @@ class Lang { ...@@ -69,25 +69,6 @@ class Lang {
return new static($key, $replacements); return new static($key, $replacements);
} }
/**
* Set the language the line should be returned in.
*
* The language specified in this method should correspond to a language directory in your application.
*
* <code>
* // Get a "fr" language line
* $line = Lang::line('validation.required')->in('fr')->get();
* </code>
*
* @param string $language
* @return Lang
*/
public function in($language)
{
$this->language = $language;
return $this;
}
/** /**
* Get the language line. * Get the language line.
* *
...@@ -123,7 +104,9 @@ class Lang { ...@@ -123,7 +104,9 @@ class Lang {
/** /**
* Parse a language key. * Parse a language key.
* *
* Language keys follow a {file}.{key} convention. * Language keys follow a {file}.{key} convention. If a specific language key is not
* specified, an exception will be thrown. Setting entire language files at run-time
* is not currently supported.
* *
* @param string $key * @param string $key
* @return array * @return array
...@@ -168,6 +151,25 @@ class Lang { ...@@ -168,6 +151,25 @@ class Lang {
return isset(static::$lines[$this->language.$file]); return isset(static::$lines[$this->language.$file]);
} }
/**
* Set the language the line should be returned in.
*
* The language specified in this method should correspond to a language directory in your application.
*
* <code>
* // Get a "fr" language line
* $line = Lang::line('validation.required')->in('fr')->get();
* </code>
*
* @param string $language
* @return Lang
*/
public function in($language)
{
$this->language = $language;
return $this;
}
/** /**
* Get the string content of the language line. * Get the string content of the language line.
*/ */
......
<?php
return array(
/*
|--------------------------------------------------------------------------
| Pagination "Next" and "Previous" Language
|--------------------------------------------------------------------------
*/
'previous' => '&laquo; Previous',
'next' => 'Next &raquo;',
);
\ No newline at end of file
...@@ -22,13 +22,14 @@ unset($laravel, $application, $config, $packages, $public, $storage); ...@@ -22,13 +22,14 @@ unset($laravel, $application, $config, $packages, $public, $storage);
// -------------------------------------------------------------- // --------------------------------------------------------------
define('CACHE_PATH', STORAGE_PATH.'cache/'); define('CACHE_PATH', STORAGE_PATH.'cache/');
define('CONFIG_PATH', APP_PATH.'config/'); define('CONFIG_PATH', APP_PATH.'config/');
define('CONTROLLER_PATH', APP_PATH.'controllers/');
define('DATABASE_PATH', STORAGE_PATH.'db/'); define('DATABASE_PATH', STORAGE_PATH.'db/');
define('LANG_PATH', APP_PATH.'lang/'); define('LANG_PATH', APP_PATH.'language/');
define('SCRIPT_PATH', PUBLIC_PATH.'js/'); define('SCRIPT_PATH', PUBLIC_PATH.'js/');
define('SESSION_PATH', STORAGE_PATH.'sessions/'); define('SESSION_PATH', STORAGE_PATH.'sessions/');
define('STYLE_PATH', PUBLIC_PATH.'css/'); define('STYLE_PATH', PUBLIC_PATH.'css/');
define('SYS_CONFIG_PATH', SYS_PATH.'config/'); define('SYS_CONFIG_PATH', SYS_PATH.'config/');
define('SYS_LANG_PATH', SYS_PATH.'lang/'); define('SYS_LANG_PATH', SYS_PATH.'language/');
define('VIEW_PATH', APP_PATH.'views/'); define('VIEW_PATH', APP_PATH.'views/');
// -------------------------------------------------------------- // --------------------------------------------------------------
...@@ -45,6 +46,13 @@ Loader::bootstrap(Config::get('aliases'), array(APP_PATH.'libraries/', APP_PATH. ...@@ -45,6 +46,13 @@ Loader::bootstrap(Config::get('aliases'), array(APP_PATH.'libraries/', APP_PATH.
spl_autoload_register(array('Laravel\\Loader', 'load')); spl_autoload_register(array('Laravel\\Loader', 'load'));
// --------------------------------------------------------------
// Bootstrap the IoC container.
// --------------------------------------------------------------
require SYS_PATH.'ioc'.EXT;
IoC::bootstrap(Config::get('container'));
// -------------------------------------------------------------- // --------------------------------------------------------------
// Set the error reporting and display levels. // Set the error reporting and display levels.
// -------------------------------------------------------------- // --------------------------------------------------------------
...@@ -66,14 +74,16 @@ set_exception_handler(function($e) use ($error_dependencies) ...@@ -66,14 +74,16 @@ set_exception_handler(function($e) use ($error_dependencies)
{ {
call_user_func($error_dependencies); call_user_func($error_dependencies);
Exception\Handler::make($e)->handle(); Exception\Handler::make(new Exception\Examiner($e, new File))->handle();
}); });
set_error_handler(function($number, $error, $file, $line) use ($error_dependencies) set_error_handler(function($number, $error, $file, $line) use ($error_dependencies)
{ {
call_user_func($error_dependencies); call_user_func($error_dependencies);
Exception\Handler::make(new \ErrorException($error, $number, 0, $file, $line))->handle(); $e = new \ErrorException($error, $number, 0, $file, $line);
Exception\Handler::make(new Exception\Examiner($e, new File))->handle();
}); });
register_shutdown_function(function() use ($error_dependencies) register_shutdown_function(function() use ($error_dependencies)
...@@ -82,9 +92,9 @@ register_shutdown_function(function() use ($error_dependencies) ...@@ -82,9 +92,9 @@ register_shutdown_function(function() use ($error_dependencies)
{ {
call_user_func($error_dependencies); call_user_func($error_dependencies);
extract($error); $e = new \ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']);
Exception\Handler::make(new \ErrorException($message, $type, 0, $file, $line))->handle(); Exception\Handler::make(new Exception\Examiner($e, new File))->handle();
} }
}); });
...@@ -96,21 +106,17 @@ date_default_timezone_set(Config::get('application.timezone')); ...@@ -96,21 +106,17 @@ date_default_timezone_set(Config::get('application.timezone'));
// -------------------------------------------------------------- // --------------------------------------------------------------
// Load all of the core routing and response classes. // Load all of the core routing and response classes.
// -------------------------------------------------------------- // --------------------------------------------------------------
require SYS_PATH.'input'.EXT;
require SYS_PATH.'request'.EXT;
require SYS_PATH.'response'.EXT; require SYS_PATH.'response'.EXT;
require SYS_PATH.'routing/route'.EXT; require SYS_PATH.'routing/route'.EXT;
require SYS_PATH.'routing/router'.EXT; require SYS_PATH.'routing/router'.EXT;
require SYS_PATH.'routing/loader'.EXT; require SYS_PATH.'routing/handler'.EXT;
require SYS_PATH.'routing/filter'.EXT;
// --------------------------------------------------------------
// Bootstrap the IoC container.
// --------------------------------------------------------------
IoC::bootstrap(Config::get('dependencies'));
// -------------------------------------------------------------- // --------------------------------------------------------------
// Load the session. // Load the session.
// -------------------------------------------------------------- // --------------------------------------------------------------
if (Config::get('session.driver') != '') Session::driver()->start(Cookie::get('laravel_session')); if (Config::get('session.driver') != '') Session\Manager::driver()->start(Cookie::get('laravel_session'));
// -------------------------------------------------------------- // --------------------------------------------------------------
// Load the packages that are in the auto-loaded packages array. // Load the packages that are in the auto-loaded packages array.
...@@ -127,44 +133,19 @@ if (count(Config::get('application.packages')) > 0) ...@@ -127,44 +133,19 @@ if (count(Config::get('application.packages')) > 0)
// -------------------------------------------------------------- // --------------------------------------------------------------
$request = new Request($_SERVER); $request = new Request($_SERVER);
// --------------------------------------------------------------
// Hydrate the input for the current request.
// --------------------------------------------------------------
$request->input = new Input($request, $_GET, $_POST, $_COOKIE, $_FILES);
// --------------------------------------------------------------
// Register the request as a singleton in the IoC container.
// --------------------------------------------------------------
IoC::container()->instance('laravel.request', $request); IoC::container()->instance('laravel.request', $request);
// -------------------------------------------------------------- // --------------------------------------------------------------
// Register the filters for the default module. // Hydrate the input for the current request.
// --------------------------------------------------------------
Routing\Filter::register(require APP_PATH.'filters'.EXT);
// --------------------------------------------------------------
// Call the "before" filter for the application and module.
// -------------------------------------------------------------- // --------------------------------------------------------------
$response = Routing\Filter::call('before', array($request->method(), $request->uri()), true); $request->input = new Input($request->method(), $request->is_spoofed(), $_GET, $_POST, $_FILES, new Cookie($_COOKIE));
// -------------------------------------------------------------- // --------------------------------------------------------------
// Route the request and get the response from the route. // Route the request and get the response from the route.
// -------------------------------------------------------------- // --------------------------------------------------------------
if (is_null($response)) $route = IoC::container()->resolve('laravel.routing.router')->route();
{
$loader = new Routing\Loader(APP_PATH);
$route = Routing\Router::make($request, $loader)->route(); $response = ( ! is_null($route)) ? IoC::container()->resolve('laravel.routing.handler')->handle($route) : new Error('404');
$response = (is_null($route)) ? Response::error('404') : $route->call();
}
$response = Response::prepare($response);
// --------------------------------------------------------------
// Call the "after" filter for the application and module.
// --------------------------------------------------------------
Routing\Filter::call('after', array($response, $request->method(), $request->uri()));
// -------------------------------------------------------------- // --------------------------------------------------------------
// Stringify the response. // Stringify the response.
...@@ -176,7 +157,7 @@ $response->content = $response->render(); ...@@ -176,7 +157,7 @@ $response->content = $response->render();
// -------------------------------------------------------------- // --------------------------------------------------------------
if (Config::get('session.driver') != '') if (Config::get('session.driver') != '')
{ {
$driver = Session::driver(); $driver = Session\Manager::driver();
$driver->flash('laravel_old_input', $request->input->get()); $driver->flash('laravel_old_input', $request->input->get());
......
...@@ -23,13 +23,14 @@ class Package { ...@@ -23,13 +23,14 @@ class Package {
* </code> * </code>
* *
* @param string|array $packages * @param string|array $packages
* @param string $path
* @return void * @return void
*/ */
public static function load($packages) public static function load($packages, $path = PACKAGE_PATH)
{ {
foreach ((array) $packages as $package) foreach ((array) $packages as $package)
{ {
if ( ! static::loaded($package) and file_exists($bootstrap = PACKAGE_PATH.$package.'/bootstrap'.EXT)) if ( ! static::loaded($package) and file_exists($bootstrap = $path.$package.'/bootstrap'.EXT))
{ {
require $bootstrap; require $bootstrap;
} }
......
<?php namespace Laravel;
class Paginator {
/**
* The results for the current page.
*
* @var array
*/
public $results;
/**
* The total number of results.
*
* @var int
*/
public $total;
/**
* The current page.
*
* @var int
*/
public $page;
/**
* The number of items per page.
*
* @var int
*/
public $per_page;
/**
* The last page available for the result set.
*
* @var int
*/
public $last_page;
/**
* The number of links that should be adjacent to the current page.
*
* @var int
*/
public $adjacent = 3;
/**
* Indicates if the generated links should use HTTPS.
*
* @var bool
*/
public $secure;
/**
* The language that should be used when generating page links.
*
* @var string
*/
public $language;
/**
* The values that should be appended to the end of the link query strings.
*
* @var array
*/
public $append = array();
/**
* Create a new Paginator instance.
*
* In general, the Paginator will be instantiated through the database query. However, you are free
* to instantiate a paginator for an arbitrary array if you wish.
*
* <code>
* // Create a Paginator for the first page of 10 total results and 2 items per page
* $paginator = new Paginator(1, 10, 2);
* </code>
*
* @param int $page
* @param int $total
* @param int $per_page
* @return void
*/
public function __construct($page, $total, $per_page)
{
$this->last_page = ceil($total / $per_page);
$this->per_page = $per_page;
$this->total = $total;
// Determine if the current request is using HTTPS. If it is, we will use HTTPS when
// generating the links unless otherwise specified by the secure() method.
$this->secure = Request::active()->is_secure();
// The page method will validate the given page number and adjust it if necessary.
// For example, when the given page number is greater than the last page or less
// than zero, the page number will be adjusted.
$this->page = $this->adjust($page);
}
/**
* Check a given page number for validity and adjust it if necessary.
*
* The page will be validated and adjusted if it is less than one or greater than the last page.
* For example, if the current page is not an integer or less than one, one will be returned.
* If the current page is greater than the last page, the last page will be returned.
*
* @param int $page
* @return int
*/
private function adjust($page)
{
if (is_numeric($page) and $page > $this->last_page) return ($this->last_page > 0) ? $this->last_page : 1;
return ($page < 1 or filter_var($page, FILTER_VALIDATE_INT) === false) ? 1 : $page;
}
/**
* Create the HTML pagination links.
*
* If there are enough pages, an intelligent, sliding list of links will be created.
* Otherwise, a simple list of page number links will be created.
*
* @return string
*/
public function links()
{
if ($this->last_page <= 1) return '';
// The hard-coded "7" is to account for all of the constant elements in a sliding range.
// Namely: The the current page, the two ellipses, the two beginning pages, and the two ending pages.
$numbers = ($this->last_page < 7 + ($this->adjacent * 2)) ? $this->range(1, $this->last_page) : $this->slider();
return '<div class="pagination">'.$this->previous().$numbers.$this->next().'</div>';
}
/**
* Build a sliding list of HTML numeric page links.
*
* If the current page is close to the beginning of the pages, all of the beginning links will be
* shown and the ending links will be abbreviated.
*
* If the current page is in the middle of the pages, the beginning and ending links will be abbreviated.
*
* If the current page is close to the end of the list of pages, all of the ending links will be
* shown and the beginning links will be abbreviated.
*
* @return string
*/
private function slider()
{
if ($this->page <= $this->adjacent * 2)
{
return $this->range(1, 2 + ($this->adjacent * 2)).$this->ending();
}
elseif ($this->page >= $this->last_page - ($this->adjacent * 2))
{
return $this->beginning().$this->range($this->last_page - 2 - ($this->adjacent * 2), $this->last_page);
}
else
{
return $this->beginning().$this->range($this->page - $this->adjacent, $this->page + $this->adjacent).$this->ending();
}
}
/**
* Generate the "previous" HTML link.
*
* The "previous" line from the "pagination" language file will be used to create the link text.
*
* @return string
*/
public function previous()
{
$text = Lang::line('pagination.previous')->get($this->language);
if ($this->page > 1)
{
return $this->link($this->page - 1, $text, 'prev_page').' ';
}
return HTML::span($text, array('class' => 'disabled prev_page')).' ';
}
/**
* Generate the "next" HTML link.
*
* The "next" line from the "pagination" language file will be used to create the link text.
*
* @return string
*/
public function next()
{
$text = Lang::line('pagination.next')->get($this->language);
if ($this->page < $this->last_page)
{
return $this->link($this->page + 1, $text, 'next_page');
}
return HTML::span($text, array('class' => 'disabled next_page'));
}
/**
* Build the first two page links for a sliding page range.
*
* @return string
*/
private function beginning()
{
return $this->range(1, 2).'<span class="dots">...</span>';
}
/**
* Build the last two page links for a sliding page range.
*
* @return string
*/
private function ending()
{
return '<span class="dots">...</span>'.$this->range($this->last_page - 1, $this->last_page);
}
/**
* Build a range of page links.
*
* A span element will be generated for the current page.
*
* @param int $start
* @param int $end
* @return string
*/
private function range($start, $end)
{
$pages = '';
for ($i = $start; $i <= $end; $i++)
{
if ($this->page == $i)
{
$pages .= HTML::span($i, array('class' => 'current')).' ';
}
else
{
$pages .= $this->link($i, $i, null).' ';
}
}
return $pages;
}
/**
* Create a HTML page link.
*
* @param int $page
* @param string $text
* @param string $attributes
* @return string
*/
private function link($page, $text, $class)
{
$append = '';
foreach ($this->append as $key => $value)
{
$append .= '&'.$key.'='.$value;
}
return HTML::link(Request::active()->uri().'?page='.$page.$append, $text, compact('class'), $this->secure);
}
/**
* Force the paginator to return links that use HTTPS.
*
* @param bool $secure
* @return Paginator
*/
public function secure($secure = true)
{
$this->secure = true;
return $this;
}
/**
* Set the language that should be used when generating page links.
*
* The language specified here should correspond to a language directory for your application.
*
* @param string $language
* @return Paginator
*/
public function lang($language)
{
$this->language = $language;
return $this;
}
/**
* Set the items that should be appended to the link query strings.
*
* <code>
* // Set the "sort" query string item on the links that will be generated
* echo $paginator->append(array('sort' => 'desc'))->links();
* </code>
*
* @param array $values
* @return Paginator
*/
public function append($values)
{
$this->append = $values;
return $this;
}
}
\ No newline at end of file
...@@ -24,15 +24,15 @@ class Redirect extends Response { ...@@ -24,15 +24,15 @@ class Redirect extends Response {
*/ */
public static function to($url, $status = 302, $method = 'location', $https = false) public static function to($url, $status = 302, $method = 'location', $https = false)
{ {
$url = IoC::container()->resolve('laravel.url')->to($url, $https); $url = URL::to($url, $https);
if ($method == 'location') if ($method == 'location')
{ {
return static::make('', $status)->header('Refresh', '0;url='.$url); return parent::__construct('', $status)->header('Refresh', '0;url='.$url);
} }
else else
{ {
return static::make('', $status)->header('Location', $url); return parent::__construct('', $status)->header('Location', $url);
} }
} }
...@@ -66,14 +66,11 @@ class Redirect extends Response { ...@@ -66,14 +66,11 @@ class Redirect extends Response {
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @param Session\Driver $driver
* @return Response * @return Response
*/ */
public function with($key, $value, Session\Driver $driver) public function with($key, $value)
{ {
if (is_null($driver)) $driver = Session::driver(); IoC::container()->resolve('laravel.session.driver')->flash($key, $value);
$driver->flash($key, $value);
return $this; return $this;
} }
...@@ -93,16 +90,14 @@ class Redirect extends Response { ...@@ -93,16 +90,14 @@ class Redirect extends Response {
{ {
$parameters = (isset($parameters[0])) ? $parameters[0] : array(); $parameters = (isset($parameters[0])) ? $parameters[0] : array();
$url = IoC::container()->resolve('laravel.url');
if (strpos($method, 'to_secure_') === 0) if (strpos($method, 'to_secure_') === 0)
{ {
return static::to($url->to_route(substr($method, 10), $parameters, true)); return static::to(URL::to_route(substr($method, 10), $parameters, true));
} }
if (strpos($method, 'to_') === 0) if (strpos($method, 'to_') === 0)
{ {
return static::to($url->to_route(substr($method, 3), $parameters)); return static::to(URL::to_route(substr($method, 3), $parameters));
} }
throw new \Exception("Method [$method] is not defined on the Redirect class."); throw new \Exception("Method [$method] is not defined on the Redirect class.");
......
...@@ -213,20 +213,4 @@ class Request { ...@@ -213,20 +213,4 @@ class Request {
} }
} }
/**
* Magic Method for dynamically retrieving properties of the request instance.
*
* <code>
* // Get all of the input for the request
* $input = Request::active()->input;
* </code>
*/
public function __get($key)
{
if ($key === 'input')
{
return $this->input->all();
}
}
} }
\ No newline at end of file
...@@ -112,41 +112,13 @@ class Response implements Renderable { ...@@ -112,41 +112,13 @@ class Response implements Renderable {
return new static($content, $status); return new static($content, $status);
} }
/**
* Factory for creating new error response instances.
*
* The response status code will be set using the specified code.
*
* Note: The specified error code should correspond to a view in your views/error directory.
*
* <code>
* // Return a 404 error response
* return Response::error('404');
* </code>
*
* @param int $code
* @param array $data
* @return Response
*/
public static function error($code, $data = array())
{
return static::make(View::make('error/'.$code, $data), $code);
}
/**
* Take a value returned by a route and prepare a Response instance.
*
* @param mixed $response
* @return Response
*/
public static function prepare($response)
{
return ( ! $response instanceof Response) ? new static($response) : $response;
}
/** /**
* Get the evaluated string contents of the response. * Get the evaluated string contents of the response.
* *
* If the content implements the Renderable interface, the render method will be called
* on the content and the result will be returned. Otherwise, the content will be cast
* to a string and returned.
*
* @return string * @return string
*/ */
public function render() public function render()
...@@ -157,14 +129,14 @@ class Response implements Renderable { ...@@ -157,14 +129,14 @@ class Response implements Renderable {
/** /**
* Send the response to the browser. * Send the response to the browser.
* *
* All of the response header will be sent to the browser first, followed by the content
* of the response instance, which will be evaluated and rendered by the render method.
*
* @return void * @return void
*/ */
public function send() public function send()
{ {
if ( ! array_key_exists('Content-Type', $this->headers)) if ( ! isset($this->headers['Content-Type'])) $this->header('Content-Type', 'text/html; charset=utf-8');
{
$this->header('Content-Type', 'text/html; charset=utf-8');
}
if ( ! headers_sent()) $this->send_headers(); if ( ! headers_sent()) $this->send_headers();
......
<?php namespace Laravel\Routing;
class Filter {
/**
* The loaded route filters.
*
* @var array
*/
private static $filters = array();
/**
* Register a set of route filters.
*
* @param array $filters
* @return void
*/
public static function register($filters)
{
static::$filters = array_merge(static::$filters, $filters);
}
/**
* Clear all of the registered route filters.
*
* @return void
*/
public static function clear()
{
static::$filters = array();
}
/**
* Call a set of route filters.
*
* @param string $filter
* @param array $parameters
* @param bool $override
* @return mixed
*/
public static function call($filters, $parameters = array(), $override = false)
{
foreach (explode(', ', $filters) as $filter)
{
if ( ! isset(static::$filters[$filter])) continue;
$response = call_user_func_array(static::$filters[$filter], $parameters);
// "Before" filters may override the request cycle. For example, an authentication
// filter may redirect a user to a login view if they are not logged in. Because of
// this, we will return the first filter response if overriding is enabled.
if ( ! is_null($response) and $override) return $response;
}
}
}
\ No newline at end of file
<?php namespace Laravel\Routing;
class Finder {
/**
* The named routes that have been found so far.
*
* @var array
*/
public static $names = array();
/**
* Find a named route in a given array of routes.
*
* @param string $name
* @param array $routes
* @return array
*/
public static function find($name, $routes)
{
if (array_key_exists($name, static::$names)) return static::$names[$name];
$arrayIterator = new \RecursiveArrayIterator($routes);
$recursiveIterator = new \RecursiveIteratorIterator($arrayIterator);
// Since routes can be nested deep within sub-directories, we need to recursively
// iterate through each directory and gather all of the routes.
foreach ($recursiveIterator as $iterator)
{
$route = $recursiveIterator->getSubIterator();
if (isset($route['name']) and $route['name'] == $name)
{
return static::$names[$name] = array($arrayIterator->key() => iterator_to_array($route));
}
}
}
}
\ No newline at end of file
<?php namespace Laravel\Routing;
use Closure;
use Laravel\IoC;
use Laravel\Error;
use Laravel\Request;
use Laravel\Response;
class Handler {
/**
* The active request instance.
*
* @var Request
*/
protected $request;
/**
* The route filter manager.
*
* @var array
*/
protected $filters;
/**
* Create a new route handler instance.
*
* @param array $filters
* @return void
*/
public function __construct(Request $request, $filters)
{
$this->request = $request;
$this->filters = $filters;
}
/**
* Execute a given route and return the response.
*
* @param Route $route
* @return Response
*/
public function handle(Route $route)
{
$this->validate($route);
if ( ! is_null($response = $this->filter(array_merge($route->before(), array('before')), array($this->request), true)))
{
return $this->finish($route, $response);
}
$closure = ( ! $route->callback instanceof Closure) ? $this->find_route_closure($route) : $route->callback;
if ( ! is_null($closure)) return $this->handle_closure($route, $closure);
return $this->finish($route, new Error('404'));
}
/**
* Validate that a given route is callable.
*
* @param Route $route
* @return void
*/
protected function validate(Route $route)
{
if ( ! $route->callback instanceof Closure and ! is_array($route->callback))
{
throw new \Exception('Invalid route defined for URI ['.$route->key.']');
}
}
/**
* Extract the route closure from the route.
*
* If a "do" index is specified on the callback, that is the handler.
* Otherwise, we will return the first callable array value.
*
* @param Route $route
* @return Closure
*/
protected function find_route_closure(Route $route)
{
if (isset($route->callback['do'])) return $route->callback['do'];
foreach ($route->callback as $value) { if (is_callable($value)) return $value; }
}
/**
* Handle a route closure.
*
* @param Route $route
* @param Closure $closure
* @return mixed
*/
protected function handle_closure(Route $route, Closure $closure)
{
$response = call_user_func_array($closure, $route->parameters);
if (is_array($response))
{
$response = $this->delegate($response[0], $response[1], $route->parameters);
}
return $this->finish($route, $response);
}
/**
* Handle the delegation of a route to a controller method.
*
* @param string $controller
* @param string $method
* @param array $parameters
* @return Response
*/
protected function delegate($controller, $method, $parameters)
{
if ( ! file_exists($path = CONTROLLER_PATH.strtolower(str_replace('.', '/', $controller)).EXT))
{
throw new \Exception("Controller [$controller] is not defined.");
}
require $path;
$controller = $this->resolve($controller);
$response = $controller->before($this->request);
return (is_null($response)) ? call_user_func_array(array($controller, $method), $parameters) : $response;
}
/**
* Resolve a controller name to a controller instance.
*
* @param string $controller
* @return Controller
*/
protected function resolve($controller)
{
if (IoC::container()->registered('controllers.'.$controller))
{
return IoC::container()->resolve('controllers.'.$controller);
}
$controller = str_replace(' ', '_', ucwords(str_replace('.', ' ', $controller))).'_Controller';
return new $controller;
}
/**
* Call a filter or set of filters.
*
* @param array $filters
* @param array $parameters
* @param bool $override
* @return mixed
*/
protected function filter($filters, $parameters = array(), $override = false)
{
foreach ((array) $filters as $filter)
{
if ( ! isset($this->filters[$filter])) continue;
$response = call_user_func_array($this->filters[$filter], $parameters);
// "Before" filters may override the request cycle. For example, an authentication
// filter may redirect a user to a login view if they are not logged in. Because of
// this, we will return the first filter response if overriding is enabled.
if ( ! is_null($response) and $override) return $response;
}
}
/**
* Finish the route handling for the request.
*
* The route response will be converted to a Response instance and the "after" filters
* defined for the route will be executed.
*
* @param Route $route
* @param mixed $response
* @return Response
*/
protected function finish(Route $route, $response)
{
if ( ! $response instanceof Response) $response = new Response($response);
$this->filter(array_merge($route->after(), array('after')), array($this->request, $response));
return $response;
}
}
\ No newline at end of file
<?php namespace Laravel\Routing;
use Laravel\Config;
class Loader {
/**
* All of the routes for the application.
*
* @var array
*/
private static $routes;
/**
* The path where the routes are located.
*
* @var string
*/
public $path;
/**
* Create a new route loader instance.
*
* @param string $path
* @return void
*/
public function __construct($path)
{
$this->path = $path;
}
/**
* Load the appropriate routes for the request URI.
*
* @param string
* @return array
*/
public function load($uri)
{
$base = (file_exists($path = $this->path.'routes'.EXT)) ? require $path : array();
return array_merge($this->load_nested_routes(explode('/', $uri)), $base);
}
/**
* Load the appropriate routes from the routes directory.
*
* @param array $segments
* @return array
*/
private function load_nested_routes($segments)
{
// If the request URI only more than one segment, and the last segment contains a dot, we will
// assume the request is for a specific format (users.json or users.xml) and strip off
// everything after the dot so we can load the appropriate file.
if (count($segments) > 0 and strpos(end($segments), '.') !== false)
{
$segment = array_pop($segments);
array_push($segments, substr($segment, 0, strpos($segment, '.')));
}
// Work backwards through the URI segments until we find the deepest possible
// matching route directory. Once we find it, we will return those routes.
foreach (array_reverse($segments, true) as $key => $value)
{
if (file_exists($path = $this->path.'routes/'.implode('/', array_slice($segments, 0, $key + 1)).EXT))
{
return require $path;
}
}
return array();
}
/**
* Get all of the routes for the application.
*
* To improve performance, this operation will only be performed once. The routes
* will be cached and returned on every subsequent call.
*
* @param bool $reload
* @return array
*/
public static function all($path = APP_PATH, $reload = false)
{
if ( ! is_null(static::$routes) and ! $reload) return static::$routes;
$routes = array();
if (file_exists($path.'routes'.EXT))
{
$routes = array_merge($routes, require $path.'routes'.EXT);
}
if (is_dir($path.'routes'))
{
// Since route files can be nested deep within the route directory, we need to
// recursively spin through the directory to find every file.
$directoryIterator = new \RecursiveDirectoryIterator($path.'routes');
$recursiveIterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($recursiveIterator as $file)
{
if (filetype($file) === 'file' and strpos($file, EXT) !== false)
{
$routes = array_merge($routes, require $file);
}
}
}
return static::$routes = $routes;
}
}
\ No newline at end of file
<?php namespace Laravel\Routing; <?php namespace Laravel\Routing;
use Laravel\Package;
use Laravel\Response;
class Route { class Route {
/** /**
...@@ -42,64 +39,39 @@ class Route { ...@@ -42,64 +39,39 @@ class Route {
} }
/** /**
* Execute the route function. * Get all of the "before" filters defined for the route.
* *
* @param mixed $route * @return array
* @param array $parameters
* @return Response
*/ */
public function call() public function before()
{
$response = null;
// The callback may be in array form, meaning it has attached filters or is named and we
// will need to evaluate it further to determine what to do. If the callback is just a
// closure, we can execute it now and return the result.
if (is_callable($this->callback))
{ {
$response = call_user_func_array($this->callback, $this->parameters); return $this->filters('before');
} }
elseif (is_array($this->callback))
{
if (isset($this->callback['needs']))
{
Package::load(explode(', ', $this->callback['needs']));
}
$response = isset($this->callback['before']) ? Filter::call($this->callback['before'], array(), true) : null;
if (is_null($response) and ! is_null($handler = $this->find_route_function())) /**
{ * Get all of the "after" filters defined for the route.
$response = call_user_func_array($handler, $this->parameters); *
} * @return array
} */
public function after()
$response = Response::prepare($response);
if (is_array($this->callback) and isset($this->callback['after']))
{ {
Filter::call($this->callback['after'], array($response)); return $this->filters('after');
}
return $response;
} }
/** /**
* Extract the route function from the route. * Get an array of filters defined for the route.
* *
* If a "do" index is specified on the callback, that is the handler. * <code>
* Otherwise, we will return the first callable array value. * // Get all of the "before" filters defined for the route.
* $filters = $route->filters('before');
* </code>
* *
* @return Closure * @param string $name
* @return array
*/ */
private function find_route_function() private function filters($name)
{ {
if (isset($this->callback['do'])) return $this->callback['do']; return (is_array($this->callback) and isset($this->callback[$name])) ? explode(', ', $this->callback[$name]) : array();
foreach ($this->callback as $value)
{
if (is_callable($value)) return $value;
}
} }
} }
\ No newline at end of file
...@@ -5,14 +5,7 @@ use Laravel\Request; ...@@ -5,14 +5,7 @@ use Laravel\Request;
class Router { class Router {
/** /**
* The request method and URI. * All of the routes available to the router.
*
* @var string
*/
public $destination;
/**
* All of the loaded routes.
* *
* @var array * @var array
*/ */
...@@ -23,58 +16,81 @@ class Router { ...@@ -23,58 +16,81 @@ class Router {
* *
* @var Request * @var Request
*/ */
private $request; protected $request;
/** /**
* The route loader instance. * The named routes that have been found so far.
* *
* @var Loader * @var array
*/ */
private $loader; protected $names = array();
/** /**
* Create a new router for a request method and URI. * Create a new router for a request method and URI.
* *
* @param Request $request * @param Request $request
* @param Loader $loader * @param array $routes
* @return void * @return void
*/ */
public function __construct(Request $request, Loader $loader) public function __construct(Request $request, $routes)
{ {
$this->loader = $loader; $this->routes = $routes;
$this->request = $request; $this->request = $request;
// Put the request method and URI in route form. Routes begin with
// the request method and a forward slash.
$this->destination = $request->method().' /'.trim($request->uri(), '/');
} }
/** /**
* Create a new router for a request method and URI. * Find a route by name.
* *
* @param Request $request * The returned array will be identical the array defined in the routes.php file.
* @param Loader $loader *
* @return Router * <code>
* // Find the "login" named route
* $route = $router->find('login');
*
* // Find the "login" named route through the IoC container
* $route = IoC::resolve('laravel.routing.router')->find('login');
* </code>
*
* @param string $name
* @return array
*/ */
public static function make(Request $request, Loader $loader) public function find($name)
{
if (array_key_exists($name, $this->names)) return $this->names[$name];
$arrayIterator = new \RecursiveArrayIterator($this->routes);
$recursiveIterator = new \RecursiveIteratorIterator($arrayIterator);
foreach ($recursiveIterator as $iterator)
{ {
return new static($request, $loader); $route = $recursiveIterator->getSubIterator();
if (isset($route['name']) and $route['name'] === $name)
{
return $this->names[$name] = array($arrayIterator->key() => iterator_to_array($route));
}
}
} }
/** /**
* Search a set of routes for the route matching a method and URI. * Search the routes for the route matching a method and URI.
*
* If no route can be found, the application controllers will be searched.
* *
* @return Route * @return Route
*/ */
public function route() public function route()
{ {
if (is_null($this->routes)) $this->routes = $this->loader->load($this->request->uri()); // Put the request method and URI in route form. Routes begin with
// the request method and a forward slash.
$destination = $this->request->method().' /'.trim($this->request->uri(), '/');
// Check for a literal route match first. If we find one, there is // Check for a literal route match first. If we find one, there is
// no need to spin through all of the routes. // no need to spin through all of the routes.
if (isset($this->routes[$this->destination])) if (isset($this->routes[$destination]))
{ {
return $this->request->route = new Route($this->destination, $this->routes[$this->destination]); return $this->request->route = new Route($destination, $this->routes[$destination]);
} }
foreach ($this->routes as $keys => $callback) foreach ($this->routes as $keys => $callback)
...@@ -85,11 +101,73 @@ class Router { ...@@ -85,11 +101,73 @@ class Router {
{ {
foreach (explode(', ', $keys) as $key) foreach (explode(', ', $keys) as $key)
{ {
if (preg_match('#^'.$this->translate_wildcards($key).'$#', $this->destination)) if (preg_match('#^'.$this->translate_wildcards($key).'$#', $destination))
{
return $this->request->route = new Route($keys, $callback, $this->parameters($destination, $key));
}
}
}
}
return $this->route_to_controller();
}
/**
* Attempt to find a controller for the incoming request.
*
* If no corresponding controller can be found, NULL will be returned.
*
* @return Route
*/
protected function route_to_controller()
{
$segments = explode('/', trim($this->request->uri(), '/'));
if ( ! is_null($key = $this->controller_key($segments)))
{ {
return $this->request->route = new Route($keys, $callback, $this->parameters($this->destination, $key)); // Create the controller name for the current request. This controller
// name will be returned by the anonymous route we will create. Instead
// of using directory slashes, dots will be used to specify the controller
// location with the controllers directory.
$controller = implode('.', array_slice($segments, 0, $key));
// Now that we have the controller path and name, we can slice the controller
// section of the URI from the array of segments.
$segments = array_slice($segments, $key);
// Extract the controller method from the URI segments. If no more segments
// are remaining after slicing off the controller, the "index" method will
// be used as the default controller method.
$method = (count($segments) > 0) ? array_shift($segments) : 'index';
// Now we're ready to dummy up a controller delegating route callback. This
// callback will look exactly like the callback the developer would create
// were they to code the controller delegation manually.
$callback = function() use ($controller, $method) { return array($controller, $method); };
return new Route($controller, $callback, $segments);
} }
} }
/**
* Search the controllers for the application and determine if an applicable
* controller exists for the current request.
*
* If a controller is found, the array key for the controller name in the URI
* segments will be returned by the method, otherwise NULL will be returned.
*
* @param array $segments
* @return int
*/
protected function controller_key($segments)
{
// Work backwards through the URI segments until we find the deepest possible
// matching controller. Once we find it, we will return those routes.
foreach (array_reverse($segments, true) as $key => $value)
{
if (file_exists($path = CONTROLLER_PATH.implode('/', array_slice($segments, 0, $key + 1)).EXT))
{
return $key + 1;
} }
} }
} }
...@@ -100,7 +178,7 @@ class Router { ...@@ -100,7 +178,7 @@ class Router {
* @param string $key * @param string $key
* @return string * @return string
*/ */
private function translate_wildcards($key) protected function translate_wildcards($key)
{ {
$replacements = 0; $replacements = 0;
...@@ -123,7 +201,7 @@ class Router { ...@@ -123,7 +201,7 @@ class Router {
* @param string $route * @param string $route
* @return array * @return array
*/ */
private function parameters($uri, $route) protected function parameters($uri, $route)
{ {
return array_values(array_intersect_key(explode('/', $uri), preg_grep('/\(.+\)/', explode('/', $route)))); return array_values(array_intersect_key(explode('/', $uri), preg_grep('/\(.+\)/', explode('/', $route))));
} }
......
<?php namespace Laravel; <?php namespace Laravel\Security;
class Auth { use Laravel\IoC;
use Laravel\Config;
use Laravel\Session\Driver;
class Authenticator {
/** /**
* The current user of the application. * The current user of the application.
...@@ -24,7 +28,7 @@ class Auth { ...@@ -24,7 +28,7 @@ class Auth {
/** /**
* The hashing engine that should be used to perform hashing. * The hashing engine that should be used to perform hashing.
* *
* @var Hash\Engine * @var Hashing\Engine
*/ */
protected $hasher; protected $hasher;
...@@ -39,10 +43,10 @@ class Auth { ...@@ -39,10 +43,10 @@ class Auth {
* Create a new Auth class instance. * Create a new Auth class instance.
* *
* @param Session\Driver $driver * @param Session\Driver $driver
* @param Hash\Engine $hasher * @param Hashing\Engine $hasher
* @return void * @return void
*/ */
public function __construct(Session\Driver $driver, Hash\Engine $hasher) public function __construct(Driver $driver, Hashing\Engine $hasher)
{ {
$this->hasher = $hasher; $this->hasher = $hasher;
$this->session = $driver; $this->session = $driver;
...@@ -53,17 +57,11 @@ class Auth { ...@@ -53,17 +57,11 @@ class Auth {
* *
* If no session driver or hasher is provided, the default implementations will be used. * If no session driver or hasher is provided, the default implementations will be used.
* *
* @param Session\Driver $driver * @return Auth
* @param Hash\Engine $hasher
* @return void
*/ */
public static function make(Session\Driver $driver = null, Hash\Engine $hasher = null) public static function make()
{ {
if (is_null($driver)) $driver = Session::driver(); return IoC::container()->resolve('laravel.security.auth');
if (is_null($hasher)) $hasher = Hasher::make();
return new static($driver, $hasher);
} }
/** /**
......
<?php namespace Laravel; <?php namespace Laravel\Security;
use Laravel\Config;
class Crypter { class Crypter {
...@@ -31,7 +33,7 @@ class Crypter { ...@@ -31,7 +33,7 @@ class Crypter {
* @param string $key * @param string $key
* @return void * @return void
*/ */
public function __construct($cipher, $mode, $key) public function __construct($cipher = MCRYPT_RIJNDAEL_256, $mode = 'cbc', $key = null)
{ {
$this->cipher = $cipher; $this->cipher = $cipher;
$this->mode = $mode; $this->mode = $mode;
......
<?php namespace Laravel\Hash; <?php namespace Laravel\Security\Hashing;
# #
# Portable PHP password hashing framework. # Portable PHP password hashing framework.
# #
......
<?php namespace Laravel\Hash; <?php namespace Laravel\Security\Hashing;
interface Engine { interface Engine {
......
<?php namespace Laravel; <?php namespace Laravel\Security\Hashing;
class Hasher { class Hasher {
...@@ -14,12 +14,12 @@ class Hasher { ...@@ -14,12 +14,12 @@ class Hasher {
* *
* If no hashing engine is provided, the BCrypt engine will be used. * If no hashing engine is provided, the BCrypt engine will be used.
* *
* @param Hash\Engine $engine * @param Engine $engine
* @return void * @return void
*/ */
public function __construct(Hash\Engine $engine = null) public function __construct(Engine $engine = null)
{ {
$this->engine = (is_null($engine)) ? new Hash\BCrypt(10, false) : $engine; $this->engine = (is_null($engine)) ? new BCrypt(10, false) : $engine;
} }
/** /**
...@@ -27,10 +27,10 @@ class Hasher { ...@@ -27,10 +27,10 @@ class Hasher {
* *
* If no hashing engine is provided, the BCrypt engine will be used. * If no hashing engine is provided, the BCrypt engine will be used.
* *
* @param Hash\Engine $engine * @param Engine $engine
* @return Hasher * @return Hasher
*/ */
public static function make(Hash\Engine $engine = null) public static function make(Engine $engine = null)
{ {
return new static($engine); return new static($engine);
} }
......
<?php namespace Laravel\Session; <?php namespace Laravel\Session;
use Laravel\Cache;
use Laravel\Config; use Laravel\Config;
class APC extends Driver { class APC extends Driver {
/**
* The APC cache driver instance.
*
* @var Cache\APC
*/
private $apc;
/**
* Create a new APC session driver instance.
*
* @param Cache\APC $apc
* @return void
*/
public function __construct(\Laravel\Cache\APC $apc)
{
$this->apc = $apc;
}
/**
* Load a session by ID.
*
* The session will be retrieved from persistant storage and returned as an array.
* The array contains the session ID, last activity UNIX timestamp, and session data.
*
* @param string $id
* @return array
*/
protected function load($id) protected function load($id)
{ {
return Cache::driver('apc')->get($id); return $this->apc->get($id);
} }
/**
* Save the session to persistant storage.
*
* @return void
*/
protected function save() protected function save()
{ {
Cache::driver('apc')->put($this->session['id'], $this->session, Config::get('session.lifetime')); $this->apc->put($this->session['id'], $this->session, Config::get('session.lifetime'));
} }
/**
* Delete the session from persistant storage.
*
* @return void
*/
protected function delete() protected function delete()
{ {
Cache::driver('apc')->forget($this->session['id']); $this->apc->forget($this->session['id']);
} }
} }
\ No newline at end of file
<?php namespace Laravel\Session; <?php namespace Laravel\Session;
use Laravel\Config; use Laravel\Config;
use Laravel\Crypter; use Laravel\Security\Crypter;
class Cookie extends Driver { class Cookie extends Driver {
/**
* The cookie engine instance.
*
* @var Cookie_Engine
*/
private $cookie;
/** /**
* The Crypter instance. * The Crypter instance.
* *
...@@ -15,11 +22,14 @@ class Cookie extends Driver { ...@@ -15,11 +22,14 @@ class Cookie extends Driver {
/** /**
* Create a new Cookie session driver instance. * Create a new Cookie session driver instance.
* *
* @param Crypter $crypter
* @param Cookie $cookie
* @return void * @return void
*/ */
public function __construct() public function __construct(Crypter $crypter, Cookie $cookie)
{ {
$this->crypter = new Crypter; $this->cookie = $cookie;
$this->crypter = $crypter;
if (Config::get('application.key') == '') if (Config::get('application.key') == '')
{ {
...@@ -27,14 +37,28 @@ class Cookie extends Driver { ...@@ -27,14 +37,28 @@ class Cookie extends Driver {
} }
} }
/**
* Load a session by ID.
*
* The session will be retrieved from persistant storage and returned as an array.
* The array contains the session ID, last activity UNIX timestamp, and session data.
*
* @param string $id
* @return array
*/
protected function load($id) protected function load($id)
{ {
if (\System\Cookie::has('session_payload')) if ($this->cookie->has('session_payload'))
{ {
return unserialize($this->crypter->decrypt(\System\Cookie::get('session_payload'))); return unserialize($this->crypter->decrypt($this->cookie->get('session_payload')));
} }
} }
/**
* Save the session to persistant storage.
*
* @return void
*/
protected function save() protected function save()
{ {
if ( ! headers_sent()) if ( ! headers_sent())
...@@ -43,13 +67,18 @@ class Cookie extends Driver { ...@@ -43,13 +67,18 @@ class Cookie extends Driver {
$payload = $this->crypter->encrypt(serialize($this->session)); $payload = $this->crypter->encrypt(serialize($this->session));
\System\Cookie::put('session_payload', $payload, $lifetime, $path, $domain, $https, $http_only); $this->cookie->put('session_payload', $payload, $lifetime, $path, $domain, $https, $http_only);
} }
} }
/**
* Delete the session from persistant storage.
*
* @return void
*/
protected function delete() protected function delete()
{ {
\System\Cookie::forget('session_payload'); $this->cookie->forget('session_payload');
} }
} }
\ No newline at end of file
<?php namespace Laravel\Session; <?php namespace Laravel\Session;
use Laravel\Config; use Laravel\Config;
use Laravel\Database\Connection;
class DB extends Driver implements Sweeper { class Database extends Driver implements Sweeper {
/**
* The database connection.
*
* @var Connection
*/
private $connection;
/**
* Create a new database session driver.
*
* @param Connection $connection
* @return void
*/
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
/**
* Load a session by ID.
*
* The session will be retrieved from persistant storage and returned as an array.
* The array contains the session ID, last activity UNIX timestamp, and session data.
*
* @param string $id
* @return array
*/
protected function load($id) protected function load($id)
{ {
$session = $this->table()->find($id); $session = $this->table()->find($id);
...@@ -18,6 +46,11 @@ class DB extends Driver implements Sweeper { ...@@ -18,6 +46,11 @@ class DB extends Driver implements Sweeper {
} }
} }
/**
* Save the session to persistant storage.
*
* @return void
*/
protected function save() protected function save()
{ {
$this->delete($this->session['id']); $this->delete($this->session['id']);
...@@ -29,11 +62,22 @@ class DB extends Driver implements Sweeper { ...@@ -29,11 +62,22 @@ class DB extends Driver implements Sweeper {
)); ));
} }
/**
* Delete the session from persistant storage.
*
* @return void
*/
protected function delete() protected function delete()
{ {
$this->table()->delete($this->session['id']); $this->table()->delete($this->session['id']);
} }
/**
* Delete all expired sessions from persistant storage.
*
* @param int $expiration
* @return void
*/
public function sweep($expiration) public function sweep($expiration)
{ {
$this->table()->where('last_activity', '<', $expiration)->delete(); $this->table()->where('last_activity', '<', $expiration)->delete();
...@@ -46,7 +90,7 @@ class DB extends Driver implements Sweeper { ...@@ -46,7 +90,7 @@ class DB extends Driver implements Sweeper {
*/ */
private function table() private function table()
{ {
return \System\DB::connection()->table(Config::get('session.table')); return $this->connection->table(Config::get('session.table'));
} }
} }
\ No newline at end of file
...@@ -2,26 +2,69 @@ ...@@ -2,26 +2,69 @@
class File extends Driver implements Sweeper { class File extends Driver implements Sweeper {
/**
* The file manager instance.
*
* @var Laravel\File
*/
private $file;
/**
* Create a new File session driver instance.
*
* @param Laravel\File $file
* @return void
*/
public function __construct(\Laravel\File $file)
{
$this->file = $file;
}
/**
* Load a session by ID.
*
* The session will be retrieved from persistant storage and returned as an array.
* The array contains the session ID, last activity UNIX timestamp, and session data.
*
* @param string $id
* @return array
*/
protected function load($id) protected function load($id)
{ {
if (file_exists($path = SESSION_PATH.$id)) return unserialize(file_get_contents($path)); if ($this->file->exists($path = SESSION_PATH.$id)) return unserialize($this->file->get($path));
} }
/**
* Save the session to persistant storage.
*
* @return void
*/
protected function save() protected function save()
{ {
file_put_contents(SESSION_PATH.$this->session['id'], serialize($this->session), LOCK_EX); $this->file->put(SESSION_PATH.$this->session['id'], serialize($this->session), LOCK_EX);
} }
/**
* Delete the session from persistant storage.
*
* @return void
*/
protected function delete() protected function delete()
{ {
@unlink(SESSION_PATH.$this->session['id']); $this->file->delete(SESSION_PATH.$this->session['id']);
} }
/**
* Delete all expired sessions from persistant storage.
*
* @param int $expiration
* @return void
*/
public function sweep($expiration) public function sweep($expiration)
{ {
foreach (glob(SESSION_PATH.'*') as $file) foreach (glob(SESSION_PATH.'*') as $file)
{ {
if (filetype($file) == 'file' and filemtime($file) < $expiration) @unlink($file); if ($this->file->type($file) == 'file' and $this->file->modified($file) < $expiration) $this->file->delete($file);
} }
} }
......
<?php namespace Laravel; <?php namespace Laravel\Session;
class Session { use Laravel\Config;
class Manager {
/** /**
* The active session driver. * The active session driver.
...@@ -22,27 +24,15 @@ class Session { ...@@ -22,27 +24,15 @@ class Session {
{ {
if (is_null(static::$driver)) if (is_null(static::$driver))
{ {
switch (Config::get('session.driver')) $driver = Config::get('session.driver');
{
case 'cookie':
return static::$driver = new Session\Cookie;
case 'file':
return static::$driver = new Session\File;
case 'db':
return static::$driver = new Session\DB;
case 'memcached': if (in_array($driver, array('cookie', 'file', 'database', 'memcached')))
return static::$driver = new Session\Memcached; {
return static::$driver = IoC::container()->resolve('laravel.session.'.$driver);
case 'apc': }
return static::$driver = new Session\APC;
default:
throw new \Exception("Session driver [$driver] is not supported."); throw new \Exception("Session driver [$driver] is not supported.");
} }
}
return static::$driver; return static::$driver;
} }
......
<?php namespace Laravel\Session; <?php namespace Laravel\Session;
use Laravel\Cache;
use Laravel\Config; use Laravel\Config;
class Memcached extends Driver { class Memcached extends Driver {
/**
* The Memcache cache driver instance.
*
* @var Memcached
*/
private $memcached;
/**
* Create a new Memcached session driver instance.
*
* @param Memcached $memcached
* @return void
*/
public function __construct(\Laravel\Cache\Memcached $memcached)
{
$this->memcached = $memcached;
}
/**
* Load a session by ID.
*
* The session will be retrieved from persistant storage and returned as an array.
* The array contains the session ID, last activity UNIX timestamp, and session data.
*
* @param string $id
* @return array
*/
protected function load($id) protected function load($id)
{ {
return Cache::driver('memcached')->get($id); return $this->memcached->get($id);
} }
/**
* Save the session to persistant storage.
*
* @return void
*/
protected function save() protected function save()
{ {
Cache::driver('memcached')->put($this->session['id'], $this->session, Config::get('session.lifetime')); $this->memcached->put($this->session['id'], $this->session, Config::get('session.lifetime'));
} }
/**
* Delete the session from persistant storage.
*
* @return void
*/
protected function delete() protected function delete()
{ {
Cache::driver('memcached')->forget($this->session['id']); $this->memcached->forget($this->session['id']);
} }
} }
\ No newline at end of file
...@@ -7,20 +7,22 @@ class URL { ...@@ -7,20 +7,22 @@ class URL {
* *
* If the given URL is already well-formed, it will be returned unchanged. * If the given URL is already well-formed, it will be returned unchanged.
* *
* <code>
* // Generate the URL: http://example.com/index.php/user/profile
* $url = URL::to('user/profile');
* </code>
*
* @param string $url * @param string $url
* @param bool $https * @param bool $https
* @return string * @return string
*/ */
public function to($url = '', $https = false) public static function to($url = '', $https = false)
{ {
if (filter_var($url, FILTER_VALIDATE_URL) !== false) return $url; if (filter_var($url, FILTER_VALIDATE_URL) !== false) return $url;
$base = Config::get('application.url').'/'.Config::get('application.index'); $base = Config::get('application.url').'/'.Config::get('application.index');
if ($https and strpos($base, 'http://') === 0) if ($https) $base = preg_replace('~http://~', 'https://', $base, 1);
{
$base = 'https://'.substr($base, 7);
}
return rtrim($base, '/').'/'.trim($url, '/'); return rtrim($base, '/').'/'.trim($url, '/');
} }
...@@ -28,25 +30,42 @@ class URL { ...@@ -28,25 +30,42 @@ class URL {
/** /**
* Generate an application URL with HTTPS. * Generate an application URL with HTTPS.
* *
* <code>
* // Generate the URL: https://example.com/index.php/user/profile
* $url = URL::to_secure('user/profile');
* </code>
*
* @param string $url * @param string $url
* @return string * @return string
*/ */
public function to_secure($url = '') public static function to_secure($url = '')
{ {
return $this->to($url, true); return static::to($url, true);
} }
/** /**
* Generate an application URL to an asset. * Generate an application URL to an asset.
* *
* The index file will not be added to asset URLs. * The index file will not be added to asset URLs. If the HTTPS option is not
* specified, HTTPS will be used when the active request is also using HTTPS.
*
* <code>
* // Generate the URL: http://example.com/img/picture.jpg
* $url = URL::to_asset('img/picture.jpg');
*
* // Generate the URL: https://example.com/img/picture.jpg
* $url = URL::to_asset('img/picture.jpg', true);
* </code>
* *
* @param string $url * @param string $url
* @param bool $https
* @return string * @return string
*/ */
public function to_asset($url) public static function to_asset($url, $https = null)
{ {
return str_replace('index.php/', '', $this->to($url, IoC::resolve('laravel.request')->is_secure())); if (is_null($https)) $https = IoC::resolve('laravel.request')->is_secure();
return str_replace('index.php/', '', static::to($url, $https));
} }
/** /**
...@@ -55,12 +74,14 @@ class URL { ...@@ -55,12 +74,14 @@ class URL {
* For routes that have wildcard parameters, an array may be passed as the second parameter to the method. * For routes that have wildcard parameters, an array may be passed as the second parameter to the method.
* The values of this array will be used to fill the wildcard segments of the route URI. * The values of this array will be used to fill the wildcard segments of the route URI.
* *
* Optional parameters will be convereted to spaces if no parameter values are specified.
*
* <code> * <code>
* // Generate a URL for the "profile" named route * // Generate a URL for the "profile" named route
* $url = $url->to_route('profile'); * $url = URL::to_route('profile');
* *
* // Generate a URL for the "profile" named route with parameters. * // Generate a URL for the "profile" named route with parameters.
* $url = $url->to_route('profile', array('fred')); * $url = URL::to_route('profile', array('fred'));
* </code> * </code>
* *
* @param string $name * @param string $name
...@@ -68,9 +89,11 @@ class URL { ...@@ -68,9 +89,11 @@ class URL {
* @param bool $https * @param bool $https
* @return string * @return string
*/ */
public function to_route($name, $parameters = array(), $https = false) public static function to_route($name, $parameters = array(), $https = false)
{ {
if ( ! is_null($route = Routing\Finder::find($name, Routing\Loader::all()))) $router = IoC::container()->resolve('laravel.routing.router');
if ( ! is_null($route = $router->find($name)))
{ {
$uris = explode(', ', key($route)); $uris = explode(', ', key($route));
...@@ -81,9 +104,7 @@ class URL { ...@@ -81,9 +104,7 @@ class URL {
$uri = preg_replace('/\(.+?\)/', $parameter, $uri, 1); $uri = preg_replace('/\(.+?\)/', $parameter, $uri, 1);
} }
$uri = str_replace(array('/(:any?)', '/(:num?)'), '', $uri); return static::to(str_replace(array('/(:any?)', '/(:num?)'), '', $uri), $https);
return $this->to($uri, $https);
} }
throw new \Exception("Error generating named route for route [$name]. Route is not defined."); throw new \Exception("Error generating named route for route [$name]. Route is not defined.");
...@@ -94,16 +115,16 @@ class URL { ...@@ -94,16 +115,16 @@ class URL {
* *
* <code> * <code>
* // Generate a HTTPS URL for the "profile" named route * // Generate a HTTPS URL for the "profile" named route
* $url = $url->to_secure_route('profile'); * $url = URL::to_secure_route('profile');
* </code> * </code>
* *
* @param string $name * @param string $name
* @param array $parameters * @param array $parameters
* @return string * @return string
*/ */
public function to_secure_route($name, $parameters = array()) public static function to_secure_route($name, $parameters = array())
{ {
return $this->to_route($name, $parameters, true); return static::to_route($name, $parameters, true);
} }
/** /**
...@@ -111,17 +132,17 @@ class URL { ...@@ -111,17 +132,17 @@ class URL {
* *
* <code> * <code>
* // Returns "my-first-post" * // Returns "my-first-post"
* $slug = $url->slug('My First Post!!'); * $slug = URL::slug('My First Post!!');
* *
* // Returns "my_first_post" * // Returns "my_first_post"
* $slug = $url->slug('My First Post!!', '_'); * $slug = URL::slug('My First Post!!', '_');
* </code> * </code>
* *
* @param string $title * @param string $title
* @param string $separator * @param string $separator
* @return string * @return string
*/ */
public function slug($title, $separator = '-') public static function slug($title, $separator = '-')
{ {
$title = Str::ascii($title); $title = Str::ascii($title);
...@@ -139,27 +160,27 @@ class URL { ...@@ -139,27 +160,27 @@ class URL {
* *
* <code> * <code>
* // Generate a URL for the "profile" named route * // Generate a URL for the "profile" named route
* $url = $url->to_profile(); * $url = URL::to_profile();
* *
* // Generate a URL for the "profile" named route using HTTPS * // Generate a URL for the "profile" named route using HTTPS
* $url = $url->to_secure_profile(); * $url = URL::to_secure_profile();
* *
* // Generate a URL for the "profile" named route with parameters. * // Generate a URL for the "profile" named route with parameters.
* $url = $url->to_profile(array('fred')); * $url = URL::to_profile(array('fred'));
* </code> * </code>
*/ */
public function __call($method, $parameters) public static function __callStatic($method, $parameters)
{ {
$parameters = (isset($parameters[0])) ? $parameters[0] : array(); $parameters = (isset($parameters[0])) ? $parameters[0] : array();
if (strpos($method, 'to_secure_') === 0) if (strpos($method, 'to_secure_') === 0)
{ {
return $this->to_route(substr($method, 10), $parameters, true); return static::to_route(substr($method, 10), $parameters, true);
} }
if (strpos($method, 'to_') === 0) if (strpos($method, 'to_') === 0)
{ {
return $this->to_route(substr($method, 3), $parameters); return static::to_route(substr($method, 3), $parameters);
} }
throw new \Exception("Method [$method] is not defined on the URL class."); throw new \Exception("Method [$method] is not defined on the URL class.");
......
<?php namespace Laravel; <?php namespace Laravel\Validation;
class Messages { class Messages {
......
<?php namespace Laravel; <?php namespace Laravel\Validation;
use Laravel\Lang;
use Laravel\DB\Manager as DB;
class Validator { class Validator {
...@@ -26,7 +29,7 @@ class Validator { ...@@ -26,7 +29,7 @@ class Validator {
/** /**
* The post-validation error messages. * The post-validation error messages.
* *
* @var array * @var Messages
*/ */
public $errors; public $errors;
...@@ -143,7 +146,9 @@ class Validator { ...@@ -143,7 +146,9 @@ class Validator {
if ( ! $this->$validator($attribute, $parameters)) if ( ! $this->$validator($attribute, $parameters))
{ {
$this->errors->add($attribute, $this->format_message($this->get_message($attribute, $rule), $attribute, $rule, $parameters)); $message = $this->format_message($this->get_message($attribute, $rule);
$this->errors->add($attribute, $message, $attribute, $rule, $parameters));
} }
} }
...@@ -170,7 +175,11 @@ class Validator { ...@@ -170,7 +175,11 @@ class Validator {
*/ */
protected function validate_confirmed($attribute) protected function validate_confirmed($attribute)
{ {
return array_key_exists($attribute.'_confirmation', $this->attributes) and $this->attributes[$attribute] == $this->attributes[$attribute.'_confirmation']; $value = $this->attributes[$attribute];
$confirmation = $this->attributes[$attribute.'_confirmation'];
return array_key_exists($attribute.'_confirmation', $this->attributes) and $value == $confirmation;
} }
/** /**
...@@ -183,7 +192,9 @@ class Validator { ...@@ -183,7 +192,9 @@ class Validator {
*/ */
protected function validate_accepted($attribute) protected function validate_accepted($attribute)
{ {
return static::validate_required($attribute) and ($this->attributes[$attribute] == 'yes' or $this->attributes[$attribute] == '1'); $value = $this->attributes[$attribute];
return static::validate_required($attribute) and ($value == 'yes' or $value == '1');
} }
/** /**
...@@ -269,7 +280,9 @@ class Validator { ...@@ -269,7 +280,9 @@ class Validator {
return $this->attributes[$attribute]; return $this->attributes[$attribute];
} }
return (array_key_exists($attribute, $_FILES)) ? $this->attributes[$attribute]['size'] / 1024 : Str::length(trim($this->attributes[$attribute])); $value = $this->attributes[$attribute];
return (array_key_exists($attribute, $_FILES)) ? $value['size'] / 1024 : Str::length(trim($value));
} }
/** /**
...@@ -402,9 +415,11 @@ class Validator { ...@@ -402,9 +415,11 @@ class Validator {
*/ */
protected function validate_mimes($attribute, $parameters) protected function validate_mimes($attribute, $parameters)
{ {
$file = IoC::container()->resolve('laravel.file');
foreach ($parameters as $extension) foreach ($parameters as $extension)
{ {
if (File::is($extension, $this->attributes[$attribute]['tmp_name'])) return true; if ($file->is($extension, $this->attributes[$attribute]['tmp_name'])) return true;
} }
return false; return false;
......
...@@ -10,7 +10,7 @@ class View implements Renderable { ...@@ -10,7 +10,7 @@ class View implements Renderable {
public $view; public $view;
/** /**
* The view name with dots replaced with slashes. * The view name with dots replaced by slashes.
* *
* @var string * @var string
*/ */
...@@ -23,32 +23,24 @@ class View implements Renderable { ...@@ -23,32 +23,24 @@ class View implements Renderable {
*/ */
public $data = array(); public $data = array();
/**
* The module that contains the view.
*
* @var string
*/
public $module;
/**
* The defined view composers.
*
* @var array
*/
public static $composers;
/** /**
* Create a new view instance. * Create a new view instance.
* *
* @param string $view * @param string $view
* @param array $data * @param array $data
* @param string $path
* @return void * @return void
*/ */
public function __construct($view, $data = array()) public function __construct($view, $data = array(), $path = VIEW_PATH)
{ {
$this->view = $view; $this->view = $view;
$this->data = $data; $this->data = $data;
$this->path = str_replace('.', '/', $view); $this->path = $path.str_replace('.', '/', $view).EXT;
if ( ! file_exists($this->path))
{
throw new \Exception('View ['.$this->path.'] does not exist.');
}
} }
/** /**
...@@ -56,11 +48,12 @@ class View implements Renderable { ...@@ -56,11 +48,12 @@ class View implements Renderable {
* *
* @param string $view * @param string $view
* @param array $data * @param array $data
* @param string $path
* @return View * @return View
*/ */
public static function make($view, $data = array()) public static function make($view, $data = array(), $path = VIEW_PATH)
{ {
return new static($view, $data); return new static($view, $data, $path);
} }
/** /**
...@@ -72,9 +65,9 @@ class View implements Renderable { ...@@ -72,9 +65,9 @@ class View implements Renderable {
*/ */
protected static function of($name, $data = array()) protected static function of($name, $data = array())
{ {
if (is_null(static::$composers)) static::$composers = require APP_PATH.'composers'.EXT; $composers = IoC::container()->resolve('laravel.composers');
foreach (static::$composers as $key => $value) foreach ($composers as $key => $value)
{ {
if ($name === $value or (isset($value['name']) and $name === $value['name'])) if ($name === $value or (isset($value['name']) and $name === $value['name']))
{ {
...@@ -92,11 +85,11 @@ class View implements Renderable { ...@@ -92,11 +85,11 @@ class View implements Renderable {
*/ */
protected function compose() protected function compose()
{ {
if (is_null(static::$composers)) static::$composers = require APP_PATH.'composers'.EXT; $composers = IoC::container()->resolve('laravel.composers');
if (isset(static::$composers[$this->view])) if (isset($composers[$this->view]))
{ {
foreach ((array) static::$composers[$this->view] as $key => $value) foreach ((array) $composers[$this->view] as $key => $value)
{ {
if (is_callable($value)) return call_user_func($value, $this); if (is_callable($value)) return call_user_func($value, $this);
} }
...@@ -106,17 +99,15 @@ class View implements Renderable { ...@@ -106,17 +99,15 @@ class View implements Renderable {
/** /**
* Get the evaluated string content of the view. * Get the evaluated string content of the view.
* *
* If the view has a composer, it will be executed. All sub-views and responses will
* also be evaluated and converted to their string values.
*
* @return string * @return string
*/ */
public function render() public function render()
{ {
$this->compose(); $this->compose();
if ( ! file_exists(VIEW_PATH.$this->path.EXT))
{
Exception\Handler::make(new Exception('View ['.$this->path.'] does not exist.'))->handle();
}
foreach ($this->data as &$data) foreach ($this->data as &$data)
{ {
if ($data instanceof Renderable) $data = $data->render(); if ($data instanceof Renderable) $data = $data->render();
...@@ -124,7 +115,14 @@ class View implements Renderable { ...@@ -124,7 +115,14 @@ class View implements Renderable {
ob_start() and extract($this->data, EXTR_SKIP); ob_start() and extract($this->data, EXTR_SKIP);
try { include VIEW_PATH.$this->path.EXT; } catch (\Exception $e) { Exception\Handler::make($e)->handle(); } try
{
include $this->path;
}
catch (\Exception $e)
{
Exception\Handler::make(new Exception\Examiner($e, new File))->handle();
}
return ob_get_clean(); return ob_get_clean();
} }
...@@ -136,8 +134,8 @@ class View implements Renderable { ...@@ -136,8 +134,8 @@ class View implements Renderable {
* // Bind the view "partial/login" to the view * // Bind the view "partial/login" to the view
* View::make('home')->partial('login', 'partial/login'); * View::make('home')->partial('login', 'partial/login');
* *
* // Equivalent binding using the "bind" method * // Equivalent binding using the "with" method
* View::make('home')->bind('login', View::make('partials/login')); * View::make('home')->with('login', View::make('partials/login'));
* </code> * </code>
* *
* @param string $key * @param string $key
...@@ -147,7 +145,7 @@ class View implements Renderable { ...@@ -147,7 +145,7 @@ class View implements Renderable {
*/ */
public function partial($key, $view, $data = array()) public function partial($key, $view, $data = array())
{ {
return $this->bind($key, new static($view, $data)); return $this->with($key, new static($view, $data));
} }
/** /**
...@@ -157,14 +155,14 @@ class View implements Renderable { ...@@ -157,14 +155,14 @@ class View implements Renderable {
* *
* <code> * <code>
* // Bind a "name" value to the view * // Bind a "name" value to the view
* View::make('home')->bind('name', 'Fred'); * View::make('home')->with('name', 'Fred');
* </code> * </code>
* *
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return View * @return View
*/ */
public function bind($key, $value) public function with($key, $value)
{ {
$this->data[$key] = $value; $this->data[$key] = $value;
return $this; return $this;
...@@ -202,7 +200,7 @@ class View implements Renderable { ...@@ -202,7 +200,7 @@ class View implements Renderable {
*/ */
public function __set($key, $value) public function __set($key, $value)
{ {
$this->bind($key, $value); $this->with($key, $value);
} }
/** /**
......
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