Commit baf46fa8 authored by Taylor Otwell's avatar Taylor Otwell

Merge branch 'develop'

parents 50c37f1d 7d50f5f9
## Authentication Configuration
Most interactive applications have the ability for users to login and logout. Obvious, right? Laravel provides a simple class to help you validate user credentials and retrieve information about the current user of your application.
The quickest way to get started is to create an [Eloquent User model](/docs/database/eloquent) in your **application/models** directory:
class User extends Eloquent {}
Next, you will need to define **email** and **password** columns on your user database table. The password column should hold 60 alpha-numeric characters. The Auth class **requires** that all passwords be hashed and salted.
> **Note:** The password column on your user table must really be named "password".
Great job! You're ready to start using the Auth class. However, there are more advanced configuration options available if you wish to use them.
Let's dig into the **application/config/auth.php** file. In this file you will find two closures: **by\_id** and **by\_username**:
'by_id' => function($id)
{
return User::find($id);
}
The **by_id** function is called when the Auth class needs to retrieve a user by their primary key. As you can see, the default implementation of this function uses an "User" Eloquent model to retrieve the user by ID. However, if you are not using Eloquent, you are free to modify this function to meet the needs of your application.
'by_username' => function($username)
{
return User::where('email', '=', $username)->first();
}
The **by_username** function is called when the Auth class needs to retrieve a user by their username, such as when using the **login** method. The default implementation of this function uses an "User" Eloquent model to retrieve the user by e-mail address. However, if you are not using Eloquent or do not wish to use e-mail addresses as usernames, you are free to modify this function as you wish as long as you return an object with **password** and **id** properties.
\ No newline at end of file
## Authentication Usage
- [Salting & Hashing](#hash)
- [Logging In](#login)
- [Protecting Routes](#filter)
- [Retrieving The Logged In User](#user)
- [Logging Out](#logout)
> **Note:** Before using the Auth class, you must [specify a session driver](/docs/session/config).
<a name="hash"></a>
### Salting & Hashing
If you are using the Auth class, Laravel requires all passwords to be hashed and salted. Web development must be done responsibly. Salted, hashed passwords make a rainbow table attack against your user's passwords impractical.
Don't worry, salting and hashing passwords is easy using the **Hash** class. The Hash class provides a simple way to hash passwords using the **bcrypt** hashing algorithm. Check out this example:
$password = Hash::make('secret');
The **make** method of the Hash class will return a 60 character hashed string.
You can compare an unhashed value against a hashed one using the **check** method on the **Hash** class:
if (Hash::check('secret', $hashed_value))
{
return 'The password is valid!';
}
> **Note:** Before using the Auth class, be sure to [create the "password" column](/docs/auth/config) on your user table.
<a name="login"></a>
### Logging In
Logging a user into your application is simple using the **login** method on the Auth class. Simply pass the username and password of the user to the method. The login method will return **true** if the credentials are valid. Otherwise, **false** will be returned:
if (Auth::login('example@gmail.com', 'password'))
{
return Redirect::to('user/profile');
}
If the user's credentials are valid, the user ID will be stored in the session and the user will be considered "logged in" on subsequent requests to your application.
To determine if the user of your application is logged in, call the **check** method:
if (Auth::check())
{
return "You're logged in!";
}
<a name="filter"></a>
### Protecting Routes
It is common to limit access to certain routes only to logged in users. It's a breeze in Laravel using the built-in [auth filter](/docs/start/routes#filters). If the user is logged in, the request will proceed as normal; however, if the user is not logged in, they will be redirected to the "login" [named route](/docs/start/routes#named).
To protect a route, simply attach the **auth** filter:
'GET /admin' => array('before' => 'auth', 'do' => function() {})
> **Note:** You are free to edit the **auth** filter however you like. A default implementation is located in **application/filters.php**.
<a name="user"></a>
### Retrieving The Logged In User
Once a user has logged in to your application, you may easily access the user model via the **user** method on the Auth class:
return Auth::user()->email;
> **Note:** If the user is not logged in, the **user** method will return NULL.
<a name="logout"></a>
### Logging Out
Ready to log the user out of your application? It's simple:
Auth::logout();
This method will remove the user ID from the session, and the user will no longer be considered logged in on subsequent requests to your application.
\ No newline at end of file
## Cache Configuration
- [Memcached](#memcached)
- [Cache Keys](#keys)
Imagine your application displays the ten most popular songs as voted on by your users. Do you really need to look up these ten songs every time someone visits your site? What if you could store them for 10 minutes, or even an hour, allowing you to dramatically speed up your application? Caching makes it simple.
Laravel provides three wonderful cache drivers out of the box:
- File System
- Memcached
- APC
By default, Laravel is configured to use the **file** system cache driver. It's ready to go. The file system driver stores cached items as files in the **application/storage/cache** directory. If you're satisfied with this driver, no other configuration is required. You're ready to start using it.
> **Note:** Before using the file system cache driver, make sure your **application/storage/cache** directory is writeable.
<a name="memcached"></a>
### Memcached
[Memcached](http://memcached.org) is an ultra-fast, open-source distributed memory object caching system used by sites such as Wikipedia and Facebook. Before using Laravel's Memcached driver, you will need to install and configure Memcached and the PHP Memcache extension on your server.
Once Memcached is installed on your server, configuring the Laravel driver is a breeze. First, set the **driver** in the **application/config/cache.php** file:
'driver' => 'memcached'
Next, add your Memcached servers to the **servers** array:
'servers' => array(
array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
)
<a name="keys"></a>
### Cache Keys
To avoid naming collisions with other applications using APC or a Memcached server, Laravel prepends a **key** to each item stored in the cache using these drivers. Feel free to change this value:
'key' => 'laravel'
\ No newline at end of file
## Cache Usage
- [Storing Items](#put)
- [Retrieving Items](#get)
- [Removing Items](#forget)
<a name="put"></a>
### Storing Items
Storing items in the cache is simple. Simply call the **put** method on the Cache class:
Cache::put('name', 'Taylor', 10);
The first parameter is the **key** to the cache item. You will use this key to retrieve the item from the cache. The second parameter is the **value** of the item. The third parameter is the number of **minutes** you want the item to be cached.
> **Note:** It is not necessary to serialize objects when storing them in the cache.
<a name="get"></a>
### Retrieving Items
Retrieving items from the cache is even more simple than storing them. It is done using the **get** method. Just mention the key of the item you wish to retrieve:
$name = Cache::get('name');
By default, NULL will be returned if the cached item has expired or does not exist. However, you may pass a different default value as a second parameter to the method:
$name = Cache::get('name', 'Fred');
Now, "Fred" will be returned if the "name" cache item has expired or does not exist.
What if you need a value from your database if a cache item doesn't exist? The solution is simple. You can pass a closure into the **get** method as a default value. The closure will only be executed if the cached item doesn't exist:
$users = Cache::get('count', function() {return DB::table('users')->count();});
Let's take this example a step further. Imagine you want to retrieve the number of registered users for your application; however, if the value is not cached, you want to store the default value in the cache. It's a breeze using the **remember** method:
$users = Cache::remember('count', function() {return DB::table('users')->count();}, 5);
Let's talk through that example. If the **count** item exists in the cache, it will be returned. If it doesn't exist, the result of the closure will be stored in the cache for five minutes **and** be returned by the method. Slick, huh?
Laravel even gives you a simple way to determine if a cached item exists using the **has** method:
if (Cache::has('name'))
{
$name = Cache::get('name');
}
<a name="forget"></a>
### Removing Items
Need to get rid of a cached item? No problem. Just mention the name of the item to the **forget** method:
Cache::forget('name');
\ No newline at end of file
## Getting Started
- [Requirements & Installation](/docs/start/install)
- [Basic Configuration](/docs/start/config)
- [Routes](/docs/start/routes)
- [Defining Routes](/docs/start/routes#define)
- [Wildcard URI Segments](/docs/start/routes#segments)
- [Named Routes](/docs/start/routes#named)
- [Route Filters](/docs/start/routes#filters)
- [Organizing Routes](/docs/start/routes#organize)
- [Views & Responses](/docs/start/views)
- [Creating Views](/docs/start/views#create)
- [Binding Data To Views](/docs/start/views#bind)
- [Nesting Views Within Views](/docs/start/views#nest)
- [Redirects](/docs/start/views#redirect)
- [Downloads](/docs/start/views#downloads)
- [Building URLs](/docs/start/views#urls)
- [Building HTML](/docs/start/views#html)
- [Interaction](/docs/start/interaction)
- [Input](/docs/start/interaction#basics)
- [Old Input](/docs/start/interaction#old)
- [Cookies](/docs/start/interaction#cookies)
- [Building Forms](/docs/start/interaction#forms)
- [Data Validation](/docs/start/validation)
## Database
- [Configuration](/docs/database/config)
- [Usage](/docs/database/usage)
- [Fluent Query Builder](/docs/database/query)
- [Eloquent ORM](/docs/database/eloquent)
## Caching
- [Configuration](/docs/cache/config)
- [Usage](/docs/cache/usage)
## Sessions
- [Configuration](/docs/session/config)
- [Usage](/docs/session/usage)
## Authentication
- [Configuration](/docs/auth/config)
- [Usage](/docs/auth/usage)
## Other Topics
- [Working With Files](/docs/other/file)
- [Localization](/docs/other/lang)
- [Encryption](/docs/other/crypt)
- [Benchmarking Code](/docs/other/benchmark)
\ No newline at end of file
## Database Configuration
- [Quick Start Using SQLite](#quick)
- [Configuring MySQL or PostgreSQL](#server)
- [Setting The Default Connection Name](#default)
Database configuration in Laravel is easy. The hardest part is deciding which database to use. Three popular open-source databases are supported out of the box:
- MySQL
- PostgreSQL
- SQLite
All of the database configuration options live in the **application/config/db.php** file. Let's get started.
<a name="quick"></a>
### Quick Start Using SQLite
[SQLite](http://sqlite.org) is an awesome, zero-configuration database system. By default, Laravel is configured to use a SQLite database. Really, you don't have to change anything. Just drop a SQLite database named **application.sqlite** into the **application/storage/db directory**. You're done.
Of course, if you want to name your database something besides "application", you can modify the database option in the SQLite section of the **application/config/db.php** file:
'sqlite' => array(
'driver' => 'sqlite',
'database' => 'your_database_name',
)
If your application receives less than 100,000 hits per day, SQLite should be suitable for production use in your application. Otherwise, consider using MySQL or PostgreSQL.
> **Note:** Need a good SQLite manager? Check out this [Firefox extension](https://addons.mozilla.org/en-US/firefox/addon/sqlite-manager/).
<a name="server"></a>
### Configuring MySQL or PostgreSQL
If you are using MySQL or PostgreSQL, you will need to edit the configuration options in **application/config/db.php**. Don't worry. In the configuration file, sample configurations exist for both systems. All you need to do is change the options as necessary for your server and set the default connection name.
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'root',
'password' => 'password',
'charset' => 'utf8',
),
<a name="default"></a>
### Setting The Default Connection Name
As you have probably noticed, each database connection defined in the **application/config/db.php** file has a name. By default, there are three connections defined: **sqlite**, **mysql**, and **pgsql**. You are free to change these connection names. The default connection can be specified via the **default** option:
'default' => 'sqlite';
The default connection will always be used by the [fluent query builder](/docs/database/query) and [Eloquent ORM](/docs/database/eloquent). If you need to change the default connection during a request, use the **Config::set** method.
\ No newline at end of file
## Eloquent ORM
- [Conventions](#conventions)
- [Retrieving Models](#get)
- [Aggregates](#aggregates)
- [Inserting & Updating Models](#save)
- [Relationships](#relationships)
- [Eager Loading](#eager)
An ORM is an [object-relational mapper](http://en.wikipedia.org/wiki/Object-relational_mapping), and Laravel has one that you will absolutely love to use. It is named "Eloquent" because it allows you to work with your database objects and relationships using an eloquent and expressive syntax. In general, you will define one Eloquent model for each table in your database. To get started, let's define a simple model:
class User extends Eloquent {}
Nice! Notice that our model extends the **Eloquent** class. This class will provide all of the functionality you need to start working eloquently with your database.
> **Note:** Typically, Eloquent models live in the **application/models** directory.
<a name="conventions"></a>
### Conventions
Eloquent makes a few basic assumptions about your database structure:
- Each table should have a primary key named **id**.
- Each table name should be the plural form of its corresponding model name.
Sometimes you may wish to use a table name other than the plural form of your model. No problem. Just add a static **table** property your model:
class User extends Eloquent {
public static $table = 'my_users';
}
<a name="get"></a>
### Retrieving Models
Retrieving models using Eloquent is refreshingly simple. The most basic way to retrieve an Eloquent model is the static **find** method. This method will return a single model by primary key with properties corresponding to each column on the table:
$user = User::find(1);
echo $user->email;
The find method will execute a query that looks something like this:
SELECT * FROM "users" WHERE "id" = 1
Need to retrieve an entire table? Just use the static **all** method:
$users = User::all();
foreach ($users as $user)
{
echo $user->email;
}
Of course, retrieving an entire table isn't very helpful. Thankfully, **every method that is available through the fluent query builder is available in Eloquent**. Just begin querying your model with a static call to one of the [query builder](/docs/database/query) methods, and execute the query using the **get** or **first** method. The get method will return an array of models, while the first method will return a single model:
$user = User::where('email', '=', $email)->first();
$user = User::where_email($email)->first();
$users = User::where_in('id', array(1, 2, 3))->or_where('email', '=', $email)->get();
$users = User::order_by('votes', 'desc')->take(10)->get();
> **Note:** If no results are found, the **first** method will return NULL. The **all** and **get** methods return an empty array.
<a name="aggregates"></a>
### Aggregates
Need to get a **MIN**, **MAX**, **AVG**, **SUM**, or **COUNT** value? Just pass the column to the appropriate method:
$min = User::min('id');
$max = User::max('id');
$avg = User::avg('id');
$sum = User::sum('id');
$count = User::count();
Of course, you may wish to limit the query using a WHERE clause first:
$count = User::where('id', '>', 10)->count();
<a name="save"></a>
### Inserting & Updating Models
Inserting Eloquent models into your tables couldn't be easier. First, instantiate a new model. Second, set its properties. Third, call the **save** method:
$user = new User;
$user->email = 'example@gmail.com';
$user->password = 'secret';
$user->save();
Updating models is just as simple. Instead of instantiating a new model, retrieve one from your database. Then, set its properties and save:
$user = User::find(1);
$user->email = 'new_email@gmail.com';
$user->password = 'new_secret';
$user->save();
Need to maintain creation and update timestamps on your database records? With Eloquent, you don't have to worry about it. Just add a static **timestamps** property to your model:
class User extends Eloquent {
public static $timestamps = true;
}
Next, add **created_at** and **updated_at** date columns to your table. Now, whenever you save the model, the creation and update timestamps will be set automatically. You're welcome.
> **Note:** You can change the default timezone of your application in the **application/config/application.php** file.
<a name="relationships"></a>
### Relationships
Unless you're doing it wrong, your database tables are probably related to one another. For instance, an order may belong to a user. Or, a post may have many comments. Eloquent makes defining relationships and retrieving related models simple and intuitive. Laravel supports three types of relationships:
- [One-To-One](#one-to-one)
- [One-To-Many](#one-to-many)
- [Many-To-Many](#many-to-many)
To define a relationship on an Eloquent model, you simply create a method that returns the result of either the **has\_one**, **has\_many**, **belongs\_to**, or **has\_and\_belongs\_to\_many** method. Let's examine each one in detail.
<a name="one-to-one"></a>
#### One-To-One
A one-to-one relationship is the most basic form of relationship. For example, let's pretend a user has one phone. Simply describe this relationship to Eloquent:
class User extends Eloquent {
public function phone()
{
return $this->has_one('Phone');
}
}
Notice that the name of the related model is passed to the **has_one** method. You can now retrieve the phone of a user through the **phone** method:
$phone = User::find(1)->phone()->first();
Let's examine the SQL performed by this statement. Two queries will be performed: one to retrieve the user and one to retrieve the user's phone:
SELECT * FROM "users" WHERE "id" = 1
SELECT * FROM "phones" WHERE "user_id" = 1
Note that Eloquent assumes the foreign key of the relationship will be **user\_id**. Most foreign keys will follow this **model\_id** convention; however, if you want to use a different column name as the foreign key, just pass it in the second parameter to the method:
return $this->has_one('Phone', 'my_foreign_key');
Want to just retrieve the user's phone without calling the first method? No problem. Just use the **dynamic phone property**. Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method:
$phone = User::find(1)->phone;
What if you need to retrieve a phone's user? Since the foreign key (**user\_id**) is on the phones table, we should describe this relationship using the **belongs\_to** method. It makes sense, right? Phones belong to users. When using the **belongs\_to** method, the name of the relationship method should correspond to the foreign key (sans the **\_id**). Since the foreign key is **user\_id**, your relationship method should be named **user**:
class Phone extends Eloquent {
public function user()
{
return $this->belongs_to('User');
}
}
Great! You can now access a User model through a Phone model using either your relationship method or dynamic property:
echo Phone::find(1)->user()->first()->email;
echo Phone::find(1)->user->email;
<a name="one-to-many"></a>
#### One-To-Many
Assume a blog post has many comments. It's easy to define this relationship using the **has_many** method:
class Post extends Eloquent {
public function comments()
{
return $this->has_many('Comment');
}
}
Now, simply access the post comments through the relationship method or dynamic property:
$comments = Post::find(1)->comments()->get();
$comments = Post::find(1)->comments;
Both of these statements will execute the following SQL:
SELECT * FROM "posts" WHERE "id" = 1
SELECT * FROM "comments" WHERE "post_id" = 1
Want to join on a different foreign key? No problem. Just pass it in the second parameter to the method:
return $this->has_many('Comment', 'my_foreign_key');
You may be wondering: _If the dynamic properties return the relationship and require less keystokes, why would I ever use the relationship methods?_ Actually, relationship methods are very powerful. They allow you to continue to chain query methods before retrieving the relationship. Check this out:
echo Post::find(1)->comments()->order_by('votes', 'desc')->take(10)->get();
<a name="many-to-many"></a>
#### Many-To-Many
Many-to-many relationships are the most complicated of the three relationships. But don't worry, you can do this. For example, assume a User has many Roles, but a Role can also belong to many Users. Three database tables must be created to accomplish this relationship: a **users** table, a **roles** table, and a **roles_users** table. The structure for each table looks like this:
**Users:**
id - INTEGER
email - VARCHAR
**Roles:**
id - INTEGER
name - VARCHAR
**Roles_Users:**
user_id - INTEGER
role_id - INTEGER
Now you're ready to define the relationship on your models using the **has\_and\_belongs\_to\_many** method:
class User extends Eloquent {
public function roles()
{
return $this->has_and_belongs_to_many('Role');
}
}
Great! Now it's time to retrieve a user's roles:
$roles = User::find(1)->roles()->get();
Or, as usual, you may retrieve the relationship through the dynamic roles property:
$roles = User::find(1)->roles;
As you may have noticed, the default name of the intermediate table is the plural names of the two related models arranged alphabetically and concatenated by an underscore. However, you are free to specify your own table name. Simply pass the table name in the second parameter to the **has\_and\_belongs\_to\_many** method:
class User extends Eloquent {
public function roles()
{
return $this->has_and_belongs_to_many('Role', 'user_roles');
}
}
<a name="eager"></a>
### Eager Loading
Eager loading exists to alleviate the N + 1 query problem. Exactly what is this problem? Well, pretend each Book belongs to an Author. We would describe this relationship like so:
class Book extends Eloquent {
public function author()
{
return $this->belongs_to('Author');
}
}
Now, examine the following code:
foreach (Book::all() as $book)
{
echo $book->author->name;
}
How many queries will be executed? Well, one query will be executed to retrieve all of the books from the table. However, another query will be required for each book to retrieve the author. To display the author name for 25 books would require **26 queries**. See how the queries can add up fast?
Thankfully, you can eager load the author models using the **with** method. Simply mention the **function name** of the relationship you wish to eager load:
foreach (Book::with('author')->get() as $book)
{
echo $book->author->name;
}
In this example, **only two queries will be executed**!
SELECT * FROM "books"
SELECT * FROM "authors" WHERE "id" IN (1, 2, 3, 4, 5, ...)
Obviously, wise use of eager loading can dramatically increase the performance of your application. In the example above, eager loading cut the execution time in half.
Need to eager load more than one relationship? It's easy:
$books = Book::with('author', 'publisher')->get();
> **Note:** When eager loading, the call to the static **with** method must always be at the beginning of the query.
\ No newline at end of file
## Fluent Query Builder
- [Retrieving Records](#get)
- [Building Where Clauses](#where)
- [Dynamic Where Clauses](#dynamic)
- [Table Joins](#joins)
- [Ordering Results](#ordering)
- [Skip & Take](#limit)
- [Aggregates](#aggregates)
- [Inserting Records](#insert)
- [Updating Records](#update)
- [Deleting Records](#delete)
Laravel provides an awesome, easy-to-use fluent interface for building SQL queries and working with your database. All queries use prepared statements and are protected against SQL injection. Working with your database doesn't have to be a headache.
You can begin a fluent query using the **table** method on the DB class. Just mention the table you wish to query:
$query = DB::table('users');
You now have a fluent query builder for the "users" table. Using this query builder, you can retrieve, insert, update, or delete records from the table.
<a name="get"></a>
### Retrieving Records
There are two methods available for retrieving records using a fluent query: **get** and **first**. The **get** method will return an array of records from your database. Each record will be an object with properties corresponding to the columns of the table:
$users = DB::table('users')->get();
foreach ($users as $user)
{
echo $user->email;
}
Instead of returning an array, the **first** method will return a single object:
$user = DB::table('users')->first();
echo $user->email;
It's easy to limit the columns returned by your query. Simply pass an array of columns you want into the **get** or **first** method:
$user = DB::table('users')->get(array('id', 'email as user_email'));
Need to get distinct records from the database? It's easy. Call the **distinct** method before retrieving your records:
$user = DB::table('users')->distinct()->get();
> **Note:** If no results are found, the **first** method will return NULL. The **get** method will return an empty array.
<a name="where"></a>
### Building Where Clauses
#### where and or\_where
Building WHERE clauses in Laravel is painless. There are a variety of methods to assist you. The most basic of these methods are the **where** and **or_where** methods. Here is how to use them:
return DB::table('users')
->where('id', '=', 1)
->or_where('email', '=', 'example@gmail.com')
->first();
Of course, you are not limited to simply checking equality. You may also use **greater-than**, **less-than**, **not-equal**, and **like**:
return DB::table('users')
->where('id', '>', 1)
->or_where('name', 'LIKE', '%Taylor%')
->first();
You may have assumed that the **where** method will add to the query using an AND condition, while the **or_where** method will use an OR condition. You assumed correctly.
#### where\_in, where\_not\_in, or\_where\_in, and or\_where\_not\_in
The suite of **where_in** methods allows you to easily construct queries that search an array of values:
DB::table('users')->where_in('id', array(1, 2, 3))->get();
DB::table('users')->where_not_in('id', array(1, 2, 3))->get();
DB::table('users')
->where('email', '=', 'example@gmail.com')
->or_where_in('id', array(1, 2, 3))
->get();
DB::table('users')
->where('email', '=', 'example@gmail.com')
->or_where_not_in('id', array(1, 2, 3))
->get();
#### where\_null, where\_not\_null, or\_where\_null, and or\_where\_not\_null
The suite of **where_null** methods makes checking for NULL values a piece of cake:
return DB::table('users')->where_null('updated_at')->get();
return DB::table('users')->where_not_null('updated_at')->get();
return DB::table('users')
->where('email', '=', 'example@gmail.com')
->or_where_null('updated_at')
->get();
return DB::table('users')
->where('email', '=', 'example@gmail.com')
->or_where_not_null('updated_at')
->get();
<a name="dynamic"></a>
### Dynamic Where Clauses
Ready for some really beautiful syntax? Check out **dynamic where methods**:
$user = DB::table('users')->where_email('example@gmail.com')->first();
$user = DB::table('users')->where_email_and_password('example@gmail.com', 'secret');
$user = DB::table('users')->where_id_or_name(1, 'Fred');
Aren't they a breathe of fresh air?
<a name="joins"></a>
### Table Joins
Need to join to another table? Try the **join** and **left\_join** methods:
DB::table('users')
->join('phone', 'users.id', '=', 'phone.user_id')
->get(array('users.email', 'phone.number'));
The **table** you wish to join is passed as the first parameter. The remaining three parameters are used to construct the **ON** clause of the join.
Once you know how to use the join method, you know how to **left_join**. The method signatures are the same:
DB::table('users')
->left_join('phone', 'users.id', '=', 'phone.user_id')
->get(array('users.email', 'phone.number'));
<a name="ordering"></a>
### Ordering Results
You can easily order the results of your query using the **order_by** method. Simply mention the column and direction (desc or asc) of the sort:
return DB::table('users')->order_by('email', 'desc')->get();
Of course, you may sort on as many columns as you wish:
return DB::table('users')
->order_by('email', 'desc')
->order_by('name', 'asc')
->get();
<a name="limit"></a>
### Skip & Take
If you would like to **LIMIT** the number of results returned by your query, you can use the **take** method:
return DB::table('users')->take(10)->get();
To set the **OFFSET** of your query, use the **skip** method:
return DB::table('users')->skip(10)->get();
<a name="aggregates"></a>
### Aggregates
Need to get a **MIN**, **MAX**, **AVG**, **SUM**, or **COUNT** value? Just pass the column to the query:
$min = DB::table('users')->min('age');
$max = DB::table('users')->max('weight');
$avg = DB::table('users')->avg('salary');
$sum = DB::table('users')->sum('votes');
$count = DB::table('users')->count();
Of course, you may wish to limit the query using a WHERE clause first:
$count = DB::table('users')->where('id', '>', 10)->count();
<a name="insert"></a>
### Inserting Records
Inserting records is amazingly easy using the **insert** method. The method only expects an array of values to insert. It couldn't be simpler. The insert method will simply return true or false, indicating whether the query was successful:
DB::table('users')->insert(array('email' => 'example@gmail.com'));
Inserting a record that has an auto-incrementing ID? You can use the **insert\_get\_id** method to insert a record and retrieve the ID:
$id = DB::table('users')->insert_get_id(array('email' => 'example@gmail.com'));
> **Note:** The **insert\_get\_id** method expects the name of the auto-incrementing column to be "id".
<a name="update"></a>
### Updating Records
Updating records is just as simple as inserting them. Simply pass an array of values to the **update** method:
$affected = DB::table('users')->update(array('email' => 'new_email@gmail.com'));
Of course, when you only want to update a few records, you should add a WHERE clause before calling the update method:
$affected = DB::table('users')
->where('id', '=', 1)
->update(array('email' => 'new_email@gmail.com'));
<a name="delete"></a>
### Deleting Records
When you want to delete records from your database, simply call the **delete** method:
$affected = DB::table('users')->where('id', '=', 1)->delete();
Want to quickly delete a record by its ID? No problem. Just pass the ID into the delete method:
$affected = DB::table('users')->delete(1);
\ No newline at end of file
## Database Usage
### Queries
Running queries against a database connection is a breeze using the **query** method on the DB class:
$users = DB::query('select * from users');
The **query** method also allows you to specify bindings for your query in the second parameter to the method:
$users = DB::query('select * from users where name = ?', array('test'));
The return value of the query method depends on the type of query that is executed:
- **SELECT** statements will return an array of stdClass objects with properties corresponding to each column on the table.
- **INSERT** statements will return **true** or **false**, depending on the success of the query.
- **UPDATE** and **DELETE** statements will return the number of rows affected by the query.
### Connections
Need to get the raw PDO object for a connection? It's easy. Just mention the connection name to the **connection** method on the DB class:
$pdo = DB::connection('sqlite');
> **Note:** If no connection name is specified, the **default** connection will be returned.
### Driver
Want to know which PDO driver is being used for a connection? Check out the **driver** method:
$driver = DB::driver('connection_name');
> **Note:** If no connection name is specified, the **default** connection driver will be returned.
\ No newline at end of file
## Benchmarking Code
- [The Basics](#basics)
- [Using Timers](#timers)
- [Checking Memory Usage](#memory)
<a name="basics"></a>
### The Basics
When making changes to your code, it's helpful to know the performance impact of your changes. Laravel provides a simple class to help you time code execution and check memory consumption. It's called the **Benchmark** class and it's a breeze to use.
<a name="timers"></a>
### Using Timers
To start a timer, simply call the **start** method on the Benchmark class and give your timer a name:
Benchmark::start('foo');
Pretty easy, right?
You can easily check how much time has elapsed (in milliseconds) using the **check** method. Again, just mention the name of the timer to the method:
echo Benchmark::check('foo');
<a name="memory"></a>
### Checking Memory Usage
Need to know how much memory is being used by your application? No problem. Just call the **memory** method to get your current memory usage in megabytes:
echo Benchmark::memory();
\ No newline at end of file
## Encryption
- [The Basics](#basics)
- [Encrypting A String](#encrypt)
- [Decrypting A String](#decrypt)
<a name="basics"></a>
### The Basics
Need to do secure, two-way encryption? Laravel has you covered with the **Crypt** class. The Crypt class provides strong AES-256 encryption and decryption out of the box via the Mcrypt PHP extension.
To get started, you must set your **application key** in the **application/config/application.php** file. This key should be very random and very secret, as it will be used during the encryption and decryption process. It is best to use a random, 32 character alpha-numeric string:
'key' => 'xXSAVghP7myRo5xqJAnMvQwBc7j8qBZI';
Wonderful. You're ready to start encrypting.
> **Note:** Don't forget to install the Mcrypt PHP extension on your server.
<a name="encrypt"></a>
### Encrypting A String
Encrypting a string is a breeze. Just pass it to the **encrypt** method on the Crypt class:
Crypt::encrypt($value);
Do you feel like James Bond yet?
<a name="decrypt"></a>
### Decrypting A String
So you're ready to decrypt a string? It's simple. Just use the **decrypt** method on the Crypt class:
Crypt::decrypt($encrypted_value);
> **Note:** The decrypt method will only decrypt strings that were encrypted using **your** application key.
\ No newline at end of file
## Working With Files
- [Reading Files](#get)
- [Writing Files](#put)
- [File Uploads](#upload)
- [File Extensions](#ext)
- [Checking File Types](#is)
- [Getting MIME Types](#mime)
<a name="get"></a>
### Reading Files
It's a breeze to get the contents of a file using the **get** method on the **File** class:
$contents = File::get('path/to/file');
<a name="put"></a>
### Writing Files
Need to write to a file? Check out the **put** method:
File::put('path/to/file', 'file contents');
Want to append to the file instead of overwriting the existing contents? No problem. Use the **append** method:
File::append('path/to/file', 'appended file content');
<a name="upload"></a>
### File Uploads
After a file has been uploaded to your application, you will want to move it from its temporary location to a permanent directory. You can do so using the **upload** method. Simply mention the **name** of the uploaded file and the path where you wish to store it:
File::upload('picture', 'path/to/pictures');
> **Note:** You can easily validate file uploads using the [Validator class](/docs/start/validation).
<a name="ext"></a>
### File Extensions
Need to get the extension of a file? Just pass the filename to the **extension** method:
File::extension('picture.png');
<a name="is"></a>
### Checking File Types
Often, it is important to know the type of a file. For instance, if a file is uploaded to your application, you may wish to verify that it is an image. It's easy using the **is** method on the **File** class. Simply pass the extension of the file type you are expecting. Here's how to verify that a file is a JPG image:
if (File::is('jpg', 'path/to/file.jpg'))
{
//
}
The **is** method does not simply check the file extension. The Fileinfo PHP extension will be used to read the content of the file and determine the actual MIME type. Pretty cool, huh?
> **Note:** You may pass any of the extensions defined in the **application/config/mimes.php** file to the **is** method.
<a name="mime"></a>
### Getting MIME Types
Need to know the MIME type associated with a file extension? Check out the **mime** method:
echo File::mime('gif');
The statement above returns the following string:
image/gif
> **Note:** This method simply returns the MIME type defined for the extension in the **application/config/mimes.php** file.
\ No newline at end of file
## Localization
- [The Basics](#basics)
- [Retrieving A Language Line](#get)
- [Place Holders & Replacements](#replace)
<a name="basics"></a>
### The Basics
Localization is the process of translating your application into different languages. The **Lang** class provides a simple mechanism to help you organize and retrieve the text of your multilingual application.
All of the language files for your application live under the **application/lang** directory. Within the **application/lang** directory, you should create a directory for each language your application speaks. So, for example, if your application speaks English and Spanish, you might create **en** and **sp** directories under the **lang** directory.
Each language directory may contain many different language files. Each language file is simply an array of string values in that language. In fact, language files are structured identically to configuration files. For example, within the **application/lang/en** directory, you could create a **marketing.php** file that looks like this:
return array(
'welcome' => 'Welcome to our website!',
);
Next, you should create a corresponding **marketing.php** file within the **application/lang/sp** directory. The file would look something like this:
return array(
'welcome' => 'Bienvenido a nuestro sitio web!',
);
Nice! Now you know how to get started setting up your language files and directories. Let's keep localizing!
<a name="basics"></a>
### Retrieving A Language Line
To retrieve a language line, first create a Lang instance using the **line** method, then call the **get** method on the instance:
echo Lang::line('marketing.welcome')->get();
Notice how a dot was used to separate "marketing" and "welcome"? The text before the dot corresponds to the language file, while the text after the dot corresponds to a specific string within that file.
But, how did the method know which language directory to retrieve the message from? By default, the **get** method will use the language specified in your **application/config/application.php** configuration file. In this file you may set the default language of your application using the **language** option:
'language' => 'en'
Need to retrieve the line in a language other than your default? Not a problem. Just mention the language to the **get** method:
echo Lang::line('marketing.welcome')->get('sp');
<a name="replace"></a>
### Place Holders & Replacements
Now, let's work on our welcome message. "Welcome to our website!" is a pretty generic message. It would be helpful to be able to specify the name of the person we are welcoming. But, creating a language line for each user of our application would be time-consuming and ridiculous. Thankfully, you don't have to. You can specify "place-holders" within your language lines. Place-holders are preceeded by a colon:
'welcome' => 'Welcome to our website, :name!'
Then, simply pass an array of place-holder replacements to the **replace** method on a Lang instance:
echo Lang::line('marketing.welcome')->replace(array('name' => 'Taylor'))->get();
This statement will return a nice, heart-warming welcome message:
Welcome to our website, Taylor!
\ No newline at end of file
<a name="config"></a>
## Session Configuration
- [File System Sessions](#file)
- [Database Sessions](#database)
- [Memcached Sessions](#memcached)
The web is a stateless environment. This means that each request to your application is considered unrelated to any previous request. However, **sessions** allow you to store arbitrary data for each visitor to your application. The session data for each visitor is stored on your web server, while a cookie containing a **session ID** is stored on the visitor's machine. This cookie allows your application to "remember" the session for that user and retrieve their session data on subsequent requests to your application.
Sound complicated? If so, don't worry about it. Just tell Laravel where to store the sessions and it will take care of the rest.
Three great session drivers are available out of the box:
- File System
- Database
- Memcached
<a name="file"></a>
### File System Sessions
Most likely, your application will work great using file system sessions. However, if your application receives heavy traffic or runs on a server farm, use database or Memcached sessions.
To get started using file system sessions, just set the driver option in the **application/config/session.php** file:
'driver' => 'file'
That's it. You're ready to go!
> **Note:** File system sessions are stored in the **application/storage/sessions** directory, so make sure it's writeable.
<a name="database"></a>
### Database Sessions
To start using database sessions, you will first need to [configure your database connection](/docs/database/config).
Already setup your database? Nice! Next, you will need to create a session table. Here are some SQL statements to help you get started:
#### SQLite
CREATE TABLE "sessions" (
"id" VARCHAR PRIMARY KEY NOT NULL UNIQUE,
"last_activity" INTEGER NOT NULL,
"data" TEXT NOT NULL
);
#### MySQL
CREATE TABLE `sessions` (
`id` VARCHAR(40) NOT NULL,
`last_activity` INT(10) NOT NULL,
`data` TEXT NOT NULL,
PRIMARY KEY (`id`)
);
If you would like to use a different table name, simply change the **table** option in the **application/config/session.php** file:
'table' => 'sessions'
Great! All you need to do now is set the driver in the **application/config/session.php** file:
'driver' => 'db'
<a name="memcached"></a>
### Memcached Sessions
Before using Memcached sessions, you must [configure your Memcached servers](/docs/cache/config#memcached).
All done? Great! Just set the driver in the **application/config/session.php** file:
'driver' => 'memcached'
\ No newline at end of file
## Session Usage
- [Storing Items](#put)
- [Retrieving Items](#get)
- [Removing Items](#forget)
- [Regeneration](#regeneration)
<a name="put"></a>
### Storing Items
Storing items in the session is a breeze. Simply call the put method on the Session class:
Session::put('name', 'Taylor');
The first parameter is the **key** to the session item. You will use this key to retrieve the item from the session. The second parameter is the **value** of the item.
Need to store an item in the session that should expire after the next request? Check out the **flash** method. It provides an easy way to store temporary data like status or error messages:
Session::flash('status', 'Welcome Back!');
<a name="get"></a>
### Retrieving Items
Retrieving items from the session is no problem. You can use the **get** method on the Session class to retrieve any item in the session, including flash data. Just pass the key of the item you wish to retrieve:
$name = Session::get('name');
By default, NULL will be returned if the session item does not exist. However, you may pass a default value as a second parameter to the get method:
$name = Session::get('name', 'Fred');
$name = Session::get('name', function() {return 'Fred';});
Now, "Fred" will be returned if the "name" item does not exist in the session.
Laravel even provides a simple way to determine if a session item exists using the **has** method:
if (Session::has('name'))
{
$name = Session::get('name');
}
<a name="forget"></a>
### Removing Items
Need to get rid of a session item? No problem. Just mention the name of the item to the **forget** method on the Session class:
Session::forget('name');
You can even remove all of the items from the session using the **flush** method:
Session::flush();
<a name="regeneration"></a>
### Regeneration
Sometimes you may want to "regenerate" the session ID. This simply means that a new, random session ID will be assigned to the session. Here's how to do it:
Session::regenerate();
\ No newline at end of file
## Basic Configuration
- [Quick Start](#quick)
- [Cleaner URLs](#clean)
- [Errors & Logging](#errors)
<a name="quick"></a>
### Quick Start
When starting a new project, you shouldn't be bombarded with loads of confusing configuration decisions. For that reason, Laravel is intelligently configured out of the box. The **application/config/application.php** file contains the basic configuration options for your application.
There is only one option that **must** be set when starting a new application. Laravel needs to know the URL you will use to access your application. Simply set the url in the **application/config/application.php** file:
'url' => 'http://localhost';
> **Note:** If you are using mod_rewrite, you should set the index option to an empty string.
<a name="clean"></a>
### Cleaner URLs
Most likely, you do not want your application URLs to contain "index.php". You can remove it using HTTP rewrite rules. If you are using Apache to serve your application, make sure to enable mod_rewrite and create a **.htaccess** file like this one in your **public** directory:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>
Is the .htaccess file above not working for you? Try this one:
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
After setting up HTTP rewriting, you should set the **index** configuration option in **application/config/application.php** to an empty string.
> **Note:** Each web server has a different method of doing HTTP rewrites, and may require a slightly different .htaccess file.
<a name="errors"></a>
### Errors & Logging
- [404 Errors](#error-404)
- [Error Detail](#error-detail)
- [Logging](#error-logging)
<a name="error-404"></a>
#### 404 Errors
When a request is made to your application that cannot be matched to a route, the 404 error view will be sent to the browser. This view lives in **application/views/error/404.php** and you are free to modify it however you wish.
<a name="error-detail"></a>
#### Error Detail
You can easily control the level of error detail via the **detail** option in the **application/config/errors.php** file.
'detail' => true;
When set to **true**, error messages will be detailed with a stack trace and snippet of the relevant file. When set to **false**, the generic error page (**application/views/error/500.php**) will be displayed. Feel free to modify this view.
> **Note:** In a production environment, it is strongly suggested that you turn off error details.
<a name="error-logging"></a>
#### Logging
You may wish to log any errors that occur in your application. Laravel makes it a breeze. You can turn on logging by setting the log option to **true** in the **application/config/errors.php** file:
'log' => true;
You have total control over how your errors are logged via the **logger** function defined in **application/config/error.php**. This function is called every time there is an unhandled error or exception in your application.
As you can see, the default logger implementation writes to the **application/storage/log.txt** file; however, you are free to modify this function however you wish.
\ No newline at end of file
## Requirements & Installation
### Requirements
- Apache, nginx, or another compatible web server.
- PHP 5.3+.
### Installation
1. [Download Laravel](https://github.com/taylorotwell/laravel/zipball/master)
2. Extract the Laravel archive and upload the contents to your web server.
4. Set the URL of your application in the **application/config/application.php** file.
5. Navigate to your application in a web browser.
If all is well, you should see a pretty Laravel splash page. Get ready, there is lots more to learn!
### Extras
Installing the following goodies will help you take full advantage of Laravel, but they are not required:
- SQLite, MySQL, or PostgreSQL PDO drivers.
- [Memcached](http://memcached.org) or APC.
### Problems?
- Make sure the **public** directory is the document root of your web server.
- If you are using mod_rewrite, set the **index** option in **application/config/application.php** to an empty string.
\ No newline at end of file
## Interaction
- [Input](/docs/start/interaction#basics)
- [Old Input](/docs/start/interaction#old)
- [Cookies](/docs/start/interaction#cookies)
- [Building Forms](/docs/start/interaction#forms)
All web applications receive input via HTTP requests. The input can be sent to your application via any of the four HTTP verbs: **GET**, **POST**, **PUT**, or **DELETE**. Input can also be sent to your application via cookies, which can store small amounts of information and are stored on the user's computer.
Let's dig into the classes Laravel provides for working with user input!
> **Note:** Laravel doesn't mess with your query strings. Feel free to use them.
<a name="basics"></a>
## Input
The **Input** class handles input that comes into your application via GET, POST, PUT, or DELETE requests. Retrieving input using the Input class is effortless. Just use the **get** method:
$email = Input::get('email');
> **Note:** The get method is used for all request types, not just GET requests. You may use it on POST, PUT, and DELETE requests as well.
By default, NULL will be returned if the input item does not exist. However, you may pass a different default value as a second parameter to the method:
$name = Input::get('name', 'Fred');
Now, "Fred" will be returned if the "name" input item does not exist. You may even pass a closure as a default value:
$name = Input::get('name', function() {return 'Fred';});
Need to determine if an input item exists? Use the **has** method:
if (Input::has('name'))
{
$name = Input::get('name');
}
> **Note:** The **has** method will return **false** if the input item exists but is an empty string.
Need to access the **$_FILES** array? It's easy using the **file** method:
$picture = Input::file('picture');
$size = Input::file('picture.size');
Sometimes you may need to merge the input and $_FILES array. Check out the **all** method:
$input = Input::all();
<a name="old"></a>
## Old Input
Have you ever tried to re-populate an input form after an invalid form submission? It can get pretty clunky. Not in Laravel. You can easily retrieve the input from the previous request using the **old** method on the Input class:
$name = Input::old('name');
> **Note:** You must specifiy a session driver before using the **old** Input method.
As you would expect, you may pass a default value in the second parameter to the method:
$name = Input::old('name', 'Fred');
Once again, there is a simple way to determine if an old input item exists using the **had** method:
if (Input::had('name'))
{
$name = Input::old('name');
}
<a name="cookies"></a>
## Cookies
The **Cookie** class provides simple functions for retrieving, setting, and deleting cookies.
To retrieve a cookie value, simply mention its name to the **get** method:
$name = Cookie::get('name');
Of course, just like the Input class, you may pass a default value in the second parameter to the **get** method:
$name = Cookie::get('name', 'Fred');
Also just like the Input class, the Cookie class has a simple method to determine if a cookie exists:
if (Cookie::has('name'))
{
$name = Cookie::get('name');
}
Need to create a cookie? No problem. Check out the **put** method:
Cookie::put('name', 'Fred', 60);
The put method accepts almost the exact same parameters as the PHP setcookie method. However, just pass the number of **minutes** you want the cookie to live as the third parameter. You don't have to worry about any clunky expiration date calculations.
If you need to create a "permanent" cookie, try the **forever** method. It creates a cookie that lives for five years:
Cookie::forever('name', 'Fred');
To delete a cookie, use the **forget** method:
Cookie::forget('name');
<a name="forms"></a>
## Building Forms
- [Opening A Form](#form-open)
- [CSRF Protection](#form-csrf)
- [Labels](#form-labels)
- [Text, Text Area, Password & Hidden Fields](#form-text)
- [Checkboxes & Radio Buttons](#form-check)
- [Drop-Down Lists](#form-lists)
- [Buttons](#form-buttons)
Almost every web application receives input through HTML forms. As you have probably already learned, Laravel is here to make your life easier. That's why generating forms using the **Form** class is a breeze.
> **Note:** All input data displayed in elements generated by the **Form** class is filtered through the HTML::entities method.
<a name="form-open"></a>
### Opening A Form
Opening a form is simple. Just call the **open** method on the Form class:
echo Form::open();
When called without any parameters, the open method will create a form that will POST to the current URL. However, you'll probably want to point your forms to other URLs too. No problem. Just mention the URL to the method. You can even specify the request method (GET, POST, PUT, or DELETE) in the second parameter to the method:
echo Form::open('user/profile', 'PUT');
Need to apply a class or other attribute to the form tag generated by the open method? Simply pass an array of attributes as a third parameter:
echo Form::open('user/profile', 'PUT', array('class' => 'awesome'));
> **Note:** The open method automatically prepares your form to receive UTF-8 input.
Need a form that can handle file uploads? Use the **open_for_files** method:
echo Form::open_for_files('user/profile');
<a name="form-csrf"></a>
### CSRF Protection
Laravel provides an easy method of protecting your application from [cross-site request forgeries](http://en.wikipedia.org/wiki/Cross-site_request_forgery). First, a random token is placed in your user's session. Don't sweat it, this is done automatically. Next, use the **token** method to generate a hidden form input field containing the random token on your form:
echo Form::token();
Now, simply [attach the built-in CSRF filter](/docs/start/routes#filters) to the route the form is posting to. If the token submitted by the form does not match the token in the user's session, the **application/views/error/500.php** view will be displayed.
Want to just get the CSRF token without generating a hidden input field? Use the **raw_token** method:
echo Form::raw_token();
> **Note:** Don't forget to [specify a session driver](/docs/session/config) before using these methods.
<a name="form-labels"></a>
### Labels
Need to generate a label for a form element? It's simple using the **label** method. Just pass the label name and display value to the method:
echo Form::label('email', 'E-Mail Address');
Of course, you may pass any attributes you wish in the third parameter to the method:
echo Form::label('email', 'E-Mail Address', array('class' => 'awesome'));
> **Note:** After creating a label, any form element you create with a name matching the label name will automatically receive an ID matching the label name as well.
<a name="form-text"></a>
### Text, Text Area, Password & Hidden Fields
Generating text boxes couldn't be easier. Just call the **text** method on the Form class and mention the name of the field:
echo Form::text('username');
Already have a value you want to put in the text box? Throw it in as a second parameter:
echo Form::text('email', 'example@gmail.com');
Again, any other attributes you wish to apply to the text box may be passed in an array as the third parameter:
echo Form::text('email', 'example@gmail.com', array('class' => 'awesome'));
> **Note:** The **password**, **hidden**, and **textarea** methods have the same signature as the text method. You just learned four methods for the price of one!
<a name="form-check"></a>
### Checkboxes & Radio Buttons
What website doesn't have a checkbox? Actually, this one doesn't! But, thankfully, generating them is simple using the **checkbox** method on the Form class. Just give the checkbox a name and a value:
echo Form::checkbox('remember', 'yes');
Of course, the example above will generate the following HTML:
<input type="checkbox" name="remember" value="yes">
Need to generate a "checked" checkbox? No problem. Simply pass **true** as the third parameter to the method:
echo Form::checkbox('remember', 'yes', true);
As always, you may specify any extra attributes that should be applied to the checkbox. Pass them as the fourth parameter to the method:
echo Form::checkbox('remember', 'yes', true, array('class' => 'awesome'));
> **Note:** The **radio** method has the same signature as the checkbox method. Two for one!
<a name="form-lists"></a>
### Drop-Down Lists
Generating drop-down lists can be a headache. Thankfully, Laravel makes it refreshingly simple using the **select** method on the Form class. All you need to do is give your list a name and an array of options:
echo Form::select('size', array('L' => 'Large', 'S' => 'Small'));
If you wish to set the selected item, just pass the value as the third parameter to the method:
echo Form::select('size', array('L' => 'Large', 'S' => 'Small'), 'S');
You may specify any other attributes that should be applied to the list in the fourth parameter to the method:
echo Form::select('size', array('L' => 'Large', 'S' => 'Small'), 'S', array('class' => 'awesome'));
<a name="form-buttons"></a>
### Buttons
Creating a submit button is a cinch. Use the **submit** method on the Form class:
echo Form::submit('Click Me!');
Again, any other attributes that should be applied to the button may be passed to the method:
echo Form::submit('Click Me!', array('class' => 'awesome'));
> **Note:** Need to create a button element? Try the **button** method. It has the same signature as submit.
\ No newline at end of file
## Routes
- [Defining Routes](/docs/start/routes#define)
- [Wildcard URI Segments](/docs/start/routes#segments)
- [Named Routes](/docs/start/routes#named)
- [Route Filters](/docs/start/routes#filters)
- [Organizing Routes](/docs/start/routes#organize)
Unlike other PHP frameworks, Laravel places routes and their corresponding functions in one file: **application/routes.php**. This file contains the "definition", or public API, of your application. To add functionality to your application, you add to the array located in this file. It's a breeze.
<a name="define"></a>
## Defining Routes
All you need to do is tell Laravel the request methods and URIs it should respond to. You define the behavior of the route using an anonymous method:
'GET /home' => function()
{
// Handles GET requests to http://example.com/index.php/home
},
You can easily define a route to handle requests to more than one URI. Just use commas:
'POST /, POST /home' => function()
{
// Handles POST requests to http://example.com and http://example.com/home
}
> **Note:** The routes.php file replaces the "controllers" found in most frameworks. Have a fat model and keep this file light and clean. Thank us later.
<a name="segments"></a>
## Wildcard URI Segments
Laravel makes matching wildcard URI segments a breeze using the **(:num)** and **(:any)** place-holders. Check out these routes:
'PUT /user/(:num)' => function($id) {}
'DELETE /user/(:any)' => function($username) {}
Laravel will automatically pass the value of the wildcard segment into your route function.
> **Note:** The **(:any)** place-holder matches letters, number, dashes, and underscores.
Want to make an URI segment optional? No problem. Just put a **?** in the place-holder:
'GET /download/(:any?)' => function($branch = 'master') {}
If you need more power and precision (or just want to be extra nerdy), you can even use regular expressions:
'GET /product/([0-9]+)' => function($id) {}
<a name="named"></a>
## Named Routes
Once you start using named routes, you won't be able to live without them. They are that great. Here's how to do it:
'GET /user/login' => array('name' => 'login', 'do' => function() {})
Notice the route now has an array value with two keys: **name** and **do**. As you learned while studying filters, the **do** value is the method that will be executed by the route. As you have probably guessed, the **name** value is the name of the route.
Now that you have named the route, you can [generate URLs](/docs/start/views#urls) and [perform redirects](/docs/start/views#redirect) using the route name instead of the route URI. This means that you can change the route URI as much as you want and the links to that route on your views will always be correct. It's beautiful, isn't it?
<a name="filters"></a>
## Route Filters
Filters are methods that run before and after a request to your application. "Before" filters can even halt the request cycle by returning a response, providing an amazingly simple way to implement common tasks like redirecting a user to a login view. Let's dig in.
All filters are defined in the **application/filters.php** file. Intuitive, right? If you open the file, you will see that four filters have already been defined for you: **before**, **after**, **auth**, and **csrf**. The **before** and **after** filters are the two "global" filters. They are always executed on every request, regardless of the request method or URI.
All other filters must be attached to individual routes. Don't worry, you'll learn how to do this soon. The built-in **auth** and **csrf** filters handle two scenarios that are common to almost every web application: redirecting users to a login page and protecting against cross-site request forgeries.
### Defining Filters
To define your own filter, simply add it to the array in the **application/filters.php** file:
'my_filter' => function()
{
return 'Filtered!';
}
### Attaching Filters To Routes
Alright, ready to attach the filter to a route? Do it like this:
'GET /user' => array('before' => 'my_filter', 'do' => function()
{
//
})
Notice the route now has an array value with two keys: **before** and **do**. The **do** value is the method that will be executed by the route, while the **before** value contains the names of any filters that should be run before the method is executed.
Why stop with one filter? You can define multiple filters for a single route by separating the filter names with commas:
'POST /user' => array('before' => 'auth, csrf', 'do' => function() {})
Remember, if a "before" filter returns a value, that value will be considered the output of the request. For example, the built-in **auth** filter checks if the user has logged in to your application. If they haven't, a [Redirect](/docs/start/views#redirect) to the login page is sent to the browser. Isn't the simplicity refreshing?
Of course, adding filters to run after the request is just as easy:
'my_filter' => function($response) {}
'GET /user' => array('after' => 'my_filter', 'do' => function() {})
> **Note:** "After" filters receive the response returned by the route function that handled the request.
<a name="organize"></a>
## Organizing Routes
So, you're building the next monolithic web application and your **application/routes.php** file is getting a little cramped? Don't worry, we have you covered.
Here's what to do. First, create an **application/routes** directory. Great! You're almost there. Now, just add route files to **application/routes** corresponding to the base URIs of your application. So, a **photo.php** file within **application/routes** would handle all requests to URIs beginning with **/photo**. Similarly, a **user.php** file handles all requests to URIs beginning with **/user**. For example, check out this **user.php** file:
<?php
return array(
'GET /user/profile/(:num)' => function($id)
{
return View::make('user/profile');
}
);
The **application/routes.php** file will continue to be loaded on every request, so any "catch-all" routes can still be placed in that file. The **application/routes.php** file should also still contain the route for the root of your application.
\ No newline at end of file
## Validation
- [The Basics](#basics)
- [Validation Rules](#rules)
- [Retrieving Error Messages](#errors)
- [Specifying Custom Error Messages](#messages)
- [Creating Custom Validation Rules](#custom)
<a name="basics"></a>
### The Basics
Almost every interactive web application needs to validate data. For instance, a registration form probably requires the password to be confirmed. Maybe the e-mail address must be unique. Validating data can be a cumbersome process. Thankfully, it isn't in Laravel. The **Validator** class provides as awesome array of validation helpers to make validating your data a breeze.
To get started, let's imagine we have the following array:
$array = array('name' => 'Taylor', 'email' => 'example@gmail.com');
Next, we're ready to define [validation rules](#rules) for our array:
$rules = array(
'name' => array('required', 'max:50'),
'email' => array('required', 'email', 'unique:users'),
);
If you don't like using arrays, you may also delimit rules using a pipe character:
$rules = array(
'name' => 'required|max:50',
'email' => 'required|email|unique:users',
);
Great! Now we're ready to make a **Validator** instance and validate our array:
$validator = Validator::make($array, $rules);
if ( ! $validator->valid())
{
return $validator->errors;
}
Via the **errors** property, you can access a simple error collector class that makes working with your error messages a breeze. Of course, default error messages have been setup for all validation rules. The default messages live in the **application/lang/en/validation.php** file.
Now you are familiar with the basic usage of the Validator class. You're ready to dig in and learn about the rules you can use to validate your data!
<a name="rules"></a>
### Validation Rules
- [Required](#rule-required)
- [Alpha, Alpha Numeric, & Alpha Dash](#rule-alphas)
- [Size](#rule-size)
- [Numericality](#rule-numeric)
- [Inclusion & Exclusion](#rule-inclusion)
- [Confirmation](#rule-confirmed)
- [Acceptance](#rule-accepted)
- [Uniqueness](#rule-unique)
- [E-Mail Addresses](#rule-email)
- [URLs](#rule-urls)
- [Uploads](#rule-uploads)
<a name="rule-required"></a>
#### Required
The **required** rule validates that an attribute is present in the array and is not an empty string:
$rules = array(
'name' => 'required',
);
<a name="rule-alphas"></a>
#### Alpha, Alpha Numeric, & Alpha Dash
The **alpha** rule validates that an attribute consists solely of letters:
$rules = array(
'name' => 'alpha',
);
The **alpha_num** rule validates that an attribute consists solely of letters and numbers:
$rules = array(
'username' => 'alpha_num',
);
The **alpha_dash** rule validates that an attribute consists solely of letters, numbers, dashes, and underscores:
$rules = array(
'username' => 'alpha_dash',
);
<a name="rule-size"></a>
#### Size
The **size** rule validates that an attribute is of a given length, or, if the attribute is numeric, is a given value:
$rules = array(
'name' => 'size:10',
);
The **between** rule validates that an attribute is between a given minimum and maximum:
$rules = array(
'payment' => 'between:10,50',
);
> **Note:** All minimum and maximum checks are inclusive.
The **min** rule validates that an attribute is greater than or equal to a given value:
$rules = array(
'payment' => 'min:10',
);
The **max** rule validates that an attribute is less than or equal to a given value:
$rules = array(
'payment' => 'max:50',
);
<a name="rule-numeric"></a>
#### Numericality
The **numeric** rule validates that an attribute is (surprise!) numeric:
$rules = array(
'payment' => 'numeric',
);
The **integer** rule validates that an attribute is an integer:
$rules = array(
'payment' => 'integer',
);
<a name="rule-inclusion"></a>
#### Inclusion & Exclusion
The **in** rule validates that an attribute is contained in a list of values:
$rules = array(
'size' => 'in:small,medium,large',
);
The **not_in** rule validates that an attribute is not contained in a list of values:
$rules = array(
'language' => 'not_in:cobol,assembler',
);
<a name="rule-confirmed"></a>
#### Confirmation
The **confirmed** rule validates that, for a given attribute, a matching **attribute_confirmation** attribute exists. For example, given the following rule:
$rules = array(
'password' => 'confirmed',
);
The Validator will make sure that the **password** attribute matches the **password_confirmation** attribute in the array being validated.
<a name="rule-accepted"></a>
#### Acceptance
The **accepted** rule validates that an attribute is equal to **yes** or **1**. This rule is helpful for validating checkbox form fields such as "terms of service".
$rules = array(
'terms' => 'accepted',
);
<a name="rule-unique"></a>
#### Uniqueness
The **unique** rule validates the uniqueness of an attribute on a given database table:
$rules = array(
'email' => 'unique:users',
);
In the example above, the **email** attribute will be checked for uniqueness on the **users** table. Need to verify uniqueness on a column name other than the attribute name? No problem:
$rules = array(
'email' => 'unique:users,email_address',
);
<a name="rule-email"></a>
#### E-Mail Addresses
The **email** rule validates that an attribute contains a correctly formatted e-mail address:
$rules = array(
'email' => 'email',
);
<a name="rule-urls"></a>
#### URLs
The **url** rule validates that an attribute contains a correctly formatted URL:
$rules = array(
'link' => 'url',
);
The **active_url** rule uses the PHP **checkdnsrr** function to verify that a URL is active:
$rules = array(
'link' => 'active_url',
);
<a name="rule-uploads"></a>
#### Uploads
The **mimes** rule validates that an uploaded file has a given MIME type. This rule uses the PHP Fileinfo extension to read the contents of the file and determine the actual MIME type. Any extension defined in the **application/config/mimes.php** file may be passed to this rule as a parameter:
$rules = array(
'picture' => 'mimes:jpg,gif',
);
$validator = Validator::make(Input::file(), $rules);
Need to validate form data and upload data at the same time? Use the **all** method on the **Input** class to get form and upload data in one array:
$validator = Validator::make(Input::all(), $rules);
The **image** rule validates that an uploaded file has a **jpg**, **gif**, **bmp**, or **png** MIME type:
$rules = array(
'picture' => 'image',
);
You may also validate the size of an upload using the **max** rule. Simply specify the maximum number of **kilobytes** the upload may be:
$rules = array(
'picture' => 'image|max:100',
);
<a name="errors"></a>
### Retrieving Error Messages
Laravel makes working with your error messages a cinch using a simple error collector class. After calling the **valid** or **invalid** method on a **Validator** instance, you may access the errors via the **errors** property:
if ( ! $validator->valid())
{
return $validator->errors;
}
The error collector has the following simple functions for retrieving your error messages: **has**, **first**, **get**, and **all**.
The **has** method will check if an error message exists for a given attribute:
if ($validator->errors->has('email'))
{
// The e-mail attribute has errors...
}
The **first** method will return the first error message for a given attribute:
echo $validator->errors->first('email');
Sometimes you may need to format the error message by wrapping it in HTML. No problem. Along with the **:message** place-holder, pass the format as the second parameter to the method:
echo $validator->errors->first('email', '<p>:message</p>');
The **get** method returns an array containing all of the error messages for a given attribute:
return $validator->errors->get('email');
return $validator->errors->get('email', '<p>:message</p>');
The **all** method returns an array containing all error messages for all attributes:
return $validator->errors->all();
return $validator->errors->all('<p>:message</p>');
<a name="messages"></a>
### Specifying Custom Error Messages
Want to use an error message other than the default? Maybe you even want to use a custom error message for a given attribute and rule. Either way, the **Validator** class makes it easy.
Simply create an array of custom messages to pass to the Validator instance:
$messages = array(
'required' => 'The :attribute field is required.',
);
$validator = Validator::make(Input::get(), $rules, $messages);
Great! Now our custom message will be used anytime a **required** validation check fails. But, what is this **:attribute** stuff in our message? To make your life easier, the Validator class will replace the **:attribute** place-holder with the actual name of the attribute! It will even remove underscores from the attribute name.
You may also use the **:size**, **:min**, **:max**, and **:values** place-holders when constructing your error messages:
$messages = array(
'size' => 'The :attribute must be exactly :size.',
'between' => 'The :attribute must be between :min - :max.',
'in' => 'The :attribute must be one of the following types: :values',
);
So, what if you need to specify a custom **required** message, but only for the **email** attribute? No problem. Just specify the message using an **attribute_rule** naming convention:
$messages = array(
'email_required' => 'We need to know your e-mail address!',
);
In the example above, the custom required message will be used for the **email** attribute, while the default message will be used for all other attributes.
<a name="custom"></a>
### Creating Custom Validation Rules
Need to create your own validation rules? You will love how easy it is! First, create a class that extends **System\Validator** and place it in your **application/libraries** directory:
<?php
class Validator extends System\Validator {}
Next, remove the **Validator** alias from **application/config/aliases.php**.
Alright! You're ready to define your own validation rule. Create a function on your new validator using a **validate_rule** naming convention. Validator methods simply need to return **true** or **false**. It couldn't be any easier, right?
<?php
class Validator extends System\Validator {
public function validate_awesome($attribute, $parameters)
{
return $attribute == 'awesome';
}
}
Let's dig into this example. The **validate_awesome** function receives two arguments. The first is the value of the attribute being validated, the second is an array of parameters that were specified for the rule, such as a size or list of accepted values (more on that in a second).
Now, how do you use your new validator? It's refreshingly simple:
$rules = array(
'username' => 'required|awesome',
);
Of course, you will need to define an error message for your new rule. You can do this either in an ad-hoc messages array:
$messages = array(
'awesome' => 'The attribute value must be awesome!',
);
$validator = Validator::make(Input::get(), $rules, $messages);
Or by adding an entry for your rule in the **application/lang/en/validation.php** file:
'awesome' => 'The attribute value must be awesome!',
As mentioned above, you may even specify and receive a list of parameters in your custom validator:
// When building your rules array...
$rules = array(
'username' => 'required|awesome:yes',
);
// In your custom validator...
class Validator extends System\Validator {
public function validate_awesome($attribute, $parameters)
{
return $attribute == $parameters[0];
}
}
In this case, the **parameters** argument of your validation rule would receive an array containing one element: "yes".
\ No newline at end of file
## Views & Responses
- [Creating Views](/docs/start/views#create)
- [Binding Data To Views](/docs/start/views#bind)
- [Nesting Views Within Views](/docs/start/views#nest)
- [Redirects](/docs/start/views#redirect)
- [Downloads](/docs/start/views#downloads)
- [Building URLs](/docs/start/views#urls)
- [Building HTML](/docs/start/views#html)
<a name="create"></a>
## Creating Views
Typically, a route function returns a **View**. Views consist of plain ole' HTML and are stored in your **application/views** directory.
A very simple view file could look like this:
<html>
Welcome to my website!
</html>
Assuming this view lives in **application/views/simple.php**, we could return it from a route like so:
'GET /home' => function()
{
return View::make('simple');
}
When building a large application, you may want to organize your views into sub-directories. That's a great idea! Assuming a view lives in **application/views/user/login.php**, we could return it like so:
'GET /home' => function()
{
return View::make('user/login');
}
It's that simple. Of course, you are not required to return a View. Strings are also welcome:
'GET /home' => function()
{
return json_encode('This is my response!');
}
<a name="bind"></a>
## Binding Data To Views
You can pass data to a view by "binding" the data to a variable. This is done using the **bind** method on the View:
'GET /home' => function()
{
return View::make('simple')->bind('email', 'example@gmail.com');
}
In the example above, the first parameter is the **name** of the view variable. The second parameter is the **value** that will be assigned to the variable.
Now, in our view, we can access the e-mail address like so:
<html>
<?php echo $email; ?>
</html>
Of course, we can bind as many variables as we wish:
'GET /home' => function()
{
return View::make('simple')
->bind('name', 'Taylor')
->bind('email', 'example@gmail.com');
}
You may also bind view data by simply setting properties on a view instance:
'GET /home' => function()
{
$view = View::make('user/login');
$view->name = 'Taylor';
$view->email = 'example@gmail.com';
return $view;
}
<a name="nest"></a>
## Nesting Views Within Views
Want to nest views inside of views? There are two ways to do it, and they are both easy. First, you can bind the view to a variable:
'GET /home' => function()
{
$view = View::make('user/login');
$view->content = View::make('partials/content');
$view->footer = View::make('partials/footer');
return $view;
}
Or, you can get the string content of a view using the **get** method:
<html>
<?php echo View::make('content')->get(); ?>
<?php echo View::make('footer')->get(); ?>
</html>
<a name="redirect"></a>
## Redirects
### Redirect Using URIs
You will often need to redirect the browser to another location within your application. The **Redirect** class makes this a piece of cake. Here's how to do it:
'GET /redirect' => function()
{
return Redirect::to('user/profile');
}
Of course, you can also redirect to the root of your application:
return Redirect::to('/');
Need to redirect to a URI that should be accessed over HTTPS? Check out the **to_secure** method:
return Redirect::to_secure('user/profile');
You can even redirect the browser to a location outside of your application:
return Redirect::to('http://www.google.com/');
<a name="named"></a>
### Redirect Using Named Routes
So far we've created redirects by specifying a URI to redirect to. But, what if the URI to the user's profile changes? It would be better to create a redirect based on the [route name](/docs/start/routes#named). Let's learn how to do it. Assuming the user profile route is named **profile**, you can redirect to the route using a dynamic, static method call like this:
return Redirect::to_profile();
Need to redirect to a route that should be accessed over HTTPS? No problem:
return Redirect::to_secure_profile();
That's great! But, what if the route URI looks like this:
'GET /user/profile/(:any)/(:any)' => array('name' => 'profile', 'do' => function()
{
//
})
You need to redirect to the named route, but you also need to replace the **(:any)** place-holders in the URI with actual values. It sounds complicated, but Laravel makes it a breeze. Just pass the parameters to the method in an array:
return Redirect::to_profile(array('taylor', 'otwell'));
The statement above will redirect the user to the following URL:
http://example.com/index.php/user/profile/taylor/otwell
<a name="with"></a>
### Redirect With Flash Data
After a user creates an account or signs into your application, it is common to display a welcome or status message. But, how can you set the status message so it is available for the next request? The **Response** and **Redirect** classes make it simple using the **with** method. This method will add a value to the Session flash data, which will be available for the next request:
return Redirect::to('user/profile')->with('status', 'Welcome Back!');
> **Note:** For more information regarding Sessions and flash data, check out the [Session documentation](/docs/session/config).
<a name="downloads"></a>
## Downloads
Perhaps you just want to force the web browser to download a file? Check out the **download** method on the **File** class:
'GET /file' => function()
{
return File::download('path/to/your/file.jpg');
}
In the example above, the image will be downloaded as "file.jpg", however, you can easily specify a different filename for the download in the second parameter to the method:
'GET /file' => function()
{
return File::download('path/to/your/file.jpg', 'photo.jpg');
}
<a name="urls"></a>
## Building URLs
- [Generating URLs Using URIs](#uri-urls)
- [Generating URLs Using Named Routes](#named-urls)
- [URL Slugs](#url-slugs)
While developing your application, you will probably need to generate a large number of URLs. Hard-coding your URLs can cause headaches if you switch domains or application locations. Nobody wants to dig through every view in their application to change URLs. Thankfully, the **URL** class provides some simple methods that allow you to easily generate URLs for your application.
<a name="uri-urls"></a>
### Generating URLs Using URIs
To generate a URL for your application, use the **to** method on the URL class:
echo URL::to();
The statement above will simply return the URL specified in your **application/config/application.php** file.
However, this method can also append a specified string to the end of your application URL:
echo URL::to('user/profile');
Now the statement will generate a URL something like this:
http://example.com/index.php/user/login
Need to generate a HTTPS URL? No problem. Check out the **to\_secure** method:
echo URL::to_secure('user/profile');
Often, you will need to generate URLs to assets such as images, scripts, or styles. You don't want "index.php" inserted into these URLs. So, use the **to_asset** method:
echo URL::to_asset('img/picture.jpg');
<a name="named-urls"></a>
### Generating URLs To Named Routes
Alright, you have learned how to generate URLs from URIs, but what about from named routes? You can do it by making a dynamic, static method call to the URL class. The syntax is beautiful:
echo URL::to_profile();
Have a route that needs to be accessed over HTTPS? No problem:
echo URL::to_secure_profile();
Could it get any easier? Now, imagine a route that is defined like this:
'GET /user/profile/(:any)/(:any)' => array('name' => 'profile', 'do' => function()
{
//
})
To generate a URL for the route, you need to replace the **(:any)** place-holders with actual values. It's easy. Just pass the parameters to the method in an array:
echo URL::to_profile(array('taylor', 'otwell'));
The method above will generate the following URL:
http://example.com/index.php/user/profile/taylor/otwell
If you don't want to use dynamic methods, you can simply call the **to_route** method:
echo URL::to_route('profile', array('taylor', 'otwell'));
<a name="url-slugs"></a>
### URL Slugs
When writing an application like a blog, it is often necessary to generate URL "slugs". Slugs are URL friendly strings of text that represent something like a blog post title. Generating slugs is a piece of cake using the **slug** method:
echo URL::slug('My blog post title!');
The statement above will return the following string:
my-blog-post-title
Want to use a different separator character? Just mention it to the method:
echo URL::slug('My blog post title!', '_');
<a name="html"></a>
## Building HTML
- [Entities](#html-entities)
- [JavaScript & Style Sheets](#html-styles)
- [Links](#html-links)
- [Links To Named Routes](#html-route-links)
- [Mail-To Links](#html-mailto)
- [Images](#html-images)
- [Lists](#html-lists)
Need some convenient methods that make writing HTML a little less painful? Introducing the **HTML** class. Enjoy.
<a name="html-entities"></a>
### Entities
When displaying user input in your Views, it is important to convert all characters which have signifance in HTML to their "entity" representation.
For example, the < symbol should be converted to its entity representation. Converting HTML characters to their entity representation helps protect your application from cross-site scripting. Thankfully, using the **entities** method on the HTML class, it's easy to add this layer of protection to your Views:
echo HTML::entities('<script>alert('hi');</script>');
<a name="html-styles"></a>
### JavaScript & Style Sheets
What trendy web application doesn't use JavaScript? Generating a reference to a JavaScript file is as simple using the **script** method.
echo HTML::script('js/scrollTo.js');
Referencing cascading style sheets is just as simple. Check out the **style method**:
echo HTML::style('css/common.css');
Need to specify a media type on your style sheet? No problem. Just pass it in the second parameter to the method:
echo HTML::style('css/common.css', 'print');
> **Note:** All scripts and stylesheets should live in the **public** directory of your application.
<a name="html-links"></a>
### Links
Generating links couldn't be easier. Just mention the URL and title to the **link** method:
echo HTML::link('user/profile', 'User Profile');
Need to generate a link to a URL that should be accessed over HTTPS? Use the **secure_link** method:
echo HTML::secure_link('user/profile', 'User Profile');
Of course, you may generate links to locations outside of your application:
echo HTML::link('http://www.google.com', 'Search the Intrawebs!');
Any other attributes that should be applied to the link may be passed in the third parameter to the method:
echo HTML::link('http://www.google.com', 'Search the Intrawebs!', array('id' => 'google'));
<a name="html-route-links"></a>
### Links To Named Routes
If you are using [named routes](#routes-named), you use intuitive, expressive syntax to create links to those routes via dynamic methods:
echo HTML::link_to_login('Login');
Or, if you need an HTTPS link:
echo HTML::link_to_secure_login('Login');
Now let's assume the **login** route is defined like this:
'GET /login/(:any)' => array('name' => 'login', 'do' => function() {})
To generate a link to the route, you need to replace the **(:any)** place-holder with an actual value. It's easy. Just pass the parameters to the method in an array:
echo HTML::link_to_login(array('user'));
This statement will generate a link to the following URL:
http://example.com/login/user
<a name="html-mailto"></a>
### Mail-To Links
It's great to allow your users to get in touch with you, but you don't want to be bombarded by spam. Laravel doesn't want you to be either. The **mailto** method allows you to create a safe mail-to link that obfuscates your e-mail address:
echo HTML::mailto('example@gmail.com');
Want the link text to be something besides your e-mail address? No problem. Just mention it to the method:
echo HTML::mailto('example@gmail.com', 'E-Mail Me!');
Need to obfuscate an e-mail address but don't want to generate an entire mail-to link? Simply pass the e-mail address to the **email** method:
echo HTML::email('example@gmail.com');
<a name="html-images"></a>
### Images
Since you're building a creative application, you will need to include some images. The **image** method makes simple. Just pass the URL and Alt text to the method:
echo HTML::image('img/smile.jpg', 'A Smiling Face');
Like the link method, any other attributes that should be applied to the image may be passed in the third parameter to the method:
echo HTML::image('img/smile.jpg', 'A Smiling Face', array('id' => 'smile'));
<a name="html-lists"></a>
### Lists
Generating HTML lists doesn't have to be a headache. Check out the **ol** method. All it needs is an array of items:
echo HTML::ol(array('Get Peanut Butter', 'Get Chocolate', 'Feast'));
As usual, you may specify any other attributes that should be applied to the list:
echo HTML::ol(array('Get Peanut Butter', 'Get Chocolate', 'Feast'), array('class' => 'awesome'));
Need an un-ordered list? No problem. Just use the **ul** method:
echo HTML::ul(array('Ubuntu', 'Snow Leopard', 'Windows'));
\ No newline at end of file
<?php
// --------------------------------------------------------------
// Define the framework paths.
// --------------------------------------------------------------
define('BASE_PATH', realpath('../').'/');
define('APP_PATH', realpath('../application').'/');
define('SYS_PATH', realpath('../system').'/');
define('PUBLIC_PATH', realpath('../public').'/');
define('PACKAGE_PATH', APP_PATH.'packages/');
// --------------------------------------------------------------
// Define the PHP file extension.
// --------------------------------------------------------------
define('EXT', '.php');
// --------------------------------------------------------------
// Load the classes used by the auto-loader.
// --------------------------------------------------------------
require SYS_PATH.'config'.EXT;
require SYS_PATH.'arr'.EXT;
// --------------------------------------------------------------
// Load the test utilities.
// --------------------------------------------------------------
require 'utils'.EXT;
// --------------------------------------------------------------
// Register the auto-loader.
// --------------------------------------------------------------
spl_autoload_register(require SYS_PATH.'loader'.EXT);
\ No newline at end of file
<phpunit colors="true" bootstrap="bootstrap.php">
<testsuites>
<testsuite name="Laravel Tests">
<directory>suite</directory>
</testsuite>
</testsuites>
</phpunit>
\ No newline at end of file
<?php
class ArrTest extends PHPUnit_Framework_TestCase {
public function testReturnsDefaultWhenItemNotPresentInArray()
{
$this->assertNull(System\Arr::get(array(), 'name'));
$this->assertEquals(System\Arr::get(array(), 'name', 'test'), 'test');
$this->assertEquals(System\Arr::get(array(), 'name', function() {return 'test';}), 'test');
}
public function testReturnsItemWhenPresentInArray()
{
$this->assertEquals(System\Arr::get(array('name' => 'test'), 'name'), 'test');
}
}
\ No newline at end of file
<?php
class InputTest extends PHPUnit_Framework_TestCase {
public static function setUpBeforeClass()
{
System\Input::$input = null;
}
public static function tearDownAfterClass()
{
System\Config::set('session.driver', '');
System\Session::$session = array();
}
public function setUp()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
}
public function tearDown()
{
System\Input::$input = null;
}
/**
* @dataProvider inputByMethodProvider
*/
public function testInputShouldHydrateBasedOnRequestMethod($method, $data)
{
$_SERVER['REQUEST_METHOD'] = $method;
$_GET = $data;
$_POST = $data;
$this->assertEquals(System\Input::get(), $data);
}
public function inputByMethodProvider()
{
return array(
array('GET', array('method' => 'GET')),
array('POST', array('method' => 'POST')),
);
}
/**
* @dataProvider inputBySpoofedMethodProvider
*/
public function testInputShouldHydrateBasedOnSpoofedRequestMethod($method, $data)
{
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST = $data;
$this->assertEquals(System\Input::get(), $data);
}
public function inputBySpoofedMethodProvider()
{
return array(
array('PUT', array('request_method' => 'PUT', 'method' => 'PUT')),
array('DELETE', array('request_method' => 'DELETE', 'method' => 'DELETE')),
);
}
public function testHasMethodReturnsTrueIfItemIsPresentInInputData()
{
System\Input::$input = array('name' => 'taylor');
$this->assertTrue(System\Input::has('name'));
}
public function testHasMethodReturnsFalseIfItemIsNotPresentInInputData()
{
System\Input::$input = array();
$this->assertFalse(System\Input::has('name'));
}
public function testHasMethodReturnsFalseIfItemIsInInputButIsEmptyString()
{
System\Input::$input = array('name' => '');
$this->assertFalse(System\Input::has('name'));
}
public function testGetMethodReturnsItemByInputKey()
{
System\Input::$input = array('name' => 'taylor');
$this->assertEquals(System\Input::get('name'), 'taylor');
}
public function testGetMethodReturnsDefaultValueWhenItemDoesntExist()
{
System\Input::$input = array();
$this->assertNull(System\Input::get('name'));
$this->assertEquals(System\Input::get('name', 'test'), 'test');
$this->assertEquals(System\Input::get('name', function() {return 'test';}), 'test');
$this->assertTrue(is_array(System\Input::get()) and count(System\Input::get()) == 0);
}
public function testGetMethodReturnsEntireInputArrayWhenNoKeyGiven()
{
System\Input::$input = array('name' => 'taylor', 'age' => 25);
$this->assertEquals(System\Input::get(), System\Input::$input);
}
public function testFileMethodReturnsItemFromGlobalFilesArray()
{
$_FILES['test'] = array('name' => 'taylor');
$this->assertEquals(System\Input::file('test'), $_FILES['test']);
}
public function testFileMethodReturnsSpecificItemFromFileArrayWhenSpecified()
{
$_FILES['test'] = array('size' => 500);
$this->assertEquals(System\Input::file('test.size'), 500);
}
public function testAllMethodReturnsBothGetAndFileArrays()
{
$_GET['name'] = 'test';
$_FILES['picture'] = array();
$this->assertArrayHasKey('name', System\Input::all());
$this->assertArrayHasKey('picture', System\Input::all());
}
/**
* @expectedException Exception
*/
public function testOldMethodShouldThrowExceptionWhenSessionsArentEnabled()
{
System\Input::old();
}
/**
* @expectedException Exception
*/
public function testHadMethodShouldThrowExceptionWhenSessionsArentEnabled()
{
System\Input::has();
}
public function testOldMethodShouldReturnOldInputDataFromSession()
{
System\Config::set('session.driver', 'test');
System\Session::$session['data']['laravel_old_input'] = array('name' => 'taylor');
$this->assertEquals(System\Input::old('name'), 'taylor');
}
public function testOldMethodReturnsDefaultValueWhenItemDoesntExist()
{
System\Config::set('session.driver', 'test');
System\Session::$session['data']['laravel_old_input'] = array();
$this->assertNull(System\Input::old('name'));
$this->assertEquals(System\Input::old('name', 'test'), 'test');
$this->assertEquals(System\Input::old('name', function() {return 'test';}), 'test');
$this->assertTrue(is_array(System\Input::old()) and count(System\Input::old()) == 0);
}
public function testHadMethodReturnsTrueIfItemIsPresentInOldInputData()
{
System\Config::set('session.driver', 'test');
System\Session::$session['data']['laravel_old_input'] = array('name' => 'taylor');
$this->assertTrue(System\Input::had('name'));
}
public function testHadMethodReturnsFalseIfItemIsNotPresentInOldInputData()
{
System\Config::set('session.driver', 'test');
System\Session::$session['data']['laravel_old_input'] = array();
$this->assertFalse(System\Input::had('name'));
}
}
\ No newline at end of file
<?php
class RequestTest extends PHPUnit_Framework_TestCase {
public function setUp()
{
unset($_SERVER['PATH_INFO'], $_SERVER['REQUEST_METHOD']);
$route = new System\Route(null, null);
$route->callback = array('name' => 'test', 'do' => function() {});
System\Request::$route = $route;
}
public function tearDown()
{
System\Request::$route = null;
}
/**
* @expectedException Exception
*/
public function testUriMethodThrowsExceptionWhenCantDetermineUri()
{
System\Request::uri();
}
public function testUriMethodReturnsPathInfoWhenSet()
{
$_SERVER['PATH_INFO'] = 'test';
$_SERVER['REQUEST_METHOD'] = 'blah';
$this->assertEquals(System\Request::uri(), 'test');
}
/**
* @dataProvider rootUriProvider1
*/
public function testUriMethodReturnsSingleSlashOnRequestForRoot($uri)
{
Config::set('application.url', 'http://example.com');
Config::set('appliation.index', '');
$_SERVER['REQUEST_URI'] = $uri;
$this->assertEquals(System\Request::uri(), '/');
}
public function rootUriProvider1()
{
return array(
array(''),
array('/'),
array('/index.php'),
array('/index.php/'),
array('/index.php///'),
array('http://example.com'),
array('http://example.com/'),
);
}
/**
* @dataProvider rootUriProvider2
*/
public function testUriMethodReturnsSingleSlashOnRequestForFolderNestedRoot($uri)
{
Config::set('application.url', 'http://example.com/laravel/public');
Config::set('appliation.index', 'index.php');
$_SERVER['REQUEST_URI'] = $uri;
$this->assertEquals(System\Request::uri(), '/');
}
public function rootUriProvider2()
{
return array(
array('http://example.com/laravel/public'),
array('http://example.com/laravel/public/index.php'),
array('http://example.com/laravel/public/index.php/'),
array('http://example.com/laravel/public/index.php///'),
array(''),
array('/'),
array('/index.php'),
array('/index.php/'),
array('/index.php///'),
array('http://example.com'),
array('http://example.com/'),
);
}
/**
* @dataProvider segmentedUriProvider1
*/
public function testUriMethodReturnsSegmentForSingleSegmentUri($uri)
{
Config::set('application.url', 'http://example.com');
Config::set('appliation.index', '');
$_SERVER['REQUEST_URI'] = $uri;
$this->assertEquals(System\Request::uri(), 'user');
}
public function segmentedUriProvider1()
{
return array(
array('http://example.com/user'),
array('http://example.com/user/'),
array('http://example.com/user//'),
);
}
/**
* @dataProvider segmentedUriProvider2
*/
public function testUriMethodReturnsSegmentsForMultiSegmentUri($uri)
{
Config::set('application.url', 'http://example.com');
Config::set('appliation.index', '');
$_SERVER['REQUEST_URI'] = $uri;
$this->assertEquals(System\Request::uri(), 'user/something');
}
public function segmentedUriProvider2()
{
return array(
array('http://example.com/user/something'),
array('http://example.com/user/something/'),
array('http://example.com/user/something//'),
);
}
public function testMethodForNonSpoofedRequests()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$this->assertEquals(System\Request::method(), 'GET');
}
public function testMethodForSpoofedRequests()
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_POST['REQUEST_METHOD'] = 'PUT';
$this->assertEquals(System\Request::method(), 'PUT');
$_POST['REQUEST_METHOD'] = 'DELETE';
$this->assertEquals(System\Request::method(), 'DELETE');
}
public function testRouteIsReturnsFalseWhenNoSuchNamedRouteExists()
{
$route = new System\Route(null, null);
$route->callback = function() {};
System\Request::$route = $route;
$this->assertFalse(System\Request::route_is('test'));
$this->assertFalse(System\Request::route_is_test());
}
public function testRouteIsReturnsFalseWhenWrongRouteNameIsGiven()
{
$this->assertFalse(System\Request::route_is('something'));
$this->assertFalse(System\Request::route_is_something());
}
public function testRouteIsReturnsTrueWhenNamedRouteExists()
{
$this->assertTrue(System\Request::route_is('test'));
$this->assertTrue(System\Request::route_is_test());
}
}
\ No newline at end of file
<?php
class RouteFilerTest extends PHPUnit_Framework_TestCase {
public static function setUpBeforeClass()
{
$filters = array(
'test' => function() {return 'test';},
'vars' => function($var) {return $var;},
'vars2' => function($var1, $var2) {return $var1.$var2;},
);
System\Route\Filter::$filters = $filters;
}
public static function tearDownAfterClass()
{
System\Route\Filter::$filters = require APP_PATH.'filters'.EXT;
}
/**
* @expectedException Exception
*/
public function testCallingUndefinedFilterThrowsException()
{
System\Route\Filter::call('not-found');
}
public function testCallingFilterWithoutOverrideReturnsNull()
{
$this->assertNull(System\Route\Filter::call('test'));
}
public function testCallingFilterWithOverrideReturnsResult()
{
$this->assertEquals(System\Route\Filter::call('test', array(), true), 'test');
}
public function testCallingFilterWithParametersPassesParametersToFilter()
{
$this->assertEquals(System\Route\Filter::call('vars', array('test'), true), 'test');
$this->assertEquals(System\Route\Filter::call('vars2', array('test1', 'test2'), true), 'test1test2');
}
}
\ No newline at end of file
<?php
class RouteFinderTest extends PHPUnit_Framework_TestCase {
public static function setUpBeforeClass()
{
$routes = array();
$routes['GET /home'] = array('GET /home' => array('name' => 'home', 'do' => function() {}));
$routes['GET /user'] = array('GET /user' => array('name' => 'user', 'do' => function() {}));
System\Route\Finder::$routes = $routes;
}
public function testRouteFinderReturnsNullWhenRouteIsNotFound()
{
$this->assertNull(System\Route\Finder::find('doesnt-exist'));
}
public function testRouteFinderReturnsRouteWhenFoundInSingleRoutesFile()
{
$this->assertArrayHasKey('GET /home', System\Route\Finder::find('home'));
$this->assertArrayHasKey('GET /user', System\Route\Finder::find('user'));
}
public function testRouteFinderLoadsRoutesFromRouteDirectoryToFindRoutes()
{
System\Route\Finder::$routes = null;
$this->setupRoutesDirectory();
$this->assertArrayHasKey('GET /user', System\Route\Finder::find('user'));
Utils::rrmdir(APP_PATH.'routes');
}
private function setupRoutesDirectory()
{
mkdir(APP_PATH.'routes', 0777);
file_put_contents(APP_PATH.'routes/user.php', "<?php return array('GET /user' => array('name' => 'user', 'do' => function() {return '/user';})); ?>", LOCK_EX);
}
}
\ No newline at end of file
<?php
class RouteTest extends PHPUnit_Framework_TestCase {
public function testSimpleRouteCallbackReturnsResponseInstance()
{
$route = new System\Route('GET /', function() {return 'test';});
$this->assertInstanceOf('System\\Response', $route->call());
$this->assertEquals($route->call()->content, 'test');
}
public function testRouteCallPassesParametersToCallback()
{
$route = new System\Route('GET /', function($parameter) {return $parameter;}, array('test'));
$this->assertEquals($route->call()->content, 'test');
$route = new System\Route('GET /', function($parameter1, $parameter2) {return $parameter1.$parameter2;}, array('test1', 'test2'));
$this->assertEquals($route->call()->content, 'test1test2');
}
public function testRouteCallWithNullBeforeFilterReturnsRouteResponse()
{
$route = new System\Route('GET /', array('before' => 'test', 'do' => function() {return 'route';}));
System\Route\Filter::$filters = array('test' => function() {return null;});
$this->assertEquals($route->call()->content, 'route');
}
public function testRouteCallWithOverridingBeforeFilterReturnsFilterResponse()
{
$route = new System\Route('GET /', array('before' => 'test', 'do' => function() {return 'route';}));
System\Route\Filter::$filters = array('test' => function() {return 'filter';});
$this->assertEquals($route->call()->content, 'filter');
}
public function testRouteAfterFilterIsCalled()
{
$route = new System\Route('GET /', array('after' => 'test', 'do' => function() {return 'route';}));
System\Route\Filter::$filters = array('test' => function() {define('LARAVEL_TEST_AFTER_FILTER', 'ran');});
$route->call();
$this->assertTrue(defined('LARAVEL_TEST_AFTER_FILTER'));
}
public function testRouteAfterFilterDoesNotAffectResponse()
{
$route = new System\Route('GET /', array('after' => 'test', 'do' => function() {return 'route';}));
System\Route\Filter::$filters = array('test' => function() {return 'filter';});
$this->assertEquals($route->call()->content, 'route');
}
}
\ No newline at end of file
<?php
class RoutingTest extends PHPUnit_Framework_TestCase {
public static function setUpBeforeClass()
{
$routes = array();
$routes['GET /'] = array('name' => 'root', 'do' => function() {});
$routes['GET /home'] = array('name' => 'home', 'do' => function() {});
$routes['POST /home'] = array('name' => 'post-home', 'do' => function() {});
$routes['GET /user/(:num)'] = array('name' => 'user', 'do' => function() {});
$routes['GET /user/(:any)/(:num)/edit'] = array('name' => 'edit', 'do' => function() {});
$routes['GET /cart/(:num?)'] = array('name' => 'cart', 'do' => function() {});
$routes['GET /download/(:num?)/(:any?)'] = array('name' => 'download', 'do' => function() {});
System\Router::$routes = $routes;
}
public static function tearDownAfterClass()
{
System\Router::$routes = null;
}
public function tearDown()
{
Utils::rrmdir(APP_PATH.'routes');
}
public function testRouterReturnsNullWhenNotFound()
{
$this->assertNull(System\Router::route('GET', 'doesnt-exist'));
}
public function testRouterRoutesToRootWhenItIsRequest()
{
$this->assertEquals(System\Router::route('GET', '/')->callback['name'], 'root');
}
public function testRouterRoutesToProperRouteWhenSegmentsArePresent()
{
$this->assertEquals(System\Router::route('GET', 'home')->callback['name'], 'home');
$this->assertEquals(System\Router::route('GET', 'user/1')->callback['name'], 'user');
$this->assertEquals(System\Router::route('GET', 'user/taylor/25/edit')->callback['name'], 'edit');
$this->assertEquals(System\Router::route('POST', 'home')->callback['name'], 'post-home');
}
public function testRouterGivesRouteProperSegmentsWhenTheyArePresent()
{
$this->assertEquals(System\Router::route('GET', 'user/1')->parameters[0], 1);
$this->assertEquals(count(System\Router::route('GET', 'user/1')->parameters), 1);
$this->assertEquals(System\Router::route('GET', 'user/taylor/25/edit')->parameters[0], 'taylor');
$this->assertEquals(System\Router::route('GET', 'user/taylor/25/edit')->parameters[1], 25);
$this->assertEquals(count(System\Router::route('GET', 'user/taylor/25/edit')->parameters), 2);
}
public function testRouterRoutesToProperRouteWhenUsingOptionalSegments()
{
$this->assertEquals(System\Router::route('GET', 'cart')->callback['name'], 'cart');
$this->assertEquals(System\Router::route('GET', 'cart/1')->callback['name'], 'cart');
$this->assertEquals(System\Router::route('GET', 'download')->callback['name'], 'download');
$this->assertEquals(System\Router::route('GET', 'download/1')->callback['name'], 'download');
$this->assertEquals(System\Router::route('GET', 'download/1/a')->callback['name'], 'download');
}
public function testRouterGivesRouteProperOptionalSegmentsWhenTheyArePresent()
{
$this->assertTrue(is_array(System\Router::route('GET', 'cart')->parameters));
$this->assertEquals(count(System\Router::route('GET', 'cart')->parameters), 0);
$this->assertEquals(System\Router::route('GET', 'cart/1')->parameters[0], 1);
$this->assertEquals(count(System\Router::route('GET', 'download')->parameters), 0);
$this->assertEquals(System\Router::route('GET', 'download/1')->parameters[0], 1);
$this->assertEquals(count(System\Router::route('GET', 'download/1')->parameters), 1);
$this->assertEquals(System\Router::route('GET', 'download/1/a')->parameters[0], 1);
$this->assertEquals(System\Router::route('GET', 'download/1/a')->parameters[1], 'a');
$this->assertEquals(count(System\Router::route('GET', 'download/1/a')->parameters), 2);
}
public function testRouterReturnsNullWhenRouteNotFound()
{
$this->assertNull(System\Router::route('GET', 'user/taylor/taylor/edit'));
$this->assertNull(System\Router::route('GET', 'user/taylor'));
$this->assertNull(System\Router::route('GET', 'user/12-3'));
$this->assertNull(System\Router::route('GET', 'cart/a'));
$this->assertNull(System\Router::route('GET', 'cart/12-3'));
$this->assertNull(System\Router::route('GET', 'download/a'));
$this->assertNull(System\Router::route('GET', 'download/1a'));
$this->assertNull(System\Router::route('POST', 'user/taylor/25/edit'));
}
public function testRouteLoaderShouldReturnSingleRoutesFileWhenNoFolderIsPresent()
{
$routes = System\Router::load('test');
// Only the Laravel default route should be returned.
$this->assertArrayHasKey('GET /', $routes);
}
public function testRouteLoaderLoadsRouteFilesInRouteDirectoryByURI()
{
$this->setupRoutesDirectory();
$this->assertArrayHasKey('GET /user', System\Router::load('user'));
$this->assertArrayHasKey('GET /cart/edit', System\Router::load('cart'));
$this->assertArrayHasKey('GET /cart/edit', System\Router::load('cart/edit'));
}
public function testRouteLoaderLoadsBaseRoutesFileForEveryRequest()
{
$this->setupRoutesDirectory();
$this->assertArrayHasKey('GET /', System\Router::load('user'));
}
private function setupRoutesDirectory()
{
mkdir(APP_PATH.'routes', 0777);
file_put_contents(APP_PATH.'routes/user.php', "<?php return array('GET /user' => function() {return '/user';}); ?>", LOCK_EX);
file_put_contents(APP_PATH.'routes/cart.php', "<?php return array('GET /cart/edit' => function() {return '/cart/edit';}); ?>", LOCK_EX);
}
}
\ No newline at end of file
<?php
class ViewTest extends PHPUnit_Framework_TestCase {
public function testConstructorSetsViewNameAndData()
{
$view = new System\View('view', array('name' => 'test'));
$this->assertEquals($view->view, 'view');
$this->assertEquals($view->data, array('name' => 'test'));
$view = new System\View('view');
$this->assertEquals($view->data, array());
}
public function testMakeMethodReturnsNewViewInstance()
{
$this->assertInstanceOf('System\\View', System\View::make('test'));
}
public function testBindMethodAddsItemToViewData()
{
$view = System\View::make('test')->bind('name', 'test');
$this->assertEquals($view->data, array('name' => 'test'));
}
public function testBoundViewDataCanBeRetrievedThroughMagicMethods()
{
$view = System\View::make('test')->bind('name', 'test');
$this->assertTrue(isset($view->name));
$this->assertEquals($view->name, 'test');
unset($view->name);
$this->assertFalse(isset($view->name));
}
public function testGetMethodReturnsStringContentOfView()
{
$this->assertTrue(is_string(System\View::make('home/index')->get()));
}
/**
* @expectedException Exception
*/
public function testExceptionIsThrownWhenViewDoesntExist()
{
System\View::make('doesnt-exist')->get();
}
}
\ No newline at end of file
<?php
class Utils {
/**
* Recursively remove a directory.
*
* @param string $directory
* @return void
*/
public static function rrmdir($directory)
{
if (is_dir($directory))
{
$objects = scandir($directory);
foreach ($objects as $object)
{
if ($object != "." && $object != "..")
{
if (filetype($directory."/".$object) == "dir") static::rrmdir($directory."/".$object); else unlink($directory."/".$object);
}
}
reset($objects);
rmdir($directory);
}
}
}
\ No newline at end of file
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