From 52b68c060bed09258f43435f5e48a17fcbf19512 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 4 Oct 2011 21:43:39 -0500 Subject: [PATCH] refactoring. adding back pagination. --- application/config/application.php | 63 ++-- laravel/controller.php | 52 ++- laravel/database/query.php | 22 +- laravel/lang.php | 4 +- laravel/language/en/pagination.php | 9 + laravel/language/en/validation.php | 32 +- laravel/laravel.php | 2 +- laravel/paginator.php | 335 ++++++++++--------- laravel/request.php | 4 +- laravel/response.php | 14 +- laravel/routing/caller.php | 125 +++---- laravel/routing/destination.php | 13 - laravel/routing/route.php | 17 +- laravel/routing/router.php | 16 +- laravel/security/auth.php | 17 +- laravel/security/hashing/bcrypt.php | 88 ++--- laravel/session/payload.php | 23 ++ laravel/session/transporters/cookie.php | 16 +- laravel/session/transporters/transporter.php | 4 + laravel/url.php | 9 +- laravel/validation/validator.php | 65 +++- 21 files changed, 551 insertions(+), 379 deletions(-) create mode 100644 laravel/language/en/pagination.php delete mode 100644 laravel/routing/destination.php diff --git a/application/config/application.php b/application/config/application.php index 8dadc03a..7503048d 100644 --- a/application/config/application.php +++ b/application/config/application.php @@ -39,18 +39,6 @@ return array( 'language' => 'en', - /* - |-------------------------------------------------------------------------- - | Application Character Encoding - |-------------------------------------------------------------------------- - | - | The default character encoding used by your application. This is the - | character encoding that will be used by the Str, Text, and Form classes. - | - */ - - 'encoding' => 'UTF-8', - /* |-------------------------------------------------------------------------- | Application Timezone @@ -65,22 +53,15 @@ return array( /* |-------------------------------------------------------------------------- - | Auto-Loaded Packages + | Application Character Encoding |-------------------------------------------------------------------------- | - | The packages that should be auto-loaded each time Laravel handles - | a request. These should generally be packages that you use on almost - | every request to your application. - | - | Each package specified here will be bootstrapped and can be conveniently - | used by your application's routes, models, and libraries. - | - | Note: The package names in this array should correspond to a package - | directory in application/packages. + | The default character encoding used by your application. This is the + | character encoding that will be used by the Str, Text, and Form classes. | */ - 'packages' => array(), + 'encoding' => 'UTF-8', /* |-------------------------------------------------------------------------- @@ -95,4 +76,40 @@ return array( 'key' => '', + /* + |-------------------------------------------------------------------------- + | SSL Link Generation + |-------------------------------------------------------------------------- + | + | Many sites use SSL to protect their users data. However, you may not + | always be able to use SSL on your development machine, meaning all HTTPS + | will be broken during development. + | + | For this reason, you may wish to disable the generation of HTTPS links + | throughout your application. This option does just that. All attempts to + | generate HTTPS links will generate regular HTTP links instead. + | + */ + + 'ssl' => true, + + /* + |-------------------------------------------------------------------------- + | Auto-Loaded Packages + |-------------------------------------------------------------------------- + | + | The packages that should be auto-loaded each time Laravel handles a + | request. These should generally be packages that you use on almost every + | request to your application. + | + | Each package specified here will be bootstrapped and can be conveniently + | used by your application's routes, models, and libraries. + | + | Note: The package names in this array should correspond to a package + | directory in application/packages. + | + */ + + 'packages' => array(), + ); \ No newline at end of file diff --git a/laravel/controller.php b/laravel/controller.php index 97baf2cf..8f966a68 100644 --- a/laravel/controller.php +++ b/laravel/controller.php @@ -1,6 +1,6 @@ -$name; } + /** + * Resolve a controller name to a controller instance. + * + * @param Container $container + * @param string $controller + * @param string $path + * @return Controller + */ + public static function resolve(Container $container, $controller, $path) + { + if ( ! static::load($controller, $path)) return; + + // If the controller is registered in the IoC container, we will resolve it out + // of the container. Using constructor injection on controllers via the container + // allows more flexible and testable development of applications. + if ($container->registered('controllers.'.$controller)) + { + return $container->resolve('controllers.'.$controller); + } + + // If the controller was not registered in the container, we will instantiate + // an instance of the controller manually. All controllers are suffixed with + // "_Controller" to avoid namespacing. Allowing controllers to exist in the + // global namespace gives the developer a convenient API for using the framework. + $controller = str_replace(' ', '_', ucwords(str_replace('.', ' ', $controller))).'_Controller'; + + return new $controller; + } + + /** + * Load the file for a given controller. + * + * @param string $controller + * @param string $path + * @return bool + */ + protected static function load($controller, $path) + { + if (file_exists($path = $path.strtolower(str_replace('.', '/', $controller)).EXT)) + { + require $path; + + return true; + } + + return false; + } + /** * Magic Method to handle calls to undefined functions on the controller. * diff --git a/laravel/database/query.php b/laravel/database/query.php index b98d9d0f..36dab41a 100644 --- a/laravel/database/query.php +++ b/laravel/database/query.php @@ -1,4 +1,4 @@ -skip(($page - 1) * $per_page)->take($per_page); } @@ -522,6 +518,22 @@ class Query { return $result; } + /** + * Get the paginated query results as a Paginator instance. + * + * @param int $per_page + * @param array $columns + * @return Paginator + */ + public function paginate($per_page, $columns = array('*')) + { + // Calculate the current page for the request. The page number will be validated + // and adjusted by the Paginator class, so we can assume it is valid. + $page = Paginator::page($total = $this->count(), $per_page); + + return Paginator::make($this->for_page($page, $per_page)->get($columns), $total, $per_page); + } + /** * Insert an array of values into the database table. * diff --git a/laravel/lang.php b/laravel/lang.php index b1e9c3f1..73bd95aa 100644 --- a/laravel/lang.php +++ b/laravel/lang.php @@ -77,6 +77,8 @@ class Lang { { if (count($paths) == 0) $paths = array(SYS_LANG_PATH, LANG_PATH); + if (is_null($language)) $language = Config::get('application.language'); + return new static($key, $replacements, $language, $paths); } @@ -147,7 +149,7 @@ class Lang { */ protected function load($file) { - if (isset(static::$lines[$this->language.$file])) return; + if (isset(static::$lines[$this->language.$file])) return true; $language = array(); diff --git a/laravel/language/en/pagination.php b/laravel/language/en/pagination.php new file mode 100644 index 00000000..5696eaa6 --- /dev/null +++ b/laravel/language/en/pagination.php @@ -0,0 +1,9 @@ + '← Previous', + 'first' => 'First', + 'next' => 'Next →', + 'last' => 'Last', + 'status' => 'Page :current of :last', + +); \ No newline at end of file diff --git a/laravel/language/en/validation.php b/laravel/language/en/validation.php index ea7e1047..6092bc0f 100644 --- a/laravel/language/en/validation.php +++ b/laravel/language/en/validation.php @@ -2,15 +2,19 @@ return array( - /** - * The validation error messages. - * - * These error messages will be used by the Validator class if no - * other messages are provided by the developer. - */ + /* + |-------------------------------------------------------------------------- + | Validation Error Messages + |-------------------------------------------------------------------------- + | + | These error messages will be used by the Validator class if no other + | messages are provided by the developer. They may be overriden by the + | developer in the application language directory. + | + */ "accepted" => "The :attribute must be accepted.", - "active_url" => "The :attribute does not exist.", + "active_url" => "The :attribute is not an active URL.", "alpha" => "The :attribute may only contain letters.", "alpha_dash" => "The :attribute may only contain letters, numbers, dashes, and underscores.", "alpha_num" => "The :attribute may only contain letters and numbers.", @@ -30,11 +34,15 @@ return array( "unique" => "The :attribute has already been taken.", "url" => "The :attribute format is invalid.", - /** - * The following words are appended to the "size" messages when - * applicable, such as when validating string lengths or the - * size of file uploads. - */ + /* + |-------------------------------------------------------------------------- + | Validation Units + |-------------------------------------------------------------------------- + | + | The following words are appended to the "size" messages when applicable, + | such as when validating string lengths or the size of file uploads. + | + */ "characters" => "characters", "kilobytes" => "kilobytes", diff --git a/laravel/laravel.php b/laravel/laravel.php index 85f28c94..a7e0bd03 100644 --- a/laravel/laravel.php +++ b/laravel/laravel.php @@ -39,8 +39,8 @@ if (Config::get('session.driver') !== '') * be returned to the browser. */ require SYS_PATH.'request'.EXT; -require SYS_PATH.'routing/router'.EXT; require SYS_PATH.'routing/route'.EXT; +require SYS_PATH.'routing/router'.EXT; require SYS_PATH.'routing/loader'.EXT; require SYS_PATH.'routing/caller'.EXT; diff --git a/laravel/paginator.php b/laravel/paginator.php index 9847804d..b4727cc7 100644 --- a/laravel/paginator.php +++ b/laravel/paginator.php @@ -9,72 +9,85 @@ class Paginator { */ 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; + protected $page; /** * The last page available for the result set. * * @var int */ - public $last_page; + protected $last; /** - * The language that should be used when generating page links. + * The total number of results. * - * @var string + * @var int */ - public $language; + protected $total; + + /** + * The number of items per page. + * + * @var int + */ + protected $per_page; /** * The values that should be appended to the end of the link query strings. * * @var array */ - public $append = array(); + protected $appends; /** - * The format that will be used to wrap the entire pagination string. + * The compiled appendage that will be appended to the links. + * + * This consists of a sprintf format with a page place-holder and query string. * * @var string */ - protected $wrapper = ''; + protected $appendage; + + /** + * The current request instance. + * + * @var Request + */ + protected $request; + + /** + * The paginatino elements that will be generated. + * + * @var array + */ + protected $elements = array('first', 'previous', 'status', 'next', 'last'); /** * Create a new Paginator instance. * * @param array $results + * @param int $last * @param int $page * @param int $total * @param int $per_page - * @param int $last_page * @return void */ - protected function __construct($results, $page, $total, $per_page, $last_page) + protected function __construct($results, $page, $total, $per_page, $last) { $this->page = $page; + $this->last = $last; $this->total = $total; $this->results = $results; $this->per_page = $per_page; - $this->last_page = $last_page; + + // Grab the active request instance. This is used to determine the current URI + // and to determine if HTTPS links should be generated. + $this->request = IoC::container()->core('request'); } /** @@ -93,10 +106,6 @@ class Paginator { /** * 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 * @return int @@ -105,9 +114,13 @@ class Paginator { { $page = IoC::container()->core('input')->get('page', 1); - if (is_numeric($page) and $page > $last_page = ceil($total / $per_page)) + // 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. + if (is_numeric($page) and $page > $last = ceil($total / $per_page)) { - return ($last_page > 0) ? $last_page : 1; + return ($last > 0) ? $last : 1; } return ($page < 1 or filter_var($page, FILTER_VALIDATE_INT) === false) ? 1 : $page; @@ -116,163 +129,183 @@ class Paginator { /** * Create the HTML pagination links. * - * @param int $adjacent * @return string */ - public function links($adjacent = 4) + public function links() { - if ($this->last_page <= 1) return ''; + if ($this->last <= 1) return ''; - // If there are two few pages to make showing a slider possible, we will just display a - // range of plain number links. The hard-coded "7" is to account for all of the constant - // elements in a sliding range, namely the current page, the two ellipses, the two - // beginning and ending pages. - $numbers = ($this->last_page < 7 + ($adjacent * 2)) ? $this->range(1, $this->last_page) : $this->slider($adjacent); + // Each pagination element is created by an element method. This allows + // us to keep this class clean and simple, because pagination code can + // become a mess. We would rather keep it simple and beautiful. + foreach ($this->elements as $element) + { + $elements[] = $this->$element(Lang::line("pagination.{$element}")->get()); + } - return sprintf($this->wrapper, $this->previous().$numbers.$this->next()); + return ''.PHP_EOL; } /** - * Build sliding list of HTML numeric page links. + * Get the "status" pagination element. * - * @param int $adjacent + * @param string $text * @return string */ - private function slider($adjacent) + protected function status($text) { - if ($this->page <= $adjacent * 2) + return str_replace(array(':current', ':last'), array($this->page, $this->last), $text); + } + + /** + * Create the "first" pagination element. + * + * @param string $text + * @return string + */ + protected function first($text) + { + return $this->backwards(__FUNCTION__, $text, 1); + } + + /** + * Create the "previous" pagination element. + * + * @param string $text + * @return string + */ + protected function previous($text) + { + return $this->backwards(__FUNCTION__, $text, $this->page - 1); + } + + /** + * Create the "next" pagination element. + * + * @param string $text + * @return string + */ + protected function next($text) + { + return $this->forwards(__FUNCTION__, $text, $this->page + 1); + } + + /** + * Create the "last" pagination element. + * + * @param string $text + * @return string + */ + protected function last($text) + { + return $this->forwards(__FUNCTION__, $text, $this->last); + } + + /** + * Create a "backwards" paginatino element. + * + * This function handles the creation of the first and previous elements. + * + * @param string $element + * @param string $text + * @param int $last + * @return string + */ + protected function backwards($element, $text, $last) + { + return $this->element($element, $text, $last, function($page) { return $page <= 1; }); + } + + /** + * Create a "forwards" paginatino element. + * + * This function handles the creation of the next and last elements. + * + * @param string $element + * @param string $text + * @param int $last + * @return string + */ + protected function forwards($element, $text, $last) + { + return $this->element($element, $text, $last, function($page, $last) { return $page >= $last; }); + } + + /** + * Create a chronological pagination element. + * + * @param string $element + * @param string $text + * @param int $page + * @param Closure $disabler + * @return string + */ + protected function element($element, $text, $page, $disabler) + { + $class = "{$element}_page"; + + if ($disabler($this->page, $this->last)) { - return $this->range(1, 2 + ($adjacent * 2)).$this->ending(); - } - elseif ($this->page >= $this->last_page - ($adjacent * 2)) - { - return $this->beginning().$this->range($this->last_page - 2 - ($adjacent * 2), $this->last_page); + return HTML::span($text, array('class' => "disabled {$class}")); } else { - return $this->beginning().$this->range($this->page - $adjacent, $this->page + $adjacent).$this->ending(); + // We will assume the page links should use HTTPS if the current request + // is also using HTTPS. Since pagination links automatically point to + // the current URI, this makes pretty good sense. + list($uri, $secure) = array($this->request->uri(), $this->request->secure()); + + return HTML::link($uri.$this->appendage($element, $page), $text, array('class' => $class), $secure); } } /** - * Generate the "previous" HTML link. - * - * @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. - * - * @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).'...'; - } - - /** - * Build the last two page links for a sliding page range. - * - * @return string - */ - private function ending() - { - return '...'.$this->range($this->last_page - 1, $this->last_page); - } - - /** - * Build a range of page links. - * - * For the current page, an HTML span element will be generated instead of a link. - * - * @param int $start - * @param int $end - * @return string - */ - private function range($start, $end) - { - $pages = ''; - - for ($i = $start; $i <= $end; $i++) - { - $pages .= ($this->page == $i) ? HTML::span($i, array('class' => 'current')).' ' : $this->link($i, $i, null).' '; - } - - return $pages; - } - - /** - * Create a HTML page link. + * Create the pagination link "appendage" for an element. * + * @param string $element * @param int $page - * @param string $text - * @param string $attributes * @return string */ - private function link($page, $text, $class) + protected function appendage($element, $page) { - $append = ''; - - foreach ($this->append as $key => $value) + // The appendage string contains the query string, but it also contains a + // place-holder for the page number. This will be used to insert the + // correct page number based on the element being created. + if (is_null($this->appendage)) { - $append .= '&'.$key.'='.$value; + $this->appendage = '?page=%s'.http_build_query((array) $this->appends); } - $request = IoC::container()->core('request'); - - return HTML::link($request->uri().'?page='.$page.$append, $text, compact('class'), $request->secure()); - } - - /** - * Set the language that should be used when generating page links. - * - * @param string $language - * @return Paginator - */ - public function lang($language) - { - $this->language = $language; - - return $this; + return sprintf($this->appendage, $page); } /** * Set the items that should be appended to the link query strings. * + * This provides a convenient method of maintaining sort or passing other information + * to the route handling pagination. + * * @param array $values * @return Paginator */ - public function append($values) + public function appends($values) { - $this->append = $values; + $this->appends = $values; + + return $this; + } + + /** + * Set the elements that should be included when creating the pagination links. + * + * The available elements are "first", "previous", "status", "next", and "last". + * + * @param array $elements + * @return string + */ + public function elements($elements) + { + $this->elements = $elements; return $this; } diff --git a/laravel/request.php b/laravel/request.php index 8a6916a7..6bdd4a5c 100644 --- a/laravel/request.php +++ b/laravel/request.php @@ -1,4 +1,4 @@ -server['REMOTE_ADDR']; } - return ($default instanceof \Closure) ? call_user_func($default) : $default; + return ($default instanceof Closure) ? call_user_func($default) : $default; } /** diff --git a/laravel/response.php b/laravel/response.php index 7b9b099d..f04b6d00 100644 --- a/laravel/response.php +++ b/laravel/response.php @@ -141,17 +141,17 @@ class Response { * * * // Create a response with the "layout" named view - * return Response::with('layout'); + * return Response::of('layout'); * * // Create a response with the "layout" named view and data - * return Response::with('layout', array('name' => 'Taylor')); + * return Response::of('layout', array('name' => 'Taylor')); * * * @param string $name * @param array $data * @return Response */ - public static function with($name, $data = array()) + public static function of($name, $data = array()) { return new static(IoC::container()->core('view')->of($name, $data)); } @@ -296,17 +296,17 @@ class Response { * * * // Create a response instance with the "layout" named view - * return Response::with_layout(); + * return Response::of_layout(); * * // Create a response instance with a named view and data - * return Response::with_layout(array('name' => 'Taylor')); + * return Response::of_layout(array('name' => 'Taylor')); * */ public static function __callStatic($method, $parameters) { - if (strpos($method, 'with_') === 0) + if (strpos($method, 'of_') === 0) { - return static::with(substr($method, 5), Arr::get($parameters, 0, array())); + return static::with(substr($method, 3), Arr::get($parameters, 0, array())); } } diff --git a/laravel/routing/caller.php b/laravel/routing/caller.php index 28061ca8..2b52da38 100644 --- a/laravel/routing/caller.php +++ b/laravel/routing/caller.php @@ -3,6 +3,7 @@ use Closure; use Laravel\Response; use Laravel\Container; +use Laravel\Controller; class Caller { @@ -45,7 +46,7 @@ class Caller { /** * Call a given route and return the route's response. * - * @param Route $route + * @param Route $route * @return Response */ public function call(Route $route) @@ -53,58 +54,70 @@ class Caller { // Since "before" filters can halt the request cycle, we will return any response // from the before filters. Allowing the filters to halt the request cycle makes // common tasks like authorization convenient to implement. - if ( ! is_null($response = $this->before($route))) + $before = array_merge(array('before'), $route->filters('before')); + + if ( ! is_null($response = $this->filter($before, array(), true))) { return $this->finish($route, $response); } - if ( ! is_null($response = $route->call())) + // If a route returns a Delegate, it means the route is delegating the handling + // of the request to a controller method. We will pass the Delegate instance + // to the "delegate" method which will call the controller. + if ($route->delegates()) + { + return $this->delegate($route, $route->call()); + } + // If no before filters returned a response and the route is not delegating + // execution to a controller, we will call the route like normal and return + // the response. If the no response is given by the route, we will return + // the 404 error view. + elseif ( ! is_null($response = $route->call())) { - // If a route returns a Delegate, it also means the route is delegating the - // handling of the request to a controller method. So, we will pass the string - // to the route delegator, exploding on "@". - if ($response instanceof Delegate) return $this->delegate($route, $response->destination); - return $this->finish($route, $response); } - - // If we get to this point, no response was returned from the filters or the route. - // The 404 response will be returned to the browser instead of a blank screen. - return $this->finish($route, Response::error('404')); + else + { + return $this->finish($route, Response::error('404')); + } } /** * Handle the delegation of a route to a controller method. * - * @param Route $route - * @param string $delegate + * @param Route $route + * @param Delegate $delegate * @return mixed */ - protected function delegate(Route $route, $delegate) + protected function delegate(Route $route, Delegate $delegate) { - if (strpos($delegate, '@') === false) + // Route delegates follow a {controller}@{method} naming convention. For example, + // to delegate to the "home" controller's "index" method, the delegate should be + // formatted like "home@index". Nested controllers may be delegated to using dot + // syntax, like so: "user.profile@show". + if (strpos($delegate->destination, '@') === false) { - throw new \Exception("Route delegate [$delegate] has an invalid format."); + throw new \Exception("Route delegate [{$delegate->destination}] has an invalid format."); } - list($controller, $method) = explode('@', $delegate); + list($controller, $method) = explode('@', $delegate->destination); - $controller = $this->resolve($controller); + $controller = Controller::resolve($this->container, $controller, $this->path); // If the controller doesn't exist or the request is to an invalid method, we will // return the 404 error response. The "before" method and any method beginning with // an underscore are not publicly available. - if (is_null($controller) or ($method == 'before' or strncmp($method, '_', 1) === 0)) + if (is_null($controller) or ! $this->callable($method)) { return Response::error('404'); } $controller->container = $this->container; - // Again, as was the case with route closures, if the controller "before" filters return - // a response, it will be considered the response to the request and the controller method - // will not be used to handle the request to the application. - $response = $this->before($controller); + // Again, as was the case with route closures, if the controller "before" filters + // return a response, it will be considered the response to the request and the + // controller method will not be used to handle the request to the application. + $response = $this->filter($controller->filters('before'), array(), true); if (is_null($response)) { @@ -115,48 +128,14 @@ class Caller { } /** - * Resolve a controller name to a controller instance. + * Determine if a given controller method is callable. * - * @param string $controller - * @return Controller - */ - protected function resolve($controller) - { - if ( ! $this->load($controller)) return; - - // If the controller is registered in the IoC container, we will resolve it out - // of the container. Using constructor injection on controllers via the container - // allows more flexible and testable development of applications. - if ($this->container->registered('controllers.'.$controller)) - { - return $this->container->resolve('controllers.'.$controller); - } - - // If the controller was not registered in the container, we will instantiate - // an instance of the controller manually. All controllers are suffixed with - // "_Controller" to avoid namespacing. Allowing controllers to exist in the - // global namespace gives the developer a convenient API for using the framework. - $controller = str_replace(' ', '_', ucwords(str_replace('.', ' ', $controller))).'_Controller'; - - return new $controller; - } - - /** - * Load the file for a given controller. - * - * @param string $controller + * @param string $method * @return bool */ - protected function load($controller) + protected function callable($method) { - if (file_exists($path = $this->path.strtolower(str_replace('.', '/', $controller)).EXT)) - { - require $path; - - return true; - } - - return false; + return $method == 'before' or $method == 'after' or strncmp($method, '_', 1) === 0; } /** @@ -164,11 +143,11 @@ class Caller { * * The route response will be converted to a Response instance and the "after" filters will be run. * - * @param Destination $route - * @param mixed $response + * @param Route|Controller $destination + * @param mixed $response * @return Response */ - protected function finish(Destination $destination, $response) + protected function finish($destination, $response) { if ( ! $response instanceof Response) $response = new Response($response); @@ -177,22 +156,6 @@ class Caller { return $response; } - /** - * Run the "before" filters for the routing destination. - * - * If a before filter returns a value, that value will be considered the response to the - * request and the route function / controller will not be used to handle the request. - * - * @param Route $route - * @return mixed - */ - protected function before(Destination $destination) - { - $before = array_merge(array('before'), $destination->filters('before')); - - return $this->filter($before, array(), true); - } - /** * Call a filter or set of filters. * diff --git a/laravel/routing/destination.php b/laravel/routing/destination.php deleted file mode 100644 index 69338180..00000000 --- a/laravel/routing/destination.php +++ /dev/null @@ -1,13 +0,0 @@ -callback) and isset($this->callback['delegate']); + } + /** * Determine if the route has a given name. * diff --git a/laravel/routing/router.php b/laravel/routing/router.php index 557276b3..c9ec23d9 100644 --- a/laravel/routing/router.php +++ b/laravel/routing/router.php @@ -1,18 +1,4 @@ - + * // Get the current user of the application + * $user = Auth::user(); + * + * // Access a property on the current user of the application + * $email = Auth::user()->email; + * * * @return object */ @@ -64,8 +73,8 @@ class Auth { /** * Attempt to log a user into the application. * - * If the given credentials are valid, the user will be considered logged into the - * application and their user ID will be stored in the session data. + * If the given credentials are valid, the user will be considered logged into + * the application and their user ID will be stored in the session data. * * @param string $username * @param string $password @@ -101,6 +110,8 @@ class Auth { /** * Log the current user out of the application. * + * The "logout" closure in the authenciation configuration file will be called. + * * @return void */ public function logout() diff --git a/laravel/security/hashing/bcrypt.php b/laravel/security/hashing/bcrypt.php index b2e61157..0e89af31 100644 --- a/laravel/security/hashing/bcrypt.php +++ b/laravel/security/hashing/bcrypt.php @@ -1,30 +1,30 @@ in 2004-2006 and placed in -# the public domain. Revised in subsequent years, still public domain. -# -# There's absolutely no warranty. -# -# The homepage URL for this framework is: -# -# http://www.openwall.com/phpass/ -# -# Please be sure to update the Version line if you edit this file in any way. -# It is suggested that you leave the main version number intact, but indicate -# your project name (after the slash) and add your own revision information. -# -# Please do not change the "private" password hashing method implemented in -# here, thereby making your hashes incompatible. However, if you must, please -# change the hash type identifier (the "$P$") to something different. -# -# Obviously, since this code is in the public domain, the above are not -# requirements (there can be none), but merely suggestions. -# +// +// Portable PHP password hashing framework. +// +// Version 0.3 / genuine. +// +// Written by Solar Designer in 2004-2006 and placed in +// the public domain. Revised in subsequent years, still public domain. +// +// There's absolutely no warranty. +// +// The homepage URL for this framework is: +// +// http://www.openwall.com/phpass/ +// +// Please be sure to update the Version line if you edit this file in any way. +// It is suggested that you leave the main version number intact, but indicate +// your project name (after the slash) and add your own revision information. +// +// Please do not change the "private" password hashing method implemented in +// here, thereby making your hashes incompatible. However, if you must, please +// change the hash type identifier (the "$P$") to something different. +// +// Obviously, since this code is in the public domain, the above are not +// requirements (there can be none), but merely suggestions. +// class Bcrypt implements Engine { var $itoa64; var $iteration_count_log2; @@ -123,12 +123,12 @@ class Bcrypt implements Engine { if (strlen($salt) != 8) return $output; - # We're kind of forced to use MD5 here since it's the only - # cryptographic primitive available in all versions of PHP - # currently in use. To implement our own low-level crypto - # in PHP would result in much worse performance and - # consequently in lower iteration counts and hashes that are - # quicker to crack (by non-PHP code). + // We're kind of forced to use MD5 here since it's the only + // cryptographic primitive available in all versions of PHP + // currently in use. To implement our own low-level crypto + // in PHP would result in much worse performance and + // consequently in lower iteration counts and hashes that are + // quicker to crack (by non-PHP code). if (PHP_VERSION >= '5') { $hash = md5($salt . $password, TRUE); do { @@ -150,8 +150,8 @@ class Bcrypt implements Engine { protected function gensalt_extended($input) { $count_log2 = min($this->iteration_count_log2 + 8, 24); - # This should be odd to not reveal weak DES keys, and the - # maximum valid value is (2**24 - 1) which is odd anyway. + // This should be odd to not reveal weak DES keys, and the + // maximum valid value is (2**24 - 1) which is odd anyway. $count = (1 << $count_log2) - 1; $output = '_'; @@ -167,14 +167,14 @@ class Bcrypt implements Engine { protected function gensalt_blowfish($input) { - # This one needs to use a different order of characters and a - # different encoding scheme from the one in encode64() above. - # We care because the last character in our encoded string will - # only represent 2 bits. While two known implementations of - # bcrypt will happily accept and correct a salt string which - # has the 4 unused bits set to non-zero, we do not want to take - # chances and we also do not want to waste an additional byte - # of entropy. + // This one needs to use a different order of characters and a + // different encoding scheme from the one in encode64() above. + // We care because the last character in our encoded string will + // only represent 2 bits. While two known implementations of + // bcrypt will happily accept and correct a salt string which + // has the 4 unused bits set to non-zero, we do not want to take + // chances and we also do not want to waste an additional byte + // of entropy. $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; $output = '$2a$'; @@ -235,9 +235,9 @@ class Bcrypt implements Engine { if (strlen($hash) == 34) return $hash; - # Returning '*' on error is safe here, but would _not_ be safe - # in a crypt(3)-like function used _both_ for generating new - # hashes and for validating passwords against existing hashes. + // Returning '*' on error is safe here, but would _not_ be safe + // in a crypt(3)-like function used _both_ for generating new + // hashes and for validating passwords against existing hashes. return '*'; } diff --git a/laravel/session/payload.php b/laravel/session/payload.php index 3685aaf6..63c39cb2 100644 --- a/laravel/session/payload.php +++ b/laravel/session/payload.php @@ -46,6 +46,14 @@ class Payload { * * A default value may also be specified, and will be returned in the item doesn't exist. * + * + * // Get an item from the session + * $name = Session::get('name'); + * + * // Return a default value if the item doesn't exist + * $name = Session::get('name', 'Taylor'); + * + * * @param string $key * @param mixed $default * @return mixed @@ -66,6 +74,11 @@ class Payload { /** * Write an item to the session. * + * + * // Write an item to the session + * Session::put('name', 'Taylor'); + * + * * @param string $key * @param mixed $value * @return Driver @@ -83,6 +96,11 @@ class Payload { * Flash data only exists for the next request. After that, it will be removed from * the session. Flash data is useful for temporary status or welcome messages. * + * + * // Flash an item to the session + * Session::flash('name', 'Taylor'); + * + * * @param string $key * @param mixed $value * @return Driver @@ -110,6 +128,11 @@ class Payload { * If a string is passed to the method, only that item will be kept. An array may also * be passed to the method, in which case all items in the array will be kept. * + * + * // Keep a session flash item from expiring + * Session::keep('name'); + * + * * @param string|array $key * @return void */ diff --git a/laravel/session/transporters/cookie.php b/laravel/session/transporters/cookie.php index 82fe14cb..73790a0e 100644 --- a/laravel/session/transporters/cookie.php +++ b/laravel/session/transporters/cookie.php @@ -9,6 +9,13 @@ class Cookie implements Transporter { */ protected $cookies; + /** + * The name of the cookie used to store the session ID. + * + * @var string + */ + const key = 'laravel_session'; + /** * Create a new cookie session transporter instance. * @@ -28,7 +35,7 @@ class Cookie implements Transporter { */ public function get($config) { - return $this->cookies->get('laravel_session'); + return $this->cookies->get(Cookie::key); } /** @@ -40,9 +47,12 @@ class Cookie implements Transporter { */ public function put($id, $config) { - $minutes = ($config['expire_on_close']) ? 0 : $config['lifetime']; + // Session cookies may be set to expire on close, which means we will need to + // pass "0" into the cookie manager. This will cause the cookie to not be + // deleted until the user closes their browser. + $minutes = ( ! $config['expire_on_close']) ? $config['lifetime'] : 0; - $this->cookies->put('laravel_session', $id, $minutes, $config['path'], $config['domain']); + $this->cookies->put(Cookie::key, $id, $minutes, $config['path'], $config['domain']); } } \ No newline at end of file diff --git a/laravel/session/transporters/transporter.php b/laravel/session/transporters/transporter.php index b1c464ab..dbed1b6d 100644 --- a/laravel/session/transporters/transporter.php +++ b/laravel/session/transporters/transporter.php @@ -1,5 +1,9 @@ rules = $rules; + $this->messages = $messages; $this->attributes = $attributes; - $this->messages = array_merge($this->messages, $messages); } /** * Create a new validator instance. * - * @param array $attributes - * @param array $rules - * @param array $messages + * @param array $attributes + * @param array $rules + * @param array $messages * @return Validator */ public static function make($attributes, $rules, $messages = array()) @@ -97,6 +104,18 @@ class Validator { return new static($attributes, $rules, $messages); } + /** + * Register a custom validator. + * + * @param string $name + * @param Closure $validator + * @return void + */ + public static function register($name, $validator) + { + static::$validators[$name] = $validator; + } + /** * Validate the target array using the specified validation rules. * @@ -138,7 +157,7 @@ class Validator { { list($rule, $parameters) = $this->parse($rule); - if ( ! method_exists($this, $validator = 'validate_'.$rule)) + if ( ! method_exists($this, $validator = 'validate_'.$rule) and ! isset(static::$validators[$rule])) { throw new \Exception("Validation rule [$rule] doesn't exist."); } @@ -327,7 +346,7 @@ class Validator { { if ( ! isset($parameters[1])) $parameters[1] = $attribute; - if (is_null($this->connection)) $this->connection = Database::connection(); + if (is_null($this->connection)) $this->connection = DB::connection(); return $this->connection->table($parameters[0])->where($parameters[1], '=', $this->attributes[$attribute])->count() == 0; } @@ -434,8 +453,8 @@ class Validator { * Developer specified attribute specific rules take first priority. * Developer specified error rules take second priority. * - * If the message has not been specified by the developer, the default will be used - * from the validation language file. + * If the message has not been specified by the developer, the default + * will be used from the validation language file. * * @param string $attribute * @param string $rule @@ -479,16 +498,23 @@ class Validator { */ protected function format_message($message, $attribute, $rule, $parameters) { - $display = Lang::line('attributes.'.$attribute)->get($this->language, str_replace('_', ' ', $attribute)); + // First we will get the language line for the attribute being validated. + // Storing attribute names in a validation file allows the easily replacement + // of attribute names (email) with more reader friendly versions (E-Mail). + $display = Lang::line('validation.attributes.'.$attribute)->get($this->language, str_replace('_', ' ', $attribute)); $message = str_replace(':attribute', $display, $message); + // The "size" family of rules all have place-holders for the values applicable + // to their function. For example, the "max" rule has a ":max" place-holder. if (in_array($rule, $this->size_rules)) { $max = ($rule == 'between') ? $parameters[1] : $parameters[0]; $message = str_replace(array(':size', ':min', ':max'), array($parameters[0], $parameters[0], $max), $message); } + // The "inclusion" rules, which are rules that check if a value is within + // a list of values, all have a place-holder to display the allowed values. elseif (in_array($rule, array('in', 'not_in', 'mimes'))) { $message = str_replace(':values', implode(', ', $parameters), $message); @@ -524,6 +550,9 @@ class Validator { */ protected function parse($rule) { + // The format for specifying validation rules and parameters follows a {rule}:{parameters} + // convention. For instance, "max:3" specifies that the value may only be 3 characters in + // length. And "unique:users" specifies that a value must be unique on the "users" table. $parameters = (($colon = strpos($rule, ':')) !== false) ? explode(',', substr($rule, $colon + 1)) : array(); return array(is_numeric($colon) ? substr($rule, 0, $colon) : $rule, $parameters); @@ -553,4 +582,20 @@ class Validator { return $this; } + /** + * Dynamically handle calls to custom registered validators. + */ + public function __call($method, $parameters) + { + // First we will slice the "validate_" prefix off of the validator since custom + // validators are not registered with such a prefix. We will then call the validator + // and pass it the parameters we received. + if (isset(static::$validators[$method = substr($method, 9)])) + { + return call_user_func_array(static::$validators[$method], $parameters); + } + + throw new \Exception("Call to undefined method [$method] on Validator instance."); + } + } \ No newline at end of file