diff --git a/apis.md b/apis.md old mode 100644 new mode 100755 diff --git a/artisan.md b/artisan.md old mode 100644 new mode 100755 diff --git a/authentication.md b/authentication.md old mode 100644 new mode 100755 index 99edacc..d62fb1c --- a/authentication.md +++ b/authentication.md @@ -79,7 +79,7 @@ If the redirect path needs custom generation logic you may define a `redirectTo` protected function redirectTo() { - // + return '/path'; } > {tip} The `redirectTo` method will take precedence over the `redirectTo` attribute. @@ -226,7 +226,7 @@ The `intended` method on the redirector will redirect the user to the URL they w #### Specifying Additional Conditions -If you wish, you also may add extra conditions to the authentication query in addition to the user's e-mail and password. For example, we may verify that user is marked as "active": +If you wish, you may also add extra conditions to the authentication query in addition to the user's e-mail and password. For example, we may verify that user is marked as "active": if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) { // The user is active, not suspended, and exists. @@ -383,7 +383,7 @@ You may define your own authentication guards using the `extend` method on the ` } } -As you can see in the example above, the callback passed to the `extend` method should return an implementation of `Illuminate\Contracts\Auth\Guard`. This interface contains a few methods you will need to implement to define a custom guard. Once your custom guard has been defined, you may use the guard in the `guards` configuration of your `auth.php` configuration file: +As you can see in the example above, the callback passed to the `extend` method should return an implementation of `Illuminate\Contracts\Auth\Guard`. This interface contains a few methods you will need to implement to define a custom guard. Once your custom guard has been defined, you may use this guard in the `guards` configuration of your `auth.php` configuration file: 'guards' => [ 'api' => [ @@ -403,7 +403,7 @@ If you are not using a traditional relational database to store your users, you use Illuminate\Support\Facades\Auth; use App\Extensions\RiakUserProvider; - use Illuminate\Support\ServiceProvider; + use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider { @@ -466,7 +466,7 @@ The `retrieveById` function typically receives a key representing the user, such The `retrieveByToken` function retrieves a user by their unique `$identifier` and "remember me" `$token`, stored in a field `remember_token`. As with the previous method, the `Authenticatable` implementation should be returned. -The `updateRememberToken` method updates the `$user` field `remember_token` with the new `$token`. The new token can be either a fresh token, assigned on a successful "remember me" login attempt, or `null` when the user is logging out. +The `updateRememberToken` method updates the `$user` field `remember_token` with the new `$token`. The new token can be either a fresh token, assigned on a successful "remember me" login attempt, or when the user is logging out. 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 `$credentials['username']`. The method should then return an implementation of `Authenticatable`. **This method should not attempt to do any password validation or authentication.** diff --git a/authorization.md b/authorization.md old mode 100644 new mode 100755 index 8974037..568531e --- a/authorization.md +++ b/authorization.md @@ -48,6 +48,40 @@ Gates are Closures that determine if a user is authorized to perform a given act }); } +Gates may also be defined using a `Class@method` style callback string, like controllers: + + /** + * Register any authentication / authorization services. + * + * @return void + */ + public function boot() + { + $this->registerPolicies(); + + Gate::define('update-post', 'PostPolicy@update'); + } + +#### Resource Gates + +You may also define multiple Gate abilities at once using the `resource` method: + + Gate::resource('posts', 'PostPolicy'); + +This is identical to manually defining the following Gate definitions: + + Gate::define('posts.view', 'PostPolicy@view'); + Gate::define('posts.create', 'PostPolicy@create'); + Gate::define('posts.update', 'PostPolicy@update'); + Gate::define('posts.delete', 'PostPolicy@delete'); + +By default, the `view`, `create`, `update`, and `delete` abilities will be defined. You may override or add to the default abilities by passing an array as a third argument to the `resource` method. The keys of the array define the names of the abilities while the values define the method names. For example, the following code will create two new Gate definitions - `posts.image` and `posts.photo`: + + Gate::resource('posts', 'PostPolicy', [ + 'image' => 'updateImage', + 'photo' => 'updatePhoto', + ]); + ### Authorizing Actions @@ -318,10 +352,10 @@ These directives are convenient shortcuts for writing `@if` and `@unless` statem Like most of the other authorization methods, you may pass a class name to the `@can` and `@cannot` directives if the action does not require a model instance: - @can('create', Post::class) + @can('create', App\Post::class) @endcan - @cannot('create', Post::class) + @cannot('create', App\Post::class) @endcannot diff --git a/billing.md b/billing.md old mode 100644 new mode 100755 index 83f7e5d..4e70577 --- a/billing.md +++ b/billing.md @@ -32,7 +32,7 @@ Laravel Cashier provides an expressive, fluent interface to [Stripe's](https://stripe.com) and [Braintree's](https://www.braintreepayments.com) subscription billing services. It handles almost all of the boilerplate subscription billing code you are dreading writing. In addition to basic subscription management, Cashier can handle coupons, swapping subscription, subscription "quantities", cancellation grace periods, and even generate invoice PDFs. -> {note} If you're only performing "one-off" charges and do not offer subscriptions. You should not use Cashier. You should use the Stripe and Braintree SDKs directly. +> {note} If you're only performing "one-off" charges and do not offer subscriptions, you should not use Cashier. Instead, use the Stripe and Braintree SDKs directly. ## Configuration @@ -42,9 +42,9 @@ Laravel Cashier provides an expressive, fluent interface to [Stripe's](https://s #### Composer -First, add the Cashier package for Stripe to your `composer.json` file and run the `composer update` command: +First, add the Cashier package for Stripe to your dependencies: - "laravel/cashier": "~7.0" + composer require "laravel/cashier":"~7.0" #### Service Provider @@ -92,6 +92,7 @@ Finally, you should configure your Stripe key in your `services.php` configurati 'stripe' => [ 'model' => App\User::class, + 'key' => env('STRIPE_KEY'), 'secret' => env('STRIPE_SECRET'), ], @@ -110,13 +111,15 @@ For many operations, the Stripe and Braintree implementations of Cashier functio #### Composer -First, add the Cashier package for Braintree to your `composer.json` file and run the `composer update` command: +First, add the Cashier package for Braintree to your dependencies: - "laravel/cashier-braintree": "~2.0" + composer require "laravel/cashier-braintree":"~2.0" #### Service Provider -Next, register the `Laravel\Cashier\CashierServiceProvider` [service provider](/docs/{{version}}/providers) in your `config/app.php` configuration file. +Next, register the `Laravel\Cashier\CashierServiceProvider` [service provider](/docs/{{version}}/providers) in your `config/app.php` configuration file: + + Laravel\Cashier\CashierServiceProvider::class #### Plan Credit Coupon @@ -199,11 +202,11 @@ To create a subscription, first retrieve an instance of your billable model, whi $user = User::find(1); - $user->newSubscription('main', 'monthly')->create($stripeToken); + $user->newSubscription('main', 'premium')->create($stripeToken); The first argument passed to the `newSubscription` method should be the name of the subscription. If your application only offers a single subscription, you might call this `main` or `primary`. The second argument is the specific Stripe / Braintree plan the user is subscribing to. This value should correspond to the plan's identifier in Stripe or Braintree. -The `create` method will begin the subscription as well as update your database with the customer ID and other relevant billing information. +The `create` method, which accepts a Stripe credit card / source token, will begin the subscription as well as update your database with the customer ID and other relevant billing information. #### Additional User Details @@ -310,7 +313,7 @@ Alternatively, you may set a specific quantity using the `updateQuantity` method $user->subscription('main')->updateQuantity(10); -For more information on subscription quantities, consult the [Stripe documentation](https://stripe.com/docs/guides/subscriptions#setting-quantities). +For more information on subscription quantities, consult the [Stripe documentation](https://stripe.com/docs/subscriptions/quantities). ### Subscription Taxes diff --git a/blade.md b/blade.md old mode 100644 new mode 100755 index ebd3e10..cc36f1b --- a/blade.md +++ b/blade.md @@ -144,23 +144,11 @@ Of course, you are not limited to displaying the contents of the variables passe The current UNIX timestamp is {{ time() }}. -> {note} Blade `{{ }}` statements are automatically sent through PHP's `htmlentities` function to prevent XSS attacks. - -#### Echoing Data If It Exists - -Sometimes you may wish to echo a variable, but you aren't sure if the variable has been set. We can express this in verbose PHP code like so: - - {{ isset($name) ? $name : 'Default' }} - -However, instead of writing a ternary statement, Blade provides you with the following convenient shortcut, which will be compiled to the ternary statement above: - - {{ $name or 'Default' }} - -In this example, if the `$name` variable exists, its value will be displayed. However, if it does not exist, the word `Default` will be displayed. +> {note} Blade `{{ }}` statements are automatically sent through PHP's `htmlspecialchars` function to prevent XSS attacks. #### Displaying Unescaped Data -By default, Blade `{{ }}` statements are automatically sent through PHP's `htmlentities` function to prevent XSS attacks. If you do not want your data to be escaped, you may use the following syntax: +By default, Blade `{{ }}` statements are automatically sent through PHP's `htmlspecialchars` function to prevent XSS attacks. If you do not want your data to be escaped, you may use the following syntax: Hello, {!! $name !!}. @@ -211,6 +199,16 @@ For convenience, Blade also provides an `@unless` directive: You are not signed in. @endunless +In addition to the conditional directives already discussed, the `@isset` and `@empty` directives may be used as convenient shortcuts for their respective PHP functions: + + @isset($records) + // $records is defined and is not null... + @endisset + + @empty($records) + // $records is "empty"... + @endempty + ### Loops @@ -339,6 +337,10 @@ Of course, if you attempt to `@include` a view which does not exist, Laravel wil @includeIf('view.name', ['some' => 'data']) +If you would like to `@include` a view depending on a given boolean condition, you may use the `@includeWhen` directive: + + @includeWhen($boolean, 'view.name', ['some' => 'data']) + > {note} You should avoid using the `__DIR__` and `__FILE__` constants in your Blade views, since they will refer to the location of the cached, compiled view. @@ -354,6 +356,8 @@ You may also pass a fourth argument to the `@each` directive. This argument dete @each('view.name', $jobs, 'job', 'view.empty') +> {note} Views rendered via `@each` do not inherit the variables from the parent view. If the child view requires these variables, you should use `@foreach` and `@include` instead. + ## Stacks diff --git a/broadcasting.md b/broadcasting.md old mode 100644 new mode 100755 index 596fff8..90b4e54 --- a/broadcasting.md +++ b/broadcasting.md @@ -1,4 +1,4 @@ -# Event Broadcasting +# Broadcasting - [Introduction](#introduction) - [Configuration](#configuration) @@ -9,6 +9,7 @@ - [Broadcast Name](#broadcast-name) - [Broadcast Data](#broadcast-data) - [Broadcast Queue](#broadcast-queue) + - [Broadcast Conditions](#broadcast-conditions) - [Authorizing Channels](#authorizing-channels) - [Defining Authorization Routes](#defining-authorization-routes) - [Defining Authorization Callbacks](#defining-authorization-callbacks) @@ -57,7 +58,7 @@ Before broadcasting any events, you will first need to register the `App\Provide If you are broadcasting your events over [Pusher](https://pusher.com), you should install the Pusher PHP SDK using the Composer package manager: - composer require pusher/pusher-php-server + composer require pusher/pusher-php-server "~2.6" Next, you should configure your Pusher credentials in the `config/broadcasting.php` configuration file. An example Pusher configuration is already included in this file, allowing you to quickly specify your Pusher key, secret, and application ID. The `config/broadcasting.php` file's `pusher` configuration also allows you to specify additional `options` that are supported by Pusher, such as the cluster: @@ -70,6 +71,8 @@ When using Pusher and [Laravel Echo](#installing-laravel-echo), you should speci import Echo from "laravel-echo" + window.Pusher = require('pusher-js'); + window.Echo = new Echo({ broadcaster: 'pusher', key: 'your-pusher-key' @@ -242,6 +245,13 @@ By default, Laravel will broadcast the event using the event's class name. Howev return 'server.created'; } +If you customize the broadcast name using the `broadcastAs` method, you should make sure to register your listener with a leading `.` character. This will instruct Echo to not prepend the application's namespace to the event: + + .listen('.server.created', function (e) { + .... + }); + + ### Broadcast Data @@ -279,6 +289,31 @@ By default, each broadcast event is placed on the default queue for the default */ public $broadcastQueue = 'your-queue-name'; +If you want to broadcast your event using the `sync` queue instead of the default queue driver, you can implement the `ShouldBroadcastNow` interface instead of `ShouldBroadcast`: + + +### Broadcast Conditions + +Sometimes you want to broadcast your event only if a given condition is true. You may define these conditions by adding a `broadcastWhen` method to your event class: + + /** + * Determine if this event should broadcast. + * + * @return bool + */ + public function broadcastWhen() + { + return $this->value > 100; + } + ## Authorizing Channels @@ -437,7 +472,7 @@ All presence channels are also private channels; therefore, users must be [autho The data returned by the authorization callback will be made available to the presence channel event listeners in your JavaScript application. If the user is not authorized to join the presence channel, you should return `false` or `null`: - Broadcast::channel('chat.*', function ($user, $roomId) { + Broadcast::channel('chat.{roomId}', function ($user, $roomId) { if ($user->canJoinRoom($roomId)) { return ['id' => $user->id, 'name' => $user->name]; } diff --git a/cache.md b/cache.md old mode 100644 new mode 100755 diff --git a/collections.md b/collections.md old mode 100644 new mode 100755 index e71060b..0dc4951 --- a/collections.md +++ b/collections.md @@ -48,13 +48,16 @@ For the remainder of this documentation, we'll discuss each method available on
[all](#method-all) +[average](#method-average) [avg](#method-avg) [chunk](#method-chunk) [collapse](#method-collapse) [combine](#method-combine) [contains](#method-contains) +[containsStrict](#method-containsstrict) [count](#method-count) [diff](#method-diff) +[diffAssoc](#method-diffassoc) [diffKeys](#method-diffkeys) [each](#method-each) [every](#method-every) @@ -71,15 +74,19 @@ For the remainder of this documentation, we'll discuss each method available on [has](#method-has) [implode](#method-implode) [intersect](#method-intersect) +[intersectKey](#method-intersectkey) [isEmpty](#method-isempty) +[isNotEmpty](#method-isnotempty) [keyBy](#method-keyby) [keys](#method-keys) [last](#method-last) [map](#method-map) [mapWithKeys](#method-mapwithkeys) [max](#method-max) +[median](#method-median) [merge](#method-merge) [min](#method-min) +[mode](#method-mode) [nth](#method-nth) [only](#method-only) [partition](#method-partition) @@ -105,16 +112,22 @@ For the remainder of this documentation, we'll discuss each method available on [split](#method-split) [sum](#method-sum) [take](#method-take) +[tap](#method-tap) +[times](#method-times) [toArray](#method-toarray) [toJson](#method-tojson) [transform](#method-transform) [union](#method-union) [unique](#method-unique) +[uniqueStrict](#method-uniquestrict) [values](#method-values) +[when](#method-when) [where](#method-where) [whereStrict](#method-wherestrict) [whereIn](#method-wherein) [whereInStrict](#method-whereinstrict) +[whereNotIn](#method-wherenotin) +[whereNotInStrict](#method-wherenotinstrict) [zip](#method-zip)
@@ -141,25 +154,23 @@ The `all` method returns the underlying array represented by the collection: // [1, 2, 3] - -#### `avg()` {#collection-method} + +#### `average()` {#collection-method} -The `avg` method returns the average of all items in the collection: +Alias for the [`avg`](#method-avg) method. - collect([1, 2, 3, 4, 5])->avg(); + +#### `avg()` {#collection-method} - // 3 +The `avg` method returns the [average value](https://en.wikipedia.org/wiki/Average) of a given key: -If the collection contains nested arrays or objects, you should pass a key to use for determining which values to calculate the average: + $average = collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]])->avg('foo'); - $collection = collect([ - ['name' => 'JavaScript: The Good Parts', 'pages' => 176], - ['name' => 'JavaScript: The Definitive Guide', 'pages' => 1096], - ]); + // 20 - $collection->avg('pages'); + $average = collect([1, 1, 2, 4])->avg(); - // 636 + // 2 #### `chunk()` {#collection-method} @@ -246,6 +257,13 @@ Finally, you may also pass a callback to the `contains` method to perform your o // false +The `contains` method uses "loose" comparisons when checking item values, meaning a string with an integer value will be considered equal to an integer of the same value. Use the [`containsStrict`](#method-containsstrict) method to filter using "strict" comparisons. + + +#### `containsStrict()` {#collection-method} + +This method has the same signature as the [`contains`](#method-contains) method; however, all values are compared using "strict" comparisons. + #### `count()` {#collection-method} @@ -270,6 +288,28 @@ The `diff` method compares the collection against another collection or a plain // [1, 3, 5] + +#### `diffAssoc()` {#collection-method} + +The `diffAssoc` method compares the collection against another collection or a plain PHP `array` based on its keys and values. This method will return the key / value pairs in the original collection that are not present in the given collection: + + $collection = collect([ + 'color' => 'orange', + 'type' => 'fruit', + 'remain' => 6 + ]); + + $diff = $collection->diffAssoc([ + 'color' => 'yellow', + 'type' => 'fruit', + 'remain' => 3, + 'used' => 6 + ]); + + $diff->all(); + + // ['color' => 'orange', 'remain' => 6] + #### `diffKeys()` {#collection-method} @@ -594,6 +634,23 @@ The `intersect` method removes any values from the original collection that are // [0 => 'Desk', 2 => 'Chair'] + +#### `intersectKey()` {#collection-method} + +The `intersectKey` method removes any keys from the original collection that are not present in the given `array` or collection: + + $collection = collect([ + 'serial' => 'UX301', 'type' => 'screen', 'year' => 2009 + ]); + + $intersect = $collection->intersectKey([ + 'reference' => 'UX404', 'type' => 'tab', 'year' => 2011 + ]); + + $intersect->all(); + + // ['type' => 'screen', 'year' => 2009] + #### `isEmpty()` {#collection-method} @@ -603,6 +660,15 @@ The `isEmpty` method returns `true` if the collection is empty; otherwise, `fals // true + +#### `isNotEmpty()` {#collection-method} + +The `isNotEmpty` method returns `true` if the collection is not empty; otherwise, `false` is returned: + + collect([])->isNotEmpty(); + + // false + #### `keyBy()` {#collection-method} @@ -639,7 +705,6 @@ You may also pass a callback to the method. The callback should return the value ] */ - #### `keys()` {#collection-method} @@ -734,10 +799,23 @@ The `max` method returns the maximum value of a given key: // 5 + +#### `median()` {#collection-method} + +The `median` method returns the [median value](https://en.wikipedia.org/wiki/Median) of a given key: + + $median = collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]])->median('foo'); + + // 15 + + $median = collect([1, 1, 2, 4])->median(); + + // 1.5 + #### `merge()` {#collection-method} -The `merge` method merges the given array with the original collection. If a string key in the given array matches a string key in the original collection, the given array's value will overwrite the value in the original collection: +The `merge` method merges the given array or collection with the original collection. If a string key in the given items matches a string key in the original collection, the given items's value will overwrite the value in the original collection: $collection = collect(['product_id' => 1, 'price' => 100]); @@ -747,7 +825,7 @@ The `merge` method merges the given array with the original collection. If a str // ['product_id' => 1, 'price' => 200, 'discount' => false] -If the given array's keys are numeric, the values will be appended to the end of the collection: +If the given items's keys are numeric, the values will be appended to the end of the collection: $collection = collect(['Desk', 'Chair']); @@ -770,6 +848,19 @@ The `min` method returns the minimum value of a given key: // 1 + +#### `mode()` {#collection-method} + +The `mode` method returns the [mode value](https://en.wikipedia.org/wiki/Mode_(statistics)) of a given key: + + $mode = collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]])->mode('foo'); + + // [10] + + $mode = collect([1, 1, 2, 4])->mode(); + + // [1] + #### `nth()` {#collection-method} @@ -880,13 +971,13 @@ The `prepend` method adds an item to the beginning of the collection: You may also pass a second argument to set the key of the prepended item: - $collection = collect(['one' => 1, 'two', => 2]); + $collection = collect(['one' => 1, 'two' => 2]); $collection->prepend(0, 'zero'); $collection->all(); - // ['zero' => 0, 'one' => 1, 'two', => 2] + // ['zero' => 0, 'one' => 1, 'two' => 2] #### `pull()` {#collection-method} @@ -1010,7 +1101,7 @@ The `search` method searches the collection for the given value and returns its // 1 -The search is done using a "loose" comparison, meaning a string with an integer value will be considered equal to an integer of the same value. To use strict comparison, pass `true` as the second argument to the method: +The search is done using a "loose" comparison, meaning a string with an integer value will be considered equal to an integer of the same value. To use "strict" comparison, pass `true` as the second argument to the method: $collection->search('4', true); @@ -1050,7 +1141,7 @@ The `shuffle` method randomly shuffles the items in the collection: $shuffled->all(); - // [3, 2, 5, 1, 4] // (generated randomly) + // [3, 2, 5, 1, 4] - (generated randomly) #### `slice()` {#collection-method} @@ -1073,7 +1164,7 @@ If you would like to limit the size of the returned slice, pass the desired size // [5, 6] -The returned slice will preserve keys by default. If you do not wish to preserve the original keys, you can use the `values` method to reindex them. +The returned slice will preserve keys by default. If you do not wish to preserve the original keys, you can use the [`values`](#method-values) method to reindex them. #### `sort()` {#collection-method} @@ -1257,6 +1348,49 @@ You may also pass a negative integer to take the specified amount of items from // [4, 5] + +#### `tap()` {#collection-method} + +The `tap` method passes the collection to the given callback, allowing you to "tap" into the collection at a specific point and do something with the items while not affecting the collection itself: + + collect([2, 4, 3, 1, 5]) + ->sort() + ->tap(function ($collection) { + Log::debug('Values after sorting', $collection->values()->toArray()); + }) + ->shift(); + + // 1 + + +#### `times()` {#collection-method} + +The static `times` method creates a new collection by invoking the callback a given amount of times: + + $collection = Collection::times(10, function ($number) { + return $number * 9; + }); + + $collection->all(); + + // [9, 18, 27, 36, 45, 54, 63, 72, 81, 90] + +This method can be useful when combined with factories to create [Eloquent](/docs/{{version}}/eloquent) models: + + $categories = Collection::times(3, function ($number) { + return factory(Category::class)->create(['name' => 'Category #'.$number]); + }); + + $categories->all(); + + /* + [ + ['id' => 1, 'name' => 'Category #1'], + ['id' => 2, 'name' => 'Category #2'], + ['id' => 3, 'name' => 'Category #3'], + ] + */ + #### `toArray()` {#collection-method} @@ -1277,7 +1411,7 @@ The `toArray` method converts the collection into a plain PHP `array`. If the co #### `toJson()` {#collection-method} -The `toJson` method converts the collection into JSON: +The `toJson` method converts the collection into a JSON serialized string: $collection = collect(['name' => 'Desk', 'price' => 200]); @@ -1366,6 +1500,13 @@ You may also pass your own callback to determine item uniqueness: ] */ +The `unique` method uses "loose" comparisons when checking item values, meaning a string with an integer value will be considered equal to an integer of the same value. Use the [`uniqueStrict`](#method-uniquestrict) method to filter using "strict" comparisons. + + +#### `uniqueStrict()` {#collection-method} + +This method has the same signature as the [`unique`](#method-unique) method; however, all values are compared using "strict" comparisons. + #### `values()` {#collection-method} @@ -1386,6 +1527,22 @@ The `values` method returns a new collection with the keys reset to consecutive 1 => ['product' => 'Desk', 'price' => 200], ] */ + + +#### `when()` {#collection-method} + +The `when` method will execute the given callback when the first argument given to the method evaluates to `true`: + + $collection = collect([1, 2, 3]); + + $collection->when(true, function ($collection) { + return $collection->push(4); + }); + + $collection->all(); + + // [1, 2, 3, 4] + #### `where()` {#collection-method} @@ -1403,13 +1560,13 @@ The `where` method filters the collection by a given key / value pair: $filtered->all(); /* - [ - ['product' => 'Chair', 'price' => 100], - ['product' => 'Door', 'price' => 100], - ] + [ + ['product' => 'Chair', 'price' => 100], + ['product' => 'Door', 'price' => 100], + ] */ -The `where` method uses loose comparisons when checking item values. Use the [`whereStrict`](#method-wherestrict) method to filter using "strict" comparisons. +The `where` method uses "loose" comparisons when checking item values, meaning a string with an integer value will be considered equal to an integer of the same value. Use the [`whereStrict`](#method-wherestrict) method to filter using "strict" comparisons. #### `whereStrict()` {#collection-method} @@ -1419,7 +1576,7 @@ This method has the same signature as the [`where`](#method-where) method; howev #### `whereIn()` {#collection-method} -The `whereIn` method filters the collection by a given key / value contained within the given array. +The `whereIn` method filters the collection by a given key / value contained within the given array: $collection = collect([ ['product' => 'Desk', 'price' => 200], @@ -1433,18 +1590,48 @@ The `whereIn` method filters the collection by a given key / value contained wit $filtered->all(); /* - [ - ['product' => 'Bookcase', 'price' => 150], - ['product' => 'Desk', 'price' => 200], - ] + [ + ['product' => 'Bookcase', 'price' => 150], + ['product' => 'Desk', 'price' => 200], + ] */ -The `whereIn` method uses "loose" comparisons when checking item values. Use the [`whereInStrict`](#method-whereinstrict) method to filter using strict comparisons. +The `whereIn` method uses "loose" comparisons when checking item values, meaning a string with an integer value will be considered equal to an integer of the same value. Use the [`whereInStrict`](#method-whereinstrict) method to filter using "strict" comparisons. #### `whereInStrict()` {#collection-method} -This method has the same signature as the [`whereIn`](#method-wherein) method; however, all values are compared using strict comparisons. +This method has the same signature as the [`whereIn`](#method-wherein) method; however, all values are compared using "strict" comparisons. + + +#### `whereNotIn()` {#collection-method} + +The `whereNotIn` method filters the collection by a given key / value not contained within the given array: + + $collection = collect([ + ['product' => 'Desk', 'price' => 200], + ['product' => 'Chair', 'price' => 100], + ['product' => 'Bookcase', 'price' => 150], + ['product' => 'Door', 'price' => 100], + ]); + + $filtered = $collection->whereNotIn('price', [150, 200]); + + $filtered->all(); + + /* + [ + ['product' => 'Chair', 'price' => 100], + ['product' => 'Door', 'price' => 100], + ] + */ + +The `whereNotIn` method uses "loose" comparisons when checking item values, meaning a string with an integer value will be considered equal to an integer of the same value. Use the [`whereNotInStrict`](#method-wherenotinstrict) method to filter using "strict" comparisons. + + +#### `whereNotInStrict()` {#collection-method} + +This method has the same signature as the [`whereNotIn`](#method-wherenotin) method; however, all values are compared using "strict" comparisons. #### `zip()` {#collection-method} @@ -1462,7 +1649,7 @@ The `zip` method merges together the values of the given array with the values o ## Higher Order Messages -Collections also provide support for "higher order messages", which are short-cuts for performing common actions on collections. The collection methods that provide higher order messages are: `contains`, `each`, `every`, `filter`, `first`, `map`, `partition`, `reject`, `sortBy`, `sortByDesc`, and `sum`. +Collections also provide support for "higher order messages", which are short-cuts for performing common actions on collections. The collection methods that provide higher order messages are: `average`, `avg`, `contains`, `each`, `every`, `filter`, `first`, `flatMap`, `map`, `partition`, `reject`, `sortBy`, `sortByDesc`, and `sum`. Each higher order message can be accessed as a dynamic property on a collection instance. For instance, let's use the `each` higher order message to call a method on each object within a collection: diff --git a/configuration.md b/configuration.md old mode 100644 new mode 100755 index a72764b..568153a --- a/configuration.md +++ b/configuration.md @@ -2,6 +2,7 @@ - [Introduction](#introduction) - [Environment Configuration](#environment-configuration) + - [Retrieving Environment Configuration](#retrieving-environment-configuration) - [Determining The Current Environment](#determining-the-current-environment) - [Accessing Configuration Values](#accessing-configuration-values) - [Configuration Caching](#configuration-caching) @@ -15,13 +16,18 @@ All of the configuration files for the Laravel framework are stored in the `conf ## Environment Configuration -It is often helpful to have different configuration values based on the environment the application is running in. For example, you may wish to use a different cache driver locally than you do on your production server. +It is often helpful to have different configuration values based on the environment where the application is running. For example, you may wish to use a different cache driver locally than you do on your production server. To make this a cinch, Laravel utilizes the [DotEnv](https://github.com/vlucas/phpdotenv) PHP library by Vance Lucas. In a fresh Laravel installation, the root directory of your application will contain a `.env.example` file. If you install Laravel via Composer, this file will automatically be renamed to `.env`. Otherwise, you should rename the file manually. -> {tip} You may also create a `.env.testing` file. This file will override values from the `.env` file when running PHPUnit tests or executing Artisan commands with the `--env=testing` option. +Your `.env` file should not be committed to your application's source control, since each developer / server using your application could require a different environment configuration. Furthermore, this would be a security risk in the event an intruder gain access to your source control repository, since any sensitive credentials would get exposed. -#### Retrieving Environment Configuration +If you are developing with a team, you may wish to continue including a `.env.example` file with your application. By putting place-holder values in the example configuration file, other developers on your team can clearly see which environment variables are needed to run your application. You may also create a `.env.testing` file. This file will override values from the `.env` file when running PHPUnit tests or executing Artisan commands with the `--env=testing` option. + +> {tip} Any variable in your `.env` file can be overridden by external environment variables such as server-level or system-level environment variables. + + +### Retrieving Environment Configuration All of the variables listed in this file will be loaded into the `$_ENV` PHP super-global when your application receives a request. However, you may use the `env` helper to retrieve values from these variables in your configuration files. In fact, if you review the Laravel configuration files, you will notice several of the options already using this helper: @@ -29,10 +35,6 @@ All of the variables listed in this file will be loaded into the `$_ENV` PHP sup The second value passed to the `env` function is the "default value". This value will be used if no environment variable exists for the given key. -Your `.env` file should not be committed to your application's source control, since each developer / server using your application could require a different environment configuration. - -If you are developing with a team, you may wish to continue including a `.env.example` file with your application. By putting place-holder values in the example configuration file, other developers on your team can clearly see which environment variables are needed to run your application. - ### Determining The Current Environment @@ -46,10 +48,12 @@ You may also pass arguments to the `environment` method to check if the environm // The environment is local } - if (App::environment('local', 'staging')) { + if (App::environment(['local', 'staging'])) { // The environment is either local OR staging... } +> {tip} The current application environment detection can be overriden by a server-level `APP_ENV` environment variable. This can be useful when you need to share the same application for different environment configurations, so you can set up a given host to match a given environment in your server's configurations. + ## Accessing Configuration Values @@ -87,9 +91,7 @@ To disable maintenance mode, use the `up` command: php artisan up -#### Maintenance Mode Response Template - -The default template for maintenance mode responses is located in `resources/views/errors/503.blade.php`. You are free to modify this view as needed for your application. +> {tip} You may customize the default maintenance mode template by defining your own template at `resources/views/errors/503.blade.php`. #### Maintenance Mode & Queues diff --git a/container.md b/container.md old mode 100644 new mode 100755 index 5431105..365911c --- a/container.md +++ b/container.md @@ -10,6 +10,7 @@ - [The Make Method](#the-make-method) - [Automatic Injection](#automatic-injection) - [Container Events](#container-events) +- [PSR-11](#psr-11) ## Introduction @@ -98,7 +99,7 @@ You may also bind an existing object instance into the container using the `inst $api = new HelpSpot\API(new HttpClient); - $this->app->instance('HelpSpot\Api', $api); + $this->app->instance('HelpSpot\API', $api); #### Binding Primitives @@ -190,6 +191,10 @@ If you are in a location of your code that does not have access to the `$app` va $api = resolve('HelpSpot\API'); +If some of your class' dependencies are not resolvable via the container, you may inject them by passing them as an associative array into the `makeWith` method: + + $api = $this->app->makeWith('HelpSpot\API', ['id' => 1]); + #### Automatic Injection @@ -247,3 +252,18 @@ The service container fires an event each time it resolves an object. You may li }); As you can see, the object being resolved will be passed to the callback, allowing you to set any additional properties on the object before it is given to its consumer. + + +## PSR-11 + +Laravel's service container implements the [PSR-11](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md) interface. Therefore, you may type-hint the PSR-11 container interface to obtain an instance of the Laravel container: + + use Psr\Container\ContainerInterface; + + Route::get('/', function (ContainerInterface $container) { + $service = $container->get('Service'); + + // + }); + +> {note} Calling the `get` method will throw an exception if the identifier has not been explicitly bound into the container. diff --git a/contracts.md b/contracts.md old mode 100644 new mode 100755 index 4d8a820..df6819d --- a/contracts.md +++ b/contracts.md @@ -192,7 +192,7 @@ Contract | References Facade [Illuminate\Contracts\Mail\Mailer](https://github.com/illuminate/contracts/blob/{{version}}/Mail/Mailer.php) | Mail [Illuminate\Contracts\Queue\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Queue/Factory.php) | Queue::driver() [Illuminate\Contracts\Queue\Queue](https://github.com/illuminate/contracts/blob/{{version}}/Queue/Queue.php) | Queue -[Illuminate\Contracts\Redis\Database](https://github.com/illuminate/contracts/blob/{{version}}/Redis/Database.php) | Redis +[Illuminate\Contracts\Redis\Factory](https://github.com/illuminate/contracts/blob/{{version}}/Redis/Factory.php) | Redis [Illuminate\Contracts\Routing\Registrar](https://github.com/illuminate/contracts/blob/{{version}}/Routing/Registrar.php) | Route [Illuminate\Contracts\Routing\ResponseFactory](https://github.com/illuminate/contracts/blob/{{version}}/Routing/ResponseFactory.php) | Response [Illuminate\Contracts\Routing\UrlGenerator](https://github.com/illuminate/contracts/blob/{{version}}/Routing/UrlGenerator.php) | URL diff --git a/contributing.md b/contributing.md old mode 100644 new mode 100755 index 266c057..e68c3d3 --- a/contributing.md +++ b/contributing.md @@ -1,17 +1,3 @@ -# ပူးပေါင်းပါဝင်မှု လမ်းညွန် +# Contribution Guidelines -###ဘာသာပြန်ခြင်း - - - ကျွန်တော်တို့ကို ပူးပေါင်းပါဝင် ကူညီပြီးဘာသာပြန်ချင်တယ်ဆိုရင် - [docs](https://github.com/setkyar/laravel-docs/) ကိုဦးစွာ Fork လုပ်ပါ၊ - - - ဘယ်အပိုင်းကို ဘာသာပြန်မည်ဆိုတာကို [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပြောပေးပါ။ (Fork - လုပ်ပြီးဘာသာပြန်နေတုန်းအခြားတစ်ယောက်ယောက်ကပါဘာသာပြန်နေတာမျိုးဖြစ်မှာစိုးလို့ပါ) - - - သင်ဘာသာပြန်မည့် File ကိုဘာသာပြန်ပါ။ ဘာသာပြန်ပြီးရင် မူရင်း repo ဆီက - [pull request](https://github.com/setkyar/laravel-docs/pulls) တောင်းပါ။ (pull request တောင်းတာကို မြန်မြန် accept - လုပ်စေချင်တယ်ဆိုရင်[Facebook]( https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) - -###ဘာသာပြန်အဆင်ပြေမှူနှင့် စာလုံးပေါင်းအမှား - -ဘာသာပြန်ထားတာတွေ ကိုဦးစွာဖတ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူ နဲ့ စာလုံးပေါင်း အမှားတွေကို စစ်ပါ။ ဘာသာပြန်အဆင်ပြေမှူမရှိတာတို့ စာလုံးပေါင်းအမှားတွေတွေ့ရင် GitHub မှာ [issue](https://github.com/setkyar/laravel-docs/issues) တင်ပေးပါ။(အမှားတွေကို အမြန်ဆုံး စစ်ပေးဖို့ [Facebook](https://www.facebook.com/groups/250409601822202/) မှာပါတင်ပေးပါ) +If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 5.1 would be submitted to the `5.1` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch. \ No newline at end of file diff --git a/contributions.md b/contributions.md old mode 100644 new mode 100755 index 9c94c09..f0f9d80 --- a/contributions.md +++ b/contributions.md @@ -19,19 +19,21 @@ Remember, bug reports are created in the hope that others with the same problem The Laravel source code is managed on Github, and there are repositories for each of the Laravel projects: -- [Laravel Framework](https://github.com/laravel/framework) +
- [Laravel Application](https://github.com/laravel/laravel) +- [Laravel Art](https://github.com/laravel/art) - [Laravel Documentation](https://github.com/laravel/docs) - [Laravel Cashier](https://github.com/laravel/cashier) - [Laravel Cashier for Braintree](https://github.com/laravel/cashier-braintree) - [Laravel Envoy](https://github.com/laravel/envoy) +- [Laravel Framework](https://github.com/laravel/framework) - [Laravel Homestead](https://github.com/laravel/homestead) - [Laravel Homestead Build Scripts](https://github.com/laravel/settler) - [Laravel Passport](https://github.com/laravel/passport) - [Laravel Scout](https://github.com/laravel/scout) - [Laravel Socialite](https://github.com/laravel/socialite) - [Laravel Website](https://github.com/laravel/laravel.com) -- [Laravel Art](https://github.com/laravel/art) +
## Core Development Discussion diff --git a/controllers.md b/controllers.md old mode 100644 new mode 100755 index 307df0d..0348d48 --- a/controllers.md +++ b/controllers.md @@ -10,6 +10,7 @@ - [Partial Resource Routes](#restful-partial-resource-routes) - [Naming Resource Routes](#restful-naming-resource-routes) - [Naming Resource Route Parameters](#restful-naming-resource-route-parameters) + - [Localizing Resource URIs](#restful-localizing-resource-uris) - [Supplementing Resource Controllers](#restful-supplementing-resource-controllers) - [Dependency Injection & Controllers](#dependency-injection-and-controllers) - [Route Caching](#route-caching) @@ -205,6 +206,32 @@ By default, `Route::resource` will create the route parameters for your resource /user/{admin_user} + +### Localizing Resource URIs + +By default, `Route::resource` will create resource URIs using English verbs. If you need to localize the `create` and `edit` action verbs, you may use the `Route::resourceVerbs` method. This may be done in the `boot` method of your `AppServiceProvider`: + + use Illuminate\Support\Facades\Route; + + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + Route::resourceVerbs([ + 'create' => 'crear', + 'edit' => 'editar', + ]); + } + +Once the verbs have been customized, a resource route registration such as `Route::resource('fotos', 'PhotoController')` will produce the following URIs: + + /fotos/crear + + /fotos/{foto}/editar + ### Supplementing Resource Controllers diff --git a/csrf.md b/csrf.md old mode 100644 new mode 100755 index 7533ffc..4694d34 --- a/csrf.md +++ b/csrf.md @@ -21,6 +21,10 @@ Anytime you define a HTML form in your application, you should include a hidden The `VerifyCsrfToken` [middleware](/docs/{{version}}/middleware), which is included in the `web` middleware group, will automatically verify that the token in the request input matches the token stored in the session. +#### CSRF Tokens & JavaScript + +When building JavaScript driven applications, it is convenient to have your JavaScript HTTP library automatically attach the CSRF token to every outgoing request. By default, the `resources/assets/js/bootstrap.js` file registers the value of the `csrf-token` meta tag with the Axios HTTP library. If you are not using this library, you will need to manually configure this behavior for your application. + ## Excluding URIs From CSRF Protection @@ -61,9 +65,11 @@ Then, once you have created the `meta` tag, you can instruct a library like jQue } }); +> {tip} By default, the `resources/assets/js/bootstrap.js` file registers the value of the `csrf-token` meta tag with the Axios HTTP library. If you are not using this library, you will need to manually configure this behavior for your application. + ## X-XSRF-TOKEN Laravel stores the current CSRF token in a `XSRF-TOKEN` cookie that is included with each response generated by the framework. You can use the cookie value to set the `X-XSRF-TOKEN` request header. -This cookie is primarily sent as a convenience since some JavaScript frameworks, like Angular, automatically place its value in the `X-XSRF-TOKEN` header. +This cookie is primarily sent as a convenience since some JavaScript frameworks and libraries, like Angular and Axios, automatically place its value in the `X-XSRF-TOKEN` header. diff --git a/database-testing.md b/database-testing.md old mode 100644 new mode 100755 index 36f10e8..1684d5a --- a/database-testing.md +++ b/database-testing.md @@ -10,6 +10,7 @@ - [Creating Models](#creating-models) - [Persisting Models](#persisting-models) - [Relationships](#relationships) +- [Available Assertions](#available-assertions) ## Introduction @@ -25,6 +26,8 @@ Laravel provides a variety of helpful tools to make it easier to test your datab ]); } +You can also used the `assertDatabaseMissing` helper to assert that data does not exist in the database. + Of course, the `assertDatabaseHas` method and other helpers like it are for convenience. You are free to use any of PHPUnit's built-in assertion methods to supplement your tests. @@ -119,11 +122,17 @@ Of course, you are free to add your own additional factories to the `ModelFactor ### Factory States -States allow you to define discrete modifications that can be applied to your model factories in any combination. For example, your `User` model might have a `delinquent` state that modifies one of its default attribute values. You may define your state transformations using the `state` method: +States allow you to define discrete modifications that can be applied to your model factories in any combination. For example, your `User` model might have a `delinquent` state that modifies one of its default attribute values. You may define your state transformations using the `state` method. For simple states, you may pass an array of attribute modifications: + + $factory->state(App\User::class, 'delinquent', [ + 'account_status' => 'delinquent', + ]); + +If your state requires calculation or a `$faker` instance, you may use a Closure to calculate the state's attribute modifications: - $factory->state(App\User::class, 'delinquent', function ($faker) { + $factory->state(App\User::class, 'address', function ($faker) { return [ - 'account_status' => 'delinquent', + 'address' => $faker->address, ]; }); @@ -224,3 +233,14 @@ These Closures also receive the evaluated attribute array of the factory that de } ]; }); + + +## Available Assertions + +Laravel provides several database assertions for your [PHPUnit](https://phpunit.de/) tests: + +Method | Description +------------- | ------------- +`$this->assertDatabaseHas($table, array $data);` | Assert that a table in the database contains the given data. +`$this->assertDatabaseMissing($table, array $data);` | Assert that a table in the database does not contain the given data. +`$this->assertSoftDeleted($table, array $data);` | Assert that the given record has been soft deleted. diff --git a/database.md b/database.md old mode 100644 new mode 100755 index 3090a0f..701304a --- a/database.md +++ b/database.md @@ -66,8 +66,8 @@ To see how read / write connections should be configured, let's look at this exa 'database' => 'database', 'username' => 'root', 'password' => '', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', ], diff --git a/documentation.md b/documentation.md old mode 100644 new mode 100755 index ab11db8..1c6d510 --- a/documentation.md +++ b/documentation.md @@ -1,22 +1,21 @@ -- Prologue +- ## Prologue - [Release Notes](/docs/{{version}}/releases) - [Upgrade Guide](/docs/{{version}}/upgrade) - [Contribution Guide](/docs/{{version}}/contributions) - [API Documentation](/api/{{version}}) -- Getting Started +- ## Getting Started - [Installation](/docs/{{version}}/installation) - [Configuration](/docs/{{version}}/configuration) - [Directory Structure](/docs/{{version}}/structure) - - [Request Lifecycle](/docs/{{version}}/lifecycle) -- Dev Environments - [Homestead](/docs/{{version}}/homestead) - [Valet](/docs/{{version}}/valet) -- Core Concepts +- ## Architecture Concepts + - [Request Lifecycle](/docs/{{version}}/lifecycle) - [Service Container](/docs/{{version}}/container) - [Service Providers](/docs/{{version}}/providers) - [Facades](/docs/{{version}}/facades) - [Contracts](/docs/{{version}}/contracts) -- The HTTP Layer +- ## The Basics - [Routing](/docs/{{version}}/routing) - [Middleware](/docs/{{version}}/middleware) - [CSRF Protection](/docs/{{version}}/csrf) @@ -26,52 +25,52 @@ - [Views](/docs/{{version}}/views) - [Session](/docs/{{version}}/session) - [Validation](/docs/{{version}}/validation) -- Frontend + - [Errors & Logging](/docs/{{version}}/errors) +- ## Frontend - [Blade Templates](/docs/{{version}}/blade) - [Localization](/docs/{{version}}/localization) - [Frontend Scaffolding](/docs/{{version}}/frontend) - [Compiling Assets](/docs/{{version}}/mix) -- Security +- ## Security - [Authentication](/docs/{{version}}/authentication) - [API Authentication](/docs/{{version}}/passport) - [Authorization](/docs/{{version}}/authorization) - [Encryption](/docs/{{version}}/encryption) - [Hashing](/docs/{{version}}/hashing) - [Password Reset](/docs/{{version}}/passwords) -- General Topics +- ## Digging Deeper - [Artisan Console](/docs/{{version}}/artisan) - [Broadcasting](/docs/{{version}}/broadcasting) - [Cache](/docs/{{version}}/cache) - [Collections](/docs/{{version}}/collections) - - [Errors & Logging](/docs/{{version}}/errors) - [Events](/docs/{{version}}/events) - [File Storage](/docs/{{version}}/filesystem) - [Helpers](/docs/{{version}}/helpers) - [Mail](/docs/{{version}}/mail) - [Notifications](/docs/{{version}}/notifications) - - [Packages](/docs/{{version}}/packages) + - [Package Development](/docs/{{version}}/packages) - [Queues](/docs/{{version}}/queues) - - [Scheduled Tasks](/docs/{{version}}/scheduling) -- Database + - [Task Scheduling](/docs/{{version}}/scheduling) +- ## Database - [Getting Started](/docs/{{version}}/database) - [Query Builder](/docs/{{version}}/queries) - [Pagination](/docs/{{version}}/pagination) - [Migrations](/docs/{{version}}/migrations) - [Seeding](/docs/{{version}}/seeding) - [Redis](/docs/{{version}}/redis) -- Eloquent ORM +- ## Eloquent ORM - [Getting Started](/docs/{{version}}/eloquent) - [Relationships](/docs/{{version}}/eloquent-relationships) - [Collections](/docs/{{version}}/eloquent-collections) - [Mutators](/docs/{{version}}/eloquent-mutators) - [Serialization](/docs/{{version}}/eloquent-serialization) -- Testing +- ## Testing - [Getting Started](/docs/{{version}}/testing) - [HTTP Tests](/docs/{{version}}/http-tests) - [Browser Tests](/docs/{{version}}/dusk) - [Database](/docs/{{version}}/database-testing) - [Mocking](/docs/{{version}}/mocking) -- Official Packages +- ## Official Packages - [Cashier](/docs/{{version}}/billing) - [Envoy](/docs/{{version}}/envoy) - [Passport](/docs/{{version}}/passport) diff --git a/dusk.md b/dusk.md old mode 100644 new mode 100755 index 1010224..780df0d --- a/dusk.md +++ b/dusk.md @@ -3,6 +3,7 @@ - [Introduction](#introduction) - [Installation](#installation) - [Using Other Browsers](#using-other-browsers) + - [ChromeDriver Options](#chromedriver-options) - [Getting Started](#getting-started) - [Generating Tests](#generating-tests) - [Running Tests](#running-tests) @@ -25,6 +26,9 @@ - [Navigating To Pages](#navigating-to-pages) - [Shorthand Selectors](#shorthand-selectors) - [Page Methods](#page-methods) +- [Continuous Integration](#continuous-integration) + - [Travis CI](#running-tests-on-travis-ci) + - [CircleCI](#running-tests-on-circle-ci) ## Introduction @@ -36,9 +40,9 @@ Laravel Dusk provides an expressive, easy-to-use browser automation and testing To get started, you should add the `laravel/dusk` Composer dependency to your project: - composer require laravel/dusk + composer require --dev laravel/dusk -Once Dusk is installed, you should register the `Laravel\Dusk\DuskServiceProvider` service provider. You should register the provider within the `register` method of your `AppServiceProvider` in order to limit the environments in which Dusk is available, since it exposes the ability to login as other users: +Once Dusk is installed, you should register the `Laravel\Dusk\DuskServiceProvider` service provider. You should register the provider within the `register` method of your `AppServiceProvider` in order to limit the environments in which Dusk is available, since it exposes the ability to log in as other users: use Laravel\Dusk\DuskServiceProvider; @@ -92,7 +96,30 @@ Next, you may simply modify the `driver` method to connect to the URL and port o protected function driver() { return RemoteWebDriver::create( - 'http://localhost:4444', DesiredCapabilities::phantomjs() + 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs() + ); + } + + +### ChromeDriver Options + +To customize the ChromeDriver session, you may modify the `driver` method of the `DuskTestCase` class: + + use Facebook\WebDriver\Chrome\ChromeOptions; + + /** + * Create the RemoteWebDriver instance. + * + * @return \Facebook\WebDriver\Remote\RemoteWebDriver + */ + protected function driver() + { + $options = (new ChromeOptions)->addArguments(['--headless']); + + return RemoteWebDriver::create( + 'http://localhost:9515', DesiredCapabilities::chrome()->setCapability( + ChromeOptions::CAPABILITY, $options + ) ); } @@ -225,6 +252,8 @@ Often, you will be testing pages that require authentication. You can use Dusk's ->visit('/home'); }); +> {note} After using the `loginAs` method, the user session will be maintained for all tests within the file. + ## Interacting With Elements @@ -283,6 +312,10 @@ To select a value in a dropdown selection box, you may use the `select` method. $browser->select('size', 'Large'); +You may select a random option by omitting the second parameter: + + $browser->select('size'); + #### Checkboxes To "check" a checkbox field, you may use the `check` method. Like many other input related methods, a full CSS selector is not required. If an exact selector match can't be found, Dusk will search for a checkbox with a matching `name` attribute: @@ -338,6 +371,13 @@ The `drag` method may be used to drag an element matching the given selector to $browser->drag('.from-selector', '.to-selector'); +Or, you may drag an element in a single direction: + + $browser->dragLeft('.selector', 10); + $browser->dragRight('.selector', 10); + $browser->dragUp('.selector', 10); + $browser->dragDown('.selector', 10); + ### Scoping Selectors @@ -404,6 +444,20 @@ The `waitForLink` method may be used to wait until the given link text is displa // Wait a maximum of one second for the link... $browser->waitForLink('Create', 1); +#### Waiting On The Page Location + +When making a path assertion such as `$browser->assertPathIs('/home')`, the assertion can fail if `window.location.pathname` is being updated asynchronously. You may use the `waitForLocation` method to wait for the location to be a given value: + + $browser->waitForLocation('/secret'); + +#### Waiting for Page Reloads + +If you need to make assertions after a page has been reloaded, use the `waitForReload` method: + + $browser->click('.some-action') + ->waitForReload() + ->assertSee('something'); + #### Waiting On JavaScript Expressions Sometimes you may wish to pause the execution of a test until a given JavaScript expression evaluates to `true`. You may easily accomplish this using the `waitUntil` method. When passing an expression to this method, you do not need to include the `return` keyword or an ending semi-colon: @@ -416,6 +470,14 @@ Sometimes you may wish to pause the execution of a test until a given JavaScript // Wait a maximum of one second for the expression to be true... $browser->waitUntil('App.data.servers.length > 0', 1); +#### Waiting With A Callback + +Many of the "wait" methods in Dusk rely on the underlying `waitUsing` method. You may use this method directly to wait for a given callback to return `true`. The `waitUsing` method accepts the maximum number of seconds to wait, the interval at which the Closure should be evaluated, the Closure, and an optional failure message: + + $browser->waitUsing(10, 1, function () use ($something) { + return $something->isReady(); + }, "Something wasn't ready in time."); + ## Available Assertions @@ -426,6 +488,10 @@ Assertion | Description `$browser->assertTitle($title)` | Assert the page title matches the given text. `$browser->assertTitleContains($title)` | Assert the page title contains the given text. `$browser->assertPathIs('/home')` | Assert the current path matches the given path. +`$browser->assertPathIsNot('/home')` | Assert the current path does not match the given path. +`$browser->assertRouteIs($name, $parameters)` | Assert the current URL matches the given named route's URL. +`$browser->assertQueryStringHas($name, $value)` | Assert the given query string parameter is present and has a given value. +`$browser->assertQueryStringMissing($name)` | Assert the given query string parameter is missing. `$browser->assertHasCookie($name)` | Assert the given cookie is present. `$browser->assertCookieValue($name, $value)` | Assert a cookie has a given value. `$browser->assertPlainCookieValue($name, $value)` | Assert an unencrypted cookie has a given value. @@ -439,6 +505,8 @@ Assertion | Description `$browser->assertInputValueIsNot($field, $value)` | Assert the given input field does not have the given value. `$browser->assertChecked($field)` | Assert the given checkbox is checked. `$browser->assertNotChecked($field)` | Assert the given checkbox is not checked. +`$browser->assertRadioSelected($field, $value)` | Assert the given radio field is selected. +`$browser->assertRadioNotSelected($field, $value)` | Assert the given radio field is not selected. `$browser->assertSelected($field, $value)` | Assert the given dropdown has the given value selected. `$browser->assertNotSelected($field, $value)` | Assert the given dropdown does not have the given value selected. `$browser->assertValue($selector, $value)` | Assert the element matching the given selector has the given value. @@ -460,7 +528,7 @@ To generate a page object, use the `dusk:page` Artisan command. All page objects ### Configuring Pages -By default, pages have three methods: `url`, `assert`, and `selectors`. We will discuss the `url` and `assert` methods now. The `selectors` method will be [discussed in more detail below](#shorthand-selectors). +By default, pages have three methods: `url`, `assert`, and `elements`. We will discuss the `url` and `assert` methods now. The `elements` method will be [discussed in more detail below](#shorthand-selectors). #### The `url` Method @@ -511,7 +579,7 @@ Sometimes you may already be on a given page and need to "load" the page's selec ### Shorthand Selectors -The `selectors` method of pages allows you to define quick, easy-to-remember shortcuts for any CSS selector on your page. For example, let's define a shortcut for the "email" input field of the application's login page: +The `elements` method of pages allows you to define quick, easy-to-remember shortcuts for any CSS selector on your page. For example, let's define a shortcut for the "email" input field of the application's login page: /** * Get the element shortcuts for the page. @@ -582,3 +650,62 @@ Once the method has been defined, you may use it within any test that utilizes t $browser->visit(new Dashboard) ->createPlaylist('My Playlist') ->assertSee('My Playlist'); + + +## Continuous Integration + + +### Travis CI + +To run your Dusk tests on Travis CI, we will need to use the "sudo-enabled" Ubuntu 14.04 (Trusty) environment. Since Travis CI is not a graphical environment, we will need to take some extra steps in order to launch a Chrome browser. In addition, we will use `php artisan serve` to launch PHP's built-in web server: + + sudo: required + dist: trusty + + before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + - ./vendor/laravel/dusk/bin/chromedriver-linux & + - cp .env.testing .env + - php artisan serve > /dev/null 2>&1 & + + script: + - php artisan dusk + + +### CircleCI + +#### CircleCI 1.0 + +If you are using CircleCI 1.0 to run your Dusk tests, you may use this configuration file as a starting point. Like TravisCI, we will use the `php artisan serve` command to launch PHP's built-in web server: + + test: + pre: + - "./vendor/laravel/dusk/bin/chromedriver-linux": + background: true + - cp .env.testing .env + - "php artisan serve": + background: true + + override: + - php artisan dusk + + #### CircleCI 2.0 + + If you are using CircleCI 2.0 to run your Dusk tests, you may add these steps to your build: + + version: 2 + jobs: + build: + steps: + - run: + name: Start Chrome Driver + command: ./vendor/laravel/dusk/bin/chromedriver-linux + background: true + - run: + name: Run Laravel Server + command: php artisan serve + background: true + - run: + name: Run Laravel Dusk Tests + command: php artisan dusk diff --git a/eloquent-collections.md b/eloquent-collections.md old mode 100644 new mode 100755 index 663e90d..fd9f0aa --- a/eloquent-collections.md +++ b/eloquent-collections.md @@ -51,11 +51,13 @@ All Eloquent collections extend the base [Laravel collection](/docs/{{version}}/
[all](/docs/{{version}}/collections#method-all) +[average](/docs/{{version}}/collections#method-average) [avg](/docs/{{version}}/collections#method-avg) [chunk](/docs/{{version}}/collections#method-chunk) [collapse](/docs/{{version}}/collections#method-collapse) [combine](/docs/{{version}}/collections#method-combine) [contains](/docs/{{version}}/collections#method-contains) +[containsStrict](/docs/{{version}}/collections#method-containsstrict) [count](/docs/{{version}}/collections#method-count) [diff](/docs/{{version}}/collections#method-diff) [diffKeys](/docs/{{version}}/collections#method-diffkeys) @@ -75,14 +77,21 @@ All Eloquent collections extend the base [Laravel collection](/docs/{{version}}/ [implode](/docs/{{version}}/collections#method-implode) [intersect](/docs/{{version}}/collections#method-intersect) [isEmpty](/docs/{{version}}/collections#method-isempty) +[isNotEmpty](/docs/{{version}}/collections#method-isnotempty) [keyBy](/docs/{{version}}/collections#method-keyby) [keys](/docs/{{version}}/collections#method-keys) [last](/docs/{{version}}/collections#method-last) [map](/docs/{{version}}/collections#method-map) +[mapWithKeys](/docs/{{version}}/collections#method-mapwithkeys) [max](/docs/{{version}}/collections#method-max) +[median](/docs/{{version}}/collections#method-median) [merge](/docs/{{version}}/collections#method-merge) [min](/docs/{{version}}/collections#method-min) +[mode](/docs/{{version}}/collections#method-mode) +[nth](/docs/{{version}}/collections#method-nth) [only](/docs/{{version}}/collections#method-only) +[partition](/docs/{{version}}/collections#method-partition) +[pipe](/docs/{{version}}/collections#method-pipe) [pluck](/docs/{{version}}/collections#method-pluck) [pop](/docs/{{version}}/collections#method-pop) [prepend](/docs/{{version}}/collections#method-prepend) @@ -101,18 +110,24 @@ All Eloquent collections extend the base [Laravel collection](/docs/{{version}}/ [sortBy](/docs/{{version}}/collections#method-sortby) [sortByDesc](/docs/{{version}}/collections#method-sortbydesc) [splice](/docs/{{version}}/collections#method-splice) +[split](/docs/{{version}}/collections#method-split) [sum](/docs/{{version}}/collections#method-sum) [take](/docs/{{version}}/collections#method-take) +[tap](/docs/{{version}}/collections#method-tap) [toArray](/docs/{{version}}/collections#method-toarray) [toJson](/docs/{{version}}/collections#method-tojson) [transform](/docs/{{version}}/collections#method-transform) [union](/docs/{{version}}/collections#method-union) [unique](/docs/{{version}}/collections#method-unique) +[uniqueStrict](/docs/{{version}}/collections#method-uniquestrict) [values](/docs/{{version}}/collections#method-values) +[when](/docs/{{version}}/collections#method-when) [where](/docs/{{version}}/collections#method-where) [whereStrict](/docs/{{version}}/collections#method-wherestrict) [whereIn](/docs/{{version}}/collections#method-wherein) -[whereInLoose](/docs/{{version}}/collections#method-whereinloose) +[whereInStrict](/docs/{{version}}/collections#method-whereinstrict) +[whereNotIn](/docs/{{version}}/collections#method-wherenotin) +[whereNotInStrict](/docs/{{version}}/collections#method-wherenotinstrict) [zip](/docs/{{version}}/collections#method-zip)
diff --git a/eloquent-mutators.md b/eloquent-mutators.md old mode 100644 new mode 100755 index 5cceb29..222f2c3 --- a/eloquent-mutators.md +++ b/eloquent-mutators.md @@ -157,7 +157,7 @@ For example, let's cast the `is_admin` attribute, which is stored in our databas class User extends Model { /** - * The attributes that should be casted to native types. + * The attributes that should be cast to native types. * * @var array */ @@ -188,7 +188,7 @@ The `array` cast type is particularly useful when working with columns that are class User extends Model { /** - * The attributes that should be casted to native types. + * The attributes that should be cast to native types. * * @var array */ diff --git a/eloquent-relationships.md b/eloquent-relationships.md old mode 100644 new mode 100755 index f60a7ba..6c63d69 --- a/eloquent-relationships.md +++ b/eloquent-relationships.md @@ -120,6 +120,41 @@ If your parent model does not use `id` as its primary key, or you wish to join t return $this->belongsTo('App\User', 'foreign_key', 'other_key'); } + +#### Default Models + +The `belongsTo` relationship allows you to define a default model that will be returned if the given relationship is `null`. This pattern is often referred to as the [Null Object pattern](https://en.wikipedia.org/wiki/Null_Object_pattern) and can help remove conditional checks in your code. In the following example, the `user` relation will return an empty `App\User` model if no `user` is attached to the post: + + /** + * Get the author of the post. + */ + public function user() + { + return $this->belongsTo('App\User')->withDefault(); + } + +To populate the default model with attributes, you may pass an array or Closure to the `withDefault` method: + + /** + * Get the author of the post. + */ + public function user() + { + return $this->belongsTo('App\User')->withDefault([ + 'name' => 'Guest Author', + ]); + } + + /** + * Get the author of the post. + */ + public function user() + { + return $this->belongsTo('App\User')->withDefault(function ($user) { + $user->name = 'Guest Author'; + }); + } + ### One To Many @@ -307,7 +342,7 @@ You can also filter the results returned by `belongsToMany` using the `wherePivo #### Defining Custom Intermediate Table Models -If you would like to define a custom model to represent the intermediate table of your relationship, you may call the `using` method when defining the relationship. All custom models used to represent intermediate tables of relationships must extend the `Illuminate\Database\Eloquent\Relations\Pivot` class: +If you would like to define a custom model to represent the intermediate table of your relationship, you may call the `using` method when defining the relationship. All custom models used to represent intermediate tables of relationships must extend the `Illuminate\Database\Eloquent\Relations\Pivot` class. For example, we may define a `Role` which uses a custom `UserRole` pivot model: ### Has Many Through @@ -368,15 +416,19 @@ Now that we have examined the table structure for the relationship, let's define The first argument passed to the `hasManyThrough` method is the name of the final model we wish to access, while the second argument is the name of the intermediate model. -Typical Eloquent foreign key conventions will be used when performing the relationship's queries. If you would like to customize the keys of the relationship, you may pass them as the third and fourth arguments to the `hasManyThrough` method. The third argument is the name of the foreign key on the intermediate model, the fourth argument is the name of the foreign key on the final model, and the fifth argument is the local key: +Typical Eloquent foreign key conventions will be used when performing the relationship's queries. If you would like to customize the keys of the relationship, you may pass them as the third and fourth arguments to the `hasManyThrough` method. The third argument is the name of the foreign key on the intermediate model. The fourth argument is the name of the foreign key on the final model. The fifth argument is the local key, while the sixth argument is the local key of the intermediate model: class Country extends Model { public function posts() { return $this->hasManyThrough( - 'App\Post', 'App\User', - 'country_id', 'user_id', 'id' + 'App\Post', + 'App\User', + 'country_id', // Foreign key on users table... + 'user_id', // Foreign key on posts table... + 'id', // Local key on countries table... + 'id' // Local key on users table... ); } } @@ -675,6 +727,19 @@ You may add the "counts" for multiple relations as well as add constraints to th echo $posts[0]->votes_count; echo $posts[0]->comments_count; +You may also alias the relationship count result, allowing multiple counts on the same relationship: + + $posts = Post::withCount([ + 'comments', + 'comments AS pending_comments' => function ($query) { + $query->where('approved', false); + } + ])->get(); + + echo $posts[0]->comments_count; + + echo $posts[0]->pending_comments_count; + ## Eager Loading @@ -725,7 +790,7 @@ For this operation, only two queries will be executed: Sometimes you may need to eager load several different relationships in a single operation. To do so, just pass additional arguments to the `with` method: - $books = App\Book::with('author', 'publisher')->get(); + $books = App\Book::with(['author', 'publisher'])->get(); #### Nested Eager Loading @@ -801,7 +866,20 @@ In addition to the `save` and `saveMany` methods, you may also use the `create` 'message' => 'A new comment.', ]); -Before using the `create` method, be sure to review the documentation on attribute [mass assignment](/docs/{{version}}/eloquent#mass-assignment). +> {tip} Before using the `create` method, be sure to review the documentation on attribute [mass assignment](/docs/{{version}}/eloquent#mass-assignment). + +You may use the `createMany` method to create multiple related models: + + $post = App\Post::find(1); + + $post->comments()->createMany([ + [ + 'message' => 'A new comment.', + ], + [ + 'message' => 'Another new comment.', + ], + ]); ### Belongs To Relationships @@ -849,7 +927,10 @@ For convenience, `attach` and `detach` also accept arrays of IDs as input: $user->roles()->detach([1, 2, 3]); - $user->roles()->attach([1 => ['expires' => $expires], 2, 3]); + $user->roles()->attach([ + 1 => ['expires' => $expires], + 2 => ['expires' => $expires] + ]); #### Syncing Associations diff --git a/eloquent-serialization.md b/eloquent-serialization.md old mode 100644 new mode 100755 index 5d6a7a4..b0fb6a0 --- a/eloquent-serialization.md +++ b/eloquent-serialization.md @@ -72,7 +72,7 @@ Sometimes you may wish to limit the attributes, such as passwords, that are incl protected $hidden = ['password']; } -> {note} When hiding relationships, use the relationship's method name, not its dynamic property name. +> {note} When hiding relationships, use the relationship's method name. Alternatively, you may use the `visible` property to define a white-list of attributes that should be included in your model's array and JSON representation. All other attributes will be hidden when the model is converted to an array or JSON: diff --git a/eloquent.md b/eloquent.md old mode 100644 new mode 100755 index ad122be..b47c0b4 --- a/eloquent.md +++ b/eloquent.md @@ -220,7 +220,7 @@ The `cursor` method allows you to iterate through your database records using a ## Retrieving Single Models / Aggregates -Of course, in addition to retrieving all of the records for a given table, you may also retrieve single records using `find` and `first`. Instead of returning a collection of models, these methods return a single model instance: +Of course, in addition to retrieving all of the records for a given table, you may also retrieve single records using `find` or `first`. Instead of returning a collection of models, these methods return a single model instance: // Retrieve a model by its primary key... $flight = App\Flight::find(1); @@ -387,12 +387,22 @@ There are two other methods you may use to create models by mass assigning attri The `firstOrNew` method, like `firstOrCreate` will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by `firstOrNew` has not yet been persisted to the database. You will need to call `save` manually to persist it: - // Retrieve the flight by the attributes, or create it if it doesn't exist... + // Retrieve flight by name, or create it if it doesn't exist... $flight = App\Flight::firstOrCreate(['name' => 'Flight 10']); - // Retrieve the flight by the attributes, or instantiate a new instance... + // Retrieve flight by name, or create it with the name and delayed attributes... + $flight = App\Flight::firstOrCreate( + ['name' => 'Flight 10'], ['delayed' => 1] + ); + + // Retrieve by name, or instantiate... $flight = App\Flight::firstOrNew(['name' => 'Flight 10']); + // Retrieve by name, or instantiate with the name and delayed attributes... + $flight = App\Flight::firstOrNew( + ['name' => 'Flight 10'], ['delayed' => 1] + ); + #### `updateOrCreate` You may also come across situations where you want to update an existing model or create a new model if none exists. Laravel provides an `updateOrCreate` method to do this in one step. Like the `firstOrCreate` method, `updateOrCreate` persists the model, so there's no need to call `save()`: @@ -553,7 +563,7 @@ Writing a global scope is simple. Define a class that implements the `Illuminate } } -> {tip} There is not a predefined folder for scopes in a default Laravel application, so feel free to make your own `Scopes` folder within your Laravel application's `app` directory. +> {tip} If your global scope is adding columns to the select clause of the query, you should use the `addSelect` method instead of `select`. This will prevent the unintentional replacement of the query's existing select clause. #### Applying Global Scopes @@ -709,7 +719,7 @@ Eloquent models fire several events, allowing you to hook into the following poi Whenever a new model is saved for the first time, the `creating` and `created` events will fire. If a model already existed in the database and the `save` method is called, the `updating` / `updated` events will fire. However, in both cases, the `saving` / `saved` events will fire. -To get started, define an `$events` property on your Eloquent model that maps various points of the Eloquent model's lifecycle to your own [event classes](/docs/{{version}}/events): +To get started, define a `$dispatchesEvents` property on your Eloquent model that maps various points of the Eloquent model's lifecycle to your own [event classes](/docs/{{version}}/events): UserSaved::class, 'deleted' => UserDeleted::class, ]; diff --git a/encryption.md b/encryption.md old mode 100644 new mode 100755 diff --git a/envoy.md b/envoy.md old mode 100644 new mode 100755 index 2155e6a..015cc15 --- a/envoy.md +++ b/envoy.md @@ -22,7 +22,7 @@ First, install Envoy using the Composer `global require` command: - composer global require "laravel/envoy=~1.0" + composer global require laravel/envoy Since global Composer libraries can sometimes cause package version conflicts, you may wish to consider using `cgr`, which is a drop-in replacement for the `composer global require` command. The `cgr` library's installation instructions can be [found on GitHub](https://github.com/consolidation-org/cgr). diff --git a/errors.md b/errors.md old mode 100644 new mode 100755 index f4bdb32..53762d9 --- a/errors.md +++ b/errors.md @@ -144,7 +144,9 @@ The `abort` helper will immediately raise an exception which will be rendered by ### Custom HTTP Error Pages -Laravel makes it easy to display custom error pages for various HTTP status codes. For example, if you wish to customize the error page for 404 HTTP status codes, create a `resources/views/errors/404.blade.php`. This file will be served on all 404 errors generated by your application. The views within this directory should be named to match the HTTP status code they correspond to. The `HttpException` instance raised by the `abort` function will be passed to the view as an `$exception` variable. +Laravel makes it easy to display custom error pages for various HTTP status codes. For example, if you wish to customize the error page for 404 HTTP status codes, create a `resources/views/errors/404.blade.php`. This file will be served on all 404 errors generated by your application. The views within this directory should be named to match the HTTP status code they correspond to. The `HttpException` instance raised by the `abort` function will be passed to the view as an `$exception` variable: + +

{{ $exception->getMessage() }}

## Logging diff --git a/events.md b/events.md old mode 100644 new mode 100755 index acb5322..67aab45 --- a/events.md +++ b/events.md @@ -277,7 +277,7 @@ To dispatch an event, you may pass an instance of the event to the `event` helpe } } -> {tip} When testing, it can be helpful to assert that certain events were dispatched without actually triggering their listeners. Laravel's [built-in testing helpers](/docs/{{version}}/mocking#mocking-events) makes it a cinch. +> {tip} When testing, it can be helpful to assert that certain events were dispatched without actually triggering their listeners. Laravel's [built-in testing helpers](/docs/{{version}}/mocking#event-fake) makes it a cinch. ## Event Subscribers diff --git a/facades.md b/facades.md old mode 100644 new mode 100755 index d1ee28a..9a4061e --- a/facades.md +++ b/facades.md @@ -108,8 +108,8 @@ The `Facade` base class makes use of the `__callStatic()` magic-method to defer namespace App\Http\Controllers; - use Cache; use App\Http\Controllers\Controller; + use Illuminate\Support\Facades\Cache; class UserController extends Controller { diff --git a/filesystem.md b/filesystem.md old mode 100644 new mode 100755 index 3de773b..c1cef46 --- a/filesystem.md +++ b/filesystem.md @@ -1,4 +1,4 @@ -# Filesystem / Cloud Storage +# File Storage - [Introduction](#introduction) - [Configuration](#configuration) @@ -166,7 +166,7 @@ The `put` method may be used to store raw file contents on a disk. You may also #### Automatic Streaming -If you would like Laravel to automatically manage streaming a given file to your storage location, you may use the `putFile` or `putFileAs` method. This method accepts either a `Illuminate\Http\File` or `Illuminate\Http\UploadedFile` instance and will automatically stream the file to your desire location: +If you would like Laravel to automatically manage streaming a given file to your storage location, you may use the `putFile` or `putFileAs` method. This method accepts either a `Illuminate\Http\File` or `Illuminate\Http\UploadedFile` instance and will automatically stream the file to your desired location: use Illuminate\Http\File; @@ -321,7 +321,11 @@ Finally, the `deleteDirectory` may be used to remove a directory and all of its Laravel's Flysystem integration provides drivers for several "drivers" out of the box; however, Flysystem is not limited to these and has adapters for many other storage systems. You can create a custom driver if you want to use one of these additional adapters in your Laravel application. -In order to set up the custom filesystem you will need to create a [service provider](/docs/{{version}}/providers) such as `DropboxServiceProvider`. In the provider's `boot` method, you may use the `Storage` facade's `extend` method to define the custom driver: +In order to set up the custom filesystem you will need a Flysystem adapter. Let's add a community maintained Dropbox adapter to our project: + + composer require spatie/flysystem-dropbox + +Next, you should create a [service provider](/docs/{{version}}/providers) such as `DropboxServiceProvider`. In the provider's `boot` method, you may use the `Storage` facade's `extend` method to define the custom driver: ## Writing CSS -The Laravel `package.json` file includes the `bootstrap-sass` package to help you get started prototyping your application's frontend using Bootstrap. However, feel free to add or remove packages from the `package.json` file as needed for your own application. You are not required to use the Bootstrap framework to build your Laravel application - it is simply provided as a good starting point for those who choose to use it. +Laravel's `package.json` file includes the `bootstrap-sass` package to help you get started prototyping your application's frontend using Bootstrap. However, feel free to add or remove packages from the `package.json` file as needed for your own application. You are not required to use the Bootstrap framework to build your Laravel application - it is simply provided as a good starting point for those who choose to use it. -Before compiling your CSS, install your project's frontend dependencies using NPM: +Before compiling your CSS, install your project's frontend dependencies using the [Node package manager (NPM)](https://www.npmjs.org): npm install @@ -42,7 +40,7 @@ All of the JavaScript dependencies required by your application can be found in npm install -By default, the Laravel `package.json` file includes a few packages such as `vue` and `axios` to help you get started building your JavaScript application. Feel free to add or remove from the `package.json` file as needed for your own application. +> {tip} By default, the Laravel `package.json` file includes a few packages such as `vue` and `axios` to help you get started building your JavaScript application. Feel free to add or remove from the `package.json` file as needed for your own application. Once the packages are installed, you can use the `npm run dev` command to [compile your assets](/docs/{{version}}/mix). Webpack is a module bundler for modern JavaScript applications. When you run the `npm run dev` command, Webpack will execute the instructions in your `webpack.mix.js` file: diff --git a/hashing.md b/hashing.md old mode 100644 new mode 100755 diff --git a/helpers.md b/helpers.md old mode 100644 new mode 100755 index 2cb4b52..a85985a --- a/helpers.md +++ b/helpers.md @@ -1,4 +1,4 @@ -# Helper Functions +# Helpers - [Introduction](#introduction) - [Available Methods](#available-methods) @@ -45,6 +45,7 @@ Laravel includes a variety of global "helper" PHP functions. Many of these funct [array_sort](#method-array-sort) [array_sort_recursive](#method-array-sort-recursive) [array_where](#method-array-where) +[array_wrap](#method-array-wrap) [head](#method-head) [last](#method-last) @@ -72,9 +73,12 @@ Laravel includes a variety of global "helper" PHP functions. Many of these funct [class_basename](#method-class-basename) [e](#method-e) [ends_with](#method-ends-with) +[kebab_case](#method-kebab-case) [snake_case](#method-snake-case) [str_limit](#method-str-limit) [starts_with](#method-starts-with) +[str_after](#method-str-after) +[str_before](#method-str-before) [str_contains](#method-str-contains) [str_finish](#method-str-finish) [str_is](#method-str-is) @@ -418,10 +422,21 @@ The `array_where` function filters the array using the given Closure: // [1 => 200, 3 => 400] + +#### `array_wrap()` {#collection-method} + +The `array_wrap` function will wrap the given value in an array. If the given value is already an array it will not be changed: + + $string = 'Laravel'; + + $array = array_wrap($string); + + // [0 => 'Laravel'] + #### `head()` {#collection-method} -The `head` function simply returns the first element in the given array: +The `head` function returns the first element in the given array: $array = [100, 200, 300]; @@ -492,7 +507,7 @@ The `public_path` function returns the fully qualified path to the `public` dire #### `resource_path()` {#collection-method} -The `resource_path` function returns the fully qualified path to the `resources` directory. You may also use the `resource_path` function to generate a fully qualified path to a given file relative to the storage directory: +The `resource_path` function returns the fully qualified path to the `resources` directory. You may also use the `resource_path` function to generate a fully qualified path to a given file relative to the resources directory: $path = resource_path(); @@ -531,7 +546,7 @@ The `class_basename` returns the class name of the given class with the class' n #### `e()` {#collection-method} -The `e` function runs `htmlspecialchars` over the given string: +The `e` function runs PHP's `htmlspecialchars` function with the `double_encode` option set to `false`: echo e('foo'); @@ -546,6 +561,16 @@ The `ends_with` function determines if the given string ends with the given valu // true + +#### `kebab_case()` {#collection-method} + +The `kebab_case` function converts the given string to `kebab-case`: + + $value = kebab_case('fooBar'); + + // foo-bar + + #### `snake_case()` {#collection-method} @@ -573,6 +598,24 @@ The `starts_with` function determines if the given string begins with the given // true + +#### `str_after()` {#collection-method} + +The `str_after` function returns everything after the given value in a string: + + $value = str_after('This is: a test', 'This is:'); + + // ' a test' + + +#### `str_before()` {#collection-method} + +The `str_before` function returns everything before the given value in a string: + + $value = str_before('Test :it before', ':it before'); + + // 'Test ' + #### `str_contains()` {#collection-method} @@ -729,6 +772,10 @@ If the route accepts parameters, you may pass them as the second argument to the $url = route('routeName', ['id' => 1]); +By default, the `route` function generates an absolute URL. If you wish to generate a relative URL, you may pass `false` as the third parameter: + + $url = route('routeName', ['id' => 1], false); + #### `secure_url()` {#collection-method} diff --git a/homestead.md b/homestead.md old mode 100644 new mode 100755 index 35874b1..b333ffe --- a/homestead.md +++ b/homestead.md @@ -14,9 +14,13 @@ - [Adding Additional Sites](#adding-additional-sites) - [Configuring Cron Schedules](#configuring-cron-schedules) - [Ports](#ports) + - [Sharing Your Environment](#sharing-your-environment) + - [Multiple PHP Versions](#multiple-php-versions) - [Network Interfaces](#network-interfaces) - [Updating Homestead](#updating-homestead) - [Old Versions](#old-versions) +- [Provider Specific Settings](#provider-specific-settings) + - [VirtualBox](#provider-specific-virtualbox) ## Introduction @@ -41,10 +45,12 @@ Homestead runs on any Windows, Mac, or Linux system, and includes the Nginx web - Sqlite3 - Postgres - Composer -- Node (With Yarn, PM2, Bower, Grunt, and Gulp) +- Node (With Yarn, Bower, Grunt, and Gulp) - Redis - Memcached - Beanstalkd +- Mailhog +- ngrok ## Installation & Setup @@ -74,7 +80,14 @@ You may install Homestead by simply cloning the repository. Consider cloning the git clone https://github.com/laravel/homestead.git Homestead -Once you have cloned the Homestead repository, run the `bash init.sh` command from the Homestead directory to create the `Homestead.yaml` configuration file. The `Homestead.yaml` file will be placed in the `~/.homestead` hidden directory: +You should check out a tagged version of Homestead since the `master` branch may not always be stable. You can find the latest stable version on the [Github Release Page](https://github.com/laravel/homestead/releases): + + cd Homestead + + // Clone the desired release... + git checkout v5.4.0 + +Once you have cloned the Homestead repository, run the `bash init.sh` command from the Homestead directory to create the `Homestead.yaml` configuration file. The `Homestead.yaml` file will be placed in the Homestead directory: // Mac / Linux... bash init.sh @@ -87,7 +100,7 @@ Once you have cloned the Homestead repository, run the `bash init.sh` command fr #### Setting Your Provider -The `provider` key in your `~/.homestead/Homestead.yaml` file indicates which Vagrant provider should be used: `virtualbox`, `vmware_fusion`, `vmware_workstation`, or `parallels`. You may set this to the provider you prefer: +The `provider` key in your `Homestead.yaml` file indicates which Vagrant provider should be used: `virtualbox`, `vmware_fusion`, `vmware_workstation`, or `parallels`. You may set this to the provider you prefer: provider: virtualbox @@ -99,13 +112,15 @@ The `folders` property of the `Homestead.yaml` file lists all of the folders you - map: ~/Code to: /home/vagrant/Code -To enable [NFS](https://www.vagrantup.com/docs/synced-folders/nfs.html), just add a simple flag to your synced folder configuration: +To enable [NFS](https://www.vagrantup.com/docs/synced-folders/nfs.html), you only need to add a simple flag to your synced folder configuration: folders: - map: ~/Code to: /home/vagrant/Code type: "nfs" +> {note} When using NFS, you should consider installing the [vagrant-bindfs](https://github.com/gael-ian/vagrant-bindfs) plug-in. This plug-in will maintain the correct user / group permissions for files and directories within the Homestead box. + You may also pass any options supported by Vagrant's [Synced Folders](https://www.vagrantup.com/docs/synced-folders/basic_usage.html) by listing them under the `options` key: folders: @@ -133,7 +148,7 @@ You must add the "domains" for your Nginx sites to the `hosts` file on your mach 192.168.10.10 homestead.app -Make sure the IP address listed is the one set in your `~/.homestead/Homestead.yaml` file. Once you have added the domain to your `hosts` file and launched the Vagrant box you will be able to access the site via your web browser: +Make sure the IP address listed is the one set in your `Homestead.yaml` file. Once you have added the domain to your `hosts` file and launched the Vagrant box you will be able to access the site via your web browser: http://homestead.app @@ -183,9 +198,9 @@ If you prefer to use MariaDB instead of MySQL, you may add the `mariadb` option ### Accessing Homestead Globally -Sometimes you may want to `vagrant up` your Homestead machine from anywhere on your filesystem. You can do this on Mac / Linux systems by adding a Bash function to your Bash profile. On Windows, you may accomplish this by adding a "batch" file to your `PATH`. This scripts will allow you to run any Vagrant command from anywhere on your system and will automatically point that command to your Homestead installation: +Sometimes you may want to `vagrant up` your Homestead machine from anywhere on your filesystem. You can do this on Mac / Linux systems by adding a Bash function to your Bash profile. On Windows, you may accomplish this by adding a "batch" file to your `PATH`. These scripts will allow you to run any Vagrant command from anywhere on your system and will automatically point that command to your Homestead installation: -#### Linux +#### Mac / Linux function homestead() { ( cd ~/Homestead && vagrant $* ) @@ -229,7 +244,7 @@ To connect to your MySQL or Postgres database from your host machine's database ### Adding Additional Sites -Once your Homestead environment is provisioned and running, you may want to add additional Nginx sites for your Laravel applications. You can run as many Laravel installations as you wish on a single Homestead environment. To add an additional site, simply add the site to your `~/.homestead/Homestead.yaml` file: +Once your Homestead environment is provisioned and running, you may want to add additional Nginx sites for your Laravel applications. You can run as many Laravel installations as you wish on a single Homestead environment. To add an additional site, simply add the site to your `Homestead.yaml` file: sites: - map: homestead.app @@ -244,6 +259,30 @@ If Vagrant is not automatically managing your "hosts" file, you may need to add Once the site has been added, run the `vagrant reload --provision` command from your Homestead directory. + +#### Site Types + +Homestead supports several types of sites which allow you to easily run projects that are not based on Laravel. For example, we may easily add a Symfony application to Homestead using the `symfony2` site type: + + sites: + - map: symfony2.app + to: /home/vagrant/Code/Symfony/public + type: symfony2 + +The available site types are: `apache`, `laravel` (the default), `proxy`, `silverstripe`, `statamic`, `symfony2`, and `symfony4`. + + +#### Site Parameters + +You may add additional Nginx `fastcgi_param` values to your site via the `params` site directive. For example, we'll add a `FOO` parameter with a value of `BAR`: + + sites: + - map: homestead.app + to: /home/vagrant/Code/Laravel/public + params: + - key: FOO + value: BAR + ### Configuring Cron Schedules @@ -268,18 +307,44 @@ By default, the following ports are forwarded to your Homestead environment: - **HTTPS:** 44300 → Forwards To 443 - **MySQL:** 33060 → Forwards To 3306 - **Postgres:** 54320 → Forwards To 5432 +- **Mailhog:** 8025 → Forwards To 8025 #### Forwarding Additional Ports If you wish, you may forward additional ports to the Vagrant box, as well as specify their protocol: ports: - - send: 93000 - to: 9300 + - send: 50000 + to: 5000 - send: 7777 to: 777 protocol: udp + +### Sharing Your Environment + +Sometimes you may wish to share what you're currently working on with coworkers or a client. Vagrant has a built-in way to support this via `vagrant share`; however, this will not work if you have multiple sites configured in your `Homestead.yaml` file. + +To solve this problem, Homestead includes its own `share` command. To get started, SSH into your Homestead machine via `vagrant ssh` and run `share homestead.app`. This will share the `homestead.app` site from your `Homestead.yaml` configuration file. Of course, you may substitute any of your other configured sites for `homestead.app`: + + share homestead.app + +After running the command, you will see an Ngrok screen appear which contains the activity log and the publicly accessible URLs for the shared site. If you would like to specify a custom region, subdomain, or other Ngrok runtime option, you may add them to your `share` command: + + share homestead.app -region=eu -subdomain=laravel + +> {note} Remember, Vagrant is inherently insecure and you are exposing your virtual machine to the Internet when running the `share` command. + + +### Multiple PHP Versions + +Homestead 6 introduced support for multiple versions of PHP on the same virtual machine. You may specify which version of PHP to use for a given site within your `Homestead.yaml` file. The available PHP versions are: "5.6", "7.0", and "7.1": + + sites: + - map: homestead.app + to: /home/vagrant/Code/Laravel/public + php: "5.6" + ## Network Interfaces @@ -337,3 +402,14 @@ When you use an older version of the Homestead box you need to match that with a |---|---|---| | PHP 7.0 | 3.1.0 | 0.6.0 | | PHP 7.1 | 4.0.0 | 1.0.0 | + + +## Provider Specific Settings + + +### VirtualBox + +By default, Homestead configures the `natdnshostresolver` setting to `on`. This allows Homestead to use your host operating system's DNS settings. If you would like to override this behavior, add the following lines to your `Homestead.yaml` file: + + provider: virtualbox + natdnshostresolver: off diff --git a/http-tests.md b/http-tests.md old mode 100644 new mode 100755 index 33ff0af..3494eb9 --- a/http-tests.md +++ b/http-tests.md @@ -3,6 +3,7 @@ - [Introduction](#introduction) - [Session / Authentication](#session-and-authentication) - [Testing JSON APIs](#testing-json-apis) +- [Testing File Uploads](#testing-file-uploads) - [Available Assertions](#available-assertions) @@ -37,7 +38,7 @@ Laravel provides a very fluent API for making HTTP requests to your application The `get` method makes a `GET` request into the application, while the `assertStatus` method asserts that the returned response should have the given HTTP status code. In addition to this simple assertion, Laravel also contains a variety of assertions for inspecting the response headers, content, JSON structure, and more. -### Session / Authentication +## Session / Authentication Laravel provides several helpers for working with the session during HTTP testing. First, you may set the session data to a given array using the `withSession` method. This is useful for loading the session with data before issuing a request to your application: @@ -56,15 +57,17 @@ Of course, one common use of the session is for maintaining state for the authen create(); + $user = factory(User::class)->create(); $response = $this->actingAs($user) ->withSession(['foo' => 'bar']) - ->get('/') + ->get('/'); } } @@ -73,7 +76,7 @@ You may also specify which guard should be used to authenticate the given user b $this->actingAs($user, 'api') -### Testing JSON APIs +## Testing JSON APIs Laravel also provides several helpers for testing JSON APIs and their responses. For example, the `json`, `get`, `post`, `put`, `patch`, and `delete` methods may be used to issue requests with various HTTP verbs. You may also easily pass data and headers to these methods. To get started, let's write a test to make a `POST` request to `/user` and assert that the expected data was returned: @@ -98,7 +101,7 @@ Laravel also provides several helpers for testing JSON APIs and their responses. } } -> {tip} The `assertJson` method converts the response to an array and utilizes `PHPUnit::assertArraySubset` to verify that the given fragment exists within the JSON response returned by the application. So, if there are other properties in the JSON response, this test will still pass as long as the given fragment is present. +> {tip} The `assertJson` method converts the response to an array and utilizes `PHPUnit::assertArraySubset` to verify that the given array exists within the JSON response returned by the application. So, if there are other properties in the JSON response, this test will still pass as long as the given fragment is present. ### Verifying Exact Match @@ -126,8 +129,52 @@ If you would like to verify that the given array is an **exact** match for the J } } + +## Testing File Uploads + +The `Illuminate\Http\UploadedFile` class provides a `fake` method which may be used to generate dummy files or images for testing. This, combined with the `Storage` facade's `fake` method greatly simplifies the testing of file uploads. For example, you may combine these two features to easily test an avatar upload form: + + json('POST', '/avatar', [ + 'avatar' => UploadedFile::fake()->image('avatar.jpg') + ]); + + // Assert the file was stored... + Storage::disk('avatars')->assertExists('avatar.jpg'); + + // Assert a file does not exist... + Storage::disk('avatars')->assertMissing('missing.jpg'); + } + } + +#### Fake File Customization + +When creating files using the `fake` method, you may specify the width, height, and size of the image in order to better test your validation rules: + + UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100); + +In addition to creating images, you may create files of any other type using the `create` method: + + UploadedFile::fake()->create('document.pdf', $sizeInKilobytes); + -### Available Assertions +## Available Assertions Laravel provides a variety of custom assertion methods for your [PHPUnit](https://phpunit.de/) tests. These assertions may be accessed on the response that is returned from the `json`, `get`, `post`, `put`, and `delete` test methods: @@ -139,7 +186,12 @@ Method | Description `$response->assertCookie($cookieName, $value = null);` | Assert that the response contains the given cookie. `$response->assertPlainCookie($cookieName, $value = null);` | Assert that the response contains the given cookie (unencrypted). `$response->assertSessionHas($key, $value = null);` | Assert that the session contains the given piece of data. +`$response->assertSessionHasErrors(array $keys);` | Assert that the session contains an error for the given field. `$response->assertSessionMissing($key);` | Assert that the session does not contain the given key. `$response->assertJson(array $data);` | Assert that the response contains the given JSON data. +`$response->assertJsonFragment(array $data);` | Assert that the response contains the given JSON fragment. +`$response->assertJsonMissing(array $data);` | Assert that the response does not contain the given JSON fragment. `$response->assertExactJson(array $data);` | Assert that the response contains an exact match of the given JSON data. +`$response->assertJsonStructure(array $structure);` | Assert that the response has a given JSON structure. +`$response->assertViewIs($value);` | Assert that the given view was returned by the route. `$response->assertViewHas($key, $value = null);` | Assert that the response view was given a piece of data. diff --git a/installation.md b/installation.md old mode 100644 new mode 100755 index db68b6d..ffa7108 --- a/installation.md +++ b/installation.md @@ -10,7 +10,7 @@ ## Installation -> {video} Are you a visual learner? Laracasts provides a [free, thorough introduction to Laravel](https://laracasts.com/series/laravel-from-scratch-2017) for newcomers to the framework. It's a great place to start your journey. +> {video} Are you a visual learner? Laracasts provides a [free, thorough introduction to Laravel](http://laravelfromscratch.com) for newcomers to the framework. It's a great place to start your journey. ### Server Requirements diff --git a/license.md b/license.md old mode 100644 new mode 100755 diff --git a/lifecycle.md b/lifecycle.md old mode 100644 new mode 100755 diff --git a/localization.md b/localization.md old mode 100644 new mode 100755 index 075487c..647dd37 --- a/localization.md +++ b/localization.md @@ -86,7 +86,7 @@ For applications with heavy translation requirements, defining every string with Translation files that use translation strings as keys are stored as JSON files in the `resources/lang` directory. For example, if your application has a Spanish translation, you should create a `resources/lang/es.json` file: { - "I love programming.": "Me encanta la programación." + "I love programming.": "Me encanta programar." } diff --git a/mail.md b/mail.md old mode 100644 new mode 100755 index d0968d7..5dcd262 --- a/mail.md +++ b/mail.md @@ -9,6 +9,7 @@ - [View Data](#view-data) - [Attachments](#attachments) - [Inline Attachments](#inline-attachments) + - [Customizing The SwiftMailer Message](#customizing-the-swiftmailer-message) - [Markdown Mailables](#markdown-mailables) - [Generating Markdown Mailables](#generating-markdown-mailables) - [Writing Markdown Messages](#writing-markdown-messages) @@ -298,6 +299,8 @@ Embedding inline images into your emails is typically cumbersome; however, Larav +> {note} `$message` variable is not available in markdown messages. + #### Embedding Raw Data Attachments If you already have a raw data string you wish to embed into an email template, you may use the `embedData` method on the `$message` variable: @@ -308,6 +311,26 @@ If you already have a raw data string you wish to embed into an email template, + +### Customizing The SwiftMailer Message + +The `withSwiftMessage` method of the `Mailable` base class allows you to register a callback which will be invoked with the raw SwiftMailer message instance before sending the message. This gives you an opportunity to customize the message before it is delivered: + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + $this->view('emails.orders.shipped'); + + $this->withSwiftMessage(function ($message) { + $message->getHeaders() + ->addTextHeader('Custom-Header', 'HeaderValue'); + }); + } + ## Markdown Mailables @@ -351,6 +374,8 @@ Markdown mailables use a combination of Blade components and Markdown syntax whi {{ config('app.name') }} @endcomponent +> {tip} Do not use excess indentation when writing Markdown emails. Markdown parsers will render indented content as code blocks. + #### Button Component The button component renders a centered button link. The component accepts two arguments, a `url` and an optional `color`. Supported colors are `blue`, `green`, and `red`. You may add as many button components to a message as you wish: @@ -520,4 +545,3 @@ Laravel fires an event just before sending mail messages. Remember, this event i 'App\Listeners\LogSentMessage', ], ]; - diff --git a/middleware.md b/middleware.md old mode 100644 new mode 100755 index 10f5d6a..e458d17 --- a/middleware.md +++ b/middleware.md @@ -50,7 +50,6 @@ This command will place a new `CheckAge` class within your `app/Http/Middleware` return $next($request); } - } As you can see, if the given `age` is less than or equal to `200`, the middleware will return an HTTP redirect to the client; otherwise, the request will be passed further into the application. To pass the request deeper into the application (allowing the middleware to "pass"), simply call the `$next` callback with the `$request`. @@ -245,6 +244,6 @@ Sometimes a middleware may need to do some work after the HTTP response has been } } -The `terminate` method should receive both the request and the response. Once you have defined a terminable middleware, you should add it to the list of global middleware in your HTTP kernel. +The `terminate` method should receive both the request and the response. Once you have defined a terminable middleware, you should add it to the list of route or global middleware in the `app/Http/Kernel.php` file. When calling the `terminate` method on your middleware, Laravel will resolve a fresh instance of the middleware from the [service container](/docs/{{version}}/container). If you would like to use the same middleware instance when the `handle` and `terminate` methods are called, register the middleware with the container using the container's `singleton` method. diff --git a/migrations.md b/migrations.md old mode 100644 new mode 100755 diff --git a/mix.md b/mix.md old mode 100644 new mode 100755 index d05d29e..6269520 --- a/mix.md +++ b/mix.md @@ -6,19 +6,26 @@ - [Working With Stylesheets](#working-with-stylesheets) - [Less](#less) - [Sass](#sass) + - [Stylus](#stylus) + - [PostCSS](#postcss) - [Plain CSS](#plain-css) + - [URL Processing](#url-processing) - [Source Maps](#css-source-maps) - [Working With JavaScript](#working-with-scripts) - - [Code Splitting](#code-splitting) + - [Vendor Extraction](#vendor-extraction) + - [React](#react) + - [Vanilla JS](#vanilla-js) - [Custom Webpack Configuration](#custom-webpack-configuration) - [Copying Files & Directories](#copying-files-and-directories) - [Versioning / Cache Busting](#versioning-and-cache-busting) +- [Browsersync Reloading](#browsersync-reloading) +- [Environment Variables](#environment-variables) - [Notifications](#notifications) ## Introduction -Laravel Mix provides a fluent API for defining Webpack build steps for your Laravel application using several common CSS and JavaScript pre-processors. Through simple method chaining, you can fluently define your asset pipeline. For example: +[Laravel Mix](https://github.com/JeffreyWay/laravel-mix) provides a fluent API for defining Webpack build steps for your Laravel application using several common CSS and JavaScript pre-processors. Through simple method chaining, you can fluently define your asset pipeline. For example: mix.js('resources/assets/js/app.js', 'public/js') .sass('resources/assets/sass/app.scss', 'public/css'); @@ -64,6 +71,10 @@ The `npm run watch` command will continue running in your terminal and watch all npm run watch +You may find that in certain environments Webpack isn't updating when your files change. If this is the case on your system, consider using the `watch-poll` command: + + npm run watch-poll + ## Working With Stylesheets @@ -85,6 +96,12 @@ If you wish to customize the file name of the compiled CSS, you may pass a full mix.less('resources/assets/less/app.less', 'public/stylesheets/styles.css'); +If you need to override the [underlying Less plug-in options](https://github.com/webpack-contrib/less-loader#options), you may pass an object as the third argument to `mix.less()`: + + mix.less('resources/assets/less/app.less', 'public/css', { + strictMath: true + }); + ### Sass @@ -97,16 +114,79 @@ Again, like the `less` method, you may compile multiple Sass files into their ow mix.sass('resources/assets/sass/app.sass', 'public/css') .sass('resources/assets/sass/admin.sass', 'public/css/admin'); +Additional [Node-Sass plug-in options](https://github.com/sass/node-sass#options) may be provided as the third argument: + + mix.sass('resources/assets/sass/app.sass', 'public/css', { + precision: 5 + }); + + +### Stylus + +Similar to Less and Sass, the `stylus` method allows you to compile [Stylus](http://stylus-lang.com/) into CSS: + + mix.stylus('resources/assets/stylus/app.styl', 'public/css'); + +You may also install additional Stylus plug-ins, such as [Rupture](https://github.com/jescalan/rupture). First, install the plug-in in question through NPM (`npm install rupture`) and then require it in your call to `mix.stylus()`: + + mix.stylus('resources/assets/stylus/app.styl', 'public/css', { + use: [ + require('rupture')() + ] + }); + + +### PostCSS + +[PostCSS](http://postcss.org/), a powerful tool for transforming your CSS, is included with Laravel Mix out of the box. By default, Mix leverages the popular [Autoprefixer](https://github.com/postcss/autoprefixer) plug-in to automatically apply all necessary CSS3 vendor prefixes. However, you're free to add any additional plug-ins that are appropriate for your application. First, install the desired plug-in through NPM and then reference it in your `webpack.mix.js` file: + + mix.sass('resources/assets/sass/app.scss', 'public/css') + .options({ + postCss: [ + require('postcss-css-variables')() + ] + }); + ### Plain CSS -If you would just like to combine some plain CSS stylesheets into a single file, you may use the `combine` method. This method also supports concatenating JavaScript files: +If you would just like to concatenate some plain CSS stylesheets into a single file, you may use the `styles` method. - mix.combine([ + mix.styles([ 'public/css/vendor/normalize.css', 'public/css/vendor/videojs.css' ], 'public/css/all.css'); + +### URL Processing + +Because Laravel Mix is built on top of Webpack, it's important to understand a few Webpack concepts. For CSS compilation, Webpack will rewrite and optimize any `url()` calls within your stylesheets. While this might initially sound strange, it's an incredibly powerful piece of functionality. Imagine that we want to compile Sass that includes a relative URL to an image: + + .example { + background: url('../images/example.png'); + } + +> {note} Absolute paths for any given `url()` will be excluded from URL-rewriting. For example, `url('/images/thing.png')` or `url('http://example.com/images/thing.png')` won't be modified. + +By default, Laravel Mix and Webpack will find `example.png`, copy it to your `public/images` folder, and then rewrite the `url()` within your generated stylesheet. As such, your compiled CSS will be: + + .example { + background: url(/images/example.png?d41d8cd98f00b204e9800998ecf8427e); + } + +As useful as this feature may be, it's possible that your existing folder structure is already configured in a way you like. If this is the case, you may disable `url()` rewriting like so: + + mix.sass('resources/assets/app/app.scss', 'public/css') + .options({ + processCssUrls: false + }); + +With this addition to your `webpack.mix.js` file, Mix will no longer match any `url()` or copy assets to your public directory. In other words, the compiled CSS will look just like how you originally typed it: + + .example { + background: url("../images/thing.png"); + } + ### Source Maps @@ -126,16 +206,17 @@ With this single line of code, you may now take advantage of:
- ES2015 syntax. +- Modules - Compilation of `.vue` files. - Minification for production environments.
- -### Code Splitting + +### Vendor Extraction One potential downside to bundling all application-specific JavaScript with your vendor libraries is that it makes long-term caching more difficult. For example, a single update to your application code will force the browser to re-download all of your vendor libraries even if they haven't changed. -If you intend to make frequent updates to your application's JavaScript, you should consider extracting all of your vendor libraries into their file. This way, a change to your application code will not affect the caching of your large `vendor.js` file. Mix's `extract` method makes this a breeze: +If you intend to make frequent updates to your application's JavaScript, you should consider extracting all of your vendor libraries into their own file. This way, a change to your application code will not affect the caching of your large `vendor.js` file. Mix's `extract` method makes this a breeze: mix.js('resources/assets/js/app.js', 'public/js') .extract(['vue']) @@ -154,12 +235,35 @@ To avoid JavaScript errors, be sure to load these files in the proper order: + +### React + +Mix can automatically install the Babel plug-ins necessary for React support. To get started, replace your `mix.js()` call with `mix.react()`: + + mix.react('resources/assets/js/app.jsx', 'public/js'); + +Behind the scenes, Mix will download and include the appropriate `babel-preset-react` Babel plug-in. + + +### Vanilla JS + +Similar to combining stylesheets with `mix.styles()`, you may also combine and minify any number of JavaScript files with the `scripts()` method: + + mix.scripts([ + 'public/js/admin.js', + 'public/js/dashboard.js' + ], 'public/js/all.js'); + +This option is particularly useful for legacy projects where you don't require Webpack compilation for your JavaScript. + +> {tip} A slight variation of `mix.scripts()` is `mix.babel()`. Its method signature is identical to `scripts`; however, the concatenated file will receive Babel compilation, which translates any ES2015 code to vanilla JavaScript that all browsers will understand. + ### Custom Webpack Configuration -Behind the scenes, Laravel Mix references a pre-configured `webpack.config.js` file to get you up and running as quickly as possible. Occasionally, you may need to manually modify this file. You might have a special loader or plugin that needs to be referenced, or maybe you prefer to use Stylus instead of Sass. In such instances, you have two choices: +Behind the scenes, Laravel Mix references a pre-configured `webpack.config.js` file to get you up and running as quickly as possible. Occasionally, you may need to manually modify this file. You might have a special loader or plug-in that needs to be referenced, or maybe you prefer to use Stylus instead of Sass. In such instances, you have two choices: -#### Merging +#### Merging Custom Configuration Mix provides a useful `webpackConfig` method that allows you to merge any short Webpack configuration overrides. This is a particularly appealing choice, as it doesn't require you to copy and maintain your own copy of the `webpack.config.js` file. The `webpackConfig` method accepts an object, which should contain any [Webpack-specific configuration](https://webpack.js.org/configuration/) that you wish to apply. @@ -171,14 +275,9 @@ Mix provides a useful `webpackConfig` method that allows you to merge any short } }); -#### Reference Your Own Configuration - -A second option is to copy Mix's `webpack.config.js` into your project root. - - cp node_modules/laravel-mix/setup/webpack.config.js ./ - -Next, you'll need to update the NPM scripts in your `package.json` to ensure that they no longer reference Mix's configuration file directly. Simply remove the `--config="node_modules/laravel-mix/setup/webpack.config.js"` entry from the commands. Once this has been done, you may freely modify your configuration file as needed. +#### Custom Configuration Files +If you would like completely customize your Webpack configuration, copy the `node_modules/laravel-mix/setup/webpack.config.js` file to your project's root directory. Next, point all of the `--config` references in your `package.json` file to the newly copied configuration file. If you choose to take this approach to customization, any future upstream updates to Mix's `webpack.config.js` must be manually merged into your customized file. ## Copying Files & Directories @@ -187,12 +286,16 @@ The `copy` method may be used to copy files and directories to new locations. Th mix.copy('node_modules/foo/bar.css', 'public/css/bar.css'); +When copying a directory, the `copy` method will flatten the directory's structure. To maintain the directory's original structure, you should use the `copyDirectory` method instead: + + mix.copyDirectory('assets/img', 'public/img'); + ## Versioning / Cache Busting Many developers suffix their compiled assets with a timestamp or unique token to force browsers to load the fresh assets instead of serving stale copies of the code. Mix can handle this for you using the `version` method. -When executed in a production environment (`npm run production`), the `version` method will automatically append a unique hash to the filenames of all compiled files, allowing for more convenient cache busting: +The `version` method will automatically append a unique hash to the filenames of all compiled files, allowing for more convenient cache busting: mix.js('resources/assets/js/app.js', 'public/js') .version(); @@ -201,6 +304,41 @@ After generating the versioned file, you won't know the exact file name. So, you +Because versioned files are usually unnecessary in development, you may instruct the versioning process to only run during `npm run production`: + + mix.js('resources/assets/js/app.js', 'public/js'); + + if (mix.inProduction()) { + mix.version(); + } + + +## Browsersync Reloading + +[BrowserSync](https://browsersync.io/) can automatically monitor your files for changes, and inject your changes into the browser without requiring a manual refresh. You may enable support by calling the `mix.browserSync()` method: + + mix.browserSync('my-domain.dev'); + + // Or... + + // https://browsersync.io/docs/options + mix.browserSync({ + proxy: 'my-domain.dev' + }); + +You may pass either a string (proxy) or object (BrowserSync settings) to this method. Next, start Webpack's dev server using the `npm run watch` command. Now, when you modify a script or PHP file, watch as the browser instantly refreshes the page to reflect your changes. + + +## Environment Variables + +You may inject environment variables into Mix by prefixing a key in your `.env` file with `MIX_`: + + MIX_SENTRY_DSN_PUBLIC=http://example.com + +After the variable has been defined in your `.env` file, you may access via the `process.env` object. If the value changes while you are running a `watch` task, you will need to restart the task: + + process.env.MIX_SENTRY_DSN_PUBLIC + ## Notifications diff --git a/mocking.md b/mocking.md old mode 100644 new mode 100755 index 95a7e13..05da6b8 --- a/mocking.md +++ b/mocking.md @@ -6,6 +6,7 @@ - [Mail Fake](#mail-fake) - [Notification Fake](#notification-fake) - [Queue Fake](#queue-fake) +- [Storage Fake](#storage-fake) - [Facades](#mocking-facades) @@ -204,6 +205,42 @@ As an alternative to mocking, you may use the `Queue` facade's `fake` method to } } + +## Storage Fake + +The `Storage` facade's `fake` method allows you to easily generate a fake disk that, combined with the file generation utilities of the `UploadedFile` class, greatly simplifies the testing of file uploads. For example: + + json('POST', '/avatar', [ + 'avatar' => UploadedFile::fake()->image('avatar.jpg') + ]); + + // Assert the file was stored... + Storage::disk('avatars')->assertExists('avatar.jpg'); + + // Assert a file does not exist... + Storage::disk('avatars')->assertMissing('missing.jpg'); + } + } + +> {tip} By default, the `fake` method will delete all files in its temporary directory. If you would like to keep these files, you may use the "persistentFake" method instead. + ## Facades diff --git a/notifications.md b/notifications.md old mode 100644 new mode 100755 index 7848f04..a97576c --- a/notifications.md +++ b/notifications.md @@ -174,6 +174,38 @@ In this example, we register a greeting, a line of text, a call to action, and t > {tip} When sending mail notifications, be sure to set the `name` value in your `config/app.php` configuration file. This value will be used in the header and footer of your mail notification messages. +#### Other Notification Formatting Options + +Instead of defining the "lines" of text in the notification class, you may use the `view` method to specify a custom template that should be used to render the notification email: + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + return (new MailMessage)->view( + 'emails.name', ['invoice' => $this->invoice] + ); + } + +In addition, you may return a [mailable object](/docs/{{version}}/mail) from the `toMail` method: + + use App\Mail\InvoicePaid as Mailable; + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return Mailable + */ + public function toMail($notifiable) + { + return (new Mailable($this->invoice))->to($this->user->email); + } + #### Error Messages @@ -450,7 +482,7 @@ The `broadcast` channel broadcasts notifications using Laravel's [event broadcas All broadcast notifications are queued for broadcasting. If you would like to configure the queue connection or queue name that is used to the queue the broadcast operation, you may use the `onConnection` and `onQueue` methods of the `BroadcastMessage`: - return new BroadcastMessage($data) + return (new BroadcastMessage($data)) ->onConnection('sqs') ->onQueue('broadcasts'); @@ -485,13 +517,11 @@ If you would like to customize which channels a notifiable entity receives its b /** * The channels the user receives notification broadcasts on. * - * @return array + * @return string */ public function receivesBroadcastNotificationsOn() { - return [ - new PrivateChannel('users.'.$this->id), - ]; + return 'users.'.$this->id; } } @@ -600,7 +630,7 @@ Before you can send notifications via Slack, you must install the Guzzle HTTP li composer require guzzlehttp/guzzle -You will also need to configure an "Incoming Webhook" integration for your Slack team. This integration will provide you with a URL you may use when [routing Slack notifications](#routing-slack-notifications). +You will also need to configure an ["Incoming Webhook"](https://api.slack.com/incoming-webhooks) integration for your Slack team. This integration will provide you with a URL you may use when [routing Slack notifications](#routing-slack-notifications). ### Formatting Slack Notifications @@ -641,6 +671,22 @@ You may use the `from` and `to` methods to customize the sender and recipient. T ->content('This will be sent to #other'); } +You may also use an image as your logo instead of an emoji: + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * @return SlackMessage + */ + public function toSlack($notifiable) + { + return (new SlackMessage) + ->from('Laravel') + ->image('https://laravel.com/favicon.png') + ->content('This will display the Laravel logo next to the message'); + } + ### Slack Attachments @@ -718,7 +764,7 @@ If some of your attachment fields contain Markdown, you may use the `markdown` m ->content('Whoops! Something went wrong.') ->attachment(function ($attachment) use ($url) { $attachment->title('Exception: File Not Found', $url) - ->content('File [background.jpg] was **not found**.') + ->content('File [background.jpg] was *not found*.') ->markdown(['title', 'text']); }); } diff --git a/package.json b/package.json index 8e62f29..f197d05 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "5.4", + "name": "5.5", "version": "1.0.0", "description": "## Contribution Guidelines", "main": "index.js", diff --git a/packages.md b/packages.md old mode 100644 new mode 100755 index 45a33dc..dbe8c69 --- a/packages.md +++ b/packages.md @@ -3,7 +3,6 @@ - [Introduction](#introduction) - [A Note On Facades](#a-note-on-facades) - [Service Providers](#service-providers) -- [Routing](#routing) - [Resources](#resources) - [Configuration](#configuration) - [Migrations](#migrations) @@ -35,21 +34,6 @@ When writing a Laravel application, it generally does not matter if you use cont A service provider extends the `Illuminate\Support\ServiceProvider` class and contains two methods: `register` and `boot`. The base `ServiceProvider` class is located in the `illuminate/support` Composer package, which you should add to your own package's dependencies. To learn more about the structure and purpose of service providers, check out [their documentation](/docs/{{version}}/providers). - -## Routing - -To define routes for your package, pass the routes file path to the `loadRoutesFrom` method from within your package service provider's `boot` method. From within your routes file, you may use the `Illuminate\Support\Facades\Route` facade to [register routes](/docs/{{version}}/routing) just as you would within a typical Laravel application: - - /** - * Perform post-registration booting of services. - * - * @return void - */ - public function boot() - { - $this->loadRoutesFrom(__DIR__.'/path/to/routes.php'); - } - ## Resources diff --git a/pagination.md b/pagination.md old mode 100644 new mode 100755 index 2a28f67..fe49575 --- a/pagination.md +++ b/pagination.md @@ -1,4 +1,4 @@ -# Pagination +# Database: Pagination - [Introduction](#introduction) - [Basic Usage](#basic-usage) diff --git a/passport.md b/passport.md old mode 100644 new mode 100755 index 356faad..915f0ca --- a/passport.md +++ b/passport.md @@ -3,6 +3,7 @@ - [Introduction](#introduction) - [Installation](#installation) - [Frontend Quickstart](#frontend-quickstart) + - [Deploying Passport](#deploying-passport) - [Configuration](#configuration) - [Token Lifetimes](#token-lifetimes) - [Issuing Access Tokens](#issuing-access-tokens) @@ -27,6 +28,7 @@ - [Checking Scopes](#checking-scopes) - [Consuming Your API With JavaScript](#consuming-your-api-with-javascript) - [Events](#events) +- [Testing](#testing) ## Introduction @@ -153,6 +155,13 @@ After registering the components, make sure to run `npm run dev` to recompile yo + +### Deploying Passport + +When deploying Passport to your production servers for the first time, you will likely need to run the `passport:keys` command. This command generates the encryption keys Passport needs in order to generate access token. The generated keys are not typically kept in source control: + + php artisan passport:keys + ## Configuration @@ -417,7 +426,21 @@ Once a grant has been enabled, developers may use their client ID to request an ## Client Credentials Grant Tokens -The client credentials grant is suitable for machine-to-machine authentication. For example, you might use this grant in a scheduled job which is performing maintenance tasks over an API. To retrieve a token, make a request to the `oauth/token` endpoint: +The client credentials grant is suitable for machine-to-machine authentication. For example, you might use this grant in a scheduled job which is performing maintenance tasks over an API. To use this method you first need to add new middleware to your `$routeMiddleware` in `app/Http/Kernel.php`: + + use Laravel\Passport\Http\Middleware\CheckClientCredentials::class; + + protected $routeMiddleware = [ + 'client' => CheckClientCredentials::class, + ]; + +Then attach this middleware to a route: + + Route::get('/user', function(Request $request) { + ... + })->middleware('client'); + +To retrieve a token, make a request to the `oauth/token` endpoint: $guzzle = new GuzzleHttp\Client; @@ -476,7 +499,7 @@ This route returns all of the [scopes](#token-scopes) defined for your applicati #### `GET /oauth/personal-access-tokens` -This route returns all of the personal access tokens that the authenticated user has created. This is primarily useful for listing all of the user's token so that they may edit or delete them: +This route returns all of the personal access tokens that the authenticated user has created. This is primarily useful for listing all of the user's tokens so that they may edit or delete them: axios.get('/oauth/personal-access-tokens') .then(response => { @@ -622,7 +645,7 @@ Typically, if you want to consume your API from your JavaScript application, you This Passport middleware will attach a `laravel_token` cookie to your outgoing responses. This cookie contains an encrypted JWT that Passport will use to authenticate API requests from your JavaScript application. Now, you may make requests to your application's API without explicitly passing an access token: - axios.get('/user') + axios.get('/api/user') .then(response => { console.log(response.data); }); @@ -657,3 +680,20 @@ protected $listen = [ ], ]; ``` + + +## Testing + +Passport's `actingAs` method may be used to specify the currently authenticated user as well as its scopes. The first argument given to the `actingAs` method is the user instance and the second is an array of scopes that should be granted to the user's token: + + public function testServerCreation() + { + Passport::actingAs( + factory(User::class)->create(), + ['create-servers'] + ); + + $response = $this->post('/api/create-server'); + + $response->assertStatus(200); + } diff --git a/passwords.md b/passwords.md old mode 100644 new mode 100755 diff --git a/providers.md b/providers.md old mode 100644 new mode 100755 diff --git a/queries.md b/queries.md old mode 100644 new mode 100755 diff --git a/queues.md b/queues.md old mode 100644 new mode 100755 index 34123b6..8087255 --- a/queues.md +++ b/queues.md @@ -107,10 +107,11 @@ Job classes are very simple, normally containing only a `handle` method which is use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; + use Illuminate\Foundation\Bus\Dispatchable; class ProcessPodcast implements ShouldQueue { - use InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $podcast; @@ -305,6 +306,8 @@ However, you may take a more granular approach by defining the maximum number of #### Timeout +> {note} The `timeout` feature is optimized for PHP 7.1+ and the `pcntl` PHP extension. + Likewise, the maximum number of seconds that jobs can run may be specified using the `--timeout` switch on the Artisan command line: php artisan queue:work --timeout=30 @@ -341,6 +344,12 @@ Laravel includes a queue worker that will process new jobs as they are pushed on Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to [restart your queue workers](#queue-workers-and-deployment). +#### Processing A Single Job + +The `--once` option may be used to instruct the worker to only process a single job from the queue: + + php artisan queue:work --once + #### Specifying The Connection & Queue You may also specify which queue connection the worker should utilize. The connection name passed to the `work` command should correspond to one of the connections defined in your `config/queue.php` configuration file: @@ -375,6 +384,8 @@ Since queue workers are long-lived processes, they will not pick up changes to y This command will instruct all queue workers to gracefully "die" after they finish processing their current job so that no existing jobs are lost. Since the queue workers will die when the `queue:restart` command is executed, you should be running a process manager such as [Supervisor](#supervisor-configuration) to automatically restart the queue workers. +> {tip} The queue uses the [cache](/docs/{{version}}/cache) to store restart signals, so you should verify a cache driver is properly configured for your application before using this feature. + ### Job Expirations & Timeouts @@ -396,7 +407,7 @@ The `retry_after` configuration option and the `--timeout` CLI option are differ #### Worker Sleep Duration -When jobs are available on the queue, the worker will keep processing jobs with no delay in between them. However, the `sleep` option determines how long the worker will "sleep" if there are no new jobs available: +When jobs are available on the queue, the worker will keep processing jobs with no delay in between them. However, the `sleep` option determines how long the worker will "sleep" if there are no new jobs available. While sleeping, the worker will not process any new jobs - the jobs will be processed after the worker wakes up again. php artisan queue:work --sleep=3 diff --git a/redirects.md b/redirects.md old mode 100644 new mode 100755 diff --git a/redis.md b/redis.md old mode 100644 new mode 100755 diff --git a/releases.md b/releases.md old mode 100644 new mode 100755 index fbecae7..cae4745 --- a/releases.md +++ b/releases.md @@ -1,21 +1,39 @@ # Release Notes +- [Versioning Scheme](#versioning-scheme) - [Support Policy](#support-policy) +- [Laravel 5.4.22](#laravel-5.4.22) - [Laravel 5.4](#laravel-5.4) -- [Laravel 5.3](#laravel-5.3) -- [Laravel 5.2](#laravel-5.2) -- [Laravel 5.1.11](#laravel-5.1.11) -- [Laravel 5.1.4](#laravel-5.1.4) -- [Laravel 5.1](#laravel-5.1) -- [Laravel 5.0](#laravel-5.0) -- [Laravel 4.2](#laravel-4.2) -- [Laravel 4.1](#laravel-4.1) + + +## Versioning Scheme + +Laravel's versioning scheme maintains the following convention: `paradigm.minor.patch`. Minor framework releases are released every six months (January and July), while patch releases may be released as often as every week. Patch releases should **never** contain breaking changes. + +When referencing the Laravel framework or its components from your application or package, you should always use a version constraint such as `5.4.*`, since minor releases of Laravel do include breaking changes. However, we strive to always ensure you may update to a new minor release in one day or less. + +Paradigm shifting releases are separated by many years and represent fundamental shifts in the framework's architecture and conventions. Currently, there is no paradigm shifting release under development. + +#### Why Doesn't Laravel Use Semantic Versioning? + +On one hand, all optional components of Laravel (Cashier, Dusk, Valet, Socialite, etc.) **do** use semantic versioning. However, the Laravel framework itself does not. The reason for this is because semantic versioning is a "reductionist" way of determining if two pieces of code are compatible. Even when using semantic versioning, you still must install the upgraded package and run your automated test suite to know if anything is *actually* incompatible with your code base. + +So, instead, the Laravel framework uses a versioning scheme that is more communicative of the actual scope of the release. Furthermore, since patch releases **never** contain intentional breaking changes, you should never receive a breaking change as long as your version constraints follow the `paradigm.minor.*` convention. ## Support Policy For LTS releases, such as Laravel 5.1, bug fixes are provided for 2 years and security fixes are provided for 3 years. These releases provide the longest window of support and maintenance. For general releases, bug fixes are provided for 6 months and security fixes are provided for 1 year. + +## Laravel 5.4.22 + +Laravel 5.4.22 patches a security vulnerability in the Laravel 5.4 release series that allows phishing attempts on users of the application. Using the password reset system, malicious users can attempt to trick your users into entering their login credentials into a separate application that they control. Since the password reset notification uses the host of the incoming request to build the password reset URL, the host of the password reset URL may be spoofed. If users do not notice that they are not on their intended application's domain, they may accidentally enter their login credentials into a malicious application. + +In Laravel 5.1 applications, the password reset notification is maintained by the developer, so this vulnerability may or may not be present. You should verify that your application generates an absolute URL for password reset links: + + {{ url('http://example.com/password/reset/'.$token) }} + ## Laravel 5.4 @@ -341,811 +359,3 @@ If you choose to switch to this character set manually and are running a version { Schema::defaultStringLength(191); } - - -## Laravel 5.3 - -Laravel 5.3 continues the improvements made in Laravel 5.2 by adding a driver based [notification system](/docs/5.3/notifications), robust realtime support via [Laravel Echo](/docs/5.3/broadcasting), painless OAuth2 servers via [Laravel Passport](/docs/5.3/passport), full-text model searching via [Laravel Scout](/docs/5.3/scout), Webpack support in Laravel Elixir, "mailable" objects, explicit separation of `web` and `api` routes, Closure based console commands, convenient helpers for storing uploaded files, support for POPO and single-action controllers, improved default frontend scaffolding, and more. - -### Notifications - -> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/9) for this feature available on Laracasts. - -Laravel Notifications provide a simple, expressive API for sending notifications across a variety of delivery channels such as email, Slack, SMS, and more. For example, you may define a notification that an invoice has been paid and deliver that notification via email and SMS. Then, you may send the notification using a single, simple method: - - $user->notify(new InvoicePaid($invoice)); - -There is already a wide variety of [community written drivers](http://laravel-notification-channels.com) for notifications, including support for iOS and Android notifications. To learn more about notifications, be sure to check out the [full notification documentation](/docs/5.3/notifications). - -### WebSockets / Event Broadcasting - -While event broadcasting existed in previous versions of Laravel, the Laravel 5.3 release greatly improves this feature of the framework by adding channel-level authentication for private and presence WebSocket channels: - - /* - * Authenticate the channel subscription... - */ - Broadcast::channel('orders.*', function ($user, $orderId) { - return $user->placedOrder($orderId); - }); - -Laravel Echo, a new JavaScript package installable via NPM, has also been released to provide a simple, beautiful API for subscribing to channels and listening for your server-side events in your client-side JavaScript application. Echo includes support for [Pusher](https://pusher.com) and [Socket.io](http://socket.io): - - Echo.channel('orders.' + orderId) - .listen('ShippingStatusUpdated', (e) => { - console.log(e.description); - }); - -In addition to subscribing to traditional channels, Laravel Echo also makes it a breeze to subscribe to presence channels which provide information about who is listening on a given channel: - - Echo.join('chat.' + roomId) - .here((users) => { - // - }) - .joining((user) => { - console.log(user.name); - }) - .leaving((user) => { - console.log(user.name); - }); - -To learn more about Echo and event broadcasting, check out the [full documentation](/docs/5.3/broadcasting). - -### Laravel Passport (OAuth2 Server) - -> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/13) for this feature available on Laracasts. - -Laravel 5.3 makes API authentication a breeze using [Laravel Passport](/docs/{{version}}/passport), which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the [League OAuth2 server](https://github.com/thephpleague/oauth2-server) that is maintained by Alex Bilbie. - -Passport makes it painless to issue access tokens via OAuth2 authorization codes. You may also allow your users to create "personal access tokens" via your web UI. To get you started quickly, Passport includes [Vue components](https://vuejs.org) that can serve as a starting point for your OAuth2 dashboard, allowing users to create clients, revoke access tokens, and more: - - - - - -If you do not want to use the Vue components, you are welcome to provide your own frontend dashboard for managing clients and access tokens. Passport exposes a simple JSON API that you may use with any JavaScript framework you choose. - -Of course, Passport also makes it simple to define access token scopes that may be requested by application's consuming your API: - - Passport::tokensCan([ - 'place-orders' => 'Place new orders', - 'check-status' => 'Check order status', - ]); - -In addition, Passport includes helpful middleware for verifying that an access token authenticated request contains the necessary token scopes: - - Route::get('/orders/{order}/status', function (Order $order) { - // Access token has "check-status" scope... - })->middleware('scope:check-status'); - -Lastly, Passport includes support for consuming your own API from your JavaScript application without worrying about passing access tokens. Passport achieves this through encrypted JWT cookies and synchronized CSRF tokens, allowing you to focus on what matters: your application. For more information on Passport, be sure to check out its [full documentation](/docs/5.3/passport). - -### Search (Laravel Scout) - -Laravel Scout provides a simple, driver based solution for adding full-text search to your [Eloquent models](/docs/5.3/eloquent). Using model observers, Scout will automatically keep your search indexes in sync with your Eloquent records. Currently, Scout ships with an [Algolia](https://www.algolia.com/) driver; however, writing custom drivers is simple and you are free to extend Scout with your own search implementations. - -Making models searchable is as simple as adding a `Searchable` trait to the model: - - save(); - -Once your models have been indexed, its a breeze to perform full-text searches across all of your models. You may even paginate your search results: - - return Order::search('Star Trek')->get(); - - return Order::search('Star Trek')->where('user_id', 1)->paginate(); - -Of course, Scout has many more features which are covered in the [full documentation](/docs/5.3/scout). - -### Mailable Objects - -> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/6) for this feature available on Laracasts. - -Laravel 5.3 ships with support for mailable objects. These objects allow you to represent your email messages as a simple objects instead of customizing mail messages within Closures. For example, you may define a simple mailable object for a "welcome" email: - - class WelcomeMessage extends Mailable - { - use Queueable, SerializesModels; - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->view('emails.welcome'); - } - } - -Once the mailable object has been defined, you can send it to a user using a simple, expressive API. Mailable objects are great for discovering the intent of your messages while scanning your code: - - Mail::to($user)->send(new WelcomeMessage); - -Of course, you may also mark mailable objects as "queueable" so that they will be sent in the background by your queue workers: - - class WelcomeMessage extends Mailable implements ShouldQueue - { - // - } - -For more information on mailable objects, be sure to check out the [mail documentation](/docs/5.3/mail). - -### Storing Uploaded Files - -> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/12) for this feature available on Laracasts. - -In web applications, one of the most common use-cases for storing files is storing user uploaded files such as profile pictures, photos, and documents. Laravel 5.3 makes it very easy to store uploaded files using the new `store` method on an uploaded file instance. Simply call the `store` method with the path at which you wish to store the uploaded file: - - /** - * Update the avatar for the user. - * - * @param Request $request - * @return Response - */ - public function update(Request $request) - { - $path = $request->file('avatar')->store('avatars', 's3'); - - return $path; - } - -For more information on storing uploaded files, check out the [full documentation](/docs/{{version}}/filesystem#file-uploads). - - -### Webpack & Laravel Elixir - -Along with Laravel 5.3, Laravel Elixir 6.0 has been released with baked-in support for the Webpack and Rollup JavaScript module bundlers. By default, the Laravel 5.3 `gulpfile.js` file now uses Webpack to compile your JavaScript. The [full Laravel Elixir documentation](/docs/5.3/elixir) contains more information on both of these bundlers: - - elixir(mix => { - mix.sass('app.scss') - .webpack('app.js'); - }); - -### Frontend Structure - -> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/4) for this feature available on Laracasts. - -Laravel 5.3 ships with a more modern frontend structure. This primarily affects the `make:auth` authentication scaffolding. Instead of loading frontend assets from a CDN, dependencies are specified in the default `package.json` file. - -In addition, support for single file [Vue components](https://vuejs.org) is now included out of the box. A sample `Example.vue` component is included in the `resources/assets/js/components` directory. In addition, the new `resources/assets/js/app.js` file bootstraps and configures your JavaScript libraries and, if applicable, Vue components. - -This structure provides more guidance on how to begin developing modern, robust JavaScript applications, without requiring your application to use any given JavaScript or CSS framework. For more information on getting started with modern Laravel frontend development, check out the new [introductory frontend documentation](/docs/5.3/frontend). - -### Routes Files - -By default, fresh Laravel 5.3 applications contain two HTTP route files in a new top-level `routes` directory. The `web` and `api` route files provide more explicit guidance in how to split the routes for your web interface and your API. The routes in the `api` route file are automatically assigned the `api` prefix by the `RouteServiceProvider`. - -### Closure Console Commands - -In addition to being defined as command classes, Artisan commands may now be defined as simple Closures in the `commands` method of your `app/Console/Kernel.php` file. In fresh Laravel 5.3 applications, the `commands` method loads a `routes/console.php` file which allows you to define your Console commands as route-like, Closure based entry points into your application: - - Artisan::command('build {project}', function ($project) { - $this->info('Building project...'); - }); - -For more information on Closure commands, check out the [full Artisan documentation](/docs/5.3/artisan#closure-commands). - -### The `$loop` Variable - -> {video} There is a free [video tutorial](https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/7) for this feature available on Laracasts. - -When looping within a Blade template, a `$loop` variable will be available inside of your loop. This variable provides access to some useful bits of information such as the current loop index and whether this is the first or last iteration through the loop: - - @foreach ($users as $user) - @if ($loop->first) - This is the first iteration. - @endif - - @if ($loop->last) - This is the last iteration. - @endif - -

This is user {{ $user->id }}

- @endforeach - -For more information, consult the [full Blade documentation](/docs/5.3/blade#the-loop-variable). - - -## Laravel 5.2 - -Laravel 5.2 continues the improvements made in Laravel 5.1 by adding multiple authentication driver support, implicit model binding, simplified Eloquent global scopes, opt-in authentication scaffolding, middleware groups, rate limiting middleware, array validation improvements, and more. - -### Authentication Drivers / "Multi-Auth" - -In previous versions of Laravel, only the default, session-based authentication driver was supported out of the box, and you could not have more than one authenticatable model instance per application. - -However, in Laravel 5.2, you may define additional authentication drivers as well define multiple authenticatable models or user tables, and control their authentication process separately from each other. For example, if your application has one database table for "admin" users and one database table for "student" users, you may now use the `Auth` methods to authenticate against each of these tables separately. - -### Authentication Scaffolding - -Laravel already makes it easy to handle authentication on the back-end; however, Laravel 5.2 provides a convenient, lightning-fast way to scaffold the authentication views for your front-end. Simply execute the `make:auth` command on your terminal: - - php artisan make:auth - -This command will generate plain, Bootstrap compatible views for user login, registration, and password reset. The command will also update your routes file with the appropriate routes. - -> {note} This feature is only meant to be used on new applications, not during application upgrades. - -### Implicit Model Binding - -Implicit model binding makes it painless to inject relevant models directly into your routes and controllers. For example, assume you have a route defined like the following: - - use App\User; - - Route::get('/user/{user}', function (User $user) { - return $user; - }); - -In Laravel 5.1, you would typically need to use the `Route::model` method to instruct Laravel to inject the `App\User` instance that matches the `{user}` parameter in your route definition. However, in Laravel 5.2, the framework will **automatically** inject this model based on the URI segment, allowing you to quickly gain access to the model instances you need. - -Laravel will automatically inject the model when the route parameter segment (`{user}`) matches the route Closure or controller method's corresponding variable name (`$user`) and the variable is type-hinting an Eloquent model class. - -### Middleware Groups - -Middleware groups allow you to group several route middleware under a single, convenient key, allowing you to assign several middleware to a route at once. For example, this can be useful when building a web UI and an API within the same application. You may group the session and CSRF routes into a `web` group, and perhaps the rate limiter in the `api` group. - -In fact, the default Laravel 5.2 application structure takes exactly this approach. For example, in the default `App\Http\Kernel.php` file you will find the following: - - /** - * The application's route middleware groups. - * - * @var array - */ - protected $middlewareGroups = [ - 'web' => [ - \App\Http\Middleware\EncryptCookies::class, - \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, - \Illuminate\Session\Middleware\StartSession::class, - \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \App\Http\Middleware\VerifyCsrfToken::class, - ], - - 'api' => [ - 'throttle:60,1', - ], - ]; - -Then, the `web` group may be assigned to routes like so: - - Route::group(['middleware' => ['web']], function () { - // - }); - -However, keep in mind the `web` middleware group is *already* applied to your routes by default since the `RouteServiceProvider` includes it in the default middleware group. - -### Rate Limiting - -A new rate limiter middleware is now included with the framework, allowing you to easily limit the number of requests that a given IP address can make to a route over a specified number of minutes. For example, to limit a route to 60 requests every minute from a single IP address, you may do the following: - - Route::get('/api/users', ['middleware' => 'throttle:60,1', function () { - // - }]); - -### Array Validation - -Validating array form input fields is much easier in Laravel 5.2. For example, to validate that each e-mail in a given array input field is unique, you may do the following: - - $validator = Validator::make($request->all(), [ - 'person.*.email' => 'email|unique:users' - ]); - -Likewise, you may use the `*` character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields: - - 'custom' => [ - 'person.*.email' => [ - 'unique' => 'Each person must have a unique e-mail address', - ] - ], - -### Bail Validation Rule - -A new `bail` validation rule has been added, which instructs the validator to stop validating after the first validation failure for a given rule. For example, you may now prevent the validator from running a `unique` check if an attribute fails an `integer` check: - - $this->validate($request, [ - 'user_id' => 'bail|integer|unique:users' - ]); - -### Eloquent Global Scope Improvements - -In previous versions of Laravel, global Eloquent scopes were complicated and error-prone to implement; however, in Laravel 5.2, global query scopes only require you to implement a single, simple method: `apply`. - -For more information on writing global scopes, check out the full [Eloquent documentation](/docs/{{version}}/eloquent#global-scopes). - - -## Laravel 5.1.11 - -Laravel 5.1.11 introduces [authorization](/docs/{{version}}/authorization) support out of the box! Conveniently organize your application's authorization logic using simple callbacks or policy classes, and authorize actions using simple, expressive methods. - -For more information, please refer to the [authorization documentation](/docs/{{version}}/authorization). - - -## Laravel 5.1.4 - -Laravel 5.1.4 introduces simple login throttling to the framework. Consult the [authentication documentation](/docs/{{version}}/authentication#authentication-throttling) for more information. - - -## Laravel 5.1 - -Laravel 5.1 continues the improvements made in Laravel 5.0 by adopting PSR-2 and adding event broadcasting, middleware parameters, Artisan improvements, and more. - -### PHP 5.5.9+ - -Since PHP 5.4 will enter "end of life" in September and will no longer receive security updates from the PHP development team, Laravel 5.1 requires PHP 5.5.9 or greater. PHP 5.5.9 allows compatibility with the latest versions of popular PHP libraries such as Guzzle and the AWS SDK. - -### LTS - - Laravel 5.1 is the first release of Laravel to receive **long term support**. Laravel 5.1 will receive bug fixes for 2 years and security fixes for 3 years. This support window is the largest ever provided for Laravel and provides stability and peace of mind for larger, enterprise clients and customers. - -### PSR-2 - -The [PSR-2 coding style guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) has been adopted as the default style guide for the Laravel framework. Additionally, all generators have been updated to generate PSR-2 compatible syntax. - -### Documentation - -Every page of the Laravel documentation has been meticulously reviewed and dramatically improved. All code examples have also been reviewed and expanded to provide more relevance and context. - -### Event Broadcasting - -In many modern web applications, web sockets are used to implement realtime, live-updating user interfaces. When some data is updated on the server, a message is typically sent over a websocket connection to be handled by the client. - -To assist you in building these types of applications, Laravel makes it easy to "broadcast" your events over a websocket connection. Broadcasting your Laravel events allows you to share the same event names between your server-side code and your client-side JavaScript framework. - -To learn more about event broadcasting, check out the [event documentation](/docs/{{version}}/events#broadcasting-events). - -### Middleware Parameters - -Middleware can now receive additional custom parameters. For example, if your application needs to verify that the authenticated user has a given "role" before performing a given action, you could create a `RoleMiddleware` that receives a role name as an additional argument: - - user()->hasRole($role)) { - // Redirect... - } - - return $next($request); - } - - } - -Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a `:`. Multiple parameters should be delimited by commas: - - Route::put('post/{id}', ['middleware' => 'role:editor', function ($id) { - // - }]); - -For more information on middleware, check out the [middleware documentation](/docs/{{version}}/middleware). - -### Testing Overhaul - -The built-in testing capabilities of Laravel have been dramatically improved. A variety of new methods provide a fluent, expressive interface for interacting with your application and examining its responses. For example, check out the following test: - - public function testNewUserRegistration() - { - $this->visit('/register') - ->type('Taylor', 'name') - ->check('terms') - ->press('Register') - ->seePageIs('/dashboard'); - } - -For more information on testing, check out the [testing documentation](/docs/{{version}}/testing). - -### Model Factories - -Laravel now ships with an easy way to create stub Eloquent models using [model factories](/docs/{{version}}/database-testing#writing-factories). Model factories allow you to easily define a set of "default" attributes for your Eloquent model, and then generate test model instances for your tests or database seeds. Model factories also take advantage of the powerful [Faker](https://github.com/fzaninotto/Faker) PHP library for generating random attribute data: - - $factory->define(App\User::class, function ($faker) { - return [ - 'name' => $faker->name, - 'email' => $faker->email, - 'password' => str_random(10), - 'remember_token' => str_random(10), - ]; - }); - -For more information on model factories, check out [the documentation](/docs/{{version}}/database-testing#writing-factories). - -### Artisan Improvements - -Artisan commands may now be defined using a simple, route-like "signature", which provides an extremely simple interface for defining command line arguments and options. For example, you may define a simple command and its options like so: - - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'email:send {user} {--force}'; - -For more information on defining Artisan commands, consult the [Artisan documentation](/docs/{{version}}/artisan). - -### Folder Structure - -To better express intent, the `app/Commands` directory has been renamed to `app/Jobs`. Additionally, the `app/Handlers` directory has been consolidated into a single `app/Listeners` directory which simply contains event listeners. However, this is not a breaking change and you are not required to update to the new folder structure to use Laravel 5.1. - -### Encryption - -In previous versions of Laravel, encryption was handled by the `mcrypt` PHP extension. However, beginning in Laravel 5.1, encryption is handled by the `openssl` extension, which is more actively maintained. - - -## Laravel 5.0 - -Laravel 5.0 introduces a fresh application structure to the default Laravel project. This new structure serves as a better foundation for building a robust application in Laravel, as well as embraces new auto-loading standards (PSR-4) throughout the application. First, let's examine some of the major changes: - -### New Folder Structure - -The old `app/models` directory has been entirely removed. Instead, all of your code lives directly within the `app` folder, and, by default, is organized to the `App` namespace. This default namespace can be quickly changed using the new `app:name` Artisan command. - -Controllers, middleware, and requests (a new type of class in Laravel 5.0) are now grouped under the `app/Http` directory, as they are all classes related to the HTTP transport layer of your application. Instead of a single, flat file of route filters, all middleware are now broken into their own class files. - -A new `app/Providers` directory replaces the `app/start` files from previous versions of Laravel 4.x. These service providers provide various bootstrapping functions to your application, such as error handling, logging, route loading, and more. Of course, you are free to create additional service providers for your application. - -Application language files and views have been moved to the `resources` directory. - -### Contracts - -All major Laravel components implement interfaces which are located in the `illuminate/contracts` repository. This repository has no external dependencies. Having a convenient, centrally located set of interfaces you may use for decoupling and dependency injection will serve as an easy alternative option to Laravel Facades. - -For more information on contracts, consult the [full documentation](/docs/{{version}}/contracts). - -### Route Cache - -If your application is made up entirely of controller routes, you may utilize the new `route:cache` Artisan command to drastically speed up the registration of your routes. This is primarily useful on applications with 100+ routes and will **drastically** speed up this portion of your application. - -### Route Middleware - -In addition to Laravel 4 style route "filters", Laravel 5 now supports HTTP middleware, and the included authentication and CSRF "filters" have been converted to middleware. Middleware provides a single, consistent interface to replace all types of filters, allowing you to easily inspect, and even reject, requests before they enter your application. - -For more information on middleware, check out [the documentation](/docs/{{version}}/middleware). - -### Controller Method Injection - -In addition to the existing constructor injection, you may now type-hint dependencies on controller methods. The [service container](/docs/{{version}}/container) will automatically inject the dependencies, even if the route contains other parameters: - - public function createPost(Request $request, PostRepository $posts) - { - // - } - -### Authentication Scaffolding - -User registration, authentication, and password reset controllers are now included out of the box, as well as simple corresponding views, which are located at `resources/views/auth`. In addition, a "users" table migration has been included with the framework. Including these simple resources allows rapid development of application ideas without bogging down on authentication boilerplate. The authentication views may be accessed on the `auth/login` and `auth/register` routes. The `App\Services\Auth\Registrar` service is responsible for user validation and creation. - -### Event Objects - -You may now define events as objects instead of simply using strings. For example, check out the following event: - - podcast = $podcast; - } - } - -The event may be dispatched like normal: - - Event::fire(new PodcastWasPurchased($podcast)); - -Of course, your event handler will receive the event object instead of a list of data: - - user = $user; - $this->podcast = $podcast; - } - - /** - * Execute the command. - * - * @return void - */ - public function handle() - { - // Handle the logic to purchase the podcast... - - event(new PodcastWasPurchased($this->user, $this->podcast)); - } - } - -The base Laravel controller utilizes the new `DispatchesCommands` trait, allowing you to easily dispatch your commands for execution: - - $this->dispatch(new PurchasePodcastCommand($user, $podcast)); - -Of course, you may also use commands for tasks that are executed synchronously (are not queued). In fact, using commands is a great way to encapsulate complex tasks your application needs to perform. For more information, check out the [command bus](/docs/{{version}}/bus) documentation. - -### Database Queue - -A `database` queue driver is now included in Laravel, providing a simple, local queue driver that requires no extra package installation beyond your database software. - -### Laravel Scheduler - -In the past, developers have generated a Cron entry for each console command they wished to schedule. However, this is a headache. Your console schedule is no longer in source control, and you must SSH into your server to add the Cron entries. Let's make our lives easier. The Laravel command scheduler allows you to fluently and expressively define your command schedule within Laravel itself, and only a single Cron entry is needed on your server. - -It looks like this: - - $schedule->command('artisan:command')->dailyAt('15:00'); - -Of course, check out the [full documentation](/docs/{{version}}/scheduling) to learn all about the scheduler! - -### Tinker / Psysh - -The `php artisan tinker` command now utilizes [Psysh](https://github.com/bobthecow/psysh) by Justin Hileman, a more robust REPL for PHP. If you liked Boris in Laravel 4, you're going to love Psysh. Even better, it works on Windows! To get started, just try: - - php artisan tinker - -### DotEnv - -Instead of a variety of confusing, nested environment configuration directories, Laravel 5 now utilizes [DotEnv](https://github.com/vlucas/phpdotenv) by Vance Lucas. This library provides a super simple way to manage your environment configuration, and makes environment detection in Laravel 5 a breeze. For more details, check out the full [configuration documentation](/docs/{{version}}/installation#environment-configuration). - -### Laravel Elixir - -Laravel Elixir, by Jeffrey Way, provides a fluent, expressive interface to compiling and concatenating your assets. If you've ever been intimidated by learning Grunt or Gulp, fear no more. Elixir makes it a cinch to get started using Gulp to compile your Less, Sass, and CoffeeScript. It can even run your tests for you! - -For more information on Elixir, check out the [full documentation](/docs/{{version}}/elixir). - -### Laravel Socialite - -Laravel Socialite is an optional, Laravel 5.0+ compatible package that provides totally painless authentication with OAuth providers. Currently, Socialite supports Facebook, Twitter, Google, and GitHub. Here's what it looks like: - - public function redirectForAuth() - { - return Socialize::with('twitter')->redirect(); - } - - public function getUserFromProvider() - { - $user = Socialize::with('twitter')->user(); - } - -No more spending hours writing OAuth authentication flows. Get started in minutes! The [full documentation](/docs/{{version}}/authentication#social-authentication) has all the details. - -### Flysystem Integration - -Laravel now includes the powerful [Flysystem](https://github.com/thephpleague/flysystem) filesystem abstraction library, providing pain free integration with local, Amazon S3, and Rackspace cloud storage - all with one, unified and elegant API! Storing a file in Amazon S3 is now as simple as: - - Storage::put('file.txt', 'contents'); - -For more information on the Laravel Flysystem integration, consult the [full documentation](/docs/{{version}}/filesystem). - -### Form Requests - -Laravel 5.0 introduces **form requests**, which extend the `Illuminate\Foundation\Http\FormRequest` class. These request objects can be combined with controller method injection to provide a boiler-plate free method of validating user input. Let's dig in and look at a sample `FormRequest`: - - 'required|email|unique:users', - 'password' => 'required|confirmed|min:8', - ]; - } - - public function authorize() - { - return true; - } - } - -Once the class has been defined, we can type-hint it on our controller action: - - public function register(RegisterRequest $request) - { - var_dump($request->input()); - } - -When the Laravel service container identifies that the class it is injecting is a `FormRequest` instance, the request will **automatically be validated**. This means that if your controller action is called, you can safely assume the HTTP request input has been validated according to the rules you specified in your form request class. Even more, if the request is invalid, an HTTP redirect, which you may customize, will automatically be issued, and the error messages will be either flashed to the session or converted to JSON. **Form validation has never been more simple.** For more information on `FormRequest` validation, check out the [documentation](/docs/{{version}}/validation#form-request-validation). - -### Simple Controller Request Validation - -The Laravel 5 base controller now includes a `ValidatesRequests` trait. This trait provides a simple `validate` method to validate incoming requests. If `FormRequests` are a little too much for your application, check this out: - - public function createPost(Request $request) - { - $this->validate($request, [ - 'title' => 'required|max:255', - 'body' => 'required', - ]); - } - -If the validation fails, an exception will be thrown and the proper HTTP response will automatically be sent back to the browser. The validation errors will even be flashed to the session! If the request was an AJAX request, Laravel even takes care of sending a JSON representation of the validation errors back to you. - -For more information on this new method, check out [the documentation](/docs/{{version}}/validation#validation-quickstart). - -### New Generators - -To complement the new default application structure, new Artisan generator commands have been added to the framework. See `php artisan list` for more details. - -### Configuration Cache - -You may now cache all of your configuration in a single file using the `config:cache` command. - -### Symfony VarDumper - -The popular `dd` helper function, which dumps variable debug information, has been upgraded to use the amazing Symfony VarDumper. This provides color-coded output and even collapsing of arrays. Just try the following in your project: - - dd([1, 2, 3]); - - -## Laravel 4.2 - -The full change list for this release by running the `php artisan changes` command from a 4.2 installation, or by [viewing the change file on Github](https://github.com/laravel/framework/blob/4.2/src/Illuminate/Foundation/changes.json). These notes only cover the major enhancements and changes for the release. - -> {note} During the 4.2 release cycle, many small bug fixes and enhancements were incorporated into the various Laravel 4.1 point releases. So, be sure to check the change list for Laravel 4.1 as well! - -### PHP 5.4 Requirement - -Laravel 4.2 requires PHP 5.4 or greater. This upgraded PHP requirement allows us to use new PHP features such as traits to provide more expressive interfaces for tools like [Laravel Cashier](/docs/billing). PHP 5.4 also brings significant speed and performance improvements over PHP 5.3. - -### Laravel Forge - -Laravel Forge, a new web based application, provides a simple way to create and manage PHP servers on the cloud of your choice, including Linode, DigitalOcean, Rackspace, and Amazon EC2. Supporting automated Nginx configuration, SSH key access, Cron job automation, server monitoring via NewRelic & Papertrail, "Push To Deploy", Laravel queue worker configuration, and more, Forge provides the simplest and most affordable way to launch all of your Laravel applications. - -The default Laravel 4.2 installation's `app/config/database.php` configuration file is now configured for Forge usage by default, allowing for more convenient deployment of fresh applications onto the platform. - -More information about Laravel Forge can be found on the [official Forge website](https://forge.laravel.com). - -### Laravel Homestead - -Laravel Homestead is an official Vagrant environment for developing robust Laravel and PHP applications. The vast majority of the boxes' provisioning needs are handled before the box is packaged for distribution, allowing the box to boot extremely quickly. Homestead includes Nginx 1.6, PHP 5.6, MySQL, Postgres, Redis, Memcached, Beanstalk, Node, Gulp, Grunt, & Bower. Homestead includes a simple `Homestead.yaml` configuration file for managing multiple Laravel applications on a single box. - -The default Laravel 4.2 installation now includes an `app/config/local/database.php` configuration file that is configured to use the Homestead database out of the box, making Laravel initial installation and configuration more convenient. - -The official documentation has also been updated to include [Homestead documentation](/docs/homestead). - -### Laravel Cashier - -Laravel Cashier is a simple, expressive library for managing subscription billing with Stripe. With the introduction of Laravel 4.2, we are including Cashier documentation along with the main Laravel documentation, though installation of the component itself is still optional. This release of Cashier brings numerous bug fixes, multi-currency support, and compatibility with the latest Stripe API. - -### Daemon Queue Workers - -The Artisan `queue:work` command now supports a `--daemon` option to start a worker in "daemon mode", meaning the worker will continue to process jobs without ever re-booting the framework. This results in a significant reduction in CPU usage at the cost of a slightly more complex application deployment process. - -More information about daemon queue workers can be found in the [queue documentation](/docs/queues#daemon-queue-worker). - -### Mail API Drivers - -Laravel 4.2 introduces new Mailgun and Mandrill API drivers for the `Mail` functions. For many applications, this provides a faster and more reliable method of sending e-mails than the SMTP options. The new drivers utilize the Guzzle 4 HTTP library. - -### Soft Deleting Traits - -A much cleaner architecture for "soft deletes" and other "global scopes" has been introduced via PHP 5.4 traits. This new architecture allows for the easier construction of similar global traits, and a cleaner separation of concerns within the framework itself. - -More information on the new `SoftDeletingTrait` may be found in the [Eloquent documentation](/docs/eloquent#soft-deleting). - -### Convenient Auth & Remindable Traits - -The default Laravel 4.2 installation now uses simple traits for including the needed properties for the authentication and password reminder user interfaces. This provides a much cleaner default `User` model file out of the box. - -### "Simple Paginate" - -A new `simplePaginate` method was added to the query and Eloquent builder which allows for more efficient queries when using simple "Next" and "Previous" links in your pagination view. - -### Migration Confirmation - -In production, destructive migration operations will now ask for confirmation. Commands may be forced to run without any prompts using the `--force` command. - - -## Laravel 4.1 - -### Full Change List - -The full change list for this release by running the `php artisan changes` command from a 4.1 installation, or by [viewing the change file on Github](https://github.com/laravel/framework/blob/4.1/src/Illuminate/Foundation/changes.json). These notes only cover the major enhancements and changes for the release. - -### New SSH Component - -An entirely new `SSH` component has been introduced with this release. This feature allows you to easily SSH into remote servers and run commands. To learn more, consult the [SSH component documentation](/docs/ssh). - -The new `php artisan tail` command utilizes the new SSH component. For more information, consult the `tail` [command documentation](http://laravel.com/docs/ssh#tailing-remote-logs). - -### Boris In Tinker - -The `php artisan tinker` command now utilizes the [Boris REPL](https://github.com/d11wtq/boris) if your system supports it. The `readline` and `pcntl` PHP extensions must be installed to use this feature. If you do not have these extensions, the shell from 4.0 will be used. - -### Eloquent Improvements - -A new `hasManyThrough` relationship has been added to Eloquent. To learn how to use it, consult the [Eloquent documentation](/docs/eloquent#has-many-through). - -A new `whereHas` method has also been introduced to allow [retrieving models based on relationship constraints](/docs/eloquent#querying-relations). - -### Database Read / Write Connections - -Automatic handling of separate read / write connections is now available throughout the database layer, including the query builder and Eloquent. For more information, consult [the documentation](/docs/database#read-write-connections). - -### Queue Priority - -Queue priorities are now supported by passing a comma-delimited list to the `queue:listen` command. - -### Failed Queue Job Handling - -The queue facilities now include automatic handling of failed jobs when using the new `--tries` switch on `queue:listen`. More information on handling failed jobs can be found in the [queue documentation](/docs/queues#failed-jobs). - -### Cache Tags - -Cache "sections" have been superseded by "tags". Cache tags allow you to assign multiple "tags" to a cache item, and flush all items assigned to a single tag. More information on using cache tags may be found in the [cache documentation](/docs/cache#cache-tags). - -### Flexible Password Reminders - -The password reminder engine has been changed to provide greater developer flexibility when validating passwords, flashing status messages to the session, etc. For more information on using the enhanced password reminder engine, [consult the documentation](/docs/security#password-reminders-and-reset). - -### Improved Routing Engine - -Laravel 4.1 features a totally re-written routing layer. The API is the same; however, registering routes is a full 100% faster compared to 4.0. The entire engine has been greatly simplified, and the dependency on Symfony Routing has been minimized to the compiling of route expressions. - -### Improved Session Engine - -With this release, we're also introducing an entirely new session engine. Similar to the routing improvements, the new session layer is leaner and faster. We are no longer using Symfony's (and therefore PHP's) session handling facilities, and are using a custom solution that is simpler and easier to maintain. - -### Doctrine DBAL - -If you are using the `renameColumn` function in your migrations, you will need to add the `doctrine/dbal` dependency to your `composer.json` file. This package is no longer included in Laravel by default. diff --git a/requests.md b/requests.md old mode 100644 new mode 100755 index fa70a40..4906f4a --- a/requests.md +++ b/requests.md @@ -3,6 +3,7 @@ - [Accessing The Request](#accessing-the-request) - [Request Path & Method](#request-path-and-method) - [PSR-7 Requests](#psr7-requests) +- [Input Trimming & Normalization](#input-trimming-and-normalization) - [Retrieving Input](#retrieving-input) - [Old Input](#old-input) - [Cookies](#cookies) @@ -131,6 +132,13 @@ Once you have installed these libraries, you may obtain a PSR-7 request by type- > {tip} If you return a PSR-7 response instance from a route or controller, it will automatically be converted back to a Laravel response instance and be displayed by the framework. + +## Input Trimming & Normalization + +By default, Laravel includes the `TrimStrings` and `ConvertEmptyStringsToNull` middleware in your application's global middleware stack. These middleware are listed in the stack by the `App\Http\Kernel` class. These middleware will automatically trim all incoming string fields on the request, as well as convert any empty string fields to `null`. This allows you to not have to worry about these normalization concerns in your routes and controllers. + +If you would like to disable this behavior, you may remove the two middleware from your application's middleware stack by removing them from the `$middleware` property of your `App\Http\Kernel` class. + ## Retrieving Input @@ -156,6 +164,20 @@ When working with forms that contain array inputs, use "dot" notation to access $names = $request->input('products.*.name'); +#### Retrieving Input From The Query String + +While the `input` method retrieves values from entire request payload (including the query string), the `query` method will only retrieve values from the query string: + + $name = $request->query('name'); + +If the requested query string value data is not present, the second argument to this method will be returned: + + $name = $request->query('name', 'Helen'); + +You may call the `query` method without any arguments in order to retrieve all of the query string values as an associative array: + + $query = $request->query(); + #### Retrieving Input Via Dynamic Properties You may also access user input using dynamic properties on the `Illuminate\Http\Request` instance. For example, if one of your application's forms contains a `name` field, you may access the value of the field like so: @@ -182,6 +204,10 @@ If you need to retrieve a subset of the input data, you may use the `only` and ` $input = $request->except('credit_card'); +The `only` method returns all of the key / value pairs that you request, even if the key is not present on the incoming request. When the key is not present on the request, the value will be `null`. If you would like to retrieve a portion of input data that is actually present on the request, you may use the `intersect` method: + + $input = $request->intersect(['username', 'password']); + #### Determining If An Input Value Is Present You should use the `has` method to determine if a value is present on the request. The `has` method returns `true` if the value is present and is not an empty string: @@ -190,6 +216,12 @@ You should use the `has` method to determine if a value is present on the reques // } +When given an array, the `has` method will determine if all of the specified values are present: + + if ($request->has(['name', 'email'])) { + // + } + ### Old Input diff --git a/responses.md b/responses.md old mode 100644 new mode 100755 index 9acb20c..9ad063e --- a/responses.md +++ b/responses.md @@ -213,6 +213,8 @@ The `download` method may be used to generate a response that forces the user's return response()->download($pathToFile); return response()->download($pathToFile, $name, $headers); + + return response()->download($pathToFile)->deleteFileAfterSend(true); > {note} Symfony HttpFoundation, which manages file downloads, requires the file being downloaded to have an ASCII file name. diff --git a/routing.md b/routing.md old mode 100644 new mode 100755 index 2537788..8e8cb4f --- a/routing.md +++ b/routing.md @@ -30,7 +30,11 @@ The most basic Laravel routes simply accept a URI and a `Closure`, providing a v All Laravel routes are defined in your route files, which are located in the `routes` directory. These files are automatically loaded by the framework. The `routes/web.php` file defines routes that are for your web interface. These routes are assigned the `web` middleware group, which provides features like session state and CSRF protection. The routes in `routes/api.php` are stateless and are assigned the `api` middleware group. -For most applications, you will begin by defining routes in your `routes/web.php` file. +For most applications, you will begin by defining routes in your `routes/web.php` file. The routes defined in `routes/web.php` may be accessed by entering the defined route's URL in your browser. For example, you may access the following route by navigating to `http://your-app.dev/user` in your browser: + + Route::get('/user', 'UsersController@index'); + +Routes defined in the `routes/api.php` file are nested within a route group by the `RouteServiceProvider`. Within this group, the `/api` URI prefix is automatically applied so you do not need to manually apply it to every route in the file. You may modify the prefix and other route group options by modifying your `RouteServiceProvider` class. #### Available Router Methods @@ -80,7 +84,7 @@ You may define as many route parameters as required by your route: // }); -Route parameters are always encased within `{}` braces and should consist of alphabetic characters. Route parameters may not contain a `-` character. Use an underscore (`_`) instead. +Route parameters are always encased within `{}` braces and should consist of alphabetic characters, and may not contain a `-` character. Instead of using the `-` character, use an underscore (`_`) instead. Route parameters are injected into route callbacks / controllers based on their order - the names of the callback / controller arguments do not matter. ### Optional Parameters @@ -166,6 +170,26 @@ If the named route defines parameters, you may pass the parameters as the second $url = route('profile', ['id' => 1]); +#### Inspecting The Current Route + +If you would like to determine if the current request was routed to a given named route, you may use the `named` method on a Route instance. For example, you may check the current route name from a route middleware: + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle($request, Closure $next) + { + if ($request->route()->named('profile')) { + // + } + + return $next($request); + } + ## Route Groups @@ -174,24 +198,24 @@ Route groups allow you to share route attributes, such as middleware or namespac ### Middleware -To assign middleware to all routes within a group, you may use the `middleware` key in the group attribute array. Middleware are executed in the order they are listed in the array: +To assign middleware to all routes within a group, you may use the `middleware` method before defining the group. Middleware are executed in the order they are listed in the array: - Route::group(['middleware' => 'auth'], function () { - Route::get('/', function () { - // Uses Auth Middleware + Route::middleware(['first', 'second'])->group(function () { + Route::get('/', function () { + // Uses first & second Middleware }); Route::get('user/profile', function () { - // Uses Auth Middleware + // Uses first & second Middleware }); }); ### Namespaces -Another common use-case for route groups is assigning the same PHP namespace to a group of controllers using the `namespace` parameter in the group array: +Another common use-case for route groups is assigning the same PHP namespace to a group of controllers using the `namespace` method: - Route::group(['namespace' => 'Admin'], function () { + Route::namespace('Admin')->group(function () { // Controllers Within The "App\Http\Controllers\Admin" Namespace }); @@ -200,9 +224,9 @@ Remember, by default, the `RouteServiceProvider` includes your route files withi ### Sub-Domain Routing -Route groups may also be used to handle sub-domain routing. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the `domain` key on the group attribute array: +Route groups may also be used to handle sub-domain routing. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified by calling the the `domain` method before defining the group: - Route::group(['domain' => '{account}.myapp.com'], function () { + Route::domain('{account}.myapp.com')->group(function () { Route::get('user/{id}', function ($account, $id) { // }); @@ -211,10 +235,10 @@ Route groups may also be used to handle sub-domain routing. Sub-domains may be a ### Route Prefixes -The `prefix` group attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with `admin`: +The `prefix` method may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with `admin`: - Route::group(['prefix' => 'admin'], function () { - Route::get('users', function () { + Route::prefix('admin')->group(function () { + Route::get('users', function () { // Matches The "/admin/users" URL }); }); @@ -227,13 +251,13 @@ When injecting a model ID to a route or controller action, you will often query ### Implicit Binding -Laravel automatically resolves Eloquent models defined in routes or controller actions whose variable names match a route segment name. For example: +Laravel automatically resolves Eloquent models defined in routes or controller actions whose type-hinted variable names match a route segment name. For example: Route::get('api/users/{user}', function (App\User $user) { return $user->email; }); -In this example, since the Eloquent `$user` variable defined on the route matches the `{user}` segment in the route's URI, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated. +Since the `$user` variable is type-hinted as the `App\User` Eloquent model and the variable name matches the `{user}` URI segment, Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated. #### Customizing The Key Name diff --git a/scheduling.md b/scheduling.md old mode 100644 new mode 100755 index f280078..acae54d --- a/scheduling.md +++ b/scheduling.md @@ -19,7 +19,7 @@ Laravel's command scheduler allows you to fluently and expressively define your When using the scheduler, you only need to add the following Cron entry to your server. If you do not know how to add Cron entries to your server, consider using a service such as [Laravel Forge](https://forge.laravel.com) which can manage the Cron entries for you: - * * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1 + * * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1 This Cron will call the Laravel command scheduler every minute. When the `schedule:run` command is executed, Laravel will evaluate your scheduled tasks and runs the tasks that are due. diff --git a/scout.md b/scout.md old mode 100644 new mode 100755 index 915a1ed..424b6af --- a/scout.md +++ b/scout.md @@ -235,6 +235,16 @@ Since Scout searches return a collection of Eloquent models, you may even return return App\Order::search($request->search)->get(); }); +If you would like to get the raw results before they are converted to Eloquent models, you should use the `raw` method: + + $orders = App\Order::search('Star Trek')->raw(); + +Search queries will typically be performed on the index specified by the model's [`searchableAs`](#configuring-model-indexes) method. However, you may use the `within` method to specify a custom index that should be searched instead: + + $orders = App\Order::search('Star Trek') + ->within('tv_shows_popularity_desc') + ->get(); + ### Where Clauses diff --git a/seeding.md b/seeding.md old mode 100644 new mode 100755 diff --git a/session.md b/session.md old mode 100644 new mode 100755 index 346c2d7..0bc0f10 --- a/session.md +++ b/session.md @@ -44,7 +44,7 @@ When using the `database` session driver, you will need to create a table to con Schema::create('sessions', function ($table) { $table->string('id')->unique(); - $table->integer('user_id')->nullable(); + $table->unsignedInteger('user_id')->nullable(); $table->string('ip_address', 45)->nullable(); $table->text('user_agent')->nullable(); $table->text('payload'); diff --git a/structure.md b/structure.md old mode 100644 new mode 100755 index f9952c8..d15d147 --- a/structure.md +++ b/structure.md @@ -71,7 +71,7 @@ The `resources` directory contains your views as well as your raw, un-compiled a #### The Routes Directory -The `routes` directory contains all of the route definitions for your application. By default, three route files are included with Laravel: `web.php`, `api.php`, and `console.php`. +The `routes` directory contains all of the route definitions for your application. By default, several route files are included with Laravel: `web.php`, `api.php`, `console.php` and `channels.php`. The `web.php` file contains routes that the `RouteServiceProvider` places in the `web` middleware group, which provides session state, CSRF protection, and cookie encryption. If your application does not offer a stateless, RESTful API, all of your routes will most likely be defined in the `web.php` file. @@ -79,6 +79,8 @@ The `api.php` file contains routes that the `RouteServiceProvider` places in the The `console.php` file is where you may define all of your Closure based console commands. Each Closure is bound to a command instance allowing a simple approach to interacting with each command's IO methods. Even though this file does not define HTTP routes, it defines console based entry points (routes) into your application. +The `channels.php` file is where you may register all of the event broadcasting channels that your application supports. + #### The Storage Directory diff --git a/testing.md b/testing.md old mode 100644 new mode 100755 index 7a6abc4..b99508b --- a/testing.md +++ b/testing.md @@ -54,4 +54,4 @@ Once the test has been generated, you may define test methods as you normally wo } } -> {note} If you define your own `setUp` method within a test class, be sure to call `parent::setUp`. +> {note} If you define your own `setUp` method within a test class, be sure to call `parent::setUp()`. diff --git a/upgrade.md b/upgrade.md old mode 100644 new mode 100755 index f8dd13a..36f337c --- a/upgrade.md +++ b/upgrade.md @@ -11,7 +11,11 @@ ### Updating Dependencies -Update your `laravel/framework` dependency to `5.4.*` in your `composer.json` file. In addition, you should update your `phpunit/phpunit` dependency to `~5.0`. +Update your `laravel/framework` dependency to `5.4.*` in your `composer.json` file. In addition, you should update your `phpunit/phpunit` dependency to `~5.7`. + +#### Removing Compiled Services File + +If it exists, you may delete the `bootstrap/cache/compiled.php` file. It is no longer used by the framework. #### Flushing The Cache @@ -77,7 +81,7 @@ If you would like to render unescaped content in a section, you must declare the ### Bootstrappers -If you are manually overriding the `$bootstrappers` array on your HTTP or Console kernel, you should rename the `DetectEnvironment` entry to `LoadEnvironmentVariables`. +If you are manually overriding the `$bootstrappers` array on your HTTP or Console kernel, you should rename the `DetectEnvironment` entry to `LoadEnvironmentVariables` and remove `ConfigureLogging`. ### Broadcasting @@ -101,6 +105,18 @@ Calling `$collection->random(1)` will now return a new collection instance with ### Container +#### Aliasing Via `bind` / `instance` + +In previous Laravel releases, you could pass an array as the first parameter to the `bind` or `instance` methods to register an alias: + + $container->bind(['foo' => FooContract::class], function () { + return 'foo'; + }); + +However, this behavior has been removed in Laravel 5.4. To register an alias, you should now use the `alias` method: + + $container->alias(FooContract::class, 'foo'); + #### Binding Classes With Leading Slashes Binding classes into the container with leading slashes is no longer supported. This feature required a significant amount of string formatting calls to be made within the container. Instead, simply register your bindings without a leading slash: @@ -157,7 +173,7 @@ If you were previously binding a service container binding for a `db.connection. #### Fetch Mode -Laravel no longer includes the ability to customize the PDO "fetch mode" from your configuration files. Instead, `PDO::FETCH_OBJ` is always used. If you will still like to customize the fetch mode for your application you may listen for the new `Illuminate\Database\Events\StatementPrepared` event: +Laravel no longer includes the ability to customize the PDO "fetch mode" from your configuration files. Instead, `PDO::FETCH_OBJ` is always used. If you would still like to customize the fetch mode for your application you may listen for the new `Illuminate\Database\Events\StatementPrepared` event: Event::listen(StatementPrepared::class, function ($event) { $event->statement->setFetchMode(...); @@ -187,6 +203,10 @@ Just like previous Laravel releases, this relationship will typically use `user_ When this is the case, Laravel will now respect your customization and determine the foreign key column name is `user_key` instead of `user_id`. +#### BelongsToMany `setJoin` + +The `setJoin` method has been renamed to `performJoin`. + #### Has One / Many `createMany` The `createMany` method of a `hasOne` or `hasMany` relationship now returns a collection object instead of an array. @@ -199,6 +219,31 @@ Related models will now use the same connection as the parent model. For example Eloquent will query the posts table on the `example` connection instead of the default database connection. If you want to read the `posts` relationship from the default connection, you should to explicitly set the model's connection to your application's default connection. +#### The `chunk` Method + +The query builder `chunk` method now requires an `orderBy` clause, which provides consistency with the `each` method. An exception will be thrown if an `orderBy` clause is not supplied. For example: + + DB::table('users')->orderBy('id')->chunk(100, function ($users) { + foreach ($users as $user) { + // + } + }); + +The Eloquent query builder `chunk` method will automatically apply an `orderBy` clause on the model's primary key if one is not supplied. + +#### The `create` & `forceCreate` Methods + +The `Model::create` & `Model::forceCreate` methods have been moved to the `Illuminate\Database\Eloquent\Builder` class in order to provide better support for creating models on multiple connections. However, if you are extending these methods in your own models, you will need to modify your implementation to call the `create` method on the builder. For example: + + public static function create(array $attributes = []) + { + $model = static::query()->create($attributes); + + // ... + + return $model; + } + #### The `hydrate` Method If you are currently passing a custom connection name to this method, you should now use the `on` method: @@ -211,7 +256,7 @@ The `Model::hydrateRaw` method has been renamed to `fromQuery`. If you are passi User::on('connection')->fromQuery('...'); -#### The `whereKey` method +#### The `whereKey` Method The `whereKey($id)` method will now add a "where" clause for the given primary key value. Previously, this would fall into the dynamic "where" clause builder and add a "where" clause for the "key" column. If you used the `whereKey` method to dynamically add a condition for the `key` column you should now use `where('key', ...)` instead. @@ -316,10 +361,16 @@ The class `Illuminate\Foundation\Http\Middleware\VerifyPostSize` has been rename The `middleware` method of the `Illuminate\Routing\Router` class has been renamed to `aliasMiddleware()`. It is likely that most applications never call this method manually, as it is typically only called by the HTTP kernel to register route-level middleware defined in the `$routeMiddleware` array. -#### The `getParameter` Method +#### `Route` Methods + +The `getUri` method of the `Illuminate\Routing\Route` class has been removed. You should use the `uri` method instead. + +The `getMethods` method of the `Illuminate\Routing\Route` class has been removed. You should use the `methods` method instead. The `getParameter` method of the `Illuminate\Routing\Route` class has been removed. You should use the `parameter` method instead. +The `getPath` method of the `Illuminate\Routing\Route` class has been removed. You should use the `uri` method instead. + ### Sessions #### Symfony Compatibility @@ -336,27 +387,35 @@ All calls to the `$request->setSession()` method should be changed to `setLarave Laravel 5.4's testing layer has been re-written to be simpler and lighter out of the box. If you would like to continue using the testing layer present in Laravel 5.3, you may install the `laravel/browser-kit-testing` [package](https://github.com/laravel/browser-kit-testing) into your application. This package provides full compatibility with the Laravel 5.3 testing layer. In fact, you can run the Laravel 5.4 testing layer side-by-side with the Laravel 5.3 testing layer. -If you have tests written using Laravel 5.3 and would like to run them side-by-side with Laravel's new testing layer, install the `laravel/browser-kit-testing` package: +In order to allow Laravel to autoload any new tests you generate using the Laravel 5.4 test generators, you should add the `Tests` namespace to your `composer.json` file's `autoload-dev` block: + + "psr-4": { + "Tests\\": "tests/" + } + +#### Running Laravel 5.3 & 5.4 Tests In A Single Application + +First install the `laravel/browser-kit-testing` package: - composer require laravel/browser-kit-testing + composer require laravel/browser-kit-testing="1.*" --dev -Next, create a copy of your `tests/TestCase.php` file and save it to your `tests` directory as `BrowserKitTest.php`. Then, modify the file to extend the `Laravel\BrowserKitTesting\TestCase` class. Once you have done this, you should have two base test classes in your `tests` directory: `TestCase.php` and `BrowserKitTest.php`. In order for your `BrowserKitTest` class to be properly loaded, you may need to add it to your `composer.json` file: +Once the package has been installed, create a copy of your `tests/TestCase.php` file and save it to your `tests` directory as `BrowserKitTestCase.php`. Then, modify the file to extend the `Laravel\BrowserKitTesting\TestCase` class. Once you have done this, you should have two base test classes in your `tests` directory: `TestCase.php` and `BrowserKitTestCase.php`. In order for your `BrowserKitTestCase` class to be properly loaded, you may need to add it to your `composer.json` file: "autoload-dev": { "classmap": [ "tests/TestCase.php", - "tests/BrowserKitTest.php" + "tests/BrowserKitTestCase.php" ] }, -Tests written on Laravel 5.3 will extend the `BrowserKitTest` class while any new tests that use the Laravel 5.4 testing layer will extend the `TestCase` class. Your `BrowserKitTest` class should look like the following: +Tests written on Laravel 5.3 will extend the `BrowserKitTestCase` class while any new tests that use the Laravel 5.4 testing layer will extend the `TestCase` class. Your `BrowserKitTestCase` class should look like the following: {note} If you are writing new tests and want them to use the Laravel 5.4 testing layer, make sure to extend the `TestCase` class. @@ -423,7 +482,7 @@ The Laravel 5.4 test class no longer manually forces `putenv('APP_ENV=testing')` #### Event Fake -The `Event` fake's `assertFired` method should be updated to `assertDispatched`. The method signature has not been changed. +The `Event` fake's `assertFired` method should be updated to `assertDispatched`, and the `assertNotFired` method should be updated to `assertNotDispatched`. The method's signatures have not been changed. #### Mail Fake diff --git a/valet.md b/valet.md old mode 100644 new mode 100755 index 73d9741..82b28eb --- a/valet.md +++ b/valet.md @@ -10,6 +10,7 @@ - [Securing Sites With TLS](#securing-sites) - [Sharing Sites](#sharing-sites) - [Custom Valet Drivers](#custom-valet-drivers) + - [Local Drivers](#local-drivers) - [Other Valet Commands](#other-valet-commands) @@ -26,15 +27,16 @@ Out of the box, Valet support includes, but is not limited to:
- [Laravel](https://laravel.com) - [Lumen](https://lumen.laravel.com) -- [Symfony](https://symfony.com) -- [Zend](https://framework.zend.com) -- [CakePHP 3](https://cakephp.org) -- [WordPress](https://wordpress.org) - [Bedrock](https://roots.io/bedrock/) +- [CakePHP 3](https://cakephp.org) - [Craft](https://craftcms.com) -- [Statamic](https://statamic.com) - [Jigsaw](http://jigsaw.tighten.co) +- [Slim](https://www.slimframework.com) +- [Statamic](https://statamic.com) - Static HTML +- [Symfony](https://symfony.com) +- [WordPress](https://wordpress.org) +- [Zend](https://framework.zend.com)
However, you may extend Valet with your own [custom drivers](#custom-valet-drivers). @@ -219,6 +221,40 @@ The `frontControllerPath` method should return the fully qualified path to your return $sitePath.'/public/index.php'; } + +### Local Drivers + +If you would like to define a custom Valet driver for a single application, create a `LocalValetDriver.php` in the application's root directory. Your custom driver may extend the base `ValetDriver` class or extend an existing application specific driver such as the `LaravelValetDriver`: + + class LocalValetDriver extends LaravelValetDriver + { + /** + * Determine if the driver serves the request. + * + * @param string $sitePath + * @param string $siteName + * @param string $uri + * @return bool + */ + public function serves($sitePath, $siteName, $uri) + { + return true; + } + + /** + * Get the fully resolved path to the application's front controller. + * + * @param string $sitePath + * @param string $siteName + * @param string $uri + * @return string + */ + public function frontControllerPath($sitePath, $siteName, $uri) + { + return $sitePath.'/public_html/index.php'; + } + } + ## Other Valet Commands diff --git a/validation.md b/validation.md old mode 100644 new mode 100755 index d4fd973..e7a7283 --- a/validation.md +++ b/validation.md @@ -6,6 +6,7 @@ - [Creating The Controller](#quick-creating-the-controller) - [Writing The Validation Logic](#quick-writing-the-validation-logic) - [Displaying The Validation Errors](#quick-displaying-the-validation-errors) + - [A Note On Optional Fields](#a-note-on-optional-fields) - [Form Request Validation](#form-request-validation) - [Creating Form Requests](#creating-form-requests) - [Authorizing Form Requests](#authorizing-form-requests) @@ -142,7 +143,7 @@ So, in our example, the user will be redirected to our controller's `create` met

Create Post

- @if (count($errors) > 0) + @if ($errors->any())