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

refactoring for dependency injection and testability.

parent 0b86c945
......@@ -19,21 +19,23 @@ return array(
*/
'Asset' => 'Laravel\\Asset',
'Auth' => 'Laravel\\Auth',
'Auth' => 'Laravel\\Security\\Authenticator',
'Benchmark' => 'Laravel\\Benchmark',
'Cache' => 'Laravel\\Cache',
'Cache' => 'Laravel\\Cache\\Manager',
'Config' => 'Laravel\\Config',
'Cookie' => 'Laravel\\Cookie',
'Crypter' => 'Laravel\\Crypter',
'DB' => 'Laravel\\DB',
'Crypter' => 'Laravel\\Security\\Crypter',
'DB' => 'Laravel\\Database\\Manager',
'Download' => 'Laravel\\Download',
'Eloquent' => 'Laravel\\DB\\Eloquent\\Model',
'Eloquent' => 'Laravel\\Database\\Eloquent\\Model',
'Error' => 'Laravel\\Error',
'File' => 'Laravel\\File',
'Form' => 'Laravel\\Form',
'Hasher' => 'Laravel\\Hasher',
'Hasher' => 'Laravel\\Security\\Hasher',
'HTML' => 'Laravel\\HTML',
'Inflector' => 'Laravel\\Inflector',
'Input' => 'Laravel\\Input',
'IoC' => 'Laravel\\IoC',
'Lang' => 'Laravel\\Lang',
'Loader' => 'Laravel\\Loader',
'Package' => 'Laravel\\Package',
......@@ -41,9 +43,9 @@ return array(
'Redirect' => 'Laravel\\Redirect',
'Request' => 'Laravel\\Request',
'Response' => 'Laravel\\Response',
'Session' => 'Laravel\\Session',
'Session' => 'Laravel\\Session\\Manager',
'Str' => 'Laravel\\Str',
'Validator' => 'Laravel\\Validator',
'Validator' => 'Laravel\\Validation\\Validator',
'View' => 'Laravel\\View',
);
\ No newline at end of file
......@@ -52,7 +52,9 @@ return array(
'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(
|
*/
'before' => function($method, $uri)
'before' => function(Laravel\Request $request)
{
// 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.
},
......@@ -62,7 +62,7 @@ return array(
'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;
use Laravel\File;
use Laravel\HTML;
class Asset {
/**
......@@ -36,7 +33,7 @@ class Asset {
{
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];
......@@ -81,15 +78,24 @@ class Asset_Container {
*/
public $assets = array();
/**
* The file manager instance.
*
* @var File
*/
private $file;
/**
* Create a new asset container instance.
*
* @param string $name
* @param File $file
* @return void
*/
public function __construct($name)
public function __construct($name, File $file)
{
$this->name = $name;
$this->file = $file;
}
/**
......@@ -119,7 +125,7 @@ class Asset_Container {
*/
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);
}
......
<?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 {
/**
* The File cache engine.
* The file manager instance.
*
* @var File_Engine
* @var Laravel\File
*/
private $file;
/**
* Create a new File cache driver instance.
*
* @param File_Engine $file
* @param Laravel\File $file
* @return void
*/
public function __construct(File_Engine $file)
public function __construct(\Laravel\File $file)
{
$this->file = $file;
}
......@@ -134,7 +80,7 @@ class File extends Driver {
*/
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.
......@@ -32,20 +35,12 @@ class Cache {
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.");
}
return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.'.$driver);
}
return static::$drivers[$driver];
......
......@@ -45,7 +45,7 @@ class Config {
* $timezone = Config::get('application.timezone');
*
* // Get the SQLite database connection configuration
* $sqlite = Config::get('db.connections.sqlite');
* $sqlite = Config::get('database.connections.sqlite');
* </code>
*
* @param string $key
......
......@@ -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()
{
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 @@
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.
*
* @param string $name
* @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 {
* @param mixed $default
* @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 {
* @param bool $http_only
* @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 {
* @param bool $http_only
* @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]);
......@@ -67,9 +85,9 @@ class Cookie {
* @param string $name
* @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 {
......
<?php namespace Laravel\DB;
<?php namespace Laravel\Database;
use PDO;
abstract class Connector {
......@@ -8,11 +10,11 @@ abstract class Connector {
* @var array
*/
public $options = array(
\PDO::ATTR_CASE => \PDO::CASE_LOWER,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL,
\PDO::ATTR_STRINGIFY_FETCHES => false,
\PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_CASE => PDO::CASE_LOWER,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,
);
/**
......
<?php namespace Laravel\DB\Eloquent;
<?php namespace Laravel\Database\Eloquent;
class Hydrator {
......@@ -50,8 +50,15 @@ class Hydrator {
$model->exists = true;
if (isset($model->attributes['id']))
{
$models[$model->id] = $model;
}
else
{
$models[] = $model;
}
}
return $models;
}
......
<?php namespace Laravel\DB\Eloquent;
<?php namespace Laravel\Database\Eloquent;
use Laravel\DB;
use Laravel\IoC;
use Laravel\Str;
use Laravel\Config;
use Laravel\Inflector;
use Laravel\Paginator;
use Laravel\Database\Manager;
abstract class Model {
......@@ -135,7 +135,7 @@ abstract class Model {
// Since this method is only used for instantiating models for querying
// 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;
}
......@@ -189,44 +189,24 @@ abstract class Model {
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
*
* @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 Paginator
* @return array
*/
private function _paginate($per_page = null, $columns = array('*'))
{
$total = $this->query->count();
if (is_null($per_page))
private function _get()
{
$per_page = (property_exists(get_class($this), 'per_page')) ? static::$per_page : 20;
}
return Paginator::make($this->select($columns)->for_page(Paginator::page($total, $per_page), $per_page)->get(), $total, $per_page);
return Hydrator::hydrate($this);
}
/**
......@@ -369,7 +349,7 @@ abstract class Model {
// 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.
$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)
{
......@@ -418,7 +398,7 @@ abstract class Model {
// delete statement to the query instance.
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 {
// 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
// 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);
}
......
<?php namespace Laravel;
<?php namespace Laravel\Database;
class DB {
use Laravel\Config;
class Manager {
/**
* The established database connections.
......@@ -24,22 +26,22 @@ class DB {
* </code>
*
* @param string $connection
* @return DB\Connection
* @return Database\Connection
*/
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 (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.");
}
$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];
......@@ -63,7 +65,7 @@ class DB {
*
* @param string $table
* @param string $connection
* @return DB\Query
* @return Database\Query
*/
public static function table($table, $connection = null)
{
......
<?php namespace Laravel\DB;
<?php namespace Laravel\Database;
use Laravel\IoC;
use Laravel\Str;
use Laravel\Config;
use Laravel\Request;
use Laravel\Paginator;
class Query {
......@@ -505,6 +505,27 @@ class Query {
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.
*
......@@ -554,36 +575,6 @@ class Query {
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.
*
......
<?php namespace Laravel\DB\Query;
<?php namespace Laravel\Database\Query;
use Laravel\DB\Query;
use Laravel\Database\Query;
class Compiler {
......
<?php namespace Laravel\DB\Query\Compiler;
<?php namespace Laravel\Database\Query\Compiler;
use Laravel\DB\Connection;
use Laravel\DB\Query\Compiler;
use Laravel\Database\Connection;
use Laravel\Database\Query\Compiler;
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 {
......
<?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 {
......
<?php namespace Laravel\DB\Query;
<?php namespace Laravel\Database\Query;
use Laravel\DB\Query;
use Laravel\DB\Connection;
use Laravel\Database\Query;
use Laravel\Database\Connection;
class Factory {
......
<?php namespace Laravel\DB\Query;
<?php namespace Laravel\Database\Query;
use Laravel\DB\Query;
use Laravel\Database\Query;
class Postgres extends Query {
......
......@@ -20,16 +20,18 @@ class Download extends Response {
{
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-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-Transfer-Encoding', 'binary');
$this->header('Expires', 0);
$this->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
$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 {
*/
public $exception;
/**
* The file manager instance.
*
* @var File
*/
private $file;
/**
* Human-readable error levels and descriptions.
*
......@@ -35,12 +42,14 @@ class Examiner {
/**
* Create a new exception examiner instance.
*
* @param Exception $e
* @param Exception $exception
* @param File $file
* @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 {
*/
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 {
*
* @var Examiner
*/
public $exception;
public $examiner;
/**
* Create a new exception handler instance.
*
* @param Exception $e
* @param Examiner $examiner
* @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.
*
* @param Exception $e
* @param Examiner $examiner
* @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 {
*/
private function log()
{
$parameters = array(
$this->exception->severity(),
$this->exception->message(),
$this->exception->getTraceAsString(),
);
$parameters = array($this->examiner->severity(), $this->examiner->message(), $this->examiner->getTraceAsString());
call_user_func_array(Config::get('error.logger'), $parameters);
}
......@@ -83,7 +79,7 @@ class Handler {
*/
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 {
private function detailed_response()
{
$data = array(
'severity' => $this->exception->severity(),
'message' => $this->exception->message(),
'line' => $this->exception->getLine(),
'trace' => $this->exception->getTraceAsString(),
'contexts' => $this->exception->context(),
'severity' => $this->examiner->severity(),
'message' => $this->examiner->message(),
'line' => $this->examiner->getLine(),
'trace' => $this->examiner->getTraceAsString(),
'contexts' => $this->examiner->context(),
);
return Response::make(View::make('error.exception', $data), 500);
......
......@@ -2,13 +2,24 @@
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.
*
* @param string $path
* @return string
*/
public static function get($path)
public function get($path)
{
return file_get_contents($path);
}
......@@ -20,7 +31,7 @@ class File {
* @param string $data
* @return int
*/
public static function put($path, $data)
public function put($path, $data)
{
return file_put_contents($path, $data, LOCK_EX);
}
......@@ -32,22 +43,66 @@ class File {
* @param string $data
* @return int
*/
public static function append($path, $data)
public function append($path, $data)
{
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.
*
* @param string $path
* @return string
*/
public static function extension($path)
public function extension($path)
{
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.
*
......@@ -55,7 +110,7 @@ class File {
*
* <code>
* // 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>
*
* @param string $path
......@@ -63,7 +118,7 @@ class File {
* @param int $padding
* @return array
*/
public static function snapshot($path, $line, $padding = 5)
public function snapshot($path, $line, $padding = 5)
{
if ( ! file_exists($path)) return array();
......@@ -85,14 +140,14 @@ class File {
*
* <code>
* // Returns "application/x-tar"
* $mime = File::mime('tar');
* $mime = $file->mime('tar');
* </code>
*
* @param string $extension
* @param string $default
* @return string
*/
public static function mime($extension, $default = 'application/octet-stream')
public function mime($extension, $default = 'application/octet-stream')
{
$mimes = Config::get('mimes');
......@@ -109,14 +164,14 @@ class File {
*
* <code>
* // 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>
*
* @param string $extension
* @param string $path
* @return bool
*/
public static function is($extension, $path)
public function is($extension, $path)
{
$mimes = Config::get('mimes');
......
......@@ -75,9 +75,9 @@ class Form {
*/
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 {
/**
* 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
*/
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));
}
......@@ -150,16 +147,11 @@ class Form {
/**
* 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
*/
public static function raw_token(Session\Driver $driver = null)
public static function raw_token()
{
if (is_null($driver)) $driver = Session::driver();
return $driver->get('csrf_token');
return IoC::container()->resolve('laravel.session.driver')->get('csrf_token');
}
/**
......@@ -449,7 +441,7 @@ class Form {
*/
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);
}
......
......@@ -24,9 +24,9 @@ class HTML {
*/
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 {
$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 {
*/
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 {
*/
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 {
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 {
{
$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 {
*/
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 {
public $post;
/**
* The $_COOKIE array for the request.
* The cookie manager instance.
*
* @var array
* @var Cookie
*/
public $cookies;
......@@ -40,31 +40,21 @@ class Input {
/**
* Create a new Input instance.
*
* @param Request $request
* @param string $method
* @param bool $spoofed
* @param array $get
* @param array $post
* @param array $cookies
* @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->post = $post;
$this->files = $files;
$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')
{
$this->input = $this->get;
......@@ -138,8 +128,6 @@ class Input {
/**
* Get input data from the previous request.
*
* If no session driver is provided, the default driver will be used.
*
* <code>
* // Get the "name" item from the old input data
* $name = Request::active()->input->old('name');
......@@ -147,12 +135,11 @@ class Input {
*
* @param string $key
* @param mixed $default
* @param Session\Driver $driver
* @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);
}
......
......@@ -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 {
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.
*
......@@ -123,7 +104,9 @@ class Lang {
/**
* 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
* @return array
......@@ -168,6 +151,25 @@ class Lang {
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.
*/
......
<?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);
// --------------------------------------------------------------
define('CACHE_PATH', STORAGE_PATH.'cache/');
define('CONFIG_PATH', APP_PATH.'config/');
define('CONTROLLER_PATH', APP_PATH.'controllers/');
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('SESSION_PATH', STORAGE_PATH.'sessions/');
define('STYLE_PATH', PUBLIC_PATH.'css/');
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/');
// --------------------------------------------------------------
......@@ -45,6 +46,13 @@ Loader::bootstrap(Config::get('aliases'), array(APP_PATH.'libraries/', APP_PATH.
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.
// --------------------------------------------------------------
......@@ -66,14 +74,16 @@ set_exception_handler(function($e) use ($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)
{
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)
......@@ -82,9 +92,9 @@ register_shutdown_function(function() use ($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'));
// --------------------------------------------------------------
// 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.'routing/route'.EXT;
require SYS_PATH.'routing/router'.EXT;
require SYS_PATH.'routing/loader'.EXT;
require SYS_PATH.'routing/filter'.EXT;
// --------------------------------------------------------------
// Bootstrap the IoC container.
// --------------------------------------------------------------
IoC::bootstrap(Config::get('dependencies'));
require SYS_PATH.'routing/handler'.EXT;
// --------------------------------------------------------------
// 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.
......@@ -127,44 +133,19 @@ if (count(Config::get('application.packages')) > 0)
// --------------------------------------------------------------
$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);
// --------------------------------------------------------------
// Register the filters for the default module.
// --------------------------------------------------------------
Routing\Filter::register(require APP_PATH.'filters'.EXT);
// --------------------------------------------------------------
// Call the "before" filter for the application and module.
// Hydrate the input for the current request.
// --------------------------------------------------------------
$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.
// --------------------------------------------------------------
if (is_null($response))
{
$loader = new Routing\Loader(APP_PATH);
$route = IoC::container()->resolve('laravel.routing.router')->route();
$route = Routing\Router::make($request, $loader)->route();
$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()));
$response = ( ! is_null($route)) ? IoC::container()->resolve('laravel.routing.handler')->handle($route) : new Error('404');
// --------------------------------------------------------------
// Stringify the response.
......@@ -176,7 +157,7 @@ $response->content = $response->render();
// --------------------------------------------------------------
if (Config::get('session.driver') != '')
{
$driver = Session::driver();
$driver = Session\Manager::driver();
$driver->flash('laravel_old_input', $request->input->get());
......
......@@ -23,13 +23,14 @@ class Package {
* </code>
*
* @param string|array $packages
* @param string $path
* @return void
*/
public static function load($packages)
public static function load($packages, $path = PACKAGE_PATH)
{
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;
}
......
<?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 {
*/
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')
{
return static::make('', $status)->header('Refresh', '0;url='.$url);
return parent::__construct('', $status)->header('Refresh', '0;url='.$url);
}
else
{
return static::make('', $status)->header('Location', $url);
return parent::__construct('', $status)->header('Location', $url);
}
}
......@@ -66,14 +66,11 @@ class Redirect extends Response {
*
* @param string $key
* @param mixed $value
* @param Session\Driver $driver
* @return Response
*/
public function with($key, $value, Session\Driver $driver)
public function with($key, $value)
{
if (is_null($driver)) $driver = Session::driver();
$driver->flash($key, $value);
IoC::container()->resolve('laravel.session.driver')->flash($key, $value);
return $this;
}
......@@ -93,16 +90,14 @@ class Redirect extends Response {
{
$parameters = (isset($parameters[0])) ? $parameters[0] : array();
$url = IoC::container()->resolve('laravel.url');
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)
{
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.");
......
......@@ -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 {
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.
*
* 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
*/
public function render()
......@@ -157,14 +129,14 @@ class Response implements Renderable {
/**
* 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
*/
public function send()
{
if ( ! array_key_exists('Content-Type', $this->headers))
{
$this->header('Content-Type', 'text/html; charset=utf-8');
}
if ( ! isset($this->headers['Content-Type'])) $this->header('Content-Type', 'text/html; charset=utf-8');
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;
use Laravel\Package;
use Laravel\Response;
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
* @param array $parameters
* @return Response
* @return array
*/
public function call()
{
$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))
public function before()
{
$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()))
{
$response = call_user_func_array($handler, $this->parameters);
}
}
$response = Response::prepare($response);
if (is_array($this->callback) and isset($this->callback['after']))
/**
* Get all of the "after" filters defined for the route.
*
* @return array
*/
public function after()
{
Filter::call($this->callback['after'], array($response));
}
return $response;
return $this->filters('after');
}
/**
* 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.
* Otherwise, we will return the first callable array value.
* <code>
* // 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'];
foreach ($this->callback as $value)
{
if (is_callable($value)) return $value;
}
return (is_array($this->callback) and isset($this->callback[$name])) ? explode(', ', $this->callback[$name]) : array();
}
}
\ No newline at end of file
......@@ -5,14 +5,7 @@ use Laravel\Request;
class Router {
/**
* The request method and URI.
*
* @var string
*/
public $destination;
/**
* All of the loaded routes.
* All of the routes available to the router.
*
* @var array
*/
......@@ -23,58 +16,81 @@ class Router {
*
* @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.
*
* @param Request $request
* @param Loader $loader
* @param array $routes
* @return void
*/
public function __construct(Request $request, Loader $loader)
public function __construct(Request $request, $routes)
{
$this->loader = $loader;
$this->routes = $routes;
$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
* @param Loader $loader
* @return Router
* The returned array will be identical the array defined in the routes.php file.
*
* <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
*/
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
// 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)
......@@ -85,11 +101,73 @@ class Router {
{
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 {
* @param string $key
* @return string
*/
private function translate_wildcards($key)
protected function translate_wildcards($key)
{
$replacements = 0;
......@@ -123,7 +201,7 @@ class Router {
* @param string $route
* @return array
*/
private function parameters($uri, $route)
protected function parameters($uri, $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.
......@@ -24,7 +28,7 @@ class Auth {
/**
* The hashing engine that should be used to perform hashing.
*
* @var Hash\Engine
* @var Hashing\Engine
*/
protected $hasher;
......@@ -39,10 +43,10 @@ class Auth {
* Create a new Auth class instance.
*
* @param Session\Driver $driver
* @param Hash\Engine $hasher
* @param Hashing\Engine $hasher
* @return void
*/
public function __construct(Session\Driver $driver, Hash\Engine $hasher)
public function __construct(Driver $driver, Hashing\Engine $hasher)
{
$this->hasher = $hasher;
$this->session = $driver;
......@@ -53,17 +57,11 @@ class Auth {
*
* If no session driver or hasher is provided, the default implementations will be used.
*
* @param Session\Driver $driver
* @param Hash\Engine $hasher
* @return void
* @return Auth
*/
public static function make(Session\Driver $driver = null, Hash\Engine $hasher = null)
public static function make()
{
if (is_null($driver)) $driver = Session::driver();
if (is_null($hasher)) $hasher = Hasher::make();
return new static($driver, $hasher);
return IoC::container()->resolve('laravel.security.auth');
}
/**
......
<?php namespace Laravel;
<?php namespace Laravel\Security;
use Laravel\Config;
class Crypter {
......@@ -31,7 +33,7 @@ class Crypter {
* @param string $key
* @return void
*/
public function __construct($cipher, $mode, $key)
public function __construct($cipher = MCRYPT_RIJNDAEL_256, $mode = 'cbc', $key = null)
{
$this->cipher = $cipher;
$this->mode = $mode;
......
<?php namespace Laravel\Hash;
<?php namespace Laravel\Security\Hashing;
#
# Portable PHP password hashing framework.
#
......
<?php namespace Laravel\Hash;
<?php namespace Laravel\Security\Hashing;
interface Engine {
......
<?php namespace Laravel;
<?php namespace Laravel\Security\Hashing;
class Hasher {
......@@ -14,12 +14,12 @@ class Hasher {
*
* If no hashing engine is provided, the BCrypt engine will be used.
*
* @param Hash\Engine $engine
* @param Engine $engine
* @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 {
*
* If no hashing engine is provided, the BCrypt engine will be used.
*
* @param Hash\Engine $engine
* @param Engine $engine
* @return Hasher
*/
public static function make(Hash\Engine $engine = null)
public static function make(Engine $engine = null)
{
return new static($engine);
}
......
<?php namespace Laravel\Session;
use Laravel\Cache;
use Laravel\Config;
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)
{
return Cache::driver('apc')->get($id);
return $this->apc->get($id);
}
/**
* Save the session to persistant storage.
*
* @return void
*/
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()
{
Cache::driver('apc')->forget($this->session['id']);
$this->apc->forget($this->session['id']);
}
}
\ No newline at end of file
<?php namespace Laravel\Session;
use Laravel\Config;
use Laravel\Crypter;
use Laravel\Security\Crypter;
class Cookie extends Driver {
/**
* The cookie engine instance.
*
* @var Cookie_Engine
*/
private $cookie;
/**
* The Crypter instance.
*
......@@ -15,11 +22,14 @@ class Cookie extends Driver {
/**
* Create a new Cookie session driver instance.
*
* @param Crypter $crypter
* @param Cookie $cookie
* @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') == '')
{
......@@ -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)
{
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()
{
if ( ! headers_sent())
......@@ -43,13 +67,18 @@ class Cookie extends Driver {
$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()
{
\System\Cookie::forget('session_payload');
$this->cookie->forget('session_payload');
}
}
\ No newline at end of file
<?php namespace Laravel\Session;
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)
{
$session = $this->table()->find($id);
......@@ -18,6 +46,11 @@ class DB extends Driver implements Sweeper {
}
}
/**
* Save the session to persistant storage.
*
* @return void
*/
protected function save()
{
$this->delete($this->session['id']);
......@@ -29,11 +62,22 @@ class DB extends Driver implements Sweeper {
));
}
/**
* Delete the session from persistant storage.
*
* @return void
*/
protected function delete()
{
$this->table()->delete($this->session['id']);
}
/**
* Delete all expired sessions from persistant storage.
*
* @param int $expiration
* @return void
*/
public function sweep($expiration)
{
$this->table()->where('last_activity', '<', $expiration)->delete();
......@@ -46,7 +90,7 @@ class DB extends Driver implements Sweeper {
*/
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 @@
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)
{
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()
{
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()
{
@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)
{
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.
......@@ -22,27 +24,15 @@ class Session {
{
if (is_null(static::$driver))
{
switch (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;
$driver = Config::get('session.driver');
case 'memcached':
return static::$driver = new Session\Memcached;
case 'apc':
return static::$driver = new Session\APC;
if (in_array($driver, array('cookie', 'file', 'database', 'memcached')))
{
return static::$driver = IoC::container()->resolve('laravel.session.'.$driver);
}
default:
throw new \Exception("Session driver [$driver] is not supported.");
}
}
return static::$driver;
}
......
<?php namespace Laravel\Session;
use Laravel\Cache;
use Laravel\Config;
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)
{
return Cache::driver('memcached')->get($id);
return $this->memcached->get($id);
}
/**
* Save the session to persistant storage.
*
* @return void
*/
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()
{
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 {
*
* 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 bool $https
* @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;
$base = Config::get('application.url').'/'.Config::get('application.index');
if ($https and strpos($base, 'http://') === 0)
{
$base = 'https://'.substr($base, 7);
}
if ($https) $base = preg_replace('~http://~', 'https://', $base, 1);
return rtrim($base, '/').'/'.trim($url, '/');
}
......@@ -28,25 +30,42 @@ class URL {
/**
* 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
* @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.
*
* 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 bool $https
* @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 {
* 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.
*
* Optional parameters will be convereted to spaces if no parameter values are specified.
*
* <code>
* // 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.
* $url = $url->to_route('profile', array('fred'));
* $url = URL::to_route('profile', array('fred'));
* </code>
*
* @param string $name
......@@ -68,9 +89,11 @@ class URL {
* @param bool $https
* @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));
......@@ -81,9 +104,7 @@ class URL {
$uri = preg_replace('/\(.+?\)/', $parameter, $uri, 1);
}
$uri = str_replace(array('/(:any?)', '/(:num?)'), '', $uri);
return $this->to($uri, $https);
return static::to(str_replace(array('/(:any?)', '/(:num?)'), '', $uri), $https);
}
throw new \Exception("Error generating named route for route [$name]. Route is not defined.");
......@@ -94,16 +115,16 @@ class URL {
*
* <code>
* // Generate a HTTPS URL for the "profile" named route
* $url = $url->to_secure_route('profile');
* $url = URL::to_secure_route('profile');
* </code>
*
* @param string $name
* @param array $parameters
* @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 {
*
* <code>
* // Returns "my-first-post"
* $slug = $url->slug('My First Post!!');
* $slug = URL::slug('My First Post!!');
*
* // Returns "my_first_post"
* $slug = $url->slug('My First Post!!', '_');
* $slug = URL::slug('My First Post!!', '_');
* </code>
*
* @param string $title
* @param string $separator
* @return string
*/
public function slug($title, $separator = '-')
public static function slug($title, $separator = '-')
{
$title = Str::ascii($title);
......@@ -139,27 +160,27 @@ class URL {
*
* <code>
* // 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
* $url = $url->to_secure_profile();
* $url = URL::to_secure_profile();
*
* // Generate a URL for the "profile" named route with parameters.
* $url = $url->to_profile(array('fred'));
* $url = URL::to_profile(array('fred'));
* </code>
*/
public function __call($method, $parameters)
public static function __callStatic($method, $parameters)
{
$parameters = (isset($parameters[0])) ? $parameters[0] : array();
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)
{
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.");
......
<?php namespace Laravel;
<?php namespace Laravel\Validation;
class Messages {
......
<?php namespace Laravel;
<?php namespace Laravel\Validation;
use Laravel\Lang;
use Laravel\DB\Manager as DB;
class Validator {
......@@ -26,7 +29,7 @@ class Validator {
/**
* The post-validation error messages.
*
* @var array
* @var Messages
*/
public $errors;
......@@ -143,7 +146,9 @@ class Validator {
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 {
*/
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 {
*/
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 {
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 {
*/
protected function validate_mimes($attribute, $parameters)
{
$file = IoC::container()->resolve('laravel.file');
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;
......
......@@ -10,7 +10,7 @@ class View implements Renderable {
public $view;
/**
* The view name with dots replaced with slashes.
* The view name with dots replaced by slashes.
*
* @var string
*/
......@@ -23,32 +23,24 @@ class View implements Renderable {
*/
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.
*
* @param string $view
* @param array $data
* @param string $path
* @return void
*/
public function __construct($view, $data = array())
public function __construct($view, $data = array(), $path = VIEW_PATH)
{
$this->view = $view;
$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 {
*
* @param string $view
* @param array $data
* @param string $path
* @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 {
*/
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']))
{
......@@ -92,11 +85,11 @@ class View implements Renderable {
*/
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);
}
......@@ -106,17 +99,15 @@ class View implements Renderable {
/**
* 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
*/
public function render()
{
$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)
{
if ($data instanceof Renderable) $data = $data->render();
......@@ -124,7 +115,14 @@ class View implements Renderable {
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();
}
......@@ -136,8 +134,8 @@ class View implements Renderable {
* // Bind the view "partial/login" to the view
* View::make('home')->partial('login', 'partial/login');
*
* // Equivalent binding using the "bind" method
* View::make('home')->bind('login', View::make('partials/login'));
* // Equivalent binding using the "with" method
* View::make('home')->with('login', View::make('partials/login'));
* </code>
*
* @param string $key
......@@ -147,7 +145,7 @@ class View implements Renderable {
*/
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 {
*
* <code>
* // Bind a "name" value to the view
* View::make('home')->bind('name', 'Fred');
* View::make('home')->with('name', 'Fred');
* </code>
*
* @param string $key
* @param mixed $value
* @return View
*/
public function bind($key, $value)
public function with($key, $value)
{
$this->data[$key] = $value;
return $this;
......@@ -202,7 +200,7 @@ class View implements Renderable {
*/
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