Commit 9caf239f authored by Taylor Otwell's avatar Taylor Otwell

various refactorings.

parent 128984fa
......@@ -13,8 +13,8 @@ return array(
|
| 'home.index' => array('name' => 'home')
|
| Now, you can create an instance of that view using the expressive View::of
| dynamic method. Take a look at this example:
| Now, you can create an instance of that view using the very expressive
| View::of dynamic method. Take a look at this example:
|
| return View::of_home();
|
......
......@@ -7,12 +7,12 @@ return array(
| Error Detail
|--------------------------------------------------------------------------
|
| Detailed error messages contain information about the file in which
| an error occurs, a stack trace, and a snapshot of the source code
| in which the error occured.
| Detailed error messages contain information about the file in which an
| error occurs, as well as a PHP stack trace containing the call stack.
|
| If your application is in production, consider turning off error details
| for enhanced security and user experience.
| for enhanced security and user experience. The error stack trace could
| contain sensitive information that should not be publicly visible.
|
*/
......@@ -23,9 +23,9 @@ return array(
| Error Logging
|--------------------------------------------------------------------------
|
| Error Logging will use the "logger" function defined below to log error
| messages, which gives you complete freedom to determine how error
| messages are logged. Enjoy the flexibility.
| When error logging is enabled, the "logger" Closure defined below will
| be called for every error in your application. You are free to log the
| errors however you want. Enjoy the flexibility.
|
*/
......@@ -37,23 +37,28 @@ return array(
|--------------------------------------------------------------------------
|
| Because of the various ways of managing error logging, you get complete
| flexibility in Laravel to manage error logging as you see fit.
| flexibility in Laravel to manage all error logging as you see fit.
|
| This function will be called when an error occurs in your application.
| You are free to handle the exception any way your heart desires.
|
| The error "severity" passed to the method is a human-readable severity
| level such as "Parsing Error" or "Fatal Error".
| You are free to handle the exception any way you want. The severity
| will be a human-readable severity level such as "Parsing Error".
|
*/
'handler' => function($exception, $severity, $message, $config)
{
$data = compact('exception', 'severity', 'message');
if ($config['detail'])
{
$data = compact('exception', 'severity', 'message');
$data['detailed'] = $config['detail'];
$response = Response::view('error.exception', $data)->status(500);
}
else
{
$response = Response::error('500');
}
Response::error('500', $data)->send();
$response->send();
},
/*
......@@ -62,19 +67,21 @@ return array(
|--------------------------------------------------------------------------
|
| Because of the various ways of managing error logging, you get complete
| flexibility to manage error logging as you see fit.
|
| This function will be called when an error occurs in your application
| and error loggins is enabled. You can log the error however you like.
| flexibility to manage error logging as you see fit. This function will
| be called anytime an error occurs within your application and error
| logging is enabled.
|
| A simple logging system has been setup for you. By default, all errors
| will be logged to the storage/log.txt file.
| You may log the error message however you like; however, a simple logging
| solution has been setup for you which will log all error messages to a
| single text file within the application storage directory.
|
*/
'logger' => function($exception, $severity, $message, $config)
{
File::append(STORAGE_PATH.'log.txt', date('Y-m-d H:i:s').' '.$severity.' - '.$message.PHP_EOL);
$message = date('Y-m-d H:i:s').' '.$severity.' - '.$message.PHP_EOL;
File::append(STORAGE_PATH.'log.txt', $message);
}
);
\ No newline at end of file
......@@ -50,19 +50,19 @@ return array(
'after' => function($response)
{
if (Config::get('session.driver') !== '') Input::flash();
Input::flash();
},
'auth' => function()
{
if ( ! Auth::check()) return Redirect::to_login();
if (Auth::guest()) return Redirect::to_login();
},
'csrf' => function()
{
if (Input::get('csrf_token') !== Form::raw_token()) return Response::error('500');
if (Request::forged()) return Response::error('500');
},
);
\ No newline at end of file
......@@ -10,9 +10,9 @@ return array(
| Here is the public API of your application. To add functionality to your
| application, you just add to the array of routes located in this file.
|
| Simply tell Laravel the HTTP verbs and URIs it should respond to. It is a
| breeze to create beautiful applications using the simplicity and elegance
| of Laravel's RESTful routing.
| Simply tell Laravel the HTTP verbs and URIs it should respond to. It's a
| piece of cake to create beautiful applications using the elegant RESTful
| routing available in Laravel.
|
| Let's respond to a simple GET request to http://example.com/hello:
|
......
......@@ -78,8 +78,8 @@ IoC::bootstrap();
spl_autoload_register(array('Laravel\\Autoloader', 'load'));
/**
* Define a few convenient functions to make our lives as
* developers a little more easy and enjoyable.
* Define a few global convenience functions to make our lives
* as Laravel PHP developers a little more easy and enjoyable.
*/
function e($value)
{
......
......@@ -39,16 +39,9 @@ $severity = function($e)
E_STRICT => 'Runtime Notice',
);
if (array_key_exists($e->getCode(), $levels))
{
$level = $levels[$e->getCode()];
}
else
{
$level = $e->getCode();
}
$code = $e->getCode();
return $level;
return (array_key_exists($code, $levels)) ? $levels[$code] : $code;
};
/**
......
......@@ -39,7 +39,10 @@ class APC extends Driver {
*/
protected function retrieve($key)
{
if ( ! is_null($cache = apc_fetch($this->key.$key))) return $cache;
if ( ! is_null($cache = apc_fetch($this->key.$key)))
{
return $cache;
}
}
/**
......
......@@ -47,7 +47,10 @@ class Memcached extends Driver {
*/
protected function retrieve($key)
{
if (($cache = $this->memcache->get($this->key.$key)) !== false) return $cache;
if (($cache = $this->memcache->get($this->key.$key)) !== false)
{
return $cache;
}
}
/**
......
......@@ -32,12 +32,12 @@ class Manager {
if ( ! array_key_exists($driver, static::$drivers))
{
if ( ! IoC::container()->registered('laravel.cache.'.$driver))
if ( ! IoC::container()->registered("laravel.cache.{$driver}"))
{
throw new \Exception("Cache driver [$driver] is not supported.");
}
return static::$drivers[$driver] = IoC::container()->core('cache.'.$driver);
return static::$drivers[$driver] = IoC::container()->core("cache.{$driver}");
}
return static::$drivers[$driver];
......
......@@ -2,6 +2,12 @@
return array(
'laravel.view.composers' => array('singleton' => true, 'resolver' => function()
{
return require APP_PATH.'composers'.EXT;
}),
'laravel.routing.router' => array('singleton' => true, 'resolver' => function($c)
{
return new Routing\Router($c->core('routing.loader'), CONTROLLER_PATH);
......
......@@ -3,32 +3,32 @@
class Connection {
/**
* The connection configuration array.
* The raw PDO connection instance.
*
* @var array
* @var PDO
*/
protected $config;
public $pdo;
/**
* The query grammar instance for the connection.
* All of the queries that have been executed on the connection.
*
* @var Grammars\Grammar
* @var array
*/
protected $grammar;
public $queries = array();
/**
* The raw PDO connection instance.
* The connection configuration array.
*
* @var PDO
* @var array
*/
public $pdo;
protected $config;
/**
* All of the queries that have been executed on the connection.
* The query grammar instance for the connection.
*
* @var array
* @var Grammars\Grammar
*/
public $queries = array();
protected $grammar;
/**
* Create a new database connection instance.
......@@ -112,7 +112,10 @@ class Connection {
*/
public function first($sql, $bindings = array())
{
if (count($results = $this->query($sql, $bindings)) > 0) return $results[0];
if (count($results = $this->query($sql, $bindings)) > 0)
{
return $results[0];
}
}
/**
......@@ -144,7 +147,7 @@ class Connection {
if ($value instanceof Expression) unset($bindings[$key]);
}
$sql = $this->transform(trim($sql), $bindings);
$sql = $this->transform($sql, $bindings);
$this->queries[] = compact('sql', 'bindings');
......@@ -164,23 +167,24 @@ class Connection {
*/
protected function transform($sql, $bindings)
{
if (strpos($sql, '(...)') === false) return $sql;
for ($i = 0; $i < count($bindings); $i++)
if (strpos($sql, '(...)') !== false)
{
// If the binding is an array, we can assume it is being used to fill
// a "where in" condition, so we will replace the next place-holder
// in the query with the correct number of parameters based on the
// number of elements in this binding.
if (is_array($bindings[$i]))
for ($i = 0; $i < count($bindings); $i++)
{
$parameters = implode(', ', array_fill(0, count($bindings[$i]), '?'));
$sql = preg_replace('~\(\.\.\.\)~', "({$parameters})", $sql, 1);
}
// If the binding is an array, we can assume it is being used to fill
// a "where in" condition, so we will replace the next place-holder
// in the query with the correct number of parameters based on the
// number of elements in this binding.
if (is_array($bindings[$i]))
{
$parameters = implode(', ', array_fill(0, count($bindings[$i]), '?'));
$sql = preg_replace('~\(\.\.\.\)~', "({$parameters})", $sql, 1);
}
}
}
return $sql;
return trim($sql);
}
/**
......@@ -204,8 +208,10 @@ class Connection {
{
return $statement->rowCount();
}
return $result;
else
{
return $result;
}
}
/**
......
......@@ -30,6 +30,10 @@ class SQLite extends Connector {
{
$options = $this->options($config);
// SQLite provides supported for "in-memory" databases, which exist only for the
// lifetime of the request. Any given in-memory database may only have one PDO
// connection open to it at a time. Generally, these databases are use for
// testing and development purposes, not in production scenarios.
if ($config['database'] == ':memory:')
{
return new PDO('sqlite::memory:', null, null, $options);
......
......@@ -84,7 +84,9 @@ class Grammar {
*/
protected function aggregate(Query $query)
{
return 'SELECT '.$query->aggregate['aggregator'].'('.$this->wrap($query->aggregate['column']).')';
$column = $this->wrap($query->aggregate['column']);
return 'SELECT '.$query->aggregate['aggregator'].'('.$column.')';
}
/**
......@@ -332,7 +334,7 @@ class Grammar {
* @param array $columns
* @return string
*/
public function columnize($columns)
final public function columnize($columns)
{
return implode(', ', array_map(array($this, 'wrap'), $columns));
}
......@@ -349,16 +351,29 @@ class Grammar {
*/
public function wrap($value)
{
if (strpos(strtolower($value), ' as ') !== false) return $this->alias($value);
// If the value being wrapped contains a column alias, we need to wrap
// it a little differently since each segment must be wrapped and not
// the entire string.
if (strpos(strtolower($value), ' as ') !== false)
{
return $this->alias($value);
}
// Expressions should be injected into the query as raw strings, so we
// do not want to wrap them in any way. We will just return the string
// value from the expression.
// value from the expression to be included in the query.
if ($value instanceof Expression) return $value->get();
foreach (explode('.', $value) as $segment)
{
$wrapped[] = ($segment !== '*') ? $this->wrapper.$segment.$this->wrapper : $segment;
if ($segment === '*')
{
$wrapped[] = $segment;
}
else
{
$wrapped[] = $this->wrapper.$segment.$this->wrapper;
}
}
return implode('.', $wrapped);
......
......@@ -55,6 +55,11 @@ class Manager {
*/
protected static function connect($config)
{
// We allow the developer to place a "connector" option in the database
// configuration, which should have a Closure value. If the connector
// is present, we will use the Closure to retrieve the PDO connection
// to the database. This allows the flexiblity to connect to database
// systems that are not officially supported by the the framework.
if (isset($config['connector']))
{
return call_user_func($config['connector'], $config);
......
......@@ -144,22 +144,7 @@ class Form {
*/
public static function token()
{
return static::input('hidden', 'csrf_token', static::raw_token());
}
/**
* Get the CSRF token for the current session.
*
* @return string
*/
public static function raw_token()
{
if (Config::get('session.driver') == '')
{
throw new \Exception("A session driver must be specified before using CSRF tokens.");
}
return Session::get('csrf_token');
return static::input('hidden', 'csrf_token', Session::token());
}
/**
......
......@@ -70,7 +70,10 @@ class Input {
*/
public static function flash()
{
Session::flash(Input::old_input, static::get());
if (Config::$items['session']['driver'] !== '')
{
Session::flash(Input::old_input, static::get());
}
}
/**
......
......@@ -74,7 +74,7 @@ switch (Request::method())
/**
* The spoofed request method is removed from the input so it is
* not unexpectedly included in Input::all() or Input::get().s
* not unexpectedly included in Input::all() or Input::get().
*/
unset($input[Request::spoofer]);
......
......@@ -145,6 +145,18 @@ class Request {
return isset($_SERVER['HTTPS']) and strtolower($_SERVER['HTTPS']) !== 'off';
}
/**
* Determine if the request has been forged.
*
* The session CSRF token will be compared to the CSRF token in the request input.
*
* @return bool
*/
public static function forged()
{
return Input::get('csrf_token') !== Session::token();
}
/**
* Determine if the current request is an AJAX request.
*
......
......@@ -258,7 +258,9 @@ class Response {
{
if ( ! isset($this->headers['Content-Type']))
{
$this->header('Content-Type', 'text/html; charset='.Config::$items['application']['encoding']);
$encoding = Config::$items['application']['encoding'];
$this->header('Content-Type', "text/html; charset={$encoding}");
}
header(Request::protocol().' '.$this->status.' '.$this->statuses[$this->status]);
......
......@@ -29,7 +29,19 @@ class Auth {
const remember_key = 'laravel_remember';
/**
* Determine if the current user of the application is authenticated.
* Determine if the user of the application is not logged in.
*
* This method is the inverse of the "check" method.
*
* @return bool
*/
public static function guest()
{
return ! static::check();
}
/**
* Determine if the user of the application is logged in.
*
* @return bool
*/
......
......@@ -43,17 +43,19 @@ class Hasher {
/**
* Get a salt for use during Bcrypt hashing.
*
* Bcrypt expects salts to be 22 alpha-numeric characters including
* dots and forward slashes. OpenSSL will be used if available and
* the Str::random method will be used if it isn't.
*
* @return string
*/
protected static function salt()
{
// Bcrypt expects the salt to be 22 base64 encoded characters, including dots
// and slashes. We will get rid of the plus signs included in the base64 data
// and replace them with dots. OpenSSL will be used if available, since it is
// more random, otherwise we will fallback on Str::random.
if (function_exists('openssl_random_pseudo_bytes'))
{
return substr(strtr(base64_encode(openssl_random_pseudo_bytes(16)), '+', '.'), 0 , 22);
$bytes = openssl_random_pseudo_bytes(16);
return substr(strtr(base64_encode($bytes), '+', '.'), 0 , 22);
}
return substr(str_replace('+', '.', base64_encode(Str::random(40))), 0, 22);
......
......@@ -182,6 +182,16 @@ class Session {
static::$exists = false;
}
/**
* Get the CSRF token that is stored in the session data.
*
* @return string
*/
public static function token()
{
return static::get('csrf_token');
}
/**
* Store the session payload in storage.
*
......@@ -196,9 +206,6 @@ class Session {
$config = Config::$items['session'];
// To keep the session persistence code clean, session drivers are
// responsible for the storage of the session array to the various
// available persistent storage mechanisms.
$driver->save(static::$session, $config, static::$exists);
static::cookie();
......
......@@ -24,13 +24,6 @@ class Messages {
/**
* Add a message to the collector.
*
* Duplicate messages will not be added.
*
* <code>
* // Add a message to the collector for the "email" attribute
* $messages->add('email', 'The e-mail address is invalid.');
* </code>
*
* @param string $key
* @param string $message
* @return void
......
......@@ -2,8 +2,8 @@
use Closure;
use Laravel\Arr;
use Laravel\IoC;
use Laravel\Str;
use Laravel\File;
use Laravel\Lang;
use Laravel\Input;
use Laravel\Database\Manager as DB;
......@@ -200,7 +200,9 @@ class Validator {
*/
protected function error($attribute, $rule, $parameters)
{
$message = $this->replace($this->message($attribute, $rule), $attribute, $rule, $parameters);
$message = $this->message($attribute, $rule);
$message = $this->replace($message, $attribute, $rule, $parameters);
$this->errors->add($attribute, $message);
}
......@@ -226,9 +228,11 @@ class Validator {
*/
protected function validate_confirmed($attribute, $value)
{
$confirmation = $this->attributes[$attribute.'_confirmation'];
$confirmed = $attribute.'_confirmation';
$confirmation = $this->attributes[$confirmed];
return array_key_exists($attribute.'_confirmation', $this->attributes) and $value == $confirmation;
return array_key_exists($confirmed, $this->attributes) and $value == $confirmation;
}
/**
......@@ -493,7 +497,10 @@ class Validator {
{
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;
......@@ -527,7 +534,7 @@ class Validator {
// If the rule being validated is a "size" rule and the attribute is not
// a number, we will need to gather the specific size message for the
// type of attribute being validated, either a file or a string.
elseif (in_array($rule, $this->size_rules) and ! $this->has_rule($attribute, $this->numeric_rules))
elseif (isset($this->size_rules[$rule]) and ! $this->has_rule($attribute, $this->numeric_rules))
{
$line = (array_key_exists($attribute, Input::file())) ? "file" : "string";
......@@ -560,7 +567,7 @@ class Validator {
{
// Even though every size rule will not have a place-holder for min,
// max, and size, we will go ahead and make replacements for all of
// them just for convenience. Except for "between" every replacement
// them just for convenience. Except for "between", every replacement
// should be the first parameter.
$max = ($rule == 'between') ? $parameters[1] : $parameters[0];
......
<?php namespace Laravel; use Closure;
<?php namespace Laravel;
use Closure;
use Laravel\Validation\Messages;
class View {
......@@ -42,6 +45,20 @@ class View {
$this->view = $view;
$this->data = $data;
$this->path = $this->path($view);
// If a session driver has been specified, we will bind an instance of
// the validation error message container to every view. If an errors
// instance exists in the session, we will use that instance.
//
// This makes the implementation of the Post/Redirect/Get pattern very
// convenient since each view can assume it has a message container.
if (Config::$items['session']['driver'] !== '')
{
$this->data['errors'] = Session::get('errors', function()
{
return new Messages;
});
}
}
/**
......@@ -117,7 +134,10 @@ class View {
*/
public static function of($name, $data = array())
{
if ( ! is_null($view = static::name($name))) return static::make($view, $data);
if ( ! is_null($view = static::name($name)))
{
return static::make($view, $data);
}
throw new \Exception("Named view [$name] is not defined.");
}
......@@ -134,11 +154,11 @@ class View {
*/
protected static function name($name)
{
if (is_null(static::$composers)) static::$composers = require APP_PATH.'composers'.EXT;
static::composers();
foreach (static::$composers as $key => $value)
{
if ($name === $value or (is_array($value) and $name === Arr::get($value, 'name')))
if ($name === $value or $name === Arr::get((array) $value, 'name'))
{
return $key;
}
......@@ -153,7 +173,7 @@ class View {
*/
protected static function compose(View $view)
{
if (is_null(static::$composers)) static::$composers = require APP_PATH.'composers'.EXT;
static::composers();
if (isset(static::$composers[$view->view]))
{
......@@ -164,6 +184,18 @@ class View {
}
}
/**
* Load the view composers for the application.
*
* For better testing flexiblity, we load the composers from the IoC container.
*
* @return void
*/
protected static function composers()
{
static::$composers = IoC::container()->core('view.composers');
}
/**
* Get the evaluated string content of the view.
*
......
......@@ -22,8 +22,9 @@
<h3>What does this mean?</h3>
<p>
We couldn't find the page you requested on our servers. We're really sorry about that.
It's our fault, not yours. We'll work hard to get this page back online as soon as possible.
We couldn't find the page you requested on our servers. We're really sorry
about that. It's our fault, not yours. We'll work hard to get this page
back online as soon as possible.
</p>
<p>
......
......@@ -30,24 +30,6 @@
<p>
Perhaps you would like to go to our <?php echo HTML::link('/', 'home page'); ?>?
</p>
<?php if (isset($detailed) and $detailed): ?>
<h3>Error Message:</h3>
<pre style="word-wrap: break-word;"><?php echo $message; ?></pre>
<h3>Stack Trace:</h3>
<?php
$search = array(APP_PATH, SYS_PATH);
$replace = array('APP_PATH/', 'SYS_PATH/');
$trace = str_replace($search, $replace, $exception->getTraceAsString());
?>
<pre style="word-wrap: break-word;"><?php echo $trace; ?></pre>
<?php endif; ?>
</div>
</body>
</html>
\ No newline at end of file
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title><?php echo $severity; ?></title>
<style>
<?php echo file_get_contents(PUBLIC_PATH.'css/laravel.css'); ?>
</style>
<style>
pre {
word-wrap: break-word;
}
</style>
</head>
<body>
<div id="main">
<img src="http://laravel.com/img/splash/error.png" class="marker">
<h1><?php echo $severity; ?></h1>
<h3>Error Message:</h3>
<pre><?php echo $message; ?></pre>
<h3>Stack Trace:</h3>
<?php
$search = array(APP_PATH, SYS_PATH);
$replace = array('APP_PATH/', 'SYS_PATH/');
$trace = str_replace($search, $replace, $exception->getTraceAsString());
?>
<pre style="word-wrap: break-word;"><?php echo $trace; ?></pre>
</div>
</body>
</html>
\ No newline at end of file
......@@ -8,6 +8,8 @@
* @link http://laravel.com
*/
define('LARAVEL_START', microtime(true));
// --------------------------------------------------------------
// The path to the application directory.
// --------------------------------------------------------------
......@@ -16,14 +18,16 @@ $application = '../application';
// --------------------------------------------------------------
// The path to the Laravel directory.
// --------------------------------------------------------------
$laravel = '../laravel';
$laravel = '../laravel';
// --------------------------------------------------------------
// The path to the public directory.
// --------------------------------------------------------------
$public = __DIR__;
$public = __DIR__;
// --------------------------------------------------------------
// Launch Laravel.
// --------------------------------------------------------------
require $laravel.'/laravel.php';
\ No newline at end of file
require $laravel.'/laravel.php';
echo (microtime(true) - LARAVEL_START) * 1000;
\ No newline at end of file
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