+ @stop
+
+注意一个Blade布局的扩展视图简单地在布局中替换了模板片段。通过在模板片段中使用 `@parent` 指令,布局的内容可以被包含在一个子视图中,这样你就可以在布局片段中添加诸如侧边栏、底部信息的内容。
+
+
+## 其他 Blade模板 控制结构
+
+**输出数据**
+
+ Hello, {{ $name }}.
+
+ The current UNIX timestamp is {{ time() }}.
+
+If you need to display a string that is wrapped in curly braces, you may escape the Blade behavior by prefixing your text with an `@` symbol:
+
+**Displaying Raw Text With Curly Braces**
+
+ @{{ This will not be processed by Blade }}
+
+你可以使用三联大括号语法来避免输出:
+
+ Hello, {{{ $name }}}.
+
+**If 声明**
+
+ @if (count($records) === 1)
+ I have one record!
+ @elseif (count($records) > 1)
+ I have multiple records!
+ @else
+ I don't have any records!
+ @endif
+
+ @unless (Auth::check())
+ You are not signed in.
+ @endunless
+
+**循环**
+
+ @for ($i = 0; $i < 10; $i++)
+ The current value is {{ $i }}
+ @endfor
+
+ @foreach ($users as $user)
+
') as $message)
+ {
+ //
+ }
+
+
+## 错误消息 & 视图
+
+一旦你执行了验证,你需要一种简单的方法向视图反馈错误消息。这在 Lavavel 中能够方便的处理。以下面的路由作为例:
+
+ Route::get('register', function()
+ {
+ return View::make('user.register');
+ });
+
+ Route::post('register', function()
+ {
+ $rules = array(...);
+
+ $validator = Validator::make(Input::all(), $rules);
+
+ if ($validator->fails())
+ {
+ return Redirect::to('register')->withErrors($validator);
+ }
+ });
+
+注意当验证失败,我们使用 `withErrors` 函数把 `Validator` 实例传递给 Redirect。这个函数将刷新 Session 中保存的错误消息,使得它们在下次请求中可用。
+
+然而,请注意在我们的 GET 路由中并没有明确的绑定错误消息到视图。这是因为 Laravel 总会检查 Session 中的错误,并且如果它们是可用的将自动绑定到视图。**所以,需要特别注意的是,对于每个请求,一个 `$errors` 变量在所有视图中总是可用的**,允许你方便的认为 `$errors` 变量总是被定义并可以安全使用的。`$errors` 变量将是一个 `MessageBag` 类的实例。
+
+所以,在跳转之后,你可以在视图中使用自动绑定的 `$errors` 变量:
+
+ first('email'); ?>
+
+
+## 可用的验证规则
+
+下面是一个所有可用的验证规则的列表以及它们的功能:
+
+- [Accepted](#rule-accepted)
+- [Active URL](#rule-active-url)
+- [After (Date)](#rule-after)
+- [Alpha](#rule-alpha)
+- [Alpha Dash](#rule-alpha-dash)
+- [Alpha Numeric](#rule-alpha-num)
+- [Before (Date)](#rule-before)
+- [Between](#rule-between)
+- [Confirmed](#rule-confirmed)
+- [Date](#rule-date)
+- [Date Format](#rule-date-format)
+- [Different](#rule-different)
+- [Digits](#rule-digits)
+- [Digits Between](#rule-digitsbetween)
+- [E-Mail](#rule-email)
+- [Exists (Database)](#rule-exists)
+- [Image (File)](#rule-image)
+- [In](#rule-in)
+- [Integer](#rule-integer)
+- [IP Address](#rule-ip)
+- [Max](#rule-max)
+- [MIME Types](#rule-mimes)
+- [Min](#rule-min)
+- [Not In](#rule-not-in)
+- [Numeric](#rule-numeric)
+- [Regular Expression](#rule-regex)
+- [Required](#rule-required)
+- [Required If](#rule-required-if)
+- [Required With](#rule-required-with)
+- [Required Without](#rule-required-without)
+- [Same](#rule-same)
+- [Size](#rule-size)
+- [Unique (Database)](#rule-unique)
+- [URL](#rule-url)
+
+
+#### accepted
+
+验证此规则的值必须是 _yes_、 _on_ 或者是 _1_。这在验证是否同意"服务条款"的时候非常有用。
+
+
+#### active_url
+
+验证此规则的值必须是一个合法的 URL,根据 PHP 函数 `checkdnsrr`。
+
+
+#### after:_date_
+
+验证此规则的值必须在给定日期之后,该日期将被传递到 PHP 的 `strtotime` 函数。
+
+
+#### alpha
+
+验证此规则的值必须全部由字母字符构成。
+
+
+#### alpha_dash
+
+验证此规则的值必须全部由字母、数字、中划线或下划线字符构成。
+
+
+#### alpha_num
+
+验证此规则的值必须全部由字母和数字构成。
+
+
+#### before:_date_
+
+验证此规则的值必须在给定日期之前,该日期将被传递到 PHP 的 `strtotime` 函数。
+
+
+#### between:_min_,_max_
+
+验证此规则的值必须在给定的 _min_ 和 _max_ 之间。字符串、数字以及文件都将使用大小规则进行比较。
+
+
+#### confirmed
+
+验证此规则的值必须和 `foo_confirmation` 的值相同。比如,需要验证此规则的字段是 `password`,那么在输入中必须有一个与之相同的 `password_confirmation` 字段。
+
+
+#### date
+
+验证此规则的值必须是一个合法的日期,根据 PHP 函数 `strtotime`。
+
+
+#### date_format:_format_
+
+验证此规则的值必须符合给定的 _format_ 的格式,根据 PHP 函数 `date_parse_from_format`。
+
+
+#### different:_field_
+
+验证此规则的值必须与指定的 _field_ 字段的值不同。
+
+
+#### digits:_value_
+
+The field under validation must be _numeric_ and must have an exact length of _value_.
+
+
+#### digitsbetween:_min_,_max_
+
+The field under validation must have a length between the given _min_ and _max_.
+
+
+#### email
+
+验证此规则的值必须是一个合法的电子邮件地址。
+
+
+#### exists:_table_,_column_
+
+验证此规则的值必须在指定的数据库的表中存在。
+
+**Exists 规则的基础使用**
+
+ 'state' => 'exists:states'
+
+**指定列名**
+
+ 'state' => 'exists:states,abbreviation'
+
+你也可以指定更多的条件,将以 "where" 的形式添加到查询。
+
+ 'email' => 'exists:staff,email,account_id,1'
+
+
+#### image
+
+验证此规则的值必须是一个图片 (jpeg, png, bmp 或者 gif)。
+
+
+#### in:_foo_,_bar_,...
+
+验证此规则的值必须在给定的列表中存在。
+
+
+#### integer
+
+验证此规则的值必须是一个整数。
+
+
+#### ip
+
+验证此规则的值必须是一个合法的 IP 地址。
+
+
+#### max:_value_
+
+验证此规则的值必须小于最大值 _value_。字符串、数字以及文件都将使用大小规则进行比较。
+
+
+#### mimes:_foo_,_bar_,...
+
+验证此规则的文件的 MIME 类型必须在给定的列表中。
+
+**MIME 规则的基础使用**
+
+ 'photo' => 'mimes:jpeg,bmp,png'
+
+
+#### min:_value_
+
+验证此规则的值必须大于最小值 _value_。字符串、数字以及文件都将使用大小规则进行比较。
+
+
+#### not_in:_foo_,_bar_,...
+
+验证此规则的值必须在给定的列表中不存在。
+
+
+#### numeric
+
+验证此规则的值必须是一个数字。
+
+
+#### regex:_pattern_
+
+验证此规则的值必须符合给定的正则表达式。
+
+**注意:** 当使用 `regex` 模式的时候,可能需要在一个数组中指定规则,而不是使用 "|" 分隔符,特别是正则表达式中包含一个 "|" 字符的时候。
+
+
+#### required
+
+验证此规则的值必须在输入数据中存在。
+
+
+#### required_if:_field_,_value_
+
+如果指定的 _field_ 字段等于指定的 _value_ ,那么验证此规则的值必须存在。
+
+
+#### required_with:_foo_,_bar_,...
+
+_仅当_其它指定的字段存在的时候,验证此规则的值必须存在。
+
+
+#### required_without:_foo_,_bar_,...
+
+_仅当_其它指定的字段不存在的时候,验证此规则的值必须存在。
+
+
+#### same:_field_
+
+验证此规则的值必须与给定的 _field_ 字段的值相同。
+
+
+#### size:_value_
+
+验证此规则的值的大小必须与给定的 _value_ 相同。对于字符串,_value_ 代表字符的个数;对于数字,_value_ 代表它的整数值,对于文件,_value_ 代表文件以KB为单位的大小。
+
+
+#### unique:_table_,_column_,_except_,_idColumn_
+
+验证此规则的值必须在给定的数据库的表中唯一。如果 `column` 没有被指定,将使用该字段的名字。
+
+**Unique 规则的基础使用**
+
+ 'email' => 'unique:users'
+
+**指定列名**
+
+ 'email' => 'unique:users,email_address'
+
+**强制忽略一个给定的 ID**
+
+ 'email' => 'unique:users,email_address,10'
+
+**添加额外的where语句**
+
+你还可以指定更多条件,这些条件将被添加到查询的"where"语句中:
+
+ 'email' => 'unique:users,email_address,NULL,id,account_id,1'
+
+在上面的规则中,只有`account_id` 为 `1` 的行才会被包含到unique检查中。
+
+
+#### url
+
+验证此规则的值必须是一个合法的 URL。
+
+
+## 有条件的添加规则
+
+有时你可能希望给定的字段仅当另一个字段的值大于100的时候必须存在。或者你可能需要两个字段均含有一个给定的值,仅当另一个字段存在的时候。添加这些验证规则并没有那么麻烦。首先,创建一个使用你永远不会改变的 _static rules_ 的 `Validator` 实例:
+
+ $v = Validator::make($data, array(
+ 'email' => 'required|email',
+ 'games' => 'required|numeric',
+ ));
+
+假设我们的WEB应用程序是服务于游戏收藏爱好者们。如果一个游戏收藏爱好者注册了我们的应用程序,并且他们拥有100多款游戏,我们想让他们说明为什么他们会拥有如此多的游戏。例如,或许他们要开一个游戏转售店,或者也许他们只是喜欢收集。为了有条件的添加这个需求,我们可以使用 `Validator` 实例的 `sometimes` 函数。
+
+ $v->sometimes('reason', 'required|max:500', function($input)
+ {
+ return $input->games >= 100;
+ });
+
+`sometimes` 函数的第一个参数是我们有条件的验证的字段名。第二个参数是我们要添加的规则。如果 `Closure` 作为第三个参数且返回了 `true`,规则将被添加。这种方法可以很容易构建复杂的条件验证。你甚至可以一次性为多个字段添加条件验证:
+
+ $v->sometimes(array('reason', 'cost'), 'required', function($input)
+ {
+ return $input->games >= 100;
+ });
+
+> **注意:** 传递到你的 `Closure` 中的 `$input` 参数将被作为 `Illuminate\Support\Fluent` 的一个实例,并且可能被用作一个对象来访问你的输入和文件。
+
+
+## 自定义错误消息
+
+如果有需要,你可以使用自定义的错误消息代替默认的消息。这里有好几种自定义错误消息的方法。
+
+**传递自定义消息到验证器**
+
+ $messages = array(
+ 'required' => 'The :attribute field is required.',
+ );
+
+ $validator = Validator::make($input, $rules, $messages);
+
+*注意:* `:attribute` 占位符将被实际要验证的字段名替换,你也可以在错误消息中使用其他占位符。
+
+**其他验证占位符**
+
+ $messages = array(
+ 'same' => 'The :attribute and :other must match.',
+ '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',
+ );
+
+有些时候,你可能希望只对一个指定的字段指定自定义的错误消息:
+
+**对一个指定的字段指定自定义的错误消息**
+
+ $messages = array(
+ 'email.required' => 'We need to know your e-mail address!',
+ );
+
+在一些情况下,你可能希望在一个语言文件中指定你的错误消息而不是直接传递给 `Validator`。为了实现这个目的,请在 `app/lang/xx/validation.php` 文件中添加你的自定义消息到 `custom` 数组。
+
+
+**在语言文件中指定错误消息**
+
+ 'custom' => array(
+ 'email' => array(
+ 'required' => 'We need to know your e-mail address!',
+ ),
+ ),
+
+
+## 自定义验证规则
+
+Laravel 提供了一系列有用的验证规则;但是,你可能希望添加自己的验证规则。其中一种方法是使用 `Validator::extend` 函数注册自定义的验证规则:
+
+**注册一个自定义的验证规则**
+
+ Validator::extend('foo', function($attribute, $value, $parameters)
+ {
+ return $value == 'foo';
+ });
+
+自定义的验证器接受三个参数:待验证属性的名字、待验证属性的值以及传递给这个规则的参数。
+
+你也可以传递一个类的函数到 `extend` 函数,而不是使用闭包:
+
+ Validator::extend('foo', 'FooValidator@validate');
+
+注意你需要为你的自定义规则定义错误消息。你既可以使用一个行内的自定义消息数组,也可以在验证语言文件中进行添加。
+
+你也可以扩展 `Validator` 类本身,而不是使用闭包回调扩展验证器。为了实现这个目的,添加一个继承自 `Illuminate\Validation\Validator` 的验证器类。你可以在类中添加以 `validate` 开头的验证函数:
+
+**扩展验证器类**
+
+
## Environment Configuration
@@ -54,6 +56,8 @@ Next, we need to instruct the framework how to determine which environment it is
));
+In this example, 'local' is the name of the environment and 'your-machine-name' is the hostname of your server. On Linux and Mac, you may determine your hostname using the `hostname` terminal command.
+
You may also pass a `Closure` to the `detectEnvironment` method, allowing you to implement your own environment detection:
$env = $app->detectEnvironment(function()
diff --git a/contributing.md b/contributing.md
index 32f12fc1a5a..ca61bb5a9b8 100644
--- a/contributing.md
+++ b/contributing.md
@@ -7,7 +7,7 @@
## Introduction
-Laravel is free, open-source software, meaning anyone can contribute to its development and progress. Laravel source code is currently hosted on [Github](http://github.com), which provides an easy method for forking the project and merging your contributions.
+Laravel is free, open-source software, meaning anyone can contribute to its development and progress. Laravel source code is currently hosted on [Github](https://github.com/laravel), which provides an easy method for forking the project and merging your contributions.
## Pull Requests
@@ -16,6 +16,8 @@ The pull request process differs for new features and bugs. Before sending a pul
Pull requests for bugs may be sent without creating any proposal issue. If you believe that you know of a solution for a bug that has been filed on Github, please leave a comment detailing your proposed fix.
+Additions and corrections to the documentation may also be contributed via the [documentation repository](https://github.com/laravel/docs) on Github.
+
### Feature Requests
If you have an idea for a new feature you would like to see added to Laravel, you may create an issue on Github with `[Request]` in the title. The feature request will then be reviewed by a core contributor.
diff --git a/controllers.md b/controllers.md
index 29177e495f7..d68f5d92c6c 100644
--- a/controllers.md
+++ b/controllers.md
@@ -67,7 +67,7 @@ However, you may also specify filters from within your controller:
*/
public function __construct()
{
- $this->beforeFilter('auth');
+ $this->beforeFilter('auth', array('except' => 'getLogin'));
$this->beforeFilter('csrf', array('on' => 'post'));
@@ -142,15 +142,15 @@ This single route declaration creates multiple routes to handle a variety of RES
**Actions Handled By Resource Controller**
-Verb | Path | Action | Route Name
-----------|-----------------------|--------------|---------------------
-GET | /resource | index | resource.index
-GET | /resource/create | create | resource.create
-POST | /resource | store | resource.store
-GET | /resource/{id} | show | resource.show
-GET | /resource/{id}/edit | edit | resource.edit
-PUT/PATCH | /resource/{id} | update | resource.update
-DELETE | /resource/{id} | destroy | resource.destroy
+Verb | Path | Action | Route Name
+----------|-----------------------------|--------------|---------------------
+GET | /resource | index | resource.index
+GET | /resource/create | create | resource.create
+POST | /resource | store | resource.store
+GET | /resource/{resource} | show | resource.show
+GET | /resource/{resource}/edit | edit | resource.edit
+PUT/PATCH | /resource/{resource} | update | resource.update
+DELETE | /resource/{resource} | destroy | resource.destroy
Sometimes you may only need to handle a subset of the resource actions:
@@ -163,6 +163,9 @@ And, you may also specify a subset of actions to handle on the route:
Route::resource('photo', 'PhotoController',
array('only' => array('index', 'show')));
+ Route::resource('photo', 'PhotoController',
+ array('except' => array('create', 'store', 'update', 'delete')));
+
## Handling Missing Methods
@@ -173,4 +176,4 @@ A catch-all method may be defined which will be called when no other matching me
public function missingMethod($parameters)
{
//
- }
\ No newline at end of file
+ }
diff --git a/database.md b/database.md
index 6898653d339..4e3f818baf5 100644
--- a/database.md
+++ b/database.md
@@ -83,4 +83,8 @@ Sometimes you may need to reconnect to a given database:
By default, Laravel keeps a log in memory of all queries that have been run for the current request. However, in some cases, such as when inserting a large number of rows, this can cause the application to use excess memory. To disable the log, you may use the `disableQueryLog` method:
- DB::connection()->disableQueryLog();
\ No newline at end of file
+ DB::connection()->disableQueryLog();
+
+To get an array of the executed queries, you may use the `getQueryLog` method:
+
+ $queries = DB::getQueryLog();
diff --git a/documentation.md b/documentation.md
index ea1af9200b2..b37018756aa 100755
--- a/documentation.md
+++ b/documentation.md
@@ -13,6 +13,7 @@
- [Errors & Logging](/docs/errors)
- Learning More
- [Cache](/docs/cache)
+ - [Core Extension](/docs/extending)
- [Events](/docs/events)
- [Facades](/docs/facades)
- [Forms & HTML](/docs/html)
diff --git a/eloquent.md b/eloquent.md
index 78fc4e00677..d37fa96bcd3 100644
--- a/eloquent.md
+++ b/eloquent.md
@@ -92,6 +92,16 @@ Of course, you may also use the query builder aggregate functions.
$count = User::where('votes', '>', 100)->count();
+If you are unable to generate the query you need via the fluent interface, feel free to use `whereRaw`:
+
+ $users = User::whereRaw('age > ? and votes = 100', array(25))->get();
+
+**Specifying The Query Connection**
+
+You may also specify which database connection should be used when running an Eloquent query. Simply use the `on` method:
+
+ $user = User::on('connection-name')->find(1);
+
## Mass Assignment
@@ -144,6 +154,10 @@ To create a new record in the database from a model, simply create a new model i
You may also use the `create` method to save a new model in a single line. The inserted model instance will be returned to you from the method. However, before doing so, you will need to specify either a `fillable` or `guarded` attribute on the model, as all Eloquent models protect against mass-assignment.
+After saving or creating a new model that uses auto-incrementing IDs, you may retrieve the ID by accessing the object's `id` attribute:
+
+ $insertedId = $user->id;
+
**Setting The Guarded Attributes On The Model**
class User extends Eloquent {
@@ -188,6 +202,8 @@ To delete a model, simply call the `delete` method on the instance:
User::destroy(1);
+ User::destroy(array(1, 2, 3));
+
User::destroy(1, 2, 3);
Of course, you may also run a delete query on a set of models:
@@ -255,7 +271,7 @@ To determine if a given model instance has been soft deleted, you may use the `t
## Timestamps
-By default, Eloquent will maintain the `created_at` and `updated_at` columns on your database table automatically. Simply add these `datetime` columns to your table and Eloquent will take care of the rest. If you do not wish for Eloquent to maintain these columns, add the following property to your model:
+By default, Eloquent will maintain the `created_at` and `updated_at` columns on your database table automatically. Simply add these `timestamp` columns to your table and Eloquent will take care of the rest. If you do not wish for Eloquent to maintain these columns, add the following property to your model:
**Disabling Auto Timestamps**
@@ -267,15 +283,15 @@ By default, Eloquent will maintain the `created_at` and `updated_at` columns on
}
-If you wish to customize the format of your timestamps, you may override the `freshTimestamp` method in your model:
+If you wish to customize the format of your timestamps, you may override the `getDateFormat` method in your model:
**Providing A Custom Timestamp Format**
class User extends Eloquent {
- public function freshTimestamp()
+ protected function getDateFormat()
{
- return time();
+ return 'U';
}
}
@@ -294,11 +310,33 @@ Scopes allow you to easily re-use query logic in your models. To define a scope,
return $query->where('votes', '>', 100);
}
+ public function scopeWomen($query)
+ {
+ return $query->whereGender('W');
+ }
+
}
**Utilizing A Query Scope**
- $users = User::popular()->orderBy('created_at')->get();
+ $users = User::popular()->women()->orderBy('created_at')->get();
+
+**Dynamic Scopes**
+
+Sometimes You may wish to define a scope that accepts parameters. Just add your parameters to your scope function:
+
+ class User extends Eloquent {
+
+ public function scopeOfType($query, $type)
+ {
+ return $query->whereType($type);
+ }
+
+ }
+
+Then pass the parameter into the scope call:
+
+ $users = User::ofType('member')->get();
## Relationships
@@ -353,6 +391,17 @@ To define the inverse of the relationship on the `Phone` model, we use the `belo
}
+In the example above, Eloquent will look for a `user_id` column on the `phones` table. If you would like to define a different foreign key column, you may pass it as the second argument to the `belongsTo` method:
+
+ class Phone extends Eloquent {
+
+ public function user()
+ {
+ return $this->belongsTo('User', 'custom_key');
+ }
+
+ }
+
### One To Many
@@ -532,7 +581,7 @@ Eloquent allows you to access your relations via dynamic properties. Eloquent wi
}
$phone = Phone::find(1);
-
+
Instead of echoing the user's email like this:
echo $phone->user()->first()->email;
@@ -541,6 +590,8 @@ It may be shortened to simply:
echo $phone->user->email;
+> **Note:** Relationships that return many results will return an instance of the `Illuminate\Database\Eloquent\Collection` class.
+
## Eager Loading
@@ -732,7 +783,7 @@ Note that this operation does not delete records from the `roles` table, but onl
## Collections
-All multi-result sets returned by Eloquent either via the `get` method or a relationship return an Eloquent `Collection` object. This object implements the `IteratorAggregate` PHP interface so it can be iterated over like an array. However, this object also has a variety of other helpful methods for working with result sets.
+All multi-result sets returned by Eloquent, either via the `get` method or a `relationship`, will return a collection object. This object implements the `IteratorAggregate` PHP interface so it can be iterated over like an array. However, this object also has a variety of other helpful methods for working with result sets.
For example, we may determine if a result set contains a given primary key using the `contains` method:
@@ -757,25 +808,34 @@ If a collection is cast to a string, it will be returned as JSON:
Eloquent collections also contain a few helpful methods for looping and filtering the items they contain:
-**Iterating & Filtering Collections**
+**Iterating Collections**
$roles = $user->roles->each(function($role)
{
-
+ //
});
- $roles = $user->roles->filter(function($role)
- {
+**Filtering Collections**
+
+When filtering collections, the callback provided will be used as callback for [array_filter](http://php.net/manual/en/function.array-filter.php).
+ $users = $user->filter(function($user)
+ {
+ if($user->isAdmin())
+ {
+ return $user;
+ }
});
+> **Note:** When filtering a collection and converting it to JSON, try calling the `values` function first to reset the array's keys.
+
**Applying A Callback To Each Collection Object**
$roles = User::find(1)->roles;
-
+
$roles->each(function($role)
{
- //
+ //
});
**Sorting A Collection By A Value**
@@ -853,7 +913,11 @@ To totally disable date mutations, simply return an empty array from the `getDat
## Model Events
-Eloquent models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`. If `false` is returned from the `creating`, `updating`, or `saving` events, the action will be cancelled:
+Eloquent models fire several events, allowing you to hook into various points in the model's lifecycle using the following methods: `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `restoring`, `restored`.
+
+Whenever a new item is saved for the first time, the `creating` and `created` events will fire. If an item is not new and the `save` method is called, the `updating` / `updated` events will fire. In both cases, the `saving` / `saved` events will fire.
+
+If `false` is returned from the `creating`, `updating`, `saving`, or `deleting` events, the action will be cancelled:
**Cancelling Save Operations Via Events**
@@ -942,6 +1006,22 @@ Sometimes you may wish to limit the attributes that are included in your model's
}
+> **Note:** When hiding relationships, use the relationship's **method** name, not the dynamic accessor name.
+
Alternatively, you may use the `visible` property to define a white-list:
protected $visible = array('first_name', 'last_name');
+
+
+Occasionally, you may need to add array attributes that do not have a corresponding column in your database. To do so, simply define an accessor for the value:
+
+ public function getIsAdminAttribute()
+ {
+ return $this->attributes['admin'] == 'yes';
+ }
+
+Once you have created the accessor, just add the value to the `appends` property on the model:
+
+ protected $appends = array('is_admin');
+
+Once the attribute has been added to the `appends` list, it will be included in both the model's array and JSON forms.
diff --git a/errors.md b/errors.md
index 439e48bb1c2..0f2c508b80b 100644
--- a/errors.md
+++ b/errors.md
@@ -44,6 +44,8 @@ To listen for PHP fatal errors, you may use the `App::fatal` method:
//
});
+If you have several exception handlers, they should be defined from most generic to most specific. So, for example, a handler that handles all exceptions of type `Exception` should be defined before a custom exception type such as `Illuminate\Encryption\DecryptException`.
+
## HTTP Exceptions
@@ -82,6 +84,10 @@ The Laravel logging facilities provide a simple layer on top of the powerful [Mo
The logger provides the seven logging levels defined in [RFC 5424](http://tools.ietf.org/html/rfc5424): **debug**, **info**, **notice**, **warning**, **error**, **critical**, and **alert**.
+An array of contextual data may also be passed to the log methods:
+
+ Log::info('Log message', array('context' => 'Other helpful information'));
+
Monolog has a variety of additional handlers you may use for logging. If needed, you may access the underlying Monolog instance being used by Laravel:
$monolog = Log::getMonolog();
diff --git a/extending.md b/extending.md
new file mode 100644
index 00000000000..d4a4057ed88
--- /dev/null
+++ b/extending.md
@@ -0,0 +1,221 @@
+# Extending The Framework
+
+- [Introduction](#introduction)
+- [Managers & Factories](#managers-and-factories)
+- [Cache](#cache)
+- [Session](#session)
+- [Authentication](#authentication)
+- [IoC Based Extension](#ioc-based-extension)
+- [Request Extension](#request-extension)
+
+
+## Introduction
+
+Laravel offers many extension points for you to customize the behavior of the framework's core components, or even replace them entirely. For example, the hashing facilities are defined by a `HasherInterface` contract, which you may implement based on your application's requirements. You may also extend the `Request` object, allowing you to add your own convenient "helper" methods. You may even add entirely new authentication, cache, and session drivers!
+
+Laravel components are generally extended in two ways: binding new implementations in the IoC container, or registering an extension with a `Manager` class, which are implementations of the "Factory" design pattern. In this chapter we'll explore the various methods of extending the framework and examine the necessary code.
+
+> **Note:** Remember, Laravel components are typically extended in one of two ways: IoC bindings and the `Manager` classes. The manager classes serve as an implementation of the "factory" design pattern, and are responsible for instantiating driver based facilities such as cache and session.
+
+
+## Managers & Factories
+
+Laravel has several `Manager` classes that manage the creation of driver-based components. These include the cache, session, authentication, and queue components. The manager class is responsible for creating a particular driver implementation based on the application's configuration. For example, the `CacheManager` class can create APC, Memcached, Native, and various other implementations of cache drivers.
+
+Each of these managers includes an `extend` method which may be used to easily inject new driver resolution functionality into the manager. We'll cover each of these managers below, with examples of how to inject custom driver support into each of them.
+
+> **Note:** Take a moment to explore the various `Manager` classes that ship with Laravel, such as the `CacheManager` and `SessionManager`. Reading through these classes will give you a more thorough understanding of how Laravel works under the hood. All manager classes extend the `Illuminate\Support\Manager` base class, which provides some helpful, common functionality for each manager.
+
+
+## Cache
+
+To extend the Laravel cache facility, we will use the `extend` method on the `CacheManager`, which is used to bind a custom driver resolver to the manager, and is common across all manager classes. For example, to register a new cache driver named "mongo", we would do the following:
+
+ Cache::extend('mongo', function($app)
+ {
+ // Return Illuminate\Cache\Repository instance...
+ });
+
+The first argument passed to the `extend` method is the name of the driver. This will correspond to your `driver` option in the `app/config/cache.php` configuration file. The second argument is a Closure that should return an `Illuminate\Cache\Repository` instance. The Closure will be passed an `$app` instance, which is an instance of `Illuminate\Foundation\Application` and an IoC container.
+
+To create our custom cache driver, we first need to implement the `Illuminate\Cache\StoreInterface` contract. So, our MongoDB cache implementation would look something like this:
+
+ class MongoStore implements Illuminate\Cache\StoreInterface {
+
+ public function get($key) {}
+ public function put($key, $value, $minutes) {}
+ public function increment($key, $value = 1) {}
+ public function decrement($key, $value = 1) {}
+ public function forever($key, $value) {}
+ public function forget($key) {}
+ public function flush() {}
+
+ }
+
+We just need to implement each of these methods using a MongoDB connection. Once our implementation is complete, we can finish our custom driver registration:
+
+ use Illuminate\Cache\Repository;
+
+ Cache::extend('mongo', function($app)
+ {
+ return new Repository(new MongoStore);
+ });
+
+As you can see in the example above, you may use the base `Illuminate\Cache\Repository` when creating custom cache drivers. There is typically no need to create your own repository class.
+
+If you're wondering where to put your custom cache driver code, consider making it available on Packagist! Or, you could create an `Extensions` namespace within your application's primary folder. For example, if the application is named `Snappy`, you could place the cache extension in `app/Snappy/Extensions/MongoStore.php`. However, keep in mind that Laravel does not have a rigid application structure and you are free to organize your application according to your preferences.
+
+> **Note:** If you're ever wondering where to put a piece of code, always consider a service provider. As we've discussed, using a service provider to organize framework extensions is a great way to organize your code.
+
+
+## Session
+
+Extending Laravel with a custom session driver is just as easy as extending the cache system. Again, we will use the `extend` method to register our custom code:
+
+ Session::extend('mongo', function($app)
+ {
+ // Return implementation of SessionHandlerInterface
+ });
+
+Note that our custom cache driver should implement the `SessionHandlerInterface`. This interface is included in the PHP 5.4+ core. If you are using PHP 5.3, the interface will be defined for you by Laravel so you have forward-compatibility. This interface contains just a few simple methods we need to implement. A stubbed MongoDB implementation would look something like this:
+
+ class MongoHandler implements SessionHandlerInterface {
+
+ public function open($savePath, $sessionName) {}
+ public function close() {}
+ public function read($sessionId) {}
+ public function write($sessionId, $data) {}
+ public function destroy($sessionId) {}
+ public function gc($lifetime) {}
+
+ }
+
+Since these methods are not as readily understandable as the cache `StoreInterface`, let's quickly cover what each of the methods do:
+
+- The `open` method would typically be used in file based session store systems. Since Laravel ships with a `native` session driver that uses PHP's native file storage for sessions, you will almost never need to put anything in this method. You can leave it as an empty stub. It is simply a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method.
+- The `close` method, like the `open` method, can also usually be disregarded. For most drivers, it is not needed.
+- The `read` method should return the string version of the session data associated with the given `$sessionId`. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you.
+- The `write` method should write the given `$data` string associated with the `$sessionId` to some persistent storage system, such as MongoDB, Dynamo, etc.
+- The `destroy` method should remove the data associated with the `$sessionId` from persistent storage.
+- The `gc` method should destroy all session data that is older than the given `$lifetime`, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty.
+
+Once the `SessionHandlerInterface` has been implemented, we are ready to register it with the Session manager:
+
+ Session::extend('mongo', function($app)
+ {
+ return new MongoHandler;
+ });
+
+Once the session driver has been registered, we may use the `mongo` driver in our `app/config/session.php` configuration file.
+
+> **Note:** Remember, if you write a custom session handler, share it on Packagist!
+
+
+## Authentication
+
+Authentication may be extended the same way as the cache and session facilities. Again, we will use the `extend` method we have become familiar with:
+
+ Auth::extend('riak', function($app)
+ {
+ // Return implementation of Illuminate\Auth\UserProviderInterface
+ });
+
+The `UserProviderInterface` implementations are only responsible for fetching a `UserInterface` implementation out of a persistent storage system, such as MySQL, Riak, etc. These two interfaces allow the Laravel authentication mechanisms to continue functioning regardless of how the user data is stored or what type of class is used to represent it.
+
+Let's take a look at the `UserProviderInterface`:
+
+ interface UserProviderInterface {
+
+ public function retrieveById($identifier);
+ public function retrieveByCredentials(array $credentials);
+ public function validateCredentials(UserInterface $user, array $credentials);
+
+ }
+
+The `retrieveById` function typically receives a numeric key representing the user, such as an auto-incrementing ID from a MySQL database. The `UserInterface` implementation matching the ID should be retrieved and returned by the method.
+
+The `retrieveByCredentials` method receives the array of credentials passed to the `Auth::attempt` method when attempting to sign into an application. The method should then "query" the underlying persistent storage for the user matching those credentials. Typically, this method will run a query with a "where" condition on `$credentails['username']`. **This method should not attempt to do any password validation or authentication.**
+
+The `validateCredentials` method should compare the given `$user` with the `$credentials` to authenticate the user. For example, this method might compare the `$user->getAuthPassword()` string to a `Hash::make` of `$credentials['password']`.
+
+Now that we have explored each of the methods on the `UserProviderInterface`, let's take a look at the `UserInterface`. Remember, the provider should return implementations of this interface from the `retrieveById` and `retrieveByCredentials` methods:
+
+ interface UserInterface {
+
+ public function getAuthIdentifier();
+ public function getAuthPassword();
+
+ }
+
+This interface is simple. The `getAuthIdentifier` method should return the "primary key" of the user. In a MySQL back-end, again, this would be the auto-incrementing primary key. The `getAuthPassword` should return the user's hashed password. This interface allows the authentication system to work with any User class, regardless of what ORM or storage abstraction layer you are using. By default, Laravel includes a `User` class in the `app/models` directory which implements this interface, so you may consult this class for an implementation example.
+
+Finally, once we have implemented the `UserProviderInterface`, we are ready to register our extension with the `Auth` facade:
+
+ Auth::extend('riak', function($app)
+ {
+ return new RiakUserProvider($app['riak.connection']);
+ });
+
+After you have registered the driver with the `extend` method, you switch to the new driver in your `app/config/auth.php` configuration file.
+
+
+## IoC Based Extension
+
+Almost every service provider included with the Laravel framework binds objects into the IoC container. You can find a list of your application's service providers in the `app/config/app.php` configuration file. As you have time, you should skim through each of these provider's source code. By doing so, you will gain a much better understanding of what each provider adds to the framework, as well as what keys are used to bind various services into the IoC container.
+
+For example, the `PaginationServiceProvider` binds a `paginator` key into the IoC container, which resolves into a `Illuminate\Pagination\Environment` instance. You can easily extend and override this class within your own application by overriding this IoC binding. For example, you could create a class that extend the base `Environment`:
+
+ namespace Snappy\Extensions\Pagination;
+
+ class Environment extends \Illuminate\Pagination\Environment {
+
+ //
+
+ }
+
+Once you have created your class extension, you may create a new `SnappyPaginationProvider` service provider class which overrides the paginator in its `boot` method:
+
+ class SnappyPaginationProvider extends PaginationServiceProvider {
+
+ public function boot()
+ {
+ App::bind('paginator', function()
+ {
+ return new Snappy\Extensions\Pagination\Environment;
+ });
+
+ parent::boot();
+ }
+
+ }
+
+Note that this class extends the `PaginationServiceProvider`, not the default `ServiceProvider` base class. Once you have extended the service provider, swap out the `PaginationServiceProvider` in your `app/config/app.php` configuration file with the name of your extended provider.
+
+This is the general method of extending any core class that is bound in the container. Essentially every core class is bound in the container in this fashion, and can be overridden. Again, reading through the included framework service providers will familiarize you with where various classes are bound into the container, and what keys they are bound by. This is a great way to learn more about how Laravel is put together.
+
+
+## Request Extension
+
+Because it is such a foundational piece of the framework and is instantiated very early in the request cycle, extending the `Request` class works a little differently than the previous examples.
+
+First, extend the class like normal:
+
+
## Mocking Facades
diff --git a/helpers.md b/helpers.md
index fc7eafd03f8..9d08ca1f63d 100644
--- a/helpers.md
+++ b/helpers.md
@@ -45,9 +45,12 @@ The `array_except` method removes the given key / value pairs from the array.
The `array_fetch` method returns a flattened array containing the selected nested element.
- $array = array(array('name' => 'Taylor'), array('name' => 'Dayle'));
+ $array = array(
+ array('developer' => array('name' => 'Taylor')),
+ array('developer' => array('name' => 'Dayle')),
+ );
- var_dump(array_fetch($array, 'name'));
+ $array = array_fetch($array, 'developer.name');
// array('Taylor', 'Dayle');
@@ -157,7 +160,7 @@ Return the last element in the array. Useful for method chaining.
### app_path
-Get the fully qualified path to the `application` directory.
+Get the fully qualified path to the `app` directory.
### base_path
@@ -169,7 +172,7 @@ Get the fully qualified path to the `public` directory.
### storage_path
-Get the fully qualified path to the `application/storage` directory.
+Get the fully qualified path to the `app/storage` directory.
## Strings
@@ -192,7 +195,7 @@ Get the class name of the given class, without any namespace names.
### e
-Run `htmlentites` over the given string, with UTF-8 support.
+Run `htmlentities` over the given string, with UTF-8 support.
$entities = e('foo');
@@ -283,6 +286,12 @@ Generate a URL for a given controller action.
$url = action('HomeController@getIndex', $params);
+### route
+
+Generate a URL for a given named route.
+
+ $url = route('routeName', $params);
+
### asset
Generate a URL for an asset.
diff --git a/html.md b/html.md
index 732f35ad746..c0ff4f73989 100644
--- a/html.md
+++ b/html.md
@@ -10,6 +10,7 @@
- [Drop-Down Lists](#drop-down-lists)
- [Buttons](#buttons)
- [Custom Macros](#custom-macros)
+- [Generating URLs](#generating-urls)
## Opening A Form
@@ -24,7 +25,7 @@ By default, a `POST` method will be assumed; however, you are free to specify an
echo Form::open(array('url' => 'foo/bar', 'method' => 'put'))
-> **Note:** Since HTML forms only support `POST`, `PUT` and `DELETE` methods will be spoofed by automatically adding a `_method` hidden field to your form.
+> **Note:** Since HTML forms only support `POST` and `GET`, `PUT` and `DELETE` methods will be spoofed by automatically adding a `_method` hidden field to your form.
You may also open forms that point to named routes or controller actions:
@@ -32,6 +33,12 @@ You may also open forms that point to named routes or controller actions:
echo Form::open(array('action' => 'Controller@method'))
+You may pass in route parameters as well:
+
+ echo Form::open(array('route' => array('route.name', $user->id)))
+
+ echo Form::open(array('action' => array('Controller@method', $user->id)))
+
If your form is going to accept file uploads, add a `files` option to your array:
echo Form::open(array('url' => 'foo/bar', 'files' => true))
@@ -101,19 +108,24 @@ This allows you to quickly build forms that not only bind to model values, but e
echo Form::password('password');
+**Generating Other Inputs**
+
+ echo Form::email($name, $value = null, $attributes = array());
+ echo Form::file($name, $attributes = array());
+
## Checkboxes and Radio Buttons
**Generating A Checkbox Or Radio Input**
echo Form::checkbox('name', 'value');
-
+
echo Form::radio('name', 'value');
**Generating A Checkbox Or Radio Input That Is Checked**
echo Form::checkbox('name', 'value', true);
-
+
echo Form::radio('name', 'value', true);
@@ -141,6 +153,14 @@ This allows you to quickly build forms that not only bind to model values, but e
'Dogs' => array('spaniel' => 'Spaniel'),
));
+**Generating A Drop-Down List With A Range**
+
+ echo Form::selectRange('number', 10, 20);
+
+**Generating A List With Month Names**
+
+ echo Form::selectMonth('month');
+
## Buttons
@@ -167,3 +187,9 @@ Now you can call your macro using its name:
**Calling A Custom Form Macro**
echo Form::myField();
+
+
+
+##Generating URLs
+
+For more information on generating URL's, check out the documentation on [helpers](/docs/helpers#urls).
diff --git a/installation.md b/installation.md
index 57f36958763..58aefbee033 100644
--- a/installation.md
+++ b/installation.md
@@ -18,7 +18,7 @@ Laravel utilizes [Composer](http://getcomposer.org) to manage its dependencies.
You may install Laravel by issuing the Composer `create-project` command in your terminal:
- composer create-project laravel/laravel
+ composer create-project laravel/laravel --prefer-dist
### Via Download
@@ -34,13 +34,13 @@ The Laravel framework has a few system requirements:
- PHP >= 5.3.7
- MCrypt PHP Extension
+As of PHP 5.5, some OS distributions may require you to manually install the PHP JSON extension. When using Ubuntu, this can be done via `apt-get install php5-json`.
+
## Configuration
Laravel needs almost no configuration out of the box. You are free to get started developing! However, you may wish to review the `app/config/app.php` file and its documentation. It contains several options such as `timezone` and `locale` that you may wish to change according to your application.
-> **Note:** One configuration option you should be sure to set is the `key` option within `app/config/app.php`. This value should be set to a 32 character, random string. This key is used when encrypting values, and encrypted values will not be safe until it is properly set. You can set this value quickly by using the following artisan command `php artisan key:generate`.
-
### Permissions
Laravel requires one set of permissions to be configured - folders within app/storage require write access by the web server.
@@ -50,8 +50,6 @@ Laravel requires one set of permissions to be configured - folders within app/st
Several of the framework directory paths are configurable. To change the location of these directories, check out the `bootstrap/paths.php` file.
-> **Note:** Laravel is designed to protect your application code, and local storage by placing only files that are necessarily public in the public folder. It is recommended that you either set the public folder as your site's documentRoot (also known as a web root) or to place the contents of public into your site's root directory and place all of Laravel's other files outside the web root.
-
## Pretty URLs
@@ -62,5 +60,6 @@ If the `.htaccess` file that ships with Laravel does not work with your Apache i
Options +FollowSymLinks
RewriteEngine On
+ RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
diff --git a/introduction.md b/introduction.md
index 1299b56abf6..62a34ad9dea 100644
--- a/introduction.md
+++ b/introduction.md
@@ -3,7 +3,6 @@
- [Laravel Philosophy](#laravel-philosophy)
- [Learning Laravel](#learning-laravel)
- [Development Team](#development-team)
-- [Framework Sponsors](#framework-sponsors)
## Laravel Philosophy
@@ -23,20 +22,13 @@ In addition to this guide, you may wish to check out some [Laravel books](http:/
- [Code Bright](https://leanpub.com/codebright) by Dayle Rees
- [Laravel Testing Decoded](https://leanpub.com/laravel-testing-decoded) by Jeffrey Way
+- [Laravel: From Apprentice To Artisan](https://leanpub.com/laravel) by Taylor Otwell
+- [Implementing Laravel](https://leanpub.com/implementinglaravel) by Chris Fidao
+- [Getting Stuff Done With Laravel 4](https://leanpub.com/gettingstuffdonelaravel) by Chuck Heintzelman
+- [Laravel 4 Cookbook](https://leanpub.com/laravel4cookbook) by Christopher Pitt
+- [Laravel in Action](http://www.manning.com/surguy/) by Maks Surguy
## Development Team
-Laravel was created by [Taylor Otwell](https://github.com/taylorotwell), who continues to lead development of the framework. Other prominent community members and contributors include [Dayle Rees](https://github.com/daylerees), [Shawn McCool](https://github.com/ShawnMcCool), [Jeffrey Way](https://github.com/JeffreyWay), [Jason Lewis](https://github.com/jasonlewis), [Ben Corlett](https://github.com/bencorlett), [Franz Liedke](https://github.com/franzliedke), [Dries Vints](https://github.com/driesvints), [Mior Muhammed Zaki](https://github.com/crynobone), and [Phil Sturgeon](https://github.com/philsturgeon).
-
-
-## Framework Sponsors
-
-The following organizations have made financial contributions to the development of the Laravel framework:
-
-- [UserScape](http://userscape.com)
-- [Cartalyst](http://cartalyst.com)
-- [Elli Davis - Toronto Realtor](http://ellidavis.com)
-- [Jay Banks - Vancouver Lofts & Condos](http://jaybanks.ca/vancouver-lofts-condos)
-- [Julie Kinnear - Toronto MLS](http://juliekinnear.com/toronto-mls-listings)
-- [Jamie Sarner - Toronto Real Estate](http://jamiesarner.com)
+Laravel was created by [Taylor Otwell](https://github.com/taylorotwell), who continues to lead development of the framework. Other prominent community members and contributors include [Dayle Rees](https://github.com/daylerees), [Shawn McCool](https://github.com/ShawnMcCool), [Jeffrey Way](https://github.com/JeffreyWay), [Jason Lewis](https://github.com/jasonlewis), [Ben Corlett](https://github.com/bencorlett), [Franz Liedke](https://github.com/franzliedke), [Dries Vints](https://github.com/driesvints), [Mior Muhammad Zaki](https://github.com/crynobone), and [Phil Sturgeon](https://github.com/philsturgeon).
diff --git a/ioc.md b/ioc.md
index 038337d5462..c61cff3e69a 100644
--- a/ioc.md
+++ b/ioc.md
@@ -165,7 +165,12 @@ The container fires an event each time it resolves an object. You may listen to
**Registering A Resolving Listener**
- App::resolving(function($object)
+ App::resolvingAny(function($object)
+ {
+ //
+ });
+
+ App::resolving('foo', function($foo)
{
//
});
diff --git a/lifecycle.md b/lifecycle.md
index fce8d59dfb9..2d2c09a0daa 100644
--- a/lifecycle.md
+++ b/lifecycle.md
@@ -25,7 +25,7 @@ You may also do pre and post request processing by registering `before`, `after`
**Registering Application Events**
- App::before(function()
+ App::before(function($request)
{
//
});
diff --git a/localization.md b/localization.md
index 2bb050b9b43..b96e25d1036 100644
--- a/localization.md
+++ b/localization.md
@@ -4,6 +4,7 @@
- [Language Files](#language-files)
- [Basic Usage](#basic-usage)
- [Pluralization](#pluralization)
+- [Validation Localization](#validation)
## Introduction
@@ -49,6 +50,10 @@ The first segment of the string passed to the `get` method is the name of the la
> **Note**: If a language line does not exist, the key will be returned by the `get` method.
+You may also use the `trans` helper function, which is an alias for the `Lang::get` method.
+
+ echo trans('messages.welcome');
+
**Making Replacements In Lines**
You may also define place-holders in your language lines:
@@ -80,3 +85,9 @@ You may then use the `Lang::choice` method to retrieve the line:
Since the Laravel translator is powered by the Symfony Translation component, you may also create more explicit pluralization rules easily:
'apples' => '{0} There are none|[1,19] There are some|[20,Inf] There are many',
+
+
+
+## Validation
+
+For localization for validation errors and messages, take a look at the documentation on Validation.
diff --git a/migrations.md b/migrations.md
index 02faec5d15a..21fc089b7e7 100644
--- a/migrations.md
+++ b/migrations.md
@@ -45,7 +45,7 @@ The `--table` and `--create` options may also be used to indicate the name of th
php artisan migrate --package=vendor/package
-> **Note:** If you receive a "class not found" error when running migrations, try running the `composer update` command.
+> **Note:** If you receive a "class not found" error when running migrations, try running the `composer dump-autoload` command.
## Rolling Back Migrations
@@ -97,6 +97,10 @@ To seed your database, you may use the `db:seed` command on the Artisan CLI:
php artisan db:seed
+By default, the `db:seed` command runs the `DatabaseSeeder` class, which may be used to call other seed classes. However, you may use the `--class` option to specify a specific seeder class to run individually:
+
+ php artisan db:seed --class=UserTableSeeder
+
You may also seed your database using the `migrate:refresh` command, which will also rollback and re-run all of your migrations:
php artisan migrate:refresh --seed
diff --git a/packages.md b/packages.md
index 2f6ae5ff64c..cda1ac0b08e 100644
--- a/packages.md
+++ b/packages.md
@@ -38,6 +38,8 @@ Once the `workbench` command has been executed, your package will be available w
Once the provider has been registered, you are ready to start developing your package! However, before diving in, you may wish to review the sections below to get more familiar with the package structure and development workflow.
+> **Note:** If your service provider cannot be found, run the `php artisan dump-autoload` command from your application's root directory
+
## Package Structure
@@ -71,6 +73,16 @@ When creating a package using the `workbench`, the `boot` command will already c
This method allows Laravel to know how to properly load the views, configuration, and other resources for your application. In general, there should be no need for you to change this line of code, as it will setup the package using the workbench conventions.
+By default, after registering a package, its resources will be available using the "package" half of `vendor/package`. However, you may pass a second argument into the `package` method to override this behavior. For example:
+
+ // Passing custom namespace to package method
+ $this->package('vendor/package', 'custom-namespace');
+
+ // Package resources now accessed via custom-namespace
+ $view = View::make('custom-namespace::foo');
+
+There is not a "default location" for service provider classes. You may put them anywhere you like, perhaps organizing them in a `Providers` namespace within your `app` directory. The file may be placed anywhere, as long as Composer's [auto-loading facilities](http://getcomposer.org/doc/01-basic-usage.md#autoloading) know how to load the class.
+
## Package Conventions
@@ -95,6 +107,12 @@ After the `workbench` command has created your package. You may `git init` from
Since your packages are in the `workbench` directory, you may be wondering how Composer knows to autoload your package's files. When the `workbench` directory exists, Laravel will intelligently scan it for packages, loading their Composer autoload files when the application starts!
+If you need to regenerate your package's autoload files, you may use the `php artisan dump-autoload` command. This command will regenerate the autoload files for your root project, as well as any workbenches you have created.
+
+**Running The Artisan Autoload Command**
+
+ php artisan dump-autoload
+
## Package Routing
@@ -126,6 +144,18 @@ However, if your package contains a single configuration file, you may simply na
Config::get('package::option');
+Sometimes, you may wish to register package resources such as views outside of the typical `$this->package` method. Typically, this would only be done if the resources were not in a conventional location. To register the resources manually, you may use the `addNamespace` method of the `View`, `Lang`, and `Config` classes:
+
+**Registering A Resource Namespace Manually**
+
+ View::addNamespace('package', __DIR__.'/path/to/views');
+
+Once the namespace has been registered, you may use the namespace name and the "double colon" syntax to access the resources:
+
+ return View::make('package::view.name');
+
+The method signature for `addNamespace` is identical on the `View`, `Lang`, and `Config` classes.
+
### Cascading Configuration Files
When other developers install your package, they may wish to override some of the configuration options. However, if they change the values in your package source code, they will be overwritten the next time Composer updates the package. Instead, the `config:publish` artisan command should be used:
diff --git a/pagination.md b/pagination.md
index 4456ea422d8..26b9b8708fc 100644
--- a/pagination.md
+++ b/pagination.md
@@ -24,7 +24,9 @@ You may also paginate [Eloquent](/docs/eloquent) models:
**Paginating An Eloquent Model**
- $users = User::where('votes', '>', 100)->paginate(15);
+ $allUsers = User::paginate(15);
+
+ $someUsers = User::where('votes', '>', 100)->paginate(15);
The argument passed to the `paginate` method is the number of items you wish to display per page. Once you have retrieved the results, you may display them on your view, and create the pagination links using the `links` method:
@@ -46,6 +48,7 @@ You may also access additional pagination information via the following methods:
- `getTotal`
- `getFrom`
- `getTo`
+- `count`
Sometimes you may wish to create a pagination instance manually, passing it an array of items. You may do so using the `Paginator::make` method:
@@ -53,6 +56,16 @@ Sometimes you may wish to create a pagination instance manually, passing it an a
$paginator = Paginator::make($items, $totalItems, $perPage);
+**Customizing The Paginator URI**
+
+You may also customize the URI used by the paginator via the `setBaseUrl` method:
+
+ $users = User::paginate();
+
+ $users->setBaseUrl('custom/url');
+
+The example above will create URLs like the following: http://example.com/custom/url?page=2
+
## Appending To Pagination Links
@@ -62,4 +75,4 @@ You can add to the query string of pagination links using the `appends` method o
This will generate URLs that look something like this:
- http://example.com/something?page=2&sort=votes
\ No newline at end of file
+ http://example.com/something?page=2&sort=votes
diff --git a/queries.md b/queries.md
index 82a2ec65409..2f709bc60b5 100644
--- a/queries.md
+++ b/queries.md
@@ -116,6 +116,12 @@ The query builder may also be used to write join statements. Take a look at the
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.id', 'contacts.phone', 'orders.price');
+**Left Join Statement**
+
+ DB::table('users')
+ ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
+ ->get();
+
You may also specify more advanced join clauses:
DB::table('users')
@@ -197,8 +203,16 @@ Sometimes you may need to use a raw expression in a query. These expressions wil
DB::table('users')->increment('votes');
+ DB::table('users')->increment('votes', 5);
+
DB::table('users')->decrement('votes');
+ DB::table('users')->decrement('votes', 5);
+
+You may also specify additional columns to update:
+
+ DB::table('users')->increment('votes', 1, array('name' => 'John'));
+
## Inserts
@@ -271,4 +285,4 @@ You may easily cache the results of a query using the `remember` method:
$users = DB::table('users')->remember(10)->get();
-In this example, the results of the query will be cached for ten minutes. While the results are cached, the query will not be run against the database, and the results will be loaded from the default cache driver specified for your application.
\ No newline at end of file
+In this example, the results of the query will be cached for ten minutes. While the results are cached, the query will not be run against the database, and the results will be loaded from the default cache driver specified for your application.
diff --git a/queues.md b/queues.md
index 61f89059cb8..0892b8e5148 100644
--- a/queues.md
+++ b/queues.md
@@ -129,6 +129,10 @@ You may also set the length of time (in seconds) each job should be allowed to r
php artisan queue:listen --timeout=60
+In addition, you may specify the number of seconds to wait before polling for new jobs:
+
+ php artisan queue:listen --sleep=5
+
To process only the first job on the queue, you may use the `queue:work` command:
**Processing The First Job On The Queue**
diff --git a/quick.md b/quick.md
index c70527da35a..a3c47f7ae6b 100644
--- a/quick.md
+++ b/quick.md
@@ -10,11 +10,23 @@
## Installation
-To install the Laravel framework, you may issue the following command from your terminal:
+The Laravel framework utilizes [Composer](http://getcomposer.org) for installation and dependency management. If you haven't already, start by [installing Composer](http://getcomposer.org/doc/00-intro.md).
- composer create-project laravel/laravel your-project-name
+Now you can install Laravel by issuing the following command from your terminal:
-Or, you may also download a copy of the [repository from Github](https://github.com/laravel/laravel/archive/master.zip). Next, after [installing Composer](http://getcomposer.org), run the `composer install` command in the root of your project directory. This command will download and install the framework's dependencies.
+ composer create-project laravel/laravel your-project-name --prefer-dist
+
+This command will download and install a fresh copy of Laravel in a new `your-project-name` folder within your current directory.
+
+If you prefer, you can alternatively download a copy of the [Laravel repository from Github](https://github.com/laravel/laravel/archive/master.zip) manually. Next run the `composer install` command in the root of your manually created project directory. This command will download and install the framework's dependencies.
+
+
+### Permissions
+
+After installing Laravel, you may need to grant the web server write permissions to the `app/storage` directories. See the [Installation](/docs/installation) documentation for more details on configuration.
+
+
+### Directory Structure
After installing the framework, take a glance around the project to familiarize yourself with the directory structure. The `app` directory contains folders such as `views`, `controllers`, and `models`. Most of your application's code will reside somewhere in this directory. You may also wish to explore the `app/config` directory and the configuration options that are available to you.
@@ -73,7 +85,7 @@ Wonderful! Now you have setup a simple view that extends a layout. Next, let's s
To create a table to hold our data, we'll use the Laravel migration system. Migrations let you expressively define modifications to your database, and easily share them with the rest of your team.
-First, let's configure a database connection. You may configure all of your database connections from the `app/config/database.php` file. By default, Laravel is configured to use SQLite, and an SQLite database is included in the `app/database` directory. If you wish, you may change the `driver` option to `mysql` and configure the `mysql` connection credentials within the database configuration file.
+First, let's configure a database connection. You may configure all of your database connections from the `app/config/database.php` file. By default, Laravel is configured to use MySQL, and you will need to supply connection credentials within the database configuration file. If you wish, you may change the `driver` option to `sqlite` and it will use the SQLite database included in the `app/database` directory.
Next, to create the migration, we'll use the [Artisan CLI](/docs/artisan). From the root of your project, run the following from your terminal:
diff --git a/redis.md b/redis.md
index a572faff126..8560f4a4c94 100644
--- a/redis.md
+++ b/redis.md
@@ -29,6 +29,8 @@ The default server configuration should suffice for development. However, you ar
The `cluster` option will tell the Laravel Redis client to perform client-side sharding across your Redis nodes, allowing you to pool nodes and create a large amount of available RAM. However, note that client-side sharding does not handle failover; therefore, is primarily suited for cached data that is available from another primary data store.
+If your Redis server requires authentication, you may supply a password by adding a `password` key / value pair to your Redis server configuration array.
+
## Usage
diff --git a/requests.md b/requests.md
index 20341878db3..26cb989ec36 100644
--- a/requests.md
+++ b/requests.md
@@ -36,7 +36,11 @@ You may access all user input with a few simple methods. You do not need to worr
$input = Input::except('credit_card');
-Some JavaScript libraries such as Backbone may send input to the application as JSON. You may access this data via `Input::get` like normal.
+When working on forms with "array" inputs, you may use dot notation to access the arrays:
+
+ $input = Input::get('products.0.name');
+
+> **Note:** Some JavaScript libraries such as Backbone may send input to the application as JSON. You may access this data via `Input::get` like normal.
## Cookies
@@ -53,6 +57,12 @@ All cookies created by the Laravel framework are encrypted and signed with an au
$response->withCookie(Cookie::make('name', 'value', $minutes));
+**Queueing A Cookie For The Next Response**
+
+If you would like to set a cookie before a response has been created, use the `Cookie::queue()` method. The cookie will automatically be attached to the final response from your application.
+
+ Cookie::queue($name, $value, $minutes);
+
**Creating A Cookie That Lasts Forever**
$cookie = Cookie::forever('name', 'value');
@@ -110,6 +120,14 @@ The object returned by the `file` method is an instance of the `Symfony\Componen
$path = Input::file('photo')->getRealPath();
+**Retrieving The Original Name Of An Uploaded File**
+
+ $name = Input::file('photo')->getClientOriginalName();
+
+**Retrieving The Extension Of An Uploaded File**
+
+ $extension = Input::file('photo')->getClientOriginalExtension();
+
**Retrieving The Size Of An Uploaded File**
$size = Input::file('photo')->getSize();
@@ -149,6 +167,13 @@ The `Request` class provides many methods for examining the HTTP request for you
**Retrieving Values From $_SERVER**
$value = Request::server('PATH_INFO');
+
+**Determining If The Request Is Over HTTPS**
+
+ if (Request::secure())
+ {
+ //
+ }
**Determine If The Request Is Using AJAX**
@@ -157,9 +182,9 @@ The `Request` class provides many methods for examining the HTTP request for you
//
}
-**Determining If The Request Is Over HTTPS**
+**Detect any type of JSON request**
- if (Request::secure())
+ if (Request::ajax() or Request::isJson() or Request::wantsJson())
{
//
}
diff --git a/responses.md b/responses.md
index 4655e4da85d..24ae23317a3 100644
--- a/responses.md
+++ b/responses.md
@@ -39,6 +39,12 @@ A `Response` instance inherits from the `Symfony\Component\HttpFoundation\Respon
return Redirect::to('user/login');
+**Returning A Redirect With Flash Data**
+
+ return Redirect::to('user/login')->with('message', 'Login Failed');
+
+> **Note:** Since the `with` method flashes data to the session, you may retrieve the data using the typical `Session::get` method.
+
**Returning A Redirect To A Named Route**
return Redirect::route('login');
@@ -89,12 +95,14 @@ The second argument passed to `View::make` is an array of data that should be ma
**Passing Data To Views**
- $view = View::make('greeting', $data);
-
$view = View::make('greeting')->with('name', 'Steve');
In the example above the variable `$name` would be accessible from the view, and would contain `Steve`.
+If you wish, you may pass an array of data as the second parameter given to the `make` method:
+
+ $view = View::make('greetings', $data);
+
You may also share a piece of data across all views:
View::share('name', 'Steve');
@@ -119,7 +127,7 @@ The sub-view can then be rendered from the parent view:
## View Composers
-View composers are callbacks or class methods that are called when a view is created. If you have data that you want bound to a given view each time that view is created throughout your application, a view composer can organize that code into a single location. Therefore, view composers may function like "view models" or "presenters".
+View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want bound to a given view each time that view is rendered throughout your application, a view composer can organize that code into a single location. Therefore, view composers may function like "view models" or "presenters".
**Defining A View Composer**
@@ -128,7 +136,7 @@ View composers are callbacks or class methods that are called when a view is cre
$view->with('count', User::count());
});
-Now each time the `profile` view is created, the `count` data will be bound to the view.
+Now each time the `profile` view is rendered, the `count` data will be bound to the view.
You may also attach a view composer to multiple views at once:
@@ -154,6 +162,15 @@ A view composer class should be defined like so:
Note that there is no convention on where composer classes may be stored. You are free to store them anywhere as long as they can be autoloaded using the directives in your `composer.json` file.
+### View Creators
+
+View **creators** work almost exactly like view composers; however, they are fired immediately when the view is instantiated. To register a view creator, simple use the `creator` method:
+
+ View::creator('profile', function($view)
+ {
+ $view->with('count', User::count());
+ });
+
## Special Responses
diff --git a/routing.md b/routing.md
index 522e55fb578..c9448a1ffb8 100644
--- a/routing.md
+++ b/routing.md
@@ -84,6 +84,23 @@ Often, you will need to generate URLs to your routes, you may do so using the `U
})
->where('id', '[0-9]+');
+Of course, you may pass an array of constraints when necessary:
+
+ Route::get('user/{id}/{name}', function($id, $name)
+ {
+ //
+ })
+ ->where(array('id' => '[0-9]+', 'name' => '[a-z]+'))
+
+If you would like a route parameter to always be constrained by a given regular expression, you may use the `pattern` method:
+
+ Route::pattern('id', '[0-9]+');
+
+ Route::get('user/{id}', function($id)
+ {
+ // Only called if {id} is numeric.
+ });
+
## Route Filters
@@ -108,6 +125,10 @@ If a response is returned from a filter, that response will be considered the re
return 'You are over 200 years old!';
}));
+**Attaching A Filter To A Controller Action**
+
+ Route::get('user', array('before' => 'old', 'uses' => 'UserController@showProfile'));
+
**Attaching Multiple Filters To A Route**
Route::get('user', array('before' => 'auth|old', function()
@@ -228,6 +249,7 @@ Laravel routes are also able to handle wildcard sub-domains, and pass you wildca
});
});
+
## Route Prefixing
diff --git a/schema.md b/schema.md
index be701864eaf..1306953941c 100644
--- a/schema.md
+++ b/schema.md
@@ -36,7 +36,7 @@ To specify which connection the schema operation should take place on, use the `
Schema::connection('foo')->create('users', function($table)
{
- $table->increments('id'):
+ $table->increments('id');
});
To drop a table, you may use the `Schema::drop` method:
@@ -60,12 +60,14 @@ The table builder contains a variety of column types that you may use when build
Command | Description
------------- | -------------
`$table->increments('id');` | Incrementing ID to the table (primary key).
+`$table->bigIncrements('id');` | Incrementing ID using a "big integer" equivalent.
`$table->string('email');` | VARCHAR equivalent column
`$table->string('name', 100);` | VARCHAR equivalent with a length
`$table->integer('votes');` | INTEGER equivalent to the table
`$table->bigInteger('votes');` | BIGINT equivalent to the table
`$table->smallInteger('votes');` | SMALLINT equivalent to the table
`$table->float('amount');` | FLOAT equivalent to the table
+`$table->double('column', 15, 8);` | DOUBLE equivalent with precision
`$table->decimal('amount', 5, 2);` | DECIMAL equivalent with a precision and scale
`$table->boolean('confirmed');` | BOOLEAN equivalent to the table
`$table->date('created_at');` | DATE equivalent to the table
diff --git a/security.md b/security.md
index a5d3db4923d..ddb589e7cd7 100644
--- a/security.md
+++ b/security.md
@@ -179,6 +179,11 @@ You may also use HTTP Basic Authentication without setting a user identifier coo
return Auth::onceBasic();
});
+If you are using PHP FastCGI, HTTP Basic authentication will not work correctly by default. The following lines should be added to your `.htaccess` file:
+
+ RewriteCond %{HTTP:Authorization} ^(.+)$
+ RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+
## Password Reminders & Reset
@@ -262,7 +267,11 @@ Again, notice we are using the `Session` to display any errors that may be detec
Route::post('password/reset/{token}', function()
{
- $credentials = array('email' => Input::get('email'));
+ $credentials = array(
+ 'email' => Input::get('email'),
+ 'password' => Input::get('password'),
+ 'password_confirmation' => Input::get('password_confirmation')
+ );
return Password::reset($credentials, function($user, $password)
{
@@ -276,6 +285,8 @@ Again, notice we are using the `Session` to display any errors that may be detec
If the password reset is successful, the `User` instance and the password will be passed to your Closure, allowing you to actually perform the save operation. Then, you may return a `Redirect` or any other type of response from the Closure which will be returned by the `reset` method. Note that the `reset` method automatically checks for a valid `token` in the request, valid credentials, and matching passwords.
+By default, password reset tokens expire after one hour. You may change this via the `reminder.expire` option of your `app/config/auth.php` file.
+
Also, similarly to the `remind` method, if an error occurs while resetting the password, the `reset` method will return a `Redirect` to the current URI with an `error` and `reason`.
@@ -297,6 +308,6 @@ You may also set the cipher and mode used by the encrypter:
**Setting The Cipher & Mode**
- Crypt::setMode('crt');
+ Crypt::setMode('ctr');
Crypt::setCipher($cipher);
diff --git a/session.md b/session.md
index 64cd7e40a8e..ed8994eb419 100644
--- a/session.md
+++ b/session.md
@@ -4,6 +4,7 @@
- [Session Usage](#session-usage)
- [Flash Data](#flash-data)
- [Database Sessions](#database-sessions)
+- [Session Drivers](#session-drivers)
## Configuration
@@ -19,6 +20,10 @@ The session configuration is stored in `app/config/session.php`. Be sure to revi
Session::put('key', 'value');
+**Push A Value Onto An Array Session Value**
+
+ Session::push('user.teams', 'developers');
+
**Retrieving An Item From The Session**
$value = Session::get('key');
@@ -29,6 +34,10 @@ The session configuration is stored in `app/config/session.php`. Be sure to revi
$value = Session::get('key', function() { return 'default'; });
+**Retrieving All Data From The Session**
+
+ $data = Session::all();
+
**Determining If An Item Exists In The Session**
if (Session::has('users'))
@@ -81,4 +90,17 @@ Of course, you may use the `session:table` Artisan command to generate this migr
composer dump-autoload
- php artisan migrate
\ No newline at end of file
+ php artisan migrate
+
+
+## Session Drivers
+
+The session "driver" defines where session data will be stored for each request. Laravel ships with several great drivers out of the box:
+
+- `native` - sessions will be handled by internal PHP session facilities.
+- `cookie` - sessions will be stored in secure, encrypted cookies.
+- `database` - sessions will be stored in a database used by your application.
+- `memcached` / `redis` - sessions will be stored in one of these fast, cached based stores.
+- `array` - sessions will be stored in a simple PHP array and will not be persisted across requests.
+
+> **Note:** The array driver is typically used for running [unit tests](/docs/testing), so no session data will be persisted.
\ No newline at end of file
diff --git a/templates.md b/templates.md
index b89a828312d..d3b30d9ba8d 100644
--- a/templates.md
+++ b/templates.md
@@ -65,6 +65,10 @@ Blade is a simple, yet powerful templating engine provided with Laravel. Unlike
Note that views which `extend` a Blade layout simply override sections from the layout. Content of the layout can be included in a child view using the `@parent` directive in a section, allowing you to append to the contents of a layout section such as a sidebar or footer.
+Sometimes, such as when you are not sure if a section has been defined, you may wish to pass a default value to the `@yield` directive. You may pass the default value as the second argument:
+
+ @yield('section', 'Default Content');
+
## Other Blade Control Structures
@@ -74,10 +78,18 @@ Note that views which `extend` a Blade layout simply override sections from the
The current UNIX timestamp is {{ time() }}.
-To escape the output, you may use the triple curly brace syntax:
+If you need to display a string that is wrapped in curly braces, you may escape the Blade behavior by prefixing your text with an `@` symbol:
+
+**Displaying Raw Text With Curly Braces**
+
+ @{{ This will not be processed by Blade }}
+
+Of course, all user supplied data should be escaped or purified. To escape the output, you may use the triple curly brace syntax:
Hello, {{{ $name }}}.
+> **Note:** Be very careful when echoing content that is supplied by users of your application. Always use the triple curly brace syntax to escape any HTML entities in the content.
+
**If Statements**
@if (count($records) === 1)
@@ -109,6 +121,20 @@ To escape the output, you may use the triple curly brace syntax:
**Including Sub-Views**
@include('view.name')
+
+You may also pass an array of data to the included view:
+
+ @include('view.name', array('some'=>'data'))
+
+**Overwriting Sections**
+
+By default, sections are appended to any previous content that exists in the section. To overwrite a section entirely, you may use the `overwrite` statement:
+
+ @extends('list.item.container')
+
+ @section('list.item.content')
+
This is an item of type {{ $item->type }}
+ @overwrite
**Displaying Language Lines**
diff --git a/testing.md b/testing.md
index 0a5d1ee1056..1985242a8c0 100644
--- a/testing.md
+++ b/testing.md
@@ -73,6 +73,8 @@ To call a HTTPS route, you may use the `callSecure` method:
$response = $this->callSecure('GET', 'foo/bar');
+> **Note:** Route filters are disabled when in the testing environment. To enable them, add `Route::enableFilters()` to your test.
+
### DOM Crawler
You may also call a route and receive a DOM Crawler instance that you may use to inspect the content:
@@ -103,7 +105,7 @@ We can mock the call to the `Event` class by using the `shouldReceive` method on
public function testGetIndex()
{
- Event::shouldReceive('fire')->once()->with(array('name' => 'Dayle'));
+ Event::shouldReceive('fire')->once()->with('foo', array('name' => 'Dayle'));
$this->call('GET', '/');
}
diff --git a/validation.md b/validation.md
index 6898ba36ffb..732fcea6784 100644
--- a/validation.md
+++ b/validation.md
@@ -4,6 +4,7 @@
- [Working With Error Messages](#working-with-error-messages)
- [Error Messages & Views](#error-messages-and-views)
- [Available Validation Rules](#available-validation-rules)
+- [Conditionally Adding Rules](#conditionally-adding-rules)
- [Custom Error Messages](#custom-error-messages)
- [Custom Validation Rules](#custom-validation-rules)
@@ -29,6 +30,21 @@ Multiple rules may be delimited using either a "pipe" character, or as separate
array('name' => 'Dayle'),
array('name' => array('required', 'min:5'))
);
+
+**Validating Multiple Fields**
+
+ $validator = Validator::make(
+ array(
+ 'name' => 'Dayle',
+ 'password' => 'lamepassword',
+ 'email' => 'email@example.com'
+ ),
+ array(
+ 'name' => 'required',
+ 'password' => 'required|min:8',
+ 'email' => 'required|email|unique:users'
+ )
+ );
Once a `Validator` instance has been created, the `fails` (or `passes`) method may be used to perform the validation.
@@ -154,6 +170,7 @@ Below is a list of all available validation rules and their function:
- [Required](#rule-required)
- [Required If](#rule-required-if)
- [Required With](#rule-required-with)
+- [Required Without](#rule-required-without)
- [Same](#rule-same)
- [Size](#rule-size)
- [Unique (Database)](#rule-unique)
@@ -227,7 +244,7 @@ The field under validation must be formatted as an e-mail address.
#### exists:_table_,_column_
-The field under validation must exists on a given database table.
+The field under validation must exist on a given database table.
**Basic Usage Of Exists Rule**
@@ -312,6 +329,11 @@ The field under validation must be present if the _field_ field is equal to _val
The field under validation must be present _only if_ the other specified fields are present.
+
+#### required_without:_foo_,_bar_,...
+
+The field under validation must be present _only when_ the other specified fields are not present.
+
#### same:_field_
@@ -339,11 +361,45 @@ The field under validation must be unique on a given database table. If the `col
'email' => 'unique:users,email_address,10'
+**Adding Additional Where Clauses**
+
+You may also specify more conditions that will be added as "where" clauses to the query:
+
+ 'email' => 'unique:users,email_address,NULL,id,account_id,1'
+
+In the rule above, only rows with an `account_id` of `1` would be included in the unique check.
+
#### url
The field under validation must be formatted as an URL.
+
+## Conditionally Adding Rules
+
+Sometimes you may wish to require a given field only if another field has a greater value than 100. Or you may need two fields to have a given value only when another field is present. Adding these validation rules doens't have to be a pain. First, create a `Validator` instance with your _static rules_ that never change:
+
+ $v = Validator::make($data, array(
+ 'email' => 'required|email',
+ 'games' => 'required|numeric',
+ ));
+
+Let's assume our web application is for game collectors. If a game collector registers with our application and they own more than 100 games, we want them to explain why they own so many games. For example, perhaps they run a game re-sell shop, or maybe they just enjoy collecting. To conditionally add this requirement, we can use the `sometimes` method on the `Validator` instance.
+
+ $v->sometimes('reason', 'required|max:500', function($input)
+ {
+ return $input->games >= 100;
+ });
+
+The first argument passed to the `sometimes` method is the name of the field we are conditionally validating. The second argument is the rules we want to add. If the `Closure` passed as the third argument returns `true`, the rules will be added. This method makes it a breeze to build complex conditional validations. You may even add conditional validations for several fields at once:
+
+ $v->sometimes(array('reason', 'cost'), 'required', function($input)
+ {
+ return $input->games >= 100;
+ });
+
+> **Note:** The `$input` parameter passed to your `Closure` will be an instance of `Illuminate\Support\Fluent` and may be used as an object to access your input and files.
+
## Custom Error Messages
@@ -378,6 +434,7 @@ Sometimes you may wish to specify a custom error messages only for a specific fi
In some cases, you may wish to specify your custom messages in a language file instead of passing them directly to the `Validator`. To do so, add your messages to `custom` array in the `app/lang/xx/validation.php` language file.
+
**Specifying Custom Messages In Language Files**
'custom' => array(
@@ -398,8 +455,6 @@ Laravel provides a variety of helpful validation rules; however, you may wish to
return $value == 'foo';
});
-> **Note:** The name of the rule passed to the `extend` method must be "snake cased".
-
The custom validator Closure receives three arguments: the name of the `$attribute` being validated, the `$value` of the attribute, and an array of `$parameters` passed to the rule.
You may also pass a class and method to the `extend` method instead of a Closure: