diff --git a/laravel/auth.php b/laravel/auth.php index b5be35b9..381cd3ad 100644 --- a/laravel/auth.php +++ b/laravel/auth.php @@ -1,10 +1,5 @@ session = $driver; + } + /** * Determine if the current user of the application is authenticated. * * @see login() * @return bool */ - public static function check() + public function check() { - return ! is_null(static::user()); + return ! is_null($this->user()); } /** @@ -50,14 +63,14 @@ public static function check() * * @return object */ - public static function user() + public function user() { - if (is_null(static::$user) and Session::has(static::$key)) + if (is_null($this->user) and $this->session->has(static::$key)) { - static::$user = call_user_func(Config::get('auth.by_id'), Session::get(static::$key)); + $this->user = call_user_func(Config::get('auth.by_id'), $this->session->get(static::$key)); } - return static::$user; + return $this->user; } /** @@ -80,13 +93,13 @@ public static function user() * @param string $password * @return bool */ - public static function login($username, $password) + public function login($username, $password) { if ( ! is_null($user = call_user_func(Config::get('auth.by_username'), $username))) { if (Hash::check($password, $user->password)) { - static::remember($user); + $this->remember($user); return true; } @@ -107,11 +120,11 @@ public static function login($username, $password) * @param object $user * @return void */ - public static function remember($user) + public function remember($user) { - static::$user = $user; + $this->user = $user; - Session::put(static::$key, $user->id); + $this->session->put(static::$key, $user->id); } /** @@ -122,11 +135,29 @@ public static function remember($user) * * @return void */ - public static function logout() + public function logout() { - static::$user = null; + $this->user = null; - Session::forget(static::$key); + $this->session->forget(static::$key); + } + + /** + * Pass all other methods to a generic Auth instance. + * + * This provides a convenient API for working with the default Auth configuration. + * + * + * // Get the current user of your application + * $user = Auth::user(); + * + * // Equivalent call using make method + * $user = Auth::make()->user(); + * + */ + public static function __callStatic($method, $parameters) + { + return call_user_func_array(array(new static(Session::driver()), $method), $parameters); } } \ No newline at end of file diff --git a/laravel/cache.php b/laravel/cache.php index 5b0e84fe..bc35c634 100644 --- a/laravel/cache.php +++ b/laravel/cache.php @@ -52,7 +52,7 @@ public static function driver($driver = null) } /** - * Pass all other methods to the default driver. + * Pass all other methods to the default cache driver. * * Passing method calls to the driver instance provides a convenient API for the developer * when always using the default cache driver. diff --git a/laravel/cache/apc.php b/laravel/cache/apc.php index 54964604..0d57f090 100644 --- a/laravel/cache/apc.php +++ b/laravel/cache/apc.php @@ -4,23 +4,57 @@ class APC extends Driver { + /** + * Determine if an item exists in the cache. + * + * + * // Determine if the "name" item exists in the cache + * $exists = Cache::driver()->has('name'); + * + * + * @param string $key + * @return bool + */ public function has($key) { return ( ! is_null($this->get($key))); } - public function get($key, $default = null) + /** + * Retrieve an item from the cache driver. + * + * @param string $key + * @return mixed + */ + protected function retrieve($key) { - $item = ( ! is_null($cache = apc_fetch(Config::get('cache.key').$key))) ? $cache : null; - - return $this->prepare($item, $default); + return ( ! is_null($cache = apc_fetch(Config::get('cache.key').$key))) ? $cache : null; } + /** + * Write an item to the cache for a given number of minutes. + * + * + * // Write the "name" item to the cache for 30 minutes + * Cache::driver()->put('name', 'Fred', 30); + * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return void + */ public function put($key, $value, $minutes) { apc_store(Config::get('cache.key').$key, $value, $minutes * 60); } + /** + * Delete an item from the cache. + * + * @param string $key + * @return void + */ public function forget($key) { apc_delete(Config::get('cache.key').$key); diff --git a/laravel/cache/driver.php b/laravel/cache/driver.php index a4a218a7..67a1dcb4 100644 --- a/laravel/cache/driver.php +++ b/laravel/cache/driver.php @@ -5,6 +5,11 @@ abstract class Driver { /** * Determine if an item exists in the cache. * + * + * // Determine if the "name" item exists in the cache + * $exists = Cache::driver()->has('name'); + * + * * @param string $key * @return bool */ @@ -29,26 +34,28 @@ abstract public function has($key); * @param string $driver * @return mixed */ - abstract public function get($key, $default = null); - - /** - * Prepare the cache item for returning to the requestor. - * - * If the item is NULL, the default will be returned. - * - * @param mixed $item - * @param mixed $default - * @return mixed - */ - protected function prepare($item, $default) + public function get($key, $default = null) { - if ( ! is_null($item)) return $item; + if ( ! is_null($item = $this->retrieve($key))) return $item; return (is_callable($default)) ? call_user_func($default) : $default; } /** - * Write an item to the cache. + * Retrieve an item from the cache driver. + * + * @param string $key + * @return mixed + */ + abstract protected function retrieve($key); + + /** + * Write an item to the cache for a given number of minutes. + * + * + * // Write the "name" item to the cache for 30 minutes + * Cache::driver()->put('name', 'Fred', 30); + * * * @param string $key * @param mixed $value @@ -73,7 +80,7 @@ abstract public function put($key, $value, $minutes); */ public function remember($key, $value, $minutes) { - if ( ! is_null($item = $this->get($key, null, $driver))) return $item; + if ( ! is_null($item = $this->get($key, null))) return $item; $default = is_callable($default) ? call_user_func($default) : $default; diff --git a/laravel/cache/file.php b/laravel/cache/file.php index 65f591db..e1ac5689 100644 --- a/laravel/cache/file.php +++ b/laravel/cache/file.php @@ -2,37 +2,64 @@ class File extends Driver { + /** + * Determine if an item exists in the cache. + * + * + * // Determine if the "name" item exists in the cache + * $exists = Cache::driver()->has('name'); + * + * + * @param string $key + * @return bool + */ public function has($key) { return ( ! is_null($this->get($key))); } - public function get($key, $default = null) + /** + * Retrieve an item from the cache driver. + * + * @param string $key + * @return mixed + */ + protected function retrieve($key) { - if ( ! file_exists(CACHE_PATH.$key)) + if ( ! file_exists(CACHE_PATH.$key)) return null; + + if (time() >= substr($cache = file_get_contents(CACHE_PATH.$key), 0, 10)) { - return $this->prepare(null, $default); + return $this->forget($key); } - $cache = file_get_contents(CACHE_PATH.$key); - - // The cache expiration date is stored as a UNIX timestamp at the beginning - // of the cache file. We'll extract it out and check it here. - if (time() >= substr($cache, 0, 10)) - { - $this->forget($key); - - return $this->prepare(null, $default); - } - - return $this->prepare(unserialize(substr($cache, 10)), $default); + return unserialize(substr($cache, 10)); } + /** + * Write an item to the cache for a given number of minutes. + * + * + * // Write the "name" item to the cache for 30 minutes + * Cache::driver()->put('name', 'Fred', 30); + * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return void + */ public function put($key, $value, $minutes) { file_put_contents(CACHE_PATH.$key, (time() + ($minutes * 60)).serialize($value), LOCK_EX); } + /** + * Delete an item from the cache. + * + * @param string $key + * @return void + */ public function forget($key) { @unlink(CACHE_PATH.$key); diff --git a/laravel/cache/memcached.php b/laravel/cache/memcached.php index fd150d62..37e5c33c 100644 --- a/laravel/cache/memcached.php +++ b/laravel/cache/memcached.php @@ -5,23 +5,57 @@ class Memcached extends Driver { + /** + * Determine if an item exists in the cache. + * + * + * // Determine if the "name" item exists in the cache + * $exists = Cache::driver()->has('name'); + * + * + * @param string $key + * @return bool + */ public function has($key) { return ( ! is_null($this->get($key))); } - public function get($key, $default = null) + /** + * Retrieve an item from the cache driver. + * + * @param string $key + * @return mixed + */ + protected function retrieve($key) { - $item = (($cache = Mem::instance()->get(Config::get('cache.key').$key)) !== false) ? $cache : null; - - return $this->prepare($item, $default); + return (($cache = Mem::instance()->get(Config::get('cache.key').$key)) !== false) ? $cache : null; } + /** + * Write an item to the cache for a given number of minutes. + * + * + * // Write the "name" item to the cache for 30 minutes + * Cache::driver()->put('name', 'Fred', 30); + * + * + * @param string $key + * @param mixed $value + * @param int $minutes + * @return void + */ public function put($key, $value, $minutes) { Mem::instance()->set(Config::get('cache.key').$key, $value, 0, $minutes * 60); } + /** + * Delete an item from the cache. + * + * @param string $key + * @return void + */ public function forget($key) { Mem::instance()->delete(Config::get('cache.key').$key); diff --git a/laravel/config.php b/laravel/config.php index 2f49ccf9..6e3b43fa 100644 --- a/laravel/config.php +++ b/laravel/config.php @@ -136,7 +136,7 @@ private static function load($module, $file) foreach (static::paths($module, $file) as $directory) { - if (file_exists($path = $directory.$file.EXT)) $config = array_merge($config, require $path); + $config = (file_exists($path = $directory.$file.EXT)) ? array_merge($config, require $path) : $config; } if (count($config) > 0) static::$items[$module][$file] = $config; @@ -150,9 +150,9 @@ private static function load($module, $file) * The paths returned by this method paths will be searched by the load method when merging * configuration files, meaning the configuration files will cascade in this order. * - * By default, the system configuration directory will be searched first, followed by the configuration - * configuration directory for the active module. Next, any environment specific configuration - * directories are searched. + * By default, the base configuration directory will be searched first, followed by the configuration + * directory for the active module. Next, any environment specific configuration directories + * will be searched. * * @param string $module * @param string $file @@ -160,6 +160,8 @@ private static function load($module, $file) */ private static function paths($module, $file) { + $module = str_replace('.', '/', $module); + $paths = array(CONFIG_PATH, Module::path($module).'config/'); if (isset($_SERVER['LARAVEL_ENV'])) diff --git a/laravel/crypter.php b/laravel/crypter.php index 5bf71cb6..86452185 100644 --- a/laravel/crypter.php +++ b/laravel/crypter.php @@ -16,17 +16,31 @@ class Crypter { */ public $mode; + /** + * The encryption key. + * + * @var string + */ + public $key; + /** * Create a new Crypter instance. * * @param string $cipher * @param string $mode + * @param string $key * @return void */ - public function __construct($cipher = 'rijndael-256', $mode = 'cbc') + public function __construct($cipher, $mode, $key) { $this->cipher = $cipher; $this->mode = $mode; + $this->key = $key; + + if (trim((string) $this->key) === '') + { + throw new \Exception('The encryption class can not be used without an encryption key.'); + } } /** @@ -34,11 +48,12 @@ public function __construct($cipher = 'rijndael-256', $mode = 'cbc') * * @param string $cipher * @param string $mode + * @param string $key * @return Crypt */ - public static function make($cipher = 'rijndael-256', $mode = 'cbc') + public static function make($cipher = MCRYPT_RIJNDAEL_256, $mode = 'cbc', $key = null) { - return new static($cipher, $mode); + return new static($cipher, $mode, (is_null($key)) ? Config::get('application.key') : $key); } /** @@ -51,7 +66,7 @@ public function encrypt($value) { $iv = mcrypt_create_iv($this->iv_size(), $this->randomizer()); - return base64_encode($iv.mcrypt_encrypt($this->cipher, $this->key(), $value, $this->mode, $iv)); + return base64_encode($iv.mcrypt_encrypt($this->cipher, $this->key, $value, $this->mode, $iv)); } /** @@ -88,19 +103,7 @@ public function decrypt($value) list($iv, $value) = array(substr($value, 0, $this->iv_size()), substr($value, $this->iv_size())); - return rtrim(mcrypt_decrypt($this->cipher, $this->key(), $value, $this->mode, $iv), "\0"); - } - - /** - * Get the application key from the application configuration file. - * - * @return string - */ - private function key() - { - if ( ! is_null($key = Config::get('application.key')) and $key !== '') return $key; - - throw new \Exception("The encryption class can not be used without an encryption key."); + return rtrim(mcrypt_decrypt($this->cipher, $this->key, $value, $this->mode, $iv), "\0"); } /** diff --git a/laravel/db.php b/laravel/db.php index 07fccef9..94d53fe0 100644 --- a/laravel/db.php +++ b/laravel/db.php @@ -15,6 +15,14 @@ class DB { * * Note: Database connections are managed as singletons. * + * + * // Get the default database connection + * $connection = DB::connection(); + * + * // Get a specific database connection + * $connection = DB::connection('mysql'); + * + * * @param string $connection * @return DB\Connection */ @@ -29,7 +37,9 @@ public static function connection($connection = null) throw new \Exception("Database connection [$connection] is not defined."); } - static::$connections[$connection] = new DB\Connection($connection, (object) $config, new DB\Connector); + $connector = DB\Connector\Factory::make($config['driver']); + + static::$connections[$connection] = DB\Connection\Factory::make($connection, $config, $connector); } return static::$connections[$connection]; @@ -38,6 +48,19 @@ public static function connection($connection = null) /** * Begin a fluent query against a table. * + * This method primarily serves as a short-cut to the $connection->table() method. + * + * + * // Begin a fluent query against the "users" table + * $query = DB::table('users'); + * + * // Equivalent call using the connection table method. + * $query = DB::connection()->table('users'); + * + * // Begin a fluent query against the "users" table for a specific connection + * $query = DB::table('users', 'mysql'); + * + * * @param string $table * @param string $connection * @return DB\Query @@ -49,6 +72,16 @@ public static function table($table, $connection = null) /** * Magic Method for calling methods on the default database connection. + * + * This provides a convenient API for querying or examining the default database connection. + * + * + * // Run a query against the default database connection + * $results = DB::query('select * from users'); + * + * // Equivalent call using the connection instance + * $results = DB::connection()->query('select * from users'); + * */ public static function __callStatic($method, $parameters) { diff --git a/laravel/db/connection.php b/laravel/db/connection.php index f0335dd8..580bc6c5 100644 --- a/laravel/db/connection.php +++ b/laravel/db/connection.php @@ -30,19 +30,60 @@ class Connection { */ public $queries = array(); + /** + * The database connector instance. + * + * @var Connector + */ + protected $connector; + /** * Create a new Connection instance. * * @param string $name - * @param object $config + * @param array $config * @param Connector $connector * @return void */ - public function __construct($name, $config, $connector) + public function __construct($name, $config, Connector $connector) { $this->name = $name; $this->config = $config; - $this->pdo = $connector->connect($this->config); + $this->connector = $connector; + } + + /** + * Establish the PDO connection for the connection instance. + * + * @return void + */ + protected function connect() + { + $this->pdo = $this->connector->connect($this->config); + } + + /** + * Determine if a PDO connection has been established for the connection. + * + * @return bool + */ + protected function connected() + { + return ! is_null($this->pdo); + } + + /** + * Execute a SQL query against the connection and return a scalar result. + * + * @param string $sql + * @param array $bindings + * @return mixed + */ + public function scalar($sql, $bindings = array()) + { + $result = (array) $this->first($sql, $bindings); + + return (strpos(strtolower($sql), 'select count') === 0) ? (int) reset($result) : (float) reset($result); } /** @@ -69,26 +110,38 @@ public function first($sql, $bindings = array()) * * @param string $sql * @param array $bindings - * @return array + * @return mixed */ public function query($sql, $bindings = array()) { - $this->queries[] = $sql; + if ( ! $this->connected()) $this->connect(); - $query = $this->pdo->prepare($sql); + $this->queries[] = compact('sql', 'bindings'); - $result = $query->execute($bindings); + return $this->execute($this->pdo->prepare($sql), $bindings); + } - if (strpos(strtoupper($sql), 'SELECT') === 0) + /** + * Execute a prepared PDO statement and return the appropriate results. + * + * @param PDOStatement $statement + * @param array $results + * @return mixed + */ + protected function execute(\PDOStatement $statement, $bindings) + { + $result = $statement->execute($bindings); + + if (strpos(strtoupper($statement->queryString), 'SELECT') === 0) { - return $query->fetchAll(\PDO::FETCH_CLASS, 'stdClass'); + return $statement->fetchAll(\PDO::FETCH_CLASS, 'stdClass'); } - elseif (strpos(strtoupper($sql), 'UPDATE') === 0 or strpos(strtoupper($sql), 'DELETE') === 0) + elseif (strpos(strtoupper($statement->queryString), 'INSERT') === 0) { - return $query->rowCount(); + return $result; } - return $result; + return $statement->rowCount(); } /** @@ -99,19 +152,7 @@ public function query($sql, $bindings = array()) */ public function table($table) { - return new Query($table, $this); - } - - /** - * Get the keyword identifier wrapper for the connection. - * - * @return string - */ - public function wrapper() - { - if (array_key_exists('wrap', $this->config) and $this->config['wrap'] === false) return ''; - - return ($this->driver() == 'mysql') ? '`' : '"'; + return Query\Factory::make($table, $this); } /** @@ -121,6 +162,8 @@ public function wrapper() */ public function driver() { + if ( ! $this->connected()) $this->connect(); + return $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); } @@ -134,4 +177,11 @@ public function prefix() return (array_key_exists('prefix', $this->config)) ? $this->config['prefix'] : ''; } + /** + * Get the keyword identifier wrapper for the connection. + * + * @return string + */ + public function wrapper() { return '"'; } + } \ No newline at end of file diff --git a/laravel/db/connection/factory.php b/laravel/db/connection/factory.php new file mode 100644 index 00000000..06bc710b --- /dev/null +++ b/laravel/db/connection/factory.php @@ -0,0 +1,30 @@ + \PDO::CASE_LOWER, - \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, - \PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL, - \PDO::ATTR_STRINGIFY_FETCHES => false, - \PDO::ATTR_EMULATE_PREPARES => false, + \PDO::ATTR_CASE => \PDO::CASE_LOWER, + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL, + \PDO::ATTR_STRINGIFY_FETCHES => false, + \PDO::ATTR_EMULATE_PREPARES => false, ); /** * Establish a PDO database connection. * - * @param object $connection + * @param array $config * @return PDO */ - public function connect($config) - { - switch ($config->driver) - { - case 'sqlite': - return $this->connect_to_sqlite($config); - - case 'mysql': - case 'pgsql': - return $this->connect_to_server($config); - - default: - return $this->connect_to_generic($config); - } - - throw new \Exception('Database driver '.$config->driver.' is not supported.'); - } - - /** - * Establish a PDO connection to a SQLite database. - * - * SQLite database paths can be specified either relative to the application/db - * directory, or as an absolute path to any location on the file system. In-memory - * databases are also supported. - * - * @param object $config - * @return PDO - */ - private function connect_to_sqlite($config) - { - if ($config->database == ':memory:') - { - return new \PDO('sqlite::memory:', null, null, $this->options); - } - elseif (file_exists($path = DATABASE_PATH.$config->database.'.sqlite')) - { - return new \PDO('sqlite:'.$path, null, null, $this->options); - } - elseif (file_exists($config->database)) - { - return new \PDO('sqlite:'.$config->database, null, null, $this->options); - } - - throw new \Exception("SQLite database [".$config->database."] could not be found."); - } - - /** - * Connect to a MySQL or PostgreSQL database server. - * - * @param object $config - * @return PDO - */ - private function connect_to_server($config) - { - $dsn = $config->driver.':host='.$config->host.';dbname='.$config->database; - - if (isset($config->port)) - { - $dsn .= ';port='.$config->port; - } - - $connection = new \PDO($dsn, $config->username, $config->password, $this->options); - - if (isset($config->charset)) - { - $connection->prepare("SET NAMES '".$config->charset."'")->execute(); - } - - return $connection; - } - - /** - * Connect to a generic data source. - * - * @param object $config - * @return PDO - */ - private function connect_to_generic($config) - { - return new \PDO($config->driver.':'.$config->dsn, $config->username, $config->password, $this->options); - } + abstract public function connect($config); } \ No newline at end of file diff --git a/laravel/db/connector/factory.php b/laravel/db/connector/factory.php new file mode 100644 index 00000000..f038d857 --- /dev/null +++ b/laravel/db/connector/factory.php @@ -0,0 +1,29 @@ +options); + } + +} \ No newline at end of file diff --git a/laravel/db/connector/mysql.php b/laravel/db/connector/mysql.php new file mode 100644 index 00000000..24cd1862 --- /dev/null +++ b/laravel/db/connector/mysql.php @@ -0,0 +1,32 @@ +options); + + if (isset($config['charset'])) + { + $connection->prepare("SET NAMES '".$config['charset']."'")->execute(); + } + + return $connection; + } + +} \ No newline at end of file diff --git a/laravel/db/connector/postgres.php b/laravel/db/connector/postgres.php new file mode 100644 index 00000000..24cd1862 --- /dev/null +++ b/laravel/db/connector/postgres.php @@ -0,0 +1,32 @@ +options); + + if (isset($config['charset'])) + { + $connection->prepare("SET NAMES '".$config['charset']."'")->execute(); + } + + return $connection; + } + +} \ No newline at end of file diff --git a/laravel/db/connector/sqlite.php b/laravel/db/connector/sqlite.php new file mode 100644 index 00000000..8f0cb34f --- /dev/null +++ b/laravel/db/connector/sqlite.php @@ -0,0 +1,31 @@ +options); + } + elseif (file_exists($path = DATABASE_PATH.$config['database'].'.sqlite')) + { + return new \PDO('sqlite:'.$path, null, null, $this->options); + } + elseif (file_exists($config['database'])) + { + return new \PDO('sqlite:'.$config['database'], null, null, $this->options); + } + + throw new \Exception("SQLite database [".$config['database']."] could not be found."); + } + +} \ No newline at end of file diff --git a/laravel/db/eloquent/hydrator.php b/laravel/db/eloquent/hydrator.php index 682bd4b3..4d38ffac 100644 --- a/laravel/db/eloquent/hydrator.php +++ b/laravel/db/eloquent/hydrator.php @@ -1,4 +1,4 @@ -table = $table; $this->connection = $connection; @@ -97,7 +97,7 @@ public function __construct($table, $connection) * @param Connection $connection * @return Query */ - public static function table($table, $connection) + public static function table($table, Connection $connection) { return new static($table, $connection); } @@ -579,18 +579,7 @@ public function insert($values) */ public function insert_get_id($values) { - $sql = $this->compile_insert($values); - - if ($this->connection->driver() == 'pgsql') - { - $query = $this->connection->pdo->prepare($sql.' RETURNING '.$this->wrap('id')); - - $query->execute(array_values($values)); - - return $query->fetch(\PDO::FETCH_CLASS, 'stdClass')->id; - } - - $this->connection->query($sql, array_values($values)); + $this->connection->query($this->compile_insert($values), array_values($values)); return $this->connection->pdo->lastInsertId(); } diff --git a/laravel/db/query/factory.php b/laravel/db/query/factory.php new file mode 100644 index 00000000..f9a649f5 --- /dev/null +++ b/laravel/db/query/factory.php @@ -0,0 +1,27 @@ +driver()) + { + case 'postgres': + return new Postgres($table, $connection); + + default: + return new Query($table, $connection); + } + } + +} \ No newline at end of file diff --git a/laravel/db/query/postgres.php b/laravel/db/query/postgres.php new file mode 100644 index 00000000..b08015a1 --- /dev/null +++ b/laravel/db/query/postgres.php @@ -0,0 +1,24 @@ +compile_insert($values); + + $query = $this->connection->pdo->prepare($sql.' RETURNING '.$this->wrap('id')); + + $query->execute(array_values($values)); + + return $query->fetch(\PDO::FETCH_CLASS, 'stdClass')->id; + } + +} \ No newline at end of file diff --git a/laravel/laravel.php b/laravel/laravel.php index 2c0bdae9..bd643451 100644 --- a/laravel/laravel.php +++ b/laravel/laravel.php @@ -8,14 +8,14 @@ // -------------------------------------------------------------- // Define the core framework paths. // -------------------------------------------------------------- -define('BASE_PATH', realpath(str_replace('laravel', '', $system)).'/'); +define('BASE_PATH', realpath(str_replace('laravel', '', $laravel)).'/'); define('MODULE_PATH', realpath($modules).'/'); define('PACKAGE_PATH', realpath($packages).'/'); define('PUBLIC_PATH', realpath($public).'/'); define('STORAGE_PATH', realpath($storage).'/'); -define('SYS_PATH', realpath($system).'/'); +define('SYS_PATH', realpath($laravel).'/'); -unset($system, $config, $modules, $packages, $public, $storage); +unset($laravel, $config, $modules, $packages, $public, $storage); // -------------------------------------------------------------- // Define various other framework paths. @@ -70,6 +70,11 @@ ini_set('display_errors', 'Off'); +// -------------------------------------------------------------- +// Set the default timezone. +// -------------------------------------------------------------- +date_default_timezone_set(Config::get('application.timezone')); + // -------------------------------------------------------------- // Register the error / exception handlers. // -------------------------------------------------------------- @@ -107,19 +112,27 @@ }); // -------------------------------------------------------------- -// Set the default timezone. +// Determine the module that should handle the request. // -------------------------------------------------------------- -date_default_timezone_set(Config::get('application.timezone')); +require SYS_PATH.'request'.EXT; + +$segments = explode('/', Request::uri()); + +define('ACTIVE_MODULE', (array_key_exists($segments[0], Module::$modules)) ? $segments[0] : DEFAULT_MODULE); + +// -------------------------------------------------------------- +// Determine the path to the root of the active module. +// -------------------------------------------------------------- +define('ACTIVE_MODULE_PATH', Module::path(ACTIVE_MODULE)); // -------------------------------------------------------------- // Load the session. // -------------------------------------------------------------- -if (Config::get('session.driver') != '') Session::load(Cookie::get('laravel_session')); +if (Config::get('session.driver') != '') Session::driver()->start(Cookie::get('laravel_session')); // -------------------------------------------------------------- // Load all of the core routing classes. // -------------------------------------------------------------- -require SYS_PATH.'request'.EXT; require SYS_PATH.'response'.EXT; require SYS_PATH.'routing/route'.EXT; require SYS_PATH.'routing/router'.EXT; @@ -136,18 +149,6 @@ Package::load(Config::get('application.packages')); } -// -------------------------------------------------------------- -// Determine the module that should handle the request. -// -------------------------------------------------------------- -$segments = explode('/', Request::uri()); - -define('ACTIVE_MODULE', (array_key_exists($segments[0], Module::$modules)) ? $segments[0] : DEFAULT_MODULE); - -// -------------------------------------------------------------- -// Determine the path to the root of the active module. -// -------------------------------------------------------------- -define('ACTIVE_MODULE_PATH', Module::path(ACTIVE_MODULE)); - // -------------------------------------------------------------- // Register the filters for the default module. // -------------------------------------------------------------- @@ -201,7 +202,19 @@ // -------------------------------------------------------------- // Close the session. // -------------------------------------------------------------- -if (Config::get('session.driver') != '') Session::close(); +if (Config::get('session.driver') != '') +{ + $driver = Session::driver(); + + $driver->flash('laravel_old_input', Input::get()); + + $driver->close(); + + if ($driver instanceof Session\Sweeper and mt_rand(1, 100) <= 2) + { + $driver->sweep(time() - (Config::get('session.lifetime') * 60)); + } +} // -------------------------------------------------------------- // Send the response to the browser. diff --git a/laravel/loader.php b/laravel/loader.php index 9124905b..6d37932e 100644 --- a/laravel/loader.php +++ b/laravel/loader.php @@ -76,32 +76,39 @@ private static function load_from_registered($file) } /** - * Load a class that is stored in a module. + * Search the active modules for a given file. * * @param string $file * @return void */ private static function load_from_module($file) { - // Since all module models and libraries must be namespaced to the - // module name, we'll extract the module name from the file. - $module = substr($file, 0, strpos($file, '/')); + if (is_null($module = static::module_path($file))) return; - if (in_array($module, Module::$modules)) + // Slice the module name off of the filename. Even though module libraries + // and models are namespaced under the module, there will obviously not be + // a folder matching that namespace in the libraries or models directory. + $file = substr($file, strlen($module)); + + foreach (array(MODULE_PATH.$module.'/models', MODULE_PATH.$module.'/libraries') as $directory) { - $module = MODULE_PATH.$module.'/'; + if (file_exists($path = $directory.'/'.$file.EXT)) return require $path; + } + } - // Slice the module name off of the filename. Even though module libraries - // and models are namespaced under the module, there will obviously not be - // a folder matching that namespace in the libraries or models directories - // of the module. Slicing it off will allow us to make a clean search for - // the relevant class file. - $file = substr($file, strpos($file, '/') + 1); - - foreach (array($module.'models', $module.'libraries') as $directory) - { - if (file_exists($path = $directory.'/'.$file.EXT)) return require $path; - } + /** + * Search the module paths for a match on the file. + * + * The file namespace should correspond to a directory within the module directory. + * + * @param string $file + * @return string + */ + private static function module_path($file) + { + foreach (Module::$modules as $key => $module) + { + if (strpos($file, $module) === 0) return $module; } } diff --git a/laravel/module.php b/laravel/module.php index ef9e647d..f605c104 100644 --- a/laravel/module.php +++ b/laravel/module.php @@ -42,6 +42,8 @@ public static function parse($key) { $module = (strpos($key, '::') !== false) ? substr($key, 0, strpos($key, ':')) : DEFAULT_MODULE; + $module = str_replace('.', '/', $module); + if ($module !== DEFAULT_MODULE) $key = substr($key, strpos($key, ':') + 2); return array($module, $key); @@ -50,9 +52,7 @@ public static function parse($key) /** * Get the path for a given module. * - * If the module exists in the module array as a key, that means a path other than - * the default path has been specified for the module. Otherwise, the module directory - * is assumed to have the same name as the module. + * Once the path has been determined, it will be cached by the class for quick access. * * @param string $module * @return string @@ -65,10 +65,6 @@ public static function path($module) { return static::$paths[$module] = MODULE_PATH.$module.'/'; } - elseif (array_key_exists($module, static::$modules)) - { - return static::$paths[$module] = MODULE_PATH.static::$modules[$module].'/'; - } } /** diff --git a/laravel/session.php b/laravel/session.php index 90f6ee49..b7f4d112 100644 --- a/laravel/session.php +++ b/laravel/session.php @@ -9,16 +9,13 @@ class Session { */ public static $driver; - /** - * The session payload, which contains the session ID, data and last activity timestamp. - * - * @var array - */ - public static $session = array(); - /** * Get the session driver. * + * The session driver returned will be the driver specified in the session configuration + * file. Only one session driver may be active for a given request, so the driver will + * be managed as a singleton. + * * @return Session\Driver */ public static function driver() @@ -51,188 +48,22 @@ public static function driver() } /** - * Load a user session by ID. + * Pass all other methods to the default session driver. * - * @param string $id - * @return void + * By dynamically passing these method calls to the default driver, the developer is + * able to use with a convenient API when working with the session. + * + * + * // Get an item from the default session driver + * $name = Session::get('name'); + * + * // Equivalent call using the driver method + * $name = Session::driver()->get('name'); + * */ - public static function load($id) + public static function __callStatic($method, $parameters) { - static::$session = ( ! is_null($id)) ? static::driver()->load($id) : null; - - if (static::invalid(static::$session)) - { - static::$session = array('id' => Str::random(40), 'data' => array()); - } - - if ( ! static::has('csrf_token')) - { - static::put('csrf_token', Str::random(16)); - } - - static::$session['last_activity'] = time(); - } - - /** - * Determine if a session is valid. - * - * A session is considered valid if it exists and has not expired. - * - * @param array $session - * @return bool - */ - private static function invalid($session) - { - return is_null($session) or (time() - $session['last_activity']) > (Config::get('session.lifetime') * 60); - } - - /** - * Determine if the session or flash data contains an item. - * - * @param string $key - * @return bool - */ - public static function has($key) - { - return ( ! is_null(static::get($key))); - } - - /** - * Get an item from the session or flash data. - * - * @param string $key - * @return mixed - */ - public static function get($key, $default = null) - { - foreach (array($key, ':old:'.$key, ':new:'.$key) as $possibility) - { - if (array_key_exists($possibility, static::$session['data'])) return static::$session['data'][$possibility]; - } - - return is_callable($default) ? call_user_func($default) : $default; - } - - /** - * Write an item to the session. - * - * @param string $key - * @param mixed $value - * @return void - */ - public static function put($key, $value) - { - static::$session['data'][$key] = $value; - } - - /** - * Write an item to the session flash data. - * - * @param string $key - * @param mixed $value - * @return void - */ - public static function flash($key, $value) - { - static::put(':new:'.$key, $value); - } - - /** - * Remove an item from the session. - * - * @param string $key - * @return void - */ - public static function forget($key) - { - unset(static::$session['data'][$key]); - } - - /** - * Remove all items from the session. - * - * @return void - */ - public static function flush() - { - static::$session['data'] = array(); - } - - /** - * Regenerate the session ID. - * - * @return void - */ - public static function regenerate() - { - static::driver()->delete(static::$session['id']); - - static::$session['id'] = Str::random(40); - } - - /** - * Close the session. - * - * The session will be stored in persistant storage and the session cookie will be - * session cookie will be sent to the browser. The old input data will also be - * stored in the session flash data. - * - * @return void - */ - public static function close() - { - static::flash('laravel_old_input', Input::get()); - - static::age_flash(); - - static::driver()->save(static::$session); - - static::write_cookie(); - - if (mt_rand(1, 100) <= 2 and static::driver() instanceof Session\Sweeper) - { - static::driver()->sweep(time() - (Config::get('session.lifetime') * 60)); - } - } - - /** - * Age the session flash data. - * - * @return void - */ - private static function age_flash() - { - foreach (static::$session['data'] as $key => $value) - { - if (strpos($key, ':old:') === 0) static::forget($key); - } - - foreach (static::$session['data'] as $key => $value) - { - if (strpos($key, ':new:') === 0) - { - static::put(':old:'.substr($key, 5), $value); - - static::forget($key); - } - } - } - - /** - * Write the session cookie. - * - * @return void - */ - private static function write_cookie() - { - if ( ! headers_sent()) - { - extract(Config::get('session')); - - $minutes = ($expire_on_close) ? 0 : $lifetime; - - Cookie::put('laravel_session', static::$session['id'], $minutes, $path, $domain, $https, $http_only); - } + return call_user_func_array(array(static::driver(), $method), $parameters); } } \ No newline at end of file diff --git a/laravel/session/apc.php b/laravel/session/apc.php index fdea6c12..53ae100c 100644 --- a/laravel/session/apc.php +++ b/laravel/session/apc.php @@ -3,39 +3,21 @@ use Laravel\Cache; use Laravel\Config; -class APC implements Driver { +class APC extends Driver { - /** - * Load a session by ID. - * - * @param string $id - * @return array - */ - public function load($id) + protected function load($id) { return Cache::driver('apc')->get($id); } - /** - * Save a session. - * - * @param array $session - * @return void - */ - public function save($session) + protected function save() { - Cache::driver('apc')->put($session['id'], $session, Config::get('session.lifetime')); + Cache::driver('apc')->put($this->session['id'], $this->session, Config::get('session.lifetime')); } - /** - * Delete a session by ID. - * - * @param string $id - * @return void - */ - public function delete($id) + protected function delete() { - Cache::driver('apc')->forget($id); + Cache::driver('apc')->forget($this->session['id']); } } \ No newline at end of file diff --git a/laravel/session/cookie.php b/laravel/session/cookie.php index 3a10f44d..e353137b 100644 --- a/laravel/session/cookie.php +++ b/laravel/session/cookie.php @@ -3,7 +3,7 @@ use Laravel\Config; use Laravel\Crypter; -class Cookie implements Driver { +class Cookie extends Driver { /** * The Crypter instance. @@ -27,13 +27,7 @@ public function __construct() } } - /** - * Load a session by ID. - * - * @param string $id - * @return array - */ - public function load($id) + protected function load($id) { if (\System\Cookie::has('session_payload')) { @@ -41,31 +35,19 @@ public function load($id) } } - /** - * Save a session. - * - * @param array $session - * @return void - */ - public function save($session) + protected function save() { if ( ! headers_sent()) { extract(Config::get('session')); - $payload = $this->crypter->encrypt(serialize($session)); + $payload = $this->crypter->encrypt(serialize($this->session)); \System\Cookie::put('session_payload', $payload, $lifetime, $path, $domain, $https, $http_only); } } - /** - * Delete a session by ID. - * - * @param string $id - * @return void - */ - public function delete($id) + protected function delete() { \System\Cookie::forget('session_payload'); } diff --git a/laravel/session/db.php b/laravel/session/db.php index 7c1ba56c..c208e021 100644 --- a/laravel/session/db.php +++ b/laravel/session/db.php @@ -2,15 +2,9 @@ use Laravel\Config; -class DB implements Driver, Sweeper { +class DB extends Driver implements Sweeper { - /** - * Load a session by ID. - * - * @param string $id - * @return array - */ - public function load($id) + protected function load($id) { $session = $this->table()->find($id); @@ -24,40 +18,22 @@ public function load($id) } } - /** - * Save a session. - * - * @param array $session - * @return void - */ - public function save($session) + protected function save() { - $this->delete($session['id']); + $this->delete($this->session['id']); $this->table()->insert(array( - 'id' => $session['id'], - 'last_activity' => $session['last_activity'], - 'data' => serialize($session['data']) + 'id' => $this->session['id'], + 'last_activity' => $this->session['last_activity'], + 'data' => serialize($this->session['data']) )); } - /** - * Delete a session by ID. - * - * @param string $id - * @return void - */ - public function delete($id) + protected function delete() { - $this->table()->delete($id); + $this->table()->delete($this->session['id']); } - /** - * Delete all expired sessions. - * - * @param int $expiration - * @return void - */ public function sweep($expiration) { $this->table()->where('last_activity', '<', $expiration)->delete(); diff --git a/laravel/session/driver.php b/laravel/session/driver.php index a630c548..c839f76d 100644 --- a/laravel/session/driver.php +++ b/laravel/session/driver.php @@ -1,29 +1,242 @@ session = ( ! is_null($id)) ? $this->load($id) : null; + + if (is_null($this->session) or (time() - $this->session['last_activity']) > (Config::get('session.lifetime') * 60)) + { + $this->session = array('id' => Str::random(40), 'data' => array()); + } + + if ( ! $this->has('csrf_token')) $this->put('csrf_token', Str::random(16)); + + $this->session['last_activity'] = time(); + } /** * 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 */ - public function load($id); + abstract protected function load($id); /** - * Save a session. + * Delete the session from persistant storage. * - * @param array $session * @return void */ - public function save($session); + abstract protected function delete(); /** - * Delete a session by ID. + * Save the session to persistant storage. * - * @param string $id * @return void */ - public function delete($id); + abstract protected function save(); + + /** + * Determine if the session or flash data contains an item. + * + * + * // Determine if "name" item exists in the session + * $exists = Session::driver()->has('name'); + * + * + * @param string $key + * @return bool + */ + public function has($key) + { + return ( ! is_null($this->get($key))); + } + + /** + * Get an item from the session. + * + * A default value may also be specified, and will be returned in the requested + * item does not exist in the session. + * + * + * // Get the "name" item from the session + * $name = Session::driver()->get('name'); + * + * // Get the "name" item from the session or return "Fred" + * $name = Session::driver()->get('name', 'Fred'); + * + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public function get($key, $default = null) + { + foreach (array($key, ':old:'.$key, ':new:'.$key) as $possibility) + { + if (array_key_exists($possibility, $this->session['data'])) return $this->session['data'][$possibility]; + } + + return is_callable($default) ? call_user_func($default) : $default; + } + + /** + * Write an item to the session. + * + * + * // Write the "name" item to the session + * Session::driver()->put('name', 'Fred'); + * + * + * @param string $key + * @param mixed $value + * @return void + */ + public function put($key, $value) + { + $this->session['data'][$key] = $value; + } + + /** + * Write an item to the session flash data. + * + * Flash data only exists for the next request. After that, it will be removed from + * the session. Flash data is useful for temporary status or welcome messages. + * + * + * // Write the "name" item to the session flash data + * Session::driver()->flash('name', 'Fred'); + * + * + * @param string $key + * @param mixed $value + * @return void + */ + public function flash($key, $value) + { + $this->put(':new:'.$key, $value); + } + + /** + * Remove an item from the session. + * + * + * // Remove the "name" item from the session + * Session::driver()->forget('name'); + * + * + * @param string $key + * @return void + */ + public function forget($key) + { + unset($this->session['data'][$key]); + } + + /** + * Remove all items from the session. + * + * @return void + */ + public function flush() + { + $this->session['data'] = array(); + } + + /** + * Regenerate the session ID. + * + * @return void + */ + public function regenerate() + { + $this->delete(); + + $this->session['id'] = Str::random(40); + } + + /** + * Close the session. + * + * The session will be stored in persistant storage and the session cookie will be + * session cookie will be sent to the browser. + * + * @return void + */ + public function close() + { + $this->age_flash(); + + $this->save(); + + $this->write_cookie(); + } + + /** + * Age the session flash data. + * + * @return void + */ + public function age_flash() + { + foreach ($this->session['data'] as $key => $value) + { + if (strpos($key, ':old:') === 0) $this->forget($key); + } + + foreach ($this->session['data'] as $key => $value) + { + if (strpos($key, ':new:') === 0) + { + $this->put(':old:'.substr($key, 5), $value); + + $this->forget($key); + } + } + } + + /** + * Write the session cookie. + * + * @return void + */ + protected function write_cookie() + { + if ( ! headers_sent()) + { + extract(Config::get('session')); + + $minutes = ($expire_on_close) ? 0 : $lifetime; + + Cookie::put('laravel_session', $this->session['id'], $minutes, $path, $domain, $https, $http_only); + } + } } \ No newline at end of file diff --git a/laravel/session/file.php b/laravel/session/file.php index 47367fa5..920121a5 100644 --- a/laravel/session/file.php +++ b/laravel/session/file.php @@ -1,46 +1,22 @@ session['id'], serialize($this->session), LOCK_EX); } - /** - * Delete a session by ID. - * - * @param string $id - * @return void - */ - public function delete($id) + protected function delete() { - @unlink(SESSION_PATH.$id); + @unlink(SESSION_PATH.$this->session['id']); } - /** - * Delete all expired sessions. - * - * @param int $expiration - * @return void - */ public function sweep($expiration) { foreach (glob(SESSION_PATH.'*') as $file) diff --git a/laravel/session/memcached.php b/laravel/session/memcached.php index a6d37c1d..de186948 100644 --- a/laravel/session/memcached.php +++ b/laravel/session/memcached.php @@ -3,39 +3,21 @@ use Laravel\Cache; use Laravel\Config; -class Memcached implements Driver { +class Memcached extends Driver { - /** - * Load a session by ID. - * - * @param string $id - * @return array - */ - public function load($id) + protected function load($id) { return Cache::driver('memcached')->get($id); } - /** - * Save a session. - * - * @param array $session - * @return void - */ - public function save($session) + protected function save() { - Cache::driver('memcached')->put($session['id'], $session, Config::get('session.lifetime')); + Cache::driver('memcached')->put($this->session['id'], $this->session, Config::get('session.lifetime')); } - /** - * Delete a session by ID. - * - * @param string $id - * @return void - */ - public function delete($id) + protected function delete() { - Cache::driver('memcached')->forget($id); + Cache::driver('memcached')->forget($this->session['id']); } } \ No newline at end of file diff --git a/laravel/session/sweeper.php b/laravel/session/sweeper.php index 95039584..8fa57eb2 100644 --- a/laravel/session/sweeper.php +++ b/laravel/session/sweeper.php @@ -3,7 +3,7 @@ interface Sweeper { /** - * Delete all expired sessions. + * Delete all expired sessions from persistant storage. * * @param int $expiration * @return void diff --git a/public/core b/public/core deleted file mode 100644 index 3e34f8a8..00000000 Binary files a/public/core and /dev/null differ diff --git a/public/favicon.gif b/public/favicon.gif deleted file mode 100644 index e69de29b..00000000 diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index e69de29b..00000000 diff --git a/public/index.php b/public/index.php index 7888af6d..193c73e4 100644 --- a/public/index.php +++ b/public/index.php @@ -8,37 +8,49 @@ * @link http://laravel.com */ -// -------------------------------------------------------------- -// The active modules for this Laravel installation. -// -------------------------------------------------------------- -$active = array(); +/* +|-------------------------------------------------------------------------- +| Active Modules +|-------------------------------------------------------------------------- +| +| Modules are a convenient way to organize your application into logical +| components. Each module may have its own libraries, models, routes, +| views, language files, and configuration. +| +| Here you may specify which modules are active for your application. +| This simply gives Laravel an easy way to know which directories to +| check when auto-loading your classes, routes, and views. +| +*/ -// -------------------------------------------------------------- -// The path to the Laravel directory. -// -------------------------------------------------------------- -$system = '../laravel'; +$active = array(); + +/* +|-------------------------------------------------------------------------- +| Installation Paths +|-------------------------------------------------------------------------- +| +| Here you may specify the location of the various Laravel framework +| directories for your installation. +| +| Of course, these are already set to the proper default values, so you do +| not need to change them if you have not modified the directory structure. +| +*/ + +$laravel = '../laravel'; -// -------------------------------------------------------------- -// The path to the packages directory. -// -------------------------------------------------------------- $packages = '../packages'; -// -------------------------------------------------------------- -// The path to the modules directory. -// -------------------------------------------------------------- $modules = '../modules'; -// -------------------------------------------------------------- -// The path to the storage directory. -// -------------------------------------------------------------- $storage = '../storage'; -// -------------------------------------------------------------- -// The path to the public directory. -// -------------------------------------------------------------- $public = __DIR__; -// -------------------------------------------------------------- -// Launch Laravel. -// -------------------------------------------------------------- -require $system.'/laravel.php'; \ No newline at end of file +/* +|-------------------------------------------------------------------------- +| 3... 2... 1... Lift-off! +|-------------------------------------------------------------------------- +*/ +require $laravel.'/laravel.php'; \ No newline at end of file