From 1e7850d9bad824c1b67b3005580882fdc2355cef Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 25 Aug 2011 22:53:05 -0500 Subject: [PATCH] refactoring for dependency injection and testability. --- application/config/aliases.php | 18 +- application/config/{db.php => database.php} | 0 application/config/error.php | 4 +- application/controllers/.gitignore | 0 application/filters.php | 6 +- application/language/en/.gitignore | 0 laravel/asset.php | 18 +- laravel/cache/file.php | 64 +--- laravel/{cache.php => cache/manager.php} | 23 +- laravel/config.php | 2 +- laravel/config/container.php | 174 ++++++++++ laravel/config/dependencies.php | 99 ------ laravel/container.php | 110 ------ laravel/controller.php | 21 ++ laravel/cookie.php | 36 +- laravel/{db => database}/connection.php | 2 +- laravel/database/connector.php | 28 ++ .../{db => database}/connector/callback.php | 0 .../{db => database}/connector/factory.php | 0 laravel/{db => database}/connector/mysql.php | 0 .../{db => database}/connector/postgres.php | 0 laravel/{db => database}/connector/sqlite.php | 0 .../{db => database}/eloquent/hydrator.php | 11 +- laravel/{db => database}/eloquent/model.php | 46 +-- laravel/{db.php => database/manager.php} | 20 +- laravel/{db => database}/query.php | 55 ++- laravel/{db => database}/query/compiler.php | 4 +- .../query/compiler/factory.php | 6 +- .../{db => database}/query/compiler/mysql.php | 4 +- .../query/compiler/postgres.php | 4 +- laravel/{db => database}/query/factory.php | 6 +- laravel/{db => database}/query/postgres.php | 4 +- laravel/db/connector.php | 26 -- laravel/download.php | 8 +- laravel/error.php | 26 ++ laravel/exception/examiner.php | 17 +- laravel/exception/handler.php | 32 +- laravel/file.php | 75 ++++- laravel/form.php | 22 +- laravel/html.php | 20 +- laravel/inflector.php | 4 +- laravel/input.php | 37 +-- laravel/ioc.php | 125 +++++++ laravel/lang.php | 42 +-- laravel/lang/en/pagination.php | 14 - laravel/{lang => language}/en/validation.php | 0 laravel/laravel.php | 69 ++-- laravel/package.php | 5 +- laravel/paginator.php | 314 ------------------ laravel/redirect.php | 19 +- laravel/request.php | 16 - laravel/response.php | 44 +-- laravel/routing/filter.php | 56 ---- laravel/routing/finder.php | 40 --- laravel/routing/handler.php | 192 +++++++++++ laravel/routing/loader.php | 116 ------- laravel/routing/route.php | 74 ++--- laravel/routing/router.php | 144 ++++++-- .../{auth.php => security/authenticator.php} | 26 +- laravel/{ => security}/crypter.php | 6 +- laravel/{hash => security/hashing}/bcrypt.php | 2 +- laravel/{hash => security/hashing}/engine.php | 2 +- laravel/{ => security/hashing}/hasher.php | 12 +- laravel/session/apc.php | 44 ++- laravel/session/cookie.php | 43 ++- laravel/session/database.php | 96 ++++++ laravel/session/db.php | 52 --- laravel/session/file.php | 51 ++- laravel/{session.php => session/manager.php} | 30 +- laravel/session/memcached.php | 44 ++- laravel/url.php | 85 +++-- laravel/{ => validation}/messages.php | 2 +- laravel/{ => validation}/validator.php | 33 +- laravel/view.php | 70 ++-- public/index.php | 2 +- 75 files changed, 1441 insertions(+), 1461 deletions(-) rename application/config/{db.php => database.php} (100%) create mode 100644 application/controllers/.gitignore create mode 100644 application/language/en/.gitignore rename laravel/{cache.php => cache/manager.php} (71%) create mode 100644 laravel/config/container.php delete mode 100644 laravel/config/dependencies.php delete mode 100644 laravel/container.php create mode 100644 laravel/controller.php rename laravel/{db => database}/connection.php (99%) create mode 100644 laravel/database/connector.php rename laravel/{db => database}/connector/callback.php (100%) rename laravel/{db => database}/connector/factory.php (100%) rename laravel/{db => database}/connector/mysql.php (100%) rename laravel/{db => database}/connector/postgres.php (100%) rename laravel/{db => database}/connector/sqlite.php (100%) rename laravel/{db => database}/eloquent/hydrator.php (97%) rename laravel/{db => database}/eloquent/model.php (91%) rename laravel/{db.php => database/manager.php} (81%) rename laravel/{db => database}/query.php (94%) rename laravel/{db => database}/query/compiler.php (99%) rename laravel/{db => database}/query/compiler/factory.php (86%) rename laravel/{db => database}/query/compiler/mysql.php (66%) rename laravel/{db => database}/query/compiler/postgres.php (80%) rename laravel/{db => database}/query/factory.php (82%) rename laravel/{db => database}/query/postgres.php (90%) delete mode 100644 laravel/db/connector.php create mode 100644 laravel/error.php delete mode 100644 laravel/lang/en/pagination.php rename laravel/{lang => language}/en/validation.php (100%) delete mode 100644 laravel/paginator.php delete mode 100644 laravel/routing/filter.php delete mode 100644 laravel/routing/finder.php create mode 100644 laravel/routing/handler.php delete mode 100644 laravel/routing/loader.php rename laravel/{auth.php => security/authenticator.php} (87%) rename laravel/{ => security}/crypter.php (94%) rename laravel/{hash => security/hashing}/bcrypt.php (99%) rename laravel/{hash => security/hashing}/engine.php (88%) rename laravel/{ => security/hashing}/hasher.php (81%) create mode 100644 laravel/session/database.php delete mode 100644 laravel/session/db.php rename laravel/{session.php => session/manager.php} (67%) rename laravel/{ => validation}/messages.php (98%) rename laravel/{ => validation}/validator.php (91%) diff --git a/application/config/aliases.php b/application/config/aliases.php index c9c547a1..6442e1b3 100644 --- a/application/config/aliases.php +++ b/application/config/aliases.php @@ -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 diff --git a/application/config/db.php b/application/config/database.php similarity index 100% rename from application/config/db.php rename to application/config/database.php diff --git a/application/config/error.php b/application/config/error.php index 885e95c1..4a0896da 100644 --- a/application/config/error.php +++ b/application/config/error.php @@ -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 diff --git a/application/controllers/.gitignore b/application/controllers/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/application/filters.php b/application/filters.php index daf0a6a6..ef07e5da 100644 --- a/application/filters.php +++ b/application/filters.php @@ -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 diff --git a/application/language/en/.gitignore b/application/language/en/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/laravel/asset.php b/laravel/asset.php index 3bdbe948..9f4cec97 100644 --- a/laravel/asset.php +++ b/laravel/asset.php @@ -1,8 +1,5 @@ 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); } diff --git a/laravel/cache/file.php b/laravel/cache/file.php index 29fe1649..91f33d92 100644 --- a/laravel/cache/file.php +++ b/laravel/cache/file.php @@ -1,75 +1,21 @@ 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 diff --git a/laravel/cache.php b/laravel/cache/manager.php similarity index 71% rename from laravel/cache.php rename to laravel/cache/manager.php index 4b580210..51041a7a 100644 --- a/laravel/cache.php +++ b/laravel/cache/manager.php @@ -1,6 +1,9 @@ -resolve('laravel.cache.file'); - - case 'memcached': - return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.memcached'); - - case 'apc': - return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.apc'); - - default: - throw new \Exception("Cache driver [$driver] is not supported."); + throw new \Exception("Cache driver [$driver] is not supported."); } + + return static::$drivers[$driver] = IoC::container()->resolve('laravel.cache.'.$driver); } return static::$drivers[$driver]; diff --git a/laravel/config.php b/laravel/config.php index c8874dc8..35a8deef 100644 --- a/laravel/config.php +++ b/laravel/config.php @@ -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'); * * * @param string $key diff --git a/laravel/config/container.php b/laravel/config/container.php new file mode 100644 index 00000000..e9b5e6d0 --- /dev/null +++ b/laravel/config/container.php @@ -0,0 +1,174 @@ + array('singleton' => true, 'resolver' => function() + { + return new File; + }), + + /* + |-------------------------------------------------------------------------- + | Laravel View Components + |-------------------------------------------------------------------------- + */ + + 'laravel.composers' => array('singleton' => true, 'resolver' => function() + { + return require APP_PATH.'composers'.EXT; + }), + + /* + |-------------------------------------------------------------------------- + | Laravel Routing Components + |-------------------------------------------------------------------------- + */ + + 'laravel.routing.router' => array('singleton' => true, 'resolver' => function($container) + { + 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 Security Components + |-------------------------------------------------------------------------- + */ + + 'laravel.security.auth' => array('resolver' => function($container) + { + $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 Session Components + |-------------------------------------------------------------------------- + */ + + 'laravel.session.driver' => array('resolver' => function() + { + return Session\Manager::driver(); + }), + + /* + |-------------------------------------------------------------------------- + | Laravel Cookie Session Components + |-------------------------------------------------------------------------- + */ + + 'laravel.session.cookie' => array('resolver' => function($container) + { + return new Session\Cookie(new Crypter, $container->resolve('laravel.request')->input->cookies); + }), + + /* + |-------------------------------------------------------------------------- + | 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')) + { + throw new \Exception('Attempting to use Memcached, but the Memcache PHP extension is not installed on this server.'); + } + + $memcache = new \Memcache; + + foreach (Config::get('cache.servers') as $server) + { + $memcache->addServer($server['host'], $server['port'], true, $server['weight']); + } + + if ($memcache->getVersion() === false) + { + throw new \Exception('Memcached is configured. However, no connections could be made. Please verify your memcached configuration.'); + } + + return $memcache; + }), + +); \ No newline at end of file diff --git a/laravel/config/dependencies.php b/laravel/config/dependencies.php deleted file mode 100644 index 42d68654..00000000 --- a/laravel/config/dependencies.php +++ /dev/null @@ -1,99 +0,0 @@ - array('singleton' => true, 'resolver' => function() - { - return new URL; - }), - - /* - |-------------------------------------------------------------------------- - | Laravel File Cache Driver - |-------------------------------------------------------------------------- - */ - - 'laravel.cache.file' => array('resolver' => function($container) - { - return new Cache\File($container->resolve('laravel.cache.file_engine')); - }), - - /* - |-------------------------------------------------------------------------- - | Laravel File Cache Driver Engine - |-------------------------------------------------------------------------- - */ - - 'laravel.cache.file_engine' => array('resolver' => function() - { - return new Cache\File_Engine; - }), - - /* - |-------------------------------------------------------------------------- - | Laravel APC Cache Driver - |-------------------------------------------------------------------------- - */ - - 'laravel.cache.apc' => array('resolver' => function($container) - { - return new Cache\APC($container->resolve('laravel.cache.apc_engine')); - }), - - /* - |-------------------------------------------------------------------------- - | Laravel APC Cache Driver Engine - |-------------------------------------------------------------------------- - */ - - 'laravel.cache.apc_engine' => array('resolver' => function() - { - return new Cache\APC_Engine; - }), - - /* - |-------------------------------------------------------------------------- - | Laravel Memcached Cache Driver - |-------------------------------------------------------------------------- - */ - - 'laravel.cache.memcached' => array('resolver' => function($container) - { - return new Cache\Memcached($container->resolve('laravel.memcache')); - }), - - /* - |-------------------------------------------------------------------------- - | Memcache Connection - |-------------------------------------------------------------------------- - */ - - 'laravel.memcache' => array('singleton' => true, 'resolver' => function() - { - if ( ! class_exists('Memcache')) - { - throw new \Exception('Attempting to use Memcached, but the Memcache PHP extension is not installed on this server.'); - } - - $memcache = new \Memcache; - - foreach (Config::get('cache.servers') as $server) - { - $memcache->addServer($server['host'], $server['port'], true, $server['weight']); - } - - if ($memcache->getVersion() === false) - { - throw new \Exception('Memcached is configured. However, no connections could be made. Please verify your memcached configuration.'); - } - - return $memcache; - }), - -); \ No newline at end of file diff --git a/laravel/container.php b/laravel/container.php deleted file mode 100644 index 2f76eb28..00000000 --- a/laravel/container.php +++ /dev/null @@ -1,110 +0,0 @@ - - * // Register a simple dependency - * $container->register('name', function() { return 'Fred'; }); - * - * // Register a dependency as a singleton - * $container->register('name', function() { return new Name; }, true); - * - * - * @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. - * - * - * // Register a dependency as a singleton - * $container->singleton('user', function() { return new User; }) - * - * - * @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. - * - * - * // Register an object instance as a singleton in the container - * $container->instance('user', new User); - * - * - * @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. - * - * - * // Resolver the "name" dependency - * $name = $container->resolve('name'); - * - * - * @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 diff --git a/laravel/controller.php b/laravel/controller.php new file mode 100644 index 00000000..4c774267 --- /dev/null +++ b/laravel/controller.php @@ -0,0 +1,21 @@ +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 diff --git a/laravel/db/connection.php b/laravel/database/connection.php similarity index 99% rename from laravel/db/connection.php rename to laravel/database/connection.php index ccf59e04..e1247388 100644 --- a/laravel/db/connection.php +++ b/laravel/database/connection.php @@ -1,4 +1,4 @@ - 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, + ); + + /** + * Establish a PDO database connection. + * + * @param array $config + * @return PDO + */ + abstract public function connect($config); + +} \ No newline at end of file diff --git a/laravel/db/connector/callback.php b/laravel/database/connector/callback.php similarity index 100% rename from laravel/db/connector/callback.php rename to laravel/database/connector/callback.php diff --git a/laravel/db/connector/factory.php b/laravel/database/connector/factory.php similarity index 100% rename from laravel/db/connector/factory.php rename to laravel/database/connector/factory.php diff --git a/laravel/db/connector/mysql.php b/laravel/database/connector/mysql.php similarity index 100% rename from laravel/db/connector/mysql.php rename to laravel/database/connector/mysql.php diff --git a/laravel/db/connector/postgres.php b/laravel/database/connector/postgres.php similarity index 100% rename from laravel/db/connector/postgres.php rename to laravel/database/connector/postgres.php diff --git a/laravel/db/connector/sqlite.php b/laravel/database/connector/sqlite.php similarity index 100% rename from laravel/db/connector/sqlite.php rename to laravel/database/connector/sqlite.php diff --git a/laravel/db/eloquent/hydrator.php b/laravel/database/eloquent/hydrator.php similarity index 97% rename from laravel/db/eloquent/hydrator.php rename to laravel/database/eloquent/hydrator.php index 4d38ffac..49684bc9 100644 --- a/laravel/db/eloquent/hydrator.php +++ b/laravel/database/eloquent/hydrator.php @@ -1,4 +1,4 @@ -exists = true; - $models[$model->id] = $model; + if (isset($model->attributes['id'])) + { + $models[$model->id] = $model; + } + else + { + $models[] = $model; + } } return $models; diff --git a/laravel/db/eloquent/model.php b/laravel/database/eloquent/model.php similarity index 91% rename from laravel/db/eloquent/model.php rename to laravel/database/eloquent/model.php index f337e7d0..3ed36f27 100644 --- a/laravel/db/eloquent/model.php +++ b/laravel/database/eloquent/model.php @@ -1,10 +1,10 @@ -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('*')) + private function _get() { - $total = $this->query->count(); - - if (is_null($per_page)) - { - $per_page = (property_exists(get_class($this), 'per_page')) ? static::$per_page : 20; - } - - return 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); } diff --git a/laravel/db.php b/laravel/database/manager.php similarity index 81% rename from laravel/db.php rename to laravel/database/manager.php index 0508ee26..1ed18e80 100644 --- a/laravel/db.php +++ b/laravel/database/manager.php @@ -1,6 +1,8 @@ - * - * @param string $connection - * @return DB\Connection + * @param string $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) { diff --git a/laravel/db/query.php b/laravel/database/query.php similarity index 94% rename from laravel/db/query.php rename to laravel/database/query.php index 7f4cb1c0..8294c50f 100644 --- a/laravel/db/query.php +++ b/laravel/database/query.php @@ -1,9 +1,9 @@ - + * // Get the the 15 users that should be displayed for page 1 + * $results = DB::table('users')->for_page(1, 15); + * + * + * @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. - * - * - * // 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); - * - * - * @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. * diff --git a/laravel/db/query/compiler.php b/laravel/database/query/compiler.php similarity index 99% rename from laravel/db/query/compiler.php rename to laravel/database/query/compiler.php index 891c7138..0e86a97a 100644 --- a/laravel/db/query/compiler.php +++ b/laravel/database/query/compiler.php @@ -1,6 +1,6 @@ - \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, - ); - - /** - * Establish a PDO database connection. - * - * @param array $config - * @return PDO - */ - abstract public function connect($config); - -} \ No newline at end of file diff --git a/laravel/download.php b/laravel/download.php index 1d042a5b..8fa2b523 100644 --- a/laravel/download.php +++ b/laravel/download.php @@ -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 diff --git a/laravel/error.php b/laravel/error.php new file mode 100644 index 00000000..28242e2a --- /dev/null +++ b/laravel/error.php @@ -0,0 +1,26 @@ + + * // Return a 404 error response + * return new Error('404'); + * + * + * @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 diff --git a/laravel/exception/examiner.php b/laravel/exception/examiner.php index 14f49b31..d6778c5e 100644 --- a/laravel/exception/examiner.php +++ b/laravel/exception/examiner.php @@ -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()); } /** diff --git a/laravel/exception/handler.php b/laravel/exception/handler.php index 3e21da5e..f327f3cc 100644 --- a/laravel/exception/handler.php +++ b/laravel/exception/handler.php @@ -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); diff --git a/laravel/file.php b/laravel/file.php index 0349f3cf..6ae6b91f 100644 --- a/laravel/file.php +++ b/laravel/file.php @@ -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 { * * * // 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); * * * @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 { * * * // Returns "application/x-tar" - * $mime = File::mime('tar'); + * $mime = $file->mime('tar'); * * * @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 { * * * // Determine if the file is a JPG image - * $image = File::is('jpg', 'path/to/image.jpg'); + * $image = $file->is('jpg', 'path/to/image.jpg'); * * * @param string $extension * @param string $path * @return bool */ - public static function is($extension, $path) + public function is($extension, $path) { $mimes = Config::get('mimes'); diff --git a/laravel/form.php b/laravel/form.php index 03732c59..c9d6310b 100644 --- a/laravel/form.php +++ b/laravel/form.php @@ -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); } diff --git a/laravel/html.php b/laravel/html.php index c665bc1a..1e6421f1 100644 --- a/laravel/html.php +++ b/laravel/html.php @@ -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 ''.PHP_EOL; + return ''.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 ''.PHP_EOL; + return ''.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 ''.static::entities($title).''; + return ''.static::entities($title).''; } /** @@ -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 ''.static::entities($title).''; + $email = 'mailto:'.$email; + + return ''.static::entities($title).''; } /** @@ -195,7 +195,7 @@ class HTML { { $attributes['alt'] = static::entities($alt); - return ''; + return ''; } /** diff --git a/laravel/inflector.php b/laravel/inflector.php index 8fdb977e..dad4fc30 100644 --- a/laravel/inflector.php +++ b/laravel/inflector.php @@ -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); } /** diff --git a/laravel/input.php b/laravel/input.php index c74a969e..588642d6 100644 --- a/laravel/input.php +++ b/laravel/input.php @@ -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 array $get - * @param array $post - * @param array $cookies - * @param array $files + * @param string $method + * @param bool $spoofed + * @param array $get + * @param array $post + * @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. - * * * // 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); } diff --git a/laravel/ioc.php b/laravel/ioc.php index 551579d4..a4e43fbd 100644 --- a/laravel/ioc.php +++ b/laravel/ioc.php @@ -67,4 +67,129 @@ class IoC { return call_user_func_array(array(static::container(), $method), $parameters); } +} + +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. + * + * + * // Register a simple dependency + * $container->register('name', function() { return 'Fred'; }); + * + * // Register a dependency as a singleton + * $container->register('name', function() { return new Name; }, true); + * + * + * @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. + * + * + * // Determine if the "user" dependency is registered in the container + * $registered = $container->registered('user'); + * + * + * @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. + * + * + * // Register a dependency as a singleton + * $container->singleton('user', function() { return new User; }) + * + * + * @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. + * + * + * // Register an object instance as a singleton in the container + * $container->instance('user', new User); + * + * + * @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. + * + * + * // Resolver the "name" dependency + * $name = $container->resolve('name'); + * + * + * @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 diff --git a/laravel/lang.php b/laravel/lang.php index a1f244db..ceeb2fa4 100644 --- a/laravel/lang.php +++ b/laravel/lang.php @@ -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. - * - * - * // Get a "fr" language line - * $line = Lang::line('validation.required')->in('fr')->get(); - * - * - * @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. + * + * + * // Get a "fr" language line + * $line = Lang::line('validation.required')->in('fr')->get(); + * + * + * @param string $language + * @return Lang + */ + public function in($language) + { + $this->language = $language; + return $this; + } + /** * Get the string content of the language line. */ diff --git a/laravel/lang/en/pagination.php b/laravel/lang/en/pagination.php deleted file mode 100644 index eef78c03..00000000 --- a/laravel/lang/en/pagination.php +++ /dev/null @@ -1,14 +0,0 @@ - '« Previous', - 'next' => 'Next »', - -); \ No newline at end of file diff --git a/laravel/lang/en/validation.php b/laravel/language/en/validation.php similarity index 100% rename from laravel/lang/en/validation.php rename to laravel/language/en/validation.php diff --git a/laravel/laravel.php b/laravel/laravel.php index 40e79b61..3fe3a2bf 100644 --- a/laravel/laravel.php +++ b/laravel/laravel.php @@ -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. +// Hydrate the input for the current request. // -------------------------------------------------------------- -Routing\Filter::register(require APP_PATH.'filters'.EXT); - -// -------------------------------------------------------------- -// Call the "before" filter for the application and module. -// -------------------------------------------------------------- -$response = Routing\Filter::call('before', array($request->method(), $request->uri()), true); +$request->input = new Input($request->method(), $request->is_spoofed(), $_GET, $_POST, $_FILES, new Cookie($_COOKIE)); // -------------------------------------------------------------- // Route the request and get the response from the route. // -------------------------------------------------------------- -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()); diff --git a/laravel/package.php b/laravel/package.php index 82e2f5fc..361f8bdc 100644 --- a/laravel/package.php +++ b/laravel/package.php @@ -23,13 +23,14 @@ class Package { * * * @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; } diff --git a/laravel/paginator.php b/laravel/paginator.php deleted file mode 100644 index a369285d..00000000 --- a/laravel/paginator.php +++ /dev/null @@ -1,314 +0,0 @@ - - * // Create a Paginator for the first page of 10 total results and 2 items per page - * $paginator = new Paginator(1, 10, 2); - * - * - * @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 ''; - } - - /** - * 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).'...'; - } - - /** - * 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. - * - * 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. - * - * - * // Set the "sort" query string item on the links that will be generated - * echo $paginator->append(array('sort' => 'desc'))->links(); - * - * - * @param array $values - * @return Paginator - */ - public function append($values) - { - $this->append = $values; - return $this; - } - -} \ No newline at end of file diff --git a/laravel/redirect.php b/laravel/redirect.php index 98d71832..7290fa79 100644 --- a/laravel/redirect.php +++ b/laravel/redirect.php @@ -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."); diff --git a/laravel/request.php b/laravel/request.php index b3e1943c..7ac16db5 100644 --- a/laravel/request.php +++ b/laravel/request.php @@ -213,20 +213,4 @@ class Request { } } - /** - * Magic Method for dynamically retrieving properties of the request instance. - * - * - * // Get all of the input for the request - * $input = Request::active()->input; - * - */ - public function __get($key) - { - if ($key === 'input') - { - return $this->input->all(); - } - } - } \ No newline at end of file diff --git a/laravel/response.php b/laravel/response.php index 2df1f941..15f6d63a 100644 --- a/laravel/response.php +++ b/laravel/response.php @@ -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. - * - * - * // Return a 404 error response - * return Response::error('404'); - * - * - * @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(); diff --git a/laravel/routing/filter.php b/laravel/routing/filter.php deleted file mode 100644 index 68b6b5b6..00000000 --- a/laravel/routing/filter.php +++ /dev/null @@ -1,56 +0,0 @@ -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 diff --git a/laravel/routing/handler.php b/laravel/routing/handler.php new file mode 100644 index 00000000..d391840d --- /dev/null +++ b/laravel/routing/handler.php @@ -0,0 +1,192 @@ +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 diff --git a/laravel/routing/loader.php b/laravel/routing/loader.php deleted file mode 100644 index b7c376a2..00000000 --- a/laravel/routing/loader.php +++ /dev/null @@ -1,116 +0,0 @@ -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 diff --git a/laravel/routing/route.php b/laravel/routing/route.php index 5f2bc590..b3450203 100644 --- a/laravel/routing/route.php +++ b/laravel/routing/route.php @@ -1,8 +1,5 @@ callback)) - { - $response = call_user_func_array($this->callback, $this->parameters); - } - 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'])) - { - Filter::call($this->callback['after'], array($response)); - } - - return $response; + return $this->filters('before'); } /** - * Extract the route function from the route. + * Get all of the "after" 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. - * - * @return Closure + * @return array */ - private function find_route_function() + public function after() { - if (isset($this->callback['do'])) return $this->callback['do']; + return $this->filters('after'); + } - foreach ($this->callback as $value) - { - if (is_callable($value)) return $value; - } + /** + * Get an array of filters defined for the route. + * + * + * // Get all of the "before" filters defined for the route. + * $filters = $route->filters('before'); + * + * + * @param string $name + * @return array + */ + private function filters($name) + { + return (is_array($this->callback) and isset($this->callback[$name])) ? explode(', ', $this->callback[$name]) : array(); } } \ No newline at end of file diff --git a/laravel/routing/router.php b/laravel/routing/router.php index eafef559..30c0cefc 100644 --- a/laravel/routing/router.php +++ b/laravel/routing/router.php @@ -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. + * + * + * // 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'); + * + * + * @param string $name + * @return array */ - public static function make(Request $request, Loader $loader) + public function find($name) { - return new static($request, $loader); + if (array_key_exists($name, $this->names)) return $this->names[$name]; + + $arrayIterator = new \RecursiveArrayIterator($this->routes); + + $recursiveIterator = new \RecursiveIteratorIterator($arrayIterator); + + foreach ($recursiveIterator as $iterator) + { + $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,13 +101,75 @@ 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($this->destination, $key)); + 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))) + { + // 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)))); } diff --git a/laravel/auth.php b/laravel/security/authenticator.php similarity index 87% rename from laravel/auth.php rename to laravel/security/authenticator.php index 5a271a2a..e85d590a 100644 --- a/laravel/auth.php +++ b/laravel/security/authenticator.php @@ -1,6 +1,10 @@ -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'); } /** diff --git a/laravel/crypter.php b/laravel/security/crypter.php similarity index 94% rename from laravel/crypter.php rename to laravel/security/crypter.php index 7bcd3ab1..db4bf52e 100644 --- a/laravel/crypter.php +++ b/laravel/security/crypter.php @@ -1,4 +1,6 @@ -cipher = $cipher; $this->mode = $mode; diff --git a/laravel/hash/bcrypt.php b/laravel/security/hashing/bcrypt.php similarity index 99% rename from laravel/hash/bcrypt.php rename to laravel/security/hashing/bcrypt.php index 87a90bfe..3f9b9944 100644 --- a/laravel/hash/bcrypt.php +++ b/laravel/security/hashing/bcrypt.php @@ -1,4 +1,4 @@ -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); } diff --git a/laravel/session/apc.php b/laravel/session/apc.php index 53ae100c..3e37d001 100644 --- a/laravel/session/apc.php +++ b/laravel/session/apc.php @@ -1,23 +1,59 @@ 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 diff --git a/laravel/session/cookie.php b/laravel/session/cookie.php index e353137b..5fa059b3 100644 --- a/laravel/session/cookie.php +++ b/laravel/session/cookie.php @@ -1,10 +1,17 @@ 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 diff --git a/laravel/session/database.php b/laravel/session/database.php new file mode 100644 index 00000000..3a28fc9e --- /dev/null +++ b/laravel/session/database.php @@ -0,0 +1,96 @@ +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); + + if ( ! is_null($session)) + { + return array( + 'id' => $session->id, + 'last_activity' => $session->last_activity, + 'data' => unserialize($session->data) + ); + } + } + + /** + * Save the session to persistant storage. + * + * @return void + */ + protected function save() + { + $this->delete($this->session['id']); + + $this->table()->insert(array( + 'id' => $this->session['id'], + 'last_activity' => $this->session['last_activity'], + 'data' => serialize($this->session['data']) + )); + } + + /** + * 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(); + } + + /** + * Get a session database query. + * + * @return Query + */ + private function table() + { + return $this->connection->table(Config::get('session.table')); + } + +} \ No newline at end of file diff --git a/laravel/session/db.php b/laravel/session/db.php deleted file mode 100644 index c208e021..00000000 --- a/laravel/session/db.php +++ /dev/null @@ -1,52 +0,0 @@ -table()->find($id); - - if ( ! is_null($session)) - { - return array( - 'id' => $session->id, - 'last_activity' => $session->last_activity, - 'data' => unserialize($session->data) - ); - } - } - - protected function save() - { - $this->delete($this->session['id']); - - $this->table()->insert(array( - 'id' => $this->session['id'], - 'last_activity' => $this->session['last_activity'], - 'data' => serialize($this->session['data']) - )); - } - - protected function delete() - { - $this->table()->delete($this->session['id']); - } - - public function sweep($expiration) - { - $this->table()->where('last_activity', '<', $expiration)->delete(); - } - - /** - * Get a session database query. - * - * @return Query - */ - private function table() - { - return \System\DB::connection()->table(Config::get('session.table')); - } - -} \ No newline at end of file diff --git a/laravel/session/file.php b/laravel/session/file.php index 920121a5..055913bb 100644 --- a/laravel/session/file.php +++ b/laravel/session/file.php @@ -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); } } diff --git a/laravel/session.php b/laravel/session/manager.php similarity index 67% rename from laravel/session.php rename to laravel/session/manager.php index b7f4d112..1a0c2abe 100644 --- a/laravel/session.php +++ b/laravel/session/manager.php @@ -1,6 +1,8 @@ -resolve('laravel.session.'.$driver); + } - case 'file': - return static::$driver = new Session\File; - - case 'db': - return static::$driver = new Session\DB; - - case 'memcached': - return static::$driver = new Session\Memcached; - - case 'apc': - return static::$driver = new Session\APC; - - default: - throw new \Exception("Session driver [$driver] is not supported."); - } + throw new \Exception("Session driver [$driver] is not supported."); } return static::$driver; diff --git a/laravel/session/memcached.php b/laravel/session/memcached.php index de186948..21ad9099 100644 --- a/laravel/session/memcached.php +++ b/laravel/session/memcached.php @@ -1,23 +1,59 @@ 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 diff --git a/laravel/url.php b/laravel/url.php index 897c7dad..9c926cef 100644 --- a/laravel/url.php +++ b/laravel/url.php @@ -7,20 +7,22 @@ class URL { * * If the given URL is already well-formed, it will be returned unchanged. * + * + * // Generate the URL: http://example.com/index.php/user/profile + * $url = URL::to('user/profile'); + * + * * @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. * + * + * // Generate the URL: https://example.com/index.php/user/profile + * $url = URL::to_secure('user/profile'); + * + * * @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. + * + * + * // 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); + * * * @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,22 +74,26 @@ 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. + * * * // 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')); * * - * @param string $name - * @param array $parameters - * @param bool $https + * @param string $name + * @param array $parameters + * @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 { * * * // Generate a HTTPS URL for the "profile" named route - * $url = $url->to_secure_route('profile'); + * $url = URL::to_secure_route('profile'); * * * @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 { * * * // 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!!', '_'); * * * @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 { * * * // 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')); * */ - 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."); diff --git a/laravel/messages.php b/laravel/validation/messages.php similarity index 98% rename from laravel/messages.php rename to laravel/validation/messages.php index a919440a..80577871 100644 --- a/laravel/messages.php +++ b/laravel/validation/messages.php @@ -1,4 +1,4 @@ -$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; @@ -442,8 +457,8 @@ class Validator { if (in_array($rule, $this->size_rules) and ! $this->has_rule($attribute, $this->numeric_rules)) { return (array_key_exists($attribute, $_FILES)) - ? rtrim($message, '.').' '.Lang::line('validation.kilobytes')->get($this->language).'.' - : rtrim($message, '.').' '.Lang::line('validation.characters')->get($this->language).'.'; + ? rtrim($message, '.').' '.Lang::line('validation.kilobytes')->get($this->language).'.' + : rtrim($message, '.').' '.Lang::line('validation.characters')->get($this->language).'.'; } return $message; diff --git a/laravel/view.php b/laravel/view.php index a63483f7..d48c0e4c 100644 --- a/laravel/view.php +++ b/laravel/view.php @@ -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')); * * * @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 { * * * // Bind a "name" value to the view - * View::make('home')->bind('name', 'Fred'); + * View::make('home')->with('name', 'Fred'); * * * @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); } /** diff --git a/public/index.php b/public/index.php index e0868e92..19a2f0a5 100644 --- a/public/index.php +++ b/public/index.php @@ -36,4 +36,4 @@ $public = __DIR__; | 3... 2... 1... Lift-off! |-------------------------------------------------------------------------- */ -require $laravel.'/laravel.php'; +require $laravel.'/laravel.php'; \ No newline at end of file