diff --git a/artisan.md b/artisan.md
index 768c94ec296..683c4b023cd 100644
--- a/artisan.md
+++ b/artisan.md
@@ -43,7 +43,7 @@ php artisan help migrate
If you are using [Laravel Sail](/docs/{{version}}/sail) as your local development environment, remember to use the `sail` command line to invoke Artisan commands. Sail will execute your Artisan commands within your application's Docker containers:
```shell
-./sail artisan list
+./vendor/bin/sail artisan list
```
@@ -60,7 +60,8 @@ All Laravel applications include Tinker by default. However, you may install Tin
composer require laravel/tinker
```
-> {tip} Looking for a graphical UI for interacting with your Laravel application? Check out [Tinkerwell](https://tinkerwell.app)!
+> **Note**
+> Looking for a graphical UI for interacting with your Laravel application? Check out [Tinkerwell](https://tinkerwell.app)!
#### Usage
@@ -77,7 +78,8 @@ You can publish Tinker's configuration file using the `vendor:publish` command:
php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"
```
-> {note} The `dispatch` helper function and `dispatch` method on the `Dispatchable` class depends on garbage collection to place the job on the queue. Therefore, when using tinker, you should use `Bus::dispatch` or `Queue::push` to dispatch jobs.
+> **Warning**
+> The `dispatch` helper function and `dispatch` method on the `Dispatchable` class depends on garbage collection to place the job on the queue. Therefore, when using tinker, you should use `Bus::dispatch` or `Queue::push` to dispatch jobs.
#### Command Allow List
@@ -154,7 +156,8 @@ Let's take a look at an example command. Note that we are able to request any de
}
}
-> {tip} For greater code reuse, it is good practice to keep your console commands light and let them defer to application services to accomplish their tasks. In the example above, note that we inject a service class to do the "heavy lifting" of sending the e-mails.
+> **Note**
+> For greater code reuse, it is good practice to keep your console commands light and let them defer to application services to accomplish their tasks. In the example above, note that we inject a service class to do the "heavy lifting" of sending the e-mails.
### Closure Commands
@@ -285,10 +288,10 @@ If you would like to define arguments or options to expect multiple input values
'mail:send {user*}'
-When calling this method, the `user` arguments may be passed in order to the command line. For example, the following command will set the value of `user` to an array with `foo` and `bar` as its values:
+When calling this method, the `user` arguments may be passed in order to the command line. For example, the following command will set the value of `user` to an array with `1` and `2` as its values:
```shell
-php artisan mail:send foo bar
+php artisan mail:send 1 2
```
This `*` character can be combined with an optional argument definition to allow zero or more instances of an argument:
@@ -300,7 +303,7 @@ This `*` character can be combined with an optional argument definition to allow
When defining an option that expects multiple input values, each option value passed to the command should be prefixed with the option name:
- 'mail:send {user} {--id=*}'
+ 'mail:send {--id=*}'
Such a command may be invoked by passing multiple `--id` arguments:
@@ -495,7 +498,8 @@ Sometimes, you may need more manual control over how a progress bar is advanced.
$bar->finish();
-> {tip} For more advanced options, check out the [Symfony Progress Bar component documentation](https://symfony.com/doc/current/components/console/helpers/progressbar.html).
+> **Note**
+> For more advanced options, check out the [Symfony Progress Bar component documentation](https://symfony.com/doc/current/components/console/helpers/progressbar.html).
## Registering Commands
diff --git a/authentication.md b/authentication.md
index cc71a308214..25581e0c034 100644
--- a/authentication.md
+++ b/authentication.md
@@ -39,7 +39,8 @@ Providers define how users are retrieved from your persistent storage. Laravel s
Your application's authentication configuration file is located at `config/auth.php`. This file contains several well-documented options for tweaking the behavior of Laravel's authentication services.
-> {tip} Guards and providers should not be confused with "roles" and "permissions". To learn more about authorizing user actions via permissions, please refer to the [authorization](/docs/{{version}}/authorization) documentation.
+> **Note**
+> Guards and providers should not be confused with "roles" and "permissions". To learn more about authorizing user actions via permissions, please refer to the [authorization](/docs/{{version}}/authorization) documentation.
### Starter Kits
@@ -79,7 +80,7 @@ _Laravel Breeze_ is a simple, minimal implementation of all of Laravel's authent
_Laravel Fortify_ is a headless authentication backend for Laravel that implements many of the features found in this documentation, including cookie-based authentication as well as other features such as two-factor authentication and email verification. Fortify provides the authentication backend for Laravel Jetstream or may be used independently in combination with [Laravel Sanctum](/docs/{{version}}/sanctum) to provide authentication for an SPA that needs to authenticate with Laravel.
-_[Laravel Jetstream](https://jetstream.laravel.com)_ is a robust application starter kit that consumes and exposes Laravel Fortify's authentication services with a beautiful, modern UI powered by [Tailwind CSS](https://tailwindcss.com), [Livewire](https://laravel-livewire.com), and / or [Inertia.js](https://inertiajs.com). Laravel Jetstream includes optional support for two-factor authentication, team support, browser session management, profile management, and built-in integration with [Laravel Sanctum](/docs/{{version}}/sanctum) to offer API token authentication. Laravel's API authentication offerings are discussed below.
+_[Laravel Jetstream](https://jetstream.laravel.com)_ is a robust application starter kit that consumes and exposes Laravel Fortify's authentication services with a beautiful, modern UI powered by [Tailwind CSS](https://tailwindcss.com), [Livewire](https://laravel-livewire.com), and / or [Inertia](https://inertiajs.com). Laravel Jetstream includes optional support for two-factor authentication, team support, browser session management, profile management, and built-in integration with [Laravel Sanctum](/docs/{{version}}/sanctum) to offer API token authentication. Laravel's API authentication offerings are discussed below.
#### Laravel's API Authentication Services
@@ -109,12 +110,13 @@ If you are building a single-page application (SPA) that will be powered by a La
Passport may be chosen when your application absolutely needs all of the features provided by the OAuth2 specification.
-And, if you would like to get started quickly, we are pleased to recommend [Laravel Jetstream](https://jetstream.laravel.com) as a quick way to start a new Laravel application that already uses our preferred authentication stack of Laravel's built-in authentication services and Laravel Sanctum.
+And, if you would like to get started quickly, we are pleased to recommend [Laravel Breeze](/docs/{{version}}/starter-kits#laravel-breeze) as a quick way to start a new Laravel application that already uses our preferred authentication stack of Laravel's built-in authentication services and Laravel Sanctum.
## Authentication Quickstart
-> {note} This portion of the documentation discusses authenticating users via the [Laravel application starter kits](/docs/{{version}}/starter-kits), which includes UI scaffolding to help you get started quickly. If you would like to integrate with Laravel's authentication systems directly, check out the documentation on [manually authenticating users](#authenticating-users).
+> **Warning**
+> This portion of the documentation discusses authenticating users via the [Laravel application starter kits](/docs/{{version}}/starter-kits), which includes UI scaffolding to help you get started quickly. If you would like to integrate with Laravel's authentication systems directly, check out the documentation on [manually authenticating users](#authenticating-users).
### Install A Starter Kit
@@ -123,7 +125,7 @@ First, you should [install a Laravel application starter kit](/docs/{{version}}/
Laravel Breeze is a minimal, simple implementation of all of Laravel's authentication features, including login, registration, password reset, email verification, and password confirmation. Laravel Breeze's view layer is made up of simple [Blade templates](/docs/{{version}}/blade) styled with [Tailwind CSS](https://tailwindcss.com). Breeze also offers an [Inertia](https://inertiajs.com) based scaffolding option using Vue or React.
-[Laravel Jetstream](https://jetstream.laravel.com) is a more robust application starter kit that includes support for scaffolding your application with [Livewire](https://laravel-livewire.com) or [Inertia.js and Vue](https://inertiajs.com). In addition, Jetstream features optional support for two-factor authentication, teams, profile management, browser session management, API support via [Laravel Sanctum](/docs/{{version}}/sanctum), account deletion, and more.
+[Laravel Jetstream](https://jetstream.laravel.com) is a more robust application starter kit that includes support for scaffolding your application with [Livewire](https://laravel-livewire.com) or [Inertia and Vue](https://inertiajs.com). In addition, Jetstream features optional support for two-factor authentication, teams, profile management, browser session management, API support via [Laravel Sanctum](/docs/{{version}}/sanctum), account deletion, and more.
### Retrieving The Authenticated User
@@ -171,7 +173,8 @@ To determine if the user making the incoming HTTP request is authenticated, you
// The user is logged in...
}
-> {tip} Even though it is possible to determine if a user is authenticated using the `check` method, you will typically use a middleware to verify that the user is authenticated before allowing the user access to certain routes / controllers. To learn more about this, check out the documentation on [protecting routes](/docs/{{version}}/authentication#protecting-routes).
+> **Note**
+> Even though it is possible to determine if a user is authenticated using the `check` method, you will typically use a middleware to verify that the user is authenticated before allowing the user access to certain routes / controllers. To learn more about this, check out the documentation on [protecting routes](/docs/{{version}}/authentication#protecting-routes).
### Protecting Routes
@@ -212,7 +215,8 @@ When attaching the `auth` middleware to a route, you may also specify which "gua
If you are using the Laravel Breeze or Laravel Jetstream [starter kits](/docs/{{version}}/starter-kits), rate limiting will automatically be applied to login attempts. By default, the user will not be able to login for one minute if they fail to provide the correct credentials after several attempts. The throttling is unique to the user's username / email address and their IP address.
-> {tip} If you would like to rate limit other routes in your application, check out the [rate limiting documentation](/docs/{{version}}/routing#rate-limiting).
+> **Note**
+> If you would like to rate limit other routes in your application, check out the [rate limiting documentation](/docs/{{version}}/routing#rate-limiting).
## Manually Authenticating Users
@@ -272,7 +276,19 @@ If you wish, you may also add extra query conditions to the authentication query
// Authentication was successful...
}
-> {note} In these examples, `email` is not a required option, it is merely used as an example. You should use whatever column name corresponds to a "username" in your database table.
+> **Warning**
+> In these examples, `email` is not a required option, it is merely used as an example. You should use whatever column name corresponds to a "username" in your database table.
+
+The `attemptWhen` method, which receives a closure as its second argument, may be used to perform more extensive inspection of the potential user before actually authenticating the user. The closure receives the potential user and should return `true` or `false` to indicate if the user may be authenticated:
+
+ if (Auth::attemptWhen([
+ 'email' => $email,
+ 'password' => $password,
+ ], function ($user) {
+ return $user->isNotBanned();
+ })) {
+ // Authentication was successful...
+ }
#### Accessing Specific Guard Instances
@@ -453,7 +469,8 @@ When the `logoutOtherDevices` method is invoked, the user's other sessions will
While building your application, you may occasionally have actions that should require the user to confirm their password before the action is performed or before the user is redirected to a sensitive area of the application. Laravel includes built-in middleware to make this process a breeze. Implementing this feature will require you to define two routes: one route to display a view asking the user to confirm their password and another route to confirm that the password is valid and redirect the user to their intended destination.
-> {tip} The following documentation discusses how to integrate with Laravel's password confirmation features directly; however, if you would like to get started more quickly, the [Laravel application starter kits](/docs/{{version}}/starter-kits) include support for this feature!
+> **Note**
+> The following documentation discusses how to integrate with Laravel's password confirmation features directly; however, if you would like to get started more quickly, the [Laravel application starter kits](/docs/{{version}}/starter-kits) include support for this feature!
### Configuration
diff --git a/authorization.md b/authorization.md
index 67c80938e67..3175bcd6bd3 100644
--- a/authorization.md
+++ b/authorization.md
@@ -38,7 +38,8 @@ You do not need to choose between exclusively using gates or exclusively using p
### Writing Gates
-> {note} Gates are a great way to learn the basics of Laravel's authorization features; however, when building robust Laravel applications you should consider using [policies](#creating-policies) to organize your authorization rules.
+> **Warning**
+> Gates are a great way to learn the basics of Laravel's authorization features; however, when building robust Laravel applications you should consider using [policies](#creating-policies) to organize your authorization rules.
Gates are simply closures that determine if a user is authorized to perform a given action. Typically, gates are defined within the `boot` method of the `App\Providers\AuthServiceProvider` class using the `Gate` facade. Gates always receive a user instance as their first argument and may optionally receive additional arguments such as a relevant Eloquent model.
@@ -195,6 +196,33 @@ When using the `Gate::authorize` method, which throws an `AuthorizationException
// The action is authorized...
+
+#### Customizing The HTTP Response Status
+
+When an action is denied via a Gate, a `403` HTTP response is returned; however, it can sometimes be useful to return an alternative HTTP status code. You may customize the HTTP status code returned for a failed authorization check using the `denyWithStatus` static constructor on the `Illuminate\Auth\Access\Response` class:
+
+ use App\Models\User;
+ use Illuminate\Auth\Access\Response;
+ use Illuminate\Support\Facades\Gate;
+
+ Gate::define('edit-settings', function (User $user) {
+ return $user->isAdmin
+ ? Response::allow()
+ : Response::denyWithStatus(404);
+ });
+
+Because hiding resources via a `404` response is such a common pattern for web applications, the `denyAsNotFound` method is offered for convenience:
+
+ use App\Models\User;
+ use Illuminate\Auth\Access\Response;
+ use Illuminate\Support\Facades\Gate;
+
+ Gate::define('edit-settings', function (User $user) {
+ return $user->isAdmin
+ ? Response::allow()
+ : Response::denyAsNotFound();
+ });
+
### Intercepting Gate Checks
@@ -233,7 +261,7 @@ Gate::allowIf(fn ($user) => $user->isAdministrator());
Gate::denyIf(fn ($user) => $user->banned());
```
-If the action is not authorized or if no user is currently authenticated, Laravel will automatically throw an `Illuminate\Auth\Access\AuthorizationException` exception. Instances of `AuthorizationException` are automatically converted to a 403 HTTP response by Laravel's exception handler:
+If the action is not authorized or if no user is currently authenticated, Laravel will automatically throw an `Illuminate\Auth\Access\AuthorizationException` exception. Instances of `AuthorizationException` are automatically converted to a 403 HTTP response by Laravel's exception handler.
## Creating Policies
@@ -308,7 +336,8 @@ If you would like to define your own policy discovery logic, you may register a
// Return the name of the policy class for the given model...
});
-> {note} Any policies that are explicitly mapped in your `AuthServiceProvider` will take precedence over any potentially auto-discovered policies.
+> **Warning**
+> Any policies that are explicitly mapped in your `AuthServiceProvider` will take precedence over any potentially auto-discovered policies.
## Writing Policies
@@ -346,7 +375,8 @@ You may continue to define additional methods on the policy as needed for the va
If you used the `--model` option when generating your policy via the Artisan console, it will already contain methods for the `viewAny`, `view`, `create`, `update`, `delete`, `restore`, and `forceDelete` actions.
-> {tip} All policies are resolved via the Laravel [service container](/docs/{{version}}/container), allowing you to type-hint any needed dependencies in the policy's constructor to have them automatically injected.
+> **Note**
+> All policies are resolved via the Laravel [service container](/docs/{{version}}/container), allowing you to type-hint any needed dependencies in the policy's constructor to have them automatically injected.
### Policy Responses
@@ -389,6 +419,49 @@ When using the `Gate::authorize` method, which throws an `AuthorizationException
// The action is authorized...
+
+#### Customizing The HTTP Response Status
+
+When an action is denied via a policy method, a `403` HTTP response is returned; however, it can sometimes be useful to return an alternative HTTP status code. You may customize the HTTP status code returned for a failed authorization check using the `denyWithStatus` static constructor on the `Illuminate\Auth\Access\Response` class:
+
+ use App\Models\Post;
+ use App\Models\User;
+ use Illuminate\Auth\Access\Response;
+
+ /**
+ * Determine if the given post can be updated by the user.
+ *
+ * @param \App\Models\User $user
+ * @param \App\Models\Post $post
+ * @return \Illuminate\Auth\Access\Response
+ */
+ public function update(User $user, Post $post)
+ {
+ return $user->id === $post->user_id
+ ? Response::allow()
+ : Response::denyWithStatus(404);
+ }
+
+Because hiding resources via a `404` response is such a common pattern for web applications, the `denyAsNotFound` method is offered for convenience:
+
+ use App\Models\Post;
+ use App\Models\User;
+ use Illuminate\Auth\Access\Response;
+
+ /**
+ * Determine if the given post can be updated by the user.
+ *
+ * @param \App\Models\User $user
+ * @param \App\Models\Post $post
+ * @return \Illuminate\Auth\Access\Response
+ */
+ public function update(User $user, Post $post)
+ {
+ return $user->id === $post->user_id
+ ? Response::allow()
+ : Response::denyAsNotFound();
+ }
+
### Methods Without Models
@@ -455,7 +528,8 @@ For certain users, you may wish to authorize all actions within a given policy.
If you would like to deny all authorization checks for a particular type of user then you may return `false` from the `before` method. If `null` is returned, the authorization check will fall through to the policy method.
-> {note} The `before` method of a policy class will not be called if the class doesn't contain a method with a name matching the name of the ability being checked.
+> **Warning**
+> The `before` method of a policy class will not be called if the class doesn't contain a method with a name matching the name of the ability being checked.
## Authorizing Actions Using Policies
@@ -622,7 +696,8 @@ The following controller methods will be mapped to their corresponding policy me
| update | update |
| destroy | delete |
-> {tip} You may use the `make:policy` command with the `--model` option to quickly generate a policy class for a given model: `php artisan make:policy PostPolicy --model=Post`.
+> **Note**
+> You may use the `make:policy` command with the `--model` option to quickly generate a policy class for a given model: `php artisan make:policy PostPolicy --model=Post`.
### Via Middleware
diff --git a/billing.md b/billing.md
index d3662815dfa..ea147eadeee 100644
--- a/billing.md
+++ b/billing.md
@@ -31,7 +31,7 @@
- [Checking Subscription Status](#checking-subscription-status)
- [Changing Prices](#changing-prices)
- [Subscription Quantity](#subscription-quantity)
- - [Multiprice Subscriptions](#multiprice-subscriptions)
+ - [Subscriptions With Multiple Products](#subscriptions-with-multiple-products)
- [Metered Billing](#metered-billing)
- [Subscription Taxes](#subscription-taxes)
- [Subscription Anchor Date](#subscription-anchor-date)
@@ -76,7 +76,8 @@
When upgrading to a new version of Cashier, it's important that you carefully review [the upgrade guide](https://github.com/laravel/cashier-stripe/blob/master/UPGRADE.md).
-> {note} To prevent breaking changes, Cashier uses a fixed Stripe API version. Cashier 13 utilizes Stripe API version `2020-08-27`. The Stripe API version will be updated on minor releases in order to make use of new Stripe features and improvements.
+> **Warning**
+> To prevent breaking changes, Cashier uses a fixed Stripe API version. Cashier 14 utilizes Stripe API version `2022-08-01`. The Stripe API version will be updated on minor releases in order to make use of new Stripe features and improvements.
## Installation
@@ -87,7 +88,8 @@ First, install the Cashier package for Stripe using the Composer package manager
composer require laravel/cashier
```
-> {note} To ensure Cashier properly handles all Stripe events, remember to [set up Cashier's webhook handling](#handling-stripe-webhooks).
+> **Warning**
+> To ensure Cashier properly handles all Stripe events, remember to [set up Cashier's webhook handling](#handling-stripe-webhooks).
### Database Migrations
@@ -118,7 +120,8 @@ If you would like to prevent Cashier's migrations from running entirely, you may
Cashier::ignoreMigrations();
}
-> {note} Stripe recommends that any column used for storing Stripe identifiers should be case-sensitive. Therefore, you should ensure the column collation for the `stripe_id` column is set to `utf8_bin` when using MySQL. More information regarding this can be found in the [Stripe documentation](https://stripe.com/docs/upgrades#what-changes-does-stripe-consider-to-be-backwards-compatible).
+> **Warning**
+> Stripe recommends that any column used for storing Stripe identifiers should be case-sensitive. Therefore, you should ensure the column collation for the `stripe_id` column is set to `utf8_bin` when using MySQL. More information regarding this can be found in the [Stripe documentation](https://stripe.com/docs/upgrades#what-changes-does-stripe-consider-to-be-backwards-compatible).
## Configuration
@@ -150,7 +153,8 @@ Cashier assumes your billable model will be the `App\Models\User` class that shi
Cashier::useCustomerModel(User::class);
}
-> {note} If you're using a model other than Laravel's supplied `App\Models\User` model, you'll need to publish and alter the [Cashier migrations](#installation) provided to match your alternative model's table name.
+> **Warning**
+> If you're using a model other than Laravel's supplied `App\Models\User` model, you'll need to publish and alter the [Cashier migrations](#installation) provided to match your alternative model's table name.
### API Keys
@@ -163,7 +167,8 @@ STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret
```
-> {note} You should ensure that the `STRIPE_WEBHOOK_SECRET` environment variable is defined in your application's `.env` file, as this variable is used to ensure that incoming webhooks are actually from Stripe.
+> **Warning**
+> You should ensure that the `STRIPE_WEBHOOK_SECRET` environment variable is defined in your application's `.env` file, as this variable is used to ensure that incoming webhooks are actually from Stripe.
### Currency Configuration
@@ -180,7 +185,8 @@ In addition to configuring Cashier's currency, you may also specify a locale to
CASHIER_CURRENCY_LOCALE=nl_BE
```
-> {note} In order to use locales other than `en`, ensure the `ext-intl` PHP extension is installed and configured on your server.
+> **Warning**
+> In order to use locales other than `en`, ensure the `ext-intl` PHP extension is installed and configured on your server.
### Tax Configuration
@@ -203,7 +209,8 @@ Once tax calculation has been enabled, any new subscriptions and any one-off inv
For this feature to work properly, your customer's billing details, such as the customer's name, address, and tax ID, need to be synced to Stripe. You may use the [customer data synchronization](#syncing-customer-data-with-stripe) and [Tax ID](#tax-ids) methods offered by Cashier to accomplish this.
-> {note} Unfortunately, for now, no tax is calculated for [single charges](#single-charges) or [single charge checkouts](#single-charge-checkouts). In addition, Stripe Tax is currently "invite-only" during its beta period. You can request access to Stripe Tax via the [Stripe Tax website](https://stripe.com/tax#request-access).
+> **Warning**
+> Unfortunately, for now, no tax is calculated for [single charges](#single-charges) or [single charge checkouts](#single-charge-checkouts). In addition, Stripe Tax is currently "invite-only" during its beta period. You can request access to Stripe Tax via the [Stripe Tax website](https://stripe.com/tax#request-access).
### Logging
@@ -289,13 +296,13 @@ Stripe allows you to credit or debit a customer's "balance". Later, this balance
$balance = $user->balance();
-To credit a customer's balance, you may provide a negative value to the `applyBalance` method. If you wish, you may also provide a description:
+To credit a customer's balance, you may provide a value to the `creditBalance` method. If you wish, you may also provide a description:
- $user->applyBalance(-500, 'Premium customer top-up.');
+ $user->creditBalance(500, 'Premium customer top-up.');
-Providing a positive value to the `applyBalance` method will debit the customer's balance:
+Providing a value to the `debitBalance` method will debit the customer's balance:
- $user->applyBalance(300, 'Bad usage penalty.');
+ $user->debitBalance(300, 'Bad usage penalty.');
The `applyBalance` method will create new customer balance transactions for the customer. You may retrieve these transaction records using the `balanceTransactions` method, which may be useful in order to provide a log of credits and debits for the customer to review:
@@ -368,7 +375,7 @@ You may customize the columns used for syncing customer information to Stripe by
return $this->company_name;
}
-Similarly, you may override the `stripeEmail`, `stripePhone`, and `stripeAddress` methods. These methods will sync information to their corresponding customer parameters when [updating the Stripe customer object](https://stripe.com/docs/api/customers/update). If you wish to take total control over the customer information sync process, you may override the `syncStripeCustomerDetails` method.
+Similarly, you may override the `stripeEmail`, `stripePhone`, `stripeAddress`, and `stripePreferredLocales` methods. These methods will sync information to their corresponding customer parameters when [updating the Stripe customer object](https://stripe.com/docs/api/customers/update). If you wish to take total control over the customer information sync process, you may override the `syncStripeCustomerDetails` method.
### Billing Portal
@@ -399,7 +406,7 @@ If you would like to generate the URL to the billing portal without generating a
### Storing Payment Methods
-In order to create subscriptions or perform "one off" charges with Stripe, you will need to store a payment method and retrieve its identifier from Stripe. The approach used to accomplish this differs based on whether you plan to use the payment method for subscriptions or single charges, so we will examine both below.
+In order to create subscriptions or perform "one-off" charges with Stripe, you will need to store a payment method and retrieve its identifier from Stripe. The approach used to accomplish this differs based on whether you plan to use the payment method for subscriptions or single charges, so we will examine both below.
#### Payment Methods For Subscriptions
@@ -465,7 +472,8 @@ cardButton.addEventListener('click', async (e) => {
After the card has been verified by Stripe, you may pass the resulting `setupIntent.payment_method` identifier to your Laravel application, where it can be attached to the customer. The payment method can either be [added as a new payment method](#adding-payment-methods) or [used to update the default payment method](#updating-the-default-payment-method). You can also immediately use the payment method identifier to [create a new subscription](#creating-subscriptions).
-> {tip} If you would like more information about Setup Intents and gathering customer payment details please [review this overview provided by Stripe](https://stripe.com/docs/payments/save-and-reuse#php).
+> **Note**
+> If you would like more information about Setup Intents and gathering customer payment details please [review this overview provided by Stripe](https://stripe.com/docs/payments/save-and-reuse#php).
#### Payment Methods For Single Charges
@@ -572,7 +580,8 @@ To sync your default payment method information with the customer's default paym
$user->updateDefaultPaymentMethodFromStripe();
-> {note} The default payment method on a customer can only be used for invoicing and creating new subscriptions. Due to limitations imposed by Stripe, it may not be used for single charges.
+> **Warning**
+> The default payment method on a customer can only be used for invoicing and creating new subscriptions. Due to limitations imposed by Stripe, it may not be used for single charges.
### Adding Payment Methods
@@ -581,7 +590,8 @@ To add a new payment method, you may call the `addPaymentMethod` method on the b
$user->addPaymentMethod($paymentMethod);
-> {tip} To learn how to retrieve payment method identifiers please review the [payment method storage documentation](#storing-payment-methods).
+> **Note**
+> To learn how to retrieve payment method identifiers please review the [payment method storage documentation](#storing-payment-methods).
### Deleting Payment Methods
@@ -602,7 +612,8 @@ By default, this method will delete payment methods of the `card` type. To delet
$user->deletePaymentMethods('sepa_debit');
-> {note} If a user has an active subscription, your application should not allow them to delete their default payment method.
+> **Warning**
+> If a user has an active subscription, your application should not allow them to delete their default payment method.
## Subscriptions
@@ -628,7 +639,8 @@ The first argument passed to the `newSubscription` method should be the internal
The `create` method, which accepts [a Stripe payment method identifier](#storing-payment-methods) or Stripe `PaymentMethod` object, will begin the subscription as well as update your database with the billable model's Stripe customer ID and other relevant billing information.
-> {note} Passing a payment method identifier directly to the `create` subscription method will also automatically add it to the user's stored payment methods.
+> **Warning**
+> Passing a payment method identifier directly to the `create` subscription method will also automatically add it to the user's stored payment methods.
#### Collecting Recurring Payments Via Invoice Emails
@@ -734,7 +746,7 @@ You may also create subscriptions from the Stripe dashboard itself. When doing s
In addition, you may only create one type of subscription via the Stripe dashboard. If your application offers multiple subscriptions that use different names, only one type of subscription may be added through the Stripe dashboard.
-Finally, you should always make sure to only add one active subscription per type of subscription offered by your application. If customer has two `default` subscriptions, only the most recently added subscription will be used by Cashier even though both would be synced with your application's database.
+Finally, you should always make sure to only add one active subscription per type of subscription offered by your application. If a customer has two `default` subscriptions, only the most recently added subscription will be used by Cashier even though both would be synced with your application's database.
### Checking Subscription Status
@@ -803,7 +815,8 @@ The `recurring` method may be used to determine if the user is currently subscri
//
}
-> {note} If a user has two subscriptions with the same name, the most recent subscription will always be returned by the `subscription` method. For example, a user might have two subscription records named `default`; however, one of the subscriptions may be an old, expired subscription, while the other is the current, active subscription. The most recent subscription will always be returned while older subscriptions are kept in the database for historical review.
+> **Warning**
+> If a user has two subscriptions with the same name, the most recent subscription will always be returned by the `subscription` method. For example, a user might have two subscription records named `default`; however, one of the subscriptions may be an old, expired subscription, while the other is the current, active subscription. The most recent subscription will always be returned while older subscriptions are kept in the database for historical review.
#### Canceled Subscription Status
@@ -863,7 +876,8 @@ If you would like the subscription to still be considered active when it's in a
Cashier::keepPastDueSubscriptionsActive();
}
-> {note} When a subscription is in an `incomplete` state it cannot be changed until the payment is confirmed. Therefore, the `swap` and `updateQuantity` methods will throw an exception when the subscription is in an `incomplete` state.
+> **Warning**
+> When a subscription is in an `incomplete` state it cannot be changed until the payment is confirmed. Therefore, the `swap` and `updateQuantity` methods will throw an exception when the subscription is in an `incomplete` state.
#### Subscription Scopes
@@ -924,7 +938,8 @@ By default, Stripe prorates charges when swapping between prices. The `noProrate
For more information on subscription proration, consult the [Stripe documentation](https://stripe.com/docs/billing/subscriptions/prorations).
-> {note} Executing the `noProrate` method before the `swapAndInvoice` method will have no effect on proration. An invoice will always be issued.
+> **Warning**
+> Executing the `noProrate` method before the `swapAndInvoice` method will have no effect on proration. An invoice will always be issued.
### Subscription Quantity
@@ -955,19 +970,19 @@ The `noProrate` method may be used to update the subscription's quantity without
For more information on subscription quantities, consult the [Stripe documentation](https://stripe.com/docs/subscriptions/quantities).
-
-#### Multiprice Subscription Quantities
+
+#### Quantities For Subscriptions With Multiple Products
-If your subscription is a [multiprice subscription](#multiprice-subscriptions), you should pass the name of the price whose quantity you wish to increment or decrement as the second argument to the increment / decrement methods:
+If your subscription is a [subscription with multiple products](#subscriptions-with-multiple-products), you should pass the ID of the price whose quantity you wish to increment or decrement as the second argument to the increment / decrement methods:
$user->subscription('default')->incrementQuantity(1, 'price_chat');
-
-### Multiprice Subscriptions
+
+### Subscriptions With Multiple Products
-[Multiprice subscriptions](https://stripe.com/docs/billing/subscriptions/multiple-products) allow you to assign multiple billing prices to a single subscription. For example, imagine you are building a customer service "helpdesk" application that has a base subscription price of $10 per month but offers a live chat add-on price for an additional $15 per month. Multiprice subscription information is stored in Cashier's `subscription_items` database table.
+[Subscription with multiple products](https://stripe.com/docs/billing/subscriptions/multiple-products) allow you to assign multiple billing products to a single subscription. For example, imagine you are building a customer service "helpdesk" application that has a base subscription price of $10 per month but offers a live chat add-on product for an additional $15 per month. Information for subscriptions with multiple products is stored in Cashier's `subscription_items` database table.
-You may specify multiple prices for a given subscription by passing an array of prices as the second argument to the `newSubscription` method:
+You may specify multiple products for a given subscription by passing an array of prices as the second argument to the `newSubscription` method:
use Illuminate\Http\Request;
@@ -1008,12 +1023,13 @@ You may remove prices from subscriptions using the `removePrice` method:
$user->subscription('default')->removePrice('price_chat');
-> {note} You may not remove the last price on a subscription. Instead, you should simply cancel the subscription.
+> **Warning**
+> You may not remove the last price on a subscription. Instead, you should simply cancel the subscription.
#### Swapping Prices
-You may also change the prices attached to a multiprice subscription. For example, imagine a customer has a `price_basic` subscription with a `price_chat` add-on price and you want to upgrade the customer from the `price_basic` to the `price_pro` price:
+You may also change the prices attached to a subscription with multiple products. For example, imagine a customer has a `price_basic` subscription with a `price_chat` add-on product and you want to upgrade the customer from the `price_basic` to the `price_pro` price:
use App\Models\User;
@@ -1043,7 +1059,7 @@ If you want to swap a single price on a subscription, you may do so using the `s
#### Proration
-By default, Stripe will prorate charges when adding or removing prices from a multiprice subscription. If you would like to make a price adjustment without proration, you should chain the `noProrate` method onto your price operation:
+By default, Stripe will prorate charges when adding or removing prices from a subscription with multiple products. If you would like to make a price adjustment without proration, you should chain the `noProrate` method onto your price operation:
$user->subscription('default')->noProrate()->removePrice('price_chat');
@@ -1060,7 +1076,8 @@ If you would like to update quantities on individual subscription prices, you ma
$user->subscription('default')->updateQuantity(10, 'price_chat');
-> {note} When a subscription has multiple prices the `stripe_price` and `quantity` attributes on the `Subscription` model will be `null`. To access the individual price attributes, you should use the `items` relationship available on the `Subscription` model.
+> **Warning**
+> When a subscription has multiple prices the `stripe_price` and `quantity` attributes on the `Subscription` model will be `null`. To access the individual price attributes, you should use the `items` relationship available on the `Subscription` model.
#### Subscription Items
@@ -1166,7 +1183,8 @@ For a full reference of all usage data returned and how to use Stripe's cursor b
### Subscription Taxes
-> {note} Instead of calculating Tax Rates manually, you can [automatically calculate taxes using Stripe Tax](#tax-configuration)
+> **Warning**
+> Instead of calculating Tax Rates manually, you can [automatically calculate taxes using Stripe Tax](#tax-configuration)
To specify the tax rates a user pays on a subscription, you should implement the `taxRates` method on your billable model and return an array containing the Stripe tax rate IDs. You can define these tax rates in [your Stripe dashboard](https://dashboard.stripe.com/test/tax-rates):
@@ -1182,7 +1200,7 @@ To specify the tax rates a user pays on a subscription, you should implement the
The `taxRates` method enables you to apply a tax rate on a customer-by-customer basis, which may be helpful for a user base that spans multiple countries and tax rates.
-If you're offering multiprice subscriptions, you may define different tax rates for each price by implementing a `priceTaxRates` method on your billable model:
+If you're offering subscriptions with multiple products, you may define different tax rates for each price by implementing a `priceTaxRates` method on your billable model:
/**
* The tax rates that should apply to the customer's subscriptions.
@@ -1196,7 +1214,8 @@ If you're offering multiprice subscriptions, you may define different tax rates
];
}
-> {note} The `taxRates` method only applies to subscription charges. If you use Cashier to make "one off" charges, you will need to manually specify the tax rate at that time.
+> **Warning**
+> The `taxRates` method only applies to subscription charges. If you use Cashier to make "one-off" charges, you will need to manually specify the tax rate at that time.
#### Syncing Tax Rates
@@ -1205,7 +1224,7 @@ When changing the hard-coded tax rate IDs returned by the `taxRates` method, the
$user->subscription('default')->syncTaxRates();
-This will also sync any multiprice subscription item tax rates. If your application is offering multiprice subscriptions, you should ensure that your billable model implements the `priceTaxRates` method [discussed above](#subscription-taxes).
+This will also sync any item tax rates for a subscription with multiple products. If your application is offering subscriptions with multiple products, you should ensure that your billable model implements the `priceTaxRates` method [discussed above](#subscription-taxes).
#### Tax Exemption
@@ -1220,7 +1239,8 @@ Cashier also offers the `isNotTaxExempt`, `isTaxExempt`, and `reverseChargeAppli
$user->isNotTaxExempt();
$user->reverseChargeApplies();
-> {note} These methods are also available on any `Laravel\Cashier\Invoice` object. However, when invoked on an `Invoice` object, the methods will determine the exemption status at the time the invoice was created.
+> **Warning**
+> These methods are also available on any `Laravel\Cashier\Invoice` object. However, when invoked on an `Invoice` object, the methods will determine the exemption status at the time the invoice was created.
### Subscription Anchor Date
@@ -1301,7 +1321,8 @@ If you would like to offer trial periods to your customers while still collectin
This method will set the trial period ending date on the subscription record within the database and instruct Stripe to not begin billing the customer until after this date. When using the `trialDays` method, Cashier will overwrite any default trial period configured for the price in Stripe.
-> {note} If the customer's subscription is not canceled before the trial ending date they will be charged as soon as the trial expires, so you should be sure to notify your users of their trial ending date.
+> **Warning**
+> If the customer's subscription is not canceled before the trial ending date they will be charged as soon as the trial expires, so you should be sure to notify your users of their trial ending date.
The `trialUntil` method allows you to provide a `DateTime` instance that specifies when the trial period should end:
@@ -1325,6 +1346,16 @@ You may use the `endTrial` method to immediately end a subscription trial:
$user->subscription('default')->endTrial();
+To determine if an existing trial has expired, you may use the `hasExpiredTrial` methods:
+
+ if ($user->hasExpiredTrial('default')) {
+ //
+ }
+
+ if ($user->subscription('default')->hasExpiredTrial()) {
+ //
+ }
+
#### Defining Trial Days In Stripe / Cashier
@@ -1342,7 +1373,8 @@ If you would like to offer trial periods without collecting the user's payment m
'trial_ends_at' => now()->addDays(10),
]);
-> {note} Be sure to add a [date cast](/docs/{{version}}/eloquent-mutators##date-casting) for the `trial_ends_at` attribute within your billable model's class definition.
+> **Warning**
+> Be sure to add a [date cast](/docs/{{version}}/eloquent-mutators##date-casting) for the `trial_ends_at` attribute within your billable model's class definition.
Cashier refers to this type of trial as a "generic trial", since it is not attached to any existing subscription. The `onTrial` method on the billable model instance will return `true` if the current date is not past the value of `trial_ends_at`:
@@ -1390,7 +1422,8 @@ The `extendTrial` method allows you to extend the trial period of a subscription
## Handling Stripe Webhooks
-> {tip} You may use [the Stripe CLI](https://stripe.com/docs/stripe-cli) to help test webhooks during local development.
+> **Note**
+> You may use [the Stripe CLI](https://stripe.com/docs/stripe-cli) to help test webhooks during local development.
Stripe can notify your application of a variety of events via webhooks. By default, a route that points to Cashier's webhook controller is automatically registered by the Cashier service provider. This controller will handle all incoming webhook requests.
@@ -1429,7 +1462,8 @@ After creation, the webhook will be immediately active. If you wish to create th
php artisan cashier:webhook --disabled
```
-> {note} Make sure you protect incoming Stripe webhook requests with Cashier's included [webhook signature verification](#verifying-webhook-signatures) middleware.
+> **Warning**
+> Make sure you protect incoming Stripe webhook requests with Cashier's included [webhook signature verification](#verifying-webhook-signatures) middleware.
#### Webhooks & CSRF Protection
@@ -1536,7 +1570,8 @@ The `charge` method will throw an exception if the charge fails. If the charge i
//
}
-> {note} The `charge` method accepts the payment amount in the lowest denominator of the currency used by your application. For example, if customers are paying in United States Dollars, amounts should be specified in pennies.
+> **Warning**
+> The `charge` method accepts the payment amount in the lowest denominator of the currency used by your application. For example, if customers are paying in United States Dollars, amounts should be specified in pennies.
### Charge With Invoice
@@ -1565,9 +1600,10 @@ Alternatively, you may use the `invoiceFor` method to make a "one-off" charge ag
$user->invoiceFor('One Time Fee', 500);
-Although the `invoiceFor` method is available for you to use, it is recommendeded that you use the `invoicePrice` and `tabPrice` methods with pre-defined prices. By doing so, you will have access to better analytics and data within your Stripe dashboard regarding your sales on a per-product basis.
+Although the `invoiceFor` method is available for you to use, it is recommended that you use the `invoicePrice` and `tabPrice` methods with pre-defined prices. By doing so, you will have access to better analytics and data within your Stripe dashboard regarding your sales on a per-product basis.
-> {note} The `invoice`, `invoicePrice`, and `invoiceFor` methods will create a Stripe invoice which will retry failed billing attempts. If you do not want invoices to retry failed charges, you will need to close them using the Stripe API after the first failed charge.
+> **Warning**
+> The `invoice`, `invoicePrice`, and `invoiceFor` methods will create a Stripe invoice which will retry failed billing attempts. If you do not want invoices to retry failed charges, you will need to close them using the Stripe API after the first failed charge.
### Creating Payment Intents
@@ -1598,7 +1634,8 @@ When using the `pay` method, the default payment methods that are enabled within
return $payment->client_secret;
});
-> {note} The `pay` and `payWith` methods accept the payment amount in the lowest denominator of the currency used by your application. For example, if customers are paying in United States Dollars, amounts should be specified in pennies.
+> **Warning**
+> The `pay` and `payWith` methods accept the payment amount in the lowest denominator of the currency used by your application. For example, if customers are paying in United States Dollars, amounts should be specified in pennies.
### Refunding Charges
@@ -1649,7 +1686,7 @@ To retrieve the upcoming invoice for a customer, you may use the `upcomingInvoic
$invoice = $user->upcomingInvoice();
-Similary, if the customer has multiple subscriptions, you can also retrieve the upcoming invoice for a specific subscription:
+Similarly, if the customer has multiple subscriptions, you can also retrieve the upcoming invoice for a specific subscription:
$invoice = $user->subscription('default')->upcomingInvoice();
@@ -1667,18 +1704,21 @@ You may pass an array of prices to the `previewInvoice` method in order to previ
### Generating Invoice PDFs
+Before generating invoice PDFs, you should use Composer to install the Dompdf library, which is the default invoice renderer for Cashier:
+
+```php
+composer require dompdf/dompdf
+```
+
From within a route or controller, you may use the `downloadInvoice` method to generate a PDF download of a given invoice. This method will automatically generate the proper HTTP response needed to download the invoice:
use Illuminate\Http\Request;
Route::get('/user/invoice/{invoice}', function (Request $request, $invoiceId) {
- return $request->user()->downloadInvoice($invoiceId, [
- 'vendor' => 'Your Company',
- 'product' => 'Your Product',
- ]);
+ return $request->user()->downloadInvoice($invoiceId);
});
-By default, all data on the invoice is derived from the customer and invoice data stored in Stripe. However, you can customize some of this data by providing an array as the second argument to the `downloadInvoice` method. This array allows you to customize information such as your company and product details:
+By default, all data on the invoice is derived from the customer and invoice data stored in Stripe. The filename is based on your `app.name` config value. However, you can customize some of this data by providing an array as the second argument to the `downloadInvoice` method. This array allows you to customize information such as your company and product details:
return $request->user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
@@ -1689,7 +1729,7 @@ By default, all data on the invoice is derived from the customer and invoice dat
'email' => 'info@example.com',
'url' => 'https://example.com',
'vendorVat' => 'BE123456789',
- ], 'my-invoice');
+ ]);
The `downloadInvoice` method also allows for a custom filename via its third argument. This filename will automatically be suffixed with `.pdf`:
@@ -1769,7 +1809,7 @@ When defining your `success_url` checkout option, you may instruct Stripe to add
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 1], [
- 'success_url' => route('checkout-success') . '?session_id={CHECKOUT_SESSION_ID}',
+ 'success_url' => route('checkout-success').'?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('checkout-cancel'),
]);
});
@@ -1804,12 +1844,14 @@ You can also perform a simple charge for an ad-hoc product that has not been cre
return $request->user()->checkoutCharge(1200, 'T-Shirt', 5);
});
-> {note} When using the `checkoutCharge` method, Stripe will always create a new product and price in your Stripe dashboard. Therefore, we recommend that you create the products up front in your Stripe dashboard and use the `checkout` method instead.
+> **Warning**
+> When using the `checkoutCharge` method, Stripe will always create a new product and price in your Stripe dashboard. Therefore, we recommend that you create the products up front in your Stripe dashboard and use the `checkout` method instead.
### Subscription Checkouts
-> {note} Using Stripe Checkout for subscriptions requires you to enable the `customer.subscription.created` webhook in your Stripe dashboard. This webhook will create the subscription record in your database and store all of the relevant subscription items.
+> **Warning**
+> Using Stripe Checkout for subscriptions requires you to enable the `customer.subscription.created` webhook in your Stripe dashboard. This webhook will create the subscription record in your database and store all of the relevant subscription items.
You may also use Stripe Checkout to initiate subscriptions. After defining your subscription with Cashier's subscription builder methods, you may call the `checkout `method. When a customer visits this route they will be redirected to Stripe's Checkout page:
@@ -1845,7 +1887,8 @@ Of course, you can also enable promotion codes for subscription checkouts:
->checkout();
});
-> {note} Unfortunately Stripe Checkout does not support all subscription billing options when starting subscriptions. Using the `anchorBillingCycleOn` method on the subscription builder, setting proration behavior, or setting payment behavior will not have any effect during Stripe Checkout sessions. Please consult [the Stripe Checkout Session API documentation](https://stripe.com/docs/api/checkout/sessions/create) to review which parameters are available.
+> **Warning**
+> Unfortunately Stripe Checkout does not support all subscription billing options when starting subscriptions. Using the `anchorBillingCycleOn` method on the subscription builder, setting proration behavior, or setting payment behavior will not have any effect during Stripe Checkout sessions. Please consult [the Stripe Checkout Session API documentation](https://stripe.com/docs/api/checkout/sessions/create) to review which parameters are available.
#### Stripe Checkout & Trial Periods
@@ -1872,7 +1915,8 @@ Checkout also supports collecting a customer's Tax ID. To enable this on a check
When this method is invoked, a new checkbox will be available to the customer that allows them to indicate if they're purchasing as a company. If so, they will have the opportunity to provide their Tax ID number.
-> {note} If you have already configured [automatic tax collection](#tax-configuration) in your application's service provider then this feature will be enabled automatically and there is no need to invoke the `collectTaxIds` method.
+> **Warning**
+> If you have already configured [automatic tax collection](#tax-configuration) in your application's service provider then this feature will be enabled automatically and there is no need to invoke the `collectTaxIds` method.
## Handling Failed Payments
@@ -1945,7 +1989,8 @@ You can derive the specific status of an incomplete payment by inspecting the `p
If your business or one of your customers is based in Europe you will need to abide by the EU's Strong Customer Authentication (SCA) regulations. These regulations were imposedĀ in September 2019 by the European Union to prevent payment fraud. Luckily, Stripe and Cashier are prepared for building SCA compliant applications.
-> {note} Before getting started, review [Stripe's guide on PSD2 and SCA](https://stripe.com/guides/strong-customer-authentication) as well as their [documentation on the new SCA APIs](https://stripe.com/docs/strong-customer-authentication).
+> **Warning**
+> Before getting started, review [Stripe's guide on PSD2 and SCA](https://stripe.com/guides/strong-customer-authentication) as well as their [documentation on the new SCA APIs](https://stripe.com/docs/strong-customer-authentication).
### Payments Requiring Additional Confirmation
@@ -1972,7 +2017,8 @@ CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notifications\ConfirmPayment
To ensure that off-session payment confirmation notifications are delivered, verify that [Stripe webhooks are configured](#handling-stripe-webhooks) for your application and the `invoice.payment_action_required` webhook is enabled in your Stripe dashboard. In addition, your `Billable` model should also use Laravel's `Illuminate\Notifications\Notifiable` trait.
-> {note} Notifications will be sent even when customers are manually making a payment that requires additional confirmation. Unfortunately, there is no way for Stripe to know that the payment was done manually or "off-session". But, a customer will simply see a "Payment Successful" message if they visit the payment page after already confirming their payment. The customer will not be allowed to accidentally confirm the same payment twice and incur an accidental second charge.
+> **Warning**
+> Notifications will be sent even when customers are manually making a payment that requires additional confirmation. Unfortunately, there is no way for Stripe to know that the payment was done manually or "off-session". But, a customer will simply see a "Payment Successful" message if they visit the payment page after already confirming their payment. The customer will not be allowed to accidentally confirm the same payment twice and incur an accidental second charge.
## Stripe SDK
@@ -2008,4 +2054,5 @@ To get started, add the **testing** version of your Stripe secret to your `phpun
Now, whenever you interact with Cashier while testing, it will send actual API requests to your Stripe testing environment. For convenience, you should pre-fill your Stripe testing account with subscriptions / prices that you may use during testing.
-> {tip} In order to test a variety of billing scenarios, such as credit card denials and failures, you may use the vast range of [testing card numbers and tokens](https://stripe.com/docs/testing) provided by Stripe.
+> **Note**
+> In order to test a variety of billing scenarios, such as credit card denials and failures, you may use the vast range of [testing card numbers and tokens](https://stripe.com/docs/testing) provided by Stripe.
diff --git a/blade.md b/blade.md
index 5a8b8a2d9ee..a54edff42d7 100644
--- a/blade.md
+++ b/blade.md
@@ -10,7 +10,7 @@
- [Loops](#loops)
- [The Loop Variable](#the-loop-variable)
- [Conditional Classes](#conditional-classes)
- - [Checked / Selected / Disabled](#checked-and-selected)
+ - [Additional Attributes](#additional-attributes)
- [Including Subviews](#including-subviews)
- [The `@once` Directive](#the-once-directive)
- [Raw PHP](#raw-php)
@@ -54,7 +54,8 @@ Blade views may be returned from routes or controllers using the global `view` h
return view('greeting', ['name' => 'Finn']);
});
-> {tip} Want to take your Blade templates to the next level and build dynamic interfaces with ease? Check out [Laravel Livewire](https://laravel-livewire.com).
+> **Note**
+> Want to take your Blade templates to the next level and build dynamic interfaces with ease? Check out [Laravel Livewire](https://laravel-livewire.com).
## Displaying Data
@@ -71,7 +72,8 @@ You may display the contents of the `name` variable like so:
Hello, {{ $name }}.
```
-> {tip} Blade's `{{ }}` echo statements are automatically sent through PHP's `htmlspecialchars` function to prevent XSS attacks.
+> **Note**
+> Blade's `{{ }}` echo statements are automatically sent through PHP's `htmlspecialchars` function to prevent XSS attacks.
You are not limited to displaying the contents of the variables passed to the view. You may also echo the results of any PHP function. In fact, you can put any PHP code you wish inside of a Blade echo statement:
@@ -113,7 +115,8 @@ By default, Blade `{{ }}` statements are automatically sent through PHP's `htmls
Hello, {!! $name !!}.
```
-> {note} Be very careful when echoing content that is supplied by users of your application. You should typically use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data.
+> **Warning**
+> Be very careful when echoing content that is supplied by users of your application. You should typically use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data.
### Blade & JavaScript Frameworks
@@ -165,7 +168,8 @@ The latest versions of the Laravel application skeleton include a `Js` facade, w
```
-> {note} You should only use the `Js::from` method to render existing variables as JSON. The Blade templating is based on regular expressions and attempts to pass a complex expression to the directive may cause unexpected failures.
+> **Warning**
+> You should only use the `Js::from` method to render existing variables as JSON. The Blade templating is based on regular expressions and attempts to pass a complex expression to the directive may cause unexpected failures.
#### The `@verbatim` Directive
@@ -340,7 +344,8 @@ In addition to conditional statements, Blade provides simple directives for work
@endwhile
```
-> {tip} While iterating through a `foreach` loop, you may use the [loop variable](#the-loop-variable) to gain valuable information about the loop, such as whether you are in the first or last iteration through the loop.
+> **Note**
+> While iterating through a `foreach` loop, you may use the [loop variable](#the-loop-variable) to gain valuable information about the loop, such as whether you are in the first or last iteration through the loop.
When using loops you may also skip the current iteration or end the loop using the `@continue` and `@break` directives:
@@ -437,8 +442,8 @@ The `@class` directive conditionally compiles a CSS class string. The directive
```
-
-### Checked / Selected / Disabled
+
+### Additional Attributes
For convenience, you may use the `@checked` directive to easily indicate if a given HTML checkbox input is "checked". This directive will echo `checked` if the provided condition evaluates to `true`:
@@ -467,10 +472,29 @@ Additionally, the `@disabled` directive may be used to indicate if a given eleme
```
+Moreover, the `@readonly` directive may be used to indicate if a given element should be "readonly":
+
+```blade
+isNotAdmin()) />
+```
+
+In addition, the `@required` directive may be used to indicate if a given element should be "required":
+
+```blade
+isAdmin()) />
+```
+
### Including Subviews
-> {tip} While you're free to use the `@include` directive, Blade [components](#components) provide similar functionality and offer several benefits over the `@include` directive such as data and attribute binding.
+> **Note**
+> While you're free to use the `@include` directive, Blade [components](#components) provide similar functionality and offer several benefits over the `@include` directive such as data and attribute binding.
Blade's `@include` directive allows you to include a Blade view from within another view. All variables that are available to the parent view will be made available to the included view:
@@ -510,7 +534,8 @@ To include the first view that exists from a given array of views, you may use t
@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])
```
-> {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.
+> **Warning**
+> 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.
#### Rendering Views For Collections
@@ -529,7 +554,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 the `@foreach` and `@include` directives instead.
+> **Warning**
+> Views rendered via `@each` do not inherit the variables from the parent view. If the child view requires these variables, you should use the `@foreach` and `@include` directives instead.
### The `@once` Directive
@@ -581,7 +607,7 @@ Blade also allows you to define comments in your views. However, unlike HTML com
Components and slots provide similar benefits to sections, layouts, and includes; however, some may find the mental model of components and slots easier to understand. There are two approaches to writing components: class based components and anonymous components.
-To create a class based component, you may use the `make:component` Artisan command. To illustrate how to use components, we will create a simple `Alert` component. The `make:component` command will place the component in the `App\View\Components` directory:
+To create a class based component, you may use the `make:component` Artisan command. To illustrate how to use components, we will create a simple `Alert` component. The `make:component` command will place the component in the `app/View/Components` directory:
```shell
php artisan make:component Alert
@@ -595,7 +621,7 @@ You may also create components within subdirectories:
php artisan make:component Forms/Input
```
-The command above will create an `Input` component in the `App\View\Components\Forms` directory and the view will be placed in the `resources/views/components/forms` directory.
+The command above will create an `Input` component in the `app/View/Components/Forms` directory and the view will be placed in the `resources/views/components/forms` directory.
If you would like to create an anonymous component (a component with only a Blade template and no class), you may use the `--view` flag when invoking the `make:component` command:
@@ -662,7 +688,7 @@ To display a component, you may use a Blade component tag within one of your Bla
<digits>
+- decimal:<precision>
- `double`
- `encrypted`
- `encrypted:array`
@@ -270,7 +270,8 @@ If you need to add a new, temporary cast at runtime, you may use the `mergeCasts
'options' => 'object',
]);
-> {note} Attributes that are `null` will not be cast. In addition, you should never define a cast (or an attribute) that has the same name as a relationship.
+> **Warning**
+> Attributes that are `null` will not be cast. In addition, you should never define a cast (or an attribute) that has the same name as a relationship.
#### Stringable Casting
@@ -424,9 +425,10 @@ If a custom format is applied to the `date` or `datetime` cast, such as `datetim
### Enum Casting
-> {note} Enum casting is only available for PHP 8.1+.
+> **Warning**
+> Enum casting is only available for PHP 8.1+.
-Eloquent also allows you to cast your attribute values to PHP ["backed" Enums](https://www.php.net/manual/en/language.enumerations.backed.php). To accomplish this, you may specify the attribute and enum you wish to cast in your model's `$casts` property array:
+Eloquent also allows you to cast your attribute values to PHP [Enums](https://www.php.net/manual/en/language.enumerations.backed.php). To accomplish this, you may specify the attribute and enum you wish to cast in your model's `$casts` property array:
use App\Enums\ServerStatus;
@@ -559,7 +561,7 @@ As an example, we will define a custom cast class that casts multiple model valu
namespace App\Casts;
- use App\Models\Address as AddressModel;
+ use App\ValueObjects\Address as AddressValueObject;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use InvalidArgumentException;
@@ -572,11 +574,11 @@ As an example, we will define a custom cast class that casts multiple model valu
* @param string $key
* @param mixed $value
* @param array $attributes
- * @return \App\Models\Address
+ * @return \App\ValueObjects\Address
*/
public function get($model, $key, $value, $attributes)
{
- return new AddressModel(
+ return new AddressValueObject(
$attributes['address_line_one'],
$attributes['address_line_two']
);
@@ -587,13 +589,13 @@ As an example, we will define a custom cast class that casts multiple model valu
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
- * @param \App\Models\Address $value
+ * @param \App\ValueObjects\Address $value
* @param array $attributes
* @return array
*/
public function set($model, $key, $value, $attributes)
{
- if (! $value instanceof AddressModel) {
+ if (! $value instanceof AddressValueObject) {
throw new InvalidArgumentException('The given value is not an Address instance.');
}
@@ -614,7 +616,8 @@ When casting to value objects, any changes made to the value object will automat
$user->save();
-> {tip} If you plan to serialize your Eloquent models containing value objects to JSON or arrays, you should implement the `Illuminate\Contracts\Support\Arrayable` and `JsonSerializable` interfaces on the value object.
+> **Note**
+> If you plan to serialize your Eloquent models containing value objects to JSON or arrays, you should implement the `Illuminate\Contracts\Support\Arrayable` and `JsonSerializable` interfaces on the value object.
### Array / JSON Serialization
diff --git a/eloquent-relationships.md b/eloquent-relationships.md
index a1053bd74e1..45584935c7c 100644
--- a/eloquent-relationships.md
+++ b/eloquent-relationships.md
@@ -343,7 +343,8 @@ public function largestOrder()
}
```
-> {note} Because PostgreSQL does not support executing the `MAX` function against UUID columns, it is not currently possible to use one-of-many relationships in combination with PostgreSQL UUID columns.
+> **Warning**
+> Because PostgreSQL does not support executing the `MAX` function against UUID columns, it is not currently possible to use one-of-many relationships in combination with PostgreSQL UUID columns.
#### Advanced Has One Of Many Relationships
@@ -609,7 +610,8 @@ If you would like your intermediate table to have `created_at` and `updated_at`
return $this->belongsToMany(Role::class)->withTimestamps();
-> {note} Intermediate tables that utilize Eloquent's automatically maintained timestamps are required to have both `created_at` and `updated_at` timestamp columns.
+> **Warning**
+> Intermediate tables that utilize Eloquent's automatically maintained timestamps are required to have both `created_at` and `updated_at` timestamp columns.
#### Customizing The `pivot` Attribute Name
@@ -697,7 +699,8 @@ When defining the `RoleUser` model, you should extend the `Illuminate\Database\E
//
}
-> {note} Pivot models may not use the `SoftDeletes` trait. If you need to soft delete pivot records consider converting your pivot model to an actual Eloquent model.
+> **Warning**
+> Pivot models may not use the `SoftDeletes` trait. If you need to soft delete pivot records consider converting your pivot model to an actual Eloquent model.
#### Custom Pivot Models And Incrementing IDs
@@ -950,7 +953,8 @@ public function bestImage()
}
```
-> {tip} It is possible to construct more advanced "one of many" relationships. For more information, please consult the [has one of many documentation](#advanced-has-one-of-many-relationships).
+> **Note**
+> It is possible to construct more advanced "one of many" relationships. For more information, please consult the [has one of many documentation](#advanced-has-one-of-many-relationships).
### Many To Many (Polymorphic)
@@ -977,7 +981,8 @@ Many-to-many polymorphic relations are slightly more complicated than "morph one
taggable_id - integer
taggable_type - string
-> {tip} Before diving into polymorphic many-to-many relationships, you may benefit from reading the documentation on typical [many-to-many relationships](#many-to-many).
+> **Note**
+> Before diving into polymorphic many-to-many relationships, you may benefit from reading the documentation on typical [many-to-many relationships](#many-to-many).
#### Model Structure
@@ -1086,7 +1091,8 @@ You may determine the morph alias of a given model at runtime using the model's
$class = Relation::getMorphedModel($alias);
-> {note} When adding a "morph map" to your existing application, every morphable `*_type` column value in your database that still contains a fully-qualified class will need to be converted to its "map" name.
+> **Warning**
+> When adding a "morph map" to your existing application, every morphable `*_type` column value in your database that still contains a fully-qualified class will need to be converted to its "map" name.
### Dynamic Relationships
@@ -1102,7 +1108,8 @@ The `resolveRelationUsing` method accepts the desired relationship name as its f
return $orderModel->belongsTo(Customer::class, 'customer_id');
});
-> {note} When defining dynamic relationships, always provide explicit key name arguments to the Eloquent relationship methods.
+> **Warning**
+> When defining dynamic relationships, always provide explicit key name arguments to the Eloquent relationship methods.
## Querying Relations
@@ -1224,12 +1231,13 @@ If you need even more power, you may use the `whereHas` and `orWhereHas` methods
$query->where('content', 'like', 'code%');
}, '>=', 10)->get();
-> {note} Eloquent does not currently support querying for relationship existence across databases. The relationships must exist within the same database.
+> **Warning**
+> Eloquent does not currently support querying for relationship existence across databases. The relationships must exist within the same database.
#### Inline Relationship Existence Queries
-If you would like to query for a relationship's existence with a single, simple where condition attached to the relationship query, you may find it more convenient to use the `whereRelation` and `whereMorphRelation` methods. For example, we may query for all posts that have unapproved comments:
+If you would like to query for a relationship's existence with a single, simple where condition attached to the relationship query, you may find it more convenient to use the `whereRelation`, `orWhereRelation`, `whereMorphRelation`, and `orWhereMorphRelation` methods. For example, we may query for all posts that have unapproved comments:
use App\Models\Post;
@@ -1512,6 +1520,15 @@ To eager load a relationship's relationships, you may use "dot" syntax. For exam
$books = Book::with('author.contacts')->get();
+Alternatively, you may specify nested eager loaded relationships by providing a nested array to the `with` method, which can be convenient when eager loading multiple nested relationships:
+
+ $books = Book::with([
+ 'author' => [
+ 'contacts',
+ 'publisher',
+ ],
+ ])->get();
+
#### Nested Eager Loading `morphTo` Relationships
@@ -1554,7 +1571,8 @@ You may not always need every column from the relationships you are retrieving.
$books = Book::with('author:id,name,book_id')->get();
-> {note} When using this feature, you should always include the `id` column and any relevant foreign key columns in the list of columns you wish to retrieve.
+> **Warning**
+> When using this feature, you should always include the `id` column and any relevant foreign key columns in the list of columns you wish to retrieve.
#### Eager Loading By Default
@@ -1618,7 +1636,8 @@ In this example, Eloquent will only eager load posts where the post's `title` co
$query->orderBy('created_at', 'desc');
}])->get();
-> {note} The `limit` and `take` query builder methods may not be used when constraining eager loads.
+> **Warning**
+> The `limit` and `take` query builder methods may not be used when constraining eager loads.
#### Constraining Eager Loading Of `morphTo` Relationships
@@ -1641,6 +1660,17 @@ If you are eager loading a `morphTo` relationship, Eloquent will run multiple qu
In this example, Eloquent will only eager load posts that have not been hidden and videos that have a `type` value of "educational".
+
+#### Constraining Eager Loads With Relationship Existence
+
+You may sometimes find yourself needing to check for the existence of a relationship while simultaneously loading the relationship based on the same conditions. For example, you may wish to only retrieve `User` models that have child `Post` models matching a given query condition while also eager loading the matching posts. You may accomplish this using the `withWhereHas` method:
+
+ use App\Models\User;
+
+ $users = User::withWhereHas('posts', function ($query) {
+ $query->where('featured', true);
+ })->get();
+
### Lazy Eager Loading
@@ -1804,7 +1834,8 @@ You may use the `createMany` method to create multiple related models:
You may also use the `findOrNew`, `firstOrNew`, `firstOrCreate`, and `updateOrCreate` methods to [create and update models on relationships](/docs/{{version}}/eloquent#upserts).
-> {tip} Before using the `create` method, be sure to review the [mass assignment](/docs/{{version}}/eloquent#mass-assignment) documentation.
+> **Note**
+> Before using the `create` method, be sure to review the [mass assignment](/docs/{{version}}/eloquent#mass-assignment) documentation.
### Belongs To Relationships
@@ -1930,4 +1961,5 @@ For example, when a `Comment` model is updated, you may want to automatically "t
}
}
-> {note} Parent model timestamps will only be updated if the child model is updated using Eloquent's `save` method.
+> **Warning**
+> Parent model timestamps will only be updated if the child model is updated using Eloquent's `save` method.
diff --git a/eloquent-resources.md b/eloquent-resources.md
index a9c5a73d9e2..978d7fb6737 100644
--- a/eloquent-resources.md
+++ b/eloquent-resources.md
@@ -44,7 +44,8 @@ php artisan make:resource UserCollection
## Concept Overview
-> {tip} This is a high-level overview of resources and resource collections. You are highly encouraged to read the other sections of this documentation to gain a deeper understanding of the customization and power offered to you by resources.
+> **Note**
+> This is a high-level overview of resources and resource collections. You are highly encouraged to read the other sections of this documentation to gain a deeper understanding of the customization and power offered to you by resources.
Before diving into all of the options available to you when writing resources, let's first take a high-level look at how resources are used within Laravel. A resource class represents a single model that needs to be transformed into a JSON structure. For example, here is a simple `UserResource` resource class:
@@ -195,7 +196,8 @@ For example, `UserCollection` will attempt to map the given user instances into
## Writing Resources
-> {tip} If you have not read the [concept overview](#concept-overview), you are highly encouraged to do so before proceeding with this documentation.
+> **Note**
+> If you have not read the [concept overview](#concept-overview), you are highly encouraged to do so before proceeding with this documentation.
In essence, resources are simple. They only need to transform a given model into an array. So, each resource contains a `toArray` method which translates your model's attributes into an API friendly array that can be returned from your application's routes or controllers:
@@ -259,7 +261,8 @@ If you would like to include related resources in your response, you may add the
];
}
-> {tip} If you would like to include relationships only when they have already been loaded, check out the documentation on [conditional relationships](#conditional-relationships).
+> **Note**
+> If you would like to include relationships only when they have already been loaded, check out the documentation on [conditional relationships](#conditional-relationships).
#### Resource Collections
@@ -320,12 +323,12 @@ By default, your outermost resource is wrapped in a `data` key when the resource
{
"id": 1,
"name": "Eladio Schroeder Sr.",
- "email": "therese28@example.com",
+ "email": "therese28@example.com"
},
{
"id": 2,
"name": "Liliana Mayert",
- "email": "evandervort@example.com",
+ "email": "evandervort@example.com"
}
]
}
@@ -344,7 +347,7 @@ If you would like to use a custom key instead of `data`, you may define a `$wrap
/**
* The "data" wrapper that should be applied.
*
- * @var string
+ * @var string|null
*/
public static $wrap = 'user';
}
@@ -381,7 +384,8 @@ If you would like to disable the wrapping of the outermost resource, you should
}
}
-> {note} The `withoutWrapping` method only affects the outermost response and will not remove `data` keys that you manually add to your own resource collections.
+> **Warning**
+> The `withoutWrapping` method only affects the outermost response and will not remove `data` keys that you manually add to your own resource collections.
#### Wrapping Nested Resources
@@ -421,12 +425,12 @@ When returning paginated collections via a resource response, Laravel will wrap
{
"id": 1,
"name": "Eladio Schroeder Sr.",
- "email": "therese28@example.com",
+ "email": "therese28@example.com"
},
{
"id": 2,
"name": "Liliana Mayert",
- "email": "evandervort@example.com",
+ "email": "evandervort@example.com"
}
],
"links":{
@@ -467,12 +471,12 @@ Paginated responses always contain `meta` and `links` keys with information abou
{
"id": 1,
"name": "Eladio Schroeder Sr.",
- "email": "therese28@example.com",
+ "email": "therese28@example.com"
},
{
"id": 2,
"name": "Liliana Mayert",
- "email": "evandervort@example.com",
+ "email": "evandervort@example.com"
}
],
"links":{
@@ -556,7 +560,8 @@ Sometimes you may have several attributes that should only be included in the re
Again, if the given condition is `false`, these attributes will be removed from the resource response before it is sent to the client.
-> {note} The `mergeWhen` method should not be used within arrays that mix string and numeric keys. Furthermore, it should not be used within arrays with numeric keys that are not ordered sequentially.
+> **Warning**
+> The `mergeWhen` method should not be used within arrays that mix string and numeric keys. Furthermore, it should not be used within arrays with numeric keys that are not ordered sequentially.
### Conditional Relationships
@@ -587,6 +592,35 @@ The `whenLoaded` method may be used to conditionally load a relationship. In ord
In this example, if the relationship has not been loaded, the `posts` key will be removed from the resource response before it is sent to the client.
+
+#### Conditional Relationship Counts
+
+In addition to conditionally including relationships, you may conditionally include relationship "counts" on your resource responses based on if the relationship's count has been loaded on the model:
+
+ new UserResource($user->loadCount('posts'));
+
+The `whenCounted` method may be used to conditionally include a relationship's count in your resource response. This method avoids unnecessarily including the attribute if the relationships' count is not present:
+
+ /**
+ * Transform the resource into an array.
+ *
+ * @param \Illuminate\Http\Request $request
+ * @return array
+ */
+ public function toArray($request)
+ {
+ return [
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'email' => $this->email,
+ 'posts_count' => $this->whenCounted('posts'),
+ 'created_at' => $this->created_at,
+ 'updated_at' => $this->updated_at,
+ ];
+ }
+
+In this example, if the `posts` relationship's count has not been loaded, the `posts_count` key will be removed from the resource response before it is sent to the client.
+
#### Conditional Pivot Information
diff --git a/eloquent-serialization.md b/eloquent-serialization.md
index e90918ae154..d1fabbef9d6 100644
--- a/eloquent-serialization.md
+++ b/eloquent-serialization.md
@@ -13,7 +13,8 @@
When building APIs using Laravel, you will often need to convert your models and relationships to arrays or JSON. Eloquent includes convenient methods for making these conversions, as well as controlling which attributes are included in the serialized representation of your models.
-> {tip} For an even more robust way of handling Eloquent model and collection JSON serialization, check out the documentation on [Eloquent API resources](/docs/{{version}}/eloquent-resources).
+> **Note**
+> For an even more robust way of handling Eloquent model and collection JSON serialization, check out the documentation on [Eloquent API resources](/docs/{{version}}/eloquent-resources).
## Serializing Models & Collections
@@ -90,7 +91,8 @@ Sometimes you may wish to limit the attributes, such as passwords, that are incl
protected $hidden = ['password'];
}
-> {tip} To hide relationships, add the relationship's method name to your Eloquent model's `$hidden` property.
+> **Note**
+> To hide relationships, add the relationship's method name to your Eloquent model's `$hidden` property.
Alternatively, you may use the `visible` property to define an "allow list" of attributes that should be included in your model's array and JSON representation. All attributes that are not present in the `$visible` array will be hidden when the model is converted to an array or JSON:
diff --git a/eloquent.md b/eloquent.md
index 67fca1ca55c..b0630d6a1c2 100644
--- a/eloquent.md
+++ b/eloquent.md
@@ -41,7 +41,8 @@
Laravel includes Eloquent, an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using Eloquent, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, Eloquent models allow you to insert, update, and delete records from the table as well.
-> {tip} Before getting started, be sure to configure a database connection in your application's `config/database.php` configuration file. For more information on configuring your database, check out [the database configuration documentation](/docs/{{version}}/database#configuration).
+> **Note**
+> Before getting started, be sure to configure a database connection in your application's `config/database.php` configuration file. For more information on configuring your database, check out [the database configuration documentation](/docs/{{version}}/database#configuration).
## Generating Model Classes
@@ -90,6 +91,15 @@ php artisan make:model Flight --all
php artisan make:model Member --pivot
```
+
+#### Inspecting Models
+
+Sometimes it can be difficult to determine all of a model's available attributes and relationships just by skimming its code. Instead, try the `model:show` Artisan command, which provides a convenient overview of all the model's attributes and relations:
+
+```shell
+php artisan model:show Flight
+```
+
## Eloquent Model Conventions
@@ -297,7 +307,8 @@ The Eloquent `all` method will return all of the results in the model's table. H
->take(10)
->get();
-> {tip} Since Eloquent models are query builders, you should review all of the methods provided by Laravel's [query builder](/docs/{{version}}/queries). You may use any of these methods when writing your Eloquent queries.
+> **Note**
+> Since Eloquent models are query builders, you should review all of the methods provided by Laravel's [query builder](/docs/{{version}}/queries). You may use any of these methods when writing your Eloquent queries.
#### Refreshing Models
@@ -401,7 +412,8 @@ Similar to the `lazy` method, the `cursor` method may be used to significantly r
The `cursor` method will only execute a single database query; however, the individual Eloquent models will not be hydrated until they are actually iterated over. Therefore, only one Eloquent model is kept in memory at any given time while iterating over the cursor.
-> {note} Since the `cursor` method only ever holds a single Eloquent model in memory at a time, it cannot eager load relationships. If you need to eager load relationships, consider using [the `lazy` method](#chunking-using-lazy-collections) instead.
+> **Warning**
+> Since the `cursor` method only ever holds a single Eloquent model in memory at a time, it cannot eager load relationships. If you need to eager load relationships, consider using [the `lazy` method](#chunking-using-lazy-collections) instead.
Internally, the `cursor` method uses PHP [generators](https://www.php.net/manual/en/language.generators.overview.php) to implement this functionality:
@@ -615,7 +627,8 @@ Updates can also be performed against models that match a given query. In this e
The `update` method expects an array of column and value pairs representing the columns that should be updated. The `update` method returns the number of affected rows.
-> {note} When issuing a mass update via Eloquent, the `saving`, `saved`, `updating`, and `updated` model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update.
+> **Warning**
+> When issuing a mass update via Eloquent, the `saving`, `saved`, `updating`, and `updated` model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update.
#### Examining Attribute Changes
@@ -766,7 +779,8 @@ If you would like to perform multiple "upserts" in a single query, then you shou
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);
-> {note} All databases except SQL Server require the columns in the second argument of the `upsert` method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the `upsert` method and always uses the "primary" and "unique" indexes of the table to detect existing records.
+> **Warning**
+> All databases except SQL Server require the columns in the second argument of the `upsert` method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the `upsert` method and always uses the "primary" and "unique" indexes of the table to detect existing records.
## Deleting Models
@@ -796,7 +810,8 @@ In the example above, we are retrieving the model from the database before calli
Flight::destroy(collect([1, 2, 3]));
-> {note} The `destroy` method loads each model individually and calls the `delete` method so that the `deleting` and `deleted` events are properly dispatched for each model.
+> **Warning**
+> The `destroy` method loads each model individually and calls the `delete` method so that the `deleting` and `deleted` events are properly dispatched for each model.
#### Deleting Models Using Queries
@@ -805,7 +820,8 @@ Of course, you may build an Eloquent query to delete all models matching your qu
$deleted = Flight::where('active', 0)->delete();
-> {note} When executing a mass delete statement via Eloquent, the `deleting` and `deleted` model events will not be dispatched for the deleted models. This is because the models are never actually retrieved when executing the delete statement.
+> **Warning**
+> When executing a mass delete statement via Eloquent, the `deleting` and `deleted` model events will not be dispatched for the deleted models. This is because the models are never actually retrieved when executing the delete statement.
### Soft Deleting
@@ -824,7 +840,8 @@ In addition to actually removing records from your database, Eloquent can also "
use SoftDeletes;
}
-> {tip} The `SoftDeletes` trait will automatically cast the `deleted_at` attribute to a `DateTime` / `Carbon` instance for you.
+> **Note**
+> The `SoftDeletes` trait will automatically cast the `deleted_at` attribute to a `DateTime` / `Carbon` instance for you.
You should also add the `deleted_at` column to your database table. The Laravel [schema builder](/docs/{{version}}/migrations) contains a helper method to create this column:
@@ -972,7 +989,8 @@ You may test your `prunable` query by executing the `model:prune` command with t
php artisan model:prune --pretend
```
-> {note} Soft deleting models will be permanently deleted (`forceDelete`) if they match the prunable query.
+> **Warning**
+> Soft deleting models will be permanently deleted (`forceDelete`) if they match the prunable query.
#### Mass Pruning
@@ -1074,7 +1092,8 @@ The `Scope` interface requires you to implement one method: `apply`. The `apply`
}
}
-> {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.
+> **Note**
+> 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
@@ -1264,7 +1283,8 @@ The `is` and `isNot` methods are also available when using the `belongsTo`, `has
## Events
-> {tip} Want to broadcast your Eloquent events directly to your client-side application? Check out Laravel's [model event broadcasting](/docs/{{version}}/broadcasting#model-broadcasting).
+> **Note**
+> Want to broadcast your Eloquent events directly to your client-side application? Check out Laravel's [model event broadcasting](/docs/{{version}}/broadcasting#model-broadcasting).
Eloquent models dispatch several events, allowing you to hook into the following moments in a model's lifecycle: `retrieved`, `creating`, `created`, `updating`, `updated`, `saving`, `saved`, `deleting`, `deleted`, `trashed`, `forceDeleted`, `restoring`, `restored`, and `replicating`.
@@ -1297,7 +1317,8 @@ To start listening to model events, define a `$dispatchesEvents` property on you
After defining and mapping your Eloquent events, you may use [event listeners](/docs/{{version}}/events#defining-listeners) to handle the events.
-> {note} When issuing a mass update or delete query via Eloquent, the `saved`, `updated`, `deleting`, and `deleted` model events will not be dispatched for the affected models. This is because the models are never actually retrieved when performing mass updates or deletes.
+> **Warning**
+> When issuing a mass update or delete query via Eloquent, the `saved`, `updated`, `deleting`, and `deleted` model events will not be dispatched for the affected models. This is because the models are never actually retrieved when performing mass updates or deletes.
### Using Closures
@@ -1440,7 +1461,8 @@ Alternatively, you may list your observers within an `$observers` property of yo
User::class => [UserObserver::class],
];
-> {tip} There are additional events an observer can listen to, such as `saving` and `retrieved`. These events are described within the [events](#events) documentation.
+> **Note**
+> There are additional events an observer can listen to, such as `saving` and `retrieved`. These events are described within the [events](#events) documentation.
#### Observers & Database Transactions
@@ -1497,3 +1519,9 @@ Sometimes you may wish to "save" a given model without dispatching any events. Y
$user->name = 'Victoria Faith';
$user->saveQuietly();
+
+You may also "update", "delete", "soft delete", "restore", and "replicate" a given model without dispatching any events:
+
+ $user->deleteQuietly();
+
+ $user->restoreQuietly();
diff --git a/envoy.md b/envoy.md
index 88483b61e31..89c0af51c6f 100644
--- a/envoy.md
+++ b/envoy.md
@@ -323,7 +323,7 @@ Envoy also supports sending notifications to [Telegram](https://telegram.org) af
### Microsoft Teams
-Envoy also supports sending notifications to [Microsoft Teams](https://www.microsoft.com/en-us/microsoft-teams) after each task is executed. The `@microsoftTeams` directive accepts a Teams Webhook (required), a message, theme color (success, info, warning, error), and an array of options. You may retrieve your Teams Webook by creating a new [incoming webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook). The Teams API has many other attributes to customize your message box like title, summary, and sections. You can find more information on the [Microsoft Teams documentation](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL#example-of-connector-message). You should pass the entire Webhook URL into the `@microsoftTeams` directive:
+Envoy also supports sending notifications to [Microsoft Teams](https://www.microsoft.com/en-us/microsoft-teams) after each task is executed. The `@microsoftTeams` directive accepts a Teams Webhook (required), a message, theme color (success, info, warning, error), and an array of options. You may retrieve your Teams Webhook by creating a new [incoming webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook). The Teams API has many other attributes to customize your message box like title, summary, and sections. You can find more information on the [Microsoft Teams documentation](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL#example-of-connector-message). You should pass the entire Webhook URL into the `@microsoftTeams` directive:
```blade
@finished
diff --git a/errors.md b/errors.md
index 513c6965dfb..60690789777 100644
--- a/errors.md
+++ b/errors.md
@@ -57,7 +57,8 @@ When you register a custom exception reporting callback using the `reportable` m
return false;
});
-> {tip} To customize the exception reporting for a given exception, you may also utilize [reportable exceptions](/docs/{{version}}/errors#renderable-exceptions).
+> **Note**
+> To customize the exception reporting for a given exception, you may also utilize [reportable exceptions](/docs/{{version}}/errors#renderable-exceptions).
#### Global Log Context
@@ -155,7 +156,8 @@ When building your application, there will be some types of exceptions you simpl
InvalidOrderException::class,
];
-> {tip} Behind the scenes, Laravel already ignores some types of errors for you, such as exceptions resulting from 404 HTTP "not found" errors or 419 HTTP responses generated by invalid CSRF tokens.
+> **Note**
+> Behind the scenes, Laravel already ignores some types of errors for you, such as exceptions resulting from 404 HTTP "not found" errors or 419 HTTP responses generated by invalid CSRF tokens.
### Rendering Exceptions
@@ -229,7 +231,7 @@ Instead of type-checking exceptions in the exception handler's `register` method
*/
public function render($request)
{
- return response(...);
+ return response(/* ... */);
}
}
@@ -262,7 +264,8 @@ If your exception contains custom reporting logic that is only necessary when ce
return false;
}
-> {tip} You may type-hint any required dependencies of the `report` method and they will automatically be injected into the method by Laravel's [service container](/docs/{{version}}/container).
+> **Note**
+> You may type-hint any required dependencies of the `report` method and they will automatically be injected into the method by Laravel's [service container](/docs/{{version}}/container).
## HTTP Exceptions
diff --git a/events.md b/events.md
index 4daf335edfa..10faa6c872a 100644
--- a/events.md
+++ b/events.md
@@ -42,7 +42,8 @@ The `App\Providers\EventServiceProvider` included with your Laravel application
],
];
-> {tip} The `event:list` command may be used to display a list of all events and listeners registered by your application.
+> **Note**
+> The `event:list` command may be used to display a list of all events and listeners registered by your application.
### Generating Events & Listeners
@@ -264,7 +265,8 @@ Next, let's take a look at the listener for our example event. Event listeners r
}
}
-> {tip} Your event listeners may also type-hint any dependencies they need on their constructors. All event listeners are resolved via the Laravel [service container](/docs/{{version}}/container), so dependencies will be injected automatically.
+> **Note**
+> Your event listeners may also type-hint any dependencies they need on their constructors. All event listeners are resolved via the Laravel [service container](/docs/{{version}}/container), so dependencies will be injected automatically.
#### Stopping The Propagation Of An Event
@@ -439,7 +441,8 @@ If your queue connection's `after_commit` configuration option is set to `false`
public $afterCommit = true;
}
-> {tip} To learn more about working around these issues, please review the documentation regarding [queued jobs and database transactions](/docs/{{version}}/queues#jobs-and-database-transactions).
+> **Note**
+> To learn more about working around these issues, please review the documentation regarding [queued jobs and database transactions](/docs/{{version}}/queues#jobs-and-database-transactions).
### Handling Failed Jobs
@@ -559,7 +562,8 @@ To dispatch an event, you may call the static `dispatch` method on the event. Th
OrderShipped::dispatchUnless($condition, $order);
-> {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.
+> **Note**
+> 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
index 2b4aec683fa..2a8e9faeb8e 100644
--- a/facades.md
+++ b/facades.md
@@ -304,3 +304,4 @@ Validator | [Illuminate\Validation\Factory](https://laravel.com/api/{{version}
Validator (Instance) | [Illuminate\Validation\Validator](https://laravel.com/api/{{version}}/Illuminate/Validation/Validator.html) |
View | [Illuminate\View\Factory](https://laravel.com/api/{{version}}/Illuminate/View/Factory.html) | `view`
View (Instance) | [Illuminate\View\View](https://laravel.com/api/{{version}}/Illuminate/View/View.html) |
+Vite | [Illuminate\Foundation\Vite](https://laravel.com/api/{{version}}/Illuminate/Foundation/Vite.html) |
diff --git a/filesystem.md b/filesystem.md
index 6a8f2ca9e5e..f1304477a2d 100644
--- a/filesystem.md
+++ b/filesystem.md
@@ -34,7 +34,8 @@ Laravel's filesystem configuration file is located at `config/filesystems.php`.
The `local` driver interacts with files stored locally on the server running the Laravel application while the `s3` driver is used to write to Amazon's S3 cloud storage service.
-> {tip} You may configure as many disks as you like and may even have multiple disks that use the same driver.
+> **Note**
+> You may configure as many disks as you like and may even have multiple disks that use the same driver.
### The Local Driver
@@ -146,7 +147,7 @@ Laravel's Flysystem integrations work great with SFTP; however, a sample configu
By default, your application's `filesystems` configuration file contains a disk configuration for the `s3` disk. In addition to using this disk to interact with Amazon S3, you may use it to interact with any S3 compatible file storage service such as [MinIO](https://github.com/minio/minio) or [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces/).
-Typically, after updating the disk's credentials to match the credentials of the service you are planning to use, you only need to update the value of the `url` configuration option. This option's value is typically defined via the `AWS_ENDPOINT` environment variable:
+Typically, after updating the disk's credentials to match the credentials of the service you are planning to use, you only need to update the value of the `endpoint` configuration option. This option's value is typically defined via the `AWS_ENDPOINT` environment variable:
'endpoint' => env('AWS_ENDPOINT', 'https://minio:9000'),
@@ -218,7 +219,8 @@ You may use the `url` method to get the URL for a given file. If you are using t
When using the `local` driver, all files that should be publicly accessible should be placed in the `storage/app/public` directory. Furthermore, you should [create a symbolic link](#the-public-disk) at `public/storage` which points to the `storage/app/public` directory.
-> {note} When using the `local` driver, the return value of `url` is not URL encoded. For this reason, we recommend always storing your files using names that will create valid URLs.
+> **Warning**
+> When using the `local` driver, the return value of `url` is not URL encoded. For this reason, we recommend always storing your files using names that will create valid URLs.
#### Temporary URLs
@@ -420,7 +422,8 @@ You may also use the `putFileAs` method on the `Storage` facade, which will perf
'avatars', $request->file('avatar'), $request->user()->id
);
-> {note} Unprintable and invalid unicode characters will automatically be removed from file paths. Therefore, you may wish to sanitize your file paths before passing them to Laravel's file storage methods. File paths are normalized using the `League\Flysystem\WhitespacePathNormalizer::normalizePath` method.
+> **Warning**
+> Unprintable and invalid unicode characters will automatically be removed from file paths. Therefore, you may wish to sanitize your file paths before passing them to Laravel's file storage methods. File paths are normalized using the `League\Flysystem\WhitespacePathNormalizer::normalizePath` method.
#### Specifying A Disk
diff --git a/fortify.md b/fortify.md
index 8c17a250d5e..f811d79bc97 100644
--- a/fortify.md
+++ b/fortify.md
@@ -32,7 +32,8 @@
Since Fortify does not provide its own user interface, it is meant to be paired with your own user interface which makes requests to the routes it registers. We will discuss exactly how to make requests to these routes in the remainder of this documentation.
-> {tip} Remember, Fortify is a package that is meant to give you a head start implementing Laravel's authentication features. **You are not required to use it.** You are always free to manually interact with Laravel's authentication services by following the documentation available in the [authentication](/docs/{{version}}/authentication), [password reset](/docs/{{version}}/passwords), and [email verification](/docs/{{version}}/verification) documentation.
+> **Note**
+> Remember, Fortify is a package that is meant to give you a head start implementing Laravel's authentication features. **You are not required to use it.** You are always free to manually interact with Laravel's authentication services by following the documentation available in the [authentication](/docs/{{version}}/authentication), [password reset](/docs/{{version}}/passwords), and [email verification](/docs/{{version}}/verification) documentation.
### What Is Fortify?
@@ -362,7 +363,7 @@ To disable two factor authentication, your application should make a DELETE requ
To begin implementing our application's registration functionality, we need to instruct Fortify how to return our "register" view. Remember, Fortify is a headless authentication library. If you would like a frontend implementation of Laravel's authentication features that are already completed for you, you should use an [application starter kit](/docs/{{version}}/starter-kits).
-All of the Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\Fortify\Fortify` class. Typically, you should call this method from the `boot` method of your `App\Providers\FortifyServiceProvider` class:
+All of Fortify's view rendering logic may be customized using the appropriate methods available via the `Laravel\Fortify\Fortify` class. Typically, you should call this method from the `boot` method of your `App\Providers\FortifyServiceProvider` class:
```php
use Laravel\Fortify\Fortify;
@@ -386,7 +387,7 @@ Fortify will take care of defining the `/register` route that returns this view.
The `/register` endpoint expects a string `name`, string email address / username, `password`, and `password_confirmation` fields. The name of the email / username field should match the `username` configuration value defined within your application's `fortify` configuration file.
-If the registration attempt is successful, Fortify will redirect the user to the URI configured via the `home` configuration option within your application's `fortify` configuration file. If the login request was an XHR request, a 200 HTTP response will be returned.
+If the registration attempt is successful, Fortify will redirect the user to the URI configured via the `home` configuration option within your application's `fortify` configuration file. If the request was an XHR request, a 201 HTTP response will be returned.
If the request was not successful, the user will be redirected back to the registration screen and the validation errors will be available to you via the shared `$errors` [Blade template variable](/docs/{{version}}/validation#quick-displaying-the-validation-errors). Or, in the case of an XHR request, the validation errors will be returned with a 422 HTTP response.
diff --git a/frontend.md b/frontend.md
new file mode 100644
index 00000000000..50174564a90
--- /dev/null
+++ b/frontend.md
@@ -0,0 +1,197 @@
+# Frontend
+
+- [Introduction](#introduction)
+- [Using PHP](#using-php)
+ - [PHP & Blade](#php-and-blade)
+ - [Livewire](#livewire)
+ - [Starter Kits](#php-starter-kits)
+- [Using Vue / React](#using-vue-react)
+ - [Inertia](#inertia)
+ - [Starter Kits](#inertia-starter-kits)
+- [Bundling Assets](#bundling-assets)
+
+
+## Introduction
+
+Laravel is a backend framework that provides all of the features you need to build modern web applications, such as [routing](/docs/{{version}}/routing), [validation](/docs/{{version}}/validation), [caching](/docs/{{version}}/cache), [queues](/docs/{{version}}/queues), [file storage](/docs/{{version}}/filesystem), and more. However, we believe it's important to offer developers a beautiful full-stack experience, including powerful approaches for building your application's frontend.
+
+There are two primary ways to tackle frontend development when building an application with Laravel, and which approach you choose is determined by whether you would like to build your frontend by leveraging PHP or by using JavaScript frameworks such as Vue and React. We'll discuss both of these options below so that you can make an informed decision regarding the best approach to frontend development for your application.
+
+
+## Using PHP
+
+
+### PHP & Blade
+
+In the past, most PHP applications rendered HTML to the browser using simple HTML templates interspersed with PHP `echo` statements which render data that was retrieved from a database during the request:
+
+```blade
+
+
+
+ @endforeach
+{{ $count }}
+
+ Profile
+
+
+
+
+
+@endfor
+```
+
+By default, the `fake` function will utilize the `app.faker_locale` configuration option in your `config/app.php` configuration file; however, you may also specify the locale by passing it to the `fake` function. Each locale will resolve an individual singleton:
+
+ fake('nl_NL')->name()
+
#### `filled()` {.collection-method}
@@ -3600,13 +3769,13 @@ If you would like to manually calculate the number of milliseconds to sleep betw
return retry(5, function () {
// ...
- }, function ($attempt) {
+ }, function ($attempt, $exception) {
return $attempt * 100;
});
For convenience, you may provide an array as the first argument to the `retry` function. This array will be used to determine how many milliseconds to sleep between subsequent attempts:
- return retry([100, 200] function () {
+ return retry([100, 200], function () {
// Sleep for 100ms on first retry, 200ms on second retry...
});
diff --git a/homestead.md b/homestead.md
index b9947fa4a38..5c21eebdf0c 100644
--- a/homestead.md
+++ b/homestead.md
@@ -42,7 +42,8 @@ Laravel strives to make the entire PHP development experience delightful, includ
Homestead runs on any Windows, macOS, or Linux system and includes Nginx, PHP, MySQL, PostgreSQL, Redis, Memcached, Node, and all of the other software you need to develop amazing Laravel applications.
-> {note} If you are using Windows, you may need to enable hardware virtualization (VT-x). It can usually be enabled via your BIOS. If you are using Hyper-V on a UEFI system you may additionally need to disable Hyper-V in order to access VT-x.
+> **Warning**
+> If you are using Windows, you may need to enable hardware virtualization (VT-x). It can usually be enabled via your BIOS. If you are using Hyper-V on a UEFI system you may additionally need to disable Hyper-V in order to access VT-x.
### Included Software
@@ -73,6 +74,7 @@ Homestead runs on any Windows, macOS, or Linux system and includes Nginx, PHP, M
- Sqlite3
- PostgreSQL 13
- Composer
+- Docker
- Node (With Yarn, Bower, Grunt, and Gulp)
- Redis
- Memcached
@@ -105,7 +107,6 @@ Homestead runs on any Windows, macOS, or Linux system and includes Nginx, PHP, M
- Chronograf
- CouchDB
- Crystal & Lucky Framework
-- Docker
- Elasticsearch
- EventStoreDB
- Gearman
@@ -183,7 +184,8 @@ The `provider` key in your `Homestead.yaml` file indicates which Vagrant provide
provider: virtualbox
-> {note} If you are using Apple Silicon, you should add `box: laravel/homestead-arm` to your `Homestead.yaml` file. Apple Silicon requires the Parallels provider.
+> **Warning**
+> If you are using Apple Silicon, you should add `box: laravel/homestead-arm` to your `Homestead.yaml` file. Apple Silicon requires the Parallels provider.
#### Configuring Shared Folders
@@ -196,7 +198,8 @@ folders:
to: /home/vagrant/project1
```
-> {note} Windows users should not use the `~/` path syntax and instead should use the full path to their project, such as `C:\Users\user\Code\project1`.
+> **Warning**
+> Windows users should not use the `~/` path syntax and instead should use the full path to their project, such as `C:\Users\user\Code\project1`.
You should always map individual applications to their own folder mapping instead of mapping a single large directory that contains all of your applications. When you map a folder, the virtual machine must keep track of all disk IO for *every* file in the folder. You may experience reduced performance if you have a large number of files in a folder:
@@ -208,7 +211,8 @@ folders:
to: /home/vagrant/project2
```
-> {note} You should never mount `.` (the current directory) when using Homestead. This causes Vagrant to not map the current folder to `/vagrant` and will break optional features and cause unexpected results while provisioning.
+> **Warning**
+> You should never mount `.` (the current directory) when using Homestead. This causes Vagrant to not map the current folder to `/vagrant` and will break optional features and cause unexpected results while provisioning.
To enable [NFS](https://www.vagrantup.com/docs/synced-folders/nfs.html), you may add a `type` option to your folder mapping:
@@ -219,7 +223,8 @@ folders:
type: "nfs"
```
-> {note} When using NFS on Windows, you should consider installing the [vagrant-winnfsd](https://github.com/winnfsd/vagrant-winnfsd) plug-in. This plug-in will maintain the correct user / group permissions for files and directories within the Homestead virtual machine.
+> **Warning**
+> When using NFS on Windows, you should consider installing the [vagrant-winnfsd](https://github.com/winnfsd/vagrant-winnfsd) plug-in. This plug-in will maintain the correct user / group permissions for files and directories within the Homestead virtual machine.
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:
@@ -246,7 +251,8 @@ sites:
If you change the `sites` property after provisioning the Homestead virtual machine, you should execute the `vagrant reload --provision` command in your terminal to update the Nginx configuration on the virtual machine.
-> {note} Homestead scripts are built to be as idempotent as possible. However, if you are experiencing issues while provisioning you should destroy and rebuild the machine by executing the `vagrant destroy && vagrant up` command.
+> **Warning**
+> Homestead scripts are built to be as idempotent as possible. However, if you are experiencing issues while provisioning you should destroy and rebuild the machine by executing the `vagrant destroy && vagrant up` command.
#### Hostname Resolution
@@ -324,7 +330,6 @@ features:
- chronograf: true
- couchdb: true
- crystal: true
- - docker: true
- elasticsearch:
version: 7.9.0
- eventstore: true
@@ -356,7 +361,8 @@ features:
You may specify a supported version of Elasticsearch, which must be an exact version number (major.minor.patch). The default installation will create a cluster named 'homestead'. You should never give Elasticsearch more than half of the operating system's memory, so make sure your Homestead virtual machine has at least twice the Elasticsearch allocation.
-> {tip} Check out the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current) to learn how to customize your configuration.
+> **Note**
+> Check out the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current) to learn how to customize your configuration.
#### MariaDB
@@ -453,7 +459,8 @@ sites:
to: /home/vagrant/project2/public
```
-> {note} You should ensure that you have configured a [folder mapping](#configuring-shared-folders) for the project's directory before adding the site.
+> **Warning**
+> You should ensure that you have configured a [folder mapping](#configuring-shared-folders) for the project's directory before adding the site.
If Vagrant is not automatically managing your "hosts" file, you may need to add the new site to that file as well. On macOS and Linux, this file is located at `/etc/hosts`. On Windows, it is located at `C:\Windows\System32\drivers\etc\hosts`:
@@ -588,7 +595,8 @@ php81
A `homestead` database is configured for both MySQL and PostgreSQL out of the box. To connect to your MySQL or PostgreSQL database from your host machine's database client, you should connect to `127.0.0.1` on port `33060` (MySQL) or `54320` (PostgreSQL). The username and password for both databases is `homestead` / `secret`.
-> {note} You should only use these non-standard ports when connecting to the databases from your host machine. You will use the default 3306 and 5432 ports in your Laravel application's `database` configuration file since Laravel is running _within_ the virtual machine.
+> **Warning**
+> You should only use these non-standard ports when connecting to the databases from your host machine. You will use the default 3306 and 5432 ports in your Laravel application's `database` configuration file since Laravel is running _within_ the virtual machine.
### Database Backups
@@ -702,7 +710,8 @@ After running the command, you will see an Ngrok screen appear which contains th
share homestead.test -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.
+> **Warning**
+> Remember, Vagrant is inherently insecure and you are exposing your virtual machine to the Internet when running the `share` command.
## Debugging & Profiling
@@ -714,7 +723,8 @@ Homestead includes support for step debugging using [Xdebug](https://xdebug.org)
By default, Xdebug is already running and ready to accept connections. If you need to enable Xdebug on the CLI, execute the `sudo phpenmod xdebug` command within your Homestead virtual machine. Next, follow your IDE's instructions to enable debugging. Finally, configure your browser to trigger Xdebug with an extension or [bookmarklet](https://www.jetbrains.com/phpstorm/marklets/).
-> {note} Xdebug causes PHP to run significantly slower. To disable Xdebug, run `sudo phpdismod xdebug` within your Homestead virtual machine and restart the FPM service.
+> **Warning**
+> Xdebug causes PHP to run significantly slower. To disable Xdebug, run `sudo phpdismod xdebug` within your Homestead virtual machine and restart the FPM service.
#### Autostarting Xdebug
@@ -723,8 +733,9 @@ When debugging functional tests that make requests to the web server, it is easi
```ini
; If Homestead.yaml contains a different subnet for the IP address, this address may be different...
-xdebug.remote_host = 192.168.10.1
-xdebug.remote_autostart = 1
+xdebug.client_host = 192.168.10.1
+xdebug.mode = debug
+xdebug.start_with_request = yes
```
diff --git a/horizon.md b/horizon.md
index 359fabb6902..b4a59566530 100644
--- a/horizon.md
+++ b/horizon.md
@@ -17,7 +17,8 @@
## Introduction
-> {tip} Before digging into Laravel Horizon, you should familiarize yourself with Laravel's base [queue services](/docs/{{version}}/queues). Horizon augments Laravel's queue with additional features that may be confusing if you are not already familiar with the basic queue features offered by Laravel.
+> **Note**
+> Before digging into Laravel Horizon, you should familiarize yourself with Laravel's base [queue services](/docs/{{version}}/queues). Horizon augments Laravel's queue with additional features that may be confusing if you are not already familiar with the basic queue features offered by Laravel.
[Laravel Horizon](https://github.com/laravel/horizon) provides a beautiful dashboard and code-driven configuration for your Laravel powered [Redis queues](/docs/{{version}}/queues). Horizon allows you to easily monitor key metrics of your queue system such as job throughput, runtime, and job failures.
@@ -28,7 +29,8 @@ When using Horizon, all of your queue worker configuration is stored in a single
## Installation
-> {note} Laravel Horizon requires that you use [Redis](https://redis.io) to power your queue. Therefore, you should ensure that your queue connection is set to `redis` in your application's `config/queue.php` configuration file.
+> **Warning**
+> Laravel Horizon requires that you use [Redis](https://redis.io) to power your queue. Therefore, you should ensure that your queue connection is set to `redis` in your application's `config/queue.php` configuration file.
You may install Horizon into your project using the Composer package manager:
@@ -47,7 +49,8 @@ php artisan horizon:install
After publishing Horizon's assets, its primary configuration file will be located at `config/horizon.php`. This configuration file allows you to configure the queue worker options for your application. Each configuration option includes a description of its purpose, so be sure to thoroughly explore this file.
-> {note} Horizon uses a Redis connection named `horizon` internally. This Redis connection name is reserved and should not be assigned to another Redis connection in the `database.php` configuration file or as the value of the `use` option in the `horizon.php` configuration file.
+> **Warning**
+> Horizon uses a Redis connection named `horizon` internally. This Redis connection name is reserved and should not be assigned to another Redis connection in the `database.php` configuration file or as the value of the `use` option in the `horizon.php` configuration file.
#### Environments
@@ -72,7 +75,8 @@ After installation, the primary Horizon configuration option that you should fam
When you start Horizon, it will use the worker process configuration options for the environment that your application is running on. Typically, the environment is determined by the value of the `APP_ENV` [environment variable](/docs/{{version}}/configuration#determining-the-current-environment). For example, the default `local` Horizon environment is configured to start three worker processes and automatically balance the number of worker processes assigned to each queue. The default `production` environment is configured to start a maximum of 10 worker processes and automatically balance the number of worker processes assigned to each queue.
-> {note} You should ensure that the `environments` portion of your `horizon` configuration file contains an entry for each [environment](/docs/{{version}}/configuration#environment-configuration) on which you plan to run Horizon.
+> **Warning**
+> You should ensure that the `environments` portion of your `horizon` configuration file contains an entry for each [environment](/docs/{{version}}/configuration#environment-configuration) on which you plan to run Horizon.
#### Supervisors
@@ -112,9 +116,9 @@ When using the `auto` strategy, you may define the `minProcesses` and `maxProces
],
],
-The `balanceMaxShift` and `balanceCooldown` configuration values to determine how quickly Horizon will scale to meet worker demand. In the example above, a maximum of one new process will be created or destroyed every three seconds. You are free to tweak these values as necessary based on your application's needs.
+The `balanceMaxShift` and `balanceCooldown` configuration values determine how quickly Horizon will scale to meet worker demand. In the example above, a maximum of one new process will be created or destroyed every three seconds. You are free to tweak these values as necessary based on your application's needs.
-When the `balance` option is set to `false`, the default Laravel behavior will be used, which processes queues in the order they are listed in your configuration.
+When the `balance` option is set to `false`, the default Laravel behavior will be used, wherein queues are processed in the order they are listed in your configuration.
### Dashboard Authorization
@@ -220,7 +224,8 @@ Supervisor is a process monitor for the Linux operating system and will automati
sudo apt-get install supervisor
```
-> {tip} If configuring Supervisor yourself sounds overwhelming, consider using [Laravel Forge](https://forge.laravel.com), which will automatically install and configure Supervisor for your Laravel projects.
+> **Note**
+> If configuring Supervisor yourself sounds overwhelming, consider using [Laravel Forge](https://forge.laravel.com), which will automatically install and configure Supervisor for your Laravel projects.
#### Supervisor Configuration
@@ -241,7 +246,8 @@ stopwaitsecs=3600
When defining your Supervisor configuration, you should ensure that the value of `stopwaitsecs` is greater than the number of seconds consumed by your longest running job. Otherwise, Supervisor may kill the job before it is finished processing.
-> {note} While the examples above are valid for Ubuntu based servers, the location and file extension expected of Supervisor configuration files may vary between other server operating systems. Please consult your server's documentation for more information.
+> **Warning**
+> While the examples above are valid for Ubuntu based servers, the location and file extension expected of Supervisor configuration files may vary between other server operating systems. Please consult your server's documentation for more information.
#### Starting Supervisor
@@ -256,7 +262,8 @@ sudo supervisorctl update
sudo supervisorctl start horizon
```
-> {tip} For more information on running Supervisor, consult the [Supervisor documentation](http://supervisord.org/index.html).
+> **Note**
+> For more information on running Supervisor, consult the [Supervisor documentation](http://supervisord.org/index.html).
## Tags
@@ -337,7 +344,8 @@ If you would like to manually define the tags for one of your queueable objects,
## Notifications
-> {note} When configuring Horizon to send Slack or SMS notifications, you should review the [prerequisites for the relevant notification channel](/docs/{{version}}/notifications).
+> **Warning**
+> When configuring Horizon to send Slack or SMS notifications, you should review the [prerequisites for the relevant notification channel](/docs/{{version}}/notifications).
If you would like to be notified when one of your queues has a long wait time, you may use the `Horizon::routeMailNotificationsTo`, `Horizon::routeSlackNotificationsTo`, and `Horizon::routeSmsNotificationsTo` methods. You may call these methods from the `boot` method of your application's `App\Providers\HorizonServiceProvider`:
diff --git a/http-client.md b/http-client.md
index 41bfd85bd8b..805e30d2b8e 100644
--- a/http-client.md
+++ b/http-client.md
@@ -8,6 +8,7 @@
- [Timeout](#timeout)
- [Retries](#retries)
- [Error Handling](#error-handling)
+ - [Guzzle Middleware](#guzzle-middleware)
- [Guzzle Options](#guzzle-options)
- [Concurrent Requests](#concurrent-requests)
- [Macros](#macros)
@@ -148,45 +149,45 @@ For convenience, you may use the `acceptJson` method to quickly specify that you
You may specify basic and digest authentication credentials using the `withBasicAuth` and `withDigestAuth` methods, respectively:
// Basic authentication...
- $response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(...);
+ $response = Http::withBasicAuth('taylor@laravel.com', 'secret')->post(/* ... */);
// Digest authentication...
- $response = Http::withDigestAuth('taylor@laravel.com', 'secret')->post(...);
+ $response = Http::withDigestAuth('taylor@laravel.com', 'secret')->post(/* ... */);
#### Bearer Tokens
If you would like to quickly add a bearer token to the request's `Authorization` header, you may use the `withToken` method:
- $response = Http::withToken('token')->post(...);
+ $response = Http::withToken('token')->post(/* ... */);
### Timeout
The `timeout` method may be used to specify the maximum number of seconds to wait for a response:
- $response = Http::timeout(3)->get(...);
+ $response = Http::timeout(3)->get(/* ... */);
If the given timeout is exceeded, an instance of `Illuminate\Http\Client\ConnectionException` will be thrown.
You may specify the maximum number of seconds to wait while trying to connect to a server using the `connectTimeout` method:
- $response = Http::connectTimeout(3)->get(...);
+ $response = Http::connectTimeout(3)->get(/* ... */);
### Retries
-If you would like HTTP client to automatically retry the request if a client or server error occurs, you may use the `retry` method. The `retry` method accepts the maximum number of times the request should be attempted and the number of milliseconds that Laravel should wait in between attempts:
+If you would like the HTTP client to automatically retry the request if a client or server error occurs, you may use the `retry` method. The `retry` method accepts the maximum number of times the request should be attempted and the number of milliseconds that Laravel should wait in between attempts:
- $response = Http::retry(3, 100)->post(...);
+ $response = Http::retry(3, 100)->post(/* ... */);
If needed, you may pass a third argument to the `retry` method. The third argument should be a callable that determines if the retries should actually be attempted. For example, you may wish to only retry the request if the initial request encounters an `ConnectionException`:
$response = Http::retry(3, 100, function ($exception, $request) {
return $exception instanceof ConnectionException;
- })->post(...);
+ })->post(/* ... */);
-If a request attempt fails, you may wish to make a change to the request before a new attempt is made. You can achieve this by modifying request argument provided to the callable you provided to the `retry` method. For example, you might want to retry the request with a new authorization token if the first attempt returned an authentication error:
+If a request attempt fails, you may wish to make a change to the request before a new attempt is made. You can achieve this by modifying the request argument provided to the callable you provided to the `retry` method. For example, you might want to retry the request with a new authorization token if the first attempt returned an authentication error:
$response = Http::withToken($this->getToken())->retry(2, 0, function ($exception, $request) {
if (! $exception instanceof RequestException || $exception->response->status() !== 401) {
@@ -196,13 +197,14 @@ If a request attempt fails, you may wish to make a change to the request before
$request->withToken($this->getNewToken());
return true;
- })->post(...);
+ })->post(/* ... */);
If all of the requests fail, an instance of `Illuminate\Http\Client\RequestException` will be thrown. If you would like to disable this behavior, you may provide a `throw` argument with a value of `false`. When disabled, the last response received by the client will be returned after all retries have been attempted:
- $response = Http::retry(3, 100, throw: false)->post(...);
+ $response = Http::retry(3, 100, throw: false)->post(/* ... */);
-> {note} If all of the requests fail because of a connection issue, a `Illuminate\Http\Client\ConnectionException` will still be thrown even when the `throw` argument is set to `false`.
+> **Warning**
+> If all of the requests fail because of a connection issue, a `Illuminate\Http\Client\ConnectionException` will still be thrown even when the `throw` argument is set to `false`.
### Error Handling
@@ -229,13 +231,16 @@ Unlike Guzzle's default behavior, Laravel's HTTP client wrapper does not throw e
If you have a response instance and would like to throw an instance of `Illuminate\Http\Client\RequestException` if the response status code indicates a client or server error, you may use the `throw` or `throwIf` methods:
- $response = Http::post(...);
+ $response = Http::post(/* ... */);
// Throw an exception if a client or server error occurred...
$response->throw();
// Throw an exception if an error occurred and the given condition is true...
$response->throwIf($condition);
+
+ // Throw an exception if an error occurred and the given condition is false...
+ $response->throwUnless($condition);
return $response['user']['id'];
@@ -243,14 +248,47 @@ The `Illuminate\Http\Client\RequestException` instance has a public `$response`
The `throw` method returns the response instance if no error occurred, allowing you to chain other operations onto the `throw` method:
- return Http::post(...)->throw()->json();
+ return Http::post(/* ... */)->throw()->json();
If you would like to perform some additional logic before the exception is thrown, you may pass a closure to the `throw` method. The exception will be thrown automatically after the closure is invoked, so you do not need to re-throw the exception from within the closure:
- return Http::post(...)->throw(function ($response, $e) {
+ return Http::post(/* ... */)->throw(function ($response, $e) {
//
})->json();
+
+### Guzzle Middleware
+
+Since Laravel's HTTP client is powered by Guzzle, you may take advantage of [Guzzle Middleware](https://docs.guzzlephp.org/en/stable/handlers-and-middleware.html) to manipulate the outgoing request or inspect the incoming response. To manipulate the outgoing request, register a Guzzle middleware via the `withMiddleware` method in combination with Guzzle's `mapRequest` middleware factory:
+
+ use GuzzleHttp\Middleware;
+ use Illuminate\Support\Facades\Http;
+ use Psr\Http\Message\RequestInterface;
+
+ $response = Http::withMiddleware(
+ Middleware::mapRequest(function (RequestInterface $request) {
+ $request->withHeader('X-Example', 'Value');
+
+ return $request;
+ })
+ ->get('http://example.com');
+
+Likewise, you can inspect the incoming HTTP response by registering a middleware via the `withMiddleware` method in combination with Guzzle's `mapResponse` middleware factory:
+
+ use GuzzleHttp\Middleware;
+ use Illuminate\Support\Facades\Http;
+ use Psr\Http\Message\ResponseInterface;
+
+ $response = Http::withMiddleware(
+ Middleware::mapResponse(function (ResponseInterface $response) {
+ $header = $response->getHeader('X-Example');
+
+ // ...
+
+ return $response;
+ })
+ )->get('http://example.com');
+
### Guzzle Options
@@ -336,7 +374,7 @@ For example, to instruct the HTTP client to return empty, `200` status code resp
Http::fake();
- $response = Http::post(...);
+ $response = Http::post(/* ... */);
#### Faking Specific URLs
@@ -374,7 +412,7 @@ Sometimes you may need to specify that a single URL should return a series of fa
->pushStatus(404),
]);
-When all of the responses in a response sequence have been consumed, any further requests will cause the response sequence to throw an exception. If you would like to specify a default response that should be returned when a sequence is empty, you may use the `whenEmpty` method:
+When all the responses in a response sequence have been consumed, any further requests will cause the response sequence to throw an exception. If you would like to specify a default response that should be returned when a sequence is empty, you may use the `whenEmpty` method:
Http::fake([
// Stub a series of responses for GitHub endpoints...
@@ -474,6 +512,45 @@ Or, you may use the `assertNothingSent` method to assert that no requests were s
Http::assertNothingSent();
+
+#### Recording Requests / Responses
+
+You may use the `recorded` method to gather all requests and their corresponding responses. The `recorded` method returns a collection of arrays that contains instances of `Illuminate\Http\Client\Request` and `Illuminate\Http\Client\Response`:
+
+```php
+Http::fake([
+ 'https://laravel.com' => Http::response(status: 500),
+ 'https://nova.laravel.com/' => Http::response(),
+]);
+
+Http::get('https://laravel.com');
+Http::get('https://nova.laravel.com/');
+
+$recorded = Http::recorded();
+
+[$request, $response] = $recorded[0];
+```
+
+Additionally, the `recorded` method accepts a closure which will receive an instance of `Illuminate\Http\Client\Request` and `Illuminate\Http\Client\Response` and may be used to filter request / response pairs based on your expectations:
+
+```php
+use Illuminate\Http\Client\Request;
+use Illuminate\Http\Client\Response;
+
+Http::fake([
+ 'https://laravel.com' => Http::response(status: 500),
+ 'https://nova.laravel.com/' => Http::response(),
+]);
+
+Http::get('https://laravel.com');
+Http::get('https://nova.laravel.com/');
+
+$recorded = Http::recorded(function (Request $request, Response $response) {
+ return $request->url() !== 'https://laravel.com' &&
+ $response->successful();
+});
+```
+
## Events
diff --git a/http-tests.md b/http-tests.md
index a1356d6ae3f..2607a78fc9f 100644
--- a/http-tests.md
+++ b/http-tests.md
@@ -78,7 +78,8 @@ Instead of returning an `Illuminate\Http\Response` instance, test request method
In general, each of your tests should only make one request to your application. Unexpected behavior may occur if multiple requests are executed within a single test method.
-> {tip} For convenience, the CSRF middleware is automatically disabled when running tests.
+> **Note**
+> For convenience, the CSRF middleware is automatically disabled when running tests.
### Customizing Request Headers
@@ -151,7 +152,7 @@ Laravel provides several helpers for interacting with the session during HTTP te
}
}
-Laravel's session is typically used to maintain state for the currently authenticated user. Therefore, the `actingAs` helper method provides a simple way to authenticate a given user as the current user. For example, we may use a [model factory](/docs/{{version}}/database-testing#writing-factories) to generate and authenticate a user:
+Laravel's session is typically used to maintain state for the currently authenticated user. Therefore, the `actingAs` helper method provides a simple way to authenticate a given user as the current user. For example, we may use a [model factory](/docs/{{version}}/eloquent-factories) to generate and authenticate a user:
actingAs($user, 'web')
@@ -278,7 +279,8 @@ In addition, JSON response data may be accessed as array variables on the respon
$this->assertTrue($response['created']);
-> {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.
+> **Note**
+> 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.
#### Asserting Exact JSON Matches
@@ -362,6 +364,7 @@ Laravel also offers a beautiful way to fluently test your application's JSON res
->assertJson(fn (AssertableJson $json) =>
$json->where('id', 1)
->where('name', 'Victoria Faith')
+ ->whereNot('status', 'pending')
->missing('password')
->etc()
);
@@ -373,6 +376,8 @@ In the example above, you may have noticed we invoked the `etc` method at the en
The intention behind this behavior is to protect you from unintentionally exposing sensitive information in your JSON responses by forcing you to either explicitly make an assertion against the attribute or explicitly allow additional attributes via the `etc` method.
+However, you should be aware that not including the `etc` method in your assertion chain does not ensure that additional attributes are not being added to arrays that are nested within your JSON object. The `etc` method only ensures that no additional attributes exist at the nesting level in which the `etc` method is invoked.
+
#### Asserting Attribute Presence / Absence
@@ -586,7 +591,7 @@ If necessary, you may use the `blade` method to evaluate and render a raw [Blade
$view->assertSee('Taylor');
-You may use the `component` method to evaluate and render a [Blade component](/docs/{{version}}/blade#components). Like the `view` method, the `component` method returns an instance of `Illuminate\Testing\TestView`:
+You may use the `component` method to evaluate and render a [Blade component](/docs/{{version}}/blade#components). The `component` method returns an instance of `Illuminate\Testing\TestComponent`:
$view = $this->component(Profile::class, ['name' => 'Taylor']);
@@ -634,6 +639,7 @@ Laravel's `Illuminate\Testing\TestResponse` class provides a variety of custom a
[assertJsonMissingExact](#assert-json-missing-exact)
[assertJsonMissingValidationErrors](#assert-json-missing-validation-errors)
[assertJsonPath](#assert-json-path)
+[assertJsonMissingPath](#assert-json-missing-path)
[assertJsonStructure](#assert-json-structure)
[assertJsonValidationErrors](#assert-json-validation-errors)
[assertJsonValidationErrorFor](#assert-json-validation-error-for)
@@ -694,7 +700,7 @@ Assert that the response contains the given cookie and it is not expired:
#### assertCookieMissing
-Assert that the response does not contains the given cookie:
+Assert that the response does not contain the given cookie:
$response->assertCookieMissing($cookieName);
@@ -812,7 +818,8 @@ Assert that the response has no JSON validation errors for the given keys:
$response->assertJsonMissingValidationErrors($keys);
-> {tip} The more generic [assertValid](#assert-valid) method may be used to assert that a response does not have validation errors that were returned as JSON **and** that no errors were flashed to session storage.
+> **Note**
+> The more generic [assertValid](#assert-valid) method may be used to assert that a response does not have validation errors that were returned as JSON **and** that no errors were flashed to session storage.
#### assertJsonPath
@@ -821,9 +828,9 @@ Assert that the response contains the given data at the specified path:
$response->assertJsonPath($path, $expectedValue);
-For example, if the JSON response returned by your application contains the following data:
+For example, if the following JSON response is returned by your application:
-```js
+```json
{
"user": {
"name": "Steve Schoger"
@@ -835,6 +842,27 @@ You may assert that the `name` property of the `user` object matches a given val
$response->assertJsonPath('user.name', 'Steve Schoger');
+
+#### assertJsonMissingPath
+
+Assert that the response does not contain the given path:
+
+ $response->assertJsonMissingPath($path);
+
+For example, if the following JSON response is returned by your application:
+
+```json
+{
+ "user": {
+ "name": "Steve Schoger"
+ }
+}
+```
+
+You may assert that it does not contain the `email` property of the `user` object:
+
+ $response->assertJsonMissingPath('user.email');
+
#### assertJsonStructure
@@ -844,7 +872,7 @@ Assert that the response has a given JSON structure:
For example, if the JSON response returned by your application contains the following data:
-```js
+```json
{
"user": {
"name": "Steve Schoger"
@@ -862,7 +890,7 @@ You may assert that the JSON structure matches your expectations like so:
Sometimes, JSON responses returned by your application may contain arrays of objects:
-```js
+```json
{
"user": [
{
@@ -898,7 +926,8 @@ Assert that the response has the given JSON validation errors for the given keys
$response->assertJsonValidationErrors(array $data, $responseKey = 'errors');
-> {tip} The more generic [assertInvalid](#assert-invalid) method may be used to assert that a response has validation errors returned as JSON **or** that errors were flashed to session storage.
+> **Note**
+> The more generic [assertInvalid](#assert-invalid) method may be used to assert that a response has validation errors returned as JSON **or** that errors were flashed to session storage.
#### assertJsonValidationErrorFor
@@ -1050,7 +1079,8 @@ Or, you may assert that a given field has a particular validation error message:
'name' => 'The given name was invalid.'
]);
-> {tip} The more generic [assertInvalid](#assert-invalid) method may be used to assert that a response has validation errors returned as JSON **or** that errors were flashed to session storage.
+> **Note**
+> The more generic [assertInvalid](#assert-invalid) method may be used to assert that a response has validation errors returned as JSON **or** that errors were flashed to session storage.
#### assertSessionHasErrorsIn
@@ -1073,7 +1103,8 @@ Assert that the session has no validation errors for the given keys:
$response->assertSessionDoesntHaveErrors($keys = [], $format = null, $errorBag = 'default');
-> {tip} The more generic [assertValid](#assert-valid) method may be used to assert that a response does not have validation errors that were returned as JSON **and** that no errors were flashed to session storage.
+> **Note**
+> The more generic [assertValid](#assert-valid) method may be used to assert that a response does not have validation errors that were returned as JSON **and** that no errors were flashed to session storage.
#### assertSessionMissing
diff --git a/installation.md b/installation.md
index dea895d1500..b5fc846d199 100644
--- a/installation.md
+++ b/installation.md
@@ -3,14 +3,14 @@
- [Meet Laravel](#meet-laravel)
- [Why Laravel?](#why-laravel)
- [Your First Laravel Project](#your-first-laravel-project)
+- [Laravel & Docker](#laravel-and-docker)
- [Getting Started On macOS](#getting-started-on-macos)
- [Getting Started On Windows](#getting-started-on-windows)
- [Getting Started On Linux](#getting-started-on-linux)
- [Choosing Your Sail Services](#choosing-your-sail-services)
- - [Installation Via Composer](#installation-via-composer)
- [Initial Configuration](#initial-configuration)
- [Environment Based Configuration](#environment-based-configuration)
- - [Directory Configuration](#directory-configuration)
+ - [Databases & Migrations](#databases-and-migrations)
- [Next Steps](#next-steps)
- [Laravel The Full Stack Framework](#laravel-the-fullstack-framework)
- [Laravel The API Backend](#laravel-the-api-backend)
@@ -48,13 +48,46 @@ Laravel combines the best packages in the PHP ecosystem to offer the most robust
## Your First Laravel Project
-We want it to be as easy as possible to get started with Laravel. There are a variety of options for developing and running a Laravel project on your local machine. While you may wish to explore these options at a later time, Laravel provides [Sail](/docs/{{version}}/sail), a built-in solution for running your Laravel project using [Docker](https://www.docker.com).
+Before creating your first Laravel project, you should ensure that your local machine has PHP and [Composer](https://getcomposer.org) installed. If you are developing on macOS, PHP and Composer can be installed via [Homebrew](https://brew.sh/). In addition, we recommend [installing Node and NPM](https://nodejs.org).
+
+After you have installed PHP and Composer, you may create a new Laravel project via the Composer `create-project` command:
+
+```nothing
+composer create-project laravel/laravel example-app
+```
+
+Or, you may create new Laravel projects by globally installing the Laravel installer via Composer:
+
+```nothing
+composer global require laravel/installer
+
+laravel new example-app
+```
+
+After the project has been created, start Laravel's local development server using the Laravel's Artisan CLI `serve` command:
+
+```nothing
+cd example-app
+
+php artisan serve
+```
+
+Once you have started the Artisan development server, your application will be accessible in your web browser at `http://localhost:8000`. Next, you're ready to [start taking your next steps into the Laravel ecosystem](#next-steps). Of course, you may also want to [configure a database](#databases-and-migrations).
+
+> **Note**
+> If you would like a head start when developing your Laravel application, consider using one of our [starter kits](/docs/{{version}}/starter-kits). Laravel's starter kits provide backend and frontend authentication scaffolding for your new Laravel application.
+
+
+## Laravel & Docker
+
+We want it to be as easy as possible to get started with Laravel regardless of your preferred operating system. So, there are a variety of options for developing and running a Laravel project on your local machine. While you may wish to explore these options at a later time, Laravel provides [Sail](/docs/{{version}}/sail), a built-in solution for running your Laravel project using [Docker](https://www.docker.com).
Docker is a tool for running applications and services in small, light-weight "containers" which do not interfere with your local machine's installed software or configuration. This means you don't have to worry about configuring or setting up complicated development tools such as web servers and databases on your local machine. To get started, you only need to install [Docker Desktop](https://www.docker.com/products/docker-desktop).
Laravel Sail is a light-weight command-line interface for interacting with Laravel's default Docker configuration. Sail provides a great starting point for building a Laravel application using PHP, MySQL, and Redis without requiring prior Docker experience.
-> {tip} Already a Docker expert? Don't worry! Everything about Sail can be customized using the `docker-compose.yml` file included with Laravel.
+> **Note**
+> Already a Docker expert? Don't worry! Everything about Sail can be customized using the `docker-compose.yml` file included with Laravel.
### Getting Started On macOS
@@ -67,6 +100,8 @@ curl -s "https://laravel.build/example-app" | bash
Of course, you can change "example-app" in this URL to anything you like - just make sure the application name only contains alpha-numeric characters, dashes, and underscores. The Laravel application's directory will be created within the directory you execute the command from.
+Sail installation may take several minutes while Sail's application containers are built on your local machine.
+
After the project has been created, you can navigate to the application directory and start Laravel Sail. Laravel Sail provides a simple command-line interface for interacting with Laravel's default Docker configuration:
```shell
@@ -75,18 +110,18 @@ cd example-app
./vendor/bin/sail up
```
-The first time you run the Sail `up` command, Sail's application containers will be built on your local machine. This could take several minutes. **Don't worry, subsequent attempts to start Sail will be much faster.**
-
Once the application's Docker containers have been started, you can access the application in your web browser at: http://localhost.
-> {tip} To continue learning more about Laravel Sail, review its [complete documentation](/docs/{{version}}/sail).
+> **Note**
+> To continue learning more about Laravel Sail, review its [complete documentation](/docs/{{version}}/sail).
### Getting Started On Windows
Before we create a new Laravel application on your Windows machine, make sure to install [Docker Desktop](https://www.docker.com/products/docker-desktop). Next, you should ensure that Windows Subsystem for Linux 2 (WSL2) is installed and enabled. WSL allows you to run Linux binary executables natively on Windows 10. Information on how to install and enable WSL2 can be found within Microsoft's [developer environment documentation](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
-> {tip} After installing and enabling WSL2, you should ensure that Docker Desktop is [configured to use the WSL2 backend](https://docs.docker.com/docker-for-windows/wsl/).
+> **Note**
+> After installing and enabling WSL2, you should ensure that Docker Desktop is [configured to use the WSL2 backend](https://docs.docker.com/docker-for-windows/wsl/).
Next, you are ready to create your first Laravel project. Launch [Windows Terminal](https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701?rtc=1&activetab=pivot:overviewtab) and begin a new terminal session for your WSL2 Linux operating system. Next, you can use a simple terminal command to create a new Laravel project. For example, to create a new Laravel application in a directory named "example-app", you may run the following command in your terminal:
@@ -96,6 +131,8 @@ curl -s https://laravel.build/example-app | bash
Of course, you can change "example-app" in this URL to anything you like - just make sure the application name only contains alpha-numeric characters, dashes, and underscores. The Laravel application's directory will be created within the directory you execute the command from.
+Sail installation may take several minutes while Sail's application containers are built on your local machine.
+
After the project has been created, you can navigate to the application directory and start Laravel Sail. Laravel Sail provides a simple command-line interface for interacting with Laravel's default Docker configuration:
```shell
@@ -104,11 +141,10 @@ cd example-app
./vendor/bin/sail up
```
-The first time you run the Sail `up` command, Sail's application containers will be built on your local machine. This could take several minutes. **Don't worry, subsequent attempts to start Sail will be much faster.**
-
Once the application's Docker containers have been started, you can access the application in your web browser at: http://localhost.
-> {tip} To continue learning more about Laravel Sail, review its [complete documentation](/docs/{{version}}/sail).
+> **Note**
+> To continue learning more about Laravel Sail, review its [complete documentation](/docs/{{version}}/sail).
#### Developing Within WSL2
@@ -127,6 +163,8 @@ curl -s https://laravel.build/example-app | bash
Of course, you can change "example-app" in this URL to anything you like - just make sure the application name only contains alpha-numeric characters, dashes, and underscores. The Laravel application's directory will be created within the directory you execute the command from.
+Sail installation may take several minutes while Sail's application containers are built on your local machine.
+
After the project has been created, you can navigate to the application directory and start Laravel Sail. Laravel Sail provides a simple command-line interface for interacting with Laravel's default Docker configuration:
```shell
@@ -135,11 +173,10 @@ cd example-app
./vendor/bin/sail up
```
-The first time you run the Sail `up` command, Sail's application containers will be built on your local machine. This could take several minutes. **Don't worry, subsequent attempts to start Sail will be much faster.**
-
Once the application's Docker containers have been started, you can access the application in your web browser at: http://localhost.
-> {tip} To continue learning more about Laravel Sail, review its [complete documentation](/docs/{{version}}/sail).
+> **Note**
+> To continue learning more about Laravel Sail, review its [complete documentation](/docs/{{version}}/sail).
### Choosing Your Sail Services
@@ -158,97 +195,52 @@ You may instruct Sail to install a default [Devcontainer](/docs/{{version}}/sail
curl -s "https://laravel.build/example-app?with=mysql,redis&devcontainer" | bash
```
-
-### Installation Via Composer
-
-If your local machine already has PHP and Composer installed, you may create a new Laravel project by using Composer directly. After the application has been created, you may start Laravel's local development server using the Artisan CLI's `serve` command:
-
-```shell
-composer create-project laravel/laravel example-app
-
-cd example-app
-
-php artisan serve
-```
-
-Once you have started the Artisan development server, you may access your application at `http://localhost:8000`.
-
-
-#### The Laravel Installer
-
-Or, you may install the Laravel Installer as a global Composer dependency:
-
-```shell
-composer global require laravel/installer
-
-laravel new example-app
-
-cd example-app
-
-php artisan serve
-```
+
+## Initial Configuration
-Make sure to place Composer's system-wide vendor bin directory in your `$PATH` so the `laravel` executable can be located by your system. This directory exists in different locations based on your operating system; however, some common locations include:
+All of the configuration files for the Laravel framework are stored in the `config` directory. Each option is documented, so feel free to look through the files and get familiar with the options available to you.
-
```
+
+### Attachable Objects
+
+While attaching files to messages via simple string paths is often sufficient, in many cases the attachable entities within your application are represented by classes. For example, if your application is attaching a photo to a message, your application may also have a `Photo` model that represents that photo. When that is the case, wouldn't it be convenient to simply pass the `Photo` model to the `attach` method? Attachable objects allow you to do just that.
+
+To get started, implement the `Illuminate\Contracts\Mail\Attachable` interface on the object that will be attachable to messages. This interface dictates that your class defines a `toMailAttachment` method that returns an `Illuminate\Mail\Attachment` instance:
+
+ view('photos.resized')
+ ->attach($this->photo);
+ }
+
+Of course, attachment data may be stored on a remote file storage service such as Amazon S3. So, Laravel also allows you to generate attachment instances from data that is stored on one of your application's [filesystem disks](/docs/{{version}}/filesystem):
+
+ // Create an attachment from a file on your default disk...
+ return Attachment::fromStorage($this->path);
+
+ // Create an attachment from a file on a specific disk...
+ return Attachment::fromStorageDisk('backblaze', $this->path);
+
+In addition, you may create attachment instances via data that you have in memory. To accomplish this, provide a closure to the `fromData` method. The closure should return the raw data that represents the attachment:
+
+ return Attachment::fromData(fn () => $this->content, 'Photo Name');
+
+Laravel also provides additional methods that you may use to customize your attachments. For example, you may use the `as` and `withMime` methods to customize the file's name and MIME type:
+
+ return Attachment::fromPath('/path/to/file')
+ ->as('Photo Name')
+ ->withMime('image/jpeg');
+
### Tags & Metadata
@@ -566,7 +629,8 @@ Thanks,
@endcomponent
```
-> {tip} Do not use excess indentation when writing Markdown emails. Per Markdown standards, Markdown parsers will render indented content as code blocks.
+> **Note**
+> Do not use excess indentation when writing Markdown emails. Per Markdown standards, Markdown parsers will render indented content as code blocks.
#### Button Component
@@ -770,7 +834,8 @@ Alternatively, you may call the `afterCommit` method from your mailable's constr
}
}
-> {tip} To learn more about working around these issues, please review the documentation regarding [queued jobs and database transactions](/docs/{{version}}/queues#jobs-and-database-transactions).
+> **Note**
+> To learn more about working around these issues, please review the documentation regarding [queued jobs and database transactions](/docs/{{version}}/queues#jobs-and-database-transactions).
## Rendering Mailables
@@ -795,7 +860,8 @@ When designing a mailable's template, it is convenient to quickly preview the re
return new App\Mail\InvoicePaid($invoice);
});
-> {note} [Inline attachments](#inline-attachments) will not be rendered when a mailable is previewed in your browser. To preview these mailables, you should send them to an email testing application such as [MailHog](https://github.com/mailhog/MailHog) or [HELO](https://usehelo.com).
+> **Warning**
+> [Inline attachments](#inline-attachments) will not be rendered when a mailable is previewed in your browser. To preview these mailables, you should send them to an email testing application such as [MailHog](https://github.com/mailhog/MailHog) or [HELO](https://usehelo.com).
## Localizing Mailables
@@ -987,7 +1053,7 @@ Once you've defined your custom transport, you may register it via the `extend`
public function boot()
{
Mail::extend('mailchimp', function (array $config = []) {
- return new MailchimpTransport(...);
+ return new MailchimpTransport(/* ... */);
})
}
diff --git a/middleware.md b/middleware.md
index e911ce65e90..aa66de2de4f 100644
--- a/middleware.md
+++ b/middleware.md
@@ -57,7 +57,8 @@ As you can see, if the given `token` does not match our secret token, the middle
It's best to envision middleware as a series of "layers" HTTP requests must pass through before they hit your application. Each layer can examine the request and even reject it entirely.
-> {tip} All middleware are resolved via the [service container](/docs/{{version}}/container), so you may type-hint any dependencies you need within a middleware's constructor.
+> **Note**
+> All middleware are resolved via the [service container](/docs/{{version}}/container), so you may type-hint any dependencies you need within a middleware's constructor.
@@ -215,7 +216,8 @@ Middleware groups may be assigned to routes and controller actions using the sam
//
});
-> {tip} Out of the box, the `web` and `api` middleware groups are automatically applied to your application's corresponding `routes/web.php` and `routes/api.php` files by the `App\Providers\RouteServiceProvider`.
+> **Note**
+> Out of the box, the `web` and `api` middleware groups are automatically applied to your application's corresponding `routes/web.php` and `routes/api.php` files by the `App\Providers\RouteServiceProvider`.
### Sorting Middleware
diff --git a/migrations.md b/migrations.md
index 69839e37bdc..8120e92fc27 100644
--- a/migrations.md
+++ b/migrations.md
@@ -43,7 +43,8 @@ Laravel will use the name of the migration to attempt to guess the name of the t
If you would like to specify a custom path for the generated migration, you may use the `--path` option when executing the `make:migration` command. The given path should be relative to your application's base path.
-> {tip} Migration stubs may be customized using [stub publishing](/docs/{{version}}/artisan#stub-customization).
+> **Note**
+> Migration stubs may be customized using [stub publishing](/docs/{{version}}/artisan#stub-customization).
### Squashing Migrations
@@ -61,7 +62,8 @@ When you execute this command, Laravel will write a "schema" file to your applic
You should commit your database schema file to source control so that other new developers on your team may quickly create your application's initial database structure.
-> {note} Migration squashing is only available for the MySQL, PostgreSQL, and SQLite databases and utilizes the database's command-line client. Schema dumps may not be restored to in-memory SQLite databases.
+> **Warning**
+> Migration squashing is only available for the MySQL, PostgreSQL, and SQLite databases and utilizes the database's command-line client. Schema dumps may not be restored to in-memory SQLite databases.
## Migration Structure
@@ -141,6 +143,12 @@ If you would like to see which migrations have run thus far, you may use the `mi
php artisan migrate:status
```
+If you would like to see the SQL statements that will be executed by the migrations without actually running them, you may provide the `--pretend` flag to the `migrate` command:
+
+```shell
+php artisan migrate --pretend
+```
+
#### Forcing Migrations To Run In Production
@@ -200,7 +208,8 @@ php artisan migrate:fresh
php artisan migrate:fresh --seed
```
-> {note} The `migrate:fresh` command will drop all database tables regardless of their prefix. This command should be used with caution when developing on a database that is shared with other applications.
+> **Warning**
+> The `migrate:fresh` command will drop all database tables regardless of their prefix. This command should be used with caution when developing on a database that is shared with other applications.
## Tables
@@ -269,6 +278,14 @@ The `temporary` method may be used to indicate that the table should be "tempora
// ...
});
+If you would like to add a "comment" to a database table, you may invoke the `comment` method on the table instance. Table comments are currently only supported by MySQL and Postgres:
+
+ Schema::create('calculations', function (Blueprint $table) {
+ $table->comment('Business calculations');
+
+ // ...
+ });
+
### Updating Tables
@@ -927,7 +944,8 @@ The `default` modifier accepts a value or an `Illuminate\Database\Query\Expressi
}
};
-> {note} Support for default expressions depends on your database driver, database version, and the field type. Please refer to your database's documentation.
+> **Warning**
+> Support for default expressions depends on your database driver, database version, and the field type. Please refer to your database's documentation. In addition, it is not possible to combine raw `default` expressions (using `DB::raw`) with column changes via the `change` method.
#### Column Order
@@ -962,7 +980,8 @@ use Illuminate\Database\DBAL\TimestampType;
],
```
-> {note} If your application is using Microsoft SQL Server, please ensure that you install `doctrine/dbal:^3.0`.
+> **Warning**
+> If your application is using Microsoft SQL Server, please ensure that you install `doctrine/dbal:^3.0`.
#### Updating Column Attributes
@@ -979,7 +998,8 @@ We could also modify a column to be nullable:
$table->string('name', 50)->nullable()->change();
});
-> {note} The following column types can be modified: `bigInteger`, `binary`, `boolean`, `char`, `date`, `dateTime`, `dateTimeTz`, `decimal`, `integer`, `json`, `longText`, `mediumText`, `smallInteger`, `string`, `text`, `time`, `unsignedBigInteger`, `unsignedInteger`, `unsignedSmallInteger`, and `uuid`. To modify a `timestamp` column type a [Doctrine type must be registered](#prerequisites).
+> **Warning**
+> The following column types can be modified: `bigInteger`, `binary`, `boolean`, `char`, `date`, `dateTime`, `dateTimeTz`, `decimal`, `integer`, `json`, `longText`, `mediumText`, `smallInteger`, `string`, `text`, `time`, `unsignedBigInteger`, `unsignedInteger`, `unsignedSmallInteger`, and `uuid`. To modify a `timestamp` column type a [Doctrine type must be registered](#prerequisites).
#### Renaming Columns
@@ -990,7 +1010,8 @@ To rename a column, you may use the `renameColumn` method provided by the schema
$table->renameColumn('from', 'to');
});
-> {note} Renaming an `enum` column is not currently supported.
+> **Warning**
+> Renaming an `enum` column is not currently supported.
### Dropping Columns
@@ -1007,7 +1028,8 @@ You may drop multiple columns from a table by passing an array of column names t
$table->dropColumn(['votes', 'avatar', 'location']);
});
-> {note} Dropping or modifying multiple columns within a single migration while using an SQLite database is not supported.
+> **Warning**
+> Dropping or modifying multiple columns within a single migration while using an SQLite database is not supported.
#### Available Command Aliases
@@ -1179,7 +1201,8 @@ You may enable or disable foreign key constraints within your migrations by usin
Schema::disableForeignKeyConstraints();
-> {note} SQLite disables foreign key constraints by default. When using SQLite, make sure to [enable foreign key support](/docs/{{version}}/database#configuration) in your database configuration before attempting to create them in your migrations. In addition, SQLite only supports foreign keys upon creation of the table and [not when tables are altered](https://www.sqlite.org/omitted.html).
+> **Warning**
+> SQLite disables foreign key constraints by default. When using SQLite, make sure to [enable foreign key support](/docs/{{version}}/database#configuration) in your database configuration before attempting to create them in your migrations. In addition, SQLite only supports foreign keys upon creation of the table and [not when tables are altered](https://www.sqlite.org/omitted.html).
## Events
@@ -1194,4 +1217,3 @@ For convenience, each migration operation will dispatch an [event](/docs/{{versi
| `Illuminate\Database\Events\MigrationEnded` | A single migration has finished executing. |
| `Illuminate\Database\Events\SchemaDumped` | A database schema dump has completed. |
| `Illuminate\Database\Events\SchemaLoaded` | An existing database schema dump has loaded. |
-
diff --git a/mix.md b/mix.md
index 33bea22bf20..803a3181ceb 100644
--- a/mix.md
+++ b/mix.md
@@ -1,23 +1,6 @@
-# Compiling Assets (Mix)
+# Laravel Mix
- [Introduction](#introduction)
-- [Installation & Setup](#installation)
-- [Running Mix](#running-mix)
-- [Working With Stylesheets](#working-with-stylesheets)
- - [Tailwind CSS](#tailwindcss)
- - [PostCSS](#postcss)
- - [Sass](#sass)
- - [URL Processing](#url-processing)
- - [Source Maps](#css-source-maps)
-- [Working With JavaScript](#working-with-scripts)
- - [Vue](#vue)
- - [React](#react)
- - [Vendor Extraction](#vendor-extraction)
- - [Custom Webpack Configuration](#custom-webpack-configuration)
-- [Versioning / Cache Busting](#versioning-and-cache-busting)
-- [Browsersync Reloading](#browsersync-reloading)
-- [Environment Variables](#environment-variables)
-- [Notifications](#notifications)
## Introduction
@@ -33,402 +16,5 @@ mix.js('resources/js/app.js', 'public/js')
If you've ever been confused and overwhelmed about getting started with webpack and asset compilation, you will love Laravel Mix. However, you are not required to use it while developing your application; you are free to use any asset pipeline tool you wish, or even none at all.
-> {tip} If you need a head start building your application with Laravel and [Tailwind CSS](https://tailwindcss.com), check out one of our [application starter kits](/docs/{{version}}/starter-kits).
-
-
-## Installation & Setup
-
-
-#### Installing Node
-
-Before running Mix, you must first ensure that Node.js and NPM are installed on your machine:
-
-```shell
-node -v
-npm -v
-```
-
-You can easily install the latest version of Node and NPM using simple graphical installers from [the official Node website](https://nodejs.org/en/download/). Or, if you are using [Laravel Sail](/docs/{{version}}/sail), you may invoke Node and NPM through Sail:
-
-```shell
-./sail node -v
-./sail npm -v
-```
-
-
-#### Installing Laravel Mix
-
-The only remaining step is to install Laravel Mix. Within a fresh installation of Laravel, you'll find a `package.json` file in the root of your directory structure. The default `package.json` file already includes everything you need to get started using Laravel Mix. Think of this file like your `composer.json` file, except it defines Node dependencies instead of PHP dependencies. You may install the dependencies it references by running:
-
-```shell
-npm install
-```
-
-
-## Running Mix
-
-Mix is a configuration layer on top of [webpack](https://webpack.js.org), so to run your Mix tasks you only need to execute one of the NPM scripts that are included in the default Laravel `package.json` file. When you run the `dev` or `production` scripts, all of your application's CSS and JavaScript assets will be compiled and placed in your application's `public` directory:
-
-```shell
-// Run all Mix tasks...
-npm run dev
-
-// Run all Mix tasks and minify output...
-npm run prod
-```
-
-
-#### Watching Assets For Changes
-
-The `npm run watch` command will continue running in your terminal and watch all relevant CSS and JavaScript files for changes. Webpack will automatically recompile your assets when it detects a change to one of these files:
-
-```shell
-npm run watch
-```
-
-Webpack may not be able to detect your file changes in certain local development environments. If this is the case on your system, consider using the `watch-poll` command:
-
-```shell
-npm run watch-poll
-```
-
-
-## Working With Stylesheets
-
-Your application's `webpack.mix.js` file is your entry point for all asset compilation. Think of it as a light configuration wrapper around [webpack](https://webpack.js.org). Mix tasks can be chained together to define exactly how your assets should be compiled.
-
-
-### Tailwind CSS
-
-[Tailwind CSS](https://tailwindcss.com) is a modern, utility-first framework for building amazing sites without ever leaving your HTML. Let's dig into how to start using it in a Laravel project with Laravel Mix. First, we should install Tailwind using NPM and generate our Tailwind configuration file:
-
-```shell
-npm install
-
-npm install -D tailwindcss
-
-npx tailwindcss init
-```
-
-The `init` command will generate a `tailwind.config.js` file. The `content` section of this file allows you to configure the paths to all of your HTML templates, JavaScript components, and any other source files that contain Tailwind class names so that any CSS classes that are not used within these files will be purged from your production CSS build:
-
-```js
-content: [
- './storage/framework/views/*.php',
- './resources/**/*.blade.php',
- './resources/**/*.js',
- './resources/**/*.vue',
- "./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php",
-],
-```
-
-Next, you should add each of Tailwind's "layers" to your application's `resources/css/app.css` file:
-
-```css
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-```
-
-Once you have configured Tailwind's layers, you are ready to update your application's `webpack.mix.js` file to compile your Tailwind powered CSS:
-
-```js
-mix.js('resources/js/app.js', 'public/js')
- .postCss('resources/css/app.css', 'public/css', [
- require('tailwindcss'),
- ]);
-```
-
-Finally, you should reference your stylesheet in your application's primary layout template. Many applications choose to store this template at `resources/views/layouts/app.blade.php`. In addition, ensure you add the responsive viewport `meta` tag if it's not already present:
-
-```blade
-
- - - - -``` - - -### PostCSS - -[PostCSS](https://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) plugin to automatically apply all necessary CSS3 vendor prefixes. However, you're free to add any additional plugins that are appropriate for your application. - -First, install the desired plugin through NPM and include it in your array of plugins when calling Mix's `postCss` method. The `postCss` method accepts the path to your CSS file as its first argument and the directory where the compiled file should be placed as its second argument: - -```js -mix.postCss('resources/css/app.css', 'public/css', [ - require('postcss-custom-properties') -]); -``` - -Or, you may execute `postCss` with no additional plugins in order to achieve simple CSS compilation and minification: - -```js -mix.postCss('resources/css/app.css', 'public/css'); -``` - - -### Sass - -The `sass` method allows you to compile [Sass](https://sass-lang.com/) into CSS that can be understood by web browsers. The `sass` method accepts the path to your Sass file as its first argument and the directory where the compiled file should be placed as its second argument: - -```js -mix.sass('resources/sass/app.scss', 'public/css'); -``` - -You may compile multiple Sass files into their own respective CSS files and even customize the output directory of the resulting CSS by calling the `sass` method multiple times: - -```js -mix.sass('resources/sass/app.sass', 'public/css') - .sass('resources/sass/admin.sass', 'public/css/admin'); -``` - - -### 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: - -```css -.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: - -```css -.example { - background: url(/images/example.png?d41d8cd98f00b204e9800998ecf8427e); -} -``` - -As useful as this feature may be, your existing folder structure may already be configured in a way you like. If this is the case, you may disable `url()` rewriting like so: - -```js -mix.sass('resources/sass/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: - -```css -.example { - background: url("../images/thing.png"); -} -``` - - -### Source Maps - -Though disabled by default, source maps may be activated by calling the `mix.sourceMaps()` method in your `webpack.mix.js` file. Though it comes with a compile/performance cost, this will provide extra debugging information to your browser's developer tools when using compiled assets: - -```js -mix.js('resources/js/app.js', 'public/js') - .sourceMaps(); -``` - - -#### Style Of Source Mapping - -Webpack offers a variety of [source mapping styles](https://webpack.js.org/configuration/devtool/#devtool). By default, Mix's source mapping style is set to `eval-source-map`, which provides a fast rebuild time. If you want to change the mapping style, you may do so using the `sourceMaps` method: - -```js -let productionSourceMaps = false; - -mix.js('resources/js/app.js', 'public/js') - .sourceMaps(productionSourceMaps, 'source-map'); -``` - - -## Working With JavaScript - -Mix provides several features to help you work with your JavaScript files, such as compiling modern ECMAScript, module bundling, minification, and concatenating plain JavaScript files. Even better, this all works seamlessly, without requiring an ounce of custom configuration: - -```js -mix.js('resources/js/app.js', 'public/js'); -``` - -With this single line of code, you may now take advantage of: - -
- - -### Vue - -Mix will automatically install the Babel plugins necessary for Vue single-file component compilation support when using the `vue` method. No further configuration is required: - -```js -mix.js('resources/js/app.js', 'public/js') - .vue(); -``` - -Once your JavaScript has been compiled, you can reference it in your application: - -```blade -
- - - - -``` - - -### React - -Mix can automatically install the Babel plugins necessary for React support. To get started, add a call to the `react` method: - -```js -mix.js('resources/js/app.jsx', 'public/js') - .react(); -``` - -Behind the scenes, Mix will download and include the appropriate `babel-preset-react` Babel plugin. Once your JavaScript has been compiled, you can reference it in your application: - -```blade -
- - - - -``` - - -### Vendor Extraction - -One potential downside to bundling all of your application-specific JavaScript with your vendor libraries such as React and Vue 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 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: - -```js -mix.js('resources/js/app.js', 'public/js') - .extract(['vue']) -``` - -The `extract` method accepts an array of all libraries or modules that you wish to extract into a `vendor.js` file. Using the snippet above as an example, Mix will generate the following files: - -
-
-To avoid JavaScript errors, be sure to load these files in the proper order:
-
-```html
-
-
-
-```
-
-
-### Custom Webpack Configuration
-
-Occasionally, you may need to manually modify the underlying Webpack configuration. For example, you might have a special loader or plugin that needs to be referenced.
-
-Mix provides a useful `webpackConfig` method that allows you to merge any short Webpack configuration overrides. This is particularly appealing, 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.
-
-```js
-mix.webpackConfig({
- resolve: {
- modules: [
- path.resolve(__dirname, 'vendor/laravel/spark/resources/assets/js')
- ]
- }
-});
-```
-
-
-## 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 automatically handle this for you using the `version` method.
-
-The `version` method will append a unique hash to the filenames of all compiled files, allowing for more convenient cache busting:
-
-```js
-mix.js('resources/js/app.js', 'public/js')
- .version();
-```
-
-After generating the versioned file, you won't know the exact filename. So, you should use Laravel's global `mix` function within your [views](/docs/{{version}}/views) to load the appropriately hashed asset. The `mix` function will automatically determine the current name of the hashed file:
-
-```blade
-
-```
-
-Because versioned files are usually unnecessary in development, you may instruct the versioning process to only run during `npm run prod`:
-
-```js
-mix.js('resources/js/app.js', 'public/js');
-
-if (mix.inProduction()) {
- mix.version();
-}
-```
-
-
-#### Custom Mix Base URLs
-
-If your Mix compiled assets are deployed to a CDN separate from your application, you will need to change the base URL generated by the `mix` function. You may do so by adding a `mix_url` configuration option to your application's `config/app.php` configuration file:
-
- 'mix_url' => env('MIX_ASSET_URL', null)
-
-After configuring the Mix URL, The `mix` function will prefix the configured URL when generating URLs to assets:
-
-```shell
-https://cdn.example.com/js/app.js?id=1964becbdd96414518cd
-```
-
-
-## 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 for this by calling the `mix.browserSync()` method:
-
-```js
-mix.browserSync('laravel.test');
-```
-
-[BrowserSync options](https://browsersync.io/docs/options) may be specified by passing a JavaScript object to the `browserSync` method:
-
-```js
-mix.browserSync({
- proxy: 'laravel.test'
-});
-```
-
-Next, start webpack's development server using the `npm run watch` command. Now, when you modify a script or PHP file you can watch as the browser instantly refreshes the page to reflect your changes.
-
-
-## Environment Variables
-
-You may inject environment variables into your `webpack.mix.js` script by prefixing one of the environment variables in your `.env` file with `MIX_`:
-
-```ini
-MIX_SENTRY_DSN_PUBLIC=http://example.com
-```
-
-After the variable has been defined in your `.env` file, you may access it via the `process.env` object. However, you will need to restart the task if the environment variable's value changes while the task is running:
-
-```js
-process.env.MIX_SENTRY_DSN_PUBLIC
-```
-
-
-## Notifications
-
-When available, Mix will automatically display OS notifications when compiling, giving you instant feedback as to whether the compilation was successful or not. However, there may be instances when you would prefer to disable these notifications. One such example might be triggering Mix on your production server. Notifications may be deactivated using the `disableNotifications` method:
-
-```js
-mix.disableNotifications();
-```
+> **Note**
+> Vite has replaced Laravel Mix in new Laravel installations. For Mix documentation, please visit the [official Laravel Mix](https://laravel-mix.com/) website. If you would like to switch to Vite, please see our [Vite migration guide](https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md#migrating-from-laravel-mix-to-vite).
diff --git a/mocking.md b/mocking.md
index fa65530a1a3..7088307f60c 100644
--- a/mocking.md
+++ b/mocking.md
@@ -123,7 +123,8 @@ We can mock the call to the `Cache` facade by using the `shouldReceive` method,
}
}
-> {note} You should not mock the `Request` facade. Instead, pass the input you desire into the [HTTP testing methods](/docs/{{version}}/http-tests) such as `get` and `post` when running your test. Likewise, instead of mocking the `Config` facade, call the `Config::set` method in your tests.
+> **Warning**
+> You should not mock the `Request` facade. Instead, pass the input you desire into the [HTTP testing methods](/docs/{{version}}/http-tests) such as `get` and `post` when running your test. Likewise, instead of mocking the `Config` facade, call the `Config::set` method in your tests.
### Facade Spies
@@ -177,7 +178,7 @@ You may use the `Bus` facade's `fake` method to prevent jobs from being dispatch
// Assert that a job was dispatched synchronously...
Bus::assertDispatchedSync(AnotherJob::class);
- // Assert that a job was not dipatched synchronously...
+ // Assert that a job was not dispatched synchronously...
Bus::assertNotDispatchedSync(AnotherJob::class);
// Assert that a job was dispatched after the response was sent...
@@ -288,7 +289,8 @@ If you would simply like to assert that an event listener is listening to a give
SendShipmentNotification::class
);
-> {note} After calling `Event::fake()`, no event listeners will be executed. So, if your tests use model factories that rely on events, such as creating a UUID during a model's `creating` event, you should call `Event::fake()` **after** using your factories.
+> **Warning**
+> After calling `Event::fake()`, no event listeners will be executed. So, if your tests use model factories that rely on events, such as creating a UUID during a model's `creating` event, you should call `Event::fake()` **after** using your factories.
#### Faking A Subset Of Events
@@ -312,6 +314,12 @@ If you only want to fake event listeners for a specific set of events, you may p
$order->update([...]);
}
+You may fake all events except for a set of specified events using the `fakeExcept` method:
+
+ Event::fakeExcept([
+ OrderCreated::class,
+ ]);
+
### Scoped Event Fakes
@@ -406,12 +414,15 @@ You may pass a closure to the `assertSent`, `assertNotSent`, `assertQueued`, or
return $mail->order->id === $order->id;
});
-When calling the `Mail` facade's assertion methods, the mailable instance accepted by the provided closure exposes helpful methods for examining the recipients of the mailable:
+When calling the `Mail` facade's assertion methods, the mailable instance accepted by the provided closure exposes helpful methods for examining the mailable:
Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
return $mail->hasTo($user->email) &&
$mail->hasCc('...') &&
- $mail->hasBcc('...');
+ $mail->hasBcc('...') &&
+ $mail->hasReplyTo('...') &&
+ $mail->hasFrom('...') &&
+ $mail->hasSubject('...');
});
You may have noticed that there are two methods for asserting that mail was not sent: `assertNotSent` and `assertNotQueued`. Sometimes you may wish to assert that no mail was sent **or** queued. To accomplish this, you may use the `assertNothingOutgoing` and `assertNotOutgoing` methods:
@@ -464,6 +475,9 @@ After calling the `Notification` facade's `fake` method, you may then assert tha
Notification::assertNotSentTo(
[$user], AnotherNotification::class
);
+
+ // Assert that a given number of notifications were sent...
+ Notification::assertCount(3);
}
}
@@ -539,6 +553,20 @@ You may pass a closure to the `assertPushed` or `assertNotPushed` methods in ord
return $job->order->id === $order->id;
});
+If you only need to fake specific jobs while allowing your other jobs to execute normally, you may pass the class names of the jobs that should be faked to the `fake` method:
+
+ public function test_orders_can_be_shipped()
+ {
+ Queue::fake([
+ ShipOrder::class,
+ ]);
+
+ // Perform order shipping...
+
+ // Assert a job was pushed twice...
+ Queue::assertPushed(ShipOrder::class, 2);
+ }
+
### Job Chains
@@ -606,7 +634,8 @@ The `Storage` facade's `fake` method allows you to easily generate a fake disk t
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. For more information on testing file uploads, you may consult the [HTTP testing documentation's information on file uploads](/docs/{{version}}/http-tests#testing-file-uploads).
-> {note} The `image` method requires the [GD extension](https://www.php.net/manual/en/book.image.php).
+> **Warning**
+> The `image` method requires the [GD extension](https://www.php.net/manual/en/book.image.php).
## Interacting With Time
diff --git a/notifications.md b/notifications.md
index 7ccbcf5ae8b..c674575b599 100644
--- a/notifications.md
+++ b/notifications.md
@@ -52,7 +52,7 @@
## Introduction
-In addition to support for [sending email](/docs/{{version}}/mail), Laravel provides support for sending notifications across a variety of delivery channels, including email, SMS (via [Vonage](https://www.vonage.com/communications-apis/), formerly known as Nexmo), and [Slack](https://slack.com). In addition, a variety of [community built notification channels](https://laravel-notification-channels.com/about/#suggesting-a-new-channel) have been created to send notification over dozens of different channels! Notifications may also be stored in a database so they may be displayed in your web interface.
+In addition to support for [sending email](/docs/{{version}}/mail), Laravel provides support for sending notifications across a variety of delivery channels, including email, SMS (via [Vonage](https://www.vonage.com/communications-apis/), formerly known as Nexmo), and [Slack](https://slack.com). In addition, a variety of [community built notification channels](https://laravel-notification-channels.com/about/#suggesting-a-new-channel) have been created to send notifications over dozens of different channels! Notifications may also be stored in a database so they may be displayed in your web interface.
Typically, notifications should be short, informational messages that notify users of something that occurred in your application. For example, if you are writing a billing application, you might send an "Invoice Paid" notification to your users via the email and SMS channels.
@@ -93,7 +93,8 @@ The `notify` method that is provided by this trait expects to receive a notifica
$user->notify(new InvoicePaid($invoice));
-> {tip} Remember, you may use the `Notifiable` trait on any of your models. You are not limited to only including it on your `User` model.
+> **Note**
+> Remember, you may use the `Notifiable` trait on any of your models. You are not limited to only including it on your `User` model.
### Using The Notification Facade
@@ -113,7 +114,8 @@ You can also send notifications immediately using the `sendNow` method. This met
Every notification class has a `via` method that determines on which channels the notification will be delivered. Notifications may be sent on the `mail`, `database`, `broadcast`, `vonage`, and `slack` channels.
-> {tip} If you would like to use other delivery channels such as Telegram or Pusher, check out the community driven [Laravel Notification Channels website](http://laravel-notification-channels.com).
+> **Note**
+> If you would like to use other delivery channels such as Telegram or Pusher, check out the community driven [Laravel Notification Channels website](http://laravel-notification-channels.com).
The `via` method receives a `$notifiable` instance, which will be an instance of the class to which the notification is being sent. You may use `$notifiable` to determine which channels the notification should be delivered on:
@@ -131,7 +133,8 @@ The `via` method receives a `$notifiable` instance, which will be an instance of
### Queueing Notifications
-> {note} Before queueing notifications you should configure your queue and [start a worker](/docs/{{version}}/queues).
+> **Warning**
+> Before queueing notifications you should configure your queue and [start a worker](/docs/{{version}}/queues).
Sending notifications can take time, especially if the channel needs to make an external API call to deliver the notification. To speed up your application's response time, let your notification be queued by adding the `ShouldQueue` interface and `Queueable` trait to your class. The interface and trait are already imported for all notifications generated using the `make:notification` command, so you may immediately add them to your notification class:
@@ -257,7 +260,8 @@ Alternatively, you may call the `afterCommit` method from your notification's co
}
}
-> {tip} To learn more about working around these issues, please review the documentation regarding [queued jobs and database transactions](/docs/{{version}}/queues#jobs-and-database-transactions).
+> **Note**
+> To learn more about working around these issues, please review the documentation regarding [queued jobs and database transactions](/docs/{{version}}/queues#jobs-and-database-transactions).
#### Determining If A Queued Notification Should Be Sent
@@ -283,9 +287,12 @@ However, if you would like to make the final determination on whether the queued
Sometimes you may need to send a notification to someone who is not stored as a "user" of your application. Using the `Notification` facade's `route` method, you may specify ad-hoc notification routing information before sending the notification:
+ use Illuminate\Broadcasting\Channel;
+
Notification::route('mail', 'taylor@example.com')
->route('vonage', '5555555555')
->route('slack', 'https://hooks.slack.com/services/...')
+ ->route('broadcast', [new Channel('channel-name')])
->notify(new InvoicePaid($invoice));
If you would like to provide the recipient's name when sending an on-demand notification to the `mail` route, you may provide an array that contains the email address as the key and the name as the value of the first element in the array:
@@ -317,22 +324,25 @@ The `MailMessage` class contains a few simple methods to help you build transact
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
+ ->lineIf($this->amount > 0, "Amount paid: {$this->amount}")
->action('View Invoice', $url)
->line('Thank you for using our application!');
}
-> {tip} Note we are using `$this->invoice->id` in our `toMail` method. You may pass any data your notification needs to generate its message into the notification's constructor.
+> **Note**
+> Note we are using `$this->invoice->id` in our `toMail` method. You may pass any data your notification needs to generate its message into the notification's constructor.
In this example, we register a greeting, a line of text, a call to action, and then another line of text. These methods provided by the `MailMessage` object make it simple and fast to format small transactional emails. The mail channel will then translate the message components into a beautiful, responsive HTML email template with a plain-text counterpart. Here is an example of an email generated by the `mail` channel:
-> {tip} When sending mail notifications, be sure to set the `name` configuration option in your `config/app.php` configuration file. This value will be used in the header and footer of your mail notification messages.
+> **Note**
+> When sending mail notifications, be sure to set the `name` configuration option in your `config/app.php` configuration file. This value will be used in the header and footer of your mail notification messages.
-
-#### Other Mail Notification Formatting Options
+
+#### Error Messages
-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:
+Some notifications inform users of errors, such as a failed invoice payment. You may indicate that a mail message is regarding an error by calling the `error` method when building your message. When using the `error` method on a mail message, the call to action button will be red instead of black:
/**
* Get the mail representation of the notification.
@@ -342,12 +352,16 @@ Instead of defining the "lines" of text in the notification class, you may use t
*/
public function toMail($notifiable)
{
- return (new MailMessage)->view(
- 'emails.name', ['invoice' => $this->invoice]
- );
+ return (new MailMessage)
+ ->error()
+ ->subject('Invoice Payment Failed')
+ ->line('...');
}
-You may specify a plain-text view for the mail message by passing the view name as the second element of an array that is given to the `view` method:
+
+#### Other Mail 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.
@@ -358,15 +372,11 @@ You may specify a plain-text view for the mail message by passing the view name
public function toMail($notifiable)
{
return (new MailMessage)->view(
- ['emails.name.html', 'emails.name.plain'],
- ['invoice' => $this->invoice]
+ 'emails.name', ['invoice' => $this->invoice]
);
}
-
-#### Error Messages
-
-Some notifications inform users of errors, such as a failed invoice payment. You may indicate that a mail message is regarding an error by calling the `error` method when building your message. When using the `error` method on a mail message, the call to action button will be red instead of black:
+You may specify a plain-text view for the mail message by passing the view name as the second element of an array that is given to the `view` method:
/**
* Get the mail representation of the notification.
@@ -376,10 +386,10 @@ Some notifications inform users of errors, such as a failed invoice payment. You
*/
public function toMail($notifiable)
{
- return (new MailMessage)
- ->error()
- ->subject('Notification Subject')
- ->line('...');
+ return (new MailMessage)->view(
+ ['emails.name.html', 'emails.name.plain'],
+ ['invoice' => $this->invoice]
+ );
}
@@ -495,6 +505,9 @@ To add attachments to an email notification, use the `attach` method while build
->attach('/path/to/file');
}
+> **Note**
+> The `attach` method offered by notification mail messages also accepts [attachable objects](/docs/{{version}}/mail#attachable-objects). Please consult the comprehensive [attachable object documentation](/docs/{{version}}/mail#attachable-objects) to learn more.
+
When attaching files to a message, you may also specify the display name and / or MIME type by passing an `array` as the second argument to the `attach` method:
/**
@@ -530,6 +543,27 @@ Unlike attaching files in mailable objects, you may not attach a file directly f
->attachFromStorage('/path/to/file');
}
+When necessary, multiple files may be attached to a message using the `attachMany` method:
+
+ /**
+ * Get the mail representation of the notification.
+ *
+ * @param mixed $notifiable
+ * @return \Illuminate\Notifications\Messages\MailMessage
+ */
+ public function toMail($notifiable)
+ {
+ return (new MailMessage)
+ ->greeting('Hello!')
+ ->attachMany([
+ '/path/to/forge.svg',
+ '/path/to/vapor.svg' => [
+ 'as' => 'Logo.svg',
+ 'mime' => 'image/svg+xml',
+ ],
+ ]);
+ }
+
#### Raw Data Attachments
@@ -572,7 +606,6 @@ Some third-party email providers such as Mailgun and Postmark support message "t
If your application is using the Mailgun driver, you may consult Mailgun's documentation for more information on [tags](https://documentation.mailgun.com/en/latest/user_manual.html#tagging-1) and [metadata](https://documentation.mailgun.com/en/latest/user_manual.html#attaching-data-to-messages). Likewise, the Postmark documentation may also be consulted for more information on their support for [tags](https://postmarkapp.com/blog/tags-support-for-smtp) and [metadata](https://postmarkapp.com/support/article/1125-custom-metadata-faq).
If your application is using Amazon SES to send emails, you should use the `metadata` method to attach [SES "tags"](https://docs.aws.amazon.com/ses/latest/APIReference/API_MessageTag.html) to the message.
-Tags and metadata can be added to the `MailMessage` - these are used by your email service for filtering/processing:
### Customizing The Symfony Message
@@ -835,7 +868,8 @@ If you want to retrieve only the "unread" notifications, you may use the `unread
echo $notification->type;
}
-> {tip} To access your notifications from your JavaScript client, you should define a notification controller for your application which returns the notifications for a notifiable entity, such as the current user. You may then make an HTTP request to that controller's URL from your JavaScript client.
+> **Note**
+> To access your notifications from your JavaScript client, you should define a notification controller for your application which returns the notifications for a notifiable entity, such as the current user. You may then make an HTTP request to that controller's URL from your JavaScript client.
### Marking Notifications As Read
@@ -1308,7 +1342,8 @@ When a notification is sent, the `Illuminate\Notifications\Events\NotificationSe
],
];
-> {tip} After registering listeners in your `EventServiceProvider`, use the `event:generate` Artisan command to quickly generate listener classes.
+> **Note**
+> After registering listeners in your `EventServiceProvider`, use the `event:generate` Artisan command to quickly generate listener classes.
Within an event listener, you may access the `notifiable`, `notification`, `channel`, and `response` properties on the event to learn more about the notification recipient or the notification itself:
diff --git a/octane.md b/octane.md
index e660c61182c..6a084e86106 100644
--- a/octane.md
+++ b/octane.md
@@ -46,7 +46,8 @@ php artisan octane:install
## Server Prerequisites
-> {note} Laravel Octane requires [PHP 8.0+](https://php.net/releases/).
+> **Warning**
+> Laravel Octane requires [PHP 8.0+](https://php.net/releases/).
### RoadRunner
@@ -82,7 +83,7 @@ After installing the RoadRunner binary, you may exit your Sail shell session. Yo
Next, update the `command` directive of your application's `docker/supervisord.conf` file so that Sail serves your application using Octane instead of the PHP development server:
```ini
-command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=roadrunner --host=0.0.0.0 --rpc-port=6001 --port=8000
+command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=roadrunner --host=0.0.0.0 --rpc-port=6001 --port=80
```
Finally, ensure the `rr` binary is executable and build your Sail images:
@@ -105,7 +106,8 @@ pecl install swoole
#### Swoole Via Laravel Sail
-> {note} Before serving an Octane application via Sail, ensure you have the latest version of Laravel Sail and execute `./vendor/bin/sail build --no-cache` within your application's root directory.
+> **Warning**
+> Before serving an Octane application via Sail, ensure you have the latest version of Laravel Sail and execute `./vendor/bin/sail build --no-cache` within your application's root directory.
Alternatively, you may develop your Swoole based Octane application using [Laravel Sail](/docs/{{version}}/sail), the official Docker based development environment for Laravel. Laravel Sail includes the Swoole extension by default. However, you will still need to adjust the `supervisor.conf` file used by Sail to keep your application running. To get started, execute the `sail:publish` Artisan command:
@@ -162,7 +164,8 @@ By default, applications running via Octane generate links prefixed with `http:/
### Serving Your Application Via Nginx
-> {tip} If you aren't quite ready to manage your own server configuration or aren't comfortable configuring all of the various services needed to run a robust Laravel Octane application, check out [Laravel Forge](https://forge.laravel.com).
+> **Note**
+> If you aren't quite ready to manage your own server configuration or aren't comfortable configuring all of the various services needed to run a robust Laravel Octane application, check out [Laravel Forge](https://forge.laravel.com).
In production environments, you should serve your Octane application behind a traditional web server such as a Nginx or Apache. Doing so will allow the web server to serve your static assets such as images and stylesheets, as well as manage your SSL certificate termination.
@@ -257,7 +260,7 @@ php artisan octane:start --workers=4 --task-workers=6
### Specifying The Max Request Count
-To help prevent stray memory leaks, Octane can gracefully restart a worker once it has handled a given number of requests. To instruct Octane to do this, you may use the `--max-requests` option:
+To help prevent stray memory leaks, Octane gracefully restarts any worker once it has handled 500 requests. To adjust this number, you may use the `--max-requests` option:
```shell
php artisan octane:start --max-requests=250
@@ -382,7 +385,8 @@ $service->method($request->input('name'));
The global `request` helper will always return the request the application is currently handling and is therefore safe to use within your application.
-> {note} It is acceptable to type-hint the `Illuminate\Http\Request` instance on your controller methods and route closures.
+> **Warning**
+> It is acceptable to type-hint the `Illuminate\Http\Request` instance on your controller methods and route closures.
### Configuration Repository Injection
@@ -453,7 +457,8 @@ While building your application, you should take special care to avoid creating
## Concurrent Tasks
-> {note} This feature requires [Swoole](#swoole).
+> **Warning**
+> This feature requires [Swoole](#swoole).
When using Swoole, you may execute operations concurrently via light-weight background tasks. You may accomplish this using Octane's `concurrently` method. You may combine this method with PHP array destructuring to retrieve the results of each operation:
@@ -477,7 +482,8 @@ php artisan octane:start --workers=4 --task-workers=6
## Ticks & Intervals
-> {note} This feature requires [Swoole](#swoole).
+> **Warning**
+> This feature requires [Swoole](#swoole).
When using Swoole, you may register "tick" operations that will be executed every specified number of seconds. You may register "tick" callbacks via the `tick` method. The first argument provided to the `tick` method should be a string that represents the name of the ticker. The second argument should be a callable that will be invoked at the specified interval.
@@ -499,7 +505,8 @@ Octane::tick('simple-ticker', fn () => ray('Ticking...'))
## The Octane Cache
-> {note} This feature requires [Swoole](#swoole).
+> **Warning**
+> This feature requires [Swoole](#swoole).
When using Swoole, you may leverage the Octane cache driver, which provides read and write speeds of up to 2 million operations per second. Therefore, this cache driver is an excellent choice for applications that need extreme read / write speeds from their caching layer.
@@ -509,7 +516,8 @@ This cache driver is powered by [Swoole tables](https://www.swoole.co.uk/docs/mo
Cache::store('octane')->put('framework', 'Laravel', 30);
```
-> {tip} The maximum number of entries allowed in the Octane cache may be defined in your application's `octane` configuration file.
+> **Note**
+> The maximum number of entries allowed in the Octane cache may be defined in your application's `octane` configuration file.
### Cache Intervals
@@ -527,7 +535,8 @@ Cache::store('octane')->interval('random', function () {
## Tables
-> {note} This feature requires [Swoole](#swoole).
+> **Warning**
+> This feature requires [Swoole](#swoole).
When using Swoole, you may define and interact with your own arbitrary [Swoole tables](https://www.swoole.co.uk/docs/modules/swoole-table). Swoole tables provide extreme performance throughput and the data in these tables can be accessed by all workers on the server. However, the data within them will be lost when the server is restarted.
@@ -555,4 +564,5 @@ Octane::table('example')->set('uuid', [
return Octane::table('example')->get('uuid');
```
-> {note} The column types supported by Swoole tables are: `string`, `int`, and `float`.
+> **Warning**
+> The column types supported by Swoole tables are: `string`, `int`, and `float`.
diff --git a/packages.md b/packages.md
index 6e667aec555..427459334e9 100644
--- a/packages.md
+++ b/packages.md
@@ -11,6 +11,7 @@
- [Translations](#translations)
- [Views](#views)
- [View Components](#view-components)
+ - ["About" Artisan Command](#about-artisan-command)
- [Commands](#commands)
- [Public Assets](#public-assets)
- [Publishing File Groups](#publishing-file-groups)
@@ -107,7 +108,8 @@ Now, when users of your package execute Laravel's `vendor:publish` command, your
$value = config('courier.option');
-> {note} You should not define closures in your configuration files. They can not be serialized correctly when users execute the `config:cache` Artisan command.
+> **Warning**
+> You should not define closures in your configuration files. They can not be serialized correctly when users execute the `config:cache` Artisan command.
#### Default Package Configuration
@@ -128,7 +130,8 @@ The `mergeConfigFrom` method accepts the path to your package's configuration fi
);
}
-> {note} This method only merges the first level of the configuration array. If your users partially define a multi-dimensional configuration array, the missing options will not be merged.
+> **Warning**
+> This method only merges the first level of the configuration array. If your users partially define a multi-dimensional configuration array, the missing options will not be merged.
### Routes
@@ -308,6 +311,23 @@ If your package contains anonymous components, they must be placed within a `com
-> {tip} The array driver is primarily used during [testing](/docs/{{version}}/testing) and prevents the data stored in the session from being persisted.
+> **Note**
+> The array driver is primarily used during [testing](/docs/{{version}}/testing) and prevents the data stored in the session from being persisted.
### Driver Prerequisites
@@ -71,7 +72,8 @@ php artisan migrate
Before using Redis sessions with Laravel, you will need to either install the PhpRedis PHP extension via PECL or install the `predis/predis` package (~1.0) via Composer. For more information on configuring Redis, consult Laravel's [Redis documentation](/docs/{{version}}/redis#configuration).
-> {tip} In the `session` configuration file, the `connection` option may be used to specify which Redis connection is used by the session.
+> **Note**
+> In the `session` configuration file, the `connection` option may be used to specify which Redis connection is used by the session.
## Interacting With The Session
@@ -129,7 +131,8 @@ You may also use the global `session` PHP function to retrieve and store data in
session(['key' => 'value']);
});
-> {tip} There is little practical difference between using the session via an HTTP request instance versus using the global `session` helper. Both methods are [testable](/docs/{{version}}/testing) via the `assertSessionHas` method which is available in all of your test cases.
+> **Note**
+> There is little practical difference between using the session via an HTTP request instance versus using the global `session` helper. Both methods are [testable](/docs/{{version}}/testing) via the `assertSessionHas` method which is available in all of your test cases.
#### Retrieving All Session Data
@@ -243,7 +246,8 @@ If you need to regenerate the session ID and remove all data from the session in
## Session Blocking
-> {note} To utilize session blocking, your application must be using a cache driver that supports [atomic locks](/docs/{{version}}/cache#atomic-locks). Currently, those cache drivers include the `memcached`, `dynamodb`, `redis`, and `database` drivers. In addition, you may not use the `cookie` session driver.
+> **Warning**
+> To utilize session blocking, your application must be using a cache driver that supports [atomic locks](/docs/{{version}}/cache#atomic-locks). Currently, those cache drivers include the `memcached`, `dynamodb`, `redis`, and `database` drivers. In addition, you may not use the `cookie` session driver.
By default, Laravel allows requests using the same session to execute concurrently. So, for example, if you use a JavaScript HTTP library to make two HTTP requests to your application, they will both execute at the same time. For many applications, this is not a problem; however, session data loss can occur in a small subset of applications that make concurrent requests to two different application endpoints which both write data to the session.
@@ -289,7 +293,8 @@ If none of the existing session drivers fit your application's needs, Laravel ma
public function gc($lifetime) {}
}
-> {tip} Laravel does not ship with a directory to contain your extensions. You are free to place them anywhere you like. In this example, we have created an `Extensions` directory to house the `MongoSessionHandler`.
+> **Note**
+> Laravel does not ship with a directory to contain your extensions. You are free to place them anywhere you like. In this example, we have created an `Extensions` directory to house the `MongoSessionHandler`.
Since the purpose of these methods is not readily understandable, let's quickly cover what each of the methods do:
diff --git a/socialite.md b/socialite.md
index 35a352deb3e..88143ae55d9 100644
--- a/socialite.md
+++ b/socialite.md
@@ -16,7 +16,8 @@
In addition to typical, form based authentication, Laravel also provides a simple, convenient way to authenticate with OAuth providers using [Laravel Socialite](https://github.com/laravel/socialite). Socialite currently supports authentication via Facebook, Twitter, LinkedIn, Google, GitHub, GitLab, and Bitbucket.
-> {tip} Adapters for other platforms are available via the community driven [Socialite Providers](https://socialiteproviders.com/) website.
+> **Note**
+> Adapters for other platforms are available via the community driven [Socialite Providers](https://socialiteproviders.com/) website.
## Installation
@@ -45,7 +46,8 @@ These credentials should be placed in your application's `config/services.php` c
'redirect' => 'http://example.com/callback-url',
],
-> {tip} If the `redirect` option contains a relative path, it will automatically be resolved to a fully qualified URL.
+> **Note**
+> If the `redirect` option contains a relative path, it will automatically be resolved to a fully qualified URL.
## Authentication
@@ -95,7 +97,8 @@ Once the user has been retrieved from the OAuth provider, you may determine if t
return redirect('/dashboard');
});
-> {tip} For more information regarding what user information is available from specific OAuth providers, please consult the documentation on [retrieving user details](#retrieving-user-details).
+> **Note**
+> For more information regarding what user information is available from specific OAuth providers, please consult the documentation on [retrieving user details](#retrieving-user-details).
### Access Scopes
@@ -125,7 +128,8 @@ A number of OAuth providers support other optional parameters on the redirect re
->with(['hd' => 'example.com'])
->redirect();
-> {note} When using the `with` method, be careful not to pass any reserved keywords such as `state` or `response_type`.
+> **Warning**
+> When using the `with` method, be careful not to pass any reserved keywords such as `state` or `response_type`.
## Retrieving User Details
@@ -183,4 +187,5 @@ The `stateless` method may be used to disable session state verification. This i
return Socialite::driver('google')->stateless()->user();
-> {note} Stateless authentication is not available for the Twitter OAuth 1.0 driver.
+> **Warning**
+> Stateless authentication is not available for the Twitter OAuth 1.0 driver.
diff --git a/starter-kits.md b/starter-kits.md
index 18f7cce7549..6ce0ab48a72 100644
--- a/starter-kits.md
+++ b/starter-kits.md
@@ -3,6 +3,7 @@
- [Introduction](#introduction)
- [Laravel Breeze](#laravel-breeze)
- [Installation](#laravel-breeze-installation)
+ - [Breeze & Blade](#breeze-and-blade)
- [Breeze & React / Vue](#breeze-and-inertia)
- [Breeze & Next.js / API](#breeze-and-next)
- [Laravel Jetstream](#laravel-jetstream)
@@ -17,51 +18,49 @@ While you are welcome to use these starter kits, they are not required. You are
## Laravel Breeze
-[Laravel Breeze](https://github.com/laravel/breeze) is a minimal, simple implementation of all of Laravel's [authentication features](/docs/{{version}}/authentication), including login, registration, password reset, email verification, and password confirmation. Laravel Breeze's default view layer is made up of simple [Blade templates](/docs/{{version}}/blade) styled with [Tailwind CSS](https://tailwindcss.com).
+[Laravel Breeze](https://github.com/laravel/breeze) is a minimal, simple implementation of all of Laravel's [authentication features](/docs/{{version}}/authentication), including login, registration, password reset, email verification, and password confirmation. Laravel Breeze's default view layer is made up of simple [Blade templates](/docs/{{version}}/blade) styled with [Tailwind CSS](https://tailwindcss.com). Or, Breeze can scaffold your application using Vue or React and [Inertia](https://inertiajs.com).
-Breeze provides a wonderful starting point for beginning a fresh Laravel application and is also great choice for projects that plan to take their Blade templates to the next level with [Laravel Livewire](https://laravel-livewire.com).
+Breeze provides a wonderful starting point for beginning a fresh Laravel application and is also a great choice for projects that plan to take their Blade templates to the next level with [Laravel Livewire](https://laravel-livewire.com).
### Installation
-First, you should [create a new Laravel application](/docs/{{version}}/installation), configure your database, and run your [database migrations](/docs/{{version}}/migrations):
+First, you should [create a new Laravel application](/docs/{{version}}/installation), configure your database, and run your [database migrations](/docs/{{version}}/migrations). Once you have created a new Laravel application, you may install Laravel Breeze using Composer:
```shell
-curl -s https://laravel.build/example-app | bash
-
-cd example-app
-
-php artisan migrate
+composer require laravel/breeze --dev
```
-Once you have created a new Laravel application, you may install Laravel Breeze using Composer:
+Once Breeze is installed, you may scaffold your application using one of the Breeze "stacks" discussed in the documentation below.
-```shell
-composer require laravel/breeze --dev
-```
+
+### Breeze & Blade
+
+After Composer has installed the Laravel Breeze package, you may run the `breeze:install` Artisan command. This command publishes the authentication views, routes, controllers, and other resources to your application. Laravel Breeze publishes all of its code to your application so that you have full control and visibility over its features and implementation.
-After Composer has installed the Laravel Breeze package, you may run the `breeze:install` Artisan command. This command publishes the authentication views, routes, controllers, and other resources to your application. Laravel Breeze publishes all of its code to your application so that you have full control and visibility over its features and implementation. After Breeze is installed, you should also compile your assets so that your application's CSS file is available:
+The default Breeze "stack" is the Blade stack, which utilizes simple [Blade templates](/docs/{{version}}/blade) to render your application's frontend. The Blade stack may be installed by invoking the `breeze:install` command with no other additional arguments. After Breeze's scaffolding is installed, you should also compile your application's frontend assets:
```shell
php artisan breeze:install
+php artisan migrate
npm install
npm run dev
-php artisan migrate
```
Next, you may navigate to your application's `/login` or `/register` URLs in your web browser. All of Breeze's routes are defined within the `routes/auth.php` file.
-> {tip} To learn more about compiling your application's CSS and JavaScript, check out the [Laravel Mix documentation](/docs/{{version}}/mix#running-mix).
+> **Note**
+> To learn more about compiling your application's CSS and JavaScript, check out Laravel's [Vite documentation](/docs/{{version}}/vite#running-vite).
### Breeze & React / Vue
-Laravel Breeze also offers React and Vue scaffolding via an [Inertia.js](https://inertiajs.com) frontend implementation. Inertia allows you to build modern, single-page React and Vue applications using classic server-side routing and controllers.
+Laravel Breeze also offers React and Vue scaffolding via an [Inertia](https://inertiajs.com) frontend implementation. Inertia allows you to build modern, single-page React and Vue applications using classic server-side routing and controllers.
-Inertia lets you enjoy the frontend power of React and Vue combined with the incredible backend productivity of Laravel. To use an Inertia stack, specify `vue` or `react` as your desired stack when executing the `breeze:install` Artisan command:
+Inertia lets you enjoy the frontend power of React and Vue combined with the incredible backend productivity of Laravel and lightning-fast [Vite](https://vitejs.dev) compilation. To use an Inertia stack, specify `vue` or `react` as your desired stack when executing the `breeze:install` Artisan command. After Breeze's scaffolding is installed, you should also compile your application's frontend assets:
```shell
php artisan breeze:install vue
@@ -70,11 +69,16 @@ php artisan breeze:install vue
php artisan breeze:install react
+php artisan migrate
npm install
npm run dev
-php artisan migrate
```
+Next, you may navigate to your application's `/login` or `/register` URLs in your web browser. All of Breeze's routes are defined within the `routes/auth.php` file.
+
+
+#### Server-Side Rendering
+
If you would like Breeze to scaffold support for [Inertia SSR](https://inertiajs.com/server-side-rendering), you may provide the `ssr` option when invoking the `breeze:install` command:
```shell
@@ -105,6 +109,6 @@ Finally, you are ready to pair this backend with the frontend of your choice. A
While Laravel Breeze provides a simple and minimal starting point for building a Laravel application, Jetstream augments that functionality with more robust features and additional frontend technology stacks. **For those brand new to Laravel, we recommend learning the ropes with Laravel Breeze before graduating to Laravel Jetstream.**
-Jetstream provides a beautifully designed application scaffolding for Laravel and includes login, registration, email verification, two-factor authentication, session management, API support via Laravel Sanctum, and optional team management. Jetstream is designed using [Tailwind CSS](https://tailwindcss.com) and offers your choice of [Livewire](https://laravel-livewire.com) or [Inertia.js](https://inertiajs.com) driven frontend scaffolding.
+Jetstream provides a beautifully designed application scaffolding for Laravel and includes login, registration, email verification, two-factor authentication, session management, API support via Laravel Sanctum, and optional team management. Jetstream is designed using [Tailwind CSS](https://tailwindcss.com) and offers your choice of [Livewire](https://laravel-livewire.com) or [Inertia](https://inertiajs.com) driven frontend scaffolding.
Complete documentation for installing Laravel Jetstream can be found within the [official Jetstream documentation](https://jetstream.laravel.com/2.x/introduction.html).
diff --git a/structure.md b/structure.md
index bfb9525cf5c..a7cf692f50b 100644
--- a/structure.md
+++ b/structure.md
@@ -76,7 +76,7 @@ The `resources` directory contains your [views](/docs/{{version}}/views) as well
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 then it is likely that all of your routes will most likely be defined in the `web.php` file.
+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 then all your routes will most likely be defined in the `web.php` file.
The `api.php` file contains routes that the `RouteServiceProvider` places in the `api` middleware group. These routes are intended to be stateless, so requests entering the application through these routes are intended to be authenticated [via tokens](/docs/{{version}}/sanctum) and will not have access to session state.
@@ -110,7 +110,8 @@ The `app` directory contains a variety of additional directories such as `Consol
A variety of other directories will be generated inside the `app` directory as you use the `make` Artisan commands to generate classes. So, for example, the `app/Jobs` directory will not exist until you execute the `make:job` Artisan command to generate a job class.
-> {tip} Many of the classes in the `app` directory can be generated by Artisan via commands. To review the available commands, run the `php artisan list make` command in your terminal.
+> **Note**
+> Many of the classes in the `app` directory can be generated by Artisan via commands. To review the available commands, run the `php artisan list make` command in your terminal.
#### The Broadcasting Directory
diff --git a/telescope.md b/telescope.md
index 3ccf67e1fb1..77d2fd39fe4 100644
--- a/telescope.md
+++ b/telescope.md
@@ -142,7 +142,8 @@ The Telescope dashboard may be accessed at the `/telescope` route. By default, y
});
}
-> {note} You should ensure you change your `APP_ENV` environment variable to `production` in your production environment. Otherwise, your Telescope installation will be publicly available.
+> **Warning**
+> You should ensure you change your `APP_ENV` environment variable to `production` in your production environment. Otherwise, your Telescope installation will be publicly available.
## Upgrading Telescope
diff --git a/testing.md b/testing.md
index 837e0947f58..2545849f6b2 100644
--- a/testing.md
+++ b/testing.md
@@ -57,7 +57,8 @@ php artisan make:test UserTest --pest
php artisan make:test UserTest --unit --pest
```
-> {tip} Test stubs may be customized using [stub publishing](/docs/{{version}}/artisan#stub-customization).
+> **Note**
+> Test stubs may be customized using [stub publishing](/docs/{{version}}/artisan#stub-customization).
Once the test has been generated, you may define test methods as you normally would using [PHPUnit](https://phpunit.de). To run your tests, execute the `vendor/bin/phpunit` or `php artisan test` command from your terminal:
@@ -80,7 +81,8 @@ Once the test has been generated, you may define test methods as you normally wo
}
}
-> {note} If you define your own `setUp` / `tearDown` methods within a test class, be sure to call the respective `parent::setUp()` / `parent::tearDown()` methods on the parent class.
+> **Warning**
+> If you define your own `setUp` / `tearDown` methods within a test class, be sure to call the respective `parent::setUp()` / `parent::tearDown()` methods on the parent class.
## Running Tests
@@ -118,7 +120,8 @@ By default, Laravel will create as many processes as there are available CPU cor
php artisan test --parallel --processes=4
```
-> {note} When running tests in parallel, some PHPUnit options (such as `--do-not-cache-result`) may not be available.
+> **Warning**
+> When running tests in parallel, some PHPUnit options (such as `--do-not-cache-result`) may not be available.
#### Parallel Testing & Databases
@@ -188,7 +191,8 @@ If you would like to access the current parallel process "token" from any other
### Reporting Test Coverage
-> {note} This feature requires [Xdebug](https://xdebug.org) or [PCOV](https://pecl.php.net/package/pcov).
+> **Warning**
+> This feature requires [Xdebug](https://xdebug.org) or [PCOV](https://pecl.php.net/package/pcov).
When running your application tests, you may want to determine whether your test cases are actually covering the application code and how much application code is used when running your tests. To accomplish this, you may provide the `--coverage` option when invoking the `test` command:
diff --git a/upgrade.md b/upgrade.md
index b94b96741ce..a2ea821fbea 100644
--- a/upgrade.md
+++ b/upgrade.md
@@ -37,7 +37,8 @@
#### Estimated Upgrade Time: 30 Minutes
-> {tip} We attempt to document every possible breaking change. Since some of these breaking changes are in obscure parts of the framework only a portion of these changes may actually affect your application. Want to save time? You can use [Laravel Shift](https://laravelshift.com/) to help automate your application upgrades.
+> **Note**
+> We attempt to document every possible breaking change. Since some of these breaking changes are in obscure parts of the framework only a portion of these changes may actually affect your application. Want to save time? You can use [Laravel Shift](https://laravelshift.com/) to help automate your application upgrades.
### Updating Dependencies
@@ -59,7 +60,7 @@ You should update the following dependencies in your application's `composer.jso
-In addition, please replace `facade/ignition` with `"spatie/laravel-ignition": "^1.0"` in your application's `composer.json` file.
+In addition, please replace `facade/ignition` with `"spatie/laravel-ignition": "^1.0"` and `pusher/pusher-php-server` (if applicable) with `"pusher/pusher-php-server": "^5.0"` in your application's `composer.json` file.
Furthermore, the following first-party packages have received new major releases to support Laravel 9.x. If applicable, you should read their individual upgrade guides before upgrading:
@@ -128,6 +129,12 @@ The exception handler's `ignore` method is now `public` instead of `protected`.
public function ignore(string $class);
```
+#### Exception Handler Contract Binding
+
+**Likelihood Of Impact: Very Low**
+
+Previously, in order to override the default Laravel exception handler, custom implementations were bound into the service container using the `\App\Exceptions\Handler::class` type. However, you should now bind custom implementations using the `\Illuminate\Contracts\Debug\ExceptionHandler::class` type.
+
### Blade
#### Lazy Collections & The `$loop` Variable
@@ -449,7 +456,7 @@ The [HTTP client](/docs/{{version}}/http-client) now has a default timeout of 30
If you wish to specify a longer timeout for a given request, you may do so using the `timeout` method:
- $response = Http::timeout(120)->get(...);
+ $response = Http::timeout(120)->get(/* ... */);
#### HTTP Fake & Middleware
@@ -508,7 +515,8 @@ Various SwiftMailer related methods, some of which were undocumented, have been
);
});
-> {note} Please thoroughly review the [Symfony Mailer documentation](https://symfony.com/doc/6.0/mailer.html#creating-sending-messages) for all possible interactions with the `Symfony\Component\Mime\Email` object.
+> **Warning**
+> Please thoroughly review the [Symfony Mailer documentation](https://symfony.com/doc/6.0/mailer.html#creating-sending-messages) for all possible interactions with the `Symfony\Component\Mime\Email` object.
The list below contains a more thorough overview of renamed methods. Many of these methods are low-level methods used to interact with SwiftMailer / Symfony Mailer directly, so may not be commonly used within most Laravel applications:
@@ -584,7 +592,8 @@ Defining stream options for the SMTP transport is no longer supported. Instead,
To learn more about the available configuration options, please review the [Symfony Mailer documentation](https://symfony.com/doc/6.0/mailer.html#transport-setup).
-> {note} In spite of the example above, you are not generally advised to disable SSL verification since it introduces the possibility of "man-in-the-middle" attacks.
+> **Warning**
+> In spite of the example above, you are not generally advised to disable SSL verification since it introduces the possibility of "man-in-the-middle" attacks.
#### SMTP `auth_mode`
diff --git a/valet.md b/valet.md
index b7c6207399b..f49bd01e3a3 100644
--- a/valet.md
+++ b/valet.md
@@ -68,7 +68,8 @@ However, you may extend Valet with your own [custom drivers](#custom-valet-drive
## Installation
-> {note} Valet requires macOS and [Homebrew](https://brew.sh/). Before installation, you should make sure that no other programs such as Apache or Nginx are binding to your local machine's port 80.
+> **Warning**
+> Valet requires macOS and [Homebrew](https://brew.sh/). Before installation, you should make sure that no other programs such as Apache or Nginx are binding to your local machine's port 80.
To get started, you first need to ensure that Homebrew is up to date using the `update` command:
@@ -117,7 +118,8 @@ php@7.2
Once this file has been created, you may simply execute the `valet use` command and the command will determine the site's preferred PHP version by reading the file.
-> {note} Valet only serves one PHP version at a time, even if you have multiple PHP versions installed.
+> **Warning**
+> Valet only serves one PHP version at a time, even if you have multiple PHP versions installed.
#### Database
@@ -270,7 +272,8 @@ valet share
To stop sharing your site, you may press `Control + C`. Sharing your site using Ngrok requires you to [create an Ngrok account](https://dashboard.ngrok.com/signup) and [setup an authentication token](https://dashboard.ngrok.com/get-started/your-authtoken).
-> {tip} You may pass additional Ngrok parameters to the share command, such as `valet share --region=eu`. For more information, consult the [ngrok documentation](https://ngrok.com/docs).
+> **Note**
+> You may pass additional Ngrok parameters to the share command, such as `valet share --region=eu`. For more information, consult the [ngrok documentation](https://ngrok.com/docs).
### Sharing Sites Via Expose
@@ -395,7 +398,8 @@ The `isStaticFile` should determine if the incoming request is for a file that i
return false;
}
-> {note} The `isStaticFile` method will only be called if the `serves` method returns `true` for the incoming request and the request URI is not `/`.
+> **Warning**
+> The `isStaticFile` method will only be called if the `serves` method returns `true` for the incoming request and the request URI is not `/`.
#### The `frontControllerPath` Method
diff --git a/validation.md b/validation.md
index b2259c324d6..5b328a88e54 100644
--- a/validation.md
+++ b/validation.md
@@ -8,6 +8,7 @@
- [Displaying The Validation Errors](#quick-displaying-the-validation-errors)
- [Repopulating Forms](#repopulating-forms)
- [A Note On Optional Fields](#a-note-on-optional-fields)
+ - [Validation Error Response Format](#validation-error-response-format)
- [Form Request Validation](#form-request-validation)
- [Creating Form Requests](#creating-form-requests)
- [Authorizing Form Requests](#authorizing-form-requests)
@@ -28,6 +29,7 @@
- [Validating Arrays](#validating-arrays)
- [Validating Nested Array Input](#validating-nested-array-input)
- [Error Message Indexes & Positions](#error-message-indexes-and-positions)
+- [Validating Files](#validating-files)
- [Validating Passwords](#validating-passwords)
- [Custom Validation Rules](#custom-validation-rules)
- [Using Rule Objects](#using-rule-objects)
@@ -99,7 +101,7 @@ Next, let's take a look at a simple controller that handles incoming requests to
Now we are ready to fill in our `store` method with the logic to validate the new blog post. To do this, we will use the `validate` method provided by the `Illuminate\Http\Request` object. If the validation rules pass, your code will keep executing normally; however, if validation fails, an `Illuminate\Validation\ValidationException` exception will be thrown and the proper error response will automatically be sent back to the user.
-If validation fails during a traditional HTTP request, a redirect response to the previous URL will be generated. If the incoming request is an XHR request, a JSON response containing the validation error messages will be returned.
+If validation fails during a traditional HTTP request, a redirect response to the previous URL will be generated. If the incoming request is an XHR request, a [JSON response containing the validation error messages](#validation-error-response-format) will be returned.
To get a better understanding of the `validate` method, let's jump back into the `store` method:
@@ -195,14 +197,14 @@ So, in our example, the user will be redirected to our controller's `create` met
#### Customizing The Error Messages
-Laravel's built-in validation rules each has an error message that is located in your application's `lang/en/validation.php` file. Within this file, you will find a translation entry for each validation rule. You are free to change or modify these messages based on the needs of your application.
+Laravel's built-in validation rules each have an error message that is located in your application's `lang/en/validation.php` file. Within this file, you will find a translation entry for each validation rule. You are free to change or modify these messages based on the needs of your application.
In addition, you may copy this file to another translation language directory to translate the messages for your application's language. To learn more about Laravel localization, check out the complete [localization documentation](/docs/{{version}}/localization).
#### XHR Requests & Validation
-In this example, we used a traditional form to send data to the application. However, many applications receive XHR requests from a JavaScript powered frontend. When using the `validate` method during an XHR request, Laravel will not generate a redirect response. Instead, Laravel generates a JSON response containing all of the validation errors. This JSON response will be sent with a 422 HTTP status code.
+In this example, we used a traditional form to send data to the application. However, many applications receive XHR requests from a JavaScript powered frontend. When using the `validate` method during an XHR request, Laravel will not generate a redirect response. Instead, Laravel generates a [JSON response containing all of the validation errors](#validation-error-response-format). This JSON response will be sent with a 422 HTTP status code.
#### The `@error` Directive
@@ -258,6 +260,34 @@ By default, Laravel includes the `TrimStrings` and `ConvertEmptyStringsToNull` m
In this example, we are specifying that the `publish_at` field may be either `null` or a valid date representation. If the `nullable` modifier is not added to the rule definition, the validator would consider `null` an invalid date.
+
+### Validation Error Response Format
+
+When your application throws a `Illuminate\Validation\ValidationException` exception and the incoming HTTP request is expecting a JSON response, Laravel will automatically format the error messages for you and return a `422 Unprocessable Entity` HTTP response.
+
+Below, you can review an example of the JSON response format for validation errors. Note that nested error keys are flattened into "dot" notation format:
+
+```json
+{
+ "message": "The team name must be a string. (and 4 more errors)",
+ "errors": {
+ "team_name": [
+ "The team name must be a string.",
+ "The team name must be at least 1 characters."
+ ],
+ "authorization.role": [
+ "The selected authorization.role is invalid."
+ ],
+ "users.0.email": [
+ "The users.0.email field is required."
+ ],
+ "users.2.email": [
+ "The users.2.email must be a valid email address."
+ ]
+ }
+}
+```
+
## Form Request Validation
@@ -287,7 +317,8 @@ As you might have guessed, the `authorize` method is responsible for determining
];
}
-> {tip} You may type-hint any dependencies you require within the `rules` method's signature. They will automatically be resolved via the Laravel [service container](/docs/{{version}}/container).
+> **Note**
+> You may type-hint any dependencies you require within the `rules` method's signature. They will automatically be resolved via the Laravel [service container](/docs/{{version}}/container).
So, how are the validation rules evaluated? All you need to do is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic:
@@ -309,7 +340,7 @@ So, how are the validation rules evaluated? All you need to do is type-hint the
$validated = $request->safe()->except(['name', 'email']);
}
-If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an XHR request, an HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.
+If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an XHR request, an HTTP response with a 422 status code will be returned to the user including a [JSON representation of the validation errors](#validation-error-response-format).
#### Adding After Hooks To Form Requests
@@ -406,7 +437,8 @@ If you plan to handle authorization logic for the request in another part of you
return true;
}
-> {tip} You may type-hint any dependencies you need within the `authorize` method's signature. They will automatically be resolved via the Laravel [service container](/docs/{{version}}/container).
+> **Note**
+> You may type-hint any dependencies you need within the `authorize` method's signature. They will automatically be resolved via the Laravel [service container](/docs/{{version}}/container).
### Customizing The Error Messages
@@ -522,7 +554,7 @@ The `stopOnFirstFailure` method will inform the validator that it should stop va
### Automatic Redirection
-If you would like to create a validator instance manually but still take advantage of the automatic redirection offered by the HTTP request's `validate` method, you may call the `validate` method on an existing validator instance. If validation fails, the user will automatically be redirected or, in the case of an XHR request, a JSON response will be returned:
+If you would like to create a validator instance manually but still take advantage of the automatic redirection offered by the HTTP request's `validate` method, you may call the `validate` method on an existing validator instance. If validation fails, the user will automatically be redirected or, in the case of an XHR request, a [JSON response will be returned](#validation-error-response-format):
Validator::make($request->all(), [
'title' => 'required|unique:posts|max:255',
@@ -590,7 +622,7 @@ Many of Laravel's built-in error messages include an `:attribute` placeholder th
You may also attach callbacks to be run after validation is completed. This allows you to easily perform further validation and even add more error messages to the message collection. To get started, call the `after` method on a validator instance:
- $validator = Validator::make(...);
+ $validator = Validator::make(/* ... */);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
@@ -691,7 +723,7 @@ The `has` method may be used to determine if any error messages exist for a give
### Specifying Custom Messages In Language Files
-Laravel's built-in validation rules each has an error message that is located in your application's `lang/en/validation.php` file. Within this file, you will find a translation entry for each validation rule. You are free to change or modify these messages based on the needs of your application.
+Laravel's built-in validation rules each have an error message that is located in your application's `lang/en/validation.php` file. Within this file, you will find a translation entry for each validation rule. You are free to change or modify these messages based on the needs of your application.
In addition, you may copy this file to another translation language directory to translate the messages for your application's language. To learn more about Laravel localization, check out the complete [localization documentation](/docs/{{version}}/localization).
@@ -791,6 +823,8 @@ Below is a list of all available validation rules and their function:
[Digits Between](#rule-digits-between)
[Dimensions (Image Files)](#rule-dimensions)
[Distinct](#rule-distinct)
+[Doesnt Start With](#rule-doesnt-start-with)
+[Doesnt End With](#rule-doesnt-end-with)
[Email](#rule-email)
[Ends With](#rule-ends-with)
[Enum](#rule-enum)
@@ -814,9 +848,11 @@ Below is a list of all available validation rules and their function:
[Less Than Or Equal](#rule-lte)
[MAC Address](#rule-mac)
[Max](#rule-max)
+[Max Digits](#rule-max-digits)
[MIME Types](#rule-mimetypes)
[MIME Type By File Extension](#rule-mimes)
[Min](#rule-min)
+[Min Digits](#rule-min-digits)
[Multiple Of](#multiple-of)
[Not In](#rule-not-in)
[Not Regex](#rule-not-regex)
@@ -913,7 +949,7 @@ When additional values are provided to the `array` rule, each key in the input a
];
Validator::make($input, [
- 'user' => 'array:username,locale',
+ 'user' => 'array:name,username',
]);
In general, you should always specify the array keys that are allowed to be present within your array.
@@ -942,7 +978,7 @@ The field under validation must be a value preceding or equal to the given date.
#### between:_min_,_max_
-The field under validation must have a size between the given _min_ and _max_. Strings, numerics, arrays, and files are evaluated in the same fashion as the [`size`](#rule-size) rule.
+The field under validation must have a size between the given _min_ and _max_ (inclusive). Strings, numerics, arrays, and files are evaluated in the same fashion as the [`size`](#rule-size) rule.
#### boolean
@@ -994,12 +1030,12 @@ The field under validation must have a different value than _field_.
#### digits:_value_
-The field under validation must be _numeric_ and must have an exact length of _value_.
+The integer under validation must have an exact length of _value_.
#### digits_between:_min_,_max_
-The field under validation must be _numeric_ and must have a length between the given _min_ and _max_.
+The integer validation must have a length between the given _min_ and _max_.
#### dimensions
@@ -1041,6 +1077,16 @@ You may add `ignore_case` to the validation rule's arguments to make the rule ig
'foo.*.id' => 'distinct:ignore_case'
+
+#### doesnt_start_with:_foo_,_bar_,...
+
+The field under validation must not start with one of the given values.
+
+
+#### doesnt_end_with:_foo_,_bar_,...
+
+The field under validation must not end with one of the given values.
+
#### email
@@ -1062,7 +1108,8 @@ The example above will apply the `RFCValidation` and `DNSCheckValidation` valida
The `filter` validator, which uses PHP's `filter_var` function, ships with Laravel and was Laravel's default email validation behavior prior to Laravel version 5.8.
-> {note} The `dns` and `spoof` validators require the PHP `intl` extension.
+> **Warning**
+> The `dns` and `spoof` validators require the PHP `intl` extension.
#### ends_with:_foo_,_bar_,...
@@ -1081,7 +1128,8 @@ The `Enum` rule is a class based rule that validates whether the field under val
'status' => [new Enum(ServerStatus::class)],
]);
-> {note} Enums are only available on PHP 8.1+.
+> **Warning**
+> Enums are only available on PHP 8.1+.
#### exclude
@@ -1219,8 +1267,8 @@ When the `in` rule is combined with the `array` rule, each value in the input ar
'airports' => [
'required',
'array',
- Rule::in(['NYC', 'LIT']),
],
+ 'airports.*' => Rule::in(['NYC', 'LIT']),
]);
@@ -1233,7 +1281,8 @@ The field under validation must exist in _anotherfield_'s values.
The field under validation must be an integer.
-> {note} This validation rule does not verify that the input is of the "integer" variable type, only that the input is of a type accepted by PHP's `FILTER_VALIDATE_INT` rule. If you need to validate the input as being a number please use this rule in combination with [the `numeric` validation rule](#rule-numeric).
+> **Warning**
+> This validation rule does not verify that the input is of the "integer" variable type, only that the input is of a type accepted by PHP's `FILTER_VALIDATE_INT` rule. If you need to validate the input as being a number please use this rule in combination with [the `numeric` validation rule](#rule-numeric).
#### ip
@@ -1275,6 +1324,11 @@ The field under validation must be a MAC address.
The field under validation must be less than or equal to a maximum _value_. Strings, numerics, arrays, and files are evaluated in the same fashion as the [`size`](#rule-size) rule.
+
+#### max_digits:_value_
+
+The integer under validation must have a maximum length of _value_.
+
#### mimetypes:_text/plain_,...
@@ -1303,12 +1357,18 @@ Even though you only need to specify the extensions, this rule actually validate
The field under validation must have a minimum _value_. Strings, numerics, arrays, and files are evaluated in the same fashion as the [`size`](#rule-size) rule.
+
+#### min_digits:_value_
+
+The integer under validation must have a minimum length of _value_.
+
#### multiple_of:_value_
The field under validation must be a multiple of _value_.
-> {note} The [`bcmath` PHP extension](https://www.php.net/manual/en/book.bc.php) is required in order to use the `multiple_of` rule.
+> **Warning**
+> The [`bcmath` PHP extension](https://www.php.net/manual/en/book.bc.php) is required in order to use the `multiple_of` rule.
#### not_in:_foo_,_bar_,...
@@ -1331,7 +1391,8 @@ The field under validation must not match the given regular expression.
Internally, this rule uses the PHP `preg_match` function. The pattern specified should obey the same formatting required by `preg_match` and thus also include valid delimiters. For example: `'email' => 'not_regex:/^.+$/i'`.
-> {note} When using the `regex` / `not_regex` patterns, it may be necessary to specify your validation rules using an array instead of using `|` delimiters, especially if the regular expression contains a `|` character.
+> **Warning**
+> When using the `regex` / `not_regex` patterns, it may be necessary to specify your validation rules using an array instead of using `|` delimiters, especially if the regular expression contains a `|` character.
#### nullable
@@ -1348,7 +1409,8 @@ The field under validation must be [numeric](https://www.php.net/manual/en/funct
The field under validation must match the authenticated user's password.
-> {note} This rule was renamed to `current_password` with the intention of removing it in Laravel 9. Please use the [Current Password](#rule-current-password) rule instead.
+> **Warning**
+> This rule was renamed to `current_password` with the intention of removing it in Laravel 9. Please use the [Current Password](#rule-current-password) rule instead.
#### present
@@ -1358,12 +1420,12 @@ The field under validation must be present in the input data but can be empty.
#### prohibited
-The field under validation must be empty or not present.
+The field under validation must be an empty string or not present.
#### prohibited_if:_anotherfield_,_value_,...
-The field under validation must be empty or not present if the _anotherfield_ field is equal to any _value_.
+The field under validation must be an empty string or not present if the _anotherfield_ field is equal to any _value_.
If complex conditional prohibition logic is required, you may utilize the `Rule::prohibitedIf` method. This method accepts a boolean or a closure. When given a closure, the closure should return `true` or `false` to indicate if the field under validation should be prohibited:
@@ -1381,7 +1443,7 @@ If complex conditional prohibition logic is required, you may utilize the `Rule:
#### prohibited_unless:_anotherfield_,_value_,...
-The field under validation must be empty or not present unless the _anotherfield_ field is equal to any _value_.
+The field under validation must be an empty string or not present unless the _anotherfield_ field is equal to any _value_.
#### prohibits:_anotherfield_,...
@@ -1395,7 +1457,8 @@ The field under validation must match the given regular expression.
Internally, this rule uses the PHP `preg_match` function. The pattern specified should obey the same formatting required by `preg_match` and thus also include valid delimiters. For example: `'email' => 'regex:/^.+@.+$/i'`.
-> {note} When using the `regex` / `not_regex` patterns, it may be necessary to specify rules in an array instead of using `|` delimiters, especially if the regular expression contains a `|` character.
+> **Warning**
+> When using the `regex` / `not_regex` patterns, it may be necessary to specify rules in an array instead of using `|` delimiters, especially if the regular expression contains a `|` character.
#### required
@@ -1533,7 +1596,8 @@ To instruct the validator to ignore the user's ID, we'll use the `Rule` class to
],
]);
-> {note} You should never pass any user controlled request input into the `ignore` method. Instead, you should only pass a system generated unique ID such as an auto-incrementing ID or UUID from an Eloquent model instance. Otherwise, your application will be vulnerable to an SQL injection attack.
+> **Warning**
+> You should never pass any user controlled request input into the `ignore` method. Instead, you should only pass a system generated unique ID such as an auto-incrementing ID or UUID from an Eloquent model instance. Otherwise, your application will be vulnerable to an SQL injection attack.
Instead of passing the model key's value to the `ignore` method, you may also pass the entire model instance. Laravel will automatically extract the key from the model:
@@ -1598,7 +1662,8 @@ In some situations, you may wish to run validation checks against a field **only
In the example above, the `email` field will only be validated if it is present in the `$data` array.
-> {tip} If you are attempting to validate a field that should always be present but may be empty, check out [this note on optional fields](#a-note-on-optional-fields).
+> **Note**
+> If you are attempting to validate a field that should always be present but may be empty, check out [this note on optional fields](#a-note-on-optional-fields).
#### Complex Conditional Validation
@@ -1624,7 +1689,8 @@ The first argument passed to the `sometimes` method is the name of the field we
return $input->games >= 100;
});
-> {tip} The `$input` parameter passed to your closure will be an instance of `Illuminate\Support\Fluent` and may be used to access your input and files under validation.
+> **Note**
+> The `$input` parameter passed to your closure will be an instance of `Illuminate\Support\Fluent` and may be used to access your input and files under validation.
#### Complex Conditional Array Validation
@@ -1747,6 +1813,48 @@ When validating arrays, you may want to reference the index or position of a par
Given the example above, validation will fail and the user will be presented with the following error of _"Please describe photo #2."_
+
+## Validating Files
+
+Laravel provides a variety of validation rules that may be used to validate uploaded files, such as `mimes`, `image`, `min`, and `max`. While you are free to specify these rules individually when validating files, Laravel also offers a fluent file validation rule builder that you may find convenient:
+
+ use Illuminate\Support\Facades\Validator;
+ use Illuminate\Validation\Rules\File;
+
+ Validator::validate($input, [
+ 'attachment' => [
+ 'required',
+ File::types(['mp3', 'wav'])
+ ->min(1024)
+ ->max(12 * 1024),
+ ],
+ ]);
+
+If your application accepts images uploaded by your users, you may use the `File` rule's `image` constructor method to indicate that the uploaded file should be an image. In addition, the `dimensions` rule may be used to limit the dimensions of the image:
+
+ use Illuminate\Support\Facades\Validator;
+ use Illuminate\Validation\Rules\File;
+
+ Validator::validate($input, [
+ 'photo' => [
+ 'required',
+ File::image()
+ ->min(1024)
+ ->max(12 * 1024)
+ ->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500)),
+ ],
+ ]);
+
+> **Note**
+> More information regarding validating image dimensions may be found in the [dimension rule documentation](#rule-dimensions).
+
+
+#### File Types
+
+Even though you only need to specify the extensions when invoking the `types` method, this method actually validates the MIME type of the file by reading the file's contents and guessing its MIME type. A full listing of MIME types and their corresponding extensions may be found at the following location:
+
+[https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types](https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
+
## Validating Passwords
@@ -1844,54 +1952,35 @@ Occasionally, you may want to attach additional validation rules to your default
Laravel provides a variety of helpful validation rules; however, you may wish to specify some of your own. One method of registering custom validation rules is using rule objects. To generate a new rule object, you may use the `make:rule` Artisan command. Let's use this command to generate a rule that verifies a string is uppercase. Laravel will place the new rule in the `app/Rules` directory. If this directory does not exist, Laravel will create it when you execute the Artisan command to create your rule:
```shell
-php artisan make:rule Uppercase
+php artisan make:rule Uppercase --invokable
```
-Once the rule has been created, we are ready to define its behavior. A rule object contains two methods: `passes` and `message`. The `passes` method receives the attribute value and name, and should return `true` or `false` depending on whether the attribute value is valid or not. The `message` method should return the validation error message that should be used when validation fails:
+Once the rule has been created, we are ready to define its behavior. A rule object contains a single method: `__invoke`. This method receives the attribute name, its value, and a callback that should be invoked on failure with the validation error message:
['required', 'string', new Uppercase],
]);
+#### Translating Validation Messages
+
+Instead of providing a literal error message to the `$fail` closure, you may also provide a [translation string key](/docs/{{version}}/localization) and instruct Laravel to translate the error message:
+
+ if (strtoupper($value) !== $value) {
+ $fail('validation.uppercase')->translate();
+ }
+
+If necessary, you may provide placeholder replacements and the preferred language as the first and second arguments to the `translate` method:
+
+ $fail('validation.location')->translate([
+ 'value' => $this->value,
+ ], 'fr')
+
#### Accessing Additional Data
If your custom validation rule class needs to access all of the other data undergoing validation, your rule class may implement the `Illuminate\Contracts\Validation\DataAwareRule` interface. This interface requires your class to define a `setData` method. This method will automatically be invoked by Laravel (before validation proceeds) with all of the data under validation:
@@ -1908,10 +2011,10 @@ If your custom validation rule class needs to access all of the other data under
namespace App\Rules;
- use Illuminate\Contracts\Validation\Rule;
use Illuminate\Contracts\Validation\DataAwareRule;
+ use Illuminate\Contracts\Validation\InvokableRule;
- class Uppercase implements Rule, DataAwareRule
+ class Uppercase implements DataAwareRule, InvokableRule
{
/**
* All of the data under validation.
@@ -1942,10 +2045,10 @@ Or, if your validation rule requires access to the validator instance performing
namespace App\Rules;
- use Illuminate\Contracts\Validation\Rule;
+ use Illuminate\Contracts\Validation\InvokableRule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
- class Uppercase implements Rule, ValidatorAwareRule
+ class Uppercase implements InvokableRule, ValidatorAwareRule
{
/**
* The validator instance.
@@ -2002,12 +2105,11 @@ By default, when an attribute being validated is not present or contains an empt
Validator::make($input, $rules)->passes(); // true
-For a custom rule to run even when an attribute is empty, the rule must imply that the attribute is required. To create an "implicit" rule, implement the `Illuminate\Contracts\Validation\ImplicitRule` interface. This interface serves as a "marker interface" for the validator; therefore, it does not contain any additional methods you need to implement beyond the methods required by the typical `Rule` interface.
-
-To generate a new implicit rule object, you may use the `make:rule` Artisan command with the `--implicit` option :
+For a custom rule to run even when an attribute is empty, the rule must imply that the attribute is required. To quickly generate a new implicit rule object, you may use the `make:rule` Artisan command with the `--implicit` option:
```shell
-php artisan make:rule Uppercase --implicit
+php artisan make:rule Uppercase --invokable --implicit
```
-> {note} An "implicit" rule only _implies_ that the attribute is required. Whether it actually invalidates a missing or empty attribute is up to you.
+> **Warning**
+> An "implicit" rule only _implies_ that the attribute is required. Whether it actually invalidates a missing or empty attribute is up to you.
diff --git a/verification.md b/verification.md
index 9caf5baf084..f56f8ece89d 100644
--- a/verification.md
+++ b/verification.md
@@ -16,7 +16,8 @@
Many web applications require users to verify their email addresses before using the application. Rather than forcing you to re-implement this feature by hand for each application you create, Laravel provides convenient built-in services for sending and verifying email verification requests.
-> {tip} Want to get started fast? Install one of the [Laravel application starter kits](/docs/{{version}}/starter-kits) in a fresh Laravel application. The starter kits will take care of scaffolding your entire authentication system, including email verification support.
+> **Note**
+> Want to get started fast? Install one of the [Laravel application starter kits](/docs/{{version}}/starter-kits) in a fresh Laravel application. The starter kits will take care of scaffolding your entire authentication system, including email verification support.
### Model Preparation
@@ -75,7 +76,8 @@ As mentioned previously, a route should be defined that will return a view instr
The route that returns the email verification notice should be named `verification.notice`. It is important that the route is assigned this exact name since the `verified` middleware [included with Laravel](#protecting-routes) will automatically redirect to this route name if a user has not verified their email address.
-> {tip} When manually implementing email verification, you are required to define the contents of the verification notice view yourself. If you would like scaffolding that includes all necessary authentication and verification views, check out the [Laravel application starter kits](/docs/{{version}}/starter-kits).
+> **Note**
+> When manually implementing email verification, you are required to define the contents of the verification notice view yourself. If you would like scaffolding that includes all necessary authentication and verification views, check out the [Laravel application starter kits](/docs/{{version}}/starter-kits).
### The Email Verification Handler
@@ -110,11 +112,11 @@ Sometimes a user may misplace or accidentally delete the email address verificat
### Protecting Routes
-[Route middleware](/docs/{{version}}/middleware) may be used to only allow verified users to access a given route. Laravel ships with a `verified` middleware, which references the `Illuminate\Auth\Middleware\EnsureEmailIsVerified` class. Since this middleware is already registered in your application's HTTP kernel, all you need to do is attach the middleware to a route definition:
+[Route middleware](/docs/{{version}}/middleware) may be used to only allow verified users to access a given route. Laravel ships with a `verified` middleware, which references the `Illuminate\Auth\Middleware\EnsureEmailIsVerified` class. Since this middleware is already registered in your application's HTTP kernel, all you need to do is attach the middleware to a route definition. Typically, this middleware is paired with the `auth` middleware:
Route::get('/profile', function () {
// Only verified users may access this route...
- })->middleware('verified');
+ })->middleware(['auth', 'verified']);
If an unverified user attempts to access a route that has been assigned this middleware, they will automatically be redirected to the `verification.notice` [named route](/docs/{{version}}/routing#named-routes).
@@ -148,7 +150,8 @@ To get started, pass a closure to the `toMailUsing` method provided by the `Illu
});
}
-> {tip} To learn more about mail notifications, please consult the [mail notification documentation](/docs/{{version}}/notifications#mail-notifications).
+> **Note**
+> To learn more about mail notifications, please consult the [mail notification documentation](/docs/{{version}}/notifications#mail-notifications).
## Events
diff --git a/views.md b/views.md
index 0df245f8164..30b521b836c 100644
--- a/views.md
+++ b/views.md
@@ -32,7 +32,8 @@ Since this view is stored at `resources/views/greeting.blade.php`, we may return
return view('greeting', ['name' => 'James']);
});
-> {tip} Looking for more information on how to write Blade templates? Check out the full [Blade documentation](/docs/{{version}}/blade) to get started.
+> **Note**
+> Looking for more information on how to write Blade templates? Check out the full [Blade documentation](/docs/{{version}}/blade) to get started.
## Creating & Rendering Views
@@ -60,7 +61,8 @@ Views may also be nested within subdirectories of the `resources/views` director
return view('admin.profile', $data);
-> {note} View directory names should not contain the `.` character.
+> **Warning**
+> View directory names should not contain the `.` character.
### Creating The First Available View
@@ -177,7 +179,8 @@ We'll use the `View` facade's `composer` method to register the view composer. L
}
}
-> {note} Remember, if you create a new service provider to contain your view composer registrations, you will need to add the service provider to the `providers` array in the `config/app.php` configuration file.
+> **Warning**
+> Remember, if you create a new service provider to contain your view composer registrations, you will need to add the service provider to the `providers` array in the `config/app.php` configuration file.
Now that we have registered the composer, the `compose` method of the `App\View\Composers\ProfileComposer` class will be executed each time the `profile` view is being rendered. Let's take a look at an example of the composer class:
@@ -266,4 +269,3 @@ You may use the `view:clear` command to clear the view cache:
```shell
php artisan view:clear
```
-
diff --git a/vite.md b/vite.md
new file mode 100644
index 00000000000..31fc0398376
--- /dev/null
+++ b/vite.md
@@ -0,0 +1,706 @@
+# Asset Bundling (Vite)
+
+- [Introduction](#introduction)
+- [Installation & Setup](#installation)
+ - [Installing Node](#installing-node)
+ - [Installing Vite And The Laravel Plugin](#installing-vite-and-laravel-plugin)
+ - [Configuring Vite](#configuring-vite)
+ - [Loading Your Scripts And Styles](#loading-your-scripts-and-styles)
+- [Running Vite](#running-vite)
+- [Working With JavaScript](#working-with-scripts)
+ - [Aliases](#aliases)
+ - [Vue](#vue)
+ - [React](#react)
+ - [Inertia](#inertia)
+ - [URL Processing](#url-processing)
+- [Working With Stylesheets](#working-with-stylesheets)
+- [Working With Blade & Routes](#working-with-blade-and-routes)
+ - [Processing Static Assets With Vite](#blade-processing-static-assets)
+ - [Refreshing On Save](#blade-refreshing-on-save)
+- [Custom Base URLs](#custom-base-urls)
+- [Environment Variables](#environment-variables)
+- [Disabling Vite In Tests](#disabling-vite-in-tests)
+- [Server-Side Rendering (SSR)](#ssr)
+- [Script & Style Tag Attributes](#script-and-style-attributes)
+ - [Content Security Policy (CSP) Nonce](#content-security-policy-csp-nonce)
+ - [Subresource Integrity (SRI)](#subresource-integrity-sri)
+ - [Arbitrary Attributes](#arbitrary-attributes)
+- [Advanced Customization](#advanced-customization)
+
+
+## Introduction
+
+[Vite](https://vitejs.dev) is a modern frontend build tool that provides an extremely fast development environment and bundles your code for production. When building applications with Laravel, you will typically use Vite to bundle your application's CSS and JavaScript files into production ready assets.
+
+Laravel integrates seamlessly with Vite by providing an official plugin and Blade directive to load your assets for development and production.
+
+> **Note**
+> Are you running Laravel Mix? Vite has replaced Laravel Mix in new Laravel installations. For Mix documentation, please visit the [Laravel Mix](https://laravel-mix.com/) website. If you would like to switch to Vite, please see our [migration guide](https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md#migrating-from-laravel-mix-to-vite).
+
+
+#### Choosing Between Vite And Laravel Mix
+
+Before transitioning to Vite, new Laravel applications utilized [Mix](https://laravel-mix.com/), which is powered by [webpack](https://webpack.js.org/), when bundling assets. Vite focuses on providing a faster and more productive experience when building rich JavaScript applications. If you are developing a Single Page Application (SPA), including those developed with tools like [Inertia](https://inertiajs.com), Vite will be the perfect fit.
+
+Vite also works well with traditional server-side rendered applications with JavaScript "sprinkles", including those using [Livewire](https://laravel-livewire.com). However, it lacks some features that Laravel Mix supports, such as the ability to copy arbitrary assets into the build that are not referenced directly in your JavaScript application.
+
+
+#### Migrating Back To Mix
+
+Have you started a new Laravel application using our Vite scaffolding but need to move back to Laravel Mix and webpack? No problem. Please consult our [official guide on migrating from Vite to Mix](https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md#migrating-from-vite-to-laravel-mix).
+
+
+## Installation & Setup
+
+> **Note**
+> The following documentation discusses how to manually install and configure the Laravel Vite plugin. However, Laravel's [starter kits](/docs/{{version}}/starter-kits) already include all of this scaffolding and are the fastest way to get started with Laravel and Vite.
+
+
+### Installing Node
+
+You must ensure that Node.js (16+) and NPM are installed before running Vite and the Laravel plugin:
+
+```sh
+node -v
+npm -v
+```
+
+You can easily install the latest version of Node and NPM using simple graphical installers from [the official Node website](https://nodejs.org/en/download/). Or, if you are using [Laravel Sail](https://laravel.com/docs/{{version}}/sail), you may invoke Node and NPM through Sail:
+
+```sh
+./vendor/bin/sail node -v
+./vendor/bin/sail npm -v
+```
+
+
+### Installing Vite And The Laravel Plugin
+
+Within a fresh installation of Laravel, you will find a `package.json` file in the root of your application's directory structure. The default `package.json` file already includes everything you need to get started using Vite and the Laravel plugin. You may install your application's frontend dependencies via NPM:
+
+```sh
+npm install
+```
+
+
+### Configuring Vite
+
+Vite is configured via a `vite.config.js` file in the root of your project. You are free to customize this file based on your needs, and you may also install any other plugins your application requires, such as `@vitejs/plugin-vue` or `@vitejs/plugin-react`.
+
+The Laravel Vite plugin requires you to specify the entry points for your application. These may be JavaScript or CSS files, and include preprocessed languages such as TypeScript, JSX, TSX, and Sass.
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ laravel([
+ 'resources/css/app.css',
+ 'resources/js/app.js',
+ ]),
+ ],
+});
+```
+
+If you are building an SPA, including applications built using Inertia, Vite works best without CSS entry points:
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ laravel([
+ 'resources/css/app.css', // [tl! remove]
+ 'resources/js/app.js',
+ ]),
+ ],
+});
+```
+
+Instead, you should import your CSS via JavaScript. Typically, this would be done in your application's `resources/js/app.js` file:
+
+```js
+import './bootstrap';
+import '../css/app.css'; // [tl! add]
+```
+
+The Laravel plugin also supports multiple entry points and advanced configuration options such as [SSR entry points](#ssr).
+
+
+#### Working With A Secure Development Server
+
+If your development web server is running on HTTPS, including Valet's [secure command](/docs/{{version}}/valet#securing-sites), you may run into issues connecting to the Vite development server. You may configure Vite to also run on HTTPS by adding the following to your `vite.config.js` configuration file:
+
+```js
+export default defineConfig({
+ // ...
+ server: { // [tl! add]
+ https: true, // [tl! add]
+ host: 'localhost', // [tl! add]
+ }, // [tl! add]
+});
+```
+
+You will also need to accept the certificate warning for Vite's development server in your browser by following the "Local" link in your console when running the `npm run dev` command.
+
+
+### Loading Your Scripts And Styles
+
+With your Vite entry points configured, you only need reference them in a `@vite()` Blade directive that you add to the `
` of your application's root template: + +```blade + +
+ {{-- ... --}} + + @vite(['resources/css/app.css', 'resources/js/app.js']) + +``` + +If you're importing your CSS via JavaScript, you only need to include the JavaScript entry point: + +```blade + +
+ {{-- ... --}} + + @vite('resources/js/app.js') + +``` + +The `@vite` directive will automatically detect the Vite development server and inject the Vite client to enable Hot Module Replacement. In build mode, the directive will load your compiled and versioned assets, including any imported CSS. + +If needed, you may also specify the build path of your compiled assets when invoking the `@vite` directive: + +```blade + +
+ {{-- Given build path is relative to public path. --}}
+
+ @vite('resources/js/app.js', 'vendor/courier/build')
+
+```
+
+
+## Running Vite
+
+There are two ways you can run Vite. You may run the development server via the `dev` command, which is useful while developing locally. The development server will automatically detect changes to your files and instantly reflect them in any open browser windows.
+
+Or, running the `build` command will version and bundle your application's assets and get them ready for you to deploy to production:
+
+```shell
+# Run the Vite development server...
+npm run dev
+
+# Build and version the assets for production...
+npm run build
+```
+
+
+## Working With JavaScript
+
+
+### Aliases
+
+By default, The Laravel plugin provides a common alias to help you hit the ground running and conveniently import your application's assets:
+
+```js
+{
+ '@' => '/resources/js'
+}
+```
+
+You may overwrite the `'@'` alias by adding your own to the `vite.config.js` configuration file:
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ laravel(['resources/ts/app.tsx']),
+ ],
+ resolve: {
+ alias: {
+ '@': '/resources/ts',
+ },
+ },
+});
+```
+
+
+### Vue
+
+There are a few additional options you will need to include in the `vite.config.js` configuration file when using the Vue plugin with the Laravel plugin:
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+import vue from '@vitejs/plugin-vue';
+
+export default defineConfig({
+ plugins: [
+ laravel(['resources/js/app.js']),
+ vue({
+ template: {
+ transformAssetUrls: {
+ // The Vue plugin will re-write asset URLs, when referenced
+ // in Single File Components, to point to the Laravel web
+ // server. Setting this to `null` allows the Laravel plugin
+ // to instead re-write asset URLs to point to the Vite
+ // server instead.
+ base: null,
+
+ // The Vue plugin will parse absolute URLs and treat them
+ // as absolute paths to files on disk. Setting this to
+ // `false` will leave absolute URLs un-touched so they can
+ // reference assets in the public directly as expected.
+ includeAbsolute: false,
+ },
+ },
+ }),
+ ],
+});
+```
+
+> **Note**
+> Laravel's [starter kits](/docs/{{version}}/starter-kits) already include the proper Laravel, Vue, and Vite configuration. Check out [Laravel Breeze](/docs/{{version}}/starter-kits#breeze-and-inertia) for the fastest way to get started with Laravel, Vue, and Vite.
+
+
+### React
+
+When using Vite with React, you will need to ensure that any files containing JSX have a `.jsx` or `.tsx` extension, remembering to update your entry point, if required, as [shown above](#configuring-vite). You will also need to include the additional `@viteReactRefresh` Blade directive alongside your existing `@vite` directive.
+
+```blade
+@viteReactRefresh
+@vite('resources/js/app.jsx')
+```
+
+The `@viteReactRefresh` directive must be called before the `@vite` directive.
+
+> **Note**
+> Laravel's [starter kits](/docs/{{version}}/starter-kits) already include the proper Laravel, React, and Vite configuration. Check out [Laravel Breeze](/docs/{{version}}/starter-kits#breeze-and-inertia) for the fastest way to get started with Laravel, React, and Vite.
+
+
+### Inertia
+
+The Laravel Vite plugin provides a convenient `resolvePageComponent` function to help you resolve your Inertia page components. Below is an example of the helper in use with Vue 3; however, you may also utilize the function in other frameworks such as React:
+
+```js
+import { createApp, h } from 'vue';
+import { createInertiaApp } from '@inertiajs/inertia-vue3';
+import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
+
+createInertiaApp({
+ resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
+ setup({ el, App, props, plugin }) {
+ createApp({ render: () => h(App, props) })
+ .use(plugin)
+ .mount(el)
+ },
+});
+```
+
+> **Note**
+> Laravel's [starter kits](/docs/{{version}}/starter-kits) already include the proper Laravel, Inertia, and Vite configuration. Check out [Laravel Breeze](/docs/{{version}}/starter-kits#breeze-and-inertia) for the fastest way to get started with Laravel, Inertia, and Vite.
+
+
+### URL Processing
+
+When using Vite and referencing assets in your application's HTML, CSS, or JS, there are a couple of things to consider. First, if you reference assets with an absolute path, Vite will not include the asset in the build; therefore, you should ensure that the asset is available in your public directory.
+
+When referencing relative asset paths, you should remember that the paths are relative to the file where they are referenced. Any assets referenced via a relative path will be re-written, versioned, and bundled by Vite.
+
+Consider the following project structure:
+
+```nothing
+public/
+ taylor.png
+resources/
+ js/
+ Pages/
+ Welcome.vue
+ images/
+ abigail.png
+```
+
+The following example demonstrates how Vite will treat relative and absolute URLs:
+
+```html
+
+
+
+
+
+```
+
+
+## Working With Stylesheets
+
+You can learn more about Vite's CSS support within the [Vite documentation](https://vitejs.dev/guide/features.html#css). If you are using PostCSS plugins such as [Tailwind](https://tailwindcss.com), you may create a `postcss.config.js` file in the root of your project and Vite will automatically apply it:
+
+```js
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
+```
+
+
+## Working With Blade & Routes
+
+
+### Processing Static Assets With Vite
+
+When referencing assets in your JavaScript or CSS, Vite automatically processes and versions them. In addition, when building Blade based applications, Vite can also process and version static assets that you reference solely in Blade templates.
+
+However, in order to accomplish this, you need to make Vite aware of your assets by importing the static assets into the application's entry point. For example, if you want to process and version all images stored in `resources/images` and all fonts stored in `resources/fonts`, you should add the following in your application's `resources/js/app.js` entry point:
+
+```js
+import.meta.glob([
+ '../images/**',
+ '../fonts/**',
+]);
+```
+
+These assets will now be processed by Vite when running `npm run build`. You can then reference these assets in Blade templates using the `Vite::asset` method, which will return the versioned URL for a given asset:
+
+```blade
+
+```
+
+
+### Refreshing On Save
+
+When your application is built using traditional server-side rendering with Blade, Vite can improve your development workflow by automatically refreshing the browser when you make changes to view files in your application. To get started, you can simply specify the `refresh` option as `true`.
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ laravel({
+ // ...
+ refresh: true,
+ }),
+ ],
+});
+```
+
+When the `refresh` option is `true`, saving files in `resources/views/**`, `app/View/Components/**`, and `routes/**` will trigger the browser to perform a full page refresh while you are running `npm run dev`.
+
+Watching the `routes/**` directory is useful if you are utilizing [Ziggy](https://github.com/tighten/ziggy) to generate route links within your application's frontend.
+
+If these default paths do not suit your needs, you can specify your own list of paths to watch:
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ laravel({
+ // ...
+ refresh: ['resources/views/**'],
+ }),
+ ],
+});
+```
+
+Under the hood, the Laravel Vite plugin uses the [`vite-plugin-full-reload`](https://github.com/ElMassimo/vite-plugin-full-reload) package, which offers some advanced configuration options to fine-tune this feature's behavior. If you need this level of customization, you may provide a `config` definition:
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ laravel({
+ // ...
+ refresh: [{
+ paths: ['path/to/watch/**'],
+ config: { delay: 300 }
+ }],
+ }),
+ ],
+});
+```
+
+
+## Custom Base URLs
+
+If your Vite compiled assets are deployed to a domain separate from your application, such as via a CDN, you must specify the `ASSET_URL` environment variable within your application's `.env` file:
+
+```env
+ASSET_URL=https://cdn.example.com
+```
+
+After configuring the asset URL, all re-written URLs to your assets will be prefixed with the configured value:
+
+```nothing
+https://cdn.example.com/build/assets/app.9dce8d17.js
+```
+
+Remember that [absolute URLs are not re-written by Vite](#url-processing), so they will not be prefixed.
+
+
+## Environment Variables
+
+You may inject environment variables into your JavaScript by prefixing them with `VITE_` in your application's `.env` file:
+
+```env
+VITE_SENTRY_DSN_PUBLIC=http://example.com
+```
+
+You may access injected environment variables via the `import.meta.env` object:
+
+```js
+import.meta.env.VITE_SENTRY_DSN_PUBLIC
+```
+
+
+## Disabling Vite In Tests
+
+Laravel's Vite integration will attempt to resolve your assets while running your tests, which requires you to either run the Vite development server or build your assets.
+
+If you would prefer to mock Vite during testing, you may call the `withoutVite` method, which is is available for any tests that extend Laravel's `TestCase` class:
+
+```php
+use Tests\TestCase;
+
+class ExampleTest extends TestCase
+{
+ public function test_without_vite_example()
+ {
+ $this->withoutVite();
+
+ // ...
+ }
+}
+```
+
+If you would like to disable Vite for all tests, you may call the `withoutVite` method from the `setUp` method on your base `TestCase` class:
+
+```php
+withoutVite();
+ }// [tl! add:end]
+}
+```
+
+
+## Server-Side Rendering (SSR)
+
+The Laravel Vite plugin makes it painless to set up server-side rendering with Vite. To get started, create an SSR entry point at `resources/js/ssr.js` and specify the entry point by passing a configuration option to the Laravel plugin:
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ laravel({
+ input: 'resources/js/app.js',
+ ssr: 'resources/js/ssr.js',
+ }),
+ ],
+});
+```
+
+To ensure you don't forget to rebuild the SSR entry point, we recommend augmenting the "build" script in your application's `package.json` to create your SSR build:
+
+```json
+"scripts": {
+ "dev": "vite",
+ "build": "vite build" // [tl! remove]
+ "build": "vite build && vite build --ssr" // [tl! add]
+}
+```
+
+Then, to build and start the SSR server, you may run the following commands:
+
+```sh
+npm run build
+node bootstrap/ssr/ssr.mjs
+```
+
+> **Note**
+> Laravel's [starter kits](/docs/{{version}}/starter-kits) already include the proper Laravel, Inertia SSR, and Vite configuration. Check out [Laravel Breeze](/docs/{{version}}/starter-kits#breeze-and-inertia) for the fastest way to get started with Laravel, Inertia SSR, and Vite.
+
+
+## Script & Style Tag Attributes
+
+
+### Content Security Policy (CSP) Nonce
+
+If you wish to include a [`nonce` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) on your script and style tags as part of your [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), you may generate or specify a nonce using the `useCspNonce` method within a custom [middleware](/docs/{{version}}/middleware):
+
+```php
+withHeaders([
+ 'Content-Security-Policy' => "script-src 'nonce-".Vite::cspNonce()."'",
+ ]);
+ }
+}
+```
+
+After invoking the `useCspNonce` method, Laravel will automatically include the `nonce` attributes on all generated script and style tags.
+
+If you need to specify the nonce elsewhere, including the [Ziggy `@route` directive](https://github.com/tighten/ziggy#using-routes-with-a-content-security-policy) included with Laravel's [starter kits](/docs/{{version}}/starter-kits), you may retrieve it using the `cspNonce` method:
+
+```blade
+@routes(nonce: Vite::cspNonce())
+```
+
+If you already have a nonce that you would like to instruct Laravel to use, you may pass the nonce to the `useCspNonce` method:
+
+```php
+Vite::useCspNonce($nonce);
+```
+
+
+### Subresource Integrity (SRI)
+
+If your Vite manifest includes `integrity` hashes for your assets, Laravel will automatically add the `integrity` attribute on any script and style tags it generates in order to enforce [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). By default, Vite does not include the `integrity` hash in its manifest, but you may enable it by installing the [`vite-plugin-manifest-uri`](https://www.npmjs.com/package/vite-plugin-manifest-sri) NPM plugin:
+
+```shell
+npm install -D vite-plugin-manifest-sri
+```
+
+You may then enable this plugin in your `vite.config.js` file:
+
+```js
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+import manifestSRI from 'vite-plugin-manifest-sri';// [tl! add]
+
+export default defineConfig({
+ plugins: [
+ laravel({
+ // ...
+ }),
+ manifestSRI(),// [tl! add]
+ ],
+});
+```
+
+If required, you may also customize the manifest key where the integrity hash can be found:
+
+```php
+use Illuminate\Support\Facades\Vite;
+
+Vite::useIntegrityKey('custom-integrity-key');
+```
+
+If you would like to disable this auto-detection completely, you may pass `false` to the `useIntegrityKey` method:
+
+```php
+Vite::useIntegrityKey(false);
+```
+
+
+### Arbitrary Attributes
+
+If you need to include additional attributes on your script and style tags, such as the [`data-turbo-track`](https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change) attribute, you may specify them via the `useScriptTagAttributes` and `useStyleTagAttributes` methods. Typically, this methods should be invoked from a [service provider](/docs/{{version}}/providers):
+
+```php
+use Illuminate\Support\Facades\Vite;
+
+Vite::useScriptTagAttributes([
+ 'data-turbo-track' => 'reload', // Specify a value for the attribute...
+ 'async' => true, // Specify an attribute without a value...
+ 'integrity' => false, // Exclude an attribute that would otherwise be included...
+]);
+
+Vite::useStyleTagAttributes([
+ 'data-turbo-track' => 'reload',
+]);
+```
+
+If you need to conditionally add attributes, you may pass a callback that will receive the asset source path, its URL, its manifest chunk, and the entire manifest:
+
+```php
+use Illuminate\Support\Facades\Vite;
+
+Vite::useScriptTagAttributes(fn (string $src, string $url, array|null $chunk, array|null $manifest) => [
+ 'data-turbo-track' => $src === 'resources/js/app.js' ? 'reload' : false,
+]);
+
+Vite::useStyleTagAttributes(fn (string $src, string $url, array|null $chunk, array|null $manifest) => [
+ 'data-turbo-track' => $chunk && $chunk['isEntry'] ? 'reload' : false,
+]);
+```
+
+> **Warning**
+> The `$chunk` and `$manifest` arguments will be `null` while the Vite development server is running.
+
+
+## Advanced Customization
+
+Out of the box, Laravel's Vite plugin uses sensible conventions that should work for the majority of applications; however, sometimes you may need to customize Vite's behavior. To enable additional customization options, we offer the following methods and options which can be used in place of the `@vite` Blade directive:
+
+```blade
+
+
+ {{-- ... --}} + + {{ + Vite::useHotFile(storage_path('vite.hot')) // Customize the "hot" file... + ->useBuildDirectory('bundle') // Customize the build directory... + ->withEntryPoints(['resources/js/app.js']) // Specify the entry points... + }} + +``` + +Within the `vite.config.js` file, you should then specify the same configuration: + +```js +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; + +export default defineConfig({ + plugins: [ + laravel({ + hotFile: 'storage/vite.hot', // Customize the "hot" file... + buildDirectory: 'bundle', // Customize the build directory... + input: ['resources/js/app.js'], // Specify the entry points... + }), + ], +}); +```