Merge branch 'develop'

This commit is contained in:
Taylor Otwell
2011-07-27 22:15:04 -05:00
23 changed files with 285 additions and 176 deletions

View File

@@ -22,12 +22,12 @@ class File implements \System\Cache\Driver {
*/
public function get($key)
{
if ( ! file_exists(APP_PATH.'storage/cache/'.$key))
if ( ! file_exists(CACHE_PATH.$key))
{
return null;
}
$cache = file_get_contents(APP_PATH.'storage/cache/'.$key);
$cache = file_get_contents(CACHE_PATH.$key);
if (time() >= substr($cache, 0, 10))
{
@@ -49,7 +49,7 @@ class File implements \System\Cache\Driver {
*/
public function put($key, $value, $minutes)
{
file_put_contents(APP_PATH.'storage/cache/'.$key, (time() + ($minutes * 60)).serialize($value), LOCK_EX);
file_put_contents(CACHE_PATH.$key, (time() + ($minutes * 60)).serialize($value), LOCK_EX);
}
/**
@@ -60,7 +60,7 @@ class File implements \System\Cache\Driver {
*/
public function forget($key)
{
@unlink(APP_PATH.'storage/cache/'.$key);
@unlink(CACHE_PATH.$key);
}
}

View File

@@ -7,7 +7,7 @@ class Config {
*
* @var array
*/
private static $items = array();
public static $items = array();
/**
* Determine if a configuration item or file exists.
@@ -95,14 +95,26 @@ class Config {
/**
* Load all of the configuration items from a file.
*
* If it exists, the configuration file in the application/config directory will be loaded first.
* Any environment specific configuration files will be merged with the root file.
*
* @param string $file
* @return void
*/
public static function load($file)
{
if ( ! array_key_exists($file, static::$items) and file_exists($path = APP_PATH.'config/'.$file.EXT))
if (array_key_exists($file, static::$items)) return;
$config = (file_exists($path = CONFIG_PATH.$file.EXT)) ? require $path : array();
if (isset($_SERVER['LARAVEL_ENV']) and file_exists($path = CONFIG_PATH.$_SERVER['LARAVEL_ENV'].'/'.$file.EXT))
{
static::$items[$file] = require $path;
$config = array_merge($config, require $path);
}
if (count($config) > 0)
{
static::$items[$file] = $config;
}
}

View File

@@ -33,6 +33,19 @@ class DB {
return static::$connections[$connection];
}
/**
* Execute a SQL query against the connection and return the first result.
*
* @param string $sql
* @param array $bindings
* @param string $connection
* @return object
*/
public static function first($sql, $bindings = array(), $connection = null)
{
return (count($results = static::query($sql, $bindings, $connection)) > 0) ? $results[0] : null;
}
/**
* Execute a SQL query against the connection.
*
@@ -46,7 +59,7 @@ class DB {
* @param string $sql
* @param array $bindings
* @param string $connection
* @return mixed
* @return array
*/
public static function query($sql, $bindings = array(), $connection = null)
{

View File

@@ -54,7 +54,7 @@ class Connector {
*/
private static function connect_to_sqlite($config)
{
if (file_exists($path = APP_PATH.'storage/db/'.$config->database.'.sqlite'))
if (file_exists($path = DATABASE_PATH.$config->database.'.sqlite'))
{
return new \PDO('sqlite:'.$path, null, null, static::$options);
}

View File

@@ -202,7 +202,7 @@ abstract class Eloquent {
$current_page = \System\Paginator::page($total, $per_page);
return new \System\Paginator($this->for_page($current_page, $per_page)->get(), $total, $per_page);
return \System\Paginator::make($this->for_page($current_page, $per_page)->get(), $total, $per_page);
}
/**

View File

@@ -413,7 +413,6 @@ class Query {
*/
public function first($columns = array('*'))
{
return (count($results = $this->take(1)->get($columns)) > 0) ? $results[0] : null;
}
@@ -458,15 +457,29 @@ class Query {
* Get paginated query results.
*
* @param int $per_page
* @param array $columns
* @return Paginator
*/
public function paginate($per_page)
public function paginate($per_page, $columns = array('*'))
{
$select = $this->select;
$total = $this->count();
// Every query clears the SELECT clause, so we store the contents of the clause
// before executing the count query and then put the contents back in afterwards.
if ( ! is_null($select))
{
$this->select = $select;
}
else
{
$this->select($columns);
}
$current_page = \System\Paginator::page($total, $per_page);
return new \System\Paginator($this->for_page($current_page, $per_page)->get(), $total, $per_page);
return \System\Paginator::make($this->for_page($current_page, $per_page)->get(), $total, $per_page);
}
/**

View File

@@ -35,6 +35,18 @@ class HTML {
return '<link href="'.static::entities(URL::to_asset($url)).'" rel="stylesheet" type="text/css" media="'.$media.'">'.PHP_EOL;
}
/**
* Generate a HTML span.
*
* @param string $value
* @param array $attributes
* @return string
*/
public static function span($value, $attributes = array())
{
return '<span'.static::attributes($attributes).'>'.static::entities($value).'</span>';
}
/**
* Generate a HTML link.
*

View File

@@ -9,21 +9,21 @@ class Lang {
*
* @var array
*/
private static $lines = array();
public static $lines = array();
/**
* The key of the line that is being requested.
*
* @var string
*/
private $key;
public $key;
/**
* The place-holder replacements.
*
* @var array
*/
private $replacements = array();
public $replacements = array();
/**
* Create a new Lang instance.
@@ -117,7 +117,9 @@ class Lang {
*/
private function load($file, $language)
{
if ( ! array_key_exists($language.$file, static::$lines) and file_exists($path = APP_PATH.'lang/'.$language.'/'.$file.EXT))
if (array_key_exists($language.$file, static::$lines)) return;
if (file_exists($path = LANG_PATH.$language.'/'.$file.EXT))
{
static::$lines[$language.$file] = require $path;
}

View File

@@ -1,35 +0,0 @@
<?php
/**
* This function is registered on the auto-loader stack by the front controller.
*
* All namespace slashes will be replaced with directory slashes since all Laravel
* system classes are organized using a namespace to directory convention.
*/
return function($class) {
$file = strtolower(str_replace('\\', '/', $class));
if (array_key_exists($class, $aliases = System\Config::get('aliases')))
{
return class_alias($aliases[$class], $class);
}
if (file_exists($path = BASE_PATH.$file.EXT))
{
require $path;
}
elseif (file_exists($path = APP_PATH.'models/'.$file.EXT))
{
require $path;
}
elseif (file_exists($path = APP_PATH.'libraries/'.$file.EXT))
{
require $path;
}
elseif (file_exists($path = APP_PATH.$file.EXT))
{
require $path;
}
};

View File

@@ -31,7 +31,7 @@ class Paginator {
public $per_page;
/**
* The last page number.
* The last page available for the result set.
*
* @var int
*/
@@ -45,33 +45,43 @@ class Paginator {
public $language;
/**
* Indicates if HTTPS links should be generated.
* Create a new Paginator instance.
*
* @var bool
* @param array $results
* @param int $page
* @param int $total
* @param int $per_page
* @param int $last_page
* @return void
*/
public $https = false;
public function __construct($results, $page, $total, $per_page, $last_page)
{
$this->last_page = $last_page;
$this->per_page = $per_page;
$this->results = $results;
$this->total = $total;
$this->page = $page;
}
/**
* Create a new Paginator instance.
*
* @param array $results
* @param int $total
* @param int $per_page
* @return void
* @param array $results
* @param int $total
* @param int $per_page
* @return Paginator
*/
public function __construct($results, $total, $per_page)
public static function make($results, $total, $per_page)
{
$this->page = static::page($total, $per_page);
$this->last_page = ceil($total / $per_page);
$this->per_page = $per_page;
$this->results = $results;
$this->total = $total;
return new static($results, static::page($total, $per_page), $total, $per_page, ceil($total / $per_page));
}
/**
* Get the current page from the request query string.
*
* 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 $total
* @param int $per_page
@@ -83,10 +93,10 @@ class Paginator {
if (is_numeric($page) and $page > $last_page = ceil($total / $per_page))
{
return $last_page;
return ($last_page > 0) ? $last_page : 1;
}
return (filter_var($page, FILTER_VALIDATE_INT) === false or $page < 1) ? 1 : $page;
return ($page < 1 or filter_var($page, FILTER_VALIDATE_INT) === false) ? 1 : $page;
}
/**
@@ -110,8 +120,6 @@ class Paginator {
*/
private function numbers($adjacent = 3)
{
// "7" is added to the adjacent range to account for the seven constant elements
// in a slider: the first and last two links, the current page, and the two "..." strings.
return ($this->last_page < 7 + ($adjacent * 2)) ? $this->range(1, $this->last_page) : $this->slider($adjacent);
}
@@ -125,7 +133,7 @@ class Paginator {
{
if ($this->page <= $adjacent * 2)
{
return $this->range(1, 4 + ($adjacent * 2)).$this->ending();
return $this->range(1, 2 + ($adjacent * 2)).$this->ending();
}
elseif ($this->page >= $this->last_page - ($adjacent * 2))
{
@@ -144,12 +152,7 @@ class Paginator {
{
$text = Lang::line('pagination.previous')->get($this->language);
if ($this->page > 1)
{
return HTML::link(Request::uri().'?page='.($this->page - 1), $text, array('class' => 'prev_page'), $this->https).' ';
}
return "<span class=\"disabled prev_page\">$text</span> ";
return ($this->page > 1) ? $this->link($this->page - 1, $text, 'prev_page').' ' : HTML::span($text, array('class' => 'disabled prev_page')).' ';
}
/**
@@ -161,12 +164,7 @@ class Paginator {
{
$text = Lang::line('pagination.next')->get($this->language);
if ($this->page < $this->last_page)
{
return HTML::link(Request::uri().'?page='.($this->page + 1), $text, array('class' => 'next_page'), $this->https);
}
return "<span class=\"disabled next_page\">$text</span>";
return ($this->page < $this->last_page) ? $this->link($this->page + 1, $text, 'next_page') : HTML::span($text, array('class' => 'disabled next_page'));
}
/**
@@ -176,7 +174,7 @@ class Paginator {
*/
private function beginning()
{
return $this->range(1, 2).'<span class="dots">...</span> ';
return $this->range(1, 2).'<span class="dots">...</span>';
}
/**
@@ -186,7 +184,7 @@ class Paginator {
*/
private function ending()
{
return '<span class="dots">...</span> '.$this->range($this->last_page - 1, $this->last_page);
return '<span class="dots">...</span>'.$this->range($this->last_page - 1, $this->last_page);
}
/**
@@ -194,8 +192,8 @@ class Paginator {
*
* For the current page, an HTML span element will be generated instead of a link.
*
* @param int $start
* @param int $end
* @param int $start
* @param int $end
* @return string
*/
private function range($start, $end)
@@ -204,14 +202,27 @@ class Paginator {
for ($i = $start; $i <= $end; $i++)
{
$pages .= ($this->page == $i) ? "<span class=\"current\">$i</span> " : HTML::link(Request::uri().'?page='.$i, $i, array(), $this->https).' ';
$pages .= ($this->page == $i) ? HTML::span($i, array('class' => 'current')).' ' : $this->link($i, $i, null).' ';
}
return $pages;
}
/**
* Set the language that should be used when generating pagination links.
* Create a HTML page link.
*
* @param int $page
* @param string $text
* @param string $attributes
* @return string
*/
private function link($page, $text, $class)
{
return HTML::link(Request::uri().'?page='.$page, $text, array('class' => $class), Request::is_secure());
}
/**
* Set the language that should be used when generating page links.
*
* @param string $language
* @return Paginator
@@ -222,15 +233,4 @@ class Paginator {
return $this;
}
/**
* Force the pagination links to use HTTPS.
*
* @return Paginator
*/
public function secure()
{
$this->https = true;
return $this;
}
}

View File

@@ -101,6 +101,18 @@ class Response {
return new static($content, $status);
}
/**
* Factory for creating new error response instances.
*
* @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.
*

View File

@@ -3,11 +3,27 @@
class Router {
/**
* All of the loaded routes.
* All of the loaded routes keyed by route file.
*
* @var array
*/
public static $routes;
public static $routes = array();
/**
* Simulate a request to a given route. Useful for implementing HMVC.
*
* @param array|string $parameters
* @return Response
*/
public static function call($parameters)
{
$route = static::route('GET', (is_array($parameters)) ? implode('/', $parameters) : (string) $parameters);
if ( ! is_null($route))
{
return $route->call();
}
}
/**
* Search a set of routes for the route matching a method and URI.
@@ -18,22 +34,19 @@ class Router {
*/
public static function route($method, $uri)
{
if (is_null(static::$routes))
{
static::$routes = static::load($uri);
}
$routes = static::load($uri);
// Put the request method and URI in route form.
// Routes begin with the request method and a forward slash.
$uri = $method.' /'.trim($uri, '/');
// Is there an exact match for the request?
if (isset(static::$routes[$uri]))
if (isset($routes[$uri]))
{
return Request::$route = new Route($uri, static::$routes[$uri]);
return Request::$route = new Route($uri, $routes[$uri]);
}
foreach (static::$routes as $keys => $callback)
foreach ($routes as $keys => $callback)
{
// Only check routes that have multiple URIs or wildcards.
// Other routes would have been caught by the check for literal matches.
@@ -58,7 +71,7 @@ class Router {
*/
public static function load($uri)
{
$base = require APP_PATH.'routes'.EXT;
$base = (isset(static::$routes[$path = APP_PATH.'routes'.EXT])) ? static::$routes[$path] : static::$routes[$path] = require $path;
return (is_dir(APP_PATH.'routes') and $uri !== '') ? array_merge(static::load_from_directory($uri), $base) : $base;
}
@@ -77,9 +90,13 @@ class Router {
// Iterate backwards through the URI looking for the deepest matching file.
foreach (array_reverse($segments, true) as $key => $value)
{
if (file_exists($path = APP_PATH.'routes/'.implode('/', array_slice($segments, 0, $key + 1)).EXT))
if (isset(static::$routes[$path = ROUTE_PATH.implode('/', array_slice($segments, 0, $key + 1)).EXT]))
{
return require $path;
return static::$routes[$path];
}
elseif (file_exists($path))
{
return static::$routes[$path] = require $path;
}
}

View File

@@ -10,7 +10,7 @@ class File implements \System\Session\Driver {
*/
public function load($id)
{
if (file_exists($path = APP_PATH.'storage/sessions/'.$id))
if (file_exists($path = SESSION_PATH.$id))
{
return unserialize(file_get_contents($path));
}
@@ -24,7 +24,7 @@ class File implements \System\Session\Driver {
*/
public function save($session)
{
file_put_contents(APP_PATH.'storage/sessions/'.$session['id'], serialize($session), LOCK_EX);
file_put_contents(SESSION_PATH.$session['id'], serialize($session), LOCK_EX);
}
/**
@@ -35,7 +35,7 @@ class File implements \System\Session\Driver {
*/
public function delete($id)
{
@unlink(APP_PATH.'storage/sessions/'.$id);
@unlink(SESSION_PATH.$id);
}
/**
@@ -46,7 +46,7 @@ class File implements \System\Session\Driver {
*/
public function sweep($expiration)
{
foreach (glob(APP_PATH.'storage/sessions/*') as $file)
foreach (glob(SESSION_PATH.'*') as $file)
{
if (filetype($file) == 'file' and filemtime($file) < $expiration)
{

View File

@@ -5,6 +5,8 @@ class URL {
/**
* Generate an application URL.
*
* If the given URL is already well-formed, it will be returned unchanged.
*
* @param string $url
* @param bool $https
* @param bool $asset
@@ -12,26 +14,18 @@ class URL {
*/
public static function to($url = '', $https = false, $asset = false)
{
if (strpos($url, '://') !== false)
if (filter_var($url, FILTER_VALIDATE_URL) !== false)
{
return $url;
}
$base = Config::get('application.url');
$base = Config::get('application.url').'/'.Config::get('application.index');
// If the URL is being generated for a public asset such as an
// image, we do not want to include "index.php" in the path.
if ( ! $asset)
{
$base .= '/'.Config::get('application.index');
}
$base = ($asset) ? str_replace('/'.Config::get('application.index'), '', $base) : $base;
if (strpos($base, 'http://') === 0 and $https)
{
$base = 'https://'.substr($base, 7);
}
$base = ($https and strpos($base, 'http://') === 0) ? 'https://'.substr($base, 7) : $base;
return rtrim($base, '/').'/'.trim($url, '/');
return rtrim($base, '/').'/'.ltrim($url, '/');
}
/**
@@ -52,9 +46,9 @@ class URL {
* @param string $url
* @return string
*/
public static function to_asset($url = '')
public static function to_asset($url)
{
return static::to($url, false, true);
return static::to($url, Request::is_secure(), true);
}
/**

View File

@@ -49,6 +49,25 @@ class View {
return new static($view, $data);
}
/**
* Create a new named view instance.
*
* @param string $view
* @param array $data
* @return View
*/
public static function of($view, $data = array())
{
$views = Config::get('view.names');
if ( ! array_key_exists($view, $views))
{
throw new \Exception("Named view [$view] is not defined.");
}
return static::make($views[$view], $data);
}
/**
* Get the parsed content of the view.
*
@@ -82,20 +101,31 @@ class View {
*
* @return string
*/
private function find()
protected function find()
{
if (file_exists($path = APP_PATH.'views/'.$this->view.EXT))
if (file_exists($path = VIEW_PATH.$this->view.EXT))
{
return $path;
}
elseif (file_exists($path = SYS_PATH.'views/'.$this->view.EXT))
elseif (file_exists($path = SYS_VIEW_PATH.$this->view.EXT))
{
return $path;
}
else
{
throw new \Exception("View [".$this->view."] doesn't exist.");
}
throw new \Exception("View [".$this->view."] doesn't exist.");
}
/**
* Add a view instance to the view data.
*
* @param string $key
* @param string $view
* @param array $data
* @return View
*/
public function partial($key, $view, $data = array())
{
return $this->bind($key, static::make($view, $data));
}
/**
@@ -118,14 +148,7 @@ class View {
{
if (strpos($method, 'of_') === 0)
{
$views = Config::get('view.names');
if ( ! array_key_exists($view = substr($method, 3), $views))
{
throw new \Exception("Named view [$view] is not defined.");
}
return static::make($views[$view], (isset($parameters[0]) and is_array($parameters[0])) ? $parameters[0] : array());
return static::of(substr($method, 3), Arr::get($parameters, 0, array()));
}
}