├── readme.md
├── license.md
├── mix.md
├── concurrency.md
├── encryption.md
├── releases.md
├── redirects.md
├── documentation.md
├── rate-limiting.md
├── hashing.md
├── mongodb.md
├── seeding.md
├── csrf.md
├── lifecycle.md
├── console-tests.md
├── pint.md
├── contributions.md
├── providers.md
├── eloquent-serialization.md
├── database-testing.md
├── verification.md
├── upgrade.md
├── mocking.md
├── deployment.md
├── testing.md
├── frontend.md
├── folio.md
├── views.md
├── socialite.md
└── envoy.md
/readme.md:
--------------------------------------------------------------------------------
1 | # Laravel Documentation
2 |
3 | You can find the online version of the Laravel documentation at [https://laravel.com/docs](https://laravel.com/docs)
4 |
5 | ## Contribution Guidelines
6 |
7 | If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel 12 would be submitted to the `12.x` branch. Documentation intended for the next release of Laravel should be submitted to the `master` branch.
8 |
--------------------------------------------------------------------------------
/license.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Taylor Otwell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/mix.md:
--------------------------------------------------------------------------------
1 | # Laravel Mix
2 |
3 | - [Introduction](#introduction)
4 |
5 |
6 | ## Introduction
7 |
8 | > [!WARNING]
9 | > Laravel Mix is a legacy package that is no longer actively maintained. [Vite](/docs/{{version}}/vite) may be used as a modern alternative.
10 |
11 | [Laravel Mix](https://github.com/laravel-mix/laravel-mix), a package developed by [Laracasts](https://laracasts.com) creator Jeffrey Way, provides a fluent API for defining [webpack](https://webpack.js.org) build steps for your Laravel application using several common CSS and JavaScript pre-processors.
12 |
13 | In other words, Mix makes it a cinch to compile and minify your application's CSS and JavaScript files. Through simple method chaining, you can fluently define your asset pipeline. For example:
14 |
15 | ```js
16 | mix.js('resources/js/app.js', 'public/js')
17 | .postCss('resources/css/app.css', 'public/css');
18 | ```
19 |
20 | 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.
21 |
22 | > [!NOTE]
23 | > 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).
24 |
--------------------------------------------------------------------------------
/concurrency.md:
--------------------------------------------------------------------------------
1 | # Concurrency
2 |
3 | - [Introduction](#introduction)
4 | - [Running Concurrent Tasks](#running-concurrent-tasks)
5 | - [Deferring Concurrent Tasks](#deferring-concurrent-tasks)
6 |
7 |
8 | ## Introduction
9 |
10 | Sometimes you may need to execute several slow tasks which do not depend on one another. In many cases, significant performance improvements can be realized by executing the tasks concurrently. Laravel's `Concurrency` facade provides a simple, convenient API for executing closures concurrently.
11 |
12 |
13 | #### How it Works
14 |
15 | Laravel achieves concurrency by serializing the given closures and dispatching them to a hidden Artisan CLI command, which unserializes the closures and invokes it within its own PHP process. After the closure has been invoked, the resulting value is serialized back to the parent process.
16 |
17 | The `Concurrency` facade supports three drivers: `process` (the default), `fork`, and `sync`.
18 |
19 | The `fork` driver offers improved performance compared to the default `process` driver, but it may only be used within PHP's CLI context, as PHP does not support forking during web requests. Before using the `fork` driver, you need to install the `spatie/fork` package:
20 |
21 | ```shell
22 | composer require spatie/fork
23 | ```
24 |
25 | The `sync` driver is primarily useful during testing when you want to disable all concurrency and simply execute the given closures in sequence within the parent process.
26 |
27 |
28 | ## Running Concurrent Tasks
29 |
30 | To run concurrent tasks, you may invoke the `Concurrency` facade's `run` method. The `run` method accepts an array of closures which should be executed simultaneously in child PHP processes:
31 |
32 | ```php
33 | use Illuminate\Support\Facades\Concurrency;
34 | use Illuminate\Support\Facades\DB;
35 |
36 | [$userCount, $orderCount] = Concurrency::run([
37 | fn () => DB::table('users')->count(),
38 | fn () => DB::table('orders')->count(),
39 | ]);
40 | ```
41 |
42 | To use a specific driver, you may use the `driver` method:
43 |
44 | ```php
45 | $results = Concurrency::driver('fork')->run(...);
46 | ```
47 |
48 | Or, to change the default concurrency driver, you should publish the `concurrency` configuration file via the `config:publish` Artisan command and update the `default` option within the file:
49 |
50 | ```shell
51 | php artisan config:publish concurrency
52 | ```
53 |
54 |
55 | ## Deferring Concurrent Tasks
56 |
57 | If you would like to execute an array of closures concurrently, but are not interested in the results returned by those closures, you should consider using the `defer` method. When the `defer` method is invoked, the given closures are not executed immediately. Instead, Laravel will execute the closures concurrently after the HTTP response has been sent to the user:
58 |
59 | ```php
60 | use App\Services\Metrics;
61 | use Illuminate\Support\Facades\Concurrency;
62 |
63 | Concurrency::defer([
64 | fn () => Metrics::report('users'),
65 | fn () => Metrics::report('orders'),
66 | ]);
67 | ```
68 |
--------------------------------------------------------------------------------
/encryption.md:
--------------------------------------------------------------------------------
1 | # Encryption
2 |
3 | - [Introduction](#introduction)
4 | - [Configuration](#configuration)
5 | - [Gracefully Rotating Encryption Keys](#gracefully-rotating-encryption-keys)
6 | - [Using the Encrypter](#using-the-encrypter)
7 |
8 |
9 | ## Introduction
10 |
11 | Laravel's encryption services provide a simple, convenient interface for encrypting and decrypting text via OpenSSL using AES-256 and AES-128 encryption. All of Laravel's encrypted values are signed using a message authentication code (MAC) so that their underlying value cannot be modified or tampered with once encrypted.
12 |
13 |
14 | ## Configuration
15 |
16 | Before using Laravel's encrypter, you must set the `key` configuration option in your `config/app.php` configuration file. This configuration value is driven by the `APP_KEY` environment variable. You should use the `php artisan key:generate` command to generate this variable's value since the `key:generate` command will use PHP's secure random bytes generator to build a cryptographically secure key for your application. Typically, the value of the `APP_KEY` environment variable will be generated for you during [Laravel's installation](/docs/{{version}}/installation).
17 |
18 |
19 | ### Gracefully Rotating Encryption Keys
20 |
21 | If you change your application's encryption key, all authenticated user sessions will be logged out of your application. This is because every cookie, including session cookies, are encrypted by Laravel. In addition, it will no longer be possible to decrypt any data that was encrypted with your previous encryption key.
22 |
23 | To mitigate this issue, Laravel allows you to list your previous encryption keys in your application's `APP_PREVIOUS_KEYS` environment variable. This variable may contain a comma-delimited list of all of your previous encryption keys:
24 |
25 | ```ini
26 | APP_KEY="base64:J63qRTDLub5NuZvP+kb8YIorGS6qFYHKVo6u7179stY="
27 | APP_PREVIOUS_KEYS="base64:2nLsGFGzyoae2ax3EF2Lyq/hH6QghBGLIq5uL+Gp8/w="
28 | ```
29 |
30 | When you set this environment variable, Laravel will always use the "current" encryption key when encrypting values. However, when decrypting values, Laravel will first try the current key, and if decryption fails using the current key, Laravel will try all previous keys until one of the keys is able to decrypt the value.
31 |
32 | This approach to graceful decryption allows users to keep using your application uninterrupted even if your encryption key is rotated.
33 |
34 |
35 | ## Using the Encrypter
36 |
37 |
38 | #### Encrypting a Value
39 |
40 | You may encrypt a value using the `encryptString` method provided by the `Crypt` facade. All encrypted values are encrypted using OpenSSL and the AES-256-CBC cipher. Furthermore, all encrypted values are signed with a message authentication code (MAC). The integrated message authentication code will prevent the decryption of any values that have been tampered with by malicious users:
41 |
42 | ```php
43 | user()->fill([
59 | 'token' => Crypt::encryptString($request->token),
60 | ])->save();
61 |
62 | return redirect('/secrets');
63 | }
64 | }
65 | ```
66 |
67 |
68 | #### Decrypting a Value
69 |
70 | You may decrypt values using the `decryptString` method provided by the `Crypt` facade. If the value cannot be properly decrypted, such as when the message authentication code is invalid, an `Illuminate\Contracts\Encryption\DecryptException` will be thrown:
71 |
72 | ```php
73 | use Illuminate\Contracts\Encryption\DecryptException;
74 | use Illuminate\Support\Facades\Crypt;
75 |
76 | try {
77 | $decrypted = Crypt::decryptString($encryptedValue);
78 | } catch (DecryptException $e) {
79 | // ...
80 | }
81 | ```
82 |
--------------------------------------------------------------------------------
/releases.md:
--------------------------------------------------------------------------------
1 | # Release Notes
2 |
3 | - [Versioning Scheme](#versioning-scheme)
4 | - [Support Policy](#support-policy)
5 | - [Laravel 12](#laravel-12)
6 |
7 |
8 | ## Versioning Scheme
9 |
10 | Laravel and its other first-party packages follow [Semantic Versioning](https://semver.org). Major framework releases are released every year (~Q1), while minor and patch releases may be released as often as every week. Minor and patch releases should **never** contain breaking changes.
11 |
12 | When referencing the Laravel framework or its components from your application or package, you should always use a version constraint such as `^12.0`, since major releases of Laravel do include breaking changes. However, we strive to always ensure you may update to a new major release in one day or less.
13 |
14 |
15 | #### Named Arguments
16 |
17 | [Named arguments](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments) are not covered by Laravel's backwards compatibility guidelines. We may choose to rename function arguments when necessary in order to improve the Laravel codebase. Therefore, using named arguments when calling Laravel methods should be done cautiously and with the understanding that the parameter names may change in the future.
18 |
19 |
20 | ## Support Policy
21 |
22 | For all Laravel releases, bug fixes are provided for 18 months and security fixes are provided for 2 years. For all additional libraries, only the latest major release receives bug fixes. In addition, please review the database versions [supported by Laravel](/docs/{{version}}/database#introduction).
23 |
24 |
25 |
26 | | Version | PHP (*) | Release | Bug Fixes Until | Security Fixes Until |
27 | | ------- |-----------| ------------------- | ------------------- | -------------------- |
28 | | 10 | 8.1 - 8.3 | February 14th, 2023 | August 6th, 2024 | February 4th, 2025 |
29 | | 11 | 8.2 - 8.4 | March 12th, 2024 | September 3rd, 2025 | March 12th, 2026 |
30 | | 12 | 8.2 - 8.5 | February 24th, 2025 | August 13th, 2026 | February 24th, 2027 |
31 | | 13 | 8.3 - 8.5 | Q1 2026 | Q3 2027 | Q1 2028 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
End of life
39 |
40 |
41 |
42 |
Security fixes only
43 |
44 |
45 |
46 | (*) Supported PHP versions
47 |
48 |
49 | ## Laravel 12
50 |
51 | Laravel 12 continues the improvements made in Laravel 11.x by updating upstream dependencies and introducing new starter kits for React, Vue, and Livewire, including the option of using [WorkOS AuthKit](https://authkit.com) for user authentication. The WorkOS variant of our starter kits offers social authentication, passkeys, and SSO support.
52 |
53 |
54 | ### Minimal Breaking Changes
55 |
56 | Much of our focus during this release cycle has been minimizing breaking changes. Instead, we have dedicated ourselves to shipping continuous quality-of-life improvements throughout the year that do not break existing applications.
57 |
58 | Therefore, the Laravel 12 release is a relatively minor "maintenance release" in order to upgrade existing dependencies. In light of this, most Laravel applications may upgrade to Laravel 12 without changing any application code.
59 |
60 |
61 | ### New Application Starter Kits
62 |
63 | Laravel 12 introduces new [application starter kits](/docs/{{version}}/starter-kits) for React, Vue, and Livewire. The React and Vue starter kits utilize Inertia 2, TypeScript, [shadcn/ui](https://ui.shadcn.com), and Tailwind, while the Livewire starter kits utilize the Tailwind-based [Flux UI](https://fluxui.dev) component library and Laravel Volt.
64 |
65 | The React, Vue, and Livewire starter kits all utilize Laravel's built-in authentication system to offer login, registration, password reset, email verification, and more. In addition, we are introducing a [WorkOS AuthKit-powered](https://authkit.com) variant of each starter kit, offering social authentication, passkeys, and SSO support. WorkOS offers free authentication for applications up to 1 million monthly active users.
66 |
67 | With the introduction of our new application starter kits, Laravel Breeze and Laravel Jetstream will no longer receive additional updates.
68 |
69 | To get started with our new starter kits, check out the [starter kit documentation](/docs/{{version}}/starter-kits).
70 |
--------------------------------------------------------------------------------
/redirects.md:
--------------------------------------------------------------------------------
1 | # HTTP Redirects
2 |
3 | - [Creating Redirects](#creating-redirects)
4 | - [Redirecting To Named Routes](#redirecting-named-routes)
5 | - [Redirecting To Controller Actions](#redirecting-controller-actions)
6 | - [Redirecting With Flashed Session Data](#redirecting-with-flashed-session-data)
7 |
8 |
9 | ## Creating Redirects
10 |
11 | Redirect responses are instances of the `Illuminate\Http\RedirectResponse` class, and contain the proper headers needed to redirect the user to another URL. There are several ways to generate a `RedirectResponse` instance. The simplest method is to use the global `redirect` helper:
12 |
13 | ```php
14 | Route::get('/dashboard', function () {
15 | return redirect('/home/dashboard');
16 | });
17 | ```
18 |
19 | Sometimes you may wish to redirect the user to their previous location, such as when a submitted form is invalid. You may do so by using the global `back` helper function. Since this feature utilizes the [session](/docs/{{version}}/session), make sure the route calling the `back` function is using the `web` middleware group or has all of the session middleware applied:
20 |
21 | ```php
22 | Route::post('/user/profile', function () {
23 | // Validate the request...
24 |
25 | return back()->withInput();
26 | });
27 | ```
28 |
29 |
30 | ## Redirecting To Named Routes
31 |
32 | When you call the `redirect` helper with no parameters, an instance of `Illuminate\Routing\Redirector` is returned, allowing you to call any method on the `Redirector` instance. For example, to generate a `RedirectResponse` to a named route, you may use the `route` method:
33 |
34 | ```php
35 | return redirect()->route('login');
36 | ```
37 |
38 | If your route has parameters, you may pass them as the second argument to the `route` method:
39 |
40 | ```php
41 | // For a route with the following URI: profile/{id}
42 |
43 | return redirect()->route('profile', ['id' => 1]);
44 | ```
45 |
46 | For convenience, Laravel also offers the global `to_route` function:
47 |
48 | ```php
49 | return to_route('profile', ['id' => 1]);
50 | ```
51 |
52 |
53 | #### Populating Parameters Via Eloquent Models
54 |
55 | If you are redirecting to a route with an "ID" parameter that is being populated from an Eloquent model, you may pass the model itself. The ID will be extracted automatically:
56 |
57 | ```php
58 | // For a route with the following URI: profile/{id}
59 |
60 | return redirect()->route('profile', [$user]);
61 | ```
62 |
63 | If you would like to customize the value that is placed in the route parameter, you should override the `getRouteKey` method on your Eloquent model:
64 |
65 | ```php
66 | /**
67 | * Get the value of the model's route key.
68 | */
69 | public function getRouteKey(): mixed
70 | {
71 | return $this->slug;
72 | }
73 | ```
74 |
75 |
76 | ## Redirecting To Controller Actions
77 |
78 | You may also generate redirects to [controller actions](/docs/{{version}}/controllers). To do so, pass the controller and action name to the `action` method:
79 |
80 | ```php
81 | use App\Http\Controllers\HomeController;
82 |
83 | return redirect()->action([HomeController::class, 'index']);
84 | ```
85 |
86 | If your controller route requires parameters, you may pass them as the second argument to the `action` method:
87 |
88 | ```php
89 | return redirect()->action(
90 | [UserController::class, 'profile'], ['id' => 1]
91 | );
92 | ```
93 |
94 |
95 | ## Redirecting With Flashed Session Data
96 |
97 | Redirecting to a new URL and [flashing data to the session](/docs/{{version}}/session#flash-data) are usually done at the same time. Typically, this is done after successfully performing an action when you flash a success message to the session. For convenience, you may create a `RedirectResponse` instance and flash data to the session in a single, fluent method chain:
98 |
99 | ```php
100 | Route::post('/user/profile', function () {
101 | // Update the user's profile...
102 |
103 | return redirect('/dashboard')->with('status', 'Profile updated!');
104 | });
105 | ```
106 |
107 | You may use the `withInput` method provided by the `RedirectResponse` instance to flash the current request's input data to the session before redirecting the user to a new location. Once the input has been flashed to the session, you may easily [retrieve it](/docs/{{version}}/requests#retrieving-old-input) during the next request:
108 |
109 | ```php
110 | return back()->withInput();
111 | ```
112 |
113 | After the user is redirected, you may display the flashed message from the [session](/docs/{{version}}/session). For example, using [Blade syntax](/docs/{{version}}/blade):
114 |
115 | ```blade
116 | @if (session('status'))
117 |
118 | {{ session('status') }}
119 |
120 | @endif
121 | ```
122 |
--------------------------------------------------------------------------------
/documentation.md:
--------------------------------------------------------------------------------
1 | - ## Prologue
2 | - [Release Notes](/docs/{{version}}/releases)
3 | - [Upgrade Guide](/docs/{{version}}/upgrade)
4 | - [Contribution Guide](/docs/{{version}}/contributions)
5 | - ## Getting Started
6 | - [Installation](/docs/{{version}}/installation)
7 | - [Configuration](/docs/{{version}}/configuration)
8 | - [Directory Structure](/docs/{{version}}/structure)
9 | - [Frontend](/docs/{{version}}/frontend)
10 | - [Starter Kits](/docs/{{version}}/starter-kits)
11 | - [Deployment](/docs/{{version}}/deployment)
12 | - ## Architecture Concepts
13 | - [Request Lifecycle](/docs/{{version}}/lifecycle)
14 | - [Service Container](/docs/{{version}}/container)
15 | - [Service Providers](/docs/{{version}}/providers)
16 | - [Facades](/docs/{{version}}/facades)
17 | - ## The Basics
18 | - [Routing](/docs/{{version}}/routing)
19 | - [Middleware](/docs/{{version}}/middleware)
20 | - [CSRF Protection](/docs/{{version}}/csrf)
21 | - [Controllers](/docs/{{version}}/controllers)
22 | - [Requests](/docs/{{version}}/requests)
23 | - [Responses](/docs/{{version}}/responses)
24 | - [Views](/docs/{{version}}/views)
25 | - [Blade Templates](/docs/{{version}}/blade)
26 | - [Asset Bundling](/docs/{{version}}/vite)
27 | - [URL Generation](/docs/{{version}}/urls)
28 | - [Session](/docs/{{version}}/session)
29 | - [Validation](/docs/{{version}}/validation)
30 | - [Error Handling](/docs/{{version}}/errors)
31 | - [Logging](/docs/{{version}}/logging)
32 | - ## Digging Deeper
33 | - [Artisan Console](/docs/{{version}}/artisan)
34 | - [Broadcasting](/docs/{{version}}/broadcasting)
35 | - [Cache](/docs/{{version}}/cache)
36 | - [Collections](/docs/{{version}}/collections)
37 | - [Concurrency](/docs/{{version}}/concurrency)
38 | - [Context](/docs/{{version}}/context)
39 | - [Contracts](/docs/{{version}}/contracts)
40 | - [Events](/docs/{{version}}/events)
41 | - [File Storage](/docs/{{version}}/filesystem)
42 | - [Helpers](/docs/{{version}}/helpers)
43 | - [HTTP Client](/docs/{{version}}/http-client)
44 | - [Localization](/docs/{{version}}/localization)
45 | - [Mail](/docs/{{version}}/mail)
46 | - [Notifications](/docs/{{version}}/notifications)
47 | - [Package Development](/docs/{{version}}/packages)
48 | - [Processes](/docs/{{version}}/processes)
49 | - [Queues](/docs/{{version}}/queues)
50 | - [Rate Limiting](/docs/{{version}}/rate-limiting)
51 | - [Strings](/docs/{{version}}/strings)
52 | - [Task Scheduling](/docs/{{version}}/scheduling)
53 | - ## Security
54 | - [Authentication](/docs/{{version}}/authentication)
55 | - [Authorization](/docs/{{version}}/authorization)
56 | - [Email Verification](/docs/{{version}}/verification)
57 | - [Encryption](/docs/{{version}}/encryption)
58 | - [Hashing](/docs/{{version}}/hashing)
59 | - [Password Reset](/docs/{{version}}/passwords)
60 | - ## Database
61 | - [Getting Started](/docs/{{version}}/database)
62 | - [Query Builder](/docs/{{version}}/queries)
63 | - [Pagination](/docs/{{version}}/pagination)
64 | - [Migrations](/docs/{{version}}/migrations)
65 | - [Seeding](/docs/{{version}}/seeding)
66 | - [Redis](/docs/{{version}}/redis)
67 | - [MongoDB](/docs/{{version}}/mongodb)
68 | - ## Eloquent ORM
69 | - [Getting Started](/docs/{{version}}/eloquent)
70 | - [Relationships](/docs/{{version}}/eloquent-relationships)
71 | - [Collections](/docs/{{version}}/eloquent-collections)
72 | - [Mutators / Casts](/docs/{{version}}/eloquent-mutators)
73 | - [API Resources](/docs/{{version}}/eloquent-resources)
74 | - [Serialization](/docs/{{version}}/eloquent-serialization)
75 | - [Factories](/docs/{{version}}/eloquent-factories)
76 | - ## Testing
77 | - [Getting Started](/docs/{{version}}/testing)
78 | - [HTTP Tests](/docs/{{version}}/http-tests)
79 | - [Console Tests](/docs/{{version}}/console-tests)
80 | - [Browser Tests](/docs/{{version}}/dusk)
81 | - [Database](/docs/{{version}}/database-testing)
82 | - [Mocking](/docs/{{version}}/mocking)
83 | - ## Packages
84 | - [Cashier (Stripe)](/docs/{{version}}/billing)
85 | - [Cashier (Paddle)](/docs/{{version}}/cashier-paddle)
86 | - [Dusk](/docs/{{version}}/dusk)
87 | - [Envoy](/docs/{{version}}/envoy)
88 | - [Fortify](/docs/{{version}}/fortify)
89 | - [Folio](/docs/{{version}}/folio)
90 | - [Homestead](/docs/{{version}}/homestead)
91 | - [Horizon](/docs/{{version}}/horizon)
92 | - [MCP](/docs/{{version}}/mcp)
93 | - [Mix](/docs/{{version}}/mix)
94 | - [Octane](/docs/{{version}}/octane)
95 | - [Passport](/docs/{{version}}/passport)
96 | - [Pennant](/docs/{{version}}/pennant)
97 | - [Pint](/docs/{{version}}/pint)
98 | - [Precognition](/docs/{{version}}/precognition)
99 | - [Prompts](/docs/{{version}}/prompts)
100 | - [Pulse](/docs/{{version}}/pulse)
101 | - [Reverb](/docs/{{version}}/reverb)
102 | - [Sail](/docs/{{version}}/sail)
103 | - [Sanctum](/docs/{{version}}/sanctum)
104 | - [Scout](/docs/{{version}}/scout)
105 | - [Socialite](/docs/{{version}}/socialite)
106 | - [Telescope](/docs/{{version}}/telescope)
107 | - [Valet](/docs/{{version}}/valet)
108 | - [API Documentation](https://api.laravel.com/docs/12.x)
109 |
--------------------------------------------------------------------------------
/rate-limiting.md:
--------------------------------------------------------------------------------
1 | # Rate Limiting
2 |
3 | - [Introduction](#introduction)
4 | - [Cache Configuration](#cache-configuration)
5 | - [Basic Usage](#basic-usage)
6 | - [Manually Incrementing Attempts](#manually-incrementing-attempts)
7 | - [Clearing Attempts](#clearing-attempts)
8 |
9 |
10 | ## Introduction
11 |
12 | Laravel includes a simple to use rate limiting abstraction which, in conjunction with your application's [cache](cache), provides an easy way to limit any action during a specified window of time.
13 |
14 | > [!NOTE]
15 | > If you are interested in rate limiting incoming HTTP requests, please consult the [rate limiter middleware documentation](/docs/{{version}}/routing#rate-limiting).
16 |
17 |
18 | ### Cache Configuration
19 |
20 | Typically, the rate limiter utilizes your default application cache as defined by the `default` key within your application's `cache` configuration file. However, you may specify which cache driver the rate limiter should use by defining a `limiter` key within your application's `cache` configuration file:
21 |
22 | ```php
23 | 'default' => env('CACHE_STORE', 'database'),
24 |
25 | 'limiter' => 'redis', // [tl! add]
26 | ```
27 |
28 |
29 | ## Basic Usage
30 |
31 | The `Illuminate\Support\Facades\RateLimiter` facade may be used to interact with the rate limiter. The simplest method offered by the rate limiter is the `attempt` method, which rate limits a given callback for a given number of seconds.
32 |
33 | The `attempt` method returns `false` when the callback has no remaining attempts available; otherwise, the `attempt` method will return the callback's result or `true`. The first argument accepted by the `attempt` method is a rate limiter "key", which may be any string of your choosing that represents the action being rate limited:
34 |
35 | ```php
36 | use Illuminate\Support\Facades\RateLimiter;
37 |
38 | $executed = RateLimiter::attempt(
39 | 'send-message:'.$user->id,
40 | $perMinute = 5,
41 | function() {
42 | // Send message...
43 | }
44 | );
45 |
46 | if (! $executed) {
47 | return 'Too many messages sent!';
48 | }
49 | ```
50 |
51 | If necessary, you may provide a fourth argument to the `attempt` method, which is the "decay rate", or the number of seconds until the available attempts are reset. For example, we can modify the example above to allow five attempts every two minutes:
52 |
53 | ```php
54 | $executed = RateLimiter::attempt(
55 | 'send-message:'.$user->id,
56 | $perTwoMinutes = 5,
57 | function() {
58 | // Send message...
59 | },
60 | $decayRate = 120,
61 | );
62 | ```
63 |
64 |
65 | ### Manually Incrementing Attempts
66 |
67 | If you would like to manually interact with the rate limiter, a variety of other methods are available. For example, you may invoke the `tooManyAttempts` method to determine if a given rate limiter key has exceeded its maximum number of allowed attempts per minute:
68 |
69 | ```php
70 | use Illuminate\Support\Facades\RateLimiter;
71 |
72 | if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
73 | return 'Too many attempts!';
74 | }
75 |
76 | RateLimiter::increment('send-message:'.$user->id);
77 |
78 | // Send message...
79 | ```
80 |
81 | Alternatively, you may use the `remaining` method to retrieve the number of attempts remaining for a given key. If a given key has retries remaining, you may invoke the `increment` method to increment the number of total attempts:
82 |
83 | ```php
84 | use Illuminate\Support\Facades\RateLimiter;
85 |
86 | if (RateLimiter::remaining('send-message:'.$user->id, $perMinute = 5)) {
87 | RateLimiter::increment('send-message:'.$user->id);
88 |
89 | // Send message...
90 | }
91 | ```
92 |
93 | If you would like to increment the value for a given rate limiter key by more than one, you may provide the desired amount to the `increment` method:
94 |
95 | ```php
96 | RateLimiter::increment('send-message:'.$user->id, amount: 5);
97 | ```
98 |
99 |
100 | #### Determining Limiter Availability
101 |
102 | When a key has no more attempts left, the `availableIn` method returns the number of seconds remaining until more attempts will be available:
103 |
104 | ```php
105 | use Illuminate\Support\Facades\RateLimiter;
106 |
107 | if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
108 | $seconds = RateLimiter::availableIn('send-message:'.$user->id);
109 |
110 | return 'You may try again in '.$seconds.' seconds.';
111 | }
112 |
113 | RateLimiter::increment('send-message:'.$user->id);
114 |
115 | // Send message...
116 | ```
117 |
118 |
119 | ### Clearing Attempts
120 |
121 | You may reset the number of attempts for a given rate limiter key using the `clear` method. For example, you may reset the number of attempts when a given message is read by the receiver:
122 |
123 | ```php
124 | use App\Models\Message;
125 | use Illuminate\Support\Facades\RateLimiter;
126 |
127 | /**
128 | * Mark the message as read.
129 | */
130 | public function read(Message $message): Message
131 | {
132 | $message->markAsRead();
133 |
134 | RateLimiter::clear('send-message:'.$message->user_id);
135 |
136 | return $message;
137 | }
138 | ```
139 |
--------------------------------------------------------------------------------
/hashing.md:
--------------------------------------------------------------------------------
1 | # Hashing
2 |
3 | - [Introduction](#introduction)
4 | - [Configuration](#configuration)
5 | - [Basic Usage](#basic-usage)
6 | - [Hashing Passwords](#hashing-passwords)
7 | - [Verifying That a Password Matches a Hash](#verifying-that-a-password-matches-a-hash)
8 | - [Determining if a Password Needs to be Rehashed](#determining-if-a-password-needs-to-be-rehashed)
9 | - [Hash Algorithm Verification](#hash-algorithm-verification)
10 |
11 |
12 | ## Introduction
13 |
14 | The Laravel `Hash` [facade](/docs/{{version}}/facades) provides secure Bcrypt and Argon2 hashing for storing user passwords. If you are using one of the [Laravel application starter kits](/docs/{{version}}/starter-kits), Bcrypt will be used for registration and authentication by default.
15 |
16 | Bcrypt is a great choice for hashing passwords because its "work factor" is adjustable, which means that the time it takes to generate a hash can be increased as hardware power increases. When hashing passwords, slow is good. The longer an algorithm takes to hash a password, the longer it takes malicious users to generate "rainbow tables" of all possible string hash values that may be used in brute force attacks against applications.
17 |
18 |
19 | ## Configuration
20 |
21 | By default, Laravel uses the `bcrypt` hashing driver when hashing data. However, several other hashing drivers are supported, including [argon](https://en.wikipedia.org/wiki/Argon2) and [argon2id](https://en.wikipedia.org/wiki/Argon2).
22 |
23 | You may specify your application's hashing driver using the `HASH_DRIVER` environment variable. But, if you want to customize all of Laravel's hashing driver options, you should publish the complete `hashing` configuration file using the `config:publish` Artisan command:
24 |
25 | ```shell
26 | php artisan config:publish hashing
27 | ```
28 |
29 |
30 | ## Basic Usage
31 |
32 |
33 | ### Hashing Passwords
34 |
35 | You may hash a password by calling the `make` method on the `Hash` facade:
36 |
37 | ```php
38 | user()->fill([
56 | 'password' => Hash::make($request->newPassword)
57 | ])->save();
58 |
59 | return redirect('/profile');
60 | }
61 | }
62 | ```
63 |
64 |
65 | #### Adjusting The Bcrypt Work Factor
66 |
67 | If you are using the Bcrypt algorithm, the `make` method allows you to manage the work factor of the algorithm using the `rounds` option; however, the default work factor managed by Laravel is acceptable for most applications:
68 |
69 | ```php
70 | $hashed = Hash::make('password', [
71 | 'rounds' => 12,
72 | ]);
73 | ```
74 |
75 |
76 | #### Adjusting The Argon2 Work Factor
77 |
78 | If you are using the Argon2 algorithm, the `make` method allows you to manage the work factor of the algorithm using the `memory`, `time`, and `threads` options; however, the default values managed by Laravel are acceptable for most applications:
79 |
80 | ```php
81 | $hashed = Hash::make('password', [
82 | 'memory' => 1024,
83 | 'time' => 2,
84 | 'threads' => 2,
85 | ]);
86 | ```
87 |
88 | > [!NOTE]
89 | > For more information on these options, please refer to the [official PHP documentation regarding Argon hashing](https://secure.php.net/manual/en/function.password-hash.php).
90 |
91 |
92 | ### Verifying That a Password Matches a Hash
93 |
94 | The `check` method provided by the `Hash` facade allows you to verify that a given plain-text string corresponds to a given hash:
95 |
96 | ```php
97 | if (Hash::check('plain-text', $hashedPassword)) {
98 | // The passwords match...
99 | }
100 | ```
101 |
102 |
103 | ### Determining if a Password Needs to be Rehashed
104 |
105 | The `needsRehash` method provided by the `Hash` facade allows you to determine if the work factor used by the hasher has changed since the password was hashed. Some applications choose to perform this check during the application's authentication process:
106 |
107 | ```php
108 | if (Hash::needsRehash($hashed)) {
109 | $hashed = Hash::make('plain-text');
110 | }
111 | ```
112 |
113 |
114 | ## Hash Algorithm Verification
115 |
116 | To prevent hash algorithm manipulation, Laravel's `Hash::check` method will first verify the given hash was generated using the application's selected hashing algorithm. If the algorithms are different, a `RuntimeException` exception will be thrown.
117 |
118 | This is the expected behavior for most applications, where the hashing algorithm is not expected to change and different algorithms can be an indication of a malicious attack. However, if you need to support multiple hashing algorithms within your application, such as when migrating from one algorithm to another, you can disable hash algorithm verification by setting the `HASH_VERIFY` environment variable to `false`:
119 |
120 | ```ini
121 | HASH_VERIFY=false
122 | ```
123 |
--------------------------------------------------------------------------------
/mongodb.md:
--------------------------------------------------------------------------------
1 | # MongoDB
2 |
3 | - [Introduction](#introduction)
4 | - [Installation](#installation)
5 | - [MongoDB Driver](#mongodb-driver)
6 | - [Starting a MongoDB Server](#starting-a-mongodb-server)
7 | - [Install the Laravel MongoDB Package](#install-the-laravel-mongodb-package)
8 | - [Configuration](#configuration)
9 | - [Features](#features)
10 |
11 |
12 | ## Introduction
13 |
14 | [MongoDB](https://www.mongodb.com/resources/products/fundamentals/why-use-mongodb) is one of the most popular NoSQL document-oriented database, used for its high write load (useful for analytics or IoT) and high availability (easy to set replica sets with automatic failover). It can also shard the database easily for horizontal scalability and has a powerful query language for doing aggregation, text search or geospatial queries.
15 |
16 | Instead of storing data in tables of rows or columns like SQL databases, each record in a MongoDB database is a document described in BSON, a binary representation of the data. Applications can then retrieve this information in a JSON format. It supports a wide variety of data types, including documents, arrays, embedded documents, and binary data.
17 |
18 | Before using MongoDB with Laravel, we recommend installing and using the `mongodb/laravel-mongodb` package via Composer. The `laravel-mongodb` package is officially maintained by MongoDB, and while MongoDB is natively supported by PHP through the MongoDB driver, the [Laravel MongoDB](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/) package provides a richer integration with Eloquent and other Laravel features:
19 |
20 | ```shell
21 | composer require mongodb/laravel-mongodb
22 | ```
23 |
24 |
25 | ## Installation
26 |
27 |
28 | ### MongoDB Driver
29 |
30 | To connect to a MongoDB database, the `mongodb` PHP extension is required. If you are developing locally using [Laravel Herd](https://herd.laravel.com) or installed PHP via `php.new`, you already have this extension installed on your system. However, if you need to install the extension manually, you may do so via PECL:
31 |
32 | ```shell
33 | pecl install mongodb
34 | ```
35 |
36 | For more information on installing the MongoDB PHP extension, check out the [MongoDB PHP extension installation instructions](https://www.php.net/manual/en/mongodb.installation.php).
37 |
38 |
39 | ### Starting a MongoDB Server
40 |
41 | The MongoDB Community Server can be used to run MongoDB locally and is available for installation on Windows, macOS, Linux, or as a Docker container. To learn how to install MongoDB, please refer to the [official MongoDB Community installation guide](https://docs.mongodb.com/manual/administration/install-community/).
42 |
43 | The connection string for the MongoDB server can be set in your `.env` file:
44 |
45 | ```ini
46 | MONGODB_URI="mongodb://localhost:27017"
47 | MONGODB_DATABASE="laravel_app"
48 | ```
49 |
50 | For hosting MongoDB in the cloud, consider using [MongoDB Atlas](https://www.mongodb.com/cloud/atlas).
51 | To access a MongoDB Atlas cluster locally from your application, you will need to [add your own IP address in the cluster's network settings](https://www.mongodb.com/docs/atlas/security/add-ip-address-to-list/) to the project's IP Access List.
52 |
53 | The connection string for MongoDB Atlas can also be set in your `.env` file:
54 |
55 | ```ini
56 | MONGODB_URI="mongodb+srv://:@.mongodb.net/?retryWrites=true&w=majority"
57 | MONGODB_DATABASE="laravel_app"
58 | ```
59 |
60 |
61 | ### Install the Laravel MongoDB Package
62 |
63 | Finally, use Composer to install the Laravel MongoDB package:
64 |
65 | ```shell
66 | composer require mongodb/laravel-mongodb
67 | ```
68 |
69 | > [!NOTE]
70 | > This installation of the package will fail if the `mongodb` PHP extension is not installed. The PHP configuration can differ between the CLI and the web server, so ensure the extension is enabled in both configurations.
71 |
72 |
73 | ## Configuration
74 |
75 | You may configure your MongoDB connection via your application's `config/database.php` configuration file. Within this file, add a `mongodb` connection that utilizes the `mongodb` driver:
76 |
77 | ```php
78 | 'connections' => [
79 | 'mongodb' => [
80 | 'driver' => 'mongodb',
81 | 'dsn' => env('MONGODB_URI', 'mongodb://localhost:27017'),
82 | 'database' => env('MONGODB_DATABASE', 'laravel_app'),
83 | ],
84 | ],
85 | ```
86 |
87 |
88 | ## Features
89 |
90 | Once your configuration is complete, you can use the `mongodb` package and database connection in your application to leverage a variety of powerful features:
91 |
92 | - [Using Eloquent](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/eloquent-models/), models can be stored in MongoDB collections. In addition to the standard Eloquent features, the Laravel MongoDB package provides additional features such as embedded relationships. The package also provides direct access to the MongoDB driver, which can be used to execute operations such as raw queries and aggregation pipelines.
93 | - [Write complex queries](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/query-builder/) using the query builder.
94 | - The `mongodb` [cache driver](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/cache/) is optimized to use MongoDB features such as TTL indexes to automatically clear expired cache entries.
95 | - [Dispatch and process queued jobs](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/queues/) with the `mongodb` queue driver.
96 | - [Storing files in GridFS](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/filesystems/), via the [GridFS Adapter for Flysystem](https://flysystem.thephpleague.com/docs/adapter/gridfs/).
97 | - Most third party packages using a database connection or Eloquent can be used with MongoDB.
98 |
99 | To continue learning how to use MongoDB and Laravel, refer to MongoDB's [Quick Start guide](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/quick-start/).
100 |
--------------------------------------------------------------------------------
/seeding.md:
--------------------------------------------------------------------------------
1 | # Database: Seeding
2 |
3 | - [Introduction](#introduction)
4 | - [Writing Seeders](#writing-seeders)
5 | - [Using Model Factories](#using-model-factories)
6 | - [Calling Additional Seeders](#calling-additional-seeders)
7 | - [Muting Model Events](#muting-model-events)
8 | - [Running Seeders](#running-seeders)
9 |
10 |
11 | ## Introduction
12 |
13 | Laravel includes the ability to seed your database with data using seed classes. All seed classes are stored in the `database/seeders` directory. By default, a `DatabaseSeeder` class is defined for you. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.
14 |
15 | > [!NOTE]
16 | > [Mass assignment protection](/docs/{{version}}/eloquent#mass-assignment) is automatically disabled during database seeding.
17 |
18 |
19 | ## Writing Seeders
20 |
21 | To generate a seeder, execute the `make:seeder` [Artisan command](/docs/{{version}}/artisan). All seeders generated by the framework will be placed in the `database/seeders` directory:
22 |
23 | ```shell
24 | php artisan make:seeder UserSeeder
25 | ```
26 |
27 | A seeder class only contains one method by default: `run`. This method is called when the `db:seed` [Artisan command](/docs/{{version}}/artisan) is executed. Within the `run` method, you may insert data into your database however you wish. You may use the [query builder](/docs/{{version}}/queries) to manually insert data or you may use [Eloquent model factories](/docs/{{version}}/eloquent-factories).
28 |
29 | As an example, let's modify the default `DatabaseSeeder` class and add a database insert statement to the `run` method:
30 |
31 | ```php
32 | insert([
49 | 'name' => Str::random(10),
50 | 'email' => Str::random(10).'@example.com',
51 | 'password' => Hash::make('password'),
52 | ]);
53 | }
54 | }
55 | ```
56 |
57 | > [!NOTE]
58 | > You may type-hint any dependencies you need within the `run` method's signature. They will automatically be resolved via the Laravel [service container](/docs/{{version}}/container).
59 |
60 |
61 | ### Using Model Factories
62 |
63 | Of course, manually specifying the attributes for each model seed is cumbersome. Instead, you can use [model factories](/docs/{{version}}/eloquent-factories) to conveniently generate large amounts of database records. First, review the [model factory documentation](/docs/{{version}}/eloquent-factories) to learn how to define your factories.
64 |
65 | For example, let's create 50 users that each has one related post:
66 |
67 | ```php
68 | use App\Models\User;
69 |
70 | /**
71 | * Run the database seeders.
72 | */
73 | public function run(): void
74 | {
75 | User::factory()
76 | ->count(50)
77 | ->hasPosts(1)
78 | ->create();
79 | }
80 | ```
81 |
82 |
83 | ### Calling Additional Seeders
84 |
85 | Within the `DatabaseSeeder` class, you may use the `call` method to execute additional seed classes. Using the `call` method allows you to break up your database seeding into multiple files so that no single seeder class becomes too large. The `call` method accepts an array of seeder classes that should be executed:
86 |
87 | ```php
88 | /**
89 | * Run the database seeders.
90 | */
91 | public function run(): void
92 | {
93 | $this->call([
94 | UserSeeder::class,
95 | PostSeeder::class,
96 | CommentSeeder::class,
97 | ]);
98 | }
99 | ```
100 |
101 |
102 | ### Muting Model Events
103 |
104 | While running seeds, you may want to prevent models from dispatching events. You may achieve this using the `WithoutModelEvents` trait. When used, the `WithoutModelEvents` trait ensures no model events are dispatched, even if additional seed classes are executed via the `call` method:
105 |
106 | ```php
107 | call([
124 | UserSeeder::class,
125 | ]);
126 | }
127 | }
128 | ```
129 |
130 |
131 | ## Running Seeders
132 |
133 | You may execute the `db:seed` Artisan command to seed your database. By default, the `db:seed` command runs the `Database\Seeders\DatabaseSeeder` class, which may in turn invoke other seed classes. However, you may use the `--class` option to specify a specific seeder class to run individually:
134 |
135 | ```shell
136 | php artisan db:seed
137 |
138 | php artisan db:seed --class=UserSeeder
139 | ```
140 |
141 | You may also seed your database using the `migrate:fresh` command in combination with the `--seed` option, which will drop all tables and re-run all of your migrations. This command is useful for completely re-building your database. The `--seeder` option may be used to specify a specific seeder to run:
142 |
143 | ```shell
144 | php artisan migrate:fresh --seed
145 |
146 | php artisan migrate:fresh --seed --seeder=UserSeeder
147 | ```
148 |
149 |
150 | #### Forcing Seeders to Run in Production
151 |
152 | Some seeding operations may cause you to alter or lose data. In order to protect you from running seeding commands against your production database, you will be prompted for confirmation before the seeders are executed in the `production` environment. To force the seeders to run without a prompt, use the `--force` flag:
153 |
154 | ```shell
155 | php artisan db:seed --force
156 | ```
157 |
--------------------------------------------------------------------------------
/csrf.md:
--------------------------------------------------------------------------------
1 | # CSRF Protection
2 |
3 | - [Introduction](#csrf-introduction)
4 | - [Preventing CSRF Requests](#preventing-csrf-requests)
5 | - [Excluding URIs](#csrf-excluding-uris)
6 | - [X-CSRF-Token](#csrf-x-csrf-token)
7 | - [X-XSRF-Token](#csrf-x-xsrf-token)
8 |
9 |
10 | ## Introduction
11 |
12 | Cross-site request forgeries are a type of malicious exploit whereby unauthorized commands are performed on behalf of an authenticated user. Thankfully, Laravel makes it easy to protect your application from [cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) attacks.
13 |
14 |
15 | #### An Explanation of the Vulnerability
16 |
17 | In case you're not familiar with cross-site request forgeries, let's discuss an example of how this vulnerability can be exploited. Imagine your application has a `/user/email` route that accepts a `POST` request to change the authenticated user's email address. Most likely, this route expects an `email` input field to contain the email address the user would like to begin using.
18 |
19 | Without CSRF protection, a malicious website could create an HTML form that points to your application's `/user/email` route and submits the malicious user's own email address:
20 |
21 | ```blade
22 |
25 |
26 |
29 | ```
30 |
31 | If the malicious website automatically submits the form when the page is loaded, the malicious user only needs to lure an unsuspecting user of your application to visit their website and their email address will be changed in your application.
32 |
33 | To prevent this vulnerability, we need to inspect every incoming `POST`, `PUT`, `PATCH`, or `DELETE` request for a secret session value that the malicious application is unable to access.
34 |
35 |
36 | ## Preventing CSRF Requests
37 |
38 | Laravel automatically generates a CSRF "token" for each active [user session](/docs/{{version}}/session) managed by the application. This token is used to verify that the authenticated user is the person actually making the requests to the application. Since this token is stored in the user's session and changes each time the session is regenerated, a malicious application is unable to access it.
39 |
40 | The current session's CSRF token can be accessed via the request's session or via the `csrf_token` helper function:
41 |
42 | ```php
43 | use Illuminate\Http\Request;
44 |
45 | Route::get('/token', function (Request $request) {
46 | $token = $request->session()->token();
47 |
48 | $token = csrf_token();
49 |
50 | // ...
51 | });
52 | ```
53 |
54 | Anytime you define a "POST", "PUT", "PATCH", or "DELETE" HTML form in your application, you should include a hidden CSRF `_token` field in the form so that the CSRF protection middleware can validate the request. For convenience, you may use the `@csrf` Blade directive to generate the hidden token input field:
55 |
56 | ```blade
57 |
63 | ```
64 |
65 | The `Illuminate\Foundation\Http\Middleware\ValidateCsrfToken` [middleware](/docs/{{version}}/middleware), which is included in the `web` middleware group by default, will automatically verify that the token in the request input matches the token stored in the session. When these two tokens match, we know that the authenticated user is the one initiating the request.
66 |
67 |
68 | ### CSRF Tokens & SPAs
69 |
70 | If you are building an SPA that is utilizing Laravel as an API backend, you should consult the [Laravel Sanctum documentation](/docs/{{version}}/sanctum) for information on authenticating with your API and protecting against CSRF vulnerabilities.
71 |
72 |
73 | ### Excluding URIs From CSRF Protection
74 |
75 | Sometimes you may wish to exclude a set of URIs from CSRF protection. For example, if you are using [Stripe](https://stripe.com) to process payments and are utilizing their webhook system, you will need to exclude your Stripe webhook handler route from CSRF protection since Stripe will not know what CSRF token to send to your routes.
76 |
77 | Typically, you should place these kinds of routes outside of the `web` middleware group that Laravel applies to all routes in the `routes/web.php` file. However, you may also exclude specific routes by providing their URIs to the `validateCsrfTokens` method in your application's `bootstrap/app.php` file:
78 |
79 | ```php
80 | ->withMiddleware(function (Middleware $middleware): void {
81 | $middleware->validateCsrfTokens(except: [
82 | 'stripe/*',
83 | 'http://example.com/foo/bar',
84 | 'http://example.com/foo/*',
85 | ]);
86 | })
87 | ```
88 |
89 | > [!NOTE]
90 | > For convenience, the CSRF middleware is automatically disabled for all routes when [running tests](/docs/{{version}}/testing).
91 |
92 |
93 | ## X-CSRF-TOKEN
94 |
95 | In addition to checking for the CSRF token as a POST parameter, the `Illuminate\Foundation\Http\Middleware\ValidateCsrfToken` middleware, which is included in the `web` middleware group by default, will also check for the `X-CSRF-TOKEN` request header. You could, for example, store the token in an HTML `meta` tag:
96 |
97 | ```blade
98 |
99 | ```
100 |
101 | Then, you can instruct a library like jQuery to automatically add the token to all request headers. This provides simple, convenient CSRF protection for your AJAX based applications using legacy JavaScript technology:
102 |
103 | ```js
104 | $.ajaxSetup({
105 | headers: {
106 | 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
107 | }
108 | });
109 | ```
110 |
111 |
112 | ## X-XSRF-TOKEN
113 |
114 | Laravel stores the current CSRF token in an encrypted `XSRF-TOKEN` cookie that is included with each response generated by the framework. You can use the cookie value to set the `X-XSRF-TOKEN` request header.
115 |
116 | This cookie is primarily sent as a developer convenience since some JavaScript frameworks and libraries, like Angular and Axios, automatically place its value in the `X-XSRF-TOKEN` header on same-origin requests.
117 |
118 | > [!NOTE]
119 | > By default, the `resources/js/bootstrap.js` file includes the Axios HTTP library which will automatically send the `X-XSRF-TOKEN` header for you.
120 |
--------------------------------------------------------------------------------
/lifecycle.md:
--------------------------------------------------------------------------------
1 | # Request Lifecycle
2 |
3 | - [Introduction](#introduction)
4 | - [Lifecycle Overview](#lifecycle-overview)
5 | - [First Steps](#first-steps)
6 | - [HTTP / Console Kernels](#http-console-kernels)
7 | - [Service Providers](#service-providers)
8 | - [Routing](#routing)
9 | - [Finishing Up](#finishing-up)
10 | - [Focus on Service Providers](#focus-on-service-providers)
11 |
12 |
13 | ## Introduction
14 |
15 | When using any tool in the "real world", you feel more confident if you understand how that tool works. Application development is no different. When you understand how your development tools function, you feel more comfortable and confident using them.
16 |
17 | The goal of this document is to give you a good, high-level overview of how the Laravel framework works. By getting to know the overall framework better, everything feels less "magical" and you will be more confident building your applications. If you don't understand all of the terms right away, don't lose heart! Just try to get a basic grasp of what is going on, and your knowledge will grow as you explore other sections of the documentation.
18 |
19 |
20 | ## Lifecycle Overview
21 |
22 |
23 | ### First Steps
24 |
25 | The entry point for all requests to a Laravel application is the `public/index.php` file. All requests are directed to this file by your web server (Apache / Nginx) configuration. The `index.php` file doesn't contain much code. Rather, it is a starting point for loading the rest of the framework.
26 |
27 | The `index.php` file loads the Composer generated autoloader definition, and then retrieves an instance of the Laravel application from `bootstrap/app.php`. The first action taken by Laravel itself is to create an instance of the application / [service container](/docs/{{version}}/container).
28 |
29 |
30 | ### HTTP / Console Kernels
31 |
32 | Next, the incoming request is sent to either the HTTP kernel or the console kernel, using the `handleRequest` or `handleCommand` methods of the application instance, depending on the type of request entering the application. These two kernels serve as the central location through which all requests flow. For now, let's just focus on the HTTP kernel, which is an instance of `Illuminate\Foundation\Http\Kernel`.
33 |
34 | The HTTP kernel defines an array of `bootstrappers` that will be run before the request is executed. These bootstrappers configure error handling, configure logging, [detect the application environment](/docs/{{version}}/configuration#environment-configuration), and perform other tasks that need to be done before the request is actually handled. Typically, these classes handle internal Laravel configuration that you do not need to worry about.
35 |
36 | The HTTP kernel is also responsible for passing the request through the application's middleware stack. These middleware handle reading and writing the [HTTP session](/docs/{{version}}/session), determining if the application is in maintenance mode, [verifying the CSRF token](/docs/{{version}}/csrf), and more. We'll talk more about these soon.
37 |
38 | The method signature for the HTTP kernel's `handle` method is quite simple: it receives a `Request` and returns a `Response`. Think of the kernel as being a big black box that represents your entire application. Feed it HTTP requests and it will return HTTP responses.
39 |
40 |
41 | ### Service Providers
42 |
43 | One of the most important kernel bootstrapping actions is loading the [service providers](/docs/{{version}}/providers) for your application. Service providers are responsible for bootstrapping all of the framework's various components, such as the database, queue, validation, and routing components.
44 |
45 | Laravel will iterate through this list of providers and instantiate each of them. After instantiating the providers, the `register` method will be called on all of the providers. Then, once all of the providers have been registered, the `boot` method will be called on each provider. This is so service providers may depend on every container binding being registered and available by the time their `boot` method is executed.
46 |
47 | Essentially every major feature offered by Laravel is bootstrapped and configured by a service provider. Since they bootstrap and configure so many features offered by the framework, service providers are the most important aspect of the entire Laravel bootstrap process.
48 |
49 | While the framework internally uses dozens of service providers, you also have the option to create your own. You can find a list of the user-defined or third-party service providers that your application is using in the `bootstrap/providers.php` file.
50 |
51 |
52 | ### Routing
53 |
54 | Once the application has been bootstrapped and all service providers have been registered, the `Request` will be handed off to the router for dispatching. The router will dispatch the request to a route or controller, as well as run any route specific middleware.
55 |
56 | Middleware provide a convenient mechanism for filtering or examining HTTP requests entering your application. For example, Laravel includes a middleware that verifies if the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application. Some middleware are assigned to all routes within the application, like `PreventRequestsDuringMaintenance`, while some are only assigned to specific routes or route groups. You can learn more about middleware by reading the complete [middleware documentation](/docs/{{version}}/middleware).
57 |
58 | If the request passes through all of the matched route's assigned middleware, the route or controller method will be executed and the response returned by the route or controller method will be sent back through the route's chain of middleware.
59 |
60 |
61 | ### Finishing Up
62 |
63 | Once the route or controller method returns a response, the response will travel back outward through the route's middleware, giving the application a chance to modify or examine the outgoing response.
64 |
65 | Finally, once the response travels back through the middleware, the HTTP kernel's `handle` method returns the response object to the `handleRequest` of the application instance, and this method calls the `send` method on the returned response. The `send` method sends the response content to the user's web browser. We've now completed our journey through the entire Laravel request lifecycle!
66 |
67 |
68 | ## Focus on Service Providers
69 |
70 | Service providers are truly the key to bootstrapping a Laravel application. The application instance is created, the service providers are registered, and the request is handed to the bootstrapped application. It's really that simple!
71 |
72 | Having a firm grasp of how a Laravel application is built and bootstrapped via service providers is very valuable. Your application's user-defined service providers are stored in the `app/Providers` directory.
73 |
74 | By default, the `AppServiceProvider` is fairly empty. This provider is a great place to add your application's own bootstrapping and service container bindings. For large applications, you may wish to create several service providers, each with more granular bootstrapping for specific services used by your application.
75 |
--------------------------------------------------------------------------------
/console-tests.md:
--------------------------------------------------------------------------------
1 | # Console Tests
2 |
3 | - [Introduction](#introduction)
4 | - [Success / Failure Expectations](#success-failure-expectations)
5 | - [Input / Output Expectations](#input-output-expectations)
6 | - [Console Events](#console-events)
7 |
8 |
9 | ## Introduction
10 |
11 | In addition to simplifying HTTP testing, Laravel provides a simple API for testing your application's [custom console commands](/docs/{{version}}/artisan).
12 |
13 |
14 | ## Success / Failure Expectations
15 |
16 | To get started, let's explore how to make assertions regarding an Artisan command's exit code. To accomplish this, we will use the `artisan` method to invoke an Artisan command from our test. Then, we will use the `assertExitCode` method to assert that the command completed with a given exit code:
17 |
18 | ```php tab=Pest
19 | test('console command', function () {
20 | $this->artisan('inspire')->assertExitCode(0);
21 | });
22 | ```
23 |
24 | ```php tab=PHPUnit
25 | /**
26 | * Test a console command.
27 | */
28 | public function test_console_command(): void
29 | {
30 | $this->artisan('inspire')->assertExitCode(0);
31 | }
32 | ```
33 |
34 | You may use the `assertNotExitCode` method to assert that the command did not exit with a given exit code:
35 |
36 | ```php
37 | $this->artisan('inspire')->assertNotExitCode(1);
38 | ```
39 |
40 | Of course, all terminal commands typically exit with a status code of `0` when they are successful and a non-zero exit code when they are not successful. Therefore, for convenience, you may utilize the `assertSuccessful` and `assertFailed` assertions to assert that a given command exited with a successful exit code or not:
41 |
42 | ```php
43 | $this->artisan('inspire')->assertSuccessful();
44 |
45 | $this->artisan('inspire')->assertFailed();
46 | ```
47 |
48 |
49 | ## Input / Output Expectations
50 |
51 | Laravel allows you to easily "mock" user input for your console commands using the `expectsQuestion` method. In addition, you may specify the exit code and text that you expect to be output by the console command using the `assertExitCode` and `expectsOutput` methods. For example, consider the following console command:
52 |
53 | ```php
54 | Artisan::command('question', function () {
55 | $name = $this->ask('What is your name?');
56 |
57 | $language = $this->choice('Which language do you prefer?', [
58 | 'PHP',
59 | 'Ruby',
60 | 'Python',
61 | ]);
62 |
63 | $this->line('Your name is '.$name.' and you prefer '.$language.'.');
64 | });
65 | ```
66 |
67 | You may test this command with the following test:
68 |
69 | ```php tab=Pest
70 | test('console command', function () {
71 | $this->artisan('question')
72 | ->expectsQuestion('What is your name?', 'Taylor Otwell')
73 | ->expectsQuestion('Which language do you prefer?', 'PHP')
74 | ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.')
75 | ->doesntExpectOutput('Your name is Taylor Otwell and you prefer Ruby.')
76 | ->assertExitCode(0);
77 | });
78 | ```
79 |
80 | ```php tab=PHPUnit
81 | /**
82 | * Test a console command.
83 | */
84 | public function test_console_command(): void
85 | {
86 | $this->artisan('question')
87 | ->expectsQuestion('What is your name?', 'Taylor Otwell')
88 | ->expectsQuestion('Which language do you prefer?', 'PHP')
89 | ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.')
90 | ->doesntExpectOutput('Your name is Taylor Otwell and you prefer Ruby.')
91 | ->assertExitCode(0);
92 | }
93 | ```
94 |
95 | If you are utilizing the `search` or `multisearch` functions provided by [Laravel Prompts](/docs/{{version}}/prompts), you may use the `expectsSearch` assertion to mock the user's input, search results, and selection:
96 |
97 | ```php tab=Pest
98 | test('console command', function () {
99 | $this->artisan('example')
100 | ->expectsSearch('What is your name?', search: 'Tay', answers: [
101 | 'Taylor Otwell',
102 | 'Taylor Swift',
103 | 'Darian Taylor'
104 | ], answer: 'Taylor Otwell')
105 | ->assertExitCode(0);
106 | });
107 | ```
108 |
109 | ```php tab=PHPUnit
110 | /**
111 | * Test a console command.
112 | */
113 | public function test_console_command(): void
114 | {
115 | $this->artisan('example')
116 | ->expectsSearch('What is your name?', search: 'Tay', answers: [
117 | 'Taylor Otwell',
118 | 'Taylor Swift',
119 | 'Darian Taylor'
120 | ], answer: 'Taylor Otwell')
121 | ->assertExitCode(0);
122 | }
123 | ```
124 |
125 | You may also assert that a console command does not generate any output using the `doesntExpectOutput` method:
126 |
127 | ```php tab=Pest
128 | test('console command', function () {
129 | $this->artisan('example')
130 | ->doesntExpectOutput()
131 | ->assertExitCode(0);
132 | });
133 | ```
134 |
135 | ```php tab=PHPUnit
136 | /**
137 | * Test a console command.
138 | */
139 | public function test_console_command(): void
140 | {
141 | $this->artisan('example')
142 | ->doesntExpectOutput()
143 | ->assertExitCode(0);
144 | }
145 | ```
146 |
147 | The `expectsOutputToContain` and `doesntExpectOutputToContain` methods may be used to make assertions against a portion of the output:
148 |
149 | ```php tab=Pest
150 | test('console command', function () {
151 | $this->artisan('example')
152 | ->expectsOutputToContain('Taylor')
153 | ->assertExitCode(0);
154 | });
155 | ```
156 |
157 | ```php tab=PHPUnit
158 | /**
159 | * Test a console command.
160 | */
161 | public function test_console_command(): void
162 | {
163 | $this->artisan('example')
164 | ->expectsOutputToContain('Taylor')
165 | ->assertExitCode(0);
166 | }
167 | ```
168 |
169 |
170 | #### Confirmation Expectations
171 |
172 | When writing a command which expects confirmation in the form of a "yes" or "no" answer, you may utilize the `expectsConfirmation` method:
173 |
174 | ```php
175 | $this->artisan('module:import')
176 | ->expectsConfirmation('Do you really wish to run this command?', 'no')
177 | ->assertExitCode(1);
178 | ```
179 |
180 |
181 | #### Table Expectations
182 |
183 | If your command displays a table of information using Artisan's `table` method, it can be cumbersome to write output expectations for the entire table. Instead, you may use the `expectsTable` method. This method accepts the table's headers as its first argument and the table's data as its second argument:
184 |
185 | ```php
186 | $this->artisan('users:all')
187 | ->expectsTable([
188 | 'ID',
189 | 'Email',
190 | ], [
191 | [1, 'taylor@example.com'],
192 | [2, 'abigail@example.com'],
193 | ]);
194 | ```
195 |
196 |
197 | ## Console Events
198 |
199 | By default, the `Illuminate\Console\Events\CommandStarting` and `Illuminate\Console\Events\CommandFinished` events are not dispatched while running your application's tests. However, you can enable these events for a given test class by adding the `Illuminate\Foundation\Testing\WithConsoleEvents` trait to the class:
200 |
201 | ```php tab=Pest
202 | use(WithConsoleEvents::class);
207 |
208 | // ...
209 | ```
210 |
211 | ```php tab=PHPUnit
212 |
14 | ## Introduction
15 |
16 | [Laravel Pint](https://github.com/laravel/pint) is an opinionated PHP code style fixer for minimalists. Pint is built on top of [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) and makes it simple to ensure that your code style stays clean and consistent.
17 |
18 | Pint is automatically installed with all new Laravel applications so you may start using it immediately. By default, Pint does not require any configuration and will fix code style issues in your code by following the opinionated coding style of Laravel.
19 |
20 |
21 | ## Installation
22 |
23 | Pint is included in recent releases of the Laravel framework, so installation is typically unnecessary. However, for older applications, you may install Laravel Pint via Composer:
24 |
25 | ```shell
26 | composer require laravel/pint --dev
27 | ```
28 |
29 |
30 | ## Running Pint
31 |
32 | You can instruct Pint to fix code style issues by invoking the `pint` binary that is available in your project's `vendor/bin` directory:
33 |
34 | ```shell
35 | ./vendor/bin/pint
36 | ```
37 |
38 | If you would like Pint to run in parallel mode (experimental) for improved performance, you may use the `--parallel` option:
39 |
40 | ```shell
41 | ./vendor/bin/pint --parallel
42 | ```
43 |
44 | Parallel mode also allows you to specify the maximum number of processes to run via the `--max-processes` option. If this option is not provided, Pint will use every available core on your machine:
45 |
46 | ```shell
47 | ./vendor/bin/pint --parallel --max-processes=4
48 | ```
49 |
50 | You may also run Pint on specific files or directories:
51 |
52 | ```shell
53 | ./vendor/bin/pint app/Models
54 |
55 | ./vendor/bin/pint app/Models/User.php
56 | ```
57 |
58 | Pint will display a thorough list of all of the files that it updates. You can view even more detail about Pint's changes by providing the `-v` option when invoking Pint:
59 |
60 | ```shell
61 | ./vendor/bin/pint -v
62 | ```
63 |
64 | If you would like Pint to simply inspect your code for style errors without actually changing the files, you may use the `--test` option. Pint will return a non-zero exit code if any code style errors are found:
65 |
66 | ```shell
67 | ./vendor/bin/pint --test
68 | ```
69 |
70 | If you would like Pint to only modify the files that differ from the provided branch according to Git, you may use the `--diff=[branch]` option. This can be effectively used in your CI environment (like GitHub actions) to save time by only inspecting new or modified files:
71 |
72 | ```shell
73 | ./vendor/bin/pint --diff=main
74 | ```
75 |
76 | If you would like Pint to only modify the files that have uncommitted changes according to Git, you may use the `--dirty` option:
77 |
78 | ```shell
79 | ./vendor/bin/pint --dirty
80 | ```
81 |
82 | If you would like Pint to fix any files with code style errors but also exit with a non-zero exit code if any errors were fixed, you may use the `--repair` option:
83 |
84 | ```shell
85 | ./vendor/bin/pint --repair
86 | ```
87 |
88 |
89 | ## Configuring Pint
90 |
91 | As previously mentioned, Pint does not require any configuration. However, if you wish to customize the presets, rules, or inspected folders, you may do so by creating a `pint.json` file in your project's root directory:
92 |
93 | ```json
94 | {
95 | "preset": "laravel"
96 | }
97 | ```
98 |
99 | In addition, if you wish to use a `pint.json` from a specific directory, you may provide the `--config` option when invoking Pint:
100 |
101 | ```shell
102 | ./vendor/bin/pint --config vendor/my-company/coding-style/pint.json
103 | ```
104 |
105 |
106 | ### Presets
107 |
108 | Presets define a set of rules that can be used to fix code style issues in your code. By default, Pint uses the `laravel` preset, which fixes issues by following the opinionated coding style of Laravel. However, you may specify a different preset by providing the `--preset` option to Pint:
109 |
110 | ```shell
111 | ./vendor/bin/pint --preset psr12
112 | ```
113 |
114 | If you wish, you may also set the preset in your project's `pint.json` file:
115 |
116 | ```json
117 | {
118 | "preset": "psr12"
119 | }
120 | ```
121 |
122 | Pint's currently supported presets are: `laravel`, `per`, `psr12`, `symfony`, and `empty`.
123 |
124 |
125 | ### Rules
126 |
127 | Rules are style guidelines that Pint will use to fix code style issues in your code. As mentioned above, presets are predefined groups of rules that should be perfect for most PHP projects, so you typically will not need to worry about the individual rules they contain.
128 |
129 | However, if you wish, you may enable or disable specific rules in your `pint.json` file or use the `empty` preset and define the rules from scratch:
130 |
131 | ```json
132 | {
133 | "preset": "laravel",
134 | "rules": {
135 | "simplified_null_return": true,
136 | "array_indentation": false,
137 | "new_with_parentheses": {
138 | "anonymous_class": true,
139 | "named_class": true
140 | }
141 | }
142 | }
143 | ```
144 |
145 | Pint is built on top of [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer). Therefore, you may use any of its rules to fix code style issues in your project: [PHP CS Fixer Configurator](https://mlocati.github.io/php-cs-fixer-configurator).
146 |
147 |
148 | ### Excluding Files / Folders
149 |
150 | By default, Pint will inspect all `.php` files in your project except those in the `vendor` directory. If you wish to exclude more folders, you may do so using the `exclude` configuration option:
151 |
152 | ```json
153 | {
154 | "exclude": [
155 | "my-specific/folder"
156 | ]
157 | }
158 | ```
159 |
160 | If you wish to exclude all files that contain a given name pattern, you may do so using the `notName` configuration option:
161 |
162 | ```json
163 | {
164 | "notName": [
165 | "*-my-file.php"
166 | ]
167 | }
168 | ```
169 |
170 | If you would like to exclude a file by providing an exact path to the file, you may do so using the `notPath` configuration option:
171 |
172 | ```json
173 | {
174 | "notPath": [
175 | "path/to/excluded-file.php"
176 | ]
177 | }
178 | ```
179 |
180 |
181 | ## Continuous Integration
182 |
183 |
184 | ### GitHub Actions
185 |
186 | To automate linting your project with Laravel Pint, you can configure [GitHub Actions](https://github.com/features/actions) to run Pint whenever new code is pushed to GitHub. First, be sure to grant "Read and write permissions" to workflows within GitHub at **Settings > Actions > General > Workflow permissions**. Then, create a `.github/workflows/lint.yml` file with the following content:
187 |
188 | ```yaml
189 | name: Fix Code Style
190 |
191 | on: [push]
192 |
193 | jobs:
194 | lint:
195 | runs-on: ubuntu-latest
196 | strategy:
197 | fail-fast: true
198 | matrix:
199 | php: [8.4]
200 |
201 | steps:
202 | - name: Checkout code
203 | uses: actions/checkout@v5
204 |
205 | - name: Setup PHP
206 | uses: shivammathur/setup-php@v2
207 | with:
208 | php-version: ${{ matrix.php }}
209 | tools: pint
210 |
211 | - name: Run Pint
212 | run: pint
213 |
214 | - name: Commit linted files
215 | uses: stefanzweifel/git-auto-commit-action@v6
216 | ```
217 |
--------------------------------------------------------------------------------
/contributions.md:
--------------------------------------------------------------------------------
1 | # Contribution Guide
2 |
3 | - [Bug Reports](#bug-reports)
4 | - [Support Questions](#support-questions)
5 | - [Core Development Discussion](#core-development-discussion)
6 | - [Which Branch?](#which-branch)
7 | - [Compiled Assets](#compiled-assets)
8 | - [Security Vulnerabilities](#security-vulnerabilities)
9 | - [Coding Style](#coding-style)
10 | - [PHPDoc](#phpdoc)
11 | - [StyleCI](#styleci)
12 | - [Code of Conduct](#code-of-conduct)
13 |
14 |
15 | ## Bug Reports
16 |
17 | To encourage active collaboration, Laravel strongly encourages pull requests, not just bug reports. Pull requests will only be reviewed when marked as "ready for review" (not in the "draft" state) and all tests for new features are passing. Lingering, non-active pull requests left in the "draft" state will be closed after a few days.
18 |
19 | However, if you file a bug report, your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix.
20 |
21 | Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help yourself and others start on the path of fixing the problem. If you want to chip in, you can help out by fixing [any bugs listed in our issue trackers](https://github.com/issues?q=is%3Aopen+is%3Aissue+label%3Abug+user%3Alaravel). You must be authenticated with GitHub to view all of Laravel's issues.
22 |
23 | If you notice improper DocBlock, PHPStan, or IDE warnings while using Laravel, do not create a GitHub issue. Instead, please submit a pull request to fix the problem.
24 |
25 | The Laravel source code is managed on GitHub, and there are repositories for each of the Laravel projects:
26 |
27 |
57 |
58 |
59 | ## Support Questions
60 |
61 | Laravel's GitHub issue trackers are not intended to provide Laravel help or support. Instead, use one of the following channels:
62 |
63 |
74 |
75 |
76 | ## Core Development Discussion
77 |
78 | You may propose new features or improvements of existing Laravel behavior in the Laravel framework repository's [GitHub discussion board](https://github.com/laravel/framework/discussions). If you propose a new feature, please be willing to implement at least some of the code that would be needed to complete the feature.
79 |
80 | Informal discussion regarding bugs, new features, and implementation of existing features takes place in the `#internals` channel of the [Laravel Discord server](https://discord.gg/laravel). Taylor Otwell, the maintainer of Laravel, is typically present in the channel on weekdays from 8am-5pm (UTC-06:00 or America/Chicago), and sporadically present in the channel at other times.
81 |
82 |
83 | ## Which Branch?
84 |
85 | **All** bug fixes should be sent to the latest version that supports bug fixes (currently `12.x`). Bug fixes should **never** be sent to the `master` branch unless they fix features that exist only in the upcoming release.
86 |
87 | **Minor** features that are **fully backward compatible** with the current release may be sent to the latest stable branch (currently `12.x`).
88 |
89 | **Major** new features or features with breaking changes should always be sent to the `master` branch, which contains the upcoming release.
90 |
91 |
92 | ## Compiled Assets
93 |
94 | If you are submitting a change that will affect a compiled file, such as most of the files in `resources/css` or `resources/js` of the `laravel/laravel` repository, do not commit the compiled files. Due to their large size, they cannot realistically be reviewed by a maintainer. This could be exploited as a way to inject malicious code into Laravel. In order to defensively prevent this, all compiled files will be generated and committed by Laravel maintainers.
95 |
96 |
97 | ## Security Vulnerabilities
98 |
99 | If you discover a security vulnerability within Laravel, please send an email to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed.
100 |
101 |
102 | ## Coding Style
103 |
104 | Laravel follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard.
105 |
106 |
107 | ### PHPDoc
108 |
109 | Below is an example of a valid Laravel documentation block. Note that the `@param` attribute is followed by two spaces, the argument type, two more spaces, and finally the variable name:
110 |
111 | ```php
112 | /**
113 | * Register a binding with the container.
114 | *
115 | * @param string|array $abstract
116 | * @param \Closure|string|null $concrete
117 | * @param bool $shared
118 | * @return void
119 | *
120 | * @throws \Exception
121 | */
122 | public function bind($abstract, $concrete = null, $shared = false)
123 | {
124 | // ...
125 | }
126 | ```
127 |
128 | When the `@param` or `@return` attributes are redundant due to the use of native types, they can be removed:
129 |
130 | ```php
131 | /**
132 | * Execute the job.
133 | */
134 | public function handle(AudioProcessor $processor): void
135 | {
136 | // ...
137 | }
138 | ```
139 |
140 | However, when the native type is generic, please specify the generic type through the use of the `@param` or `@return` attributes:
141 |
142 | ```php
143 | /**
144 | * Get the attachments for the message.
145 | *
146 | * @return array
147 | */
148 | public function attachments(): array
149 | {
150 | return [
151 | Attachment::fromStorage('/path/to/file'),
152 | ];
153 | }
154 | ```
155 |
156 |
157 | ### StyleCI
158 |
159 | Don't worry if your code styling isn't perfect! [StyleCI](https://styleci.io/) will automatically merge any style fixes into the Laravel repository after pull requests are merged. This allows us to focus on the content of the contribution and not the code style.
160 |
161 |
162 | ## Code of Conduct
163 |
164 | The Laravel code of conduct is derived from the Ruby code of conduct. Any violations of the code of conduct may be reported to Taylor Otwell (taylor@laravel.com):
165 |
166 |
167 |
168 | - Participants will be tolerant of opposing views.
169 | - Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
170 | - When interpreting the words and actions of others, participants should always assume good intentions.
171 | - Behavior that can be reasonably considered harassment will not be tolerated.
172 |
173 |
174 |
--------------------------------------------------------------------------------
/providers.md:
--------------------------------------------------------------------------------
1 | # Service Providers
2 |
3 | - [Introduction](#introduction)
4 | - [Writing Service Providers](#writing-service-providers)
5 | - [The Register Method](#the-register-method)
6 | - [The Boot Method](#the-boot-method)
7 | - [Registering Providers](#registering-providers)
8 | - [Deferred Providers](#deferred-providers)
9 |
10 |
11 | ## Introduction
12 |
13 | Service providers are the central place of all Laravel application bootstrapping. Your own application, as well as all of Laravel's core services, are bootstrapped via service providers.
14 |
15 | But, what do we mean by "bootstrapped"? In general, we mean **registering** things, including registering service container bindings, event listeners, middleware, and even routes. Service providers are the central place to configure your application.
16 |
17 | Laravel uses dozens of service providers internally to bootstrap its core services, such as the mailer, queue, cache, and others. Many of these providers are "deferred" providers, meaning they will not be loaded on every request, but only when the services they provide are actually needed.
18 |
19 | All user-defined service providers are registered in the `bootstrap/providers.php` file. In the following documentation, you will learn how to write your own service providers and register them with your Laravel application.
20 |
21 | > [!NOTE]
22 | > If you would like to learn more about how Laravel handles requests and works internally, check out our documentation on the Laravel [request lifecycle](/docs/{{version}}/lifecycle).
23 |
24 |
25 | ## Writing Service Providers
26 |
27 | All service providers extend the `Illuminate\Support\ServiceProvider` class. Most service providers contain a `register` and a `boot` method. Within the `register` method, you should **only bind things into the [service container](/docs/{{version}}/container)**. You should never attempt to register any event listeners, routes, or any other piece of functionality within the `register` method.
28 |
29 | The Artisan CLI can generate a new provider via the `make:provider` command. Laravel will automatically register your new provider in your application's `bootstrap/providers.php` file:
30 |
31 | ```shell
32 | php artisan make:provider RiakServiceProvider
33 | ```
34 |
35 |
36 | ### The Register Method
37 |
38 | As mentioned previously, within the `register` method, you should only bind things into the [service container](/docs/{{version}}/container). You should never attempt to register any event listeners, routes, or any other piece of functionality within the `register` method. Otherwise, you may accidentally use a service that is provided by a service provider which has not loaded yet.
39 |
40 | Let's take a look at a basic service provider. Within any of your service provider methods, you always have access to the `$app` property which provides access to the service container:
41 |
42 | ```php
43 | app->singleton(Connection::class, function (Application $app) {
59 | return new Connection(config('riak'));
60 | });
61 | }
62 | }
63 | ```
64 |
65 | This service provider only defines a `register` method, and uses that method to define an implementation of `App\Services\Riak\Connection` in the service container. If you're not yet familiar with Laravel's service container, check out [its documentation](/docs/{{version}}/container).
66 |
67 |
68 | #### The `bindings` and `singletons` Properties
69 |
70 | If your service provider registers many simple bindings, you may wish to use the `bindings` and `singletons` properties instead of manually registering each container binding. When the service provider is loaded by the framework, it will automatically check for these properties and register their bindings:
71 |
72 | ```php
73 | DigitalOceanServerProvider::class,
93 | ];
94 |
95 | /**
96 | * All of the container singletons that should be registered.
97 | *
98 | * @var array
99 | */
100 | public $singletons = [
101 | DowntimeNotifier::class => PingdomDowntimeNotifier::class,
102 | ServerProvider::class => ServerToolsProvider::class,
103 | ];
104 | }
105 | ```
106 |
107 |
108 | ### The Boot Method
109 |
110 | So, what if we need to register a [view composer](/docs/{{version}}/views#view-composers) within our service provider? This should be done within the `boot` method. **This method is called after all other service providers have been registered**, meaning you have access to all other services that have been registered by the framework:
111 |
112 | ```php
113 |
135 | #### Boot Method Dependency Injection
136 |
137 | You may type-hint dependencies for your service provider's `boot` method. The [service container](/docs/{{version}}/container) will automatically inject any dependencies you need:
138 |
139 | ```php
140 | use Illuminate\Contracts\Routing\ResponseFactory;
141 |
142 | /**
143 | * Bootstrap any application services.
144 | */
145 | public function boot(ResponseFactory $response): void
146 | {
147 | $response->macro('serialized', function (mixed $value) {
148 | // ...
149 | });
150 | }
151 | ```
152 |
153 |
154 | ## Registering Providers
155 |
156 | All service providers are registered in the `bootstrap/providers.php` configuration file. This file returns an array that contains the class names of your application's service providers:
157 |
158 | ```php
159 |
178 | ## Deferred Providers
179 |
180 | If your provider is **only** registering bindings in the [service container](/docs/{{version}}/container), you may choose to defer its registration until one of the registered bindings is actually needed. Deferring the loading of such a provider will improve the performance of your application, since it is not loaded from the filesystem on every request.
181 |
182 | Laravel compiles and stores a list of all of the services supplied by deferred service providers, along with the name of its service provider class. Then, only when you attempt to resolve one of these services does Laravel load the service provider.
183 |
184 | To defer the loading of a provider, implement the `\Illuminate\Contracts\Support\DeferrableProvider` interface and define a `provides` method. The `provides` method should return the service container bindings registered by the provider:
185 |
186 | ```php
187 | app->singleton(Connection::class, function (Application $app) {
204 | return new Connection($app['config']['riak']);
205 | });
206 | }
207 |
208 | /**
209 | * Get the services provided by the provider.
210 | *
211 | * @return array
212 | */
213 | public function provides(): array
214 | {
215 | return [Connection::class];
216 | }
217 | }
218 | ```
219 |
--------------------------------------------------------------------------------
/eloquent-serialization.md:
--------------------------------------------------------------------------------
1 | # Eloquent: Serialization
2 |
3 | - [Introduction](#introduction)
4 | - [Serializing Models and Collections](#serializing-models-and-collections)
5 | - [Serializing to Arrays](#serializing-to-arrays)
6 | - [Serializing to JSON](#serializing-to-json)
7 | - [Hiding Attributes From JSON](#hiding-attributes-from-json)
8 | - [Appending Values to JSON](#appending-values-to-json)
9 | - [Date Serialization](#date-serialization)
10 |
11 |
12 | ## Introduction
13 |
14 | 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.
15 |
16 | > [!NOTE]
17 | > 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).
18 |
19 |
20 | ## Serializing Models and Collections
21 |
22 |
23 | ### Serializing to Arrays
24 |
25 | To convert a model and its loaded [relationships](/docs/{{version}}/eloquent-relationships) to an array, you should use the `toArray` method. This method is recursive, so all attributes and all relations (including the relations of relations) will be converted to arrays:
26 |
27 | ```php
28 | use App\Models\User;
29 |
30 | $user = User::with('roles')->first();
31 |
32 | return $user->toArray();
33 | ```
34 |
35 | The `attributesToArray` method may be used to convert a model's attributes to an array but not its relationships:
36 |
37 | ```php
38 | $user = User::first();
39 |
40 | return $user->attributesToArray();
41 | ```
42 |
43 | You may also convert entire [collections](/docs/{{version}}/eloquent-collections) of models to arrays by calling the `toArray` method on the collection instance:
44 |
45 | ```php
46 | $users = User::all();
47 |
48 | return $users->toArray();
49 | ```
50 |
51 |
52 | ### Serializing to JSON
53 |
54 | To convert a model to JSON, you should use the `toJson` method. Like `toArray`, the `toJson` method is recursive, so all attributes and relations will be converted to JSON. You may also specify any JSON encoding options that are [supported by PHP](https://secure.php.net/manual/en/function.json-encode.php):
55 |
56 | ```php
57 | use App\Models\User;
58 |
59 | $user = User::find(1);
60 |
61 | return $user->toJson();
62 |
63 | return $user->toJson(JSON_PRETTY_PRINT);
64 | ```
65 |
66 | Alternatively, you may cast a model or collection to a string, which will automatically call the `toJson` method on the model or collection:
67 |
68 | ```php
69 | return (string) User::find(1);
70 | ```
71 |
72 | Since models and collections are converted to JSON when cast to a string, you can return Eloquent objects directly from your application's routes or controllers. Laravel will automatically serialize your Eloquent models and collections to JSON when they are returned from routes or controllers:
73 |
74 | ```php
75 | Route::get('/users', function () {
76 | return User::all();
77 | });
78 | ```
79 |
80 |
81 | #### Relationships
82 |
83 | When an Eloquent model is converted to JSON, its loaded relationships will automatically be included as attributes on the JSON object. Also, though Eloquent relationship methods are defined using "camel case" method names, a relationship's JSON attribute will be "snake case".
84 |
85 |
86 | ## Hiding Attributes From JSON
87 |
88 | Sometimes you may wish to limit the attributes, such as passwords, that are included in your model's array or JSON representation. To do so, add a `$hidden` property to your model. Attributes that are listed in the `$hidden` property's array will not be included in the serialized representation of your model:
89 |
90 | ```php
91 |
103 | */
104 | protected $hidden = ['password'];
105 | }
106 | ```
107 |
108 | > [!NOTE]
109 | > To hide relationships, add the relationship's method name to your Eloquent model's `$hidden` property.
110 |
111 | 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:
112 |
113 | ```php
114 |
132 | #### Temporarily Modifying Attribute Visibility
133 |
134 | If you would like to make some typically hidden attributes visible on a given model instance, you may use the `makeVisible` or `mergeVisible` methods. The `makeVisible` method returns the model instance:
135 |
136 | ```php
137 | return $user->makeVisible('attribute')->toArray();
138 |
139 | return $user->mergeVisible(['name', 'email'])->toArray();
140 | ```
141 |
142 | Likewise, if you would like to hide some attributes that are typically visible, you may use the `makeHidden` or `mergeHidden` methods:
143 |
144 | ```php
145 | return $user->makeHidden('attribute')->toArray();
146 |
147 | return $user->mergeHidden(['name', 'email'])->toArray();
148 | ```
149 |
150 | If you wish to temporarily override all of the visible or hidden attributes, you may use the `setVisible` and `setHidden` methods respectively:
151 |
152 | ```php
153 | return $user->setVisible(['id', 'name'])->toArray();
154 |
155 | return $user->setHidden(['email', 'password', 'remember_token'])->toArray();
156 | ```
157 |
158 |
159 | ## Appending Values to JSON
160 |
161 | Occasionally, when converting models to arrays or JSON, you may wish to add attributes that do not have a corresponding column in your database. To do so, first define an [accessor](/docs/{{version}}/eloquent-mutators) for the value:
162 |
163 | ```php
164 | 'yes',
180 | );
181 | }
182 | }
183 | ```
184 |
185 | If you would like the accessor to always be appended to your model's array and JSON representations, you may add the attribute name to the `appends` property of your model. Note that attribute names are typically referenced using their "snake case" serialized representation, even though the accessor's PHP method is defined using "camel case":
186 |
187 | ```php
188 |
208 | #### Appending at Run Time
209 |
210 | At runtime, you may instruct a model instance to append additional attributes using the `append` or `mergeAppends` methods. Or, you may use the `setAppends` method to override the entire array of appended properties for a given model instance:
211 |
212 | ```php
213 | return $user->append('is_admin')->toArray();
214 |
215 | return $user->mergeAppends(['is_admin', 'status'])->toArray();
216 |
217 | return $user->setAppends(['is_admin'])->toArray();
218 | ```
219 |
220 |
221 | ## Date Serialization
222 |
223 |
224 | #### Customizing the Default Date Format
225 |
226 | You may customize the default serialization format by overriding the `serializeDate` method. This method does not affect how your dates are formatted for storage in the database:
227 |
228 | ```php
229 | /**
230 | * Prepare a date for array / JSON serialization.
231 | */
232 | protected function serializeDate(DateTimeInterface $date): string
233 | {
234 | return $date->format('Y-m-d');
235 | }
236 | ```
237 |
238 |
239 | #### Customizing the Date Format per Attribute
240 |
241 | You may customize the serialization format of individual Eloquent date attributes by specifying the date format in the model's [cast declarations](/docs/{{version}}/eloquent-mutators#attribute-casting):
242 |
243 | ```php
244 | protected function casts(): array
245 | {
246 | return [
247 | 'birthday' => 'date:Y-m-d',
248 | 'joined_at' => 'datetime:Y-m-d H:00',
249 | ];
250 | }
251 | ```
252 |
--------------------------------------------------------------------------------
/database-testing.md:
--------------------------------------------------------------------------------
1 | # Database Testing
2 |
3 | - [Introduction](#introduction)
4 | - [Resetting the Database After Each Test](#resetting-the-database-after-each-test)
5 | - [Model Factories](#model-factories)
6 | - [Running Seeders](#running-seeders)
7 | - [Available Assertions](#available-assertions)
8 |
9 |
10 | ## Introduction
11 |
12 | Laravel provides a variety of helpful tools and assertions to make it easier to test your database driven applications. In addition, Laravel model factories and seeders make it painless to create test database records using your application's Eloquent models and relationships. We'll discuss all of these powerful features in the following documentation.
13 |
14 |
15 | ### Resetting the Database After Each Test
16 |
17 | Before proceeding much further, let's discuss how to reset your database after each of your tests so that data from a previous test does not interfere with subsequent tests. Laravel's included `Illuminate\Foundation\Testing\RefreshDatabase` trait will take care of this for you. Simply use the trait on your test class:
18 |
19 | ```php tab=Pest
20 | use(RefreshDatabase::class);
25 |
26 | test('basic example', function () {
27 | $response = $this->get('/');
28 |
29 | // ...
30 | });
31 | ```
32 |
33 | ```php tab=PHPUnit
34 | get('/');
51 |
52 | // ...
53 | }
54 | }
55 | ```
56 |
57 | The `Illuminate\Foundation\Testing\RefreshDatabase` trait does not migrate your database if your schema is up to date. Instead, it will only execute the test within a database transaction. Therefore, any records added to the database by test cases that do not use this trait may still exist in the database.
58 |
59 | If you would like to totally reset the database, you may use the `Illuminate\Foundation\Testing\DatabaseMigrations` or `Illuminate\Foundation\Testing\DatabaseTruncation` traits instead. However, both of these options are significantly slower than the `RefreshDatabase` trait.
60 |
61 |
62 | ## Model Factories
63 |
64 | When testing, you may need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Laravel allows you to define a set of default attributes for each of your [Eloquent models](/docs/{{version}}/eloquent) using [model factories](/docs/{{version}}/eloquent-factories).
65 |
66 | To learn more about creating and utilizing model factories to create models, please consult the complete [model factory documentation](/docs/{{version}}/eloquent-factories). Once you have defined a model factory, you may utilize the factory within your test to create models:
67 |
68 | ```php tab=Pest
69 | use App\Models\User;
70 |
71 | test('models can be instantiated', function () {
72 | $user = User::factory()->create();
73 |
74 | // ...
75 | });
76 | ```
77 |
78 | ```php tab=PHPUnit
79 | use App\Models\User;
80 |
81 | public function test_models_can_be_instantiated(): void
82 | {
83 | $user = User::factory()->create();
84 |
85 | // ...
86 | }
87 | ```
88 |
89 |
90 | ## Running Seeders
91 |
92 | If you would like to use [database seeders](/docs/{{version}}/seeding) to populate your database during a feature test, you may invoke the `seed` method. By default, the `seed` method will execute the `DatabaseSeeder`, which should execute all of your other seeders. Alternatively, you pass a specific seeder class name to the `seed` method:
93 |
94 | ```php tab=Pest
95 | use(RefreshDatabase::class);
102 |
103 | test('orders can be created', function () {
104 | // Run the DatabaseSeeder...
105 | $this->seed();
106 |
107 | // Run a specific seeder...
108 | $this->seed(OrderStatusSeeder::class);
109 |
110 | // ...
111 |
112 | // Run an array of specific seeders...
113 | $this->seed([
114 | OrderStatusSeeder::class,
115 | TransactionStatusSeeder::class,
116 | // ...
117 | ]);
118 | });
119 | ```
120 |
121 | ```php tab=PHPUnit
122 | seed();
142 |
143 | // Run a specific seeder...
144 | $this->seed(OrderStatusSeeder::class);
145 |
146 | // ...
147 |
148 | // Run an array of specific seeders...
149 | $this->seed([
150 | OrderStatusSeeder::class,
151 | TransactionStatusSeeder::class,
152 | // ...
153 | ]);
154 | }
155 | }
156 | ```
157 |
158 | Alternatively, you may instruct Laravel to automatically seed the database before each test that uses the `RefreshDatabase` trait. You may accomplish this by defining a `$seed` property on your base test class:
159 |
160 | ```php
161 |
192 | ## Available Assertions
193 |
194 | Laravel provides several database assertions for your [Pest](https://pestphp.com) or [PHPUnit](https://phpunit.de) feature tests. We'll discuss each of these assertions below.
195 |
196 |
197 | #### assertDatabaseCount
198 |
199 | Assert that a table in the database contains the given number of records:
200 |
201 | ```php
202 | $this->assertDatabaseCount('users', 5);
203 | ```
204 |
205 |
206 | #### assertDatabaseEmpty
207 |
208 | Assert that a table in the database contains no records:
209 |
210 | ```php
211 | $this->assertDatabaseEmpty('users');
212 | ```
213 |
214 |
215 | #### assertDatabaseHas
216 |
217 | Assert that a table in the database contains records matching the given key / value query constraints:
218 |
219 | ```php
220 | $this->assertDatabaseHas('users', [
221 | 'email' => 'sally@example.com',
222 | ]);
223 | ```
224 |
225 |
226 | #### assertDatabaseMissing
227 |
228 | Assert that a table in the database does not contain records matching the given key / value query constraints:
229 |
230 | ```php
231 | $this->assertDatabaseMissing('users', [
232 | 'email' => 'sally@example.com',
233 | ]);
234 | ```
235 |
236 |
237 | #### assertSoftDeleted
238 |
239 | The `assertSoftDeleted` method may be used to assert a given Eloquent model has been "soft deleted":
240 |
241 | ```php
242 | $this->assertSoftDeleted($user);
243 | ```
244 |
245 |
246 | #### assertNotSoftDeleted
247 |
248 | The `assertNotSoftDeleted` method may be used to assert a given Eloquent model hasn't been "soft deleted":
249 |
250 | ```php
251 | $this->assertNotSoftDeleted($user);
252 | ```
253 |
254 |
255 | #### assertModelExists
256 |
257 | Assert that a given model or collection of models exist in the database:
258 |
259 | ```php
260 | use App\Models\User;
261 |
262 | $user = User::factory()->create();
263 |
264 | $this->assertModelExists($user);
265 | ```
266 |
267 |
268 | #### assertModelMissing
269 |
270 | Assert that a given model or collection of models do not exist in the database:
271 |
272 | ```php
273 | use App\Models\User;
274 |
275 | $user = User::factory()->create();
276 |
277 | $user->delete();
278 |
279 | $this->assertModelMissing($user);
280 | ```
281 |
282 |
283 | #### expectsDatabaseQueryCount
284 |
285 | The `expectsDatabaseQueryCount` method may be invoked at the beginning of your test to specify the total number of database queries that you expect to be run during the test. If the actual number of executed queries does not exactly match this expectation, the test will fail:
286 |
287 | ```php
288 | $this->expectsDatabaseQueryCount(5);
289 |
290 | // Test...
291 | ```
292 |
--------------------------------------------------------------------------------
/verification.md:
--------------------------------------------------------------------------------
1 | # Email Verification
2 |
3 | - [Introduction](#introduction)
4 | - [Model Preparation](#model-preparation)
5 | - [Database Preparation](#database-preparation)
6 | - [Routing](#verification-routing)
7 | - [The Email Verification Notice](#the-email-verification-notice)
8 | - [The Email Verification Handler](#the-email-verification-handler)
9 | - [Resending the Verification Email](#resending-the-verification-email)
10 | - [Protecting Routes](#protecting-routes)
11 | - [Customization](#customization)
12 | - [Events](#events)
13 |
14 |
15 | ## Introduction
16 |
17 | 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.
18 |
19 | > [!NOTE]
20 | > 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.
21 |
22 |
23 | ### Model Preparation
24 |
25 | Before getting started, verify that your `App\Models\User` model implements the `Illuminate\Contracts\Auth\MustVerifyEmail` contract:
26 |
27 | ```php
28 |
55 | ### Database Preparation
56 |
57 | Next, your `users` table must contain an `email_verified_at` column to store the date and time that the user's email address was verified. Typically, this is included in Laravel's default `0001_01_01_000000_create_users_table.php` database migration.
58 |
59 |
60 | ## Routing
61 |
62 | To properly implement email verification, three routes will need to be defined. First, a route will be needed to display a notice to the user that they should click the email verification link in the verification email that Laravel sent them after registration.
63 |
64 | Second, a route will be needed to handle requests generated when the user clicks the email verification link in the email.
65 |
66 | Third, a route will be needed to resend a verification link if the user accidentally loses the first verification link.
67 |
68 |
69 | ### The Email Verification Notice
70 |
71 | As mentioned previously, a route should be defined that will return a view instructing the user to click the email verification link that was emailed to them by Laravel after registration. This view will be displayed to users when they try to access other parts of the application without verifying their email address first. Remember, the link is automatically emailed to the user as long as your `App\Models\User` model implements the `MustVerifyEmail` interface:
72 |
73 | ```php
74 | Route::get('/email/verify', function () {
75 | return view('auth.verify-email');
76 | })->middleware('auth')->name('verification.notice');
77 | ```
78 |
79 | 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.
80 |
81 | > [!NOTE]
82 | > 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).
83 |
84 |
85 | ### The Email Verification Handler
86 |
87 | Next, we need to define a route that will handle requests generated when the user clicks the email verification link that was emailed to them. This route should be named `verification.verify` and be assigned the `auth` and `signed` middlewares:
88 |
89 | ```php
90 | use Illuminate\Foundation\Auth\EmailVerificationRequest;
91 |
92 | Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
93 | $request->fulfill();
94 |
95 | return redirect('/home');
96 | })->middleware(['auth', 'signed'])->name('verification.verify');
97 | ```
98 |
99 | Before moving on, let's take a closer look at this route. First, you'll notice we are using an `EmailVerificationRequest` request type instead of the typical `Illuminate\Http\Request` instance. The `EmailVerificationRequest` is a [form request](/docs/{{version}}/validation#form-request-validation) that is included with Laravel. This request will automatically take care of validating the request's `id` and `hash` parameters.
100 |
101 | Next, we can proceed directly to calling the `fulfill` method on the request. This method will call the `markEmailAsVerified` method on the authenticated user and dispatch the `Illuminate\Auth\Events\Verified` event. The `markEmailAsVerified` method is available to the default `App\Models\User` model via the `Illuminate\Foundation\Auth\User` base class. Once the user's email address has been verified, you may redirect them wherever you wish.
102 |
103 |
104 | ### Resending the Verification Email
105 |
106 | Sometimes a user may misplace or accidentally delete the email address verification email. To accommodate this, you may wish to define a route to allow the user to request that the verification email be resent. You may then make a request to this route by placing a simple form submission button within your [verification notice view](#the-email-verification-notice):
107 |
108 | ```php
109 | use Illuminate\Http\Request;
110 |
111 | Route::post('/email/verification-notification', function (Request $request) {
112 | $request->user()->sendEmailVerificationNotification();
113 |
114 | return back()->with('message', 'Verification link sent!');
115 | })->middleware(['auth', 'throttle:6,1'])->name('verification.send');
116 | ```
117 |
118 |
119 | ### Protecting Routes
120 |
121 | [Route middleware](/docs/{{version}}/middleware) may be used to only allow verified users to access a given route. Laravel includes a `verified` [middleware alias](/docs/{{version}}/middleware#middleware-aliases), which is an alias for the `Illuminate\Auth\Middleware\EnsureEmailIsVerified` middleware class. Since this alias is already automatically registered by Laravel, all you need to do is attach the `verified` middleware to a route definition. Typically, this middleware is paired with the `auth` middleware:
122 |
123 | ```php
124 | Route::get('/profile', function () {
125 | // Only verified users may access this route...
126 | })->middleware(['auth', 'verified']);
127 | ```
128 |
129 | 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).
130 |
131 |
132 | ## Customization
133 |
134 |
135 | #### Verification Email Customization
136 |
137 | Although the default email verification notification should satisfy the requirements of most applications, Laravel allows you to customize how the email verification mail message is constructed.
138 |
139 | To get started, pass a closure to the `toMailUsing` method provided by the `Illuminate\Auth\Notifications\VerifyEmail` notification. The closure will receive the notifiable model instance that is receiving the notification as well as the signed email verification URL that the user must visit to verify their email address. The closure should return an instance of `Illuminate\Notifications\Messages\MailMessage`. Typically, you should call the `toMailUsing` method from the `boot` method of your application's `AppServiceProvider` class:
140 |
141 | ```php
142 | use Illuminate\Auth\Notifications\VerifyEmail;
143 | use Illuminate\Notifications\Messages\MailMessage;
144 |
145 | /**
146 | * Bootstrap any application services.
147 | */
148 | public function boot(): void
149 | {
150 | // ...
151 |
152 | VerifyEmail::toMailUsing(function (object $notifiable, string $url) {
153 | return (new MailMessage)
154 | ->subject('Verify Email Address')
155 | ->line('Click the button below to verify your email address.')
156 | ->action('Verify Email Address', $url);
157 | });
158 | }
159 | ```
160 |
161 | > [!NOTE]
162 | > To learn more about mail notifications, please consult the [mail notification documentation](/docs/{{version}}/notifications#mail-notifications).
163 |
164 |
165 | ## Events
166 |
167 | When using the [Laravel application starter kits](/docs/{{version}}/starter-kits), Laravel dispatches an `Illuminate\Auth\Events\Verified` [event](/docs/{{version}}/events) during the email verification process. If you are manually handling email verification for your application, you may wish to manually dispatch these events after verification is completed.
168 |
--------------------------------------------------------------------------------
/upgrade.md:
--------------------------------------------------------------------------------
1 | # Upgrade Guide
2 |
3 | - [Upgrading To 12.0 From 11.x](#upgrade-12.0)
4 |
5 |
6 | ## High Impact Changes
7 |
8 |
38 |
39 |
40 | ## Upgrading To 12.0 From 11.x
41 |
42 | #### Estimated Upgrade Time: 5 Minutes
43 |
44 | > [!NOTE]
45 | > 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.
46 |
47 |
48 | ### Updating Dependencies
49 |
50 | **Likelihood Of Impact: High**
51 |
52 | You should update the following dependencies in your application's `composer.json` file:
53 |
54 |
55 |
56 | - `laravel/framework` to `^12.0`
57 | - `phpunit/phpunit` to `^11.0`
58 | - `pestphp/pest` to `^3.0`
59 |
60 |
61 |
62 |
63 | #### Carbon 3
64 |
65 | **Likelihood Of Impact: Low**
66 |
67 | Support for [Carbon 2.x](https://carbon.nesbot.com/docs/) has been removed. All Laravel 12 applications now require [Carbon 3.x](https://carbon.nesbot.com/docs/#api-carbon-3).
68 |
69 |
70 | ### Updating the Laravel Installer
71 |
72 | If you are using the Laravel installer CLI tool to create new Laravel applications, you should update your installer installation to be compatible with Laravel 12.x and the [new Laravel starter kits](https://laravel.com/starter-kits). If you installed the Laravel installer via `composer global require`, you may update the installer using `composer global update`:
73 |
74 | ```shell
75 | composer global update laravel/installer
76 | ```
77 |
78 | If you originally installed PHP and Laravel via `php.new`, you may simply re-run the `php.new` installation commands for your operating system to install the latest version of PHP and the Laravel installer:
79 |
80 | ```shell tab=macOS
81 | /bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)"
82 | ```
83 |
84 | ```shell tab=Windows PowerShell
85 | # Run as administrator...
86 | Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://php.new/install/windows/8.4'))
87 | ```
88 |
89 | ```shell tab=Linux
90 | /bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)"
91 | ```
92 |
93 | Or, if you are using [Laravel Herd's](https://herd.laravel.com) bundled copy of the Laravel installer, you should update your Herd installation to the latest release.
94 |
95 |
96 | ### Authentication
97 |
98 |
99 | #### Updated `DatabaseTokenRepository` Constructor Signature
100 |
101 | **Likelihood Of Impact: Very Low**
102 |
103 | The constructor of the `Illuminate\Auth\Passwords\DatabaseTokenRepository` class now expects the `$expires` parameter to be given in seconds, rather than minutes.
104 |
105 |
106 | ### Concurrency
107 |
108 |
109 | #### Concurrency Result Index Mapping
110 |
111 | **Likelihood Of Impact: Low**
112 |
113 | When invoking the `Concurrency::run` method with an associative array, the results of the concurrent operations are now returned with their associated keys:
114 |
115 | ```php
116 | $result = Concurrency::run([
117 | 'task-1' => fn () => 1 + 1,
118 | 'task-2' => fn () => 2 + 2,
119 | ]);
120 |
121 | // ['task-1' => 2, 'task-2' => 4]
122 | ```
123 |
124 |
125 | ### Container
126 |
127 |
128 | #### Container Class Dependency Resolution
129 |
130 | **Likelihood Of Impact: Low**
131 |
132 | The dependency injection container now respects the default value of class properties when resolving a class instance. If you were previously relying on the container to resolve a class instance without the default value, you may need to adjust your application to account for this new behavior:
133 |
134 | ```php
135 | class Example
136 | {
137 | public function __construct(public ?Carbon $date = null) {}
138 | }
139 |
140 | $example = resolve(Example::class);
141 |
142 | // <= 11.x
143 | $example->date instanceof Carbon;
144 |
145 | // >= 12.x
146 | $example->date === null;
147 | ```
148 |
149 |
150 | ### Database
151 |
152 |
153 | #### Multi-Schema Database Inspecting
154 |
155 | **Likelihood Of Impact: Low**
156 |
157 | The `Schema::getTables()`, `Schema::getViews()`, and `Schema::getTypes()` methods now include the results from all schemas by default. You may pass the `schema` argument to retrieve the result for the given schema only:
158 |
159 | ```php
160 | // All tables on all schemas...
161 | $tables = Schema::getTables();
162 |
163 | // All tables on the 'main' schema...
164 | $tables = Schema::getTables(schema: 'main');
165 |
166 | // All tables on the 'main' and 'blog' schemas...
167 | $tables = Schema::getTables(schema: ['main', 'blog']);
168 | ```
169 |
170 | The `Schema::getTableListing()` method now returns schema-qualified table names by default. You may pass the `schemaQualified` argument to change the behavior as desired:
171 |
172 | ```php
173 | $tables = Schema::getTableListing();
174 | // ['main.migrations', 'main.users', 'blog.posts']
175 |
176 | $tables = Schema::getTableListing(schema: 'main');
177 | // ['main.migrations', 'main.users']
178 |
179 | $tables = Schema::getTableListing(schema: 'main', schemaQualified: false);
180 | // ['migrations', 'users']
181 | ```
182 |
183 | The `db:table` and `db:show` commands now output the results of all schemas on MySQL, MariaDB, and SQLite, just like PostgreSQL and SQL Server.
184 |
185 |
186 | #### Updated `Blueprint` Constructor Signature
187 |
188 | **Likelihood Of Impact: Very Low**
189 |
190 | The constructor of the `Illuminate\Database\Schema\Blueprint` class now expects an instance of `Illuminate\Database\Connection` as its first argument.
191 |
192 |
193 | ### Eloquent
194 |
195 |
196 | #### Models and UUIDv7
197 |
198 | **Likelihood Of Impact: Medium**
199 |
200 | The `HasUuids` trait now returns UUIDs that are compatible with version 7 of the UUID spec (ordered UUIDs). If you would like to continue using ordered UUIDv4 strings for your model's IDs, you should now use the `HasVersion4Uuids` trait:
201 |
202 | ```php
203 | use Illuminate\Database\Eloquent\Concerns\HasUuids; // [tl! remove]
204 | use Illuminate\Database\Eloquent\Concerns\HasVersion4Uuids as HasUuids; // [tl! add]
205 | ```
206 |
207 | The `HasVersion7Uuids` trait has been removed. If you were previously using this trait, you should use the `HasUuids` trait instead, which now provides the same behavior.
208 |
209 |
210 | ### Requests
211 |
212 |
213 | #### Nested Array Request Merging
214 |
215 | **Likelihood Of Impact: Low**
216 |
217 | The `$request->mergeIfMissing()` method now allows merging nested array data using "dot" notation. If you were previously relying on this method to create a top-level array key containing the "dot" notation version of the key, you may need to adjust your application to account for this new behavior:
218 |
219 | ```php
220 | $request->mergeIfMissing([
221 | 'user.last_name' => 'Otwell',
222 | ]);
223 | ```
224 |
225 |
226 | ### Storage
227 |
228 |
229 | #### Local Filesystem Disk Default Root Path
230 |
231 | **Likelihood Of Impact: Low**
232 |
233 | If your application does not explicitly define a `local` disk in your filesystems configuration, Laravel will now default the local disk's root to `storage/app/private`. In previous releases, this defaulted to `storage/app`. As a result, calls to `Storage::disk('local')` will read from and write to `storage/app/private` unless otherwise configured. To restore the previous behavior, you may define the `local` disk manually and set the desired root path.
234 |
235 |
236 | ### Validation
237 |
238 |
239 | #### Image Validation Now Excludes SVGs
240 |
241 | **Likelihood Of Impact: Low**
242 |
243 | The `image` validation rule no longer allows SVG images by default. If you would like to allow SVGs when using the `image` rule, you must explicitly allow them:
244 |
245 | ```php
246 | use Illuminate\Validation\Rules\File;
247 |
248 | 'photo' => 'required|image:allow_svg'
249 |
250 | // Or...
251 | 'photo' => ['required', File::image(allowSvg: true)],
252 | ```
253 |
254 |
255 | ### Miscellaneous
256 |
257 | We also encourage you to view the changes in the `laravel/laravel` [GitHub repository](https://github.com/laravel/laravel). While many of these changes are not required, you may wish to keep these files in sync with your application. Some of these changes will be covered in this upgrade guide, but others, such as changes to configuration files or comments, will not be. You can easily view the changes with the [GitHub comparison tool](https://github.com/laravel/laravel/compare/11.x...12.x) and choose which updates are important to you.
258 |
--------------------------------------------------------------------------------
/mocking.md:
--------------------------------------------------------------------------------
1 | # Mocking
2 |
3 | - [Introduction](#introduction)
4 | - [Mocking Objects](#mocking-objects)
5 | - [Mocking Facades](#mocking-facades)
6 | - [Facade Spies](#facade-spies)
7 | - [Interacting With Time](#interacting-with-time)
8 |
9 |
10 | ## Introduction
11 |
12 | When testing Laravel applications, you may wish to "mock" certain aspects of your application so they are not actually executed during a given test. For example, when testing a controller that dispatches an event, you may wish to mock the event listeners so they are not actually executed during the test. This allows you to only test the controller's HTTP response without worrying about the execution of the event listeners since the event listeners can be tested in their own test case.
13 |
14 | Laravel provides helpful methods for mocking events, jobs, and other facades out of the box. These helpers primarily provide a convenience layer over Mockery so you do not have to manually make complicated Mockery method calls.
15 |
16 |
17 | ## Mocking Objects
18 |
19 | When mocking an object that is going to be injected into your application via Laravel's [service container](/docs/{{version}}/container), you will need to bind your mocked instance into the container as an `instance` binding. This will instruct the container to use your mocked instance of the object instead of constructing the object itself:
20 |
21 | ```php tab=Pest
22 | use App\Service;
23 | use Mockery;
24 | use Mockery\MockInterface;
25 |
26 | test('something can be mocked', function () {
27 | $this->instance(
28 | Service::class,
29 | Mockery::mock(Service::class, function (MockInterface $mock) {
30 | $mock->expects('process');
31 | })
32 | );
33 | });
34 | ```
35 |
36 | ```php tab=PHPUnit
37 | use App\Service;
38 | use Mockery;
39 | use Mockery\MockInterface;
40 |
41 | public function test_something_can_be_mocked(): void
42 | {
43 | $this->instance(
44 | Service::class,
45 | Mockery::mock(Service::class, function (MockInterface $mock) {
46 | $mock->expects('process');
47 | })
48 | );
49 | }
50 | ```
51 |
52 | In order to make this more convenient, you may use the `mock` method that is provided by Laravel's base test case class. For example, the following example is equivalent to the example above:
53 |
54 | ```php
55 | use App\Service;
56 | use Mockery\MockInterface;
57 |
58 | $mock = $this->mock(Service::class, function (MockInterface $mock) {
59 | $mock->expects('process');
60 | });
61 | ```
62 |
63 | You may use the `partialMock` method when you only need to mock a few methods of an object. The methods that are not mocked will be executed normally when called:
64 |
65 | ```php
66 | use App\Service;
67 | use Mockery\MockInterface;
68 |
69 | $mock = $this->partialMock(Service::class, function (MockInterface $mock) {
70 | $mock->expects('process');
71 | });
72 | ```
73 |
74 | Similarly, if you want to [spy](http://docs.mockery.io/en/latest/reference/spies.html) on an object, Laravel's base test case class offers a `spy` method as a convenient wrapper around the `Mockery::spy` method. Spies are similar to mocks; however, spies record any interaction between the spy and the code being tested, allowing you to make assertions after the code is executed:
75 |
76 | ```php
77 | use App\Service;
78 |
79 | $spy = $this->spy(Service::class);
80 |
81 | // ...
82 |
83 | $spy->shouldHaveReceived('process');
84 | ```
85 |
86 |
87 | ## Mocking Facades
88 |
89 | Unlike traditional static method calls, [facades](/docs/{{version}}/facades) (including [real-time facades](/docs/{{version}}/facades#real-time-facades)) may be mocked. This provides a great advantage over traditional static methods and grants you the same testability that you would have if you were using traditional dependency injection. When testing, you may often want to mock a call to a Laravel facade that occurs in one of your controllers. For example, consider the following controller action:
90 |
91 | ```php
92 | with('key')
124 | ->andReturn('value');
125 |
126 | $response = $this->get('/users');
127 |
128 | // ...
129 | });
130 | ```
131 |
132 | ```php tab=PHPUnit
133 | with('key')
146 | ->andReturn('value');
147 |
148 | $response = $this->get('/users');
149 |
150 | // ...
151 | }
152 | }
153 | ```
154 |
155 | > [!WARNING]
156 | > 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.
157 |
158 |
159 | ### Facade Spies
160 |
161 | If you would like to [spy](http://docs.mockery.io/en/latest/reference/spies.html) on a facade, you may call the `spy` method on the corresponding facade. Spies are similar to mocks; however, spies record any interaction between the spy and the code being tested, allowing you to make assertions after the code is executed:
162 |
163 | ```php tab=Pest
164 | get('/');
172 |
173 | $response->assertStatus(200);
174 |
175 | Cache::shouldHaveReceived('put')->with('name', 'Taylor', 10);
176 | });
177 | ```
178 |
179 | ```php tab=PHPUnit
180 | use Illuminate\Support\Facades\Cache;
181 |
182 | public function test_values_are_stored_in_cache(): void
183 | {
184 | Cache::spy();
185 |
186 | $response = $this->get('/');
187 |
188 | $response->assertStatus(200);
189 |
190 | Cache::shouldHaveReceived('put')->with('name', 'Taylor', 10);
191 | }
192 | ```
193 |
194 |
195 | ## Interacting With Time
196 |
197 | When testing, you may occasionally need to modify the time returned by helpers such as `now` or `Illuminate\Support\Carbon::now()`. Thankfully, Laravel's base feature test class includes helpers that allow you to manipulate the current time:
198 |
199 | ```php tab=Pest
200 | test('time can be manipulated', function () {
201 | // Travel into the future...
202 | $this->travel(5)->milliseconds();
203 | $this->travel(5)->seconds();
204 | $this->travel(5)->minutes();
205 | $this->travel(5)->hours();
206 | $this->travel(5)->days();
207 | $this->travel(5)->weeks();
208 | $this->travel(5)->years();
209 |
210 | // Travel into the past...
211 | $this->travel(-5)->hours();
212 |
213 | // Travel to an explicit time...
214 | $this->travelTo(now()->minus(hours: 6));
215 |
216 | // Return back to the present time...
217 | $this->travelBack();
218 | });
219 | ```
220 |
221 | ```php tab=PHPUnit
222 | public function test_time_can_be_manipulated(): void
223 | {
224 | // Travel into the future...
225 | $this->travel(5)->milliseconds();
226 | $this->travel(5)->seconds();
227 | $this->travel(5)->minutes();
228 | $this->travel(5)->hours();
229 | $this->travel(5)->days();
230 | $this->travel(5)->weeks();
231 | $this->travel(5)->years();
232 |
233 | // Travel into the past...
234 | $this->travel(-5)->hours();
235 |
236 | // Travel to an explicit time...
237 | $this->travelTo(now()->minus(hours: 6));
238 |
239 | // Return back to the present time...
240 | $this->travelBack();
241 | }
242 | ```
243 |
244 | You may also provide a closure to the various time travel methods. The closure will be invoked with time frozen at the specified time. Once the closure has executed, time will resume as normal:
245 |
246 | ```php
247 | $this->travel(5)->days(function () {
248 | // Test something five days into the future...
249 | });
250 |
251 | $this->travelTo(now()->mins(days: 10), function () {
252 | // Test something during a given moment...
253 | });
254 | ```
255 |
256 | The `freezeTime` method may be used to freeze the current time. Similarly, the `freezeSecond` method will freeze the current time but at the start of the current second:
257 |
258 | ```php
259 | use Illuminate\Support\Carbon;
260 |
261 | // Freeze time and resume normal time after executing closure...
262 | $this->freezeTime(function (Carbon $time) {
263 | // ...
264 | });
265 |
266 | // Freeze time at the current second and resume normal time after executing closure...
267 | $this->freezeSecond(function (Carbon $time) {
268 | // ...
269 | })
270 | ```
271 |
272 | As you would expect, all of the methods discussed above are primarily useful for testing time sensitive application behavior, such as locking inactive posts on a discussion forum:
273 |
274 | ```php tab=Pest
275 | use App\Models\Thread;
276 |
277 | test('forum threads lock after one week of inactivity', function () {
278 | $thread = Thread::factory()->create();
279 |
280 | $this->travel(1)->week();
281 |
282 | expect($thread->isLockedByInactivity())->toBeTrue();
283 | });
284 | ```
285 |
286 | ```php tab=PHPUnit
287 | use App\Models\Thread;
288 |
289 | public function test_forum_threads_lock_after_one_week_of_inactivity()
290 | {
291 | $thread = Thread::factory()->create();
292 |
293 | $this->travel(1)->week();
294 |
295 | $this->assertTrue($thread->isLockedByInactivity());
296 | }
297 | ```
298 |
--------------------------------------------------------------------------------
/deployment.md:
--------------------------------------------------------------------------------
1 | # Deployment
2 |
3 | - [Introduction](#introduction)
4 | - [Server Requirements](#server-requirements)
5 | - [Server Configuration](#server-configuration)
6 | - [Nginx](#nginx)
7 | - [FrankenPHP](#frankenphp)
8 | - [Directory Permissions](#directory-permissions)
9 | - [Optimization](#optimization)
10 | - [Caching Configuration](#optimizing-configuration-loading)
11 | - [Caching Events](#caching-events)
12 | - [Caching Routes](#optimizing-route-loading)
13 | - [Caching Views](#optimizing-view-loading)
14 | - [Reloading Services](#reloading-services)
15 | - [Debug Mode](#debug-mode)
16 | - [The Health Route](#the-health-route)
17 | - [Deploying With Laravel Cloud or Forge](#deploying-with-cloud-or-forge)
18 |
19 |
20 | ## Introduction
21 |
22 | When you're ready to deploy your Laravel application to production, there are some important things you can do to make sure your application is running as efficiently as possible. In this document, we'll cover some great starting points for making sure your Laravel application is deployed properly.
23 |
24 |
25 | ## Server Requirements
26 |
27 | The Laravel framework has a few system requirements. You should ensure that your web server has the following minimum PHP version and extensions:
28 |
29 |
47 |
48 |
49 | ## Server Configuration
50 |
51 |
52 | ### Nginx
53 |
54 | If you are deploying your application to a server that is running Nginx, you may use the following configuration file as a starting point for configuring your web server. Most likely, this file will need to be customized depending on your server's configuration. **If you would like assistance in managing your server, consider using a fully-managed Laravel platform like [Laravel Cloud](https://cloud.laravel.com).**
55 |
56 | Please ensure, like the configuration below, your web server directs all requests to your application's `public/index.php` file. You should never attempt to move the `index.php` file to your project's root, as serving the application from the project root will expose many sensitive configuration files to the public Internet:
57 |
58 | ```nginx
59 | server {
60 | listen 80;
61 | listen [::]:80;
62 | server_name example.com;
63 | root /srv/example.com/public;
64 |
65 | add_header X-Frame-Options "SAMEORIGIN";
66 | add_header X-Content-Type-Options "nosniff";
67 |
68 | index index.php;
69 |
70 | charset utf-8;
71 |
72 | location / {
73 | try_files $uri $uri/ /index.php?$query_string;
74 | }
75 |
76 | location = /favicon.ico { access_log off; log_not_found off; }
77 | location = /robots.txt { access_log off; log_not_found off; }
78 |
79 | error_page 404 /index.php;
80 |
81 | location ~ ^/index\.php(/|$) {
82 | fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
83 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
84 | include fastcgi_params;
85 | fastcgi_hide_header X-Powered-By;
86 | }
87 |
88 | location ~ /\.(?!well-known).* {
89 | deny all;
90 | }
91 | }
92 | ```
93 |
94 |
95 | ### FrankenPHP
96 |
97 | [FrankenPHP](https://frankenphp.dev/) may also be used to serve your Laravel applications. FrankenPHP is a modern PHP application server written in Go. To serve a Laravel PHP application using FrankenPHP, you may simply invoke its `php-server` command:
98 |
99 | ```shell
100 | frankenphp php-server -r public/
101 | ```
102 |
103 | To take advantage of more powerful features supported by FrankenPHP, such as its [Laravel Octane](/docs/{{version}}/octane) integration, HTTP/3, modern compression, or the ability to package Laravel applications as standalone binaries, please consult FrankenPHP's [Laravel documentation](https://frankenphp.dev/docs/laravel/).
104 |
105 |
106 | ### Directory Permissions
107 |
108 | Laravel will need to write to the `bootstrap/cache` and `storage` directories, so you should ensure the web server process owner has permission to write to these directories.
109 |
110 |
111 | ## Optimization
112 |
113 | When deploying your application to production, there are a variety of files that should be cached, including your configuration, events, routes, and views. Laravel provides a single, convenient `optimize` Artisan command that will cache all of these files. This command should typically be invoked as part of your application's deployment process:
114 |
115 | ```shell
116 | php artisan optimize
117 | ```
118 |
119 | The `optimize:clear` method may be used to remove all of the cache files generated by the `optimize` command as well as all keys in the default cache driver:
120 |
121 | ```shell
122 | php artisan optimize:clear
123 | ```
124 |
125 | In the following documentation, we will discuss each of the granular optimization commands that are executed by the `optimize` command.
126 |
127 |
128 | ### Caching Configuration
129 |
130 | When deploying your application to production, you should make sure that you run the `config:cache` Artisan command during your deployment process:
131 |
132 | ```shell
133 | php artisan config:cache
134 | ```
135 |
136 | This command will combine all of Laravel's configuration files into a single, cached file, which greatly reduces the number of trips the framework must make to the filesystem when loading your configuration values.
137 |
138 | > [!WARNING]
139 | > If you execute the `config:cache` command during your deployment process, you should be sure that you are only calling the `env` function from within your configuration files. Once the configuration has been cached, the `.env` file will not be loaded and all calls to the `env` function for `.env` variables will return `null`.
140 |
141 |
142 | ### Caching Events
143 |
144 | You should cache your application's auto-discovered event to listener mappings during your deployment process. This can be accomplished by invoking the `event:cache` Artisan command during deployment:
145 |
146 | ```shell
147 | php artisan event:cache
148 | ```
149 |
150 |
151 | ### Caching Routes
152 |
153 | If you are building a large application with many routes, you should make sure that you are running the `route:cache` Artisan command during your deployment process:
154 |
155 | ```shell
156 | php artisan route:cache
157 | ```
158 |
159 | This command reduces all of your route registrations into a single method call within a cached file, improving the performance of route registration when registering hundreds of routes.
160 |
161 |
162 | ### Caching Views
163 |
164 | When deploying your application to production, you should make sure that you run the `view:cache` Artisan command during your deployment process:
165 |
166 | ```shell
167 | php artisan view:cache
168 | ```
169 |
170 | This command precompiles all your Blade views so they are not compiled on demand, improving the performance of each request that returns a view.
171 |
172 |
173 | ## Reloading Services
174 |
175 | > [!NOTE]
176 | > When deploying to [Laravel Cloud](https://cloud.laravel.com), it is not necessary to use the `reload` command, as gracefully reloading of all services is handled automatically.
177 |
178 | After deploying a new version of your application, any long-running services such as queue workers, Laravel Reverb, or Laravel Octane should be reloaded / restarted to use the new code. Laravel provides a single `reload` Artisan command that will terminate these services:
179 |
180 | ```shell
181 | php artisan reload
182 | ```
183 |
184 | If you are not using [Laravel Cloud](https://cloud.laravel.com), you should manually configure a process monitor that can detect when your reloadable processes exit and automatically restart them.
185 |
186 |
187 | ## Debug Mode
188 |
189 | The debug option in your `config/app.php` configuration file determines how much information about an error is actually displayed to the user. By default, this option is set to respect the value of the `APP_DEBUG` environment variable, which is stored in your application's `.env` file.
190 |
191 | > [!WARNING]
192 | > **In your production environment, this value should always be `false`. If the `APP_DEBUG` variable is set to `true` in production, you risk exposing sensitive configuration values to your application's end users.**
193 |
194 |
195 | ## The Health Route
196 |
197 | Laravel includes a built-in health check route that can be used to monitor the status of your application. In production, this route may be used to report the status of your application to an uptime monitor, load balancer, or orchestration system such as Kubernetes.
198 |
199 | By default, the health check route is served at `/up` and will return a 200 HTTP response if the application has booted without exceptions. Otherwise, a 500 HTTP response will be returned. You may configure the URI for this route in your application's `bootstrap/app` file:
200 |
201 | ```php
202 | ->withRouting(
203 | web: __DIR__.'/../routes/web.php',
204 | commands: __DIR__.'/../routes/console.php',
205 | health: '/up', // [tl! remove]
206 | health: '/status', // [tl! add]
207 | )
208 | ```
209 |
210 | When HTTP requests are made to this route, Laravel will also dispatch a `Illuminate\Foundation\Events\DiagnosingHealth` event, allowing you to perform additional health checks relevant to your application. Within a [listener](/docs/{{version}}/events) for this event, you may check your application's database or cache status. If you detect a problem with your application, you may simply throw an exception from the listener.
211 |
212 |
213 | ## Deploying With Laravel Cloud or Forge
214 |
215 |
216 | #### Laravel Cloud
217 |
218 | If you would like a fully-managed, auto-scaling deployment platform tuned for Laravel, check out [Laravel Cloud](https://cloud.laravel.com). Laravel Cloud is a robust deployment platform for Laravel, offering managed compute, databases, caches, and object storage.
219 |
220 | Launch your Laravel application on Cloud and fall in love with the scalable simplicity. Laravel Cloud is fine-tuned by Laravel's creators to work seamlessly with the framework so you can keep writing your Laravel applications exactly like you're used to.
221 |
222 |
223 | #### Laravel Forge
224 |
225 | If you prefer to manage your own servers but aren't comfortable configuring all of the various services needed to run a robust Laravel application, [Laravel Forge](https://forge.laravel.com) is a VPS server management platform for Laravel applications.
226 |
227 | Laravel Forge can create servers on various infrastructure providers such as DigitalOcean, Linode, AWS, and more. In addition, Forge installs and manages all of the tools needed to build robust Laravel applications, such as Nginx, MySQL, Redis, Memcached, Beanstalk, and more.
228 |
--------------------------------------------------------------------------------
/testing.md:
--------------------------------------------------------------------------------
1 | # Testing: Getting Started
2 |
3 | - [Introduction](#introduction)
4 | - [Environment](#environment)
5 | - [Creating Tests](#creating-tests)
6 | - [Running Tests](#running-tests)
7 | - [Running Tests in Parallel](#running-tests-in-parallel)
8 | - [Reporting Test Coverage](#reporting-test-coverage)
9 | - [Profiling Tests](#profiling-tests)
10 | - [Configuration Caching](#configuration-caching)
11 |
12 |
13 | ## Introduction
14 |
15 | Laravel is built with testing in mind. In fact, support for testing with [Pest](https://pestphp.com) and [PHPUnit](https://phpunit.de) is included out of the box and a `phpunit.xml` file is already set up for your application. The framework also ships with convenient helper methods that allow you to expressively test your applications.
16 |
17 | By default, your application's `tests` directory contains two directories: `Feature` and `Unit`. Unit tests are tests that focus on a very small, isolated portion of your code. In fact, most unit tests probably focus on a single method. Tests within your "Unit" test directory do not boot your Laravel application and therefore are unable to access your application's database or other framework services.
18 |
19 | Feature tests may test a larger portion of your code, including how several objects interact with each other or even a full HTTP request to a JSON endpoint. **Generally, most of your tests should be feature tests. These types of tests provide the most confidence that your system as a whole is functioning as intended.**
20 |
21 | An `ExampleTest.php` file is provided in both the `Feature` and `Unit` test directories. After installing a new Laravel application, execute the `vendor/bin/pest`, `vendor/bin/phpunit`, or `php artisan test` commands to run your tests.
22 |
23 |
24 | ## Environment
25 |
26 | When running tests, Laravel will automatically set the [configuration environment](/docs/{{version}}/configuration#environment-configuration) to `testing` because of the environment variables defined in the `phpunit.xml` file. Laravel also automatically configures the session and cache to the `array` driver so that no session or cache data will be persisted while testing.
27 |
28 | You are free to define other testing environment configuration values as necessary. The `testing` environment variables may be configured in your application's `phpunit.xml` file, but make sure to clear your configuration cache using the `config:clear` Artisan command before running your tests!
29 |
30 |
31 | #### The `.env.testing` Environment File
32 |
33 | In addition, you may create a `.env.testing` file in the root of your project. This file will be used instead of the `.env` file when running Pest and PHPUnit tests or executing Artisan commands with the `--env=testing` option.
34 |
35 |
36 | ## Creating Tests
37 |
38 | To create a new test case, use the `make:test` Artisan command. By default, tests will be placed in the `tests/Feature` directory:
39 |
40 | ```shell
41 | php artisan make:test UserTest
42 | ```
43 |
44 | If you would like to create a test within the `tests/Unit` directory, you may use the `--unit` option when executing the `make:test` command:
45 |
46 | ```shell
47 | php artisan make:test UserTest --unit
48 | ```
49 |
50 | > [!NOTE]
51 | > Test stubs may be customized using [stub publishing](/docs/{{version}}/artisan#stub-customization).
52 |
53 | Once the test has been generated, you may define test as you normally would using Pest or PHPUnit. To run your tests, execute the `vendor/bin/pest`, `vendor/bin/phpunit`, or `php artisan test` command from your terminal:
54 |
55 | ```php tab=Pest
56 | toBeTrue();
60 | });
61 | ```
62 |
63 | ```php tab=PHPUnit
64 | assertTrue(true);
78 | }
79 | }
80 | ```
81 |
82 | > [!WARNING]
83 | > 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. Typically, you should invoke `parent::setUp()` at the start of your own `setUp` method, and `parent::tearDown()` at the end of your `tearDown` method.
84 |
85 |
86 | ## Running Tests
87 |
88 | As mentioned previously, once you've written tests, you may run them using `pest` or `phpunit`:
89 |
90 | ```shell tab=Pest
91 | ./vendor/bin/pest
92 | ```
93 |
94 | ```shell tab=PHPUnit
95 | ./vendor/bin/phpunit
96 | ```
97 |
98 | In addition to the `pest` or `phpunit` commands, you may use the `test` Artisan command to run your tests. The Artisan test runner provides verbose test reports in order to ease development and debugging:
99 |
100 | ```shell
101 | php artisan test
102 | ```
103 |
104 | Any arguments that can be passed to the `pest` or `phpunit` commands may also be passed to the Artisan `test` command:
105 |
106 | ```shell
107 | php artisan test --testsuite=Feature --stop-on-failure
108 | ```
109 |
110 |
111 | ### Running Tests in Parallel
112 |
113 | By default, Laravel and Pest / PHPUnit execute your tests sequentially within a single process. However, you may greatly reduce the amount of time it takes to run your tests by running tests simultaneously across multiple processes. To get started, you should install the `brianium/paratest` Composer package as a "dev" dependency. Then, include the `--parallel` option when executing the `test` Artisan command:
114 |
115 | ```shell
116 | composer require brianium/paratest --dev
117 |
118 | php artisan test --parallel
119 | ```
120 |
121 | By default, Laravel will create as many processes as there are available CPU cores on your machine. However, you may adjust the number of processes using the `--processes` option:
122 |
123 | ```shell
124 | php artisan test --parallel --processes=4
125 | ```
126 |
127 | > [!WARNING]
128 | > When running tests in parallel, some Pest / PHPUnit options (such as `--do-not-cache-result`) may not be available.
129 |
130 |
131 | #### Parallel Testing and Databases
132 |
133 | As long as you have configured a primary database connection, Laravel automatically handles creating and migrating a test database for each parallel process that is running your tests. The test databases will be suffixed with a process token which is unique per process. For example, if you have two parallel test processes, Laravel will create and use `your_db_test_1` and `your_db_test_2` test databases.
134 |
135 | By default, test databases persist between calls to the `test` Artisan command so that they can be used again by subsequent `test` invocations. However, you may re-create them using the `--recreate-databases` option:
136 |
137 | ```shell
138 | php artisan test --parallel --recreate-databases
139 | ```
140 |
141 |
142 | #### Parallel Testing Hooks
143 |
144 | Occasionally, you may need to prepare certain resources used by your application's tests so they may be safely used by multiple test processes.
145 |
146 | Using the `ParallelTesting` facade, you may specify code to be executed on the `setUp` and `tearDown` of a process or test case. The given closures receive the `$token` and `$testCase` variables that contain the process token and the current test case, respectively:
147 |
148 | ```php
149 |
190 | #### Accessing the Parallel Testing Token
191 |
192 | If you would like to access the current parallel process "token" from any other location in your application's test code, you may use the `token` method. This token is a unique, string identifier for an individual test process and may be used to segment resources across parallel test processes. For example, Laravel automatically appends this token to the end of the test databases created by each parallel testing process:
193 |
194 | $token = ParallelTesting::token();
195 |
196 |
197 | ### Reporting Test Coverage
198 |
199 | > [!WARNING]
200 | > This feature requires [Xdebug](https://xdebug.org) or [PCOV](https://pecl.php.net/package/pcov).
201 |
202 | 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:
203 |
204 | ```shell
205 | php artisan test --coverage
206 | ```
207 |
208 |
209 | #### Enforcing a Minimum Coverage Threshold
210 |
211 | You may use the `--min` option to define a minimum test coverage threshold for your application. The test suite will fail if this threshold is not met:
212 |
213 | ```shell
214 | php artisan test --coverage --min=80.3
215 | ```
216 |
217 |
218 | ### Profiling Tests
219 |
220 | The Artisan test runner also includes a convenient mechanism for listing your application's slowest tests. Invoke the `test` command with the `--profile` option to be presented with a list of your ten slowest tests, allowing you to easily investigate which tests can be improved to speed up your test suite:
221 |
222 | ```shell
223 | php artisan test --profile
224 | ```
225 |
226 |
227 | ## Configuration Caching
228 |
229 | When running tests, Laravel boots the application for each individual test method. Without a cached configuration file, each configuration file in your application must be loaded at the start of a test. To build the configuration once and re-use it for all tests in a single run, you may use the `Illuminate\Foundation\Testing\WithCachedConfig` trait:
230 |
231 | ```php tab=Pest
232 | use(WithCachedConfig::class);
237 |
238 | // ...
239 | ```
240 |
241 | ```php tab=PHPUnit
242 |
14 | ## Introduction
15 |
16 | 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.
17 |
18 | 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.
19 |
20 |
21 | ## Using PHP
22 |
23 |
24 | ### PHP and Blade
25 |
26 | 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:
27 |
28 | ```blade
29 |
30 |
31 | Hello, name; ?>
32 |
33 |
34 | ```
35 |
36 | In Laravel, this approach to rendering HTML can still be achieved using [views](/docs/{{version}}/views) and [Blade](/docs/{{version}}/blade). Blade is an extremely light-weight templating language that provides convenient, short syntax for displaying data, iterating over data, and more:
37 |
38 | ```blade
39 |
44 | ```
45 |
46 | When building applications in this fashion, form submissions and other page interactions typically receive an entirely new HTML document from the server and the entire page is re-rendered by the browser. Even today, many applications may be perfectly suited to having their frontends constructed in this way using simple Blade templates.
47 |
48 |
49 | #### Growing Expectations
50 |
51 | However, as user expectations regarding web applications have matured, many developers have found the need to build more dynamic frontends with interactions that feel more polished. In light of this, some developers choose to begin building their application's frontend using JavaScript frameworks such as Vue and React.
52 |
53 | Others, preferring to stick with the backend language they are comfortable with, have developed solutions that allow the construction of modern web application UIs while still primarily utilizing their backend language of choice. For example, in the [Rails](https://rubyonrails.org/) ecosystem, this has spurred the creation of libraries such as [Turbo](https://turbo.hotwired.dev/) [Hotwire](https://hotwired.dev/), and [Stimulus](https://stimulus.hotwired.dev/).
54 |
55 | Within the Laravel ecosystem, the need to create modern, dynamic frontends by primarily using PHP has led to the creation of [Laravel Livewire](https://livewire.laravel.com) and [Alpine.js](https://alpinejs.dev/).
56 |
57 |
58 | ### Livewire
59 |
60 | [Laravel Livewire](https://livewire.laravel.com) is a framework for building Laravel powered frontends that feel dynamic, modern, and alive just like frontends built with modern JavaScript frameworks like Vue and React.
61 |
62 | When using Livewire, you will create Livewire "components" that render a discrete portion of your UI and expose methods and data that can be invoked and interacted with from your application's frontend. For example, a simple "Counter" component might look like the following:
63 |
64 | ```php
65 | count++;
78 | }
79 |
80 | public function render()
81 | {
82 | return view('livewire.counter');
83 | }
84 | }
85 | ```
86 |
87 | And, the corresponding template for the counter would be written like so:
88 |
89 | ```blade
90 |
91 |
92 |
{{ $count }}
93 |
94 | ```
95 |
96 | As you can see, Livewire enables you to write new HTML attributes such as `wire:click` that connect your Laravel application's frontend and backend. In addition, you can render your component's current state using simple Blade expressions.
97 |
98 | For many, Livewire has revolutionized frontend development with Laravel, allowing them to stay within the comfort of Laravel while constructing modern, dynamic web applications. Typically, developers using Livewire will also utilize [Alpine.js](https://alpinejs.dev/) to "sprinkle" JavaScript onto their frontend only where it is needed, such as in order to render a dialog window.
99 |
100 | If you're new to Laravel, we recommend getting familiar with the basic usage of [views](/docs/{{version}}/views) and [Blade](/docs/{{version}}/blade). Then, consult the official [Laravel Livewire documentation](https://livewire.laravel.com/docs) to learn how to take your application to the next level with interactive Livewire components.
101 |
102 |
103 | ### Starter Kits
104 |
105 | If you would like to build your frontend using PHP and Livewire, you can leverage our [Livewire starter kit](/docs/{{version}}/starter-kits) to jump-start your application's development.
106 |
107 |
108 | ## Using React or Vue
109 |
110 | Although it's possible to build modern frontends using Laravel and Livewire, many developers still prefer to leverage the power of a JavaScript framework like React or Vue. This allows developers to take advantage of the rich ecosystem of JavaScript packages and tools available via NPM.
111 |
112 | However, without additional tooling, pairing Laravel with React or Vue would leave us needing to solve a variety of complicated problems such as client-side routing, data hydration, and authentication. Client-side routing is often simplified by using opinionated React / Vue frameworks such as [Next](https://nextjs.org/) and [Nuxt](https://nuxt.com/); however, data hydration and authentication remain complicated and cumbersome problems to solve when pairing a backend framework like Laravel with these frontend frameworks.
113 |
114 | In addition, developers are left maintaining two separate code repositories, often needing to coordinate maintenance, releases, and deployments across both repositories. While these problems are not insurmountable, we don't believe it's a productive or enjoyable way to develop applications.
115 |
116 |
117 | ### Inertia
118 |
119 | Thankfully, Laravel offers the best of both worlds. [Inertia](https://inertiajs.com) bridges the gap between your Laravel application and your modern React or Vue frontend, allowing you to build full-fledged, modern frontends using React or Vue while leveraging Laravel routes and controllers for routing, data hydration, and authentication — all within a single code repository. With this approach, you can enjoy the full power of both Laravel and React / Vue without crippling the capabilities of either tool.
120 |
121 | After installing Inertia into your Laravel application, you will write routes and controllers like normal. However, instead of returning a Blade template from your controller, you will return an Inertia page:
122 |
123 | ```php
124 | User::findOrFail($id)
141 | ]);
142 | }
143 | }
144 | ```
145 |
146 | An Inertia page corresponds to a React or Vue component, typically stored within the `resources/js/pages` directory of your application. The data given to the page via the `Inertia::render` method will be used to hydrate the "props" of the page component:
147 |
148 | ```jsx
149 | import Layout from '@/layouts/authenticated';
150 | import { Head } from '@inertiajs/react';
151 |
152 | export default function Show({ user }) {
153 | return (
154 |
155 |
156 |
Welcome
157 |
Hello {user.name}, welcome to Inertia.
158 |
159 | )
160 | }
161 | ```
162 |
163 | As you can see, Inertia allows you to leverage the full power of React or Vue when building your frontend, while providing a light-weight bridge between your Laravel powered backend and your JavaScript powered frontend.
164 |
165 | #### Server-Side Rendering
166 |
167 | If you're concerned about diving into Inertia because your application requires server-side rendering, don't worry. Inertia offers [server-side rendering support](https://inertiajs.com/server-side-rendering). And, when deploying your application via [Laravel Cloud](https://cloud.laravel.com) or [Laravel Forge](https://forge.laravel.com), it's a breeze to ensure that Inertia's server-side rendering process is always running.
168 |
169 |
170 | ### Starter Kits
171 |
172 | If you would like to build your frontend using Inertia and Vue / React, you can leverage our [React or Vue application starter kits](/docs/{{version}}/starter-kits) to jump-start your application's development. Both of these starter kits scaffold your application's backend and frontend authentication flow using Inertia, Vue / React, [Tailwind](https://tailwindcss.com), and [Vite](https://vitejs.dev) so that you can start building your next big idea.
173 |
174 |
175 | ## Bundling Assets
176 |
177 | Regardless of whether you choose to develop your frontend using Blade and Livewire or Vue / React and Inertia, you will likely need to bundle your application's CSS into production-ready assets. Of course, if you choose to build your application's frontend with Vue or React, you will also need to bundle your components into browser ready JavaScript assets.
178 |
179 | By default, Laravel utilizes [Vite](https://vitejs.dev) to bundle your assets. Vite provides lightning-fast build times and near instantaneous Hot Module Replacement (HMR) during local development. In all new Laravel applications, including those using our [starter kits](/docs/{{version}}/starter-kits), you will find a `vite.config.js` file that loads our light-weight Laravel Vite plugin that makes Vite a joy to use with Laravel applications.
180 |
181 | The fastest way to get started with Laravel and Vite is by beginning your application's development using [our application starter kits](/docs/{{version}}/starter-kits), which jump-starts your application by providing frontend and backend authentication scaffolding.
182 |
183 | > [!NOTE]
184 | > For more detailed documentation on utilizing Vite with Laravel, please see our [dedicated documentation on bundling and compiling your assets](/docs/{{version}}/vite).
185 |
--------------------------------------------------------------------------------
/folio.md:
--------------------------------------------------------------------------------
1 | # Laravel Folio
2 |
3 | - [Introduction](#introduction)
4 | - [Installation](#installation)
5 | - [Page Paths / URIs](#page-paths-uris)
6 | - [Subdomain Routing](#subdomain-routing)
7 | - [Creating Routes](#creating-routes)
8 | - [Nested Routes](#nested-routes)
9 | - [Index Routes](#index-routes)
10 | - [Route Parameters](#route-parameters)
11 | - [Route Model Binding](#route-model-binding)
12 | - [Soft Deleted Models](#soft-deleted-models)
13 | - [Render Hooks](#render-hooks)
14 | - [Named Routes](#named-routes)
15 | - [Middleware](#middleware)
16 | - [Route Caching](#route-caching)
17 |
18 |
19 | ## Introduction
20 |
21 | [Laravel Folio](https://github.com/laravel/folio) is a powerful page based router designed to simplify routing in Laravel applications. With Laravel Folio, generating a route becomes as effortless as creating a Blade template within your application's `resources/views/pages` directory.
22 |
23 | For example, to create a page that is accessible at the `/greeting` URL, just create a `greeting.blade.php` file in your application's `resources/views/pages` directory:
24 |
25 | ```php
26 |
27 | Hello World
28 |
29 | ```
30 |
31 |
32 | ## Installation
33 |
34 | To get started, install Folio into your project using the Composer package manager:
35 |
36 | ```shell
37 | composer require laravel/folio
38 | ```
39 |
40 | After installing Folio, you may execute the `folio:install` Artisan command, which will install Folio's service provider into your application. This service provider registers the directory where Folio will search for routes / pages:
41 |
42 | ```shell
43 | php artisan folio:install
44 | ```
45 |
46 |
47 | ### Page Paths / URIs
48 |
49 | By default, Folio serves pages from your application's `resources/views/pages` directory, but you may customize these directories in your Folio service provider's `boot` method.
50 |
51 | For example, sometimes it may be convenient to specify multiple Folio paths in the same Laravel application. You may wish to have a separate directory of Folio pages for your application's "admin" area, while using another directory for the rest of your application's pages.
52 |
53 | You may accomplish this using the `Folio::path` and `Folio::uri` methods. The `path` method registers a directory that Folio will scan for pages when routing incoming HTTP requests, while the `uri` method specifies the "base URI" for that directory of pages:
54 |
55 | ```php
56 | use Laravel\Folio\Folio;
57 |
58 | Folio::path(resource_path('views/pages/guest'))->uri('/');
59 |
60 | Folio::path(resource_path('views/pages/admin'))
61 | ->uri('/admin')
62 | ->middleware([
63 | '*' => [
64 | 'auth',
65 | 'verified',
66 |
67 | // ...
68 | ],
69 | ]);
70 | ```
71 |
72 |
73 | ### Subdomain Routing
74 |
75 | You may also route to pages based on the incoming request's subdomain. For example, you may wish to route requests from `admin.example.com` to a different page directory than the rest of your Folio pages. You may accomplish this by invoking the `domain` method after invoking the `Folio::path` method:
76 |
77 | ```php
78 | use Laravel\Folio\Folio;
79 |
80 | Folio::domain('admin.example.com')
81 | ->path(resource_path('views/pages/admin'));
82 | ```
83 |
84 | The `domain` method also allows you to capture parts of the domain or subdomain as parameters. These parameters will be injected into your page template:
85 |
86 | ```php
87 | use Laravel\Folio\Folio;
88 |
89 | Folio::domain('{account}.example.com')
90 | ->path(resource_path('views/pages/admin'));
91 | ```
92 |
93 |
94 | ## Creating Routes
95 |
96 | You may create a Folio route by placing a Blade template in any of your Folio mounted directories. By default, Folio mounts the `resources/views/pages` directory, but you may customize these directories in your Folio service provider's `boot` method.
97 |
98 | Once a Blade template has been placed in a Folio mounted directory, you may immediately access it via your browser. For example, a page placed in `pages/schedule.blade.php` may be accessed in your browser at `http://example.com/schedule`.
99 |
100 | To quickly view a list of all of your Folio pages / routes, you may invoke the `folio:list` Artisan command:
101 |
102 | ```shell
103 | php artisan folio:list
104 | ```
105 |
106 |
107 | ### Nested Routes
108 |
109 | You may create a nested route by creating one or more directories within one of Folio's directories. For instance, to create a page that is accessible via `/user/profile`, create a `profile.blade.php` template within the `pages/user` directory:
110 |
111 | ```shell
112 | php artisan folio:page user/profile
113 |
114 | # pages/user/profile.blade.php → /user/profile
115 | ```
116 |
117 |
118 | ### Index Routes
119 |
120 | Sometimes, you may wish to make a given page the "index" of a directory. By placing an `index.blade.php` template within a Folio directory, any requests to the root of that directory will be routed to that page:
121 |
122 | ```shell
123 | php artisan folio:page index
124 | # pages/index.blade.php → /
125 |
126 | php artisan folio:page users/index
127 | # pages/users/index.blade.php → /users
128 | ```
129 |
130 |
131 | ## Route Parameters
132 |
133 | Often, you will need to have segments of the incoming request's URL injected into your page so that you can interact with them. For example, you may need to access the "ID" of the user whose profile is being displayed. To accomplish this, you may encapsulate a segment of the page's filename in square brackets:
134 |
135 | ```shell
136 | php artisan folio:page "users/[id]"
137 |
138 | # pages/users/[id].blade.php → /users/1
139 | ```
140 |
141 | Captured segments can be accessed as variables within your Blade template:
142 |
143 | ```html
144 |
145 | User {{ $id }}
146 |
147 | ```
148 |
149 | To capture multiple segments, you can prefix the encapsulated segment with three dots `...`:
150 |
151 | ```shell
152 | php artisan folio:page "users/[...ids]"
153 |
154 | # pages/users/[...ids].blade.php → /users/1/2/3
155 | ```
156 |
157 | When capturing multiple segments, the captured segments will be injected into the page as an array:
158 |
159 | ```html
160 |
161 | @foreach ($ids as $id)
162 |
User {{ $id }}
163 | @endforeach
164 |
165 | ```
166 |
167 |
168 | ## Route Model Binding
169 |
170 | If a wildcard segment of your page template's filename corresponds one of your application's Eloquent models, Folio will automatically take advantage of Laravel's route model binding capabilities and attempt to inject the resolved model instance into your page:
171 |
172 | ```shell
173 | php artisan folio:page "users/[User]"
174 |
175 | # pages/users/[User].blade.php → /users/1
176 | ```
177 |
178 | Captured models can be accessed as variables within your Blade template. The model's variable name will be converted to "camel case":
179 |
180 | ```html
181 |
182 | User {{ $user->id }}
183 |
184 | ```
185 |
186 | #### Customizing the Key
187 |
188 | Sometimes you may wish to resolve bound Eloquent models using a column other than `id`. To do so, you may specify the column in the page's filename. For example, a page with the filename `[Post:slug].blade.php` will attempt to resolve the bound model via the `slug` column instead of the `id` column.
189 |
190 | On Windows, you should use `-` to separate the model name from the key: `[Post-slug].blade.php`.
191 |
192 | #### Model Location
193 |
194 | By default, Folio will search for your model within your application's `app/Models` directory. However, if needed, you may specify the fully-qualified model class name in your template's filename:
195 |
196 | ```shell
197 | php artisan folio:page "users/[.App.Models.User]"
198 |
199 | # pages/users/[.App.Models.User].blade.php → /users/1
200 | ```
201 |
202 |
203 | ### Soft Deleted Models
204 |
205 | By default, models that have been soft deleted are not retrieved when resolving implicit model bindings. However, if you wish, you can instruct Folio to retrieve soft deleted models by invoking the `withTrashed` function within the page's template:
206 |
207 | ```php
208 |
215 |
216 |
217 | User {{ $user->id }}
218 |
219 | ```
220 |
221 |
222 | ## Render Hooks
223 |
224 | By default, Folio will return the content of the page's Blade template as the response to the incoming request. However, you may customize the response by invoking the `render` function within the page's template.
225 |
226 | The `render` function accepts a closure which will receive the `View` instance being rendered by Folio, allowing you to add additional data to the view or customize the entire response. In addition to receiving the `View` instance, any additional route parameters or model bindings will also be provided to the `render` closure:
227 |
228 | ```php
229 | can('view', $post)) {
239 | return response('Unauthorized', 403);
240 | }
241 |
242 | return $view->with('photos', $post->author->photos);
243 | }); ?>
244 |
245 |
246 | {{ $post->content }}
247 |
248 |
249 |
250 | This author has also taken {{ count($photos) }} photos.
251 |
252 | ```
253 |
254 |
255 | ## Named Routes
256 |
257 | You may specify a name for a given page's route using the `name` function:
258 |
259 | ```php
260 |
271 | All Users
272 |
273 | ```
274 |
275 | If the page has parameters, you may simply pass their values to the `route` function:
276 |
277 | ```php
278 | route('users.show', ['user' => $user]);
279 | ```
280 |
281 |
282 | ## Middleware
283 |
284 | You can apply middleware to a specific page by invoking the `middleware` function within the page's template:
285 |
286 | ```php
287 |
294 |
295 |
296 | Dashboard
297 |
298 | ```
299 |
300 | Or, to assign middleware to a group of pages, you may chain the `middleware` method after invoking the `Folio::path` method.
301 |
302 | To specify which pages the middleware should be applied to, the array of middleware may be keyed using the corresponding URL patterns of the pages they should be applied to. The `*` character may be utilized as a wildcard character:
303 |
304 | ```php
305 | use Laravel\Folio\Folio;
306 |
307 | Folio::path(resource_path('views/pages'))->middleware([
308 | 'admin/*' => [
309 | 'auth',
310 | 'verified',
311 |
312 | // ...
313 | ],
314 | ]);
315 | ```
316 |
317 | You may include closures in the array of middleware to define inline, anonymous middleware:
318 |
319 | ```php
320 | use Closure;
321 | use Illuminate\Http\Request;
322 | use Laravel\Folio\Folio;
323 |
324 | Folio::path(resource_path('views/pages'))->middleware([
325 | 'admin/*' => [
326 | 'auth',
327 | 'verified',
328 |
329 | function (Request $request, Closure $next) {
330 | // ...
331 |
332 | return $next($request);
333 | },
334 | ],
335 | ]);
336 | ```
337 |
338 |
339 | ## Route Caching
340 |
341 | When using Folio, you should always take advantage of [Laravel's route caching capabilities](/docs/{{version}}/routing#route-caching). Folio listens for the `route:cache` Artisan command to ensure that Folio page definitions and route names are properly cached for maximum performance.
342 |
--------------------------------------------------------------------------------
/views.md:
--------------------------------------------------------------------------------
1 | # Views
2 |
3 | - [Introduction](#introduction)
4 | - [Writing Views in React / Vue](#writing-views-in-react-or-vue)
5 | - [Creating and Rendering Views](#creating-and-rendering-views)
6 | - [Nested View Directories](#nested-view-directories)
7 | - [Creating the First Available View](#creating-the-first-available-view)
8 | - [Determining if a View Exists](#determining-if-a-view-exists)
9 | - [Passing Data to Views](#passing-data-to-views)
10 | - [Sharing Data With All Views](#sharing-data-with-all-views)
11 | - [View Composers](#view-composers)
12 | - [View Creators](#view-creators)
13 | - [Optimizing Views](#optimizing-views)
14 |
15 |
16 | ## Introduction
17 |
18 | Of course, it's not practical to return entire HTML documents strings directly from your routes and controllers. Thankfully, views provide a convenient way to place all of our HTML in separate files.
19 |
20 | Views separate your controller / application logic from your presentation logic and are stored in the `resources/views` directory. When using Laravel, view templates are usually written using the [Blade templating language](/docs/{{version}}/blade). A simple view might look something like this:
21 |
22 | ```blade
23 |
24 |
25 |
26 |
27 |
Hello, {{ $name }}
28 |
29 |
30 | ```
31 |
32 | Since this view is stored at `resources/views/greeting.blade.php`, we may return it using the global `view` helper like so:
33 |
34 | ```php
35 | Route::get('/', function () {
36 | return view('greeting', ['name' => 'James']);
37 | });
38 | ```
39 |
40 | > [!NOTE]
41 | > Looking for more information on how to write Blade templates? Check out the full [Blade documentation](/docs/{{version}}/blade) to get started.
42 |
43 |
44 | ### Writing Views in React / Vue
45 |
46 | Instead of writing their frontend templates in PHP via Blade, many developers have begun to prefer to write their templates using React or Vue. Laravel makes this painless thanks to [Inertia](https://inertiajs.com/), a library that makes it a cinch to tie your React / Vue frontend to your Laravel backend without the typical complexities of building an SPA.
47 |
48 | Our [React and Vue application starter kits](/docs/{{version}}/starter-kits) give you a great starting point for your next Laravel application powered by Inertia.
49 |
50 |
51 | ## Creating and Rendering Views
52 |
53 | You may create a view by placing a file with the `.blade.php` extension in your application's `resources/views` directory or by using the `make:view` Artisan command:
54 |
55 | ```shell
56 | php artisan make:view greeting
57 | ```
58 |
59 | The `.blade.php` extension informs the framework that the file contains a [Blade template](/docs/{{version}}/blade). Blade templates contain HTML as well as Blade directives that allow you to easily echo values, create "if" statements, iterate over data, and more.
60 |
61 | Once you have created a view, you may return it from one of your application's routes or controllers using the global `view` helper:
62 |
63 | ```php
64 | Route::get('/', function () {
65 | return view('greeting', ['name' => 'James']);
66 | });
67 | ```
68 |
69 | Views may also be returned using the `View` facade:
70 |
71 | ```php
72 | use Illuminate\Support\Facades\View;
73 |
74 | return View::make('greeting', ['name' => 'James']);
75 | ```
76 |
77 | As you can see, the first argument passed to the `view` helper corresponds to the name of the view file in the `resources/views` directory. The second argument is an array of data that should be made available to the view. In this case, we are passing the `name` variable, which is displayed in the view using [Blade syntax](/docs/{{version}}/blade).
78 |
79 |
80 | ### Nested View Directories
81 |
82 | Views may also be nested within subdirectories of the `resources/views` directory. "Dot" notation may be used to reference nested views. For example, if your view is stored at `resources/views/admin/profile.blade.php`, you may return it from one of your application's routes / controllers like so:
83 |
84 | ```php
85 | return view('admin.profile', $data);
86 | ```
87 |
88 | > [!WARNING]
89 | > View directory names should not contain the `.` character.
90 |
91 |
92 | ### Creating the First Available View
93 |
94 | Using the `View` facade's `first` method, you may create the first view that exists in a given array of views. This may be useful if your application or package allows views to be customized or overwritten:
95 |
96 | ```php
97 | use Illuminate\Support\Facades\View;
98 |
99 | return View::first(['custom.admin', 'admin'], $data);
100 | ```
101 |
102 |
103 | ### Determining if a View Exists
104 |
105 | If you need to determine if a view exists, you may use the `View` facade. The `exists` method will return `true` if the view exists:
106 |
107 | ```php
108 | use Illuminate\Support\Facades\View;
109 |
110 | if (View::exists('admin.profile')) {
111 | // ...
112 | }
113 | ```
114 |
115 |
116 | ## Passing Data to Views
117 |
118 | As you saw in the previous examples, you may pass an array of data to views to make that data available to the view:
119 |
120 | ```php
121 | return view('greetings', ['name' => 'Victoria']);
122 | ```
123 |
124 | When passing information in this manner, the data should be an array with key / value pairs. After providing data to a view, you can then access each value within your view using the data's keys, such as ``.
125 |
126 | As an alternative to passing a complete array of data to the `view` helper function, you may use the `with` method to add individual pieces of data to the view. The `with` method returns an instance of the view object so that you can continue chaining methods before returning the view:
127 |
128 | ```php
129 | return view('greeting')
130 | ->with('name', 'Victoria')
131 | ->with('occupation', 'Astronaut');
132 | ```
133 |
134 |
135 | ### Sharing Data With All Views
136 |
137 | Occasionally, you may need to share data with all views that are rendered by your application. You may do so using the `View` facade's `share` method. Typically, you should place calls to the `share` method within a service provider's `boot` method. You are free to add them to the `App\Providers\AppServiceProvider` class or generate a separate service provider to house them:
138 |
139 | ```php
140 |
167 | ## View Composers
168 |
169 | View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location. View composers may prove particularly useful if the same view is returned by multiple routes or controllers within your application and always needs a particular piece of data.
170 |
171 | Typically, view composers will be registered within one of your application's [service providers](/docs/{{version}}/providers). In this example, we'll assume that the `App\Providers\AppServiceProvider` will house this logic.
172 |
173 | We'll use the `View` facade's `composer` method to register the view composer. Laravel does not include a default directory for class-based view composers, so you are free to organize them however you wish. For example, you could create an `app/View/Composers` directory to house all of your application's view composers:
174 |
175 | ```php
176 | with('count', $this->users->count());
240 | }
241 | }
242 | ```
243 |
244 | As you can see, all view composers are resolved via the [service container](/docs/{{version}}/container), so you may type-hint any dependencies you need within a composer's constructor.
245 |
246 |
247 | #### Attaching a Composer to Multiple Views
248 |
249 | You may attach a view composer to multiple views at once by passing an array of views as the first argument to the `composer` method:
250 |
251 | ```php
252 | use App\Views\Composers\MultiComposer;
253 | use Illuminate\Support\Facades\View;
254 |
255 | View::composer(
256 | ['profile', 'dashboard'],
257 | MultiComposer::class
258 | );
259 | ```
260 |
261 | The `composer` method also accepts the `*` character as a wildcard, allowing you to attach a composer to all views:
262 |
263 | ```php
264 | use Illuminate\Support\Facades;
265 | use Illuminate\View\View;
266 |
267 | Facades\View::composer('*', function (View $view) {
268 | // ...
269 | });
270 | ```
271 |
272 |
273 | ### View Creators
274 |
275 | View "creators" are very similar to view composers; however, they are executed immediately after the view is instantiated instead of waiting until the view is about to render. To register a view creator, use the `creator` method:
276 |
277 | ```php
278 | use App\View\Creators\ProfileCreator;
279 | use Illuminate\Support\Facades\View;
280 |
281 | View::creator('profile', ProfileCreator::class);
282 | ```
283 |
284 |
285 | ## Optimizing Views
286 |
287 | By default, Blade template views are compiled on demand. When a request is executed that renders a view, Laravel will determine if a compiled version of the view exists. If the file exists, Laravel will then determine if the uncompiled view has been modified more recently than the compiled view. If the compiled view either does not exist, or the uncompiled view has been modified, Laravel will recompile the view.
288 |
289 | Compiling views during the request may have a small negative impact on performance, so Laravel provides the `view:cache` Artisan command to precompile all of the views utilized by your application. For increased performance, you may wish to run this command as part of your deployment process:
290 |
291 | ```shell
292 | php artisan view:cache
293 | ```
294 |
295 | You may use the `view:clear` command to clear the view cache:
296 |
297 | ```shell
298 | php artisan view:clear
299 | ```
300 |
--------------------------------------------------------------------------------
/socialite.md:
--------------------------------------------------------------------------------
1 | # Laravel Socialite
2 |
3 | - [Introduction](#introduction)
4 | - [Installation](#installation)
5 | - [Upgrading Socialite](#upgrading-socialite)
6 | - [Configuration](#configuration)
7 | - [Authentication](#authentication)
8 | - [Routing](#routing)
9 | - [Authentication and Storage](#authentication-and-storage)
10 | - [Access Scopes](#access-scopes)
11 | - [Slack Bot Scopes](#slack-bot-scopes)
12 | - [Optional Parameters](#optional-parameters)
13 | - [Retrieving User Details](#retrieving-user-details)
14 | - [Testing](#testing)
15 |
16 |
17 | ## Introduction
18 |
19 | 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, X, LinkedIn, Google, GitHub, GitLab, Bitbucket, and Slack.
20 |
21 | > [!NOTE]
22 | > Adapters for other platforms are available via the community driven [Socialite Providers](https://socialiteproviders.com/) website.
23 |
24 |
25 | ## Installation
26 |
27 | To get started with Socialite, use the Composer package manager to add the package to your project's dependencies:
28 |
29 | ```shell
30 | composer require laravel/socialite
31 | ```
32 |
33 |
34 | ## Upgrading Socialite
35 |
36 | When upgrading to a new major version of Socialite, it's important that you carefully review [the upgrade guide](https://github.com/laravel/socialite/blob/master/UPGRADE.md).
37 |
38 |
39 | ## Configuration
40 |
41 | Before using Socialite, you will need to add credentials for the OAuth providers your application utilizes. Typically, these credentials may be retrieved by creating a "developer application" within the dashboard of the service you will be authenticating with.
42 |
43 | These credentials should be placed in your application's `config/services.php` configuration file, and should use the key `facebook`, `x`, `linkedin-openid`, `google`, `github`, `gitlab`, `bitbucket`, `slack`, or `slack-openid`, depending on the providers your application requires:
44 |
45 | ```php
46 | 'github' => [
47 | 'client_id' => env('GITHUB_CLIENT_ID'),
48 | 'client_secret' => env('GITHUB_CLIENT_SECRET'),
49 | 'redirect' => 'http://example.com/callback-url',
50 | ],
51 | ```
52 |
53 | > [!NOTE]
54 | > If the `redirect` option contains a relative path, it will automatically be resolved to a fully qualified URL.
55 |
56 |
57 | ## Authentication
58 |
59 |
60 | ### Routing
61 |
62 | To authenticate users using an OAuth provider, you will need two routes: one for redirecting the user to the OAuth provider, and another for receiving the callback from the provider after authentication. The example routes below demonstrate the implementation of both routes:
63 |
64 | ```php
65 | use Laravel\Socialite\Socialite;
66 |
67 | Route::get('/auth/redirect', function () {
68 | return Socialite::driver('github')->redirect();
69 | });
70 |
71 | Route::get('/auth/callback', function () {
72 | $user = Socialite::driver('github')->user();
73 |
74 | // $user->token
75 | });
76 | ```
77 |
78 | The `redirect` method provided by the `Socialite` facade takes care of redirecting the user to the OAuth provider, while the `user` method will examine the incoming request and retrieve the user's information from the provider after they have approved the authentication request.
79 |
80 |
81 | ### Authentication and Storage
82 |
83 | Once the user has been retrieved from the OAuth provider, you may determine if the user exists in your application's database and [authenticate the user](/docs/{{version}}/authentication#authenticate-a-user-instance). If the user does not exist in your application's database, you will typically create a new record in your database to represent the user:
84 |
85 | ```php
86 | use App\Models\User;
87 | use Illuminate\Support\Facades\Auth;
88 | use Laravel\Socialite\Socialite;
89 |
90 | Route::get('/auth/callback', function () {
91 | $githubUser = Socialite::driver('github')->user();
92 |
93 | $user = User::updateOrCreate([
94 | 'github_id' => $githubUser->id,
95 | ], [
96 | 'name' => $githubUser->name,
97 | 'email' => $githubUser->email,
98 | 'github_token' => $githubUser->token,
99 | 'github_refresh_token' => $githubUser->refreshToken,
100 | ]);
101 |
102 | Auth::login($user);
103 |
104 | return redirect('/dashboard');
105 | });
106 | ```
107 |
108 | > [!NOTE]
109 | > For more information regarding what user information is available from specific OAuth providers, please consult the documentation on [retrieving user details](#retrieving-user-details).
110 |
111 |
112 | ### Access Scopes
113 |
114 | Before redirecting the user, you may use the `scopes` method to specify the "scopes" that should be included in the authentication request. This method will merge all previously specified scopes with the scopes that you specify:
115 |
116 | ```php
117 | use Laravel\Socialite\Socialite;
118 |
119 | return Socialite::driver('github')
120 | ->scopes(['read:user', 'public_repo'])
121 | ->redirect();
122 | ```
123 |
124 | You can overwrite all existing scopes on the authentication request using the `setScopes` method:
125 |
126 | ```php
127 | return Socialite::driver('github')
128 | ->setScopes(['read:user', 'public_repo'])
129 | ->redirect();
130 | ```
131 |
132 |
133 | ### Slack Bot Scopes
134 |
135 | Slack's API provides [different types of access tokens](https://api.slack.com/authentication/token-types), each with their own set of [permission scopes](https://api.slack.com/scopes). Socialite is compatible with both of the following Slack access tokens types:
136 |
137 |
138 |
139 | - Bot (prefixed with `xoxb-`)
140 | - User (prefixed with `xoxp-`)
141 |
142 |
143 |
144 | By default, the `slack` driver will generate a `user` token and invoking the driver's `user` method will return the user's details.
145 |
146 | Bot tokens are primarily useful if your application will be sending notifications to external Slack workspaces that are owned by your application's users. To generate a bot token, invoke the `asBotUser` method before redirecting the user to Slack for authentication:
147 |
148 | ```php
149 | return Socialite::driver('slack')
150 | ->asBotUser()
151 | ->setScopes(['chat:write', 'chat:write.public', 'chat:write.customize'])
152 | ->redirect();
153 | ```
154 |
155 | In addition, you must invoke the `asBotUser` method before invoking the `user` method after Slack redirects the user back to your application after authentication:
156 |
157 | ```php
158 | $user = Socialite::driver('slack')->asBotUser()->user();
159 | ```
160 |
161 | When generating a bot token, the `user` method will still return a `Laravel\Socialite\Two\User` instance; however, only the `token` property will be hydrated. This token may be stored in order to [send notifications to the authenticated user's Slack workspaces](/docs/{{version}}/notifications#notifying-external-slack-workspaces).
162 |
163 |
164 | ### Optional Parameters
165 |
166 | A number of OAuth providers support other optional parameters on the redirect request. To include any optional parameters in the request, call the `with` method with an associative array:
167 |
168 | ```php
169 | use Laravel\Socialite\Socialite;
170 |
171 | return Socialite::driver('google')
172 | ->with(['hd' => 'example.com'])
173 | ->redirect();
174 | ```
175 |
176 | > [!WARNING]
177 | > When using the `with` method, be careful not to pass any reserved keywords such as `state` or `response_type`.
178 |
179 |
180 | ## Retrieving User Details
181 |
182 | After the user is redirected back to your application's authentication callback route, you may retrieve the user's details using Socialite's `user` method. The user object returned by the `user` method provides a variety of properties and methods you may use to store information about the user in your own database.
183 |
184 | Differing properties and methods may be available on this object depending on whether the OAuth provider you are authenticating with supports OAuth 1.0 or OAuth 2.0:
185 |
186 | ```php
187 | use Laravel\Socialite\Socialite;
188 |
189 | Route::get('/auth/callback', function () {
190 | $user = Socialite::driver('github')->user();
191 |
192 | // OAuth 2.0 providers...
193 | $token = $user->token;
194 | $refreshToken = $user->refreshToken;
195 | $expiresIn = $user->expiresIn;
196 |
197 | // OAuth 1.0 providers...
198 | $token = $user->token;
199 | $tokenSecret = $user->tokenSecret;
200 |
201 | // All providers...
202 | $user->getId();
203 | $user->getNickname();
204 | $user->getName();
205 | $user->getEmail();
206 | $user->getAvatar();
207 | });
208 | ```
209 |
210 |
211 | #### Retrieving User Details From a Token
212 |
213 | If you already have a valid access token for a user, you can retrieve their user details using Socialite's `userFromToken` method:
214 |
215 | ```php
216 | use Laravel\Socialite\Socialite;
217 |
218 | $user = Socialite::driver('github')->userFromToken($token);
219 | ```
220 |
221 | If you are using Facebook Limited Login via an iOS application, Facebook will return an OIDC token instead of an access token. Like an access token, the OIDC token can be provided to the `userFromToken` method in order to retrieve user details.
222 |
223 |
224 | #### Stateless Authentication
225 |
226 | The `stateless` method may be used to disable session state verification. This is useful when adding social authentication to a stateless API that does not utilize cookie based sessions:
227 |
228 | ```php
229 | use Laravel\Socialite\Socialite;
230 |
231 | return Socialite::driver('google')->stateless()->user();
232 | ```
233 |
234 |
235 | ## Testing
236 |
237 | Laravel Socialite provides a convenient way to test OAuth authentication flows without making actual requests to OAuth providers. The `fake` method allows you to mock the OAuth provider's behavior and define the user data that should be returned.
238 |
239 |
240 | #### Faking the Redirect
241 |
242 | To test that your application correctly redirects users to an OAuth provider, you may invoke the `fake` method before making a request to your redirect route. This will cause Socialite to return a redirect to a fake authorization URL instead of redirecting to the actual OAuth provider:
243 |
244 | ```php
245 | use Laravel\Socialite\Socialite;
246 |
247 | test('user is redirected to github', function () {
248 | Socialite::fake('github');
249 |
250 | $response = $this->get('/auth/github/redirect');
251 |
252 | $response->assertRedirect();
253 | });
254 | ```
255 |
256 |
257 | #### Faking the Callback
258 |
259 | To test your application's callback route, you may invoke the `fake` method and provide a `User` instance that should be returned when your application requests the user's details from the provider. The `User` instance may be created using the `map` method:
260 |
261 | ```php
262 | use Laravel\Socialite\Socialite;
263 | use Laravel\Socialite\Two\User;
264 |
265 | test('user can login with github', function () {
266 | Socialite::fake('github', (new User)->map([
267 | 'id' => 'github-123',
268 | 'name' => 'Jason Beggs',
269 | 'email' => 'jason@example.com',
270 | ]));
271 |
272 | $response = $this->get('/auth/github/callback');
273 |
274 | $response->assertRedirect('/dashboard');
275 |
276 | $this->assertDatabaseHas('users', [
277 | 'name' => 'Jason Beggs',
278 | 'email' => 'jason@example.com',
279 | 'github_id' => 'github-123',
280 | ]);
281 | });
282 | ```
283 |
284 | By default, the `User` instance will also include a `token` property. If needed, you may manually specify additional properties on the `User` instance:
285 |
286 | ```php
287 | $fakeUser = (new User)->map([
288 | 'id' => 'github-123',
289 | 'name' => 'Jason Beggs',
290 | 'email' => 'jason@example.com',
291 | ])->setToken('fake-token')
292 | ->setRefreshToken('fake-refresh-token')
293 | ->setExpiresIn(3600)
294 | ->setApprovedScopes(['read', 'write'])
295 | ```
296 |
--------------------------------------------------------------------------------
/envoy.md:
--------------------------------------------------------------------------------
1 | # Laravel Envoy
2 |
3 | - [Introduction](#introduction)
4 | - [Installation](#installation)
5 | - [Writing Tasks](#writing-tasks)
6 | - [Defining Tasks](#defining-tasks)
7 | - [Multiple Servers](#multiple-servers)
8 | - [Setup](#setup)
9 | - [Variables](#variables)
10 | - [Stories](#stories)
11 | - [Hooks](#completion-hooks)
12 | - [Running Tasks](#running-tasks)
13 | - [Confirming Task Execution](#confirming-task-execution)
14 | - [Notifications](#notifications)
15 | - [Slack](#slack)
16 | - [Discord](#discord)
17 | - [Telegram](#telegram)
18 | - [Microsoft Teams](#microsoft-teams)
19 |
20 |
21 | ## Introduction
22 |
23 | [Laravel Envoy](https://github.com/laravel/envoy) is a tool for executing common tasks you run on your remote servers. Using [Blade](/docs/{{version}}/blade) style syntax, you can easily setup tasks for deployment, Artisan commands, and more. Currently, Envoy only supports the Mac and Linux operating systems. However, Windows support is achievable using [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
24 |
25 |
26 | ## Installation
27 |
28 | First, install Envoy into your project using the Composer package manager:
29 |
30 | ```shell
31 | composer require laravel/envoy --dev
32 | ```
33 |
34 | Once Envoy has been installed, the Envoy binary will be available in your application's `vendor/bin` directory:
35 |
36 | ```shell
37 | php vendor/bin/envoy
38 | ```
39 |
40 |
41 | ## Writing Tasks
42 |
43 |
44 | ### Defining Tasks
45 |
46 | Tasks are the basic building block of Envoy. Tasks define the shell commands that should execute on your remote servers when the task is invoked. For example, you might define a task that executes the `php artisan queue:restart` command on all of your application's queue worker servers.
47 |
48 | All of your Envoy tasks should be defined in an `Envoy.blade.php` file at the root of your application. Here's an example to get you started:
49 |
50 | ```blade
51 | @servers(['web' => ['user@192.168.1.1'], 'workers' => ['user@192.168.1.2']])
52 |
53 | @task('restart-queues', ['on' => 'workers'])
54 | cd /home/user/example.com
55 | php artisan queue:restart
56 | @endtask
57 | ```
58 |
59 | As you can see, an array of `@servers` is defined at the top of the file, allowing you to reference these servers via the `on` option of your task declarations. The `@servers` declaration should always be placed on a single line. Within your `@task` declarations, you should place the shell commands that should execute on your servers when the task is invoked.
60 |
61 |
62 | #### Local Tasks
63 |
64 | You can force a script to run on your local computer by specifying the server's IP address as `127.0.0.1`:
65 |
66 | ```blade
67 | @servers(['localhost' => '127.0.0.1'])
68 | ```
69 |
70 |
71 | #### Importing Envoy Tasks
72 |
73 | Using the `@import` directive, you may import other Envoy files so their stories and tasks are added to yours. After the files have been imported, you may execute the tasks they contain as if they were defined in your own Envoy file:
74 |
75 | ```blade
76 | @import('vendor/package/Envoy.blade.php')
77 | ```
78 |
79 |
80 | ### Multiple Servers
81 |
82 | Envoy allows you to easily run a task across multiple servers. First, add additional servers to your `@servers` declaration. Each server should be assigned a unique name. Once you have defined your additional servers you may list each of the servers in the task's `on` array:
83 |
84 | ```blade
85 | @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])
86 |
87 | @task('deploy', ['on' => ['web-1', 'web-2']])
88 | cd /home/user/example.com
89 | git pull origin {{ $branch }}
90 | php artisan migrate --force
91 | @endtask
92 | ```
93 |
94 |
95 | #### Parallel Execution
96 |
97 | By default, tasks will be executed on each server serially. In other words, a task will finish running on the first server before proceeding to execute on the second server. If you would like to run a task across multiple servers in parallel, add the `parallel` option to your task declaration:
98 |
99 | ```blade
100 | @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2'])
101 |
102 | @task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true])
103 | cd /home/user/example.com
104 | git pull origin {{ $branch }}
105 | php artisan migrate --force
106 | @endtask
107 | ```
108 |
109 |
110 | ### Setup
111 |
112 | Sometimes, you may need to execute arbitrary PHP code before running your Envoy tasks. You may use the `@setup` directive to define a block of PHP code that should execute before your tasks:
113 |
114 | ```php
115 | @setup
116 | $now = new DateTime;
117 | @endsetup
118 | ```
119 |
120 | If you need to require other PHP files before your task is executed, you may use the `@include` directive at the top of your `Envoy.blade.php` file:
121 |
122 | ```blade
123 | @include('vendor/autoload.php')
124 |
125 | @task('restart-queues')
126 | # ...
127 | @endtask
128 | ```
129 |
130 |
131 | ### Variables
132 |
133 | If needed, you may pass arguments to Envoy tasks by specifying them on the command line when invoking Envoy:
134 |
135 | ```shell
136 | php vendor/bin/envoy run deploy --branch=master
137 | ```
138 |
139 | You may access the options within your tasks using Blade's "echo" syntax. You may also define Blade `if` statements and loops within your tasks. For example, let's verify the presence of the `$branch` variable before executing the `git pull` command:
140 |
141 | ```blade
142 | @servers(['web' => ['user@192.168.1.1']])
143 |
144 | @task('deploy', ['on' => 'web'])
145 | cd /home/user/example.com
146 |
147 | @if ($branch)
148 | git pull origin {{ $branch }}
149 | @endif
150 |
151 | php artisan migrate --force
152 | @endtask
153 | ```
154 |
155 |
156 | ### Stories
157 |
158 | Stories group a set of tasks under a single, convenient name. For instance, a `deploy` story may run the `update-code` and `install-dependencies` tasks by listing the task names within its definition:
159 |
160 | ```blade
161 | @servers(['web' => ['user@192.168.1.1']])
162 |
163 | @story('deploy')
164 | update-code
165 | install-dependencies
166 | @endstory
167 |
168 | @task('update-code')
169 | cd /home/user/example.com
170 | git pull origin master
171 | @endtask
172 |
173 | @task('install-dependencies')
174 | cd /home/user/example.com
175 | composer install
176 | @endtask
177 | ```
178 |
179 | Once the story has been written, you may invoke it in the same way you would invoke a task:
180 |
181 | ```shell
182 | php vendor/bin/envoy run deploy
183 | ```
184 |
185 |
186 | ### Hooks
187 |
188 | When tasks and stories run, a number of hooks are executed. The hook types supported by Envoy are `@before`, `@after`, `@error`, `@success`, and `@finished`. All of the code in these hooks is interpreted as PHP and executed locally, not on the remote servers that your tasks interact with.
189 |
190 | You may define as many of each of these hooks as you like. They will be executed in the order that they appear in your Envoy script.
191 |
192 |
193 | #### `@before`
194 |
195 | Before each task execution, all of the `@before` hooks registered in your Envoy script will execute. The `@before` hooks receive the name of the task that will be executed:
196 |
197 | ```blade
198 | @before
199 | if ($task === 'deploy') {
200 | // ...
201 | }
202 | @endbefore
203 | ```
204 |
205 |
206 | #### `@after`
207 |
208 | After each task execution, all of the `@after` hooks registered in your Envoy script will execute. The `@after` hooks receive the name of the task that was executed:
209 |
210 | ```blade
211 | @after
212 | if ($task === 'deploy') {
213 | // ...
214 | }
215 | @endafter
216 | ```
217 |
218 |
219 | #### `@error`
220 |
221 | After every task failure (exits with a status code greater than `0`), all of the `@error` hooks registered in your Envoy script will execute. The `@error` hooks receive the name of the task that was executed:
222 |
223 | ```blade
224 | @error
225 | if ($task === 'deploy') {
226 | // ...
227 | }
228 | @enderror
229 | ```
230 |
231 |
232 | #### `@success`
233 |
234 | If all tasks have executed without errors, all of the `@success` hooks registered in your Envoy script will execute:
235 |
236 | ```blade
237 | @success
238 | // ...
239 | @endsuccess
240 | ```
241 |
242 |
243 | #### `@finished`
244 |
245 | After all tasks have been executed (regardless of exit status), all of the `@finished` hooks will be executed. The `@finished` hooks receive the status code of the completed task, which may be `null` or an `integer` greater than or equal to `0`:
246 |
247 | ```blade
248 | @finished
249 | if ($exitCode > 0) {
250 | // There were errors in one of the tasks...
251 | }
252 | @endfinished
253 | ```
254 |
255 |
256 | ## Running Tasks
257 |
258 | To run a task or story that is defined in your application's `Envoy.blade.php` file, execute Envoy's `run` command, passing the name of the task or story you would like to execute. Envoy will execute the task and display the output from your remote servers as the task is running:
259 |
260 | ```shell
261 | php vendor/bin/envoy run deploy
262 | ```
263 |
264 |
265 | ### Confirming Task Execution
266 |
267 | If you would like to be prompted for confirmation before running a given task on your servers, you should add the `confirm` directive to your task declaration. This option is particularly useful for destructive operations:
268 |
269 | ```blade
270 | @task('deploy', ['on' => 'web', 'confirm' => true])
271 | cd /home/user/example.com
272 | git pull origin {{ $branch }}
273 | php artisan migrate
274 | @endtask
275 | ```
276 |
277 |
278 | ## Notifications
279 |
280 |
281 | ### Slack
282 |
283 | Envoy supports sending notifications to [Slack](https://slack.com) after each task is executed. The `@slack` directive accepts a Slack hook URL and a channel / user name. You may retrieve your webhook URL by creating an "Incoming WebHooks" integration in your Slack control panel.
284 |
285 | You should pass the entire webhook URL as the first argument given to the `@slack` directive. The second argument given to the `@slack` directive should be a channel name (`#channel`) or a user name (`@user`):
286 |
287 | ```blade
288 | @finished
289 | @slack('webhook-url', '#bots')
290 | @endfinished
291 | ```
292 |
293 | By default, Envoy notifications will send a message to the notification channel describing the task that was executed. However, you may overwrite this message with your own custom message by passing a third argument to the `@slack` directive:
294 |
295 | ```blade
296 | @finished
297 | @slack('webhook-url', '#bots', 'Hello, Slack.')
298 | @endfinished
299 | ```
300 |
301 |
302 | ### Discord
303 |
304 | Envoy also supports sending notifications to [Discord](https://discord.com) after each task is executed. The `@discord` directive accepts a Discord hook URL and a message. You may retrieve your webhook URL by creating a "Webhook" in your Server Settings and choosing which channel the webhook should post to. You should pass the entire Webhook URL into the `@discord` directive:
305 |
306 | ```blade
307 | @finished
308 | @discord('discord-webhook-url')
309 | @endfinished
310 | ```
311 |
312 |
313 | ### Telegram
314 |
315 | Envoy also supports sending notifications to [Telegram](https://telegram.org) after each task is executed. The `@telegram` directive accepts a Telegram Bot ID and a Chat ID. You may retrieve your Bot ID by creating a new bot using [BotFather](https://t.me/botfather). You can retrieve a valid Chat ID using [@username_to_id_bot](https://t.me/username_to_id_bot). You should pass the entire Bot ID and Chat ID into the `@telegram` directive:
316 |
317 | ```blade
318 | @finished
319 | @telegram('bot-id','chat-id')
320 | @endfinished
321 | ```
322 |
323 |
324 | ### Microsoft Teams
325 |
326 | 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:
327 |
328 | ```blade
329 | @finished
330 | @microsoftTeams('webhook-url')
331 | @endfinished
332 | ```
333 |
--------------------------------------------------------------------------------