Commit b5442c67 authored by Taylor Otwell's avatar Taylor Otwell

merged skunkworks into develop.

parent 610d8827
<?php
/*
|--------------------------------------------------------------------------
| Auto-Loader PSR-0 Directories
|--------------------------------------------------------------------------
|
| The Laravel auto-loader can search directories for files using the PSR-0
| naming convention. This convention basically organizes classes by using
| the class namespace to indicate the directory structure.
|
| So you don't have to manually map all of your models, we've added the
| models and libraries directories for you. So, you can model away and
| the auto-loader will take care of the rest.
|
*/
Autoloader::psr(array(
APP_PATH.'models',
APP_PATH.'libraries',
));
/*
|--------------------------------------------------------------------------
| Auto-Loader Mappings
|--------------------------------------------------------------------------
|
| Laravel uses a simple array of class to path mappings to drive the class
| auto-loader. This simple approach helps avoid the performance problems
| of searching through directories by some kind of convention. It also
| gives you the freedom to organize your application how you want.
|
| Registering a mapping couldn't be easier. Just pass an array of class
| to path maps into the "map" function of Autoloader. Then, when you
| want to use that class, just use it. It's a piece of cake.
|
*/
Autoloader::map(array(
//'User' => APP_PATH.'models/user.php',
//'Role' => APP_PATH.'models/role.php',
));
\ No newline at end of file
<?php
return array(
/*
|--------------------------------------------------------------------------
| View Names & Composers
|--------------------------------------------------------------------------
|
| Named views give you beautiful syntax when working with your views.
|
| Here's how to define a named view:
|
| 'home.index' => array('name' => 'home')
|
| Now, you can create an instance of that view using the very expressive
| View::of dynamic method. Take a look at this example:
|
| return View::of_home();
|
| View composers provide a convenient way to add common elements to a view
| each time it is created. For example, you may wish to bind a header and
| footer partial each time the view is created.
|
| The composer will receive an instance of the view being created, and is
| free to modify the view however you wish. Here is how to define one:
|
| 'home.index' => function($view)
| {
| //
| }
|
| Of course, you may define a view name and a composer for a single view:
|
| 'home.index' => array('name' => 'home', function($view)
| {
| //
| })
|
*/
'home.index' => array('name' => 'home', function($view)
{
// This composer is called for the "home.index" view.
}),
);
\ No newline at end of file
......@@ -7,7 +7,9 @@ return array(
| Application URL
|--------------------------------------------------------------------------
|
| The URL used to access your application. No trailing slash.
| The URL used to access your application without a trailing slash. The URL
| does nto have to be set. If it isn't we'll try our best to guess the URL
| of your application.
|
*/
......@@ -20,8 +22,8 @@ return array(
|
| If you are including the "index.php" in your URLs, you can ignore this.
|
| However, if you are using mod_rewrite or something similar to get
| cleaner URLs, set this option to an empty string.
| However, if you are using mod_rewrite to get cleaner URLs, just set
| this option to an empty string and we'll take care of the rest.
|
*/
......@@ -32,11 +34,10 @@ return array(
| Application Key
|--------------------------------------------------------------------------
|
| The application key should be a random, 32 character string.
|
| This key is used by the encryption and cookie classes to generate secure
| encrypted strings and hashes. It is extremely important that this key
| remain secret and should not be shared with anyone.
| remain secret and should not be shared with anyone. Make it about 32
| characters of random gibberish.
|
*/
......@@ -48,7 +49,8 @@ return array(
|--------------------------------------------------------------------------
|
| The default character encoding used by your application. This encoding
| will be used by the Str, Text, and Form classes.
| will be used by the Str, Text, Form, and any other classes that need
| to know what type of encoding to use for your awesome application.
|
*/
......@@ -89,12 +91,28 @@ return array(
|--------------------------------------------------------------------------
|
| The default timezone of your application. This timezone will be used when
| Laravel needs a date, such as when writing to a log file.
| Laravel needs a date, such as when writing to a log file or travelling
| to a distant star at warp speed.
|
*/
'timezone' => 'UTC',
/*
|--------------------------------------------------------------------------
| Autoloaded Bundles
|--------------------------------------------------------------------------
|
| Bundles can provide a ton of awesome drop-in functionality for your web
| application. Everything from Twitter integration to an admin backend.
|
| Here you may specify the bundles that should be automatically started
| on every request to your application.
|
*/
'bundles' => array(),
/*
|--------------------------------------------------------------------------
| Class Aliases
......@@ -112,26 +130,26 @@ return array(
*/
'aliases' => array(
'Arr' => 'Laravel\\Arr',
'Asset' => 'Laravel\\Asset',
'Auth' => 'Laravel\\Auth',
'Asset' => 'Laravel\\Asset',
'Autoloader' => 'Laravel\\Autoloader',
'Benchmark' => 'Laravel\\Benchmark',
'Cache' => 'Laravel\\Cache\\Manager',
'Bundle' => 'Laravel\\Bundle',
'Cache' => 'Laravel\\Cache',
'Config' => 'Laravel\\Config',
'Controller' => 'Laravel\\Routing\\Controller',
'Cookie' => 'Laravel\\Cookie',
'Crypter' => 'Laravel\\Crypter',
'DB' => 'Laravel\\Database\\Manager',
'Eloquent' => 'Laravel\\Database\\Eloquent\\Model',
'DB' => 'Laravel\\Database',
'Event' => 'Laravel\\Event',
'File' => 'Laravel\\File',
'Filter' => 'Laravel\\Routing\\Filter',
'Form' => 'Laravel\\Form',
'Hash' => 'Laravel\\Hash',
'HTML' => 'Laravel\\HTML',
'Inflector' => 'Laravel\\Inflector',
'Input' => 'Laravel\\Input',
'IoC' => 'Laravel\\IoC',
'Lang' => 'Laravel\\Lang',
'Log' => 'Laravel\\Log',
'Memcached' => 'Laravel\\Memcached',
'Paginator' => 'Laravel\\Paginator',
'URL' => 'Laravel\\URL',
......@@ -139,9 +157,13 @@ return array(
'Redis' => 'Laravel\\Redis',
'Request' => 'Laravel\\Request',
'Response' => 'Laravel\\Response',
'Router' => 'Laravel\\Routing\\Router',
'Schema' => 'Laravel\\Database\\Schema',
'Section' => 'Laravel\\Section',
'Session' => 'Laravel\\Facades\\Session',
'Session' => 'Laravel\\Session',
'Str' => 'Laravel\\Str',
'Task' => 'Laravel\\CLI\\Tasks\\Task',
'URI' => 'Laravel\\URI',
'Validator' => 'Laravel\\Validator',
'View' => 'Laravel\\View',
),
......
......@@ -2,45 +2,27 @@
return array(
/*
|--------------------------------------------------------------------------
| Authentication Username
|--------------------------------------------------------------------------
|
} This option should be set to the "username" property of your users.
| Typically, this will be set to "email" or "username".
|
| The value of this property will be used by the "attempt" closure when
| searching for users by their username. It will also be used when the
| user is set to be "remembered", as the username is embedded into the
| encrypted cookie and is used to verify the user's identity.
|
*/
'username' => 'email',
/*
|--------------------------------------------------------------------------
| Retrieve The Current User
|--------------------------------------------------------------------------
|
| This closure is called by the Auth::user() method when attempting to
| retrieve a user by their ID stored in the session.
| This closure is called by the Auth class' "user" method when trying to
| retrieve a user by the ID that is stored in their session. If you find
| the user, just return the user object, but make sure it has an "id"
| property. If you can't find the user, just return null.
|
| Simply return an object representing the user with the given ID. Or, if
| no user with the given ID is registered to use your application, you do
| not need to return anything.
|
| Of course, a simple, elegant authentication solution is already provided
| for you using Eloquent and the default Laravel hashing engine.
| Of course, a simple and elegant authentication solution has already
| been provided for you using the query builder and hashing engine.
| We love making your life as easy as possible.
|
*/
'user' => function($id)
{
if ( ! is_null($id) and filter_var($id, FILTER_VALIDATE_INT) !== false)
if (filter_var($id, FILTER_VALIDATE_INT) !== false)
{
return User::find($id);
return DB::table('users')->find($id);
}
},
......@@ -50,19 +32,19 @@ return array(
|--------------------------------------------------------------------------
|
| This closure is called by the Auth::attempt() method when attempting to
| authenticate a user that is logging into your application.
| authenticate a user that is logging into your application. It's like a
| super buff bouncer to your application.
|
| If the provided credentials are correct, simply return an object that
| represents the user being authenticated. If the credentials are not
| valid, don't return anything.
|
| Note: If a user object is returned, it must have an "id" property.
| represents the user being authenticated. As long as it has a property
| for the "id", any object will work. If the credentials are not valid,
| you don't meed to return anything.
|
*/
'attempt' => function($username, $password, $config)
'attempt' => function($username, $password)
{
$user = User::where($config['username'], '=', $username)->first();
$user = DB::table('users')->where_username($username)->first();
if ( ! is_null($user) and Hash::check($password, $user->password))
{
......@@ -72,12 +54,12 @@ return array(
/*
|--------------------------------------------------------------------------
| Logout
| Logout The Current User
|--------------------------------------------------------------------------
|
| Here you may do anything that needs to be done when a user logs out of
| your application, such as call the logout method on a third-party API
| you are using for authentication, or anything else you desire.
| you are using for authentication or anything else you desire.
|
*/
......
......@@ -7,12 +7,15 @@ return array(
| Cache Driver
|--------------------------------------------------------------------------
|
| The name of the default cache driver for your application.
| The name of the default cache driver for your application. Caching can
| be used to increase the performance of your application by storing any
| commonly accessed data in memory, a file, or some other storage.
|
| Caching can be used to increase the performance of your application
| by storing commonly accessed data in memory or in a file.
| A variety of awesome drivers are available for you to use with Laravel.
| Some, like APC, are extremely fast. However, if that isn't an option
| in your environment, try file or database caching.
|
| Supported Drivers: 'file', 'memcached', 'apc', 'redis'.
| Drivers: 'file', 'memcached', 'apc', 'redis', 'database'.
|
*/
......@@ -23,8 +26,10 @@ return array(
| Cache Key
|--------------------------------------------------------------------------
|
| This key will be prepended to item keys stored using Memcached and APC to
| prevent collisions with other applications on the server.
| This key will be prepended to item keys stored using Memcached and APC
| to prevent collisions with other applications on the server. Since the
| memory based stores could be shared by other applications, we need to
| be polite and use a prefix to uniquely identifier our items.
|
*/
......@@ -32,16 +37,28 @@ return array(
/*
|--------------------------------------------------------------------------
| Memcached Servers
| Cache Database
|--------------------------------------------------------------------------
|
| The Memcached servers used by your application.
| When using the database cache driver, this database table will be used
| to store the cached item. You may also add a "connection" option to
| the array to specify which database connection should be used.
|
*/
'database' => array('table' => 'laravel_cache'),
/*
|--------------------------------------------------------------------------
| Memcached Servers
|--------------------------------------------------------------------------
|
| Memcached is a free and open source, high-performance, distributed memory
| object caching system, generic in nature, but intended for use in speeding
| up dynamic web applications by alleviating database load.
| The Memcached servers used by your application. Memcached is a free and
| open source, high-performance, distributed memory caching system. It is
| generic in nature but intended for use in speeding up web applications
| by alleviating database load.
|
| For more information about Memcached, check out: http://memcached.org
| For more information, check out: http://memcached.org
|
*/
......
<?php
return array(
/*
|--------------------------------------------------------------------------
| Inversion of Control Container
|--------------------------------------------------------------------------
|
| Here you may define resolvers for the Laravel inversion of control (IoC)
| container. An IoC container provides the ability to create more flexible
| and testable applications, as well as a convenient method of managing
| the instantiation of complex objects.
|
| To register a resolver in the container, simple create add an item to
| the array for the object with a closure that returns an instance of
| the object.
|
| For example, here's how to register a resolver for a Mailer class:
|
| 'mailer' => function($c)
| {
| return new Mailer($sender, $key);
| }
|
| Note that the container instance itself is passed into the resolver,
| allowing you to continue to resolve dependencies within the resolver
| itself. This allows you to easily resolve nested dependencies.
|
| When creating controller instances, Laravel will check to see if a
| resolver has been registered for the controller. If it has, it will
| be used to create the controller instance. All controller resolvers
| should be registered beginning using a {controllers}.{name} naming
| convention. For example:
|
| 'controllers.user' => function($c)
| {
| return new User_Controller($c->resolve('repository'));
| }
|
| Of course, sometimes you may wish to register an object as a singleton
| Singletons are resolved by the controller the first time they are
| resolved; however, that same resolved instance will continue to be
| returned by the container each time it is requested. Registering an
| object as a singleton couldn't be simpler:
|
| 'mailer' => array('singleton' => true, 'resolver' => function($c)
| {
| return new Mailer($sender, $key);
| })
|
*/
);
\ No newline at end of file
......@@ -7,39 +7,29 @@ return array(
| Default Database Connection
|--------------------------------------------------------------------------
|
| The name of your default database connection.
|
| This connection will be the default for all database operations unless a
| different connection is specified when performing the operation.
| The name of your default database connection. This connection will used
| as the default for all database operations unless a different name is
| given when performing said operation. This connection name should be
| listed in the array of connections below.
|
*/
'default' => 'sqlite',
'default' => 'mysql',
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| All of the database connections used by your application.
|
| Supported Drivers: 'mysql', 'pgsql', 'sqlite'.
|
| Note: When using the SQLite driver, the path and "sqlite" extention will
| be added automatically. You only need to specify the database name.
| All of the database connections used by your application. Many of your
| applications will no doubt only use one connection; however, you have
| the freedom to specify as many connections as you can handle.
|
| Using a driver that isn't supported? You can still establish a PDO
| connection. Simply specify a driver and DSN option:
| All database work in Laravel is done through the PHP's PDO facilities,
| so make sure you have the PDO drivers for your particlar database of
| choice installed on your machine.
|
| 'odbc' => array(
| 'driver' => 'odbc',
| 'dsn' => 'your-dsn',
| 'username' => 'username',
| 'password' => 'password',
| )
|
| Note: When using an unsupported driver, Eloquent and the fluent query
| builder may not work as expected.
| Drivers: 'mysql', 'pgsql', 'sqlsrv', 'sqlite'.
|
*/
......@@ -68,6 +58,14 @@ return array(
'charset' => 'utf8',
),
'sqlsrv' => array(
'driver' => 'sqlsrv',
'host' => 'localhost',
'database' => 'database',
'username' => 'root',
'password' => 'password',
),
),
/*
......@@ -77,11 +75,9 @@ return array(
|
| Redis is an open source, fast, and advanced key-value store. However, it
| provides a richer set of commands than a typical key-value store such as
| APC or memcached.
|
| Here you may specify the hosts and ports for your Redis databases.
| APC or memcached. All the cool kids are using it.
|
| For more information regarding Redis, check out: http://redis.io
| To get the scoop on Redis, check out: http://redis.io
|
*/
......
......@@ -7,7 +7,7 @@ return array(
| Ignored Error Levels
|--------------------------------------------------------------------------
|
| Here you may specify the error levels that should be ignored by the
| Here you simply specify the error levels that should be ignored by the
| Laravel error handler. These levels will still be logged; however, no
| information about about them will be displayed.
|
......@@ -22,10 +22,11 @@ return array(
|
| Detailed error messages contain information about the file in which an
| error occurs, as well as a PHP stack trace containing the call stack.
| You'll want them when you're trying to debug your application.
|
| If your application is in production, consider turning off error details
| for enhanced security and user experience. The error stack trace could
| contain sensitive information that should not be publicly visible.
| If your application is in production, you'll want to turn off the error
| details for enhanced security and user experience since the exception
| stack trace could contain sensitive information.
|
*/
......@@ -56,18 +57,13 @@ return array(
|
| You may log the error message however you like; however, a simple log
| solution has been setup for you which will log all error messages to
| a single text file within the application storage directory.
|
| Of course, you are free to implement more complex solutions including
| emailing the exceptions details to your team, etc.
| text files within the application storage directory.
|
*/
'logger' => function($exception)
{
$message = (string) $exception;
File::append(STORAGE_PATH.'log.txt', date('Y-m-d H:i:s').' - '.$message.PHP_EOL);
Log::exception($exception);
},
);
\ No newline at end of file
......@@ -7,12 +7,12 @@ return array(
| Session Driver
|--------------------------------------------------------------------------
|
| The name of the session driver for your application.
| The name of the session driver used by your application. Since HTTP is
| stateless, sessions are used to simulate "state" across requests made
| by the same user of your application. In other words, it's how an
| application knows who the heck you are.
|
| Since HTTP is stateless, sessions are used to maintain "state" across
| multiple requests from the same user of your application.
|
| Supported Drivers: 'cookie', 'file', 'database', 'memcached', 'apc', 'redis'.
| Drivers: 'cookie', 'file', 'database', 'memcached', 'apc', 'redis'.
|
*/
......@@ -23,9 +23,9 @@ return array(
| Session Database
|--------------------------------------------------------------------------
|
| The database table on which the session should be stored.
|
| This option is only relevant when using the "database" session driver.
| The database table on which the session should be stored. It probably
| goes without saying that this option only matters if you are using
| the super slick database session driver.
|
*/
......@@ -40,8 +40,9 @@ return array(
| This option specifies the probability of session garbage collection
| occuring for any given request.
|
| For example, the default value states that garbage collection has about
| a 2% (2 / 100) chance of occuring for any given request.
| For example, the default value states that garbage collection has a
| 2% chance of occuring for any given request to the application.
| Feel free to tune this to your application's size and speed.
|
*/
......
<?php
return array(
/*
|--------------------------------------------------------------------------
| String Inflection
|--------------------------------------------------------------------------
|
| This array contains the singular and plural forms of words. It's used by
| the "singular" and "plural" methods on the Str class to convert a given
| word from singular to plural and vice versa.
|
| This simple array is in constrast to the complicated regular expression
| patterns used by other frameworks. We think you'll enjoy the speed and
| simplicity of this solution.
|
| When adding a word to the array, the key should be the singular form,
| while the array value should be the plural form. We've included an
| example to get you started!
|
*/
'inflection' => array(
'user' => 'users',
'person' => 'people',
'comment' => 'comments',
),
/*
|--------------------------------------------------------------------------
| ASCII Characters
|--------------------------------------------------------------------------
|
| This array contains foreign characters and their 7-bit ASCII equivalents.
| The array is used by the "ascii" method on the Str class to get strings
| ready for inclusion in a URL slug.
|
| Of course, the "ascii" method may also be used by you for whatever your
| application requires. Feel free to add any characters we missed, and be
| sure to let us know about them!
|
*/
'ascii' => array(
'/æ|ǽ/' => 'ae',
'/œ/' => 'oe',
'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|А/' => 'A',
'/à|á|â|ã|ä|å|ǻ|ā|ă|ą|ǎ|ª|а/' => 'a',
'/Б/' => 'B',
'/б/' => 'b',
'/Ç|Ć|Ĉ|Ċ|Č|Ц/' => 'C',
'/ç|ć|ĉ|ċ|č|ц/' => 'c',
'/Ð|Ď|Đ|Д/' => 'Dj',
'/ð|ď|đ|д/' => 'dj',
'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Е|Ё|Э/' => 'E',
'/è|é|ê|ë|ē|ĕ|ė|ę|ě|е|ё|э/' => 'e',
'/Ф/' => 'F',
'/ƒ|ф/' => 'f',
'/Ĝ|Ğ|Ġ|Ģ|Г/' => 'G',
'/ĝ|ğ|ġ|ģ|г/' => 'g',
'/Ĥ|Ħ|Х/' => 'H',
'/ĥ|ħ|х/' => 'h',
'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|И/' => 'I',
'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|и/' => 'i',
'/Ĵ|Й/' => 'J',
'/ĵ|й/' => 'j',
'/Ķ|К/' => 'K',
'/ķ|к/' => 'k',
'/Ĺ|Ļ|Ľ|Ŀ|Ł|Л/' => 'L',
'/ĺ|ļ|ľ|ŀ|ł|л/' => 'l',
'/М/' => 'M',
'/м/' => 'm',
'/Ñ|Ń|Ņ|Ň|Н/' => 'N',
'/ñ|ń|ņ|ň|ʼn|н/' => 'n',
'/Ö|Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|О/' => 'O',
'/ö|ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|о/' => 'o',
'/П/' => 'P',
'/п/' => 'p',
'/Ŕ|Ŗ|Ř|Р/' => 'R',
'/ŕ|ŗ|ř|р/' => 'r',
'/Ś|Ŝ|Ş|Š|С/' => 'S',
'/ś|ŝ|ş|š|ſ|с/' => 's',
'/Ţ|Ť|Ŧ|Т/' => 'T',
'/ţ|ť|ŧ|т/' => 't',
'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|У/' => 'U',
'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|у/' => 'u',
'/В/' => 'V',
'/в/' => 'v',
'/Ý|Ÿ|Ŷ|Ы/' => 'Y',
'/ý|ÿ|ŷ|ы/' => 'y',
'/Ŵ/' => 'W',
'/ŵ/' => 'w',
'/Ź|Ż|Ž|З/' => 'Z',
'/ź|ż|ž|з/' => 'z',
'/Æ|Ǽ/' => 'AE',
'/ß/'=> 'ss',
'/IJ/' => 'IJ',
'/ij/' => 'ij',
'/Œ/' => 'OE',
'/Ч/' => 'Ch',
'/ч/' => 'ch',
'/Ю/' => 'Ju',
'/ю/' => 'ju',
'/Я/' => 'Ja',
'/я/' => 'ja',
'/Ш/' => 'Sh',
'/ш/' => 'sh',
'/Щ/' => 'Shch',
'/щ/' => 'shch',
'/Ж/' => 'Zh',
'/ж/' => 'zh',
),
);
\ No newline at end of file
......@@ -7,10 +7,10 @@ class Home_Controller extends Controller {
| The Default Controller
|--------------------------------------------------------------------------
|
| Instead of using RESTful routes and anonymous functions, you may wish to
| use controllers to organize your application API. You'll love them.
| Instead of using RESTful routes and anonymous functions, you might wish
| to use controllers to organize your application API. You'll love them.
|
| To start using this controller, simply remove the default route from the
| To start using this controller simply remove the default route from the
| application "routes.php" file. Laravel is smart enough to find this
| controller and call the default method, which is "action_index".
|
......
<?php
return array(
/*
|--------------------------------------------------------------------------
| Filters
|--------------------------------------------------------------------------
|
| Filters provide a convenient method for attaching functionality to your
| routes. Filters can run either before or after a route is exectued.
|
| The built-in "before" and "after" filters are called before and after
| every request to your application; however, you may create other filters
| that can be attached to individual routes.
|
| Filters also make common tasks such as authentication and CSRF protection
| a breeze. If a filter that runs before a route returns a response, that
| response will override the route action.
|
| Let's walk through an example...
|
| First, define a filter:
|
| 'simple_filter' => function()
| {
| return 'Filtered!';
| }
|
| Next, attach the filter to a route:
|
| 'GET /' => array('before' => 'simple_filter', function()
| {
| return 'Hello World!';
| })
|
| Now every requests to http://example.com will return "Filtered!", since
| the filter is overriding the route action by returning a value.
|
| To make your life easier, we have built authentication and CSRF filters
| that are ready to attach to your routes. Enjoy.
|
*/
'before' => function()
{
// Do stuff before every request to your application.
},
'after' => function($response)
{
// Do stuff after every request to your application.
},
'auth' => function()
{
if (Auth::guest()) return Redirect::to_login();
},
'csrf' => function()
{
if (Request::forged()) return Response::error('500');
},
);
\ No newline at end of file
......@@ -8,8 +8,8 @@ return array(
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the pagination links. They may be easily changed by the developer to
| anything they wish.
| the pagination links. You're free to change them to anything you want.
| If you come up with something more exciting, let us know.
|
*/
......
......@@ -8,11 +8,12 @@ return array(
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly, such as "E-Mail Address" instead
| of "email".
| with something more reader friendly such as "E-Mail Address" instead
| of "email". Your users will thank you.
|
| The Validator class will automatically search this array of lines when
| attempting to replace the :attribute place-holder in error messages.
| The Validator class will automatically search this array of lines it
| is attempting to replace the :attribute place-holder in messages.
| It's pretty slick. We think you'll like it.
|
*/
......@@ -28,9 +29,9 @@ return array(
| such as the size (max, min, between) rules. These versions are used
| for different input types such as strings and files.
|
| These language lines may be easily changed by the developer to provide
| custom error messages in their application. Error messages for custom
| validation rules may also be added to this file.
| These language lines may be easily changed to provide custom error
| messages in your application. Error messages for custom validation
| rules may also be added to this file.
|
*/
......
<?php
return array(
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Simply tell Laravel the HTTP verbs and URIs it should respond to. It is a
| breeze to setup your applications using Laravel's RESTful routing, and it
| is perfectly suited for building both large applications and simple APIs.
| Enjoy the fresh air and simplicity of the framework.
|
| Let's respond to a simple GET request to http://example.com/hello:
|
| Router::register('GET /hello', function()
| {
| return 'Hello World!';
| });
|
| You can even respond to more than one URI:
|
| Router::register('GET /hello, GET /world', function()
| {
| return 'Hello World!';
| });
|
| It's easy to allow URI wildcards using (:num) or (:any):
|
| Router::register('GET /hello/(:any)', function($name)
| {
| return "Welcome, $name.";
| });
|
*/
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Simply tell Laravel the HTTP verbs and URIs it should respond to. It's a
| piece of cake to create beautiful applications using the elegant RESTful
| routing available in Laravel.
|
| Let's respond to a simple GET request to http://example.com/hello:
|
| 'GET /hello' => function()
| {
| return 'Hello World!';
| }
|
| You can even respond to more than one URI:
|
| 'GET /hello, GET /world' => function()
| {
| return 'Hello World!';
| }
|
| It's easy to allow URI wildcards using (:num) or (:any):
|
| 'GET /hello/(:any)' => function($name)
| {
| return "Welcome, $name.";
| }
|
*/
Router::register(array('GET /', 'GET /home'), function()
{
return View::make('home.index');
});
'GET /' => function()
{
return View::make('home.index');
},
/*
|--------------------------------------------------------------------------
| Route Filters
|--------------------------------------------------------------------------
|
| Filters provide a convenient method for attaching functionality to your
| routes. The built-in "before" and "after" filters are called before and
| after every request to your application, and you may even create other
| filters that can be attached to individual routes.
|
| Let's walk through an example...
|
| First, define a filter:
|
| Filter::register('filter', function()
| {
| return 'Filtered!';
| });
|
| Next, attach the filter to a route:
|
| Router::register('GET /', array('before' => 'filter', function()
| {
| return 'Hello World!';
| }));
|
*/
);
\ No newline at end of file
Filter::register('before', function()
{
// Do stuff before every request to your application...
});
Filter::register('after', function()
{
// Do stuff after every request to your application...
});
Filter::register('csrf', function()
{
if (Request::forged()) return Response::error('500');
});
Filter::register('auth', function()
{
if (Auth::guest()) return Redirect::to('login');
});
\ No newline at end of file
<?php
/**
* Laravel (CLI) - A Command Line For Web Artisans
*
* @package Laravel
* @version 2.0.7
* @author Taylor Otwell <taylorotwell@gmail.com>
* @link http://laravel.com
*/
// --------------------------------------------------------------
// Define the directory separator for the environment.
// --------------------------------------------------------------
define('DS', DIRECTORY_SEPARATOR);
// --------------------------------------------------------------
// The path to the application directory.
// --------------------------------------------------------------
define('APP_PATH', realpath('application').'/');
// --------------------------------------------------------------
// The path to the bundles directory.
// --------------------------------------------------------------
define('BUNDLE_PATH', realpath('bundles').'/');
// --------------------------------------------------------------
// The path to the storage directory.
// --------------------------------------------------------------
define('STORAGE_PATH', realpath('storage').'/');
// --------------------------------------------------------------
// The path to the Laravel directory.
// --------------------------------------------------------------
define('SYS_PATH', realpath('laravel').'/');
// --------------------------------------------------------------
// The path to the public directory.
// --------------------------------------------------------------
define('PUBLIC_PATH', realpath('public').'/');
// --------------------------------------------------------------
// Bootstrap the Laravel core.
// --------------------------------------------------------------
require SYS_PATH.'core.php';
// --------------------------------------------------------------
// Launch the Laravel "Artisan" CLI.
// --------------------------------------------------------------
require SYS_PATH.'cli/artisan'.EXT;
\ No newline at end of file
# Laravel Change Log
## Version 2.1.0
- Fix: Multiple wildcards / regular expressions per segment are now supported.
### Upgrading from 2.0.9
- Replace **laravel** directory.
## Version 2.0.9
- Minor: Made "timestamps" method in Eloquent model protected instead of private.
- Fix: Authentication cookies are not deleted properly when custom domains or paths are used.
### Upgrading from 2.0.8
- Replace **laravel** directory.
## Version 2.0.8
- Fix: Limited URI segments to 20 to protect against DDoS.
### Upgrading from 2.0.7
- Replace **laravel** directory.
## Version 2.0.7
- Fix: Fixed raw_where in query builder.
......
<?php namespace Laravel; use Closure;
class Arr {
/**
* Get an item from an array.
*
* "Dot" notation may be used to dig deep into the array.
*
* <code>
* // Get the $array['user']['name'] value from the array
* $name = Arr::get($array, 'user.name');
*
* // Return a default from if the specified item doesn't exist
* $name = Arr::get($array, 'user.name', 'Taylor');
* </code>
*
* @param array $array
* @param string $key
* @param mixed $default
* @return mixed
*/
public static function get($array, $key, $default = null)
{
if (is_null($key)) return $array;
foreach (explode('.', $key) as $segment)
{
if ( ! is_array($array) or ! array_key_exists($segment, $array))
{
return ($default instanceof Closure) ? call_user_func($default) : $default;
}
$array = $array[$segment];
}
return $array;
}
/**
* Set an array item to a given value.
*
* The same "dot" syntax used by the "get" method may be used here.
*
* If no key is given to the method, the entire array will be replaced.
*
* <code>
* // Set the $array['user']['name'] value on the array
* Arr::set($array, 'user.name', 'Taylor');
* </code>
*
* @param array $array
* @param string $key
* @param mixed $value
* @return void
*/
public static function set(&$array, $key, $value)
{
if (is_null($key)) return $array = $value;
$keys = explode('.', $key);
while (count($keys) > 1)
{
$key = array_shift($keys);
if ( ! isset($array[$key]) or ! is_array($array[$key]))
{
$array[$key] = array();
}
$array =& $array[$key];
}
$array[array_shift($keys)] = $value;
}
/**
* Remove an array item from a given array.
*
* The same "dot" syntax used by the "get" method may be used here.
*
* <code>
* // Remove the $array['user']['name'] item from the array
* Arr::forget($array, 'user.name');
* </code>
*
* @param array $array
* @param string $key
* @return void
*/
public static function forget(&$array, $key)
{
if (is_null($key)) return;
$keys = explode('.', $key);
while (count($keys) > 1)
{
$key = array_shift($keys);
if ( ! isset($array[$key]) or ! is_array($array[$key]))
{
return;
}
$array =& $array[$key];
}
unset($array[array_shift($keys)]);
}
/**
* Return the first element in an array which passes a given truth test.
*
* <code>
* // Return the first array element that equals "Taylor"
* $value = Arr::first($array, function($k, $v) {return $v === 'Taylor';});
*
* // Return a default value if no matching element is found
* $value = Arr::first($array, function($k, $v) {return $v === 'Taylor'}, 'Default');
* </code>
*
* @param array $array
* @param Closure $callback
* @param mixed $default
* @return mixed
*/
public static function first($array, $callback, $default = null)
{
foreach ($array as $key => $value)
{
if (call_user_func($callback, $key, $value)) return $value;
}
return ($default instanceof Closure) ? call_user_func($default) : $default;
}
/**
* Remove all array values that are contained within a given array of values.
*
* <code>
* // Remove all array values that are empty strings
* $array = Arr::without($array, '');
*
* // Remove all array values that are "One", "Two", or "Three"
* $array = Arr::without($array, array('One', 'Two', 'Three'));
* </code>
*
* @param array $array
* @param array $without
* @return array
*/
public static function without($array, $without = array())
{
$without = (array) $without;
foreach ((array) $array as $key => $value)
{
if (in_array($value, $without)) unset($array[$key]);
}
return $array;
}
}
\ No newline at end of file
<?php namespace Laravel;
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
class Asset {
......@@ -34,7 +34,7 @@ class Asset {
}
/**
* Magic Method for calling methods on the default Asset container.
* Magic Method for calling methods on the default container.
*
* <code>
* // Call the "styles" method on the default container
......@@ -60,6 +60,13 @@ class Asset_Container {
*/
public $name;
/**
* The bundle that the assets belong to.
*
* @var string
*/
public $bundle = DEFAULT_BUNDLE;
/**
* All of the registered assets.
*
......@@ -83,8 +90,8 @@ class Asset_Container {
* Add an asset to the container.
*
* The extension of the asset source will be used to determine the type of
* asset being registered (CSS or JavaScript). If you are using a non-standard
* extension, you may use the style or script methods to register assets.
* asset being registered (CSS or JavaScript). When using a non-standard
* extension, the style/script methods may be used to register assets.
*
* <code>
* // Add an asset to the container
......@@ -107,7 +114,7 @@ class Asset_Container {
{
$type = (pathinfo($source, PATHINFO_EXTENSION) == 'css') ? 'style' : 'script';
return call_user_func(array($this, $type), $name, $source, $dependencies, $attributes);
return $this->$type($name, $source, $dependencies, $attributes);
}
/**
......@@ -147,6 +154,29 @@ class Asset_Container {
return $this;
}
/**
* Returns the full-path for an asset.
*
* @param string $source
* @return string
*/
public function path($source)
{
return Bundle::assets($this->bundle).$source;
}
/**
* Set the bundle that the container's assets belong to.
*
* @param string $bundle
* @return Asset_Container
*/
public function bundle($bundle)
{
$this->bundle = $bundle;
return $this;
}
/**
* Add an asset to the array of registered assets.
*
......@@ -219,6 +249,14 @@ class Asset_Container {
$asset = $this->assets[$group][$name];
// If the bundle source is not a complete URL, we will go ahead and prepend
// the bundle's asset path to the source provided with the asset. This will
// ensure that we attach the correct path to the asset.
if (filter_var($asset['source'], FILTER_VALIDATE_URL) === false)
{
$asset['source'] = Bundle::assets($this->bundle).$asset['source'];
}
return HTML::$group($asset['source'], $asset['attributes']);
}
......@@ -257,7 +295,7 @@ class Asset_Container {
{
// If the asset has no more dependencies, we can add it to the sorted list
// and remove it from the array of assets. Otherwise, we will not verify
// the asset's dependencies and determine if they have already been sorted.
// the asset's dependencies and determine if they've been sorted.
if (count($assets[$asset]['dependencies']) == 0)
{
$sorted[$asset] = $value;
......@@ -289,7 +327,8 @@ class Asset_Container {
* Verify that an asset's dependency is valid.
*
* A dependency is considered valid if it exists, is not a circular reference, and is
* not a reference to the owning asset itself.
* not a reference to the owning asset itself. If the dependency doesn't exist, no
* error or warning will be given. For the other cases, an exception is thrown.
*
* @param string $asset
* @param string $dependency
......@@ -299,16 +338,20 @@ class Asset_Container {
*/
protected function dependency_is_valid($asset, $dependency, $original, $assets)
{
if ( ! isset($original[$dependency])) return false;
if ($dependency === $asset)
if ( ! isset($original[$dependency]))
{
throw new \LogicException("Asset [$asset] is dependent on itself.");
return false;
}
elseif ($dependency === $asset)
{
throw new \Exception("Asset [$asset] is dependent on itself.");
}
elseif (isset($assets[$dependency]) and in_array($asset, $assets[$dependency]['dependencies']))
{
throw new \LogicException("Assets [$asset] and [$dependency] have a circular dependency.");
throw new \Exception("Assets [$asset] and [$dependency] have a circular dependency.");
}
return true;
}
}
......@@ -7,7 +7,7 @@ class Auth {
*
* @var object
*/
protected static $user;
public static $user;
/**
* The key used when storing the user ID in the session.
......@@ -48,12 +48,6 @@ class Auth {
/**
* Get the current user of the application.
*
* This method will call the "user" closure in the auth configuration file.
* If the user is not authenticated, null will be returned by the methd.
*
* If no user exists in the session, the method will check for a "remember me"
* cookie and attempt to login the user based on the value of that cookie.
*
* <code>
* // Get the current user of the application
* $user = Auth::user();
......@@ -62,20 +56,26 @@ class Auth {
* $email = Auth::user()->email;
* </code>
*
* @return object
* @return object|null
*/
public static function user()
{
if ( ! is_null(static::$user)) return static::$user;
$id = IoC::core('session')->get(Auth::user_key);
$id = Session::get(Auth::user_key);
static::$user = call_user_func(Config::get('auth.user'), $id);
// To retrieve the user, we'll first attempt to use the "user" Closure
// defined in the auth configuration file, passing in the ID. The user
// Closure gives the developer a ton of freedom surrounding how the
// user is actually retrieved.
$config = Config::get('auth');
// If the user was not found in the database, but a "remember me" cookie
// exists, we will attempt to recall the user based on the cookie value.
// Since all cookies contain a fingerprint hash verifying that the have
// not been modified on the client, we should be able to trust it.
static::$user = call_user_func($config['user'], $id);
// If the user wasn't found in the database but a "remember me" cookie
// exists, we'll attempt to recall the user based on the cookie value.
// Since all cookies contain a fingerprint hash verifying that they
// haven't changed, we can trust it.
$recaller = Cookie::get(Auth::remember_key);
if (is_null(static::$user) and ! is_null($recaller))
......@@ -94,13 +94,17 @@ class Auth {
*/
protected static function recall($recaller)
{
// When the "remember me" cookie is stored, it is encrypted and contains the
// user's ID and a long, random string. The ID and string are separated by
// a pipe character. Since we exploded the decrypted string, we can just
// pass the first item in the array to the user Closure.
// When the remember me cookie is stored, it is encrypted and contains
// the user's ID and a long, random string. The segments are separated
// by a pipe character so we'll explode on that.
$recaller = explode('|', Crypter::decrypt($recaller));
if ( ! is_null($user = call_user_func(Config::get('auth.user'), $recaller[0])))
// We'll pass the ID that was stored in the cookie into the same user
// Closure that is used by the "user" method. If the method returns
// a user, we will log them into the application.
$user = call_user_func(Config::get('auth.user'), $recaller[0]);
if ( ! is_null($user))
{
static::login($user);
......@@ -111,12 +115,13 @@ class Auth {
/**
* Attempt to log a user into the application.
*
* If the credentials are valid, the user will be logged into the application
* and their user ID will be stored in the session via the "login" method.
* <code>
* // Attempt to log a user into the application
* $success = Auth::attempt('username', 'password');
*
* The user may also be "remembered", which will keep the user logged into the
* application for one year or until they logout. The user is remembered via
* an encrypted cookie.
* // Attempt to login a user and set the "remember me" cookie
* Auth::attempt('username', 'password', true);
* </code>
*
* @param string $username
* @param string $password
......@@ -127,32 +132,35 @@ class Auth {
{
$config = Config::get('auth');
$user = call_user_func($config['attempt'], $username, $password, $config);
// When attempting to login the user, we will call the "attempt" closure
// from the configuration file. This gives the developer the freedom to
// authenticate based on the needs of their application.
//
// All of the password hashing and checking and left totally up to the
// developer, as this gives them the freedom to use any hashing scheme
// or authentication provider they wish.
$user = call_user_func($config['attempt'], $username, $password);
if ( ! is_null($user))
{
static::login($user, $remember);
// If the user credentials were authenticated by the closure, we will
// log the user into the application, which will store their user ID
// in the session for subsequent requests.
if (is_null($user)) return false;
return true;
}
static::login($user, $remember);
return false;
return true;
}
/**
* Log a user into the application.
*
* An object representing the user or an integer user ID may be given to the method.
* If an object is given, the object must have an "id" property containing the user
* ID as it is stored in the database.
*
* <code>
* // Login a user by passing a user object
* Auth::login($user);
*
* // Login the user with an ID of 15
* Auth::login(15);
*
* // Login a user by passing a user object
* Auth::login($user);
*
* // Login a user and set a "remember me" cookie
* Auth::login($user, true);
* </code>
......@@ -167,11 +175,11 @@ class Auth {
if ($remember) static::remember($id);
IoC::core('session')->put(Auth::user_key, $id);
Session::put(Auth::user_key, $id);
}
/**
* Set a cookie so that users are "remembered" and don't need to login.
* Set a cookie so that the user is "remembered".
*
* @param string $id
* @return void
......@@ -183,7 +191,7 @@ class Auth {
// This method assumes the "remember me" cookie should have the same
// configuration as the session cookie. Since this cookie, like the
// session cookie, should be kept very secure, it's probably safe
// to assume the settings are the same.
// to assume the settings are the same for this cookie.
$config = Config::get('session');
extract($config, EXTR_SKIP);
......@@ -194,14 +202,13 @@ class Auth {
/**
* Log the current user out of the application.
*
* The "logout" closure in the authenciation configuration file will be
* called. All authentication cookies will be deleted and the user ID
* will be removed from the session.
*
* @return void
*/
public static function logout()
{
// We will call the "logout" closure first, which gives the developer
// the chance to do any clean-up or before the user is logged out of
// the application. No action is taken by default.
call_user_func(Config::get('auth.logout'), static::user());
static::$user = null;
......@@ -213,11 +220,9 @@ class Auth {
// When forgetting the cookie, we need to also pass in the path and
// domain that would have been used when the cookie was originally
// set by the framework, otherwise it will not be deleted.
Cookie::forget(Auth::user_key, $path, $domain, $secure);
Cookie::forget(Auth::remember_key, $path, $domain, $secure);
IoC::core('session')->forget(Auth::user_key);
Session::forget(Auth::user_key);
}
}
\ No newline at end of file
<?php namespace Laravel;
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
class Autoloader {
......@@ -10,176 +10,143 @@ class Autoloader {
public static $mappings = array();
/**
* The PSR-0 compliant libraries registered with the loader.
* All of the class aliases registered with the auto-loader.
*
* @var array
*/
public static $libraries = array();
public static $aliases = array();
/**
* The paths to be searched by the loader.
* The directories that use the PSR-0 naming convention.
*
* @var array
*/
protected static $paths = array(MODEL_PATH, LIBRARY_PATH);
public static $psr = array();
/**
* Load the file corresponding to a given class.
*
* This method is registerd in the core bootstrap file as an SPL Autoloader.
* This method is registerd in the bootstrap file as an SPL auto-loader.
*
* @param string $class
* @return void
*/
public static function load($class)
{
if (isset(Config::$items['application']['aliases'][$class]))
// First, we will check to see if the class has been aliased. If it has,
// we will register the alias, which may cause the auto-loader to be
// called again for the "real" class name.
if (isset(static::$aliases[$class]))
{
return class_alias(Config::$items['application']['aliases'][$class], $class);
class_alias(static::$aliases[$class], $class);
}
if ( ! is_null($path = static::find($class)))
// All classes in Laravel are staticly mapped. There is no crazy search
// routine that digs through directories. It's just a simple array of
// class to file path maps for ultra-fast file loading.
elseif (isset(static::$mappings[$class]))
{
require $path;
}
}
/**
* Determine the file path associated with a given class name.
*
* @param string $class
* @return string
*/
protected static function find($class)
{
// First we will look for the class in the hard-coded class mappings, since
// this is the fastest way to resolve a class name to its associated file.
// This saves us from having to search through the file system manually.
if (isset(static::$mappings[$class]))
{
return static::$mappings[$class];
require static::$mappings[$class];
}
// If the library has been registered as a PSR-0 compliant library, we will
// load the library according to the PSR-0 naming standards, which state that
// namespaces and underscores indicate the directory hierarchy of the class.
if (in_array(static::library($class), static::$libraries))
// If the class is namespaced to an existing bundle and the bundle has
// not been started, we will start the bundle and attempt to load the
// class file again. If that fails, an error will be thrown by PHP.
//
// This allows bundle classes to be loaded by the auto-loader before
// their class mappings have actually been registered; however, it
// is up to the bundle developer to namespace their classes to
// match the name of their bundle.
elseif (($slash = strpos($class, '\\')) !== false)
{
return LIBRARY_PATH.str_replace(array('\\', '_'), '/', $class).EXT;
}
// Next we will search through the common Laravel paths for the class file.
// The Laravel libraries and models directories will be searched according
// to the Laravel class naming standards.
$file = strtolower(str_replace('\\', '/', $class));
$bundle = substr($class, 0, $slash);
foreach (static::$paths as $path)
{
if (file_exists($path = $path.$file.EXT))
// It's very important that we make sure the bundle has not been
// started here. If we don't, we'll end up in an infinite loop
// attempting to load a bundle's class.
if (Bundle::exists($bundle) and ! Bundle::started($bundle))
{
return $path;
Bundle::start($bundle);
static::load($class);
}
}
// Since not all controllers will be resolved by the controller resolver,
// we will do a quick check in the controller directory for the class.
// For instance, since base controllers would not be resolved by the
// controller class, we will need to resolve them here.
if (file_exists($path = static::controller($class)))
{
return $path;
}
static::load_psr($class);
}
/**
* Extract the "library" name from the given class.
*
* The library name is essentially the namespace, or the string that preceeds
* the first PSR-0 separator. PSR-0 states that namespaces or undescores may
* be used to indicate the directory structure in which the file resides.
* Attempt to resolve a class using the PSR-0 standard.
*
* @param string $class
* @return string
* @return void
*/
protected static function library($class)
protected static function load_psr($class)
{
if (($separator = strpos($class, '\\')) !== false)
{
return substr($class, 0, $separator);
}
elseif (($separator = strpos($class, '_')) !== false)
// The PSR-0 standard indicates that class namespace slashes or
// underscores should be used to indicate the directory tree in
// which the class resides.
$file = str_replace(array('\\', '_'), '/', $class);
// Once we have formatted the class name, we will simply spin
// through the registered PSR-0 directories and attempt to
// locate and load the class into the script.
foreach (static::$psr as $directory)
{
return substr($class, 0, $separator);
if (file_exists($path = $directory.strtolower($file).EXT))
{
return require $path;
}
elseif (file_exists($path = $directory.$file.EXT))
{
return require $path;
}
}
}
/**
* Translate a given controller class name into the corresponding file name.
*
* The controller suffix will be removed, and the underscores will be translated
* into directory slashes. Of course, the entire class name will be converted to
* lower case as well.
* Register an array of class to path mappings.
*
* <code>
* // Returns "user/profile"...
* $file = static::controller('User_Profile_Controller');
* // Register a class mapping with the Autoloader
* Autoloader::map(array('User' => APP_PATH.'models/user.php'));
* </code>
*
* @param string $class
* @return string
* @param array $mappings
* @return void
*/
protected static function controller($class)
public static function map($mappings)
{
$controller = str_replace(array('_', '_Controller'), array('/', ''), $class);
return CONTROLLER_PATH.strtolower($controller).EXT;
static::$mappings = array_merge(static::$mappings, $mappings);
}
/**
* Register an array of class to path mappings.
*
* The mappings will be used to resolve file paths from class names when
* a class is lazy loaded through the Autoloader, providing a faster way
* of resolving file paths than the typical file_exists method.
*
* <code>
* // Register a class mapping with the Autoloader
* Autoloader::maps(array('User' => MODEL_PATH.'user'.EXT));
* </code>
* Register a class alias with the auto-loader.
*
* @param array $mappings
* @param string $class
* @param string $alias
* @return void
*/
public static function maps($mappings)
public static function alias($class, $alias)
{
foreach ($mappings as $class => $path)
{
static::$mappings[$class] = $path;
}
static::$aliases[$alias] = $class;
}
/**
* Register PSR-0 libraries with the Autoloader.
*
* The library names given to this method should match directories within
* the application libraries directory. This method provides an easy way
* to indicate that some libraries should be loaded using the PSR-0
* naming conventions instead of the Laravel conventions.
*
* <code>
* // Register the "Assetic" library with the Autoloader
* Autoloader::libraries('Assetic');
*
* // Register several libraries with the Autoloader
* Autoloader::libraries(array('Assetic', 'Twig'));
* </code>
* Register directories to be searched as a PSR-0 library.
*
* @param array $libraries
* @param string|array $directory
* @return void
*/
public static function libraries($libraries)
public static function psr($directory)
{
static::$libraries = array_merge(static::$libraries, (array) $libraries);
$directories = array_map(function($directory)
{
return rtrim($directory, '/').'/';
}, (array) $directory);
static::$psr = array_unique(array_merge(static::$psr, $directories));
}
}
\ No newline at end of file
<?php namespace Laravel;
class Benchmark {
/**
* All of the benchmark starting times.
*
* @var array
*/
protected static $marks = array();
/**
* Start a benchmark starting time.
*
* @param string $name
* @return void
*/
public static function start($name)
{
static::$marks[$name] = microtime(true);
}
/**
* Get the elapsed time in milliseconds since starting a benchmark.
*
* @param string $name
* @return float
*/
public static function check($name)
{
if (array_key_exists($name, static::$marks))
{
return (float) number_format((microtime(true) - static::$marks[$name]) * 1000, 2);
}
return (float) 0.0;
}
/**
* Get the total memory usage in megabytes.
*
* @return float
*/
public static function memory()
{
return (float) number_format(memory_get_usage() / 1024 / 1024, 2);
}
}
\ No newline at end of file
<?php namespace Laravel;
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
class Blade {
......@@ -49,10 +49,6 @@ class Blade {
/**
* Rewrites Blade echo statements into PHP echo statements.
*
* Blade echo statements are simply PHP statement enclosed within double curly
* braces. For example, {{$content}} will simply echo out the content variable
* to the output buffer.
*
* @param string $value
* @return string
*/
......@@ -64,10 +60,6 @@ class Blade {
/**
* Rewrites Blade structure openings into PHP structure openings.
*
* By "structures", we mean the if, elseif, foreach, for, and while statements.
* All of these structures essentially have the same format, and can be lumped
* into a single regular expression.
*
* @param string $value
* @return string
*/
......
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
class Bundle {
/**
* All of the application's bundles.
*
* @var array
*/
protected static $bundles;
/**
* A cache of the parsed bundle elements.
*
* @var array
*/
protected static $elements = array();
/**
* All of the bundles that have been started.
*
* @var array
*/
protected static $started = array();
/**
* Load a bundle by running it's start-up script.
*
* If the bundle has already been started, no action will be taken.
*
* @param string $bundle
* @return void
*/
public static function start($bundle)
{
if (static::started($bundle)) return;
if ($bundle !== DEFAULT_BUNDLE and ! static::exists($bundle))
{
throw new \Exception("Bundle [$bundle] has not been installed.");
}
// Each bundle may have a "start" script which is responsible for preparing
// the bundle for use by the application. The start script may register any
// classes the bundle uses with the auto-loader, or perhaps will start any
// dependent bundles so that they are available.
if (file_exists($path = static::path($bundle).'bundle'.EXT))
{
require $path;
}
// Each bundle may also have a "routes" file which is responsible for
// registering the bundle's routes. This is kept separate from the
// start script for reverse routing efficiency purposes.
static::routes($bundle);
static::$started[] = strtolower($bundle);
}
/**
* Load the "routes" file for a given bundle.
*
* @param string $bundle
* @return void
*/
public static function routes($bundle)
{
if (static::started($bundle)) return;
if (file_exists($path = static::path($bundle).'routes'.EXT))
{
require $path;
}
}
/**
* Determine if the given bundle is "routable".
*
* A bundle is considered routable if it has a controller directory or a routes file.
*
* @param string $bundle
* @return bool
*/
public static function routable($bundle)
{
$path = static::path($bundle);
return is_dir($path.'controllers/') or file_exists($path.'routes'.EXT);
}
/**
* Deteremine if a bundle exists within the bundles directory.
*
* @param string $bundle
* @return bool
*/
public static function exists($bundle)
{
return in_array(strtolower($bundle), static::all());
}
/**
* Determine if a given bundle has been started for the request.
*
* @param string $bundle
* @return void
*/
public static function started($bundle)
{
return in_array(strtolower($bundle), static::$started);
}
/**
* Get the identifier prefix for the bundle.
*
* @param string $bundle
* @return string
*/
public static function prefix($bundle)
{
return ($bundle !== DEFAULT_BUNDLE) ? "{$bundle}::" : '';
}
/**
* Get the class prefix for a given bundle.
*
* @param string $bundle
* @return string
*/
public static function class_prefix($bundle)
{
return ($bundle !== DEFAULT_BUNDLE) ? Str::classify($bundle).'_' : '';
}
/**
* Return the root bundle path for a given bundle.
*
* <code>
* // Returns the bundle path for the "admin" bundle
* $path = Bundle::path('admin');
*
* // Returns the APP_PATH constant as the default bundle
* $path = Bundle::path('application');
* </code>
*
* @param string $bundle
* @return string
*/
public static function path($bundle)
{
return ($bundle != DEFAULT_BUNDLE) ? BUNDLE_PATH.strtolower($bundle).DS : APP_PATH;
}
/**
* Return the root asset path for the given bundle.
*
* @param string $bundle
* @return string
*/
public static function assets($bundle)
{
return ($bundle != DEFAULT_BUNDLE) ? PUBLIC_PATH."bundles/{$bundle}/" : PUBLIC_PATH;
}
/**
* Get the bundle name from a given identifier.
*
* <code>
* // Returns "admin" as the bundle name for the identifier
* $bundle = Bundle::name('admin::home.index');
* </code>
*
* @param string $identifier
* @return string
*/
public static function name($identifier)
{
list($bundle, $element) = static::parse($identifier);
return $bundle;
}
/**
* Get the element name from a given identifier.
*
* <code>
* // Returns "home.index" as the element name for the identifier
* $bundle = Bundle::bundle('admin::home.index');
* </code>
*
* @param string $identifier
* @return string
*/
public static function element($identifier)
{
list($bundle, $element) = static::parse($identifier);
return $element;
}
/**
* Reconstruct an identifier from a given bundle and element.
*
* <code>
* // Returns "admin::home.index"
* $identifier = Bundle::identifier('admin', 'home.index');
*
* // Returns "home.index"
* $identifier = Bundle::identifier('application', 'home.index');
* </code>
*
* @param string $bundle
* @param string $element
* @return string
*/
public static function identifier($bundle, $element)
{
return (is_null($bundle) or $bundle == DEFAULT_BUNDLE) ? $element : $bundle.'::'.$element;
}
/**
* Return the bundle name if it exists, else return the default bundle.
*
* @param string $bundle
* @return string
*/
public static function resolve($bundle)
{
return (static::exists($bundle)) ? $bundle : DEFAULT_BUNDLE;
}
/**
* Parse a element identifier and return the bundle name and element.
*
* <code>
* // Returns array(null, 'admin.user')
* $element = Bundle::parse('admin.user');
*
* // Parses "admin::user" and returns array('admin', 'user')
* $element = Bundle::parse('admin::user');
* </code>
*
* @param string $identifier
* @return array
*/
public static function parse($identifier)
{
// The parsed elements are cached so we don't have to reparse them on each
// subsequent request for the parsed element. So, if we've already parsed
// the given element, we'll just return the cached copy.
if (isset(static::$elements[$identifier]))
{
return static::$elements[$identifier];
}
if (strpos($identifier, '::') !== false)
{
$element = explode('::', strtolower($identifier));
}
// If no bundle is in the identifier, we will insert the default bundle
// since classes like Config and Lang organize their items by bundle.
// The "application" folder essentially behaves as a bundle.
else
{
$element = array(DEFAULT_BUNDLE, strtolower($identifier));
}
return static::$elements[$identifier] = $element;
}
/**
* Detect all of the existing bundles in the application.
*
* The names of the bundles are cached so this operation will be only be
* performed once and then the same array will be returned on each later
* request for the bundle names.
*
* @return array
*/
public static function all()
{
if (is_array(static::$bundles)) return static::$bundles;
$bundles = array();
foreach (array_filter(glob(BUNDLE_PATH.'*'), 'is_dir') as $bundle)
{
$bundles[] = basename($bundle);
}
return static::$bundles = $bundles;
}
}
\ No newline at end of file
<?php namespace Laravel\Cache;
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
use Laravel\Redis;
use Laravel\Config;
use Laravel\Memcached;
class Manager {
class Cache {
/**
* All of the active cache drivers.
*
* @var array
*/
protected static $drivers = array();
public static $drivers = array();
/**
* Get a cache driver instance.
*
* If no driver name is specified, the default cache driver will
* be returned as defined in the cache configuration file.
* If no driver name is specified, the default will be returned.
*
* <code>
* // Get the default cache driver instance
......@@ -34,9 +29,9 @@ class Manager {
{
if (is_null($driver)) $driver = Config::get('cache.driver');
if ( ! array_key_exists($driver, static::$drivers))
if ( ! isset(static::$drivers[$driver]))
{
return static::$drivers[$driver] = static::factory($driver);
static::$drivers[$driver] = static::factory($driver);
}
return static::$drivers[$driver];
......@@ -53,33 +48,33 @@ class Manager {
switch ($driver)
{
case 'apc':
return new Drivers\APC(Config::get('cache.key'));
return new Cache\Drivers\APC(Config::get('cache.key'));
case 'file':
return new Drivers\File(CACHE_PATH);
return new Cache\Drivers\File(CACHE_PATH);
case 'memcached':
return new Drivers\Memcached(Memcached::instance(), Config::get('cache.key'));
return new Cache\Drivers\Memcached(Memcached::connection(), Config::get('cache.key'));
case 'redis':
return new Drivers\Redis(Redis::db());
return new Cache\Drivers\Redis(Redis::db());
case 'database':
return new Cache\Drivers\Database(Config::get('cache.key'));
default:
throw new \DomainException("Cache driver {$driver} is not supported.");
throw new \Exception("Cache driver {$driver} is not supported.");
}
}
/**
* 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.
* Magic Method for calling the methods on the default cache driver.
*
* <code>
* // Call the "get" method on the default driver
* // Call the "get" method on the default cache driver
* $name = Cache::get('name');
*
* // Call the "put" method on the default driver
* // Call the "put" method on the default cache driver
* Cache::put('name', 'Taylor', 15);
* </code>
*/
......
<?php namespace Laravel\Cache\Drivers;
use Laravel\Config;
use Laravel\Database as DB;
use Laravel\Database\Connection;
class Database extends Driver {
/**
* The cache key from the cache configuration file.
*
* @var string
*/
protected $key;
/**
* Create a new database cache driver instance.
*
* @param string $key
* @return void
*/
public function __construct($key)
{
$this->key = $key;
}
/**
* Determine if an item exists in the cache.
*
* @param string $key
* @return bool
*/
public function has($key)
{
return ( ! is_null($this->get($key)));
}
/**
* Retrieve an item from the cache driver.
*
* @param string $key
* @return mixed
*/
protected function retrieve($key)
{
$cache = $this->table()->where('key', '=', $this->key.$key)->first();
if ( ! is_null($cache))
{
if (time() >= $cache->expiration) return $this->forget($key);
return unserialize($cache->value);
}
}
/**
* Write an item to the cache for a given number of minutes.
*
* <code>
* // Put an item in the cache for 15 minutes
* Cache::put('name', 'Taylor', 15);
* </code>
*
* @param string $key
* @param mixed $value
* @param int $minutes
* @return void
*/
public function put($key, $value, $minutes)
{
$key = $this->key.$key;
$value = serialize($value);
$expiration = $this->expiration($minutes);
// To update the value, we'll first attempt an insert against the
// database and if we catch an exception, we'll assume that the
// primary key already exists in the table and update.
try
{
$this->table()->insert(compact('key', 'value', 'expiration'));
}
catch (\Exception $e)
{
$this->table()->where('key', '=', $key)->update(compact('value', 'expiration'));
}
}
/**
* Delete an item from the cache.
*
* @param string $key
* @return void
*/
public function forget($key)
{
$this->table()->where('key', '=', $this->key.$key)->delete();
}
/**
* Get a query builder for the database table.
*
* @return Query
*/
protected function table()
{
$connection = DB::connection(Config::get('cache.database.connection'));
return $connection->table(Config::get('cache.database.table'));
}
}
\ No newline at end of file
......@@ -28,9 +28,7 @@ abstract class Driver {
*/
public function get($key, $default = null)
{
if ( ! is_null($item = $this->retrieve($key))) return $item;
return ($default instanceof Closure) ? call_user_func($default) : $default;
return ( ! is_null($item = $this->retrieve($key))) ? $item : value($default);
}
/**
......@@ -57,8 +55,7 @@ abstract class Driver {
abstract public function put($key, $value, $minutes);
/**
* Get an item from the cache. If the item doesn't exist in the
* cache, store the default value in the cache and return it.
* Get an item from the cache, or cache and return the default value.
*
* <code>
* // Get an item from the cache, or cache a value for 15 minutes
......@@ -77,9 +74,7 @@ abstract class Driver {
{
if ( ! is_null($item = $this->get($key, null))) return $item;
$default = ($default instanceof Closure) ? call_user_func($default) : $default;
$this->put($key, $default, $minutes);
$this->put($key, value($default), $minutes);
return $default;
}
......@@ -92,4 +87,15 @@ abstract class Driver {
*/
abstract public function forget($key);
/**
* Get the expiration time as a UNIX timestamp.
*
* @param int $minutes
* @return int
*/
protected function expiration($minutes)
{
return time() + ($minutes * 60);
}
}
......@@ -68,7 +68,7 @@ class File extends Driver {
*/
public function put($key, $value, $minutes)
{
$value = (time() + ($minutes * 60)).serialize($value);
$value = $this->expiration($minutes).serialize($value);
file_put_contents($this->path.$key, $value, LOCK_EX);
}
......@@ -81,10 +81,7 @@ class File extends Driver {
*/
public function forget($key)
{
if (file_exists($this->path.$key))
{
@unlink($this->path.$key);
}
if (file_exists($this->path.$key)) @unlink($this->path.$key);
}
}
\ No newline at end of file
<?php namespace Laravel\CLI; defined('APP_PATH') or die('No direct script access.');
use Laravel\IoC;
use Laravel\Bundle;
use Laravel\Database as DB;
/**
* Fire up the default bundle. This will ensure any dependencies that
* need to be registered in the IoC container are registered and that
* the auto-loader mappings are registered.
*/
Bundle::start(DEFAULT_BUNDLE);
/**
* We will register all of the Laravel provided tasks inside the IoC
* container so they can be resolved by the task class. This allows
* us to seamlessly add tasks to the CLI so that the Task class
* doesn't have to worry about how to resolve core tasks.
*/
/**
* The bundle task is responsible for the installation of bundles
* and their dependencies. It utilizes the bundles API to get the
* meta-data for the available bundles.
*/
IoC::register('task: bundle', function()
{
return new Tasks\Bundle\Bundler;
});
/**
* The migrate task is responsible for running database migrations
* as well as migration rollbacks. We will also create an instance
* of the migration resolver and database classes, which are used
* to perform various support functions for the migrator.
*/
IoC::register('task: migrate', function()
{
$database = new Tasks\Migrate\Database;
$resolver = new Tasks\Migrate\Resolver($database);
return new Tasks\Migrate\Migrator($resolver, $database);
});
/**
* We will wrap the command execution in a try / catch block and
* simply write out any exception messages we receive to the CLI
* for the developer. Note that this only writes out messages
* for the CLI exceptions. All others will be not be caught
* and will be totally dumped out to the CLI.
*/
try
{
Command::run(array_slice($_SERVER['argv'], 1));
}
catch (\Exception $e)
{
echo $e->getMessage();
}
echo PHP_EOL;
\ No newline at end of file
<?php namespace Laravel\CLI;
use Laravel\IoC;
use Laravel\Str;
use Laravel\Bundle;
class Command {
/**
* Run a CLI task with the given arguments.
*
* @param array $arguments
* @return void
*/
public static function run($arguments = array())
{
if ( ! isset($arguments[0]))
{
throw new \Exception("Whoops! You forgot to provide the task name.");
}
list($bundle, $task, $method) = static::parse($arguments[0]);
// If the task exists within a bundle, we will start the bundle so that
// any dependencies can be registered in the application IoC container.
// If the task is registered in the container, it will be resolved
// via the container instead of by this class.
if (Bundle::exists($bundle)) Bundle::start($bundle);
if (is_null($task = static::resolve($bundle, $task)))
{
throw new \Exception("Sorry, I can't find that task.");
}
$task->$method(array_slice($arguments, 1));
}
/**
* Parse the task name to extract the bundle, task, and method.
*
* @param string $task
* @return array
*/
protected static function parse($task)
{
list($bundle, $task) = Bundle::parse($task);
// Extract the task method from the task string. Methods are called
// on tasks by separating the task and method with a single colon.
// If no task is specified, "run" is used as the default method.
if (str_contains($task, ':'))
{
list($task, $method) = explode(':', $task);
}
else
{
$method = 'run';
}
return array($bundle, $task, $method);
}
/**
* Resolve an instance of the given task name.
*
* @param string $bundle
* @param string $task
* @return object
*/
public static function resolve($bundle, $task)
{
$identifier = Bundle::identifier($bundle, $task);
// First we'll check to see if the task has been registered in
// the application IoC container. This allows dependencies to
// be injected into tasks for more testability.
if (IoC::registered("task: {$identifier}"))
{
return IoC::resolve("task: {$identifier}");
}
// If the task file exists, we'll format the bundle and task
// name into a task class name and resolve an instance of
// the so that the requested method may be executed.
if (file_exists($path = Bundle::path($bundle).'tasks/'.$task.EXT))
{
require $path;
$task = static::format($bundle, $task);
return new $task;
}
}
/**
* Format a bundle and task into a task class name.
*
* @param string $bundle
* @param string $task
* @return string
*/
protected static function format($bundle, $task)
{
$prefix = Bundle::class_prefix($bundle);
return '\\'.$prefix.Str::clasify($task).'_Task';
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Bundle; defined('APP_PATH') or die('No direct script access.');
use Laravel\IoC;
use Laravel\Bundle;
use Laravel\CLI\Tasks\Task;
IoC::singleton('bundle.repository', function()
{
return new Repository;
});
IoC::singleton('bundle.publisher', function()
{
return new Publisher;
});
IoC::singleton('bundle.provider: github', function()
{
return new Providers\Github;
});
class Bundler extends Task {
/**
* Install the given bundles into the application.
*
* @param array $bundles
* @return void
*/
public function install($bundles)
{
$publisher = IoC::resolve('bundle.publisher');
foreach ($this->get($bundles) as $bundle)
{
if (is_dir(BUNDLE_PATH.$bundle['name']))
{
echo "Bundle {$bundle['name']} is already installed.";
continue;
}
// Once we have the bundle information, we can resolve an instance
// of a provider and install the bundle into the application and
// all of its registered dependencies as well.
//
// Each bundle provider implements the Provider interface and
// is repsonsible for retrieving the bundle source from its
// hosting party and installing it into the application.
$provider = "bundle.provider: {$bundle['provider']}";
IoC::resolve($provider)->install($bundle);
$publisher->publish($bundle);
}
}
/**
* Publish bundle assets to the public directory.
*
* @param array $bundles
* @return void
*/
public function publish($bundles)
{
// If no bundles are passed to the command, we'll just gather all
// of the installed bundle names and publish the assets for each
// for each one of the bundles to the public directory.
if (count($bundles) == 0) $bundles = Bundle::all();
$publisher = IoC::resolve('bundle.publisher');
foreach ($bundles as $bundle)
{
$publisher->publish($bundle);
}
}
/**
* Gather all of the bundles from the bundle repository.
*
* @param array $bundles
* @return array
*/
protected function get($bundles)
{
$responses = array();
$repository = IoC::resolve('bundle.repository');
// This method is primarily responsible for gathering the data
// for all bundles that need to be installed. This allows us
// to verify the existence of the bundle before even getting
// started on the actual installation process.
foreach ($bundles as $bundle)
{
// First we'll call the bundle repository to gather the bundle data
// array, which contains all of the information needed to install
// the bundle into the application. We'll verify that the bundle
// exists and the API is responding for each bundle.
$response = $repository->get($bundle);
if ( ! $response)
{
throw new \Exception("The bundle API is not responding.");
}
if ($response['status'] == 'not-found')
{
throw new \Exception("There is not a bundle named [$bundle].");
}
// If the bundle was retrieved successfully, we will add it to
// our array of bundles, as well as merge all of the bundle's
// dependencies into the array of responses so that they are
// installed along with the consuming dependency.
$bundle = $response['bundle'];
$responses[] = $bundle;
$responses = array_merge($responses, $this->get($bundle['dependencies']));
}
return $responses;
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Bundle\Providers;
class Github implements Provider {
/**
* Install the given bundle into the application.
*
* @param string $bundle
* @return void
*/
public function install($bundle)
{
$repository = "git://github.com/{$bundle['location']}.git";
// We need to just extract the basename of the bundle path when
// adding the submodule. Of course, we can't add a submodule to
// a location outside of the Git repository, so we don't need
// the full bundle path. We'll just take the basename in case
// the bundle directory has been renamed.
$path = basename(BUNDLE_PATH).'/';
passthru('git submodule add '.$repository.' '.$path.$bundle['name']);
passthru('git submodule update');
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Bundle\Providers;
interface Provider {
/**
* Install the given bundle into the application.
*
* @param string $bundle
* @return void
*/
public function install($bundle);
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Bundle;
use Laravel\Bundle;
use FilesystemIterator;
class Publisher {
/**
* Publish a bundle's assets to the public directory.
*
* @param string $bundle
* @return void
*/
public function publish($bundle)
{
$this->move($bundle, $this->from($bundle), $this->to($bundle));
echo "Assets published for bundle [$bundle].".PHP_EOL;
}
/**
* Copy the contents of a bundle's assets to the public folder.
*
* @param string $bundle
* @param string $source
* @param string $destination
* @return void
*/
protected function move($bundle, $source, $destination)
{
if ( ! is_dir($source)) return;
// First we need to create the destination directory if it doesn't
// already exists. This directory hosts all of the assets we copy
// from the installed bundle's source directory.
if ( ! is_dir($destination))
{
mkdir($destination);
}
$items = new FilesystemIterator($source, FilesystemIterator::SKIP_DOTS);
foreach ($items as $item)
{
// If the file system item is a directory, we will recurse the
// function, passing in the item directory. To get the proper
// destination path, we'll replace the root bundle asset
// directory with the root public asset directory.
if ($item->isDir())
{
$path = $item->getRealPath();
$recurse = str_replace($this->from($bundle), $this->to($bundle), $path);
$this->move($bundle, $path, $recurse);
}
// If the file system item is an actual file, we can copy the
// file from the bundle asset directory to the public asset
// directory. The "copy" method will overwrite any existing
// files with the same name.
else
{
copy($item->getRealPath(), $destination.DS.$item->getBasename());
}
}
}
/**
* Get the "to" location of the bundle's assets.
*
* @param string $bundle
* @return string
*/
protected function to($bundle)
{
return PUBLIC_PATH.'bundles'.DS.$bundle.DS;
}
/**
* Get the "from" location of the bundle's assets.
*
* @param string $bundle
* @return string
*/
protected function from($bundle)
{
return Bundle::path($bundle).'public';
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Bundle;
class Repository {
/**
* The root of the Laravel bundle API.
*
* @var string
*/
protected $api = 'http://bundles.laravel.com/api/';
/**
* Get the decoded JSON information for a bundle.
*
* @param string|int $bundle
* @return array
*/
public function get($bundle)
{
// The Bundle API will return a JSON string that we can decode and
// pass back to the consumer. The decoded array will contain info
// regarding the bundle's provider and location, as well as all
// of the bundle's dependencies.
$bundle = @file_get_contents($this->api.$bundle);
return json_decode($bundle, true);
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Migrate;
use Laravel\Database as DB;
class Database {
/**
* Log a migration in the migration table.
*
* @param string $bundle
* @param string $name
* @param int $batch
* @return void
*/
public function log($bundle, $name, $batch)
{
$this->table()->insert(compact('bundle', 'name', 'batch'));
}
/**
* Delete a row from the migration table.
*
* @param string $bundle
* @param string $name
* @return void
*/
public function delete($bundle, $name)
{
$this->table()->where_bundle_and_name($bundle, $name)->delete();
}
/**
* Return an array of the last batch of migrations.
*
* @return array
*/
public function last()
{
$table = $this->table();
// First we need to grab the last batch ID from the migration table,
// as this will allow us to grab the lastest batch of migrations
// that need to be run for a rollback command.
$id = $this->batch();
// Once we have the batch ID, we will pull all of the rows for that
// batch. Then we can feed the results into the resolve method to
// get the migration instances for the command.
return $table->where_batch($id)->order_by('name', 'desc')->get();
}
/**
* Get all of the migrations that have run for a bundle.
*
* @param string $bundle
* @return array
*/
public function ran($bundle)
{
return $this->table()->where_bundle($bundle)->lists('name');
}
/**
* Get the maximum batch ID from the migration table.
*
* @return int
*/
public function batch()
{
return $this->table()->max('batch');
}
/**
* Get a database query instance for the migration table.
*
* @return Query
*/
protected function table()
{
return DB::connection()->table('laravel_migrations');
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Migrate;
use Laravel\Str;
use Laravel\File;
use Laravel\Bundle;
use Laravel\CLI\Tasks\Task;
use Laravel\Database\Schema;
class Migrator extends Task {
/**
* The migration resolver instance.
*
* @var Resolver
*/
protected $resolver;
/**
* The migration database instance.
*
* @var Database
*/
protected $database;
/**
* Create a new instance of the Migrator CLI task.
*
* @param Resolver $resolver
* @param Database $database
* @return void
*/
public function __construct(Resolver $resolver, Database $database)
{
$this->resolver = $resolver;
$this->database = $database;
}
/**
* Run a database migration command.
*
* @param array $arguments
* @return void
*/
public function run($arguments = array())
{
// If no arguments were passed to the task, we will just migrate
// to the latest version across all bundles. Otherwise, we will
// parse the arguments to determine the bundle for which the
// database migrations should be run.
if (count($arguments) == 0)
{
$this->migrate();
}
else
{
$this->migrate(array_get($arguments, 0));
}
}
/**
* Run the outstanding migrations for a given bundle.
*
* @param string $bundle
* @param int $version
* @return void
*/
public function migrate($bundle = null, $version = null)
{
$migrations = $this->resolver->outstanding($bundle);
if (count($migrations) == 0)
{
echo "No outstanding migrations.";
return;
}
// We need to grab the latest batch ID and increment it
// by one. This allows us to group the migrations such
// that we can easily determine which migrations need
// to be rolled back for a given command.
$batch = $this->database->batch() + 1;
foreach ($migrations as $migration)
{
$migration['migration']->up();
echo 'Migrated: '.$this->display($migration).PHP_EOL;
// After running a migration, we log its execution in the
// migration table so that we can easily determine which
// migrations we will need to reverse on a rollback.
$this->database->log($migration['bundle'], $migration['name'], $batch);
}
}
/**
* Rollback the latest migration command.
*
* @param array $arguments
* @return bool
*/
public function rollback($arguments = array())
{
$migrations = $this->resolver->last();
if (count($migrations) == 0)
{
echo "Nothing to rollback.";
return false;
}
// The "last" method on the resolver returns an array of migrations,
// along with their bundles and names. We will iterate through each
// migration and run the "down" method, removing them from the
// database as we go.
foreach ($migrations as $migration)
{
$migration['migration']->down();
echo 'Rolled back: '.$this->display($migration).PHP_EOL;
// By only removing the migration after it has successfully rolled back,
// we can re-run the rollback command in the event of any errors with
// the migration. When we re-run, only the migrations that have not
// been rolled-back for the batch will still be in the database.
$this->database->delete($migration['bundle'], $migration['name']);
}
return true;
}
/**
* Rollback all of the executed migrations.
*
* @param array $arguments
* @return void
*/
public function reset($arguments = array())
{
while ($this->rollback()) {};
}
/**
* Install the database tables used by the migration system.
*
* @return void
*/
public function install()
{
Schema::table('laravel_migrations', function($table)
{
$table->create();
// Migrations can be run for a specific bundle, so we'll use
// the bundle name and string migration name as an unique ID
// for the migrations, allowing us to easily identify which
// migrations have been run for each bundle.
$table->string('bundle');
$table->string('name');
// When running a migration command, we will store a batch
// ID with each of the rows on the table. This will allow
// us to grab all of the migrations that were run for the
// last command when performing rollbacks.
$table->integer('batch');
$table->primary(array('bundle', 'name'));
});
echo "Migration table created successfully.";
}
/**
* Generate a new migration file.
*
* @param array $arguments
* @return void
*/
public function make($arguments = array())
{
if (count($arguments) == 0)
{
throw new \Exception("I need to know what to name the migration.");
}
list($bundle, $migration) = Bundle::parse($arguments[0]);
// The migration path is prefixed with the UNIX timestamp, which
// is a better way of ordering migrations than a simple integer
// incrementation, since developers may start working on the
// next migration at the same time unknowingly.
$date = date('Y_m_d').'_'.time();
$path = Bundle::path($bundle).'migrations/'.$date.'_'.$migration.EXT;
File::put($path, $this->stub($bundle, $migration));
echo "Great! New migration created!";
}
/**
* Get the stub migration with the proper class name.
*
* @param string $bundle
* @param string $migration
* @return string
*/
protected function stub($bundle, $migration)
{
$stub = File::get(SYS_PATH.'cli/tasks/migrate/stub'.EXT);
// The class name is formatted simialrly to tasks and controllers,
// where the bundle name is prefixed to the class if it is not in
// the default bundle. However, unlike tasks, there is nothing
// appended to the class name since they're already unique.
$class = Bundle::class_prefix($bundle).Str::classify($migration);
return str_replace('{{class}}', $class, $stub);
}
/**
* Get the migration bundle and name for display.
*
* @param array $migration
* @return string
*/
protected function display($migration)
{
return $migration['bundle'].'/'.$migration['name'];
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks\Migrate;
use Laravel\Bundle;
class Resolver {
/**
* The migration database instance.
*
* @var Database
*/
protected $database;
/**
* Create a new instance of the migration resolver.
*
* @param Database $datbase
* @return void
*/
public function __construct(Database $database)
{
$this->database = $database;
}
/**
* Resolve all of the outstanding migrations for a bundle.
*
* @param string $bundle
* @return array
*/
public function outstanding($bundle = null)
{
$migrations = array();
// If no bundle was given to the command, we'll grab every bundle for
// the application, including the "application" bundle, which is not
// returned by "all" method on the Bundle class.
if (is_null($bundle))
{
$bundles = array_merge(Bundle::all(), array('application'));
}
else
{
$bundles = array($bundle);
}
foreach ($bundles as $bundle)
{
// First we need to grab all of the migrations that have already
// run for this bundle, as well as all of the migration files
// for the bundle. Once we have these, we can determine which
// migrations are still outstanding.
$ran = $this->database->ran($bundle);
$files = $this->migrations($bundle);
// To find outstanding migrations, we will simply iterate over
// the migration files and add the files that do not exist in
// the array of ran migrations to the outstanding array.
foreach ($files as $key => $name)
{
if ( ! in_array($name, $ran))
{
$migrations[] = compact('bundle', 'name');
}
}
}
return $this->resolve($migrations);
}
/**
* Resolve an array of the last batch of migrations.
*
* @return array
*/
public function last()
{
return $this->resolve($this->database->last());
}
/**
* Resolve an array of migration instances.
*
* @param array $migrations
* @return array
*/
protected function resolve($migrations)
{
$instances = array();
foreach ($migrations as $migration)
{
$migration = (array) $migration;
// The migration array contains the bundle name, so we will get the
// path to the bundle's migrations and resolve an instance of the
// migration using the name.
$bundle = $migration['bundle'];
$path = Bundle::path($bundle).'migrations/';
// Migrations are not resolved through the auto-loader, so we will
// manually instantiate the migration class instances for each of
// the migration names we're given.
$name = $migration['name'];
require_once $path.$name.EXT;
// Since the migration name will begin with the numeric ID, we'll
// slice off the ID so we are left with the migration class name.
// The IDs are for sorting when resolving outstanding migrations.
//
// Migrations that exist within bundles other than the default
// will be prefixed with the bundle name to avoid any possible
// naming collisions with other bundle's migrations.
$prefix = Bundle::class_prefix($bundle);
$class = $prefix.substr($name, 22);
$migration = new $class;
// When adding to the array of instances, we will actually
// add the migration instance, the bundle, and the name.
// This allows the migrator to log the bundle and name
// when the migration is executed.
$instances[] = compact('bundle', 'name', 'migration');
}
return $instances;
}
/**
* Grab all of the migration filenames for a bundle.
*
* @param string $bundle
* @return array
*/
protected function migrations($bundle)
{
$files = glob(Bundle::path($bundle).'migrations/*_*'.EXT);
// Once we have the array of files in the migration directory,
// we'll take the basename of the file and remove the PHP file
// extension, which isn't needed.
foreach ($files as &$file)
{
$file = str_replace(EXT, '', basename($file));
}
// We'll also sort the files so that the earlier migrations
// will be at the front of the array and will be resolved
// first by this class' resolve method.
sort($files);
return $files;
}
}
\ No newline at end of file
<?php
class {{class}} {
/**
* Make changes to the database.
*
* @return void
*/
public function up()
{
//
}
/**
* Revert the changes to the database.
*
* @return void
*/
public function down()
{
//
}
}
\ No newline at end of file
<?php namespace Laravel\CLI\Tasks;
abstract class Task {}
\ No newline at end of file
<?php namespace Laravel; use Closure;
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
use Closure;
class Config {
/**
* All of the loaded configuration items.
*
* The configuration arrays are keyed by their owning file name.
* The configuration arrays are keyed by their owning bundle and file.
*
* @var array
*/
public static $items = array();
/**
* The paths to the configuration files.
* A cache of the loaded configuration items.
*
* @var array
*/
public static $paths = array(SYS_CONFIG_PATH, CONFIG_PATH, ENV_CONFIG_PATH);
protected static $cache = array();
/**
* Determine if a configuration item or file exists.
......@@ -25,7 +27,7 @@ class Config {
* // Determine if the "session" configuration file exists
* $exists = Config::has('session');
*
* // Determine if the "timezone" option exists in the "application" configuration
* // Determine if the "timezone" option exists in the configuration
* $exists = Config::has('application.timezone');
* </code>
*
......@@ -46,29 +48,38 @@ class Config {
* // Get the "session" configuration array
* $session = Config::get('session');
*
* // Get a configuration item from a bundle's configuration file
* $name = Config::get('admin::names.first');
*
* // Get the "timezone" option from the "application" configuration file
* $timezone = Config::get('application.timezone');
* </code>
*
* @param string $key
* @param string $default
* @return array
*/
public static function get($key, $default = null)
public static function get($key)
{
list($file, $key) = static::parse($key);
if ( ! static::load($file))
// First, we'll check the keyed cache of configuration items, as this will
// be the fastest method of retrieving the configuration option. After an
// item is retrieved, it is always stored in the cache by its key.
if (array_key_exists($key, static::$cache))
{
return ($default instanceof Closure) ? call_user_func($default) : $default;
return static::$cache[$key];
}
$items = static::$items[$file];
list($bundle, $file, $item) = static::parse($key);
if ( ! static::load($bundle, $file)) return;
$items = static::$items[$bundle][$file];
// If a specific configuration item was not requested, the key will be null,
// meaning we need to return the entire array of configuration item from the
// requested configuration file. Otherwise we can return the item.
return (is_null($key)) ? $items : Arr::get($items, $key, $default);
$value = (is_null($item)) ? $items : array_get($items, $item);
return static::$cache[$key] = $value;
}
/**
......@@ -78,6 +89,9 @@ class Config {
* // Set the "session" configuration array
* Config::set('session', $array);
*
* // Set a configuration option that belongs by a bundle
* Config::set('admin::names.first', 'Taylor');
*
* // Set the "timezone" option in the "application" configuration file
* Config::set('application.timezone', 'UTC');
* </code>
......@@ -88,61 +102,53 @@ class Config {
*/
public static function set($key, $value)
{
list($file, $key) = static::parse($key);
static::load($file);
if (is_null($key))
{
Arr::set(static::$items, $file, $value);
}
else
{
Arr::set(static::$items[$file], $key, $value);
}
static::$cache[$key] = $value;
}
/**
* Parse a configuration key and return its file and key segments.
* Parse a key and return its bundle, file, and key segments.
*
* The first segment of a configuration key represents the configuration
* file, while the remaining segments represent an item within that file.
* If no item segment is present, null will be returned for the item value
* indicating that the entire configuration array should be returned.
* Configuration items are named using the {bundle}::{file}.{item} convention.
*
* @param string $key
* @return array
*/
protected static function parse($key)
{
$segments = explode('.', $key);
$bundle = Bundle::name($key);
$segments = explode('.', Bundle::element($key));
// If there are not at least two segments in the array, it means that the
// developer is requesting the entire configuration array to be returned.
// If that is the case, we'll make the item field of the array "null".
if (count($segments) >= 2)
{
return array($segments[0], implode('.', array_slice($segments, 1)));
return array($bundle, $segments[0], implode('.', array_slice($segments, 1)));
}
else
{
return array($segments[0], null);
return array($bundle, $segments[0], null);
}
}
/**
* Load all of the configuration items from a configuration file.
*
* @param string $bundle
* @param string $file
* @return bool
*/
public static function load($file)
public static function load($bundle, $file)
{
if (isset(static::$items[$file])) return true;
if (isset(static::$items[$bundle][$file])) return true;
$config = array();
// Configuration files cascade. Typically, the system configuration array is
// loaded first, followed by the application array, providing the convenient
// cascading of configuration options from system to application.
foreach (static::$paths as $directory)
// Configuration files cascade. Typically, the bundle configuration array is
// loaded first, followed by the environment array, providing the convenient
// cascading of configuration options across environments.
foreach (static::paths($bundle) as $directory)
{
if ($directory !== '' and file_exists($path = $directory.$file.EXT))
{
......@@ -150,9 +156,37 @@ class Config {
}
}
if (count($config) > 0) static::$items[$file] = $config;
if (count($config) > 0)
{
static::$items[$bundle][$file] = $config;
}
return isset(static::$items[$bundle][$file]);
}
/**
* Get the array of configuration paths that should be searched for a bundle.
*
* @param string $bundle
* @return array
*/
protected static function paths($bundle)
{
$paths[] = Bundle::path($bundle).'config/';
// Configuration files can be made specific for a given environment. If an
// environment has been set, we will merge the environment configuration
// in last, so that it overrides all other options.
//
// This allows the developer to quickly and easily create configurations
// for various scenarios, such as local development and production,
// without constantly changing configuration files.
if (isset($_SERVER['LARAVEL_ENV']))
{
$paths[] = $paths[count($paths) - 1].$_SERVER['LARAVEL_ENV'].'/';
}
return isset(static::$items[$file]);
return $paths;
}
}
\ No newline at end of file
<?php
return array(
'/æ|ǽ/' => 'ae',
'/œ/' => 'oe',
'/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|А/' => 'A',
'/à|á|â|ã|ä|å|ǻ|ā|ă|ą|ǎ|ª|а/' => 'a',
'/Б/' => 'B',
'/б/' => 'b',
'/Ç|Ć|Ĉ|Ċ|Č|Ц/' => 'C',
'/ç|ć|ĉ|ċ|č|ц/' => 'c',
'/Ð|Ď|Đ|Д/' => 'Dj',
'/ð|ď|đ|д/' => 'dj',
'/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Е|Ё|Э/' => 'E',
'/è|é|ê|ë|ē|ĕ|ė|ę|ě|е|ё|э/' => 'e',
'/Ф/' => 'F',
'/ƒ|ф/' => 'f',
'/Ĝ|Ğ|Ġ|Ģ|Г/' => 'G',
'/ĝ|ğ|ġ|ģ|г/' => 'g',
'/Ĥ|Ħ|Х/' => 'H',
'/ĥ|ħ|х/' => 'h',
'/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|И/' => 'I',
'/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|и/' => 'i',
'/Ĵ|Й/' => 'J',
'/ĵ|й/' => 'j',
'/Ķ|К/' => 'K',
'/ķ|к/' => 'k',
'/Ĺ|Ļ|Ľ|Ŀ|Ł|Л/' => 'L',
'/ĺ|ļ|ľ|ŀ|ł|л/' => 'l',
'/М/' => 'M',
'/м/' => 'm',
'/Ñ|Ń|Ņ|Ň|Н/' => 'N',
'/ñ|ń|ņ|ň|ʼn|н/' => 'n',
'/Ö|Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|О/' => 'O',
'/ö|ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|о/' => 'o',
'/П/' => 'P',
'/п/' => 'p',
'/Ŕ|Ŗ|Ř|Р/' => 'R',
'/ŕ|ŗ|ř|р/' => 'r',
'/Ś|Ŝ|Ş|Š|С/' => 'S',
'/ś|ŝ|ş|š|ſ|с/' => 's',
'/Ţ|Ť|Ŧ|Т/' => 'T',
'/ţ|ť|ŧ|т/' => 't',
'/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|У/' => 'U',
'/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|у/' => 'u',
'/В/' => 'V',
'/в/' => 'v',
'/Ý|Ÿ|Ŷ|Ы/' => 'Y',
'/ý|ÿ|ŷ|ы/' => 'y',
'/Ŵ/' => 'W',
'/ŵ/' => 'w',
'/Ź|Ż|Ž|З/' => 'Z',
'/ź|ż|ž|з/' => 'z',
'/Æ|Ǽ/' => 'AE',
'/ß/'=> 'ss',
'/IJ/' => 'IJ',
'/ij/' => 'ij',
'/Œ/' => 'OE',
'/Ч/' => 'Ch',
'/ч/' => 'ch',
'/Ю/' => 'Ju',
'/ю/' => 'ju',
'/Я/' => 'Ja',
'/я/' => 'ja',
'/Ш/' => 'Sh',
'/ш/' => 'sh',
'/Щ/' => 'Shch',
'/щ/' => 'shch',
'/Ж/' => 'Zh',
'/ж/' => 'zh',
);
\ No newline at end of file
<?php namespace Laravel; use Closure;
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
if (trim(Config::$items['application']['key']) === '')
use Closure;
if (trim(Config::get('application.key')) === '')
{
throw new \LogicException('The cookie class may not be used without an application key.');
throw new \Exception('The cookie class may not be used without an application key.');
}
class Cookie {
......@@ -21,99 +23,106 @@ class Cookie {
/**
* Get the value of a cookie.
*
* <code>
* // Get the value of the "favorite" cookie
* $favorite = Cookie::get('favorite');
*
* // Get the value of a cookie or return a default value if it doesn't exist
* $favorite = Cookie::get('framework', 'Laravel');
* </code>
*
* @param string $name
* @param mixed $default
* @return string
*/
public static function get($name, $default = null)
{
$value = Arr::get($_COOKIE, $name);
$value = array_get($_COOKIE, $name);
if ( ! is_null($value))
if ( ! is_null($value) and isset($value[40]) and $value[40] == '~')
{
// All Laravel managed cookies are "signed" with a fingerprint hash.
// The hash serves to verify that the contents of the cookie have not
// been modified by the user. We can verify the integrity of the cookie
// by extracting the value and re-hashing it, then comparing that hash
// against the hash stored in the cookie.
if (isset($value[40]) and $value[40] === '~')
// The hash signature and the cookie value are separated by a tilde
// character for convenience. To separate the hash and the contents
// we can simply expode on that character.
//
// By re-feeding the cookie value into the "sign" method, we should
// be able to generate a hash that matches the one taken out of the
// cookie. If they don't match, the cookie value has been changed.
list($hash, $value) = explode('~', $value, 2);
if (static::hash($name, $value) === $hash)
{
list($hash, $value) = explode('~', $value, 2);
if (static::hash($name, $value) === $hash)
{
return $value;
}
return $value;
}
}
return ($default instanceof Closure) ? call_user_func($default) : $default;
return value($default);
}
/**
* Set a "permanent" cookie. The cookie will last for one year.
* Set the value of a cookie.
*
* If the response headers have already been sent, the cookie will not be set.
*
* <code>
* // Set the value of the "favorite" cookie
* Cookie::put('favorite', 'Laravel');
*
* // Set the value of the "favorite" cookie for twenty minutes
* Cookie::put('favorite', 'Laravel', 20);
* </code>
*
* @param string $name
* @param string $value
* @param int $minutes
* @param string $path
* @param string $domain
* @param bool $secure
* @param bool $http_only
* @return bool
*/
public static function forever($name, $value, $path = '/', $domain = null, $secure = false, $http_only = false)
public static function put($name, $value, $minutes = 0, $path = '/', $domain = null, $secure = false)
{
return static::put($name, $value, 525600, $path, $domain, $secure, $http_only);
if (headers_sent()) return false;
$time = ($minutes !== 0) ? time() + ($minutes * 60) : 0;
return setcookie($name, static::sign($name, $value), $time, $path, $domain, $secure);
}
/**
* Set the value of a cookie.
*
* If a negative number of minutes is specified, the cookie will be deleted.
* Set a "permanent" cookie. The cookie will last for one year.
*
* This method's signature is very similar to the PHP setcookie method.
* However, you simply need to pass the number of minutes for which you
* wish the cookie to be valid. No funky time calculation is required.
* <code>
* // Set a cookie that should last one year
* Cookie::forever('favorite', 'Blue');
* </code>
*
* @param string $name
* @param string $value
* @param int $minutes
* @param string $path
* @param string $domain
* @param bool $secure
* @param bool $http_only
* @return bool
*/
public static function put($name, $value, $minutes = 0, $path = '/', $domain = null, $secure = false, $http_only = false)
public static function forever($name, $value, $path = '/', $domain = null, $secure = false)
{
if (headers_sent()) return false;
$time = ($minutes !== 0) ? time() + ($minutes * 60) : 0;
$value = static::hash($name, $value).'~'.$value;
if ($minutes < 0)
{
unset($_COOKIE[$name]);
}
else
{
$_COOKIE[$name] = $value;
}
return setcookie($name, $value, $time, $path, $domain, $secure, $http_only);
return static::put($name, $value, 525600, $path, $domain, $secure);
}
/**
* Generate a cookie hash.
*
* Cookie salts are used to verify that the contents of the cookie have not
* been modified by the user, since they serve as a fingerprint of the cookie
* contents. The application key is used to salt the salts.
* Generate a cookie signature based on the contents.
*
* When the cookie is read using the "get" method, the value will be extracted
* from the cookie and hashed, if the hash in the cookie and the hashed value
* do not match, we know the cookie has been changed on the client.
* @param string $name
* @param string $value
* @return string
*/
protected static function sign($name, $value)
{
return static::hash($name, $value).'~'.$value;
}
/**
* Generate a cookie hash based on the contents.
*
* @param string $name
* @param string $value
......@@ -121,7 +130,7 @@ class Cookie {
*/
protected static function hash($name, $value)
{
return sha1($name.$value.Config::$items['application']['key']);
return sha1($name.$value.Config::get('application.key'));
}
/**
......@@ -131,12 +140,11 @@ class Cookie {
* @param string $path
* @param string $domain
* @param bool $secure
* @param bool $http_only
* @return bool
*/
public static function forget($name, $path = '/', $domain = null, $secure = false, $http_only = false)
public static function forget($name, $path = '/', $domain = null, $secure = false)
{
return static::put($name, null, -2000, $path, $domain, $secure, $http_only);
return static::put($name, null, -2000, $path, $domain, $secure);
}
}
\ No newline at end of file
......@@ -9,59 +9,22 @@
define('EXT', '.php');
define('CRLF', "\r\n");
define('BLADE_EXT', '.blade.php');
define('APP_PATH', realpath($application).'/');
define('PUBLIC_PATH', realpath($public).'/');
define('SYS_PATH', realpath($laravel).'/');
define('STORAGE_PATH', APP_PATH.'storage/');
define('CACHE_PATH', STORAGE_PATH.'cache/');
define('CONFIG_PATH', APP_PATH.'config/');
define('CONTROLLER_PATH', APP_PATH.'controllers/');
define('DATABASE_PATH', STORAGE_PATH.'database/');
define('LANG_PATH', APP_PATH.'language/');
define('LIBRARY_PATH', APP_PATH.'libraries/');
define('MODEL_PATH', APP_PATH.'models/');
define('ROUTE_PATH', APP_PATH.'routes/');
define('SESSION_PATH', STORAGE_PATH.'sessions/');
define('SYS_CONFIG_PATH', SYS_PATH.'config/');
define('VIEW_PATH', APP_PATH.'views/');
/**
* Define the Laravel environment configuration path. This path is used
* by the configuration class to load configuration options specific for
* the server environment, allowing the developer to conveniently change
* configuration options based on the application environment.
*
*/
$environment = '';
if (isset($_SERVER['LARAVEL_ENV']))
{
$environment = CONFIG_PATH.$_SERVER['LARAVEL_ENV'].'/';
}
define('ENV_CONFIG_PATH', $environment);
unset($application, $public, $laravel, $environment);
define('CACHE_PATH', STORAGE_PATH.'cache'.DS);
define('DATABASE_PATH', STORAGE_PATH.'database'.DS);
define('SESSION_PATH', STORAGE_PATH.'sessions'.DS);
define('DEFAULT_BUNDLE', 'application');
define('MB_STRING', (int) function_exists('mb_get_info'));
/**
* Require all of the classes that can't be loaded by the auto-loader.
* These are typically classes that the auto-loader itself relies upon
* to load classes, such as the array and configuration classes.
*/
require SYS_PATH.'arr'.EXT;
require SYS_PATH.'bundle'.EXT;
require SYS_PATH.'config'.EXT;
require SYS_PATH.'facades'.EXT;
require SYS_PATH.'helpers'.EXT;
require SYS_PATH.'autoloader'.EXT;
/**
* Load a few of the core configuration files that are loaded for every
* request to the application. It is quicker to load them manually each
* request rather than parse the keys for every request.
*/
Config::load('application');
Config::load('session');
Config::load('error');
/**
* Register the Autoloader's "load" method on the auto-loader stack.
* This method provides the lazy-loading of all class files, as well
......@@ -75,22 +38,27 @@ spl_autoload_register(array('Laravel\\Autoloader', 'load'));
* More mappings can also be registered by the developer as needed.
*/
Autoloader::$mappings = array(
'Laravel\\Arr' => SYS_PATH.'arr'.EXT,
'Laravel\\Asset' => SYS_PATH.'asset'.EXT,
'Laravel\\Auth' => SYS_PATH.'auth'.EXT,
'Laravel\\Asset' => SYS_PATH.'asset'.EXT,
'Laravel\\Benchmark' => SYS_PATH.'benchmark'.EXT,
'Laravel\\Blade' => SYS_PATH.'blade'.EXT,
'Laravel\\Bundle' => SYS_PATH.'bundle'.EXT,
'Laravel\\Cache' => SYS_PATH.'cache'.EXT,
'Laravel\\Config' => SYS_PATH.'config'.EXT,
'Laravel\\Cookie' => SYS_PATH.'cookie'.EXT,
'Laravel\\Crypter' => SYS_PATH.'crypter'.EXT,
'Laravel\\Database' => SYS_PATH.'database'.EXT,
'Laravel\\Error' => SYS_PATH.'error'.EXT,
'Laravel\\Event' => SYS_PATH.'event'.EXT,
'Laravel\\File' => SYS_PATH.'file'.EXT,
'Laravel\\Fluent' => SYS_PATH.'fluent'.EXT,
'Laravel\\Form' => SYS_PATH.'form'.EXT,
'Laravel\\Hash' => SYS_PATH.'hash'.EXT,
'Laravel\\HTML' => SYS_PATH.'html'.EXT,
'Laravel\\Inflector' => SYS_PATH.'inflector'.EXT,
'Laravel\\Input' => SYS_PATH.'input'.EXT,
'Laravel\\IoC' => SYS_PATH.'ioc'.EXT,
'Laravel\\Lang' => SYS_PATH.'lang'.EXT,
'Laravel\\Log' => SYS_PATH.'log'.EXT,
'Laravel\\Memcached' => SYS_PATH.'memcached'.EXT,
'Laravel\\Messages' => SYS_PATH.'messages'.EXT,
'Laravel\\Paginator' => SYS_PATH.'paginator'.EXT,
......@@ -99,40 +67,62 @@ Autoloader::$mappings = array(
'Laravel\\Request' => SYS_PATH.'request'.EXT,
'Laravel\\Response' => SYS_PATH.'response'.EXT,
'Laravel\\Section' => SYS_PATH.'section'.EXT,
'Laravel\\Session' => SYS_PATH.'session'.EXT,
'Laravel\\Str' => SYS_PATH.'str'.EXT,
'Laravel\\URI' => SYS_PATH.'uri'.EXT,
'Laravel\\URL' => SYS_PATH.'url'.EXT,
'Laravel\\Validator' => SYS_PATH.'validator'.EXT,
'Laravel\\View' => SYS_PATH.'view'.EXT,
'Laravel\\Cache\\Manager' => SYS_PATH.'cache/manager'.EXT,
'Laravel\\Cache\\Drivers\\APC' => SYS_PATH.'cache/drivers/apc'.EXT,
'Laravel\\Cache\\Drivers\\Driver' => SYS_PATH.'cache/drivers/driver'.EXT,
'Laravel\\Cache\\Drivers\\File' => SYS_PATH.'cache/drivers/file'.EXT,
'Laravel\\Cache\\Drivers\\Memcached' => SYS_PATH.'cache/drivers/memcached'.EXT,
'Laravel\\Cache\\Drivers\\Redis' => SYS_PATH.'cache/drivers/redis'.EXT,
'Laravel\\Cache\\Drivers\\Database' => SYS_PATH.'cache/drivers/database'.EXT,
'Laravel\\CLI\\Command' => SYS_PATH.'cli/command'.EXT,
'Laravel\\CLI\\Tasks\\Task' => SYS_PATH.'cli/tasks/task'.EXT,
'Laravel\\CLI\\Tasks\\Bundle\\Bundler' => SYS_PATH.'cli/tasks/bundle/bundler'.EXT,
'Laravel\\CLI\\Tasks\\Bundle\\Repository' => SYS_PATH.'cli/tasks/bundle/repository'.EXT,
'Laravel\\CLI\\Tasks\\Bundle\\Publisher' => SYS_PATH.'cli/tasks/bundle/publisher'.EXT,
'Laravel\\CLI\\Tasks\\Bundle\\Providers\\Provider' => SYS_PATH.'cli/tasks/bundle/providers/provider'.EXT,
'Laravel\\CLI\\Tasks\\Bundle\\Providers\\Github' => SYS_PATH.'cli/tasks/bundle/providers/github'.EXT,
'Laravel\\CLI\\Tasks\\Migrate\\Migrator' => SYS_PATH.'cli/tasks/migrate/migrator'.EXT,
'Laravel\\CLI\\Tasks\\Migrate\\Resolver' => SYS_PATH.'cli/tasks/migrate/resolver'.EXT,
'Laravel\\CLI\\Tasks\\Migrate\\Database' => SYS_PATH.'cli/tasks/migrate/database'.EXT,
'Laravel\\Database\\Connection' => SYS_PATH.'database/connection'.EXT,
'Laravel\\Database\\Expression' => SYS_PATH.'database/expression'.EXT,
'Laravel\\Database\\Manager' => SYS_PATH.'database/manager'.EXT,
'Laravel\\Database\\Query' => SYS_PATH.'database/query'.EXT,
'Laravel\\Database\\Schema' => SYS_PATH.'database/schema'.EXT,
'Laravel\\Database\\Grammar' => SYS_PATH.'database/grammar'.EXT,
'Laravel\\Database\\Connectors\\Connector' => SYS_PATH.'database/connectors/connector'.EXT,
'Laravel\\Database\\Connectors\\MySQL' => SYS_PATH.'database/connectors/mysql'.EXT,
'Laravel\\Database\\Connectors\\Postgres' => SYS_PATH.'database/connectors/postgres'.EXT,
'Laravel\\Database\\Connectors\\SQLite' => SYS_PATH.'database/connectors/sqlite'.EXT,
'Laravel\\Database\\Eloquent\\Hydrator' => SYS_PATH.'database/eloquent/hydrator'.EXT,
'Laravel\\Database\\Eloquent\\Model' => SYS_PATH.'database/eloquent/model'.EXT,
'Laravel\\Database\\Grammars\\Grammar' => SYS_PATH.'database/grammars/grammar'.EXT,
'Laravel\\Database\\Grammars\\MySQL' => SYS_PATH.'database/grammars/mysql'.EXT,
'Laravel\\Database\\Connectors\\SQLServer' => SYS_PATH.'database/connectors/sqlserver'.EXT,
'Laravel\\Database\\Query\\Grammars\\Grammar' => SYS_PATH.'database/query/grammars/grammar'.EXT,
'Laravel\\Database\\Query\\Grammars\\MySQL' => SYS_PATH.'database/query/grammars/mysql'.EXT,
'Laravel\\Database\\Query\\Grammars\\SQLServer' => SYS_PATH.'database/query/grammars/sqlserver'.EXT,
'Laravel\\Database\\Schema\\Table' => SYS_PATH.'database/schema/table'.EXT,
'Laravel\\Database\\Schema\\Grammars\\Grammar' => SYS_PATH.'database/schema/grammars/grammar'.EXT,
'Laravel\\Database\\Schema\\Grammars\\MySQL' => SYS_PATH.'database/schema/grammars/mysql'.EXT,
'Laravel\\Database\\Schema\\Grammars\\Postgres' => SYS_PATH.'database/schema/grammars/postgres'.EXT,
'Laravel\\Database\\Schema\\Grammars\\SQLServer' => SYS_PATH.'database/schema/grammars/sqlserver'.EXT,
'Laravel\\Database\\Schema\\Grammars\\SQLite' => SYS_PATH.'database/schema/grammars/sqlite'.EXT,
'Laravel\\Routing\\Controller' => SYS_PATH.'routing/controller'.EXT,
'Laravel\\Routing\\Filter' => SYS_PATH.'routing/filter'.EXT,
'Laravel\\Routing\\Loader' => SYS_PATH.'routing/loader'.EXT,
'Laravel\\Routing\\Filter_Collection' => SYS_PATH.'routing/filter'.EXT,
'Laravel\\Routing\\Route' => SYS_PATH.'routing/route'.EXT,
'Laravel\\Routing\\Router' => SYS_PATH.'routing/router'.EXT,
'Laravel\\Session\\Payload' => SYS_PATH.'session/payload'.EXT,
'Laravel\\Session\\Drivers\\APC' => SYS_PATH.'session/drivers/apc'.EXT,
'Laravel\\Session\\Drivers\\Cookie' => SYS_PATH.'session/drivers/cookie'.EXT,
'Laravel\\Session\\Drivers\\Database' => SYS_PATH.'session/drivers/database'.EXT,
'Laravel\\Session\\Drivers\\Driver' => SYS_PATH.'session/drivers/driver'.EXT,
'Laravel\\Session\\Drivers\\Factory' => SYS_PATH.'session/drivers/factory'.EXT,
'Laravel\\Session\\Drivers\\File' => SYS_PATH.'session/drivers/file'.EXT,
'Laravel\\Session\\Drivers\\Memcached' => SYS_PATH.'session/drivers/memcached'.EXT,
'Laravel\\Session\\Drivers\\Redis' => SYS_PATH.'session/drivers/redis'.EXT,
......@@ -140,16 +130,9 @@ Autoloader::$mappings = array(
);
/**
* Register the default timezone for the application. This will be
* the default timezone used by all date / timezone functions in
* the entire application.
*/
date_default_timezone_set(Config::$items['application']['timezone']);
/**
* Define a few global, convenient functions. These functions
* provide short-cuts for things like the retrieval of language
* lines and HTML::entities. They just make our lives as devs a
* little sweeter and more enjoyable.
* Register all of the core class aliases. These aliases provide a
* convenient way of working with the Laravel core classes without
* having to worry about the namespacing. The developer is also
* free to remove aliases when they extend core classes.
*/
require SYS_PATH.'helpers'.EXT;
\ No newline at end of file
Autoloader::$aliases = Config::get('application.aliases');
\ No newline at end of file
<?php namespace Laravel;
<?php namespace Laravel; defined('APP_PATH') or die('No direct script access.');
if (trim(Config::$items['application']['key']) === '')
if (trim(Config::get('application.key')) === '')
{
throw new \LogicException('The encryption class may not be used without an application key.');
throw new \Exception('The Crypter class may not be used without an application key.');
}
class Crypter {
......@@ -12,28 +12,19 @@ class Crypter {
*
* @var string
*/
protected static $cipher = MCRYPT_RIJNDAEL_256;
public static $cipher = MCRYPT_RIJNDAEL_256;
/**
* The encryption mode.
*
* @var string
*/
protected static $mode = MCRYPT_MODE_CBC;
public static $mode = MCRYPT_MODE_CBC;
/**
* Encrypt a string using Mcrypt.
*
* The given string will be encrypted using AES-256 encryption for a high
* degree of security. The returned string will also be base64 encoded.
*
* Mcrypt must be installed on your machine before using this method, and
* an application key must be specified in the application configuration.
*
* <code>
* // Encrypt a string using the Mcrypt PHP extension
* $encrypted = Crypter::encrpt('secret');
* </code>
* The string will be encrypted using the AES-256 scheme and will be base64 encoded.
*
* @param string $value
* @return string
......@@ -50,26 +41,27 @@ class Crypter {
/**
* Decrypt a string using Mcrypt.
*
* The given encrypted value must have been encrypted using Laravel and
* the application key specified in the application configuration file.
*
* Mcrypt must be installed on your machine before using this method.
*
* @param string $value
* @return string
*/
public static function decrypt($value)
{
if (($value = base64_decode($value)) === false)
{
throw new \InvalidArgumentException('Input value is not valid base64 data.');
}
$value = base64_decode($value);
// To decrypt the value, we first need to extract the input vector and
// the encrypted value. The input vector size varies across different
// encryption ciphers and modes, so we will get the correct size for
// the cipher and mode being used by the class.
$iv = substr($value, 0, static::iv_size());
$value = substr($value, static::iv_size());
return rtrim(mcrypt_decrypt(static::$cipher, static::key(), $value, static::$mode, $iv), "\0");
// Once we have the input vector and the value, we can give them both
// to Mcrypt for decryption. The value is sometimes padded with \0,
// so we will trim all of the padding characters from the string.
$key = static::key();
return rtrim(mcrypt_decrypt(static::$cipher, $key, $value, static::$mode, $iv), "\0");
}
/**
......@@ -89,7 +81,7 @@ class Crypter {
*/
protected static function key()
{
return Config::$items['application']['key'];
return Config::get('application.key');
}
}
\ No newline at end of file
<?php namespace Laravel\Database;
<?php namespace Laravel;
use Laravel\IoC;
use Laravel\Config;
use Laravel\Database\Expression;
use Laravel\Database\Connection;
class Manager {
class Database {
/**
* The established database connections.
*
* @var array
*/
protected static $connections = array();
public static $connections = array();
/**
* Get a database connection.
......@@ -38,7 +38,7 @@ class Manager {
if (is_null($config))
{
throw new \OutOfBoundsException("Connection is not defined for [$connection].");
throw new \Exception("Database connection is not defined for [$connection].");
}
static::$connections[$connection] = new Connection(static::connect($config), $config);
......@@ -55,26 +55,12 @@ class Manager {
*/
protected static function connect($config)
{
// We allow the developer to place a "connector" option in the database
// configuration, which should have a Closure value. If the connector
// is present, we will use the Closure to retrieve the PDO connection
// to the database. This allows the flexiblity to connect to database
// systems that are not officially supported by the the framework.
if (isset($config['connector']))
{
return call_user_func($config['connector'], $config);
}
return static::connector($config['driver'])->connect($config);
}
/**
* Create a new database connector instance.
*
* The database connectors are responsible for simply establishing a PDO
* database connection given a configuration. This allows us to easily
* drop in support for new database systems by writing a connector.
*
* @param string $driver
* @return Connector
*/
......@@ -83,16 +69,19 @@ class Manager {
switch ($driver)
{
case 'sqlite':
return new Connectors\SQLite(DATABASE_PATH);
return new Database\Connectors\SQLite;
case 'mysql':
return new Connectors\MySQL;
return new Database\Connectors\MySQL;
case 'pgsql':
return new Connectors\Postgres;
return new Database\Connectors\Postgres;
case 'sqlsrv':
return new Database\Connectors\SQLServer;
default:
throw new \DomainException("Database driver [$driver] is not supported.");
throw new \Exception("Database driver [$driver] is not supported.");
}
}
......@@ -124,7 +113,13 @@ class Manager {
/**
* Magic Method for calling methods on the default database connection.
*
* This provides a convenient API for querying or examining the default database connection.
* <code>
* // Get the driver name for the default database connection
* $driver = DB::driver();
*
* // Execute a fluent query on the default database connection
* $users = DB::table('users')->get();
* </code>
*/
public static function __callStatic($method, $parameters)
{
......
......@@ -9,13 +9,6 @@ class Connection {
*/
public $pdo;
/**
* All of the queries that have been executed on the connection.
*
* @var array
*/
public $queries = array();
/**
* The connection configuration array.
*
......@@ -30,6 +23,13 @@ class Connection {
*/
protected $grammar;
/**
* All of the queries that have been executed on all connections.
*
* @var array
*/
public static $queries = array();
/**
* Create a new database connection instance.
*
......@@ -46,6 +46,14 @@ class Connection {
/**
* Begin a fluent query against a table.
*
* <code>
* // Start a fluent query against the "users" table
* $query = DB::connection()->table('users');
*
* // Start a fluent query against the "users" table and get all the users
* $users = DB::connection()->table('users')->get();
* </code>
*
* @param string $table
* @return Query
*/
......@@ -57,27 +65,22 @@ class Connection {
/**
* Create a new query grammar for the connection.
*
* Query grammars allow support for new database systems to be added quickly
* and easily. Since the responsibility of the query generation is delegated
* to the grammar classes, it is simple to override only the methods with
* SQL syntax that differs from the default implementation.
*
* @return Grammars\Grammar
* @return Query\Grammars\Grammar
*/
protected function grammar()
{
if (isset($this->grammar)) return $this->grammar;
// We allow the developer to hard-code a grammar for the connection. This really
// has no use yet; however, if database systems that can use multiple grammars
// like ODBC are added in the future, this will be needed.
switch (isset($this->config['grammar']) ? $this->config['grammar'] : $this->driver())
{
case 'mysql':
return $this->grammar = new Grammars\MySQL;
return $this->grammar = new Query\Grammars\MySQL;
case 'sqlsrv':
return $this->grammar = new Query\Grammars\SQLServer;
default:
return $this->grammar = new Grammars\Grammar;
return $this->grammar = new Query\Grammars\Grammar;
}
}
......@@ -98,9 +101,9 @@ class Connection {
*/
public function only($sql, $bindings = array())
{
$result = (array) $this->first($sql, $bindings);
$results = (array) $this->first($sql, $bindings);
return reset($result);
return reset($results);
}
/**
......@@ -127,67 +130,124 @@ class Connection {
}
/**
* Execute a SQL query against the connection.
* Execute a SQL query and return an array of StdClass objects.
*
* The method returns the following based on query type:
* @param string $sql
* @param array $bindings
* @return array
*/
public function query($sql, $bindings = array())
{
list($statement, $result) = $this->execute($sql, $bindings);
return $statement->fetchAll(PDO::FETCH_CLASS, 'stdClass');
}
/**
* Execute a SQL UPDATE query and return the affected row count.
*
* SELECT -> Array of stdClasses
* UPDATE -> Number of rows affected.
* DELETE -> Number of Rows affected.
* ELSE -> Boolean true / false depending on success.
* @param string $sql
* @param array $bindings
* @return int
*/
public function update($sql, $bindings = array())
{
list($statement, $result) = $this->execute($sql, $bindings);
return $statement->rowCount();
}
/**
* Execute a SQL DELETE query and return the affected row count.
*
* <code>
* // Execute a query against the database connection
* $users = DB::connection()->query('select * from users');
* @param string $sql
* @param array $bindings
* @return int
*/
public function delete($sql, $bindings = array())
{
list($statement, $result) = $this->execute($sql, $bindings);
return $statement->rowCount();
}
/**
* Execute an SQL query and return the boolean result of the PDO statement.
*
* // Execute a query with bound parameters
* $user = DB::connection()->query('select * from users where id = ?', array($id));
* </code>
* @param string $sql
* @param array $bindings
* @return bool
*/
public function statement($sql, $bindings = array())
{
list($statement, $result) = $this->execute($sql, $bindings);
return $result;
}
/**
* Execute a SQL query against the connection.
*
* The PDO statement and boolean result will be return in an array.
*
* @param string $sql
* @param array $bindings
* @return mixed
* @return array
*/
public function query($sql, $bindings = array())
protected function execute($sql, $bindings = array())
{
// Since expressions are injected into the query as raw strings, we need
// to remove them from the array of bindings. They are not truly bound
// to the PDO statement as named parameters.
foreach ($bindings as $key => $value)
// Since expressions are injected into the query as strings, we need to
// remove them from the array of bindings. After we have removed them,
// we'll reset the array so there aren't gaps in the keys.
$bindings = array_values(array_filter($bindings, function($binding)
{
if ($value instanceof Expression) unset($bindings[$key]);
}
$bindings = array_values($bindings);
return ! $binding instanceof Expression;
}));
$sql = $this->transform($sql, $bindings);
$this->queries[] = compact('sql', 'bindings');
$statement = $this->pdo->prepare($sql);
return $this->execute($this->pdo->prepare($sql), $bindings);
// Every query is timed so that we can log the executinon time along
// with the query SQL and array of bindings. This should be make it
// convenient for the developer to profile the application's query
// performance to diagnose bottlenecks.
$time = microtime(true);
$result = $statement->execute($bindings);
$time = number_format((microtime(true) - $time) * 1000, 2);
// Once we have execute the query, we log the SQL, bindings, and
// execution time in a static array that is accessed by all of
// the connections used by the application. This allows us to
// review all of the executed SQL.
static::$queries[] = compact('sql', 'bindings', 'time');
return array($statement, $result);
}
/**
* Transform an SQL query into an executable query.
*
* Laravel provides a convenient short-cut when writing raw queries for
* handling cumbersome "where in" statements. This method will transform
* those segments into their full SQL counterparts.
*
* @param string $sql
* @param array $bindings
* @return string
*/
protected function transform($sql, $bindings)
{
// Laravel provides an easy short-cut notation for writing raw
// WHERE IN statements. If (...) is in the query, it will be
// replaced with the correct number of parameters based on
// the bindings for the query.
if (strpos($sql, '(...)') !== false)
{
for ($i = 0; $i < count($bindings); $i++)
{
// If the binding is an array, we can assume it is being used to fill
// a "where in" condition, so we will replace the next place-holder
// in the query with the correct number of parameters based on the
// number of elements in this binding.
// If the binding is an array, we can assume it is being used
// to fill a "where in" condition, so we'll replace the next
// place-holder in the SQL query with the correct number of
// parameters based on the elements in the binding.
if (is_array($bindings[$i]))
{
$parameters = implode(', ', array_fill(0, count($bindings[$i]), '?'));
......@@ -200,33 +260,6 @@ class Connection {
return trim($sql);
}
/**
* Execute a prepared PDO statement and return the appropriate results.
*
* @param PDOStatement $statement
* @param array $bindings
* @return mixed
*/
protected function execute(PDOStatement $statement, $bindings)
{
$result = $statement->execute($bindings);
$sql = strtoupper($statement->queryString);
if (strpos($sql, 'SELECT') === 0)
{
return $statement->fetchAll(PDO::FETCH_CLASS, 'stdClass');
}
elseif (strpos($sql, 'UPDATE') === 0 or strpos($sql, 'DELETE') === 0)
{
return $statement->rowCount();
}
else
{
return $result;
}
}
/**
* Get the driver name for the database connection.
*
......
......@@ -16,7 +16,7 @@ abstract class Connector {
);
/**
* Establish a PDO database connection for a given database configuration.
* Establish a PDO database connection.
*
* @param array $config
* @return PDO
......@@ -24,7 +24,7 @@ abstract class Connector {
abstract public function connect($config);
/**
* Get the PDO connection options for a given database configuration.
* Get the PDO connection options for the configuration.
*
* Developer specified options will override the default connection options.
*
......
......@@ -3,7 +3,7 @@
class MySQL extends Connector {
/**
* Establish a PDO database connection for a given database configuration.
* Establish a PDO database connection.
*
* @param array $config
* @return PDO
......@@ -15,7 +15,7 @@ class MySQL extends Connector {
// Format the initial MySQL PDO connection string. These options are required
// for every MySQL connection that is established. The connection strings
// have the following convention: "mysql:host=hostname;dbname=database"
$dsn = sprintf('%s:host=%s;dbname=%s', $driver, $host, $database);
$dsn = "mysql:host={$host};dbname={$database}";
// Check for any optional MySQL PDO options. These options are not required
// to establish a PDO connection; however, may be needed in certain server
......
......@@ -3,7 +3,7 @@
class Postgres extends Connector {
/**
* Establish a PDO database connection for a given database configuration.
* Establish a PDO database connection.
*
* @param array $config
* @return PDO
......@@ -15,7 +15,7 @@ class Postgres extends Connector {
// Format the initial Postgres PDO connection string. These options are required
// for every Postgres connection that is established. The connection strings
// have the following convention: "pgsql:host=hostname;dbname=database"
$dsn = sprintf('%s:host=%s;dbname=%s', $driver, $host, $database);
$dsn = "pgsql:host={$host};dbname={$database}";
// Check for any optional Postgres PDO options. These options are not required
// to establish a PDO connection; however, may be needed in certain server
......
......@@ -3,25 +3,7 @@
class SQLite extends Connector {
/**
* The path to the SQLite databases for the application.
*
* @var string
*/
protected $path;
/**
* Create a new SQLite database connector instance.
*
* @param string $path
* @return void
*/
public function __construct($path)
{
$this->path = $path;
}
/**
* Establish a PDO database connection for a given database configuration.
* Establish a PDO database connection.
*
* @param array $config
* @return PDO
......@@ -32,27 +14,19 @@ class SQLite extends Connector {
// SQLite provides supported for "in-memory" databases, which exist only for the
// lifetime of the request. Any given in-memory database may only have one PDO
// connection open to it at a time. Generally, these databases are use for
// connection open to it at a time. Generally, these databases are used for
// testing and development purposes, not in production scenarios.
if ($config['database'] == ':memory:')
{
return new PDO('sqlite::memory:', null, null, $options);
}
// First, we will check for the database in the default storage directory for the
// application. If we don't find the database there, we will assume the database
// name is actually a full qualified path to the database on disk and attempt
// to load it. If we still can't find it, we'll bail out.
elseif (file_exists($path = $this->path.$config['database'].'.sqlite'))
if (file_exists($path = DATABASE_PATH.$config['database'].'.sqlite'))
{
return new PDO('sqlite:'.$path, null, null, $options);
}
elseif (file_exists($config['database']))
{
return new PDO('sqlite:'.$config['database'], null, null, $options);
}
throw new \OutOfBoundsException("SQLite database [{$config['database']}] could not be found.");
throw new \Exception("SQLite database [{$config['database']}] could not be found.");
}
}
<?php namespace Laravel\Database\Connectors; use PDO;
class SQLServer extends Connector {
/**
* The PDO connection options.
*
* @var array
*/
protected $options = array(
PDO::ATTR_CASE => PDO::CASE_LOWER,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
);
/**
* Establish a PDO database connection.
*
* @param array $config
* @return PDO
*/
public function connect($config)
{
extract($config);
// Format the SQL Server connection string. This connection string format can
// also be used to connect to Azure SQL Server databases. The port is defined
// directly after the server name, so we'll create that and then create the
// final DSN string to pass to PDO.
$port = (isset($port)) ? ','.$port : '';
$dsn = "sqlsrv:Server={$host}{$port};Database={$database}";
return new PDO($dsn, $username, $password, $this->options($config));
}
}
\ No newline at end of file
<?php namespace Laravel\Database\Eloquent;
class Hydrator {
/**
* Load the array of hydrated models and their eager relationships.
*
* @param Model $eloquent
* @return array
*/
public static function hydrate($eloquent)
{
$results = static::base(get_class($eloquent), $eloquent->query->get());
if (count($results) > 0)
{
foreach ($eloquent->includes as $include)
{
if ( ! method_exists($eloquent, $include))
{
throw new \LogicException("Attempting to eager load [$include], but the relationship is not defined.");
}
static::eagerly($eloquent, $results, $include);
}
}
return $results;
}
/**
* Hydrate the base models for a query.
*
* The resulting model array is keyed by the primary keys of the models.
* This allows the models to easily be matched to their children.
*
* @param string $class
* @param array $results
* @return array
*/
private static function base($class, $results)
{
$models = array();
foreach ($results as $result)
{
$model = new $class;
$model->attributes = (array) $result;
$model->exists = true;
if (isset($model->attributes['id']))
{
$models[$model->id] = $model;
}
else
{
$models[] = $model;
}
}
return $models;
}
/**
* Eagerly load a relationship.
*
* @param object $eloquent
* @param array $parents
* @param string $include
* @return void
*/
private static function eagerly($eloquent, &$parents, $include)
{
// We temporarily spoof the query attributes to allow the query to be fetched without
// any problems, since the belongs_to method actually gets the related attribute.
$first = reset($parents);
$eloquent->attributes = $first->attributes;
$relationship = $eloquent->$include();
$eloquent->attributes = array();
// Reset the WHERE clause and bindings on the query. We'll add our own WHERE clause soon.
// This will allow us to load a range of related models instead of only one.
$relationship->query->reset_where();
// Initialize the relationship attribute on the parents. As expected, "many" relationships
// are initialized to an array and "one" relationships are initialized to null.
foreach ($parents as &$parent)
{
$parent->ignore[$include] = (in_array($eloquent->relating, array('has_many', 'has_and_belongs_to_many'))) ? array() : null;
}
if (in_array($relating = $eloquent->relating, array('has_one', 'has_many', 'belongs_to')))
{
return static::$relating($relationship, $parents, $eloquent->relating_key, $include);
}
else
{
static::has_and_belongs_to_many($relationship, $parents, $eloquent->relating_key, $eloquent->relating_table, $include);
}
}
/**
* Eagerly load a 1:1 relationship.
*
* @param object $relationship
* @param array $parents
* @param string $relating_key
* @param string $relating
* @param string $include
* @return void
*/
private static function has_one($relationship, &$parents, $relating_key, $include)
{
foreach ($relationship->where_in($relating_key, array_keys($parents))->get() as $key => $child)
{
$parents[$child->$relating_key]->ignore[$include] = $child;
}
}
/**
* Eagerly load a 1:* relationship.
*
* @param object $relationship
* @param array $parents
* @param string $relating_key
* @param string $relating
* @param string $include
* @return void
*/
private static function has_many($relationship, &$parents, $relating_key, $include)
{
foreach ($relationship->where_in($relating_key, array_keys($parents))->get() as $key => $child)
{
$parents[$child->$relating_key]->ignore[$include][$child->id] = $child;
}
}
/**
* Eagerly load a 1:1 belonging relationship.
*
* @param object $relationship
* @param array $parents
* @param string $relating_key
* @param string $include
* @return void
*/
private static function belongs_to($relationship, &$parents, $relating_key, $include)
{
$keys = array();
foreach ($parents as &$parent)
{
$keys[] = $parent->$relating_key;
}
$children = $relationship->where_in('id', array_unique($keys))->get();
foreach ($parents as &$parent)
{
if (array_key_exists($parent->$relating_key, $children))
{
$parent->ignore[$include] = $children[$parent->$relating_key];
}
}
}
/**
* Eagerly load a many-to-many relationship.
*
* @param object $relationship
* @param array $parents
* @param string $relating_key
* @param string $relating_table
* @param string $include
*
* @return void
*/
private static function has_and_belongs_to_many($relationship, &$parents, $relating_key, $relating_table, $include)
{
// The model "has and belongs to many" method sets the SELECT clause; however, we need
// to clear it here since we will be adding the foreign key to the select.
$relationship->query->select = null;
$relationship->query->where_in($relating_table.'.'.$relating_key, array_keys($parents));
// The foreign key is added to the select to allow us to easily match the models back to their parents.
// Otherwise, there would be no apparent connection between the models to allow us to match them.
$children = $relationship->query->get(array(Model::table(get_class($relationship)).'.*', $relating_table.'.'.$relating_key));
$class = get_class($relationship);
foreach ($children as $child)
{
$related = new $class;
$related->attributes = (array) $child;
$related->exists = true;
// Remove the foreign key since it was only added to the query to help match the models.
unset($related->attributes[$relating_key]);
$parents[$child->$relating_key]->ignore[$include][$child->id] = $related;
}
}
}
This diff is collapsed.
<?php namespace Laravel\Database;
abstract class Grammar {
/**
* The keyword identifier for the database system.
*
* @var string
*/
protected $wrapper = '"%s"';
/**
* Wrap a value in keyword identifiers.
*
* @param string $value
* @return string
*/
public function wrap($value)
{
// If the value being wrapped contains a column alias, we need to
// wrap it a little differently as each segment must be wrapped
// and not the entire string. We'll split the value on the "as"
// joiner to extract the column and the alias.
if (strpos(strtolower($value), ' as ') !== false)
{
$segments = explode(' ', $value);
return $this->wrap($segments[0]).' AS '.$this->wrap($segments[2]);
}
// Expressions should be injected into the query as raw strings,
// so we do not want to wrap them in any way. We'll just return
// the string value from the expression to be included.
if ($value instanceof Expression) return $value->get();
// Since columns may be prefixed with their corresponding table
// name so as to not make them ambiguous, we will need to wrap
// the table and the column in keyword identifiers.
foreach (explode('.', $value) as $segment)
{
if ($segment == '*')
{
$wrapped[] = $segment;
}
else
{
$wrapped[] = sprintf($this->wrapper, $segment);
}
}
return implode('.', $wrapped);
}
/**
* Create query parameters from an array of values.
*
* <code>
* Returns "?, ?, ?", which may be used as PDO place-holders
* $parameters = $grammar->parameterize(array(1, 2, 3));
*
* // Returns "?, "Taylor"" since an expression is used
* $parameters = $grammar->parameterize(array(1, DB::raw('Taylor')));
* </code>
*
* @param array $values
* @return string
*/
final public function parameterize($values)
{
return implode(', ', array_map(array($this, 'parameter'), $values));
}
/**
* Get the appropriate query parameter string for a value.
*
* <code>
* // Returns a "?" PDO place-holder
* $value = $grammar->parameter('Taylor Otwell');
*
* // Returns "Taylor Otwell" as the raw value of the expression
* $value = $grammar->parameter(DB::raw('Taylor Otwell'));
* </code>
*
* @param mixed $value
* @return string
*/
final public function parameter($value)
{
return ($value instanceof Expression) ? $value->get() : '?';
}
/**
* Create a comma-delimited list of wrapped column names.
*
* <code>
* // Returns ""Taylor", "Otwell"" when the identifier is quotes
* $columns = $grammar->columnize(array('Taylor', 'Otwell'));
* </code>
*
* @param array $columns
* @return string
*/
final public function columnize($columns)
{
return implode(', ', array_map(array($this, 'wrap'), $columns));
}
}
\ No newline at end of file
This diff is collapsed.
<?php namespace Laravel\Database\Grammars;
<?php namespace Laravel\Database\Query\Grammars;
class MySQL extends Grammar {
......@@ -7,6 +7,6 @@ class MySQL extends Grammar {
*
* @var string
*/
protected $wrapper = '`';
protected $wrapper = '`%s`';
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment