From dbb3411ad44095dcc7d6250973d084d7f6b9814c Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Tue, 3 Jan 2023 09:34:50 +0000 Subject: [PATCH] =?UTF-8?q?[10.x]=20Uses=20PHP=20Native=20Type=20Declarati?= =?UTF-8?q?ons=20=F0=9F=90=98=20(#8287)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adds types to `up` and `down` migration methods * Adds types casts `get` and `set` methods * Adds types to `handle` middleware methods * Adds types to `join` channel method * Adds types to `handle` command method * Adds types to `render` component method * Adds types to `broadcastOn` event method * Adds types to `definition` model factory method * Adds missing types to `render` blade component * Adds missing types to `handle` middleware methods, `handle` listeners methods, and exceptions `render` methods * Adds missing types to `build` mail component * Adds missing types to notification component * Adds types to observers * Adds types to policies * Adds types to providers * Adds types to form requests * Adds types to resources * Adds types to rules * Adds types to scopes * Adds types to seeds * Adds types to tests * Fully types `artisan.md` * Fully types `authentication.md` * Fully types `authorization.md` * Fully types `billing.md` * Fully types `blade.md` * Fully types `broadcasting.md` * Fully types `cache.md` * Fully types `collections.md` * Fully types `container.md` * Fully types `controllers.md` * Fully types `database.md` * Fully types `cashier-paddle.md` * Fully types `container.md` * Fully types `controllers.md` * Fully types `database.md` * Fully types `dusk.md` * Fully types `eloquent-collections.md` * Fully types `eloquent-factories.md` * Fully types `eloquent-mutators.md` * Fully types `eloquent-relationships.md` * Fully types `eloquent-resources.md` * Fully types `eloquent-serialization.md` * Fully types `eloquent.md` * Fully types `encryption.md` * Fully types `errors.md` * Fully types `events.md` * Fully types `facades.md` * Fully types `filesystem.md` * Fully types `fortify.md` * Fully types `frontend.md` * Fully types `hashing.md` * Fully types `helpers.md` * Fully types `horizon.md` * Fully types `http-client.md` * Fully types `locatization.md` * Fully types `logging.md` * Fully types `mail.md` * Fully types `middleware.md` * Fully types `migrations.md` * Fully types `mocking.md` * Fully types `notifications.md` * Fully types `octane.md` * Fully types `pagination.md` * Fully types `passport.md` * Fully types `passport.md` * Fully types `passwords.md` * Fully types `providers.md` * Re-adds missing type * Fully types `queries.md` * Fully types `queues.md` * Fully types `rate-limiting.md` * Fully types `redirects.md` * Fully types `redis.md` * Fully types `requests.md` * Fully types `responses.md` * Fully types `routing.md` * Fully types `scheduling.md` * Fully types `scout.md` * Fully types `session.md` * Fully types `telescope.md` * Fully types `testing.md` * Fully types `urls.md` * Fully types `validation.md` * Fully types `verification.md` * Fully types `views.md` * Fully types `vite.md` * Adds some missing types * Types middlewares `$next` argument * Types missing responses * Uses `void` as command return type * Reverts changes on dots * Fixes signature * Reverts changes on Authenticable * Reverts changes on `UserProvider` * Reverts changes on `UserProvider` * Fixes type * Reverts changes on `resolveChildRouteBinding` * Clarifies returns on components * Reverts order of types * Updates types order * Reworks broadcasting docs * Removes unused import * Uses dots * Applies more types on casts * Fixes `withResponse` type * Improves order of types * Fixes order of imports * More dots * Fixes return type of scope * Improves `report` on exceptions * Improves errors * Fixes style * Adds missing type on Horizon's gate method * Revert changes on `sendPasswordResetNotifications` * Adds missing import * Revert changes on upgrade * More adjustsments * Clarifies that `$notifiable` is an object * Removes non-needed imports * Uses `response()->noContent()` * Improves rules types * Adjusts isolable commands types * Typo on comments * Adds remaining docs types --- artisan.md | 70 ++++------- authentication.md | 62 +++++----- authorization.md | 133 +++++++------------- billing.md | 103 ++++++---------- blade.md | 84 ++++--------- broadcasting.md | 132 ++++++++++---------- cache.md | 29 ++--- cashier-paddle.md | 74 +++++------ collections.md | 164 ++++++++++++------------ console-tests.md | 8 +- container.md | 72 +++++------ contracts.md | 10 +- contributions.md | 2 +- controllers.md | 47 +++---- database-testing.md | 10 +- database.md | 32 ++--- dusk.md | 109 ++++++---------- eloquent-collections.md | 11 +- eloquent-factories.md | 37 +++--- eloquent-mutators.md | 104 +++++----------- eloquent-relationships.md | 158 ++++++++++++++---------- eloquent-resources.md | 108 +++++++--------- eloquent-serialization.md | 7 +- eloquent.md | 165 +++++++++---------------- encryption.md | 10 +- errors.md | 66 +++++----- events.md | 126 +++++++------------ facades.md | 34 ++--- filesystem.md | 25 ++-- fortify.md | 43 +++---- frontend.md | 6 +- hashing.md | 8 +- helpers.md | 83 ++++++++----- horizon.md | 28 ++--- http-client.md | 27 ++-- http-tests.md | 62 ++++------ localization.md | 10 +- logging.md | 29 ++--- mail.md | 109 ++++++---------- middleware.md | 65 +++++----- migrations.md | 24 ++-- mocking.md | 46 +++---- notifications.md | 254 ++++++++++++-------------------------- octane.md | 41 +++--- packages.md | 56 +++------ pagination.md | 17 +-- passport.md | 55 +++------ passwords.md | 15 ++- providers.md | 33 ++--- queries.md | 50 ++++---- queues.md | 216 ++++++++++++-------------------- rate-limiting.md | 5 +- redirects.md | 4 +- redis.md | 26 ++-- releases.md | 4 +- requests.md | 76 ++++++------ responses.md | 10 +- routing.md | 106 ++++++++-------- sanctum.md | 10 +- scheduling.md | 13 +- scout.md | 47 +++---- seeding.md | 16 +-- session.md | 43 +++---- telescope.md | 33 ++--- testing.md | 19 ++- urls.md | 20 ++- validation.md | 137 ++++++++++---------- verification.md | 6 +- views.md | 51 ++++---- vite.md | 16 ++- 70 files changed, 1594 insertions(+), 2317 deletions(-) diff --git a/artisan.md b/artisan.md index 8795ecb8cc9..843bb5898b2 100644 --- a/artisan.md +++ b/artisan.md @@ -147,11 +147,8 @@ Let's take a look at an example command. Note that we are able to request any de /** * Execute the console command. - * - * @param \App\Support\DripEmailer $drip - * @return mixed */ - public function handle(DripEmailer $drip) + public function handle(DripEmailer $drip): void { $drip->send(User::find($this->argument('user'))); } @@ -167,17 +164,15 @@ Closure based commands provide an alternative to defining console commands as cl /** * Register the closure based commands for the application. - * - * @return void */ - protected function commands() + protected function commands(): void { require base_path('routes/console.php'); } Even though this file does not define HTTP routes, it defines console based entry points (routes) into your application. Within this file, you may define all of your closure based console commands using the `Artisan::command` method. The `command` method accepts two arguments: the [command signature](#defining-input-expectations) and a closure which receives the command's arguments and options: - Artisan::command('mail:send {user}', function ($user) { + Artisan::command('mail:send {user}', function (string $user) { $this->info("Sending email to: {$user}!"); }); @@ -191,7 +186,7 @@ In addition to receiving your command's arguments and options, command closures use App\Models\User; use App\Support\DripEmailer; - Artisan::command('mail:send {user}', function (DripEmailer $drip, $user) { + Artisan::command('mail:send {user}', function (DripEmailer $drip, string $user) { $drip->send(User::find($user)); }); @@ -200,7 +195,7 @@ In addition to receiving your command's arguments and options, command closures When defining a closure based command, you may use the `purpose` method to add a description to the command. This description will be displayed when you run the `php artisan list` or `php artisan help` commands: - Artisan::command('mail:send {user}', function ($user) { + Artisan::command('mail:send {user}', function (string $user) { // ... })->purpose('Send a marketing email to a user'); @@ -242,12 +237,13 @@ php artisan mail:send 1 --isolated=12 By default, isolation locks expire after the command is finished. Or, if the command is interrupted and unable to finish, the lock will expire after one hour. However, you may adjust the lock expiration time by defining a `isolationLockExpiresAt` method on your command: ```php +use DateTimeInterface; +use DateInterval; + /** * Determine when an isolation lock expires for the command. - * - * @return \DateTimeInterface|\DateInterval */ -public function isolationLockExpiresAt() +public function isolationLockExpiresAt(): DateTimeInterface|DateInterval { return now()->addMinutes(5); } @@ -385,14 +381,10 @@ While your command is executing, you will likely need to access the values for t /** * Execute the console command. - * - * @return int */ - public function handle() + public function handle(): void { $userId = $this->argument('user'); - - // } If you need to retrieve all of the arguments as an `array`, call the `arguments` method: @@ -414,12 +406,12 @@ In addition to displaying output, you may also ask the user to provide input dur /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): void { $name = $this->ask('What is your name?'); + + // ... } The `secret` method is similar to `ask`, but the user's input will not be visible to them as they type in the console. This method is useful when asking for sensitive information such as passwords: @@ -432,13 +424,13 @@ The `secret` method is similar to `ask`, but the user's input will not be visibl If you need to ask the user for a simple "yes or no" confirmation, you may use the `confirm` method. By default, this method will return `false`. However, if the user enters `y` or `yes` in response to the prompt, the method will return `true`. if ($this->confirm('Do you wish to continue?')) { - // + // ... } If necessary, you may specify that the confirmation prompt should return `true` by default by passing `true` as the second argument to the `confirm` method: if ($this->confirm('Do you wish to continue?', true)) { - // + // ... } @@ -450,7 +442,7 @@ The `anticipate` method can be used to provide auto-completion for possible choi Alternatively, you may pass a closure as the second argument to the `anticipate` method. The closure will be called each time the user types an input character. The closure should accept a string parameter containing the user's input so far, and return an array of options for auto-completion: - $name = $this->anticipate('What is your address?', function ($input) { + $name = $this->anticipate('What is your address?', function (string $input) { // Return auto-completion options... }); @@ -482,10 +474,8 @@ To send output to the console, you may use the `line`, `info`, `comment`, `quest /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): void { // ... @@ -528,7 +518,7 @@ For long running tasks, it can be helpful to show a progress bar that informs us use App\Models\User; - $users = $this->withProgressBar(User::all(), function ($user) { + $users = $this->withProgressBar(User::all(), function (User $user) { $this->performTask($user); }); @@ -558,10 +548,8 @@ All of your console commands are registered within your application's `App\Conso /** * Register the commands for the application. - * - * @return void */ - protected function commands() + protected function commands(): void { $this->load(__DIR__.'/Commands'); $this->load(__DIR__.'/../Domain/Orders/Commands'); @@ -582,12 +570,12 @@ Sometimes you may wish to execute an Artisan command outside of the CLI. For exa use Illuminate\Support\Facades\Artisan; - Route::post('/user/{user}/mail', function ($user) { + Route::post('/user/{user}/mail', function (string $user) { $exitCode = Artisan::call('mail:send', [ 'user' => $user, '--queue' => 'default' ]); - // + // ... }); Alternatively, you may pass the entire Artisan command to the `call` method as a string: @@ -623,12 +611,12 @@ Using the `queue` method on the `Artisan` facade, you may even queue Artisan com use Illuminate\Support\Facades\Artisan; - Route::post('/user/{user}/mail', function ($user) { + Route::post('/user/{user}/mail', function (string $user) { Artisan::queue('mail:send', [ 'user' => $user, '--queue' => 'default' ]); - // + // ... }); Using the `onConnection` and `onQueue` methods, you may specify the connection or queue the Artisan command should be dispatched to: @@ -644,16 +632,14 @@ Sometimes you may wish to call other commands from an existing Artisan command. /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): void { $this->call('mail:send', [ 'user' => 1, '--queue' => 'default' ]); - // + // ... } If you would like to call another console command and suppress all of its output, you may use the `callSilently` method. The `callSilently` method has the same signature as the `call` method: @@ -669,10 +655,8 @@ As you may know, operating systems allow signals to be sent to running processes /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): void { $this->trap(SIGTERM, fn () => $this->shouldKeepRunning = false); @@ -683,7 +667,7 @@ As you may know, operating systems allow signals to be sent to running processes To listen for multiple signals at once, you may provide an array of signals to the `trap` method: - $this->trap([SIGTERM, SIGQUIT], function ($signal) { + $this->trap([SIGTERM, SIGQUIT], function (int $signal) { $this->shouldKeepRunning = false; dump($signal); // SIGTERM / SIGQUIT diff --git a/authentication.md b/authentication.md index dfa26b2440f..fd80f884a9d 100644 --- a/authentication.md +++ b/authentication.md @@ -147,18 +147,18 @@ Alternatively, once a user is authenticated, you may access the authenticated us namespace App\Http\Controllers; use Illuminate\Http\Request; + use Illuminate\Http\Response; class FlightController extends Controller { /** * Update the flight information for an existing flight. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function update(Request $request) + public function update(Request $request): Response { // $request->user() + + return response()->noContent(); } } @@ -190,13 +190,12 @@ To determine if the user making the incoming HTTP request is authenticated, you When the `auth` middleware detects an unauthenticated user, it will redirect the user to the `login` [named route](/docs/{{version}}/routing#named-routes). You may modify this behavior by updating the `redirectTo` function in your application's `app/Http/Middleware/Authenticate.php` file: + use Illuminate\Http\Request; + /** * Get the path the user should be redirected to. - * - * @param \Illuminate\Http\Request $request - * @return string */ - protected function redirectTo($request) + protected function redirectTo(Request $request): string { return route('login'); } @@ -230,17 +229,15 @@ We will access Laravel's authentication services via the `Auth` [facade](/docs/{ namespace App\Http\Controllers; use Illuminate\Http\Request; + use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Auth; class LoginController extends Controller { /** * Handle an authentication attempt. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function authenticate(Request $request) + public function authenticate(Request $request): RedirectResponse { $credentials = $request->validate([ 'email' => ['required', 'email'], @@ -278,10 +275,12 @@ If you wish, you may also add extra query conditions to the authentication query For complex query conditions, you may provide a closure in your array of credentials. This closure will be invoked with the query instance, allowing you to customize the query based on your application's needs: + use Illuminate\Database\Eloquent\Builder; + if (Auth::attempt([ 'email' => $email, 'password' => $password, - fn ($query) => $query->has('activeSubscription'), + fn (Builder $query) => $query->has('activeSubscription'), ])) { // Authentication was successful... } @@ -294,7 +293,7 @@ The `attemptWhen` method, which receives a closure as its second argument, may b if (Auth::attemptWhen([ 'email' => $email, 'password' => $password, - ], function ($user) { + ], function (User $user) { return $user->isNotBanned(); })) { // Authentication was successful... @@ -369,7 +368,7 @@ You may pass a boolean value as the second argument to the `loginUsingId` method You may use the `once` method to authenticate a user with the application for a single request. No sessions or cookies will be utilized when calling this method: if (Auth::once($credentials)) { - // + // ... } @@ -402,18 +401,19 @@ You may also use HTTP Basic Authentication without setting a user identifier coo namespace App\Http\Middleware; + use Closure; + use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; + use Symfony\Component\HttpFoundation\Response; class AuthenticateOnceWithBasicAuth { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, $next) + public function handle(Request $request, Closure $next): Response { return Auth::onceBasic() ?: $next($request); } @@ -434,15 +434,13 @@ To manually log users out of your application, you may use the `logout` method p In addition to calling the `logout` method, it is recommended that you invalidate the user's session and regenerate their [CSRF token](/docs/{{version}}/csrf). After logging the user out, you would typically redirect the user to the root of your application: use Illuminate\Http\Request; + use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Auth; /** * Log the user out of the application. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function logout(Request $request) + public function logout(Request $request): RedirectResponse { Auth::logout(); @@ -547,6 +545,7 @@ You may define your own authentication guards using the `extend` method on the ` namespace App\Providers; use App\Services\Auth\JwtGuard; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Auth; @@ -554,14 +553,12 @@ You may define your own authentication guards using the `extend` method on the ` { /** * Register any application authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); - Auth::extend('jwt', function ($app, $name, array $config) { + Auth::extend('jwt', function (Application $app, string $name, array $config) { // Return an instance of Illuminate\Contracts\Auth\Guard... return new JwtGuard(Auth::createUserProvider($config['provider'])); @@ -591,10 +588,8 @@ To get started, call the `Auth::viaRequest` method within the `boot` method of y /** * Register any application authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -621,6 +616,7 @@ If you are not using a traditional relational database to store your users, you namespace App\Providers; use App\Extensions\MongoUserProvider; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Auth; @@ -628,14 +624,12 @@ If you are not using a traditional relational database to store your users, you { /** * Register any application authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); - Auth::provider('mongo', function ($app, array $config) { + Auth::provider('mongo', function (Application $app, array $config) { // Return an instance of Illuminate\Contracts\Auth\UserProvider... return new MongoUserProvider($app->make('mongo.connection')); diff --git a/authorization.md b/authorization.md index 3175bcd6bd3..58367dcbb7b 100644 --- a/authorization.md +++ b/authorization.md @@ -51,10 +51,8 @@ In this example, we'll define a gate to determine if a user can update a given ` /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -70,10 +68,8 @@ Like controllers, gates may also be defined using a class callback array: /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -92,24 +88,23 @@ To authorize an action using gates, you should use the `allows` or `denies` meth use App\Http\Controllers\Controller; use App\Models\Post; use Illuminate\Http\Request; + use Illuminate\Http\Response; use Illuminate\Support\Facades\Gate; class PostController extends Controller { /** * Update the given post. - * - * @param \Illuminate\Http\Request $request - * @param \App\Models\Post $post - * @return \Illuminate\Http\Response */ - public function update(Request $request, Post $post) + public function update(Request $request, Post $post): Response { if (! Gate::allows('update-post', $post)) { abort(403); } // Update the post... + + return response()->noContent(); } } @@ -151,7 +146,7 @@ The gate methods for authorizing abilities (`allows`, `denies`, `check`, `any`, use App\Models\User; use Illuminate\Support\Facades\Gate; - Gate::define('create-post', function (User $user, Category $category, $pinned) { + Gate::define('create-post', function (User $user, Category $category, bool $pinned) { if (! $user->canPublishToGroup($category->group)) { return false; } elseif ($pinned && ! $user->canPinPosts()) { @@ -228,9 +223,10 @@ Because hiding resources via a `404` response is such a common pattern for web a Sometimes, you may wish to grant all abilities to a specific user. You may use the `before` method to define a closure that is run before all other authorization checks: + use App\Models\User; use Illuminate\Support\Facades\Gate; - Gate::before(function ($user, $ability) { + Gate::before(function (User $user, string $ability) { if ($user->isAdministrator()) { return true; } @@ -240,7 +236,9 @@ If the `before` closure returns a non-null result that result will be considered You may use the `after` method to define a closure to be executed after all other authorization checks: - Gate::after(function ($user, $ability, $result, $arguments) { + use App\Models\User; + + Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) { if ($user->isAdministrator()) { return true; } @@ -254,11 +252,12 @@ Similar to the `before` method, if the `after` closure returns a non-null result Occasionally, you may wish to determine if the currently authenticated user is authorized to perform a given action without writing a dedicated gate that corresponds to the action. Laravel allows you to perform these types of "inline" authorization checks via the `Gate::allowIf` and `Gate::denyIf` methods: ```php +use App\Models\User; use Illuminate\Support\Facades\Gate; -Gate::allowIf(fn ($user) => $user->isAdministrator()); +Gate::allowIf(fn (User $user) => $user->isAdministrator()); -Gate::denyIf(fn ($user) => $user->banned()); +Gate::denyIf(fn (User $user) => $user->banned()); ``` If the action is not authorized or if no user is currently authenticated, Laravel will automatically throw an `Illuminate\Auth\Access\AuthorizationException` exception. Instances of `AuthorizationException` are automatically converted to a 403 HTTP response by Laravel's exception handler. @@ -312,14 +311,12 @@ The `App\Providers\AuthServiceProvider` included with fresh Laravel applications /** * Register any application authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); - // + // ... } } @@ -332,7 +329,7 @@ If you would like to define your own policy discovery logic, you may register a use Illuminate\Support\Facades\Gate; - Gate::guessPolicyNamesUsing(function ($modelClass) { + Gate::guessPolicyNamesUsing(function (string $modelClass) { // Return the name of the policy class for the given model... }); @@ -360,12 +357,8 @@ The `update` method will receive a `User` and a `Post` instance as its arguments { /** * Determine if the given post can be updated by the user. - * - * @param \App\Models\User $user - * @param \App\Models\Post $post - * @return bool */ - public function update(User $user, Post $post) + public function update(User $user, Post $post): bool { return $user->id === $post->user_id; } @@ -389,12 +382,8 @@ So far, we have only examined policy methods that return simple boolean values. /** * Determine if the given post can be updated by the user. - * - * @param \App\Models\User $user - * @param \App\Models\Post $post - * @return \Illuminate\Auth\Access\Response */ - public function update(User $user, Post $post) + public function update(User $user, Post $post): Response { return $user->id === $post->user_id ? Response::allow() @@ -430,12 +419,8 @@ When an action is denied via a policy method, a `403` HTTP response is returned; /** * Determine if the given post can be updated by the user. - * - * @param \App\Models\User $user - * @param \App\Models\Post $post - * @return \Illuminate\Auth\Access\Response */ - public function update(User $user, Post $post) + public function update(User $user, Post $post): Response { return $user->id === $post->user_id ? Response::allow() @@ -450,12 +435,8 @@ Because hiding resources via a `404` response is such a common pattern for web a /** * Determine if the given post can be updated by the user. - * - * @param \App\Models\User $user - * @param \App\Models\Post $post - * @return \Illuminate\Auth\Access\Response */ - public function update(User $user, Post $post) + public function update(User $user, Post $post): Response { return $user->id === $post->user_id ? Response::allow() @@ -469,11 +450,8 @@ Some policy methods only receive an instance of the currently authenticated user /** * Determine if the given user can create posts. - * - * @param \App\Models\User $user - * @return bool */ - public function create(User $user) + public function create(User $user): bool { return $user->role == 'writer'; } @@ -494,12 +472,8 @@ By default, all gates and policies automatically return `false` if the incoming { /** * Determine if the given post can be updated by the user. - * - * @param \App\Models\User $user - * @param \App\Models\Post $post - * @return bool */ - public function update(?User $user, Post $post) + public function update(?User $user, Post $post): bool { return optional($user)->id === $post->user_id; } @@ -514,16 +488,14 @@ For certain users, you may wish to authorize all actions within a given policy. /** * Perform pre-authorization checks. - * - * @param \App\Models\User $user - * @param string $ability - * @return void|bool */ - public function before(User $user, $ability) + public function before(User $user, string $ability): bool|null { if ($user->isAdministrator()) { return true; } + + return null; } If you would like to deny all authorization checks for a particular type of user then you may return `false` from the `before` method. If `null` is returned, the authorization check will fall through to the policy method. @@ -546,23 +518,22 @@ The `App\Models\User` model that is included with your Laravel application inclu use App\Http\Controllers\Controller; use App\Models\Post; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PostController extends Controller { /** * Update the given post. - * - * @param \Illuminate\Http\Request $request - * @param \App\Models\Post $post - * @return \Illuminate\Http\Response */ - public function update(Request $request, Post $post) + public function update(Request $request, Post $post): Response { if ($request->user()->cannot('update', $post)) { abort(403); } // Update the post... + + return response()->noContent(); } } @@ -580,22 +551,22 @@ Remember, some actions may correspond to policy methods like `create` that do no use App\Http\Controllers\Controller; use App\Models\Post; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PostController extends Controller { /** * Create a post. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { if ($request->user()->cannot('create', Post::class)) { abort(403); } // Create the post... + + return response()->noContent(); } } @@ -613,23 +584,22 @@ Like the `can` method, this method accepts the name of the action you wish to au use App\Http\Controllers\Controller; use App\Models\Post; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PostController extends Controller { /** * Update the given blog post. * - * @param \Illuminate\Http\Request $request - * @param \App\Models\Post $post - * @return \Illuminate\Http\Response - * * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function update(Request $request, Post $post) + public function update(Request $request, Post $post): Response { $this->authorize('update', $post); // The current user can update the blog post... + + return response()->noContent(); } } @@ -640,20 +610,20 @@ As previously discussed, some policy methods like `create` do not require a mode use App\Models\Post; use Illuminate\Http\Request; + use Illuminate\Http\Response; /** * Create a new blog post. * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function create(Request $request) + public function create(Request $request): Response { $this->authorize('create', Post::class); // The current user can create blog posts... + + return response()->noContent(); } @@ -675,8 +645,6 @@ The `authorizeResource` method accepts the model's class name as its first argum { /** * Create the controller instance. - * - * @return void */ public function __construct() { @@ -802,13 +770,8 @@ When authorizing actions using policies, you may pass an array as the second arg /** * Determine if the given post can be updated by the user. - * - * @param \App\Models\User $user - * @param \App\Models\Post $post - * @param int $category - * @return bool */ - public function update(User $user, Post $post, int $category) + public function update(User $user, Post $post, int $category): bool { return $user->id === $post->user_id && $user->canUpdateCategory($category); @@ -819,15 +782,13 @@ When attempting to determine if the authenticated user can update a given post, /** * Update the given blog post. * - * @param \Illuminate\Http\Request $request - * @param \App\Models\Post $post - * @return \Illuminate\Http\Response - * * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function update(Request $request, Post $post) + public function update(Request $request, Post $post): Response { $this->authorize('update', [$post, $request->category]); // The current user can update the blog post... + + return response()->noContent(); } diff --git a/billing.md b/billing.md index 06cd49ec7dc..62519b8e934 100644 --- a/billing.md +++ b/billing.md @@ -113,10 +113,8 @@ If you would like to prevent Cashier's migrations from running entirely, you may /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { Cashier::ignoreMigrations(); } @@ -146,10 +144,8 @@ Cashier assumes your billable model will be the `App\Models\User` class that shi /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Cashier::useCustomerModel(User::class); } @@ -198,10 +194,8 @@ Thanks to [Stripe Tax](https://stripe.com/tax), it's possible to automatically c /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Cashier::calculateTaxes(); } @@ -243,10 +237,8 @@ After defining your model, you may instruct Cashier to use your custom model via /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Cashier::useSubscriptionModel(Subscription::class); Cashier::useSubscriptionItemModel(SubscriptionItem::class); @@ -346,16 +338,15 @@ Typically, when your application's users update their name, email address, or ot To automate this, you may define an event listener on your billable model that reacts to the model's `updated` event. Then, within your event listener, you may invoke the `syncStripeCustomerDetails` method on the model: + use App\Models\User; use function Illuminate\Events\queueable; /** * The "booted" method of the model. - * - * @return void */ - protected static function booted() + protected static function booted(): void { - static::updated(queueable(function ($customer) { + static::updated(queueable(function (User $customer) { if ($customer->hasStripeId()) { $customer->syncStripeCustomerDetails(); } @@ -368,10 +359,8 @@ You may customize the columns used for syncing customer information to Stripe by /** * Get the customer name that should be synced to Stripe. - * - * @return string|null */ - public function stripeName() + public function stripeName(): string|null { return $this->company_name; } @@ -555,19 +544,19 @@ You can retrieve a specific payment method that is attached to the billable mode To determine if a billable model has a default payment method attached to their account, invoke the `hasDefaultPaymentMethod` method: if ($user->hasDefaultPaymentMethod()) { - // + // ... } You may use the `hasPaymentMethod` method to determine if a billable model has at least one payment method attached to their account: if ($user->hasPaymentMethod()) { - // + // ... } This method will determine if the billable model has payment methods of the `card` type. To determine if a payment method of another type exists for the model, you may pass the `type` as an argument to the method: if ($user->hasPaymentMethod('sepa_debit')) { - // + // ... } @@ -759,7 +748,7 @@ Finally, you should always make sure to only add one active subscription per typ Once a customer is subscribed to your application, you may easily check their subscription status using a variety of convenient methods. First, the `subscribed` method returns `true` if the customer has an active subscription, even if the subscription is currently within its trial period. The `subscribed` method accepts the name of the subscription as its first argument: if ($user->subscribed('default')) { - // + // ... } The `subscribed` method also makes a great candidate for a [route middleware](/docs/{{version}}/middleware), allowing you to filter access to routes and controllers based on the user's subscription status: @@ -769,17 +758,17 @@ The `subscribed` method also makes a great candidate for a [route middleware](/d namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; class EnsureUserIsSubscribed { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { if ($request->user() && ! $request->user()->subscribed('default')) { // This user is not a paying customer... @@ -793,31 +782,31 @@ The `subscribed` method also makes a great candidate for a [route middleware](/d If you would like to determine if a user is still within their trial period, you may use the `onTrial` method. This method can be useful for determining if you should display a warning to the user that they are still on their trial period: if ($user->subscription('default')->onTrial()) { - // + // ... } The `subscribedToProduct` method may be used to determine if the user is subscribed to a given product based on a given Stripe product's identifier. In Stripe, products are collections of prices. In this example, we will determine if the user's `default` subscription is actively subscribed to the application's "premium" product. The given Stripe product identifier should correspond to one of your product's identifiers in the Stripe dashboard: if ($user->subscribedToProduct('prod_premium', 'default')) { - // + // ... } By passing an array to the `subscribedToProduct` method, you may determine if the user's `default` subscription is actively subscribed to the application's "basic" or "premium" product: if ($user->subscribedToProduct(['prod_basic', 'prod_premium'], 'default')) { - // + // ... } The `subscribedToPrice` method may be used to determine if a customer's subscription corresponds to a given price ID: if ($user->subscribedToPrice('price_basic_monthly', 'default')) { - // + // ... } The `recurring` method may be used to determine if the user is currently subscribed and is no longer within their trial period: if ($user->subscription('default')->recurring()) { - // + // ... } > **Warning** @@ -829,19 +818,19 @@ The `recurring` method may be used to determine if the user is currently subscri To determine if the user was once an active subscriber but has canceled their subscription, you may use the `canceled` method: if ($user->subscription('default')->canceled()) { - // + // ... } You may also determine if a user has canceled their subscription but are still on their "grace period" until the subscription fully expires. For example, if a user cancels a subscription on March 5th that was originally scheduled to expire on March 10th, the user is on their "grace period" until March 10th. Note that the `subscribed` method still returns `true` during this time: if ($user->subscription('default')->onGracePeriod()) { - // + // ... } To determine if the user has canceled their subscription and is no longer within their "grace period", you may use the `ended` method: if ($user->subscription('default')->ended()) { - // + // ... } @@ -852,11 +841,11 @@ If a subscription requires a secondary payment action after creation the subscri Similarly, if a secondary payment action is required when swapping prices the subscription will be marked as `past_due`. When your subscription is in either of these states it will not be active until the customer has confirmed their payment. Determining if a subscription has an incomplete payment may be accomplished using the `hasIncompletePayment` method on the billable model or a subscription instance: if ($user->hasIncompletePayment('default')) { - // + // ... } if ($user->subscription('default')->hasIncompletePayment()) { - // + // ... } When a subscription has an incomplete payment, you should direct the user to Cashier's payment confirmation page, passing the `latestPayment` identifier. You may use the `latestPayment` method available on subscription instance to retrieve this identifier: @@ -873,10 +862,8 @@ If you would like the subscription to still be considered active when it's in a /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { Cashier::keepPastDueSubscriptionsActive(); Cashier::keepIncompleteSubscriptionsActive(); @@ -1197,9 +1184,9 @@ To specify the tax rates a user pays on a subscription, you should implement the /** * The tax rates that should apply to the customer's subscriptions. * - * @return array + * @return array */ - public function taxRates() + public function taxRates(): array { return ['txr_id']; } @@ -1211,9 +1198,9 @@ If you're offering subscriptions with multiple products, you may define differen /** * The tax rates that should apply to the customer's subscriptions. * - * @return array + * @return array> */ - public function priceTaxRates() + public function priceTaxRates(): array { return [ 'price_monthly' => ['txr_id'], @@ -1281,7 +1268,7 @@ For example, if a customer cancels a subscription on March 1st, but the subscrip You may determine if a user has canceled their subscription but are still on their "grace period" using the `onGracePeriod` method: if ($user->subscription('default')->onGracePeriod()) { - // + // ... } If you wish to cancel a subscription immediately, call the `cancelNow` method on the user's subscription: @@ -1341,11 +1328,11 @@ The `trialUntil` method allows you to provide a `DateTime` instance that specifi You may determine if a user is within their trial period using either the `onTrial` method of the user instance or the `onTrial` method of the subscription instance. The two examples below are equivalent: if ($user->onTrial('default')) { - // + // ... } if ($user->subscription('default')->onTrial()) { - // + // ... } You may use the `endTrial` method to immediately end a subscription trial: @@ -1355,11 +1342,11 @@ You may use the `endTrial` method to immediately end a subscription trial: To determine if an existing trial has expired, you may use the `hasExpiredTrial` methods: if ($user->hasExpiredTrial('default')) { - // + // ... } if ($user->subscription('default')->hasExpiredTrial()) { - // + // ... } @@ -1500,11 +1487,8 @@ Both events contain the full payload of the Stripe webhook. For example, if you { /** * Handle received Stripe webhooks. - * - * @param \Laravel\Cashier\Events\WebhookReceived $event - * @return void */ - public function handle(WebhookReceived $event) + public function handle(WebhookReceived $event): void { if ($event->payload['type'] === 'invoice.payment_succeeded') { // Handle the incoming event... @@ -1573,7 +1557,7 @@ The `charge` method will throw an exception if the charge fails. If the charge i try { $payment = $user->charge(100, $paymentMethod); } catch (Exception $e) { - // + // ... } > **Warning** @@ -1720,7 +1704,7 @@ From within a route or controller, you may use the `downloadInvoice` method to g use Illuminate\Http\Request; - Route::get('/user/invoice/{invoice}', function (Request $request, $invoiceId) { + Route::get('/user/invoice/{invoice}', function (Request $request, string $invoiceId) { return $request->user()->downloadInvoice($invoiceId); }); @@ -1754,11 +1738,6 @@ Cashier also makes it possible to use a custom invoice renderer. By default, Cas { /** * Render the given invoice and return the raw PDF bytes. - * - * @param \Laravel\Cashier\Invoice. $invoice - * @param array $data - * @param array $options - * @return string */ public function render(Invoice $invoice, array $data = [], array $options = []): string { @@ -1996,11 +1975,11 @@ Payment exceptions may be thrown for the following methods: `charge`, `invoiceFo Determining if an existing subscription has an incomplete payment may be accomplished using the `hasIncompletePayment` method on the billable model or a subscription instance: if ($user->hasIncompletePayment('default')) { - // + // ... } if ($user->subscription('default')->hasIncompletePayment()) { - // + // ... } You can derive the specific status of an incomplete payment by inspecting the `payment` property on the exception instance: diff --git a/blade.md b/blade.md index 62bf8956887..2368e328cbb 100644 --- a/blade.md +++ b/blade.md @@ -101,10 +101,8 @@ By default, Blade (and the Laravel `e` helper) will double encode HTML entities. { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::withoutDoubleEncoding(); } @@ -653,7 +651,7 @@ However, if you are building a package that utilizes Blade components, you will /** * Bootstrap your package's services. */ - public function boot() + public function boot(): void { Blade::component('package-alert', Alert::class); } @@ -670,10 +668,8 @@ Alternatively, you may use the `componentNamespace` method to autoload component /** * Bootstrap your package's services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade'); } @@ -720,6 +716,7 @@ You should define all of the component's data attributes in its class constructo namespace App\View\Components; use Illuminate\View\Component; + use Illuminate\View\View; class Alert extends Component { @@ -739,12 +736,8 @@ You should define all of the component's data attributes in its class constructo /** * Create the component instance. - * - * @param string $type - * @param string $message - * @return void */ - public function __construct($type, $message) + public function __construct(string $type, string $message) { $this->type = $type; $this->message = $message; @@ -752,10 +745,8 @@ You should define all of the component's data attributes in its class constructo /** * Get the view / contents that represent the component. - * - * @return \Illuminate\View\View|\Closure|string */ - public function render() + public function render(): View { return view('components.alert'); } @@ -776,11 +767,8 @@ Component constructor arguments should be specified using `camelCase`, while `ke /** * Create the component instance. - * - * @param string $alertType - * @return void */ - public function __construct($alertType) + public function __construct(string $alertType) { $this->alertType = $alertType; } @@ -830,11 +818,8 @@ In addition to public variables being available to your component template, any /** * Determine if the given option is the currently selected option. - * - * @param string $option - * @return bool */ - public function isSelected($option) + public function isSelected(string $option): bool { return $option === $this->selected; } @@ -852,12 +837,12 @@ You may execute this method from your component template by invoking the variabl Blade components also allow you to access the component name, attributes, and slot inside the class's render method. However, in order to access this data, you should return a closure from your component's `render` method. The closure will receive a `$data` array as its only argument. This array will contain several elements that provide information about the component: + use Closure; + /** * Get the view / contents that represent the component. - * - * @return \Illuminate\View\View|\Closure|string */ - public function render() + public function render(): Closure { return function (array $data) { // $data['componentName']; @@ -882,13 +867,8 @@ use App\Services\AlertCreator; /** * Create the component instance. - * - * @param \App\Services\AlertCreator $creator - * @param string $type - * @param string $message - * @return void */ -public function __construct(AlertCreator $creator, $type, $message) +public function __construct(AlertCreator $creator, string $type, string $message) { $this->creator = $creator; $this->type = $type; @@ -1032,7 +1012,7 @@ If you would like an attribute other than `class` to have its default value and You may filter attributes using the `filter` method. This method accepts a closure which should return `true` if you wish to retain the attribute in the attribute bag: ```blade -{{ $attributes->filter(fn ($value, $key) => $key == 'foo') }} +{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }} ``` For convenience, you may use the `whereStartsWith` method to retrieve all attributes whose keys begin with a given string: @@ -1191,10 +1171,8 @@ For very small components, it may feel cumbersome to manage both the component c /** * Get the view / contents that represent the component. - * - * @return \Illuminate\View\View|\Closure|string */ - public function render() + public function render(): string { return <<<'blade'
@@ -1236,10 +1214,8 @@ However, if you are building a package that utilizes Blade components or placing /** * Bootstrap your package's services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::component('package-alert', AlertComponent::class); } @@ -1258,10 +1234,8 @@ Alternatively, you may use the `componentNamespace` method to autoload component /** * Bootstrap your package's services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade'); } @@ -1390,10 +1364,8 @@ The `anonymousComponentPath` method accepts the "path" to the anonymous componen /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::anonymousComponentPath(__DIR__.'/../components'); } @@ -1740,22 +1712,18 @@ The following example creates a `@datetime($var)` directive which formats a give { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - Blade::directive('datetime', function ($expression) { + Blade::directive('datetime', function (string $expression) { return "format('m/d/Y H:i'); ?>"; }); } @@ -1780,10 +1748,8 @@ In these cases, Blade allows you to register a custom echo handler for that part /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::stringable(function (Money $money) { return $money->formatTo('en_GB'); @@ -1805,12 +1771,10 @@ Programming a custom directive is sometimes more complex than necessary when def /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - Blade::if('disk', function ($value) { + Blade::if('disk', function (string $value) { return config('filesystems.default') === $value; }); } diff --git a/broadcasting.md b/broadcasting.md index 7a5c7d5292a..84a44c1a9c3 100644 --- a/broadcasting.md +++ b/broadcasting.md @@ -281,7 +281,6 @@ When a user is viewing one of their orders, we don't want them to have to refres use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PresenceChannel; - use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Queue\SerializesModels; @@ -297,14 +296,32 @@ When a user is viewing one of their orders, we don't want them to have to refres The `ShouldBroadcast` interface requires our event to define a `broadcastOn` method. This method is responsible for returning the channels that the event should broadcast on. An empty stub of this method is already defined on generated event classes, so we only need to fill in its details. We only want the creator of the order to be able to view status updates, so we will broadcast the event on a private channel that is tied to the order: + use Illuminate\Broadcasting\Channel; + use Illuminate\Broadcasting\PrivateChannel; + + /** + * Get the channel the event should broadcast on. + */ + public function broadcastOn(): Channel + { + return new PrivateChannel('orders.'.$this->order->id); + } + +If you wish the event to broadcast on multiple channels, you may return an `array` instead: + + use Illuminate\Broadcasting\PrivateChannel; + /** * Get the channels the event should broadcast on. * - * @return \Illuminate\Broadcasting\PrivateChannel + * @return array */ - public function broadcastOn() + public function broadcastOn(): array { - return new PrivateChannel('orders.'.$this->order->id); + return [ + new PrivateChannel('orders.'.$this->order->id), + // ... + ]; } @@ -313,8 +330,9 @@ The `ShouldBroadcast` interface requires our event to define a `broadcastOn` met Remember, users must be authorized to listen on private channels. We may define our channel authorization rules in our application's `routes/channels.php` file. In this example, we need to verify that any user attempting to listen on the private `orders.1` channel is actually the creator of the order: use App\Models\Order; + use App\Models\User; - Broadcast::channel('orders.{orderId}', function ($user, $orderId) { + Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) { return $user->id === Order::findOrNew($orderId)->user_id; }); @@ -366,9 +384,6 @@ The `ShouldBroadcast` interface requires you to implement a single method: `broa /** * Create a new event instance. - * - * @param \App\Models\User $user - * @return void */ public function __construct(User $user) { @@ -378,11 +393,13 @@ The `ShouldBroadcast` interface requires you to implement a single method: `broa /** * Get the channels the event should broadcast on. * - * @return Channel|array + * @return array */ - public function broadcastOn() + public function broadcastOn(): array { - return new PrivateChannel('user.'.$this->user->id); + return [ + new PrivateChannel('user.'.$this->user->id), + ]; } } @@ -395,10 +412,8 @@ By default, Laravel will broadcast the event using the event's class name. Howev /** * The event's broadcast name. - * - * @return string */ - public function broadcastAs() + public function broadcastAs(): string { return 'server.created'; } @@ -429,9 +444,9 @@ However, if you wish to have more fine-grained control over your broadcast paylo /** * Get the data to broadcast. * - * @return array + * @return array */ - public function broadcastWith() + public function broadcastWith(): array { return ['id' => $this->user->id]; } @@ -459,10 +474,8 @@ Alternatively, you may customize the queue name by defining a `broadcastQueue` m /** * The name of the queue on which to place the broadcasting job. - * - * @return string */ - public function broadcastQueue() + public function broadcastQueue(): string { return 'default'; } @@ -475,7 +488,7 @@ If you would like to broadcast your event using the `sync` queue instead of the class OrderShipmentStatusUpdated implements ShouldBroadcastNow { - // + // ... } @@ -485,10 +498,8 @@ Sometimes you want to broadcast your event only if a given condition is true. Yo /** * Determine if this event should broadcast. - * - * @return bool */ - public function broadcastWhen() + public function broadcastWhen(): bool { return $this->order->value > 100; } @@ -578,7 +589,9 @@ window.Echo = new Echo({ Next, we need to define the logic that will actually determine if the currently authenticated user can listen to a given channel. This is done in the `routes/channels.php` file that is included with your application. In this file, you may use the `Broadcast::channel` method to register channel authorization callbacks: - Broadcast::channel('orders.{orderId}', function ($user, $orderId) { + use App\Models\User; + + Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) { return $user->id === Order::findOrNew($orderId)->user_id; }); @@ -592,8 +605,9 @@ All authorization callbacks receive the currently authenticated user as their fi Just like HTTP routes, channel routes may also take advantage of implicit and explicit [route model binding](/docs/{{version}}/routing#route-model-binding). For example, instead of receiving a string or numeric order ID, you may request an actual `Order` model instance: use App\Models\Order; + use App\Models\User; - Broadcast::channel('orders.{order}', function ($user, Order $order) { + Broadcast::channel('orders.{order}', function (User $user, Order $order) { return $user->id === $order->user_id; }); @@ -637,22 +651,16 @@ Finally, you may place the authorization logic for your channel in the channel c { /** * Create a new channel instance. - * - * @return void */ public function __construct() { - // + // ... } /** * Authenticate the user's access to the channel. - * - * @param \App\Models\User $user - * @param \App\Models\Order $order - * @return array|bool */ - public function join(User $user, Order $order) + public function join(User $user, Order $order): array|bool { return $user->id === $order->user_id; } @@ -733,8 +741,6 @@ Alternatively, you may specify the event's broadcast connection by calling the ` /** * Create a new event instance. - * - * @return void */ public function __construct() { @@ -808,7 +814,7 @@ Alternatively, you may prefix event classes with a `.` when subscribing to them ```js Echo.channel('orders') .listen('.Namespace\\Event\\Class', (e) => { - // + // ... }); ``` @@ -824,7 +830,9 @@ All presence channels are also private channels; therefore, users must be [autho The data returned by the authorization callback will be made available to the presence channel event listeners in your JavaScript application. If the user is not authorized to join the presence channel, you should return `false` or `null`: - Broadcast::channel('chat.{roomId}', function ($user, $roomId) { + use App\Models\User; + + Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) { if ($user->canJoinRoom($roomId)) { return ['id' => $user->id, 'name' => $user->name]; } @@ -838,7 +846,7 @@ To join a presence channel, you may use Echo's `join` method. The `join` method ```js Echo.join(`chat.${roomId}`) .here((users) => { - // + // ... }) .joining((user) => { console.log(user.name); @@ -861,11 +869,13 @@ Presence channels may receive events just like public or private channels. Using /** * Get the channels the event should broadcast on. * - * @return Channel|array + * @return array */ - public function broadcastOn() + public function broadcastOn(): array { - return new PresenceChannel('room.'.$this->message->room_id); + return [ + new PresenceChannel('room.'.$this->message->room_id), + ]; } As with other events, you may use the `broadcast` helper and the `toOthers` method to exclude the current user from receiving the broadcast: @@ -882,7 +892,7 @@ Echo.join(`chat.${roomId}`) .joining(/* ... */) .leaving(/* ... */) .listen('NewMessage', (e) => { - // + // ... }); ``` @@ -903,10 +913,12 @@ To get started, your Eloquent model should use the `Illuminate\Database\Eloquent namespace App\Models; +use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Database\Eloquent\BroadcastsEvents; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; class Post extends Model { @@ -915,7 +927,7 @@ class Post extends Model /** * Get the user that the post belongs to. */ - public function user() + public function user(): BelongsTo { return $this->belongsTo(User::class); } @@ -923,10 +935,9 @@ class Post extends Model /** * Get the channels that model events should broadcast on. * - * @param string $event - * @return \Illuminate\Broadcasting\Channel|array + * @return array */ - public function broadcastOn($event) + public function broadcastOn(string $event): array { return [$this, $this->user]; } @@ -941,10 +952,9 @@ In addition, you may have noticed that the `broadcastOn` method receives a strin /** * Get the channels that model events should broadcast on. * - * @param string $event - * @return \Illuminate\Broadcasting\Channel|array + * @return array> */ -public function broadcastOn($event) +public function broadcastOn(string $event): array { return match ($event) { 'deleted' => [], @@ -963,11 +973,8 @@ use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred; /** * Create a new broadcastable model event for the model. - * - * @param string $event - * @return \Illuminate\Database\Eloquent\BroadcastableModelEventOccurred */ -protected function newBroadcastableEvent($event) +protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred { return (new BroadcastableModelEventOccurred( $this, $event @@ -991,12 +998,13 @@ use Illuminate\Broadcasting\PrivateChannel; /** * Get the channels that model events should broadcast on. * - * @param string $event - * @return \Illuminate\Broadcasting\Channel|array + * @return array */ -public function broadcastOn($event) +public function broadcastOn(string $event): array { - return [new PrivateChannel('user.'.$this->id)]; + return [ + new PrivateChannel('user.'.$this->id) + ]; } ``` @@ -1038,11 +1046,8 @@ If you would like, you may define a custom broadcast name and payload by adding ```php /** * The model event's broadcast name. - * - * @param string $event - * @return string|null */ -public function broadcastAs($event) +public function broadcastAs(string $event): string|null { return match ($event) { 'created' => 'post.created', @@ -1053,10 +1058,9 @@ public function broadcastAs($event) /** * Get the data to broadcast for the model. * - * @param string $event - * @return array + * @return array */ -public function broadcastWith($event) +public function broadcastWith(string $event): array { return match ($event) { 'created' => ['title' => $this->title], diff --git a/cache.md b/cache.md index 6812e22aa6a..2654f42c92d 100644 --- a/cache.md +++ b/cache.md @@ -44,7 +44,7 @@ The cache configuration file also contains various other options, which are docu When using the `database` cache driver, you will need to set up a table to contain the cache items. You'll find an example `Schema` declaration for the table below: - Schema::create('cache', function ($table) { + Schema::create('cache', function (Blueprint $table) { $table->string('key')->unique(); $table->text('value'); $table->integer('expiration'); @@ -110,14 +110,14 @@ To obtain a cache store instance, you may use the `Cache` facade, which is what { /** * Show a list of all users of the application. - * - * @return Response */ - public function index() + public function index(): array { $value = Cache::get('key'); - // + return [ + // ... + ]; } } @@ -151,7 +151,7 @@ You may even pass a closure as the default value. The result of the closure will The `has` method may be used to determine if an item exists in the cache. This method will also return `false` if the item exists but its value is `null`: if (Cache::has('key')) { - // + // ... } @@ -311,7 +311,7 @@ In contrast, this statement would remove only cached values tagged with `authors When using the `database` cache driver, you will need to setup a table to contain your application's cache locks. You'll find an example `Schema` declaration for the table below: - Schema::create('cache_locks', function ($table) { + Schema::create('cache_locks', function (Blueprint $table) { $table->string('key')->primary(); $table->string('owner'); $table->integer('expiration'); @@ -413,7 +413,7 @@ To create our custom cache driver, we first need to implement the `Illuminate\Co We just need to implement each of these methods using a MongoDB connection. For an example of how to implement each of these methods, take a look at the `Illuminate\Cache\MemcachedStore` in the [Laravel framework source code](https://github.com/laravel/framework). Once our implementation is complete, we can finish our custom driver registration by calling the `Cache` facade's `extend` method: - Cache::extend('mongo', function ($app) { + Cache::extend('mongo', function (Application $app) { return Cache::repository(new MongoStore); }); @@ -430,6 +430,7 @@ To register the custom cache driver with Laravel, we will use the `extend` metho namespace App\Providers; use App\Extensions\MongoStore; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\Cache; use Illuminate\Support\ServiceProvider; @@ -437,13 +438,11 @@ To register the custom cache driver with Laravel, we will use the `extend` metho { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { $this->app->booting(function () { - Cache::extend('mongo', function ($app) { + Cache::extend('mongo', function (Application $app) { return Cache::repository(new MongoStore); }); }); @@ -451,12 +450,10 @@ To register the custom cache driver with Laravel, we will use the `extend` metho /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - // + // ... } } diff --git a/cashier-paddle.md b/cashier-paddle.md index af8d5bf757f..dcfb3926660 100644 --- a/cashier-paddle.md +++ b/cashier-paddle.md @@ -101,10 +101,8 @@ If you would like to prevent Cashier's migrations from running entirely, you may /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { Cashier::ignoreMigrations(); } @@ -198,10 +196,8 @@ After defining your model, you may instruct Cashier to use your custom model via /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Cashier::useReceiptModel(Receipt::class); Cashier::useSubscriptionModel(Subscription::class); @@ -448,10 +444,8 @@ Cashier allows you to define some useful defaults for your customers when creati /** * Get the customer's email address to associate with Paddle. - * - * @return string|null */ - public function paddleEmail() + public function paddleEmail(): string|null { return $this->email; } @@ -461,12 +455,11 @@ Cashier allows you to define some useful defaults for your customers when creati * * This needs to be a 2 letter code. See the link below for supported countries. * - * @return string|null * @link https://developer.paddle.com/reference/platform-parameters/supported-countries */ - public function paddleCountry() + public function paddleCountry(): string|null { - // + // ... } /** @@ -474,12 +467,11 @@ Cashier allows you to define some useful defaults for your customers when creati * * See the link below for countries which require this. * - * @return string|null * @link https://developer.paddle.com/reference/platform-parameters/supported-countries#countries-requiring-postcode */ - public function paddlePostcode() + public function paddlePostcode(): string|null { - // + // ... } These defaults will be used for every action in Cashier that generates a [pay link](#pay-links). @@ -554,7 +546,7 @@ You can also pass an array of metadata using the `withMetadata` method: Once a user is subscribed to your application, you may check their subscription status using a variety of convenient methods. First, the `subscribed` method returns `true` if the user has an active subscription, even if the subscription is currently within its trial period: if ($user->subscribed('default')) { - // + // ... } The `subscribed` method also makes a great candidate for a [route middleware](/docs/{{version}}/middleware), allowing you to filter access to routes and controllers based on the user's subscription status: @@ -564,17 +556,17 @@ The `subscribed` method also makes a great candidate for a [route middleware](/d namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; class EnsureUserIsSubscribed { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { if ($request->user() && ! $request->user()->subscribed('default')) { // This user is not a paying customer... @@ -588,25 +580,25 @@ The `subscribed` method also makes a great candidate for a [route middleware](/d If you would like to determine if a user is still within their trial period, you may use the `onTrial` method. This method can be useful for determining if you should display a warning to the user that they are still on their trial period: if ($user->subscription('default')->onTrial()) { - // + // ... } The `subscribedToPlan` method may be used to determine if the user is subscribed to a given plan based on a given Paddle plan ID. In this example, we will determine if the user's `default` subscription is actively subscribed to the monthly plan: if ($user->subscribedToPlan($monthly = 12345, 'default')) { - // + // ... } By passing an array to the `subscribedToPlan` method, you may determine if the user's `default` subscription is actively subscribed to the monthly or the yearly plan: if ($user->subscribedToPlan([$monthly = 12345, $yearly = 54321], 'default')) { - // + // ... } The `recurring` method may be used to determine if the user is currently subscribed and is no longer within their trial period: if ($user->subscription('default')->recurring()) { - // + // ... } @@ -615,19 +607,19 @@ The `recurring` method may be used to determine if the user is currently subscri To determine if the user was once an active subscriber but has cancelled their subscription, you may use the `cancelled` method: if ($user->subscription('default')->cancelled()) { - // + // ... } You may also determine if a user has cancelled their subscription, but are still on their "grace period" until the subscription fully expires. For example, if a user cancels a subscription on March 5th that was originally scheduled to expire on March 10th, the user is on their "grace period" until March 10th. Note that the `subscribed` method still returns `true` during this time: if ($user->subscription('default')->onGracePeriod()) { - // + // ... } To determine if the user has cancelled their subscription and is no longer within their "grace period", you may use the `ended` method: if ($user->subscription('default')->ended()) { - // + // ... } @@ -636,7 +628,7 @@ To determine if the user has cancelled their subscription and is no longer withi If a payment fails for a subscription, it will be marked as `past_due`. When your subscription is in this state it will not be active until the customer has updated their payment information. You may determine if a subscription is past due using the `pastDue` method on the subscription instance: if ($user->subscription('default')->pastDue()) { - // + // ... } When a subscription is past due, you should instruct the user to [update their payment information](#updating-payment-information). You may configure how past due subscriptions are handled in your [Paddle subscription settings](https://vendors.paddle.com/subscription-settings). @@ -647,10 +639,8 @@ If you would like subscriptions to still be considered active when they are `pas /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { Cashier::keepPastDueSubscriptionsActive(); } @@ -823,7 +813,7 @@ When a subscription is paused, Cashier will automatically set the `paused_from` You may determine if a user has paused their subscription but are still on their "grace period" using the `onPausedGracePeriod` method: if ($user->subscription('default')->onPausedGracePeriod()) { - // + // ... } To resume a paused a subscription, you may call the `unpause` method on the user's subscription: @@ -845,7 +835,7 @@ When a subscription is cancelled, Cashier will automatically set the `ends_at` c You may determine if a user has cancelled their subscription but are still on their "grace period" using the `onGracePeriod` method: if ($user->subscription('default')->onGracePeriod()) { - // + // ... } If you wish to cancel a subscription immediately, you may call the `cancelNow` method on the user's subscription: @@ -885,21 +875,21 @@ This method will set the trial period ending date on the subscription record wit You may determine if the user is within their trial period using either the `onTrial` method of the user instance or the `onTrial` method of the subscription instance. The two examples below are equivalent: if ($user->onTrial('default')) { - // + // ... } if ($user->subscription('default')->onTrial()) { - // + // ... } To determine if an existing trial has expired, you may use the `hasExpiredTrial` methods: if ($user->hasExpiredTrial('default')) { - // + // ... } if ($user->subscription('default')->hasExpiredTrial()) { - // + // ... } @@ -1007,11 +997,8 @@ Both events contain the full payload of the Paddle webhook. For example, if you { /** * Handle received Paddle webhooks. - * - * @param \Laravel\Paddle\Events\WebhookReceived $event - * @return void */ - public function handle(WebhookReceived $event) + public function handle(WebhookReceived $event): void { if ($event->payload['alert_name'] === 'payment_succeeded') { // Handle the incoming event... @@ -1219,11 +1206,8 @@ Alternatively, you can perform more precise customization by catching the [`subs { /** * Handle subscription payment failed. - * - * @param array $payload - * @return void */ - public function handleSubscriptionPaymentFailed($payload) + public function handleSubscriptionPaymentFailed(array $payload): void { // Handle the failed subscription payment... } diff --git a/collections.md b/collections.md index 10758e24ffe..b74a6c727c6 100644 --- a/collections.md +++ b/collections.md @@ -16,9 +16,9 @@ The `Illuminate\Support\Collection` class provides a fluent, convenient wrapper for working with arrays of data. For example, check out the following code. We'll use the `collect` helper to create a new collection instance from the array, run the `strtoupper` function on each element, and then remove all empty elements: - $collection = collect(['taylor', 'abigail', null])->map(function ($name) { + $collection = collect(['taylor', 'abigail', null])->map(function (string $name) { return strtoupper($name); - })->reject(function ($name) { + })->reject(function (string $name) { return empty($name); }); @@ -43,7 +43,7 @@ Collections are "macroable", which allows you to add additional methods to the ` use Illuminate\Support\Str; Collection::macro('toUpper', function () { - return $this->map(function ($value) { + return $this->map(function (string $value) { return Str::upper($value); }); }); @@ -64,8 +64,8 @@ If necessary, you may define macros that accept additional arguments: use Illuminate\Support\Collection; use Illuminate\Support\Facades\Lang; - Collection::macro('toLocale', function ($locale) { - return $this->map(function ($value) use ($locale) { + Collection::macro('toLocale', function (string $locale) { + return $this->map(function (string $value) use ($locale) { return Lang::get($value, [], $locale); }); }); @@ -313,7 +313,7 @@ The `chunkWhile` method breaks the collection into multiple, smaller collections $collection = collect(str_split('AABBCCCD')); - $chunks = $collection->chunkWhile(function ($value, $key, $chunk) { + $chunks = $collection->chunkWhile(function (string $value, int $key, Collection $chunk) { return $value === $chunk->last(); }); @@ -407,7 +407,7 @@ The `contains` method determines whether the collection contains a given item. Y $collection = collect([1, 2, 3, 4, 5]); - $collection->contains(function ($value, $key) { + $collection->contains(function (int $value, int $key) { return $value > 5; }); @@ -493,7 +493,7 @@ You pass a closure to the `countBy` method to count all items by a custom value: $collection = collect(['alice@gmail.com', 'bob@yahoo.com', 'carlos@gmail.com']); - $counted = $collection->countBy(function ($email) { + $counted = $collection->countBy(function (string $email) { return substr(strrchr($email, "@"), 1); }); @@ -629,7 +629,7 @@ The `doesntContain` method determines whether the collection does not contain a $collection = collect([1, 2, 3, 4, 5]); - $collection->doesntContain(function ($value, $key) { + $collection->doesntContain(function (int $value, int $key) { return $value < 5; }); @@ -713,13 +713,15 @@ This method has the same signature as the [`duplicates`](#method-duplicates) met The `each` method iterates over the items in the collection and passes each item to a closure: - $collection->each(function ($item, $key) { - // + $collection = collect([1, 2, 3, 4]); + + $collection->each(function (int $item, int $key) { + // ... }); If you would like to stop iterating through the items, you may return `false` from your closure: - $collection->each(function ($item, $key) { + $collection->each(function (int $item, int $key) { if (/* condition */) { return false; } @@ -732,13 +734,13 @@ The `eachSpread` method iterates over the collection's items, passing each neste $collection = collect([['John Doe', 35], ['Jane Doe', 33]]); - $collection->eachSpread(function ($name, $age) { - // + $collection->eachSpread(function (string $name, int $age) { + // ... }); You may stop iterating through the items by returning `false` from the callback: - $collection->eachSpread(function ($name, $age) { + $collection->eachSpread(function (string $name, int $age) { return false; }); @@ -747,7 +749,7 @@ You may stop iterating through the items by returning `false` from the callback: The `every` method may be used to verify that all elements of a collection pass a given truth test: - collect([1, 2, 3, 4])->every(function ($value, $key) { + collect([1, 2, 3, 4])->every(function (int $value, int $key) { return $value > 2; }); @@ -757,7 +759,7 @@ If the collection is empty, the `every` method will return true: $collection = collect([]); - $collection->every(function ($value, $key) { + $collection->every(function (int $value, int $key) { return $value > 2; }); @@ -788,7 +790,7 @@ The `filter` method filters the collection using the given callback, keeping onl $collection = collect([1, 2, 3, 4]); - $filtered = $collection->filter(function ($value, $key) { + $filtered = $collection->filter(function (int $value, int $key) { return $value > 2; }); @@ -811,7 +813,7 @@ For the inverse of `filter`, see the [reject](#method-reject) method. The `first` method returns the first element in the collection that passes a given truth test: - collect([1, 2, 3, 4])->first(function ($value, $key) { + collect([1, 2, 3, 4])->first(function (int $value, int $key) { return $value > 2; }); @@ -828,7 +830,7 @@ You may also call the `first` method with no arguments to get the first element The `firstOrFail` method is identical to the `first` method; however, if no result is found, an `Illuminate\Support\ItemNotFoundException` exception will be thrown: - collect([1, 2, 3, 4])->firstOrFail(function ($value, $key) { + collect([1, 2, 3, 4])->firstOrFail(function (int $value, int $key) { return $value > 5; }); @@ -879,7 +881,7 @@ The `flatMap` method iterates through the collection and passes each value to th ['age' => 28] ]); - $flattened = $collection->flatMap(function ($values) { + $flattened = $collection->flatMap(function (array $values) { return array_map('strtoupper', $values); }); @@ -1033,7 +1035,7 @@ The `groupBy` method groups the collection's items by a given key: Instead of passing a string `key`, you may pass a callback. The callback should return the value you wish to key the group by: - $grouped = $collection->groupBy(function ($item, $key) { + $grouped = $collection->groupBy(function (array $item, int $key) { return substr($item['account_id'], -3); }); @@ -1060,7 +1062,7 @@ Multiple grouping criteria may be passed as an array. Each array element will be 40 => ['user' => 4, 'skill' => 2, 'roles' => ['Role_2']], ]); - $result = $data->groupBy(['skill', function ($item) { + $result = $data->groupBy(['skill', function (array $item) { return $item['roles']; }], preserveKeys: true); @@ -1145,7 +1147,7 @@ If the collection contains simple strings or numeric values, you should pass the You may pass a closure to the `implode` method if you would like to format the values being imploded: - $collection->implode(function ($item, $key) { + $collection->implode(function (array $item, int $key) { return strtoupper($item['product']); }, ', '); @@ -1236,7 +1238,7 @@ The `keyBy` method keys the collection by the given key. If multiple items have You may also pass a callback to the method. The callback should return the value to key the collection by: - $keyed = $collection->keyBy(function ($item, $key) { + $keyed = $collection->keyBy(function (array $item, int $key) { return strtoupper($item['product_id']); }); @@ -1270,7 +1272,7 @@ The `keys` method returns all of the collection's keys: The `last` method returns the last element in the collection that passes a given truth test: - collect([1, 2, 3, 4])->last(function ($value, $key) { + collect([1, 2, 3, 4])->last(function (int $value, int $key) { return $value < 3; }); @@ -1324,7 +1326,7 @@ The `map` method iterates through the collection and passes each value to the gi $collection = collect([1, 2, 3, 4, 5]); - $multiplied = $collection->map(function ($item, $key) { + $multiplied = $collection->map(function (int $item, int $key) { return $item * 2; }); @@ -1344,9 +1346,6 @@ The `mapInto()` method iterates over the collection, creating a new instance of { /** * Create a new currency instance. - * - * @param string $code - * @return void */ function __construct(string $code) { @@ -1371,7 +1370,7 @@ The `mapSpread` method iterates over the collection's items, passing each nested $chunks = $collection->chunk(2); - $sequence = $chunks->mapSpread(function ($even, $odd) { + $sequence = $chunks->mapSpread(function (int $even, int $odd) { return $even + $odd; }); @@ -1399,7 +1398,7 @@ The `mapToGroups` method groups the collection's items by the given closure. The ] ]); - $grouped = $collection->mapToGroups(function ($item, $key) { + $grouped = $collection->mapToGroups(function (array $item, int $key) { return [$item['department'] => $item['name']]; }); @@ -1434,7 +1433,7 @@ The `mapWithKeys` method iterates through the collection and passes each value t ] ]); - $keyed = $collection->mapWithKeys(function ($item, $key) { + $keyed = $collection->mapWithKeys(function (array $item, int $key) { return [$item['email'] => $item['name']]; }); @@ -1624,7 +1623,7 @@ The `partition` method may be combined with PHP array destructuring to separate $collection = collect([1, 2, 3, 4, 5, 6]); - [$underThree, $equalOrAboveThree] = $collection->partition(function ($i) { + [$underThree, $equalOrAboveThree] = $collection->partition(function (int $i) { return $i < 3; }); @@ -1643,7 +1642,7 @@ The `pipe` method passes the collection to the given closure and returns the res $collection = collect([1, 2, 3]); - $piped = $collection->pipe(function ($collection) { + $piped = $collection->pipe(function (Collection $collection) { return $collection->sum(); }); @@ -1663,9 +1662,6 @@ The `pipeInto` method creates a new instance of the given class and passes the c /** * Create a new ResourceCollection instance. - * - * @param Collection $collection - * @return void */ public function __construct(Collection $collection) { @@ -1686,13 +1682,15 @@ The `pipeInto` method creates a new instance of the given class and passes the c The `pipeThrough` method passes the collection to the given array of closures and returns the result of the executed closures: + use Illuminate\Support\Collection; + $collection = collect([1, 2, 3]); $result = $collection->pipeThrough([ - function ($collection) { + function (Collection $collection) { return $collection->merge([4, 5]); }, - function ($collection) { + function (Collection $collection) { return $collection->sum(); }, ]); @@ -1875,7 +1873,9 @@ If the collection instance has fewer items than requested, the `random` method w The `random` method also accepts a closure, which will receive the current collection instance: - $random = $collection->random(fn ($items) => min(10, count($items))); + use Illuminate\Support\Collection; + + $random = $collection->random(fn (Collection $items) => min(10, count($items))); $random->all(); @@ -1899,7 +1899,7 @@ The `reduce` method reduces the collection to a single value, passing the result $collection = collect([1, 2, 3]); - $total = $collection->reduce(function ($carry, $item) { + $total = $collection->reduce(function (int $carry, int $item) { return $carry + $item; }); @@ -1907,7 +1907,7 @@ The `reduce` method reduces the collection to a single value, passing the result The value for `$carry` on the first iteration is `null`; however, you may specify its initial value by passing a second argument to `reduce`: - $collection->reduce(function ($carry, $item) { + $collection->reduce(function (int $carry, int $item) { return $carry + $item; }, 4); @@ -1927,7 +1927,7 @@ The `reduce` method also passes array keys in associative collections to the giv 'eur' => 1.22, ]; - $collection->reduce(function ($carry, $value, $key) use ($ratio) { + $collection->reduce(function (int $carry, int $value, int $key) use ($ratio) { return $carry + ($value * $ratio[$key]); }); @@ -1957,7 +1957,7 @@ The `reject` method filters the collection using the given closure. The closure $collection = collect([1, 2, 3, 4]); - $filtered = $collection->reject(function ($value, $key) { + $filtered = $collection->reject(function (int $value, int $key) { return $value > 2; }); @@ -2044,7 +2044,7 @@ The search is done using a "loose" comparison, meaning a string with an integer Alternatively, you may provide your own closure to search for the first item that passes a given truth test: - collect([2, 4, 6, 8])->search(function ($item, $key) { + collect([2, 4, 6, 8])->search(function (int $item, int $key) { return $item > 5; }); @@ -2110,7 +2110,7 @@ The `skipUntil` method skips over items from the collection until the given call $collection = collect([1, 2, 3, 4]); - $subset = $collection->skipUntil(function ($item) { + $subset = $collection->skipUntil(function (int $item) { return $item >= 3; }); @@ -2138,7 +2138,7 @@ The `skipWhile` method skips over items from the collection while the given call $collection = collect([1, 2, 3, 4]); - $subset = $collection->skipWhile(function ($item) { + $subset = $collection->skipWhile(function (int $item) { return $item <= 3; }); @@ -2187,7 +2187,7 @@ The `sliding` method returns a new collection of chunks representing a "sliding This is especially useful in conjunction with the [`eachSpread`](#method-eachspread) method: - $transactions->sliding(2)->eachSpread(function ($previous, $current) { + $transactions->sliding(2)->eachSpread(function (Collection $previous, Collection $current) { $current->total = $previous->total + $current->amount; }); @@ -2206,7 +2206,7 @@ You may optionally pass a second "step" value, which determines the distance bet The `sole` method returns the first element in the collection that passes a given truth test, but only if the truth test matches exactly one element: - collect([1, 2, 3, 4])->sole(function ($value, $key) { + collect([1, 2, 3, 4])->sole(function (int $value, int $key) { return $value === 2; }); @@ -2309,7 +2309,7 @@ Alternatively, you may pass your own closure to determine how to sort the collec ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], ]); - $sorted = $collection->sortBy(function ($product, $key) { + $sorted = $collection->sortBy(function (array $product, int $key) { return count($product['colors']); }); @@ -2358,8 +2358,8 @@ When sorting a collection by multiple attributes, you may also provide closures ]); $sorted = $collection->sortBy([ - fn ($a, $b) => $a['name'] <=> $b['name'], - fn ($a, $b) => $b['age'] <=> $a['age'], + fn (array $a, array $b) => $a['name'] <=> $b['name'], + fn (array $a, array $b) => $b['age'] <=> $a['age'], ]); $sorted->values()->all(); @@ -2545,7 +2545,7 @@ In addition, you may pass your own closure to determine which values of the coll ['name' => 'Bookcase', 'colors' => ['Red', 'Beige', 'Brown']], ]); - $collection->sum(function ($product) { + $collection->sum(function (array $product) { return count($product['colors']); }); @@ -2581,7 +2581,7 @@ The `takeUntil` method returns items in the collection until the given callback $collection = collect([1, 2, 3, 4]); - $subset = $collection->takeUntil(function ($item) { + $subset = $collection->takeUntil(function (int $item) { return $item >= 3; }); @@ -2609,7 +2609,7 @@ The `takeWhile` method returns items in the collection until the given callback $collection = collect([1, 2, 3, 4]); - $subset = $collection->takeWhile(function ($item) { + $subset = $collection->takeWhile(function (int $item) { return $item < 3; }); @@ -2627,7 +2627,7 @@ The `tap` method passes the collection to the given callback, allowing you to "t collect([2, 4, 3, 1, 5]) ->sort() - ->tap(function ($collection) { + ->tap(function (Collection $collection) { Log::debug('Values after sorting', $collection->values()->all()); }) ->shift(); @@ -2639,7 +2639,7 @@ The `tap` method passes the collection to the given callback, allowing you to "t The static `times` method creates a new collection by invoking the given closure a specified number of times: - $collection = Collection::times(10, function ($number) { + $collection = Collection::times(10, function (int $number) { return $number * 9; }); @@ -2683,7 +2683,7 @@ The `transform` method iterates over the collection and calls the given callback $collection = collect([1, 2, 3, 4, 5]); - $collection->transform(function ($item, $key) { + $collection->transform(function (int $item, int $key) { return $item * 2; }); @@ -2778,7 +2778,7 @@ When dealing with nested arrays or objects, you may specify the key used to dete Finally, you may also pass your own closure to the `unique` method to specify which value should determine an item's uniqueness: - $unique = $collection->unique(function ($item) { + $unique = $collection->unique(function (array $item) { return $item['brand'].$item['type']; }); @@ -2810,11 +2810,11 @@ The `unless` method will execute the given callback unless the first argument gi $collection = collect([1, 2, 3]); - $collection->unless(true, function ($collection) { + $collection->unless(true, function (Collection $collection) { return $collection->push(4); }); - $collection->unless(false, function ($collection) { + $collection->unless(false, function (Collection $collection) { return $collection->push(5); }); @@ -2826,9 +2826,9 @@ A second callback may be passed to the `unless` method. The second callback will $collection = collect([1, 2, 3]); - $collection->unless(true, function ($collection) { + $collection->unless(true, function (Collection $collection) { return $collection->push(4); - }, function ($collection) { + }, function (Collection $collection) { return $collection->push(5); }); @@ -2907,11 +2907,11 @@ The `when` method will execute the given callback when the first argument given $collection = collect([1, 2, 3]); - $collection->when(true, function ($collection, $value) { + $collection->when(true, function (Collection $collection, int $value) { return $collection->push(4); }); - $collection->when(false, function ($collection, $value) { + $collection->when(false, function (Collection $collection, int $value) { return $collection->push(5); }); @@ -2923,9 +2923,9 @@ A second callback may be passed to the `when` method. The second callback will b $collection = collect([1, 2, 3]); - $collection->when(false, function ($collection, $value) { + $collection->when(false, function (Collection $collection, int $value) { return $collection->push(4); - }, function ($collection) { + }, function (Collection $collection) { return $collection->push(5); }); @@ -2942,7 +2942,7 @@ The `whenEmpty` method will execute the given callback when the collection is em $collection = collect(['Michael', 'Tom']); - $collection->whenEmpty(function ($collection) { + $collection->whenEmpty(function (Collection $collection) { return $collection->push('Adam'); }); @@ -2953,7 +2953,7 @@ The `whenEmpty` method will execute the given callback when the collection is em $collection = collect(); - $collection->whenEmpty(function ($collection) { + $collection->whenEmpty(function (Collection $collection) { return $collection->push('Adam'); }); @@ -2965,9 +2965,9 @@ A second closure may be passed to the `whenEmpty` method that will be executed w $collection = collect(['Michael', 'Tom']); - $collection->whenEmpty(function ($collection) { + $collection->whenEmpty(function (Collection $collection) { return $collection->push('Adam'); - }, function ($collection) { + }, function (Collection $collection) { return $collection->push('Taylor'); }); @@ -2984,7 +2984,7 @@ The `whenNotEmpty` method will execute the given callback when the collection is $collection = collect(['michael', 'tom']); - $collection->whenNotEmpty(function ($collection) { + $collection->whenNotEmpty(function (Collection $collection) { return $collection->push('adam'); }); @@ -2995,7 +2995,7 @@ The `whenNotEmpty` method will execute the given callback when the collection is $collection = collect(); - $collection->whenNotEmpty(function ($collection) { + $collection->whenNotEmpty(function (Collection $collection) { return $collection->push('adam'); }); @@ -3007,9 +3007,9 @@ A second closure may be passed to the `whenNotEmpty` method that will be execute $collection = collect(); - $collection->whenNotEmpty(function ($collection) { + $collection->whenNotEmpty(function (Collection $collection) { return $collection->push('adam'); - }, function ($collection) { + }, function (Collection $collection) { return $collection->push('taylor'); }); @@ -3320,7 +3320,7 @@ For example, imagine your application needs to process a multi-gigabyte log file while (($line = fgets($handle)) !== false) { yield $line; } - })->chunk(4)->map(function ($lines) { + })->chunk(4)->map(function (array $lines) { return LogEntry::fromLines($lines); })->each(function (LogEntry $logEntry) { // Process the log entry... @@ -3330,7 +3330,7 @@ Or, imagine you need to iterate through 10,000 Eloquent models. When using tradi use App\Models\User; - $users = User::all()->filter(function ($user) { + $users = User::all()->filter(function (User $user) { return $user->id > 500; }); @@ -3338,7 +3338,7 @@ However, the query builder's `cursor` method returns a `LazyCollection` instance use App\Models\User; - $users = User::cursor()->filter(function ($user) { + $users = User::cursor()->filter(function (User $user) { return $user->id > 500; }); @@ -3510,7 +3510,7 @@ The `takeUntilTimeout` method returns a new lazy collection that will enumerate $lazyCollection = LazyCollection::times(INF) ->takeUntilTimeout(now()->addMinute()); - $lazyCollection->each(function ($number) { + $lazyCollection->each(function (int $number) { dump($number); sleep(1); @@ -3531,7 +3531,7 @@ To illustrate the usage of this method, imagine an application that submits invo ->takeUntilTimeout( Carbon::createFromTimestamp(LARAVEL_START)->add(14, 'minutes') ) - ->each(fn ($invoice) => $invoice->submit()); + ->each(fn (Invoice $invoice) => $invoice->submit()); #### `tapEach()` {.collection-method} @@ -3539,7 +3539,7 @@ To illustrate the usage of this method, imagine an application that submits invo While the `each` method calls the given callback for each item in the collection right away, the `tapEach` method only calls the given callback as the items are being pulled out of the list one by one: // Nothing has been dumped so far... - $lazyCollection = LazyCollection::times(INF)->tapEach(function ($value) { + $lazyCollection = LazyCollection::times(INF)->tapEach(function (int $value) { dump($value); }); diff --git a/console-tests.md b/console-tests.md index 2ad53ff7644..785d2aa8600 100644 --- a/console-tests.md +++ b/console-tests.md @@ -16,10 +16,8 @@ To get started, let's explore how to make assertions regarding an Artisan comman /** * Test a console command. - * - * @return void */ - public function test_console_command() + public function test_console_command(): void { $this->artisan('inspire')->assertExitCode(0); } @@ -55,10 +53,8 @@ You may test this command with the following test which utilizes the `expectsQue /** * Test a console command. - * - * @return void */ - public function test_console_command() + public function test_console_command(): void { $this->artisan('question') ->expectsQuestion('What is your name?', 'Taylor Otwell') diff --git a/container.md b/container.md index aaac9d05e96..11cab659106 100644 --- a/container.md +++ b/container.md @@ -32,6 +32,7 @@ Let's look at a simple example: use App\Http\Controllers\Controller; use App\Repositories\UserRepository; use App\Models\User; + use Illuminate\View\View; class UserController extends Controller { @@ -44,9 +45,6 @@ Let's look at a simple example: /** * Create a new controller instance. - * - * @param UserRepository $users - * @return void */ public function __construct(UserRepository $users) { @@ -55,11 +53,8 @@ Let's look at a simple example: /** * Show the profile for the given user. - * - * @param int $id - * @return Response */ - public function show($id) + public function show(string $id): View { $user = $this->users->find($id); @@ -80,7 +75,7 @@ If a class has no dependencies or only depends on other concrete classes (not in class Service { - // + // ... } Route::get('/', function (Service $service) { @@ -121,8 +116,9 @@ Within a service provider, you always have access to the container via the `$thi use App\Services\Transistor; use App\Services\PodcastParser; + use Illuminate\Contracts\Foundation\Application; - $this->app->bind(Transistor::class, function ($app) { + $this->app->bind(Transistor::class, function (Application $app) { return new Transistor($app->make(PodcastParser::class)); }); @@ -131,9 +127,10 @@ Note that we receive the container itself as an argument to the resolver. We can As mentioned, you will typically be interacting with the container within service providers; however, if you would like to interact with the container outside of a service provider, you may do so via the `App` [facade](/docs/{{version}}/facades): use App\Services\Transistor; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\App; - App::bind(Transistor::class, function ($app) { + App::bind(Transistor::class, function (Application $app) { // ... }); @@ -147,8 +144,9 @@ The `singleton` method binds a class or interface into the container that should use App\Services\Transistor; use App\Services\PodcastParser; + use Illuminate\Contracts\Foundation\Application; - $this->app->singleton(Transistor::class, function ($app) { + $this->app->singleton(Transistor::class, function (Application $app) { return new Transistor($app->make(PodcastParser::class)); }); @@ -159,8 +157,9 @@ The `scoped` method binds a class or interface into the container that should on use App\Services\Transistor; use App\Services\PodcastParser; + use Illuminate\Contracts\Foundation\Application; - $this->app->scoped(Transistor::class, function ($app) { + $this->app->scoped(Transistor::class, function (Application $app) { return new Transistor($app->make(PodcastParser::class)); }); @@ -192,9 +191,6 @@ This statement tells the container that it should inject the `RedisEventPusher` /** * Create a new class instance. - * - * @param \App\Contracts\EventPusher $pusher - * @return void */ public function __construct(EventPusher $pusher) { @@ -275,10 +271,6 @@ Occasionally, you may have a class that receives an array of typed objects using /** * Create a new class instance. - * - * @param \App\Services\Logger $logger - * @param array $filters - * @return void */ public function __construct(Logger $logger, Filter ...$filters) { @@ -291,7 +283,7 @@ Using contextual binding, you may resolve this dependency by providing the `give $this->app->when(Firewall::class) ->needs(Filter::class) - ->give(function ($app) { + ->give(function (Application $app) { return [ $app->make(NullFilter::class), $app->make(ProfanityFilter::class), @@ -324,18 +316,18 @@ Sometimes a class may have a variadic dependency that is type-hinted as a given Occasionally, you may need to resolve all of a certain "category" of binding. For example, perhaps you are building a report analyzer that receives an array of many different `Report` interface implementations. After registering the `Report` implementations, you can assign them a tag using the `tag` method: $this->app->bind(CpuReport::class, function () { - // + // ... }); $this->app->bind(MemoryReport::class, function () { - // + // ... }); $this->app->tag([CpuReport::class, MemoryReport::class], 'reports'); Once the services have been tagged, you may easily resolve them all via the container's `tagged` method: - $this->app->bind(ReportAnalyzer::class, function ($app) { + $this->app->bind(ReportAnalyzer::class, function (Application $app) { return new ReportAnalyzer($app->tagged('reports')); }); @@ -344,7 +336,7 @@ Once the services have been tagged, you may easily resolve them all via the cont The `extend` method allows the modification of resolved services. For example, when a service is resolved, you may run additional code to decorate or configure the service. The `extend` method accepts two arguments, the service class you're extending and a closure that should return the modified service. The closure receives the service being resolved and the container instance: - $this->app->extend(Service::class, function ($service, $app) { + $this->app->extend(Service::class, function (Service $service, Application $app) { return new DecoratedService($service); }); @@ -381,9 +373,6 @@ If you would like to have the Laravel container instance itself injected into a /** * Create a new class instance. - * - * @param \Illuminate\Container\Container $container - * @return void */ public function __construct(Container $container) { @@ -402,6 +391,7 @@ For example, you may type-hint a repository defined by your application in a con namespace App\Http\Controllers; use App\Repositories\UserRepository; + use App\Models\User; class UserController extends Controller { @@ -414,9 +404,6 @@ For example, you may type-hint a repository defined by your application in a con /** * Create a new controller instance. - * - * @param \App\Repositories\UserRepository $users - * @return void */ public function __construct(UserRepository $users) { @@ -425,13 +412,12 @@ For example, you may type-hint a repository defined by your application in a con /** * Show the user with the given ID. - * - * @param int $id - * @return \Illuminate\Http\Response */ - public function show($id) + public function show(string $id): User { - // + $user = $this->users->findOrFail($id); + + return $user; } } @@ -450,13 +436,12 @@ Sometimes you may wish to invoke a method on an object instance while allowing t { /** * Generate a new user report. - * - * @param \App\Repositories\UserRepository $repository - * @return array */ - public function generate(UserRepository $repository) + public function generate(UserRepository $repository): array { - // ... + return [ + // ... + ]; } } @@ -482,12 +467,13 @@ The `call` method accepts any PHP callable. The container's `call` method may ev The service container fires an event each time it resolves an object. You may listen to this event using the `resolving` method: use App\Services\Transistor; + use Illuminate\Contracts\Foundation\Application; - $this->app->resolving(Transistor::class, function ($transistor, $app) { + $this->app->resolving(Transistor::class, function (Transistor $transistor, Application $app) { // Called when container resolves objects of type "Transistor"... }); - $this->app->resolving(function ($object, $app) { + $this->app->resolving(function (mixed $object, Application $app) { // Called when container resolves object of any type... }); @@ -504,7 +490,7 @@ Laravel's service container implements the [PSR-11](https://github.com/php-fig/f Route::get('/', function (ContainerInterface $container) { $service = $container->get(Transistor::class); - // + // ... }); An exception is thrown if the given identifier can't be resolved. The exception will be an instance of `Psr\Container\NotFoundExceptionInterface` if the identifier was never bound. If the identifier was bound but was unable to be resolved, an instance of `Psr\Container\ContainerExceptionInterface` will be thrown. diff --git a/contracts.md b/contracts.md index f589cd4730e..51da8d56c8d 100644 --- a/contracts.md +++ b/contracts.md @@ -57,9 +57,6 @@ For example, take a look at this event listener: /** * Create a new event handler instance. - * - * @param \Illuminate\Contracts\Redis\Factory $redis - * @return void */ public function __construct(Factory $redis) { @@ -68,13 +65,10 @@ For example, take a look at this event listener: /** * Handle the event. - * - * @param \App\Events\OrderWasPlaced $event - * @return void */ - public function handle(OrderWasPlaced $event) + public function handle(OrderWasPlaced $event): void { - // + // ... } } diff --git a/contributions.md b/contributions.md index fbe08faf9ab..e01ad8ca642 100644 --- a/contributions.md +++ b/contributions.md @@ -113,7 +113,7 @@ Below is an example of a valid Laravel documentation block. Note that the `@para */ public function bind($abstract, $concrete = null, $shared = false) { - // + // ... } diff --git a/controllers.md b/controllers.md index 4ee0bfd8e05..77f7407a0a5 100644 --- a/controllers.md +++ b/controllers.md @@ -34,16 +34,14 @@ Let's take a look at an example of a basic controller. Note that the controller namespace App\Http\Controllers; use App\Models\User; + use Illuminate\View\View; class UserController extends Controller { /** * Show the profile for a given user. - * - * @param int $id - * @return \Illuminate\View\View */ - public function show($id) + public function show(string $id): View { return view('user.profile', [ 'user' => User::findOrFail($id) @@ -72,17 +70,18 @@ If a controller action is particularly complex, you might find it convenient to namespace App\Http\Controllers; use App\Models\User; + use Illuminate\Http\Response; class ProvisionServer extends Controller { /** * Provision a new web server. - * - * @return \Illuminate\Http\Response */ - public function __invoke() + public function __invoke(): Response { // ... + + return response()->noContent(); } } @@ -114,8 +113,6 @@ Or, you may find it convenient to specify middleware within your controller's co { /** * Instantiate a new controller instance. - * - * @return void */ public function __construct() { @@ -127,7 +124,10 @@ Or, you may find it convenient to specify middleware within your controller's co Controllers also allow you to register middleware using a closure. This provides a convenient way to define an inline middleware for a single controller without defining an entire middleware class: - $this->middleware(function ($request, $next) { + use Closure; + use Illuminate\Http\Request; + + $this->middleware(function (Request $request, Closure $next) { return $next($request); }); @@ -344,10 +344,8 @@ By default, `Route::resource` will create resource URIs using English verbs and /** * Define your route model bindings, pattern filters, etc. - * - * @return void */ - public function boot() + public function boot(): void { Route::resourceVerbs([ 'create' => 'crear', @@ -468,9 +466,6 @@ The Laravel [service container](/docs/{{version}}/container) is used to resolve /** * Create a new controller instance. - * - * @param \App\Repositories\UserRepository $users - * @return void */ public function __construct(UserRepository $users) { @@ -488,20 +483,20 @@ In addition to constructor injection, you may also type-hint dependencies on you namespace App\Http\Controllers; use Illuminate\Http\Request; + use Illuminate\Http\Response; class UserController extends Controller { /** * Store a new user. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $name = $request->name; - // + // ... + + return response()->noContent(); } } @@ -523,13 +518,11 @@ You may still type-hint the `Illuminate\Http\Request` and access your `id` param { /** * Update the given user. - * - * @param \Illuminate\Http\Request $request - * @param string $id - * @return \Illuminate\Http\Response */ - public function update(Request $request, $id) + public function update(Request $request, string $id): Response { - // + // ... + + return response()->noContent(); } } diff --git a/database-testing.md b/database-testing.md index 757d5c8ead6..8d516cd6800 100644 --- a/database-testing.md +++ b/database-testing.md @@ -30,10 +30,8 @@ Before proceeding much further, let's discuss how to reset your database after e /** * A basic functional test example. - * - * @return void */ - public function test_basic_example() + public function test_basic_example(): void { $response = $this->get('/'); @@ -54,7 +52,7 @@ To learn more about creating and utilizing model factories to create models, ple use App\Models\User; - public function test_models_can_be_instantiated() + public function test_models_can_be_instantiated(): void { $user = User::factory()->create(); @@ -82,10 +80,8 @@ If you would like to use [database seeders](/docs/{{version}}/seeding) to popula /** * Test creating a new order. - * - * @return void */ - public function test_orders_can_be_created() + public function test_orders_can_be_created(): void { // Run the DatabaseSeeder... $this->seed(); diff --git a/database.md b/database.md index 34b1579d1c2..64123d35997 100644 --- a/database.md +++ b/database.md @@ -128,15 +128,14 @@ To run a basic SELECT query, you may use the `select` method on the `DB` facade: use App\Http\Controllers\Controller; use Illuminate\Support\Facades\DB; + use Illuminate\View\View; class UserController extends Controller { /** * Show a list of all of the application's users. - * - * @return \Illuminate\Http\Response */ - public function index() + public function index(): View { $users = DB::select('select * from users where active = ?', [1]); @@ -250,6 +249,7 @@ If you would like to specify a closure that is invoked for each SQL query execut namespace App\Providers; + use Illuminate\Database\Events\QueryExecuted; use Illuminate\Support\Facades\DB; use Illuminate\Support\ServiceProvider; @@ -257,22 +257,18 @@ If you would like to specify a closure that is invoked for each SQL query execut { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - DB::listen(function ($query) { + DB::listen(function (QueryExecuted $query) { // $query->sql; // $query->bindings; // $query->time; @@ -298,20 +294,16 @@ A common performance bottleneck of modern web applications is the amount of time { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event) { // Notify development team... @@ -431,10 +423,8 @@ use Illuminate\Support\Facades\Notification; /** * Register any other events for your application. - * - * @return void */ -public function boot() +public function boot(): void { Event::listen(function (DatabaseBusy $event) { Notification::route('mail', 'dev@example.com') diff --git a/dusk.md b/dusk.md index 55db79d4d66..f42a2f13d0d 100644 --- a/dusk.md +++ b/dusk.md @@ -109,21 +109,20 @@ To get started, open your `tests/DuskTestCase.php` file, which is the base Dusk * Prepare for Dusk test execution. * * @beforeClass - * @return void */ - public static function prepare() + public static function prepare(): void { // static::startChromeDriver(); } Next, you may modify the `driver` method to connect to the URL and port of your choice. In addition, you may modify the "desired capabilities" that should be passed to the WebDriver: + use Facebook\WebDriver\Remote\RemoteWebDriver; + /** * Create the RemoteWebDriver instance. - * - * @return \Facebook\WebDriver\Remote\RemoteWebDriver */ - protected function driver() + protected function driver(): RemoteWebDriver { return RemoteWebDriver::create( 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs() @@ -197,21 +196,20 @@ By default, Dusk will automatically attempt to start ChromeDriver. If this does * Prepare for Dusk test execution. * * @beforeClass - * @return void */ - public static function prepare() + public static function prepare(): void { // static::startChromeDriver(); } In addition, if you start ChromeDriver on a port other than 9515, you should modify the `driver` method of the same class to reflect the correct port: + use Facebook\WebDriver\Remote\RemoteWebDriver; + /** * Create the RemoteWebDriver instance. - * - * @return \Facebook\WebDriver\Remote\RemoteWebDriver */ - protected function driver() + protected function driver(): RemoteWebDriver { return RemoteWebDriver::create( 'http://localhost:9515', DesiredCapabilities::chrome() @@ -239,6 +237,7 @@ To get started, let's write a test that verifies we can log into our application use App\Models\User; use Illuminate\Foundation\Testing\DatabaseMigrations; + use Laravel\Dusk\Browser; use Laravel\Dusk\Chrome; use Tests\DuskTestCase; @@ -248,16 +247,14 @@ To get started, let's write a test that verifies we can log into our application /** * A basic browser test example. - * - * @return void */ - public function test_basic_example() + public function test_basic_example(): void { $user = User::factory()->create([ 'email' => 'taylor@laravel.com', ]); - $this->browse(function ($browser) use ($user) { + $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'password') @@ -274,7 +271,7 @@ As you can see in the example above, the `browse` method accepts a closure. A br Sometimes you may need multiple browsers in order to properly carry out a test. For example, multiple browsers may be needed to test a chat screen that interacts with websockets. To create multiple browsers, simply add more browser arguments to the signature of the closure given to the `browse` method: - $this->browse(function ($first, $second) { + $this->browse(function (Browser $first, Browser $second) { $first->loginAs(User::find(1)) ->visit('/home') ->waitForText('Message'); @@ -349,12 +346,10 @@ If you would like to define a custom browser method that you can re-use in a var { /** * Register Dusk's browser macros. - * - * @return void */ - public function boot() + public function boot(): void { - Browser::macro('scrollToElement', function ($element = null) { + Browser::macro('scrollToElement', function (string $element = null) { $this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);"); return $this; @@ -364,7 +359,7 @@ If you would like to define a custom browser method that you can re-use in a var The `macro` function accepts a name as its first argument, and a closure as its second. The macro's closure will be executed when calling the macro as a method on a `Browser` instance: - $this->browse(function ($browser) use ($user) { + $this->browse(function (Browser $browser) use ($user) { $browser->visit('/pay') ->scrollToElement('#credit-card-details') ->assertSee('Enter Credit Card Details'); @@ -376,8 +371,9 @@ The `macro` function accepts a name as its first argument, and a closure as its Often, you will be testing pages that require authentication. You can use Dusk's `loginAs` method in order to avoid interacting with your application's login screen during every test. The `loginAs` method accepts a primary key associated with your authenticatable model or an authenticatable model instance: use App\Models\User; + use Laravel\Dusk\Browser; - $this->browse(function ($browser) { + $this->browse(function (Browser $browser) { $browser->loginAs(User::find(1)) ->visit('/home'); }); @@ -708,22 +704,22 @@ To close an open JavaScript dialog by clicking the "Cancel" button, you may invo Sometimes you may wish to perform several operations while scoping all of the operations within a given selector. For example, you may wish to assert that some text exists only within a table and then click a button within that table. You may use the `with` method to accomplish this. All operations performed within the closure given to the `with` method will be scoped to the original selector: - $browser->with('.table', function ($table) { + $browser->with('.table', function (Browser $table) { $table->assertSee('Hello World') ->clickLink('Delete'); }); You may occasionally need to execute assertions outside of the current scope. You may use the `elsewhere` and `elsewhereWhenAvailable` methods to accomplish this: - $browser->with('.table', function ($table) { + $browser->with('.table', function (Browser $table) { // Current scope is `body .table`... - $browser->elsewhere('.page-title', function ($title) { + $browser->elsewhere('.page-title', function (Browser $title) { // Current scope is `body .page-title`... $title->assertSee('Hello World'); }); - $browser->elsewhereWhenAvailable('.page-title', function ($title) { + $browser->elsewhereWhenAvailable('.page-title', function (Browser $title) { // Current scope is `body .page-title`... $title->assertSee('Hello World'); }); @@ -795,7 +791,7 @@ Or, you may wait until the element matching the given selector is enabled or dis Occasionally, you may wish to wait for an element to appear that matches a given selector and then interact with the element. For example, you may wish to wait until a modal window is available and then press the "OK" button within the modal. The `whenAvailable` method may be used to accomplish this. All element operations performed within the given closure will be scoped to the original selector: - $browser->whenAvailable('.modal', function ($modal) { + $browser->whenAvailable('.modal', function (Browser $modal) { $modal->assertSee('Hello World') ->press('OK'); }); @@ -904,7 +900,7 @@ The `waitForEvent` method can be used to pause the execution of a test until a J The event listener is attached to the current scope, which is the `body` element by default. When using a scoped selector, the event listener will be attached to the matching element: - $browser->with('iframe', function ($iframe) { + $browser->with('iframe', function (Browser $iframe) { // Wait for the iframe's load event... $iframe->waitForEvent('load'); }); @@ -1565,10 +1561,8 @@ You may assert on the state of the Vue component like so: /** * A basic Vue test example. - * - * @return void */ - public function testVue() + public function test_vue(): void { $this->browse(function (Browser $browser) { $browser->visit('/') @@ -1621,10 +1615,8 @@ The `url` method should return the path of the URL that represents the page. Dus /** * Get the URL for the page. - * - * @return string */ - public function url() + public function url(): string { return '/login'; } @@ -1636,10 +1628,8 @@ The `assert` method may make any assertions necessary to verify that the browser /** * Assert that the browser is on the page. - * - * @return void */ - public function assert(Browser $browser) + public function assert(Browser $browser): void { $browser->assertPathIs($this->url()); } @@ -1670,9 +1660,9 @@ The `elements` method within page classes allows you to define quick, easy-to-re /** * Get the element shortcuts for the page. * - * @return array + * @return array */ - public function elements() + public function elements(): array { return [ '@email' => 'input[name=email]', @@ -1691,9 +1681,9 @@ After installing Dusk, a base `Page` class will be placed in your `tests/Browser /** * Get the global element shortcuts for the site. * - * @return array + * @return array */ - public static function siteElements() + public static function siteElements(): array { return [ '@element' => '#selector', @@ -1717,12 +1707,8 @@ In addition to the default methods defined on pages, you may define additional m /** * Create a new playlist. - * - * @param \Laravel\Dusk\Browser $browser - * @param string $name - * @return void */ - public function createPlaylist(Browser $browser, $name) + public function createPlaylist(Browser $browser, string $name): void { $browser->type('name', $name) ->check('share') @@ -1763,21 +1749,16 @@ As shown above, a "date picker" is an example of a component that might exist th { /** * Get the root selector for the component. - * - * @return string */ - public function selector() + public function selector(): string { return '.date-picker'; } /** * Assert that the browser page contains the component. - * - * @param Browser $browser - * @return void */ - public function assert(Browser $browser) + public function assert(Browser $browser): void { $browser->assertVisible($this->selector()); } @@ -1785,9 +1766,9 @@ As shown above, a "date picker" is an example of a component that might exist th /** * Get the element shortcuts for the component. * - * @return array + * @return array */ - public function elements() + public function elements(): array { return [ '@date-field' => 'input.datepicker-input', @@ -1799,23 +1780,17 @@ As shown above, a "date picker" is an example of a component that might exist th /** * Select the given date. - * - * @param \Laravel\Dusk\Browser $browser - * @param int $year - * @param int $month - * @param int $day - * @return void */ - public function selectDate(Browser $browser, $year, $month, $day) + public function selectDate(Browser $browser, int $year, int $month, int $day): void { $browser->click('@date-field') - ->within('@year-list', function ($browser) use ($year) { + ->within('@year-list', function (Browser $browser) use ($year) { $browser->click($year); }) - ->within('@month-list', function ($browser) use ($month) { + ->within('@month-list', function (Browser $browser) use ($month) { $browser->click($month); }) - ->within('@day-list', function ($browser) use ($day) { + ->within('@day-list', function (Browser $browser) use ($day) { $browser->click($day); }); } @@ -1839,14 +1814,12 @@ Once the component has been defined, we can easily select a date within the date { /** * A basic component test example. - * - * @return void */ - public function testBasicExample() + public function test_basic_example(): void { $this->browse(function (Browser $browser) { $browser->visit('/') - ->within(new DatePicker, function ($browser) { + ->within(new DatePicker, function (Browser $browser) { $browser->selectDate(2019, 1, 30); }) ->assertSee('January'); diff --git a/eloquent-collections.md b/eloquent-collections.md index 76ef8113e64..eead73a998b 100644 --- a/eloquent-collections.md +++ b/eloquent-collections.md @@ -21,9 +21,9 @@ All collections also serve as iterators, allowing you to loop over them as if th However, as previously mentioned, collections are much more powerful than arrays and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, we may remove all inactive models and then gather the first name for each remaining user: - $names = User::all()->reject(function ($user) { + $names = User::all()->reject(function (User $user) { return $user->active === false; - })->map(function ($user) { + })->map(function (User $user) { return $user->name; }); @@ -223,6 +223,7 @@ If you would like to use a custom `Collection` object when interacting with a gi namespace App\Models; use App\Support\UserCollection; + use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; class User extends Model @@ -230,10 +231,10 @@ If you would like to use a custom `Collection` object when interacting with a gi /** * Create a new Eloquent Collection instance. * - * @param array $models - * @return \Illuminate\Database\Eloquent\Collection + * @param array $models + * @return \Illuminate\Database\Eloquent\Collection */ - public function newCollection(array $models = []) + public function newCollection(array $models = []): Collection { return new UserCollection($models); } diff --git a/eloquent-factories.md b/eloquent-factories.md index d2d88fd67bd..3b5d11b8e31 100644 --- a/eloquent-factories.md +++ b/eloquent-factories.md @@ -26,17 +26,17 @@ To see an example of how to write a factory, take a look at the `database/factor namespace Database\Factories; - use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Str; + use Illuminate\Database\Eloquent\Factories\Factory; class UserFactory extends Factory { /** * Define the model's default state. * - * @return array + * @return array */ - public function definition() + public function definition(): array { return [ 'name' => fake()->name(), @@ -76,14 +76,13 @@ Once you have defined your factories, you may use the static `factory` method pr The `HasFactory` trait's `factory` method will use conventions to determine the proper factory for the model the trait is assigned to. Specifically, the method will look for a factory in the `Database\Factories` namespace that has a class name matching the model name and is suffixed with `Factory`. If these conventions do not apply to your particular application or factory, you may overwrite the `newFactory` method on your model to return an instance of the model's corresponding factory directly: + use Illuminate\Database\Eloquent\Factories\Factory; use Database\Factories\Administration\FlightFactory; /** * Create a new factory instance for the model. - * - * @return \Illuminate\Database\Eloquent\Factories\Factory */ - protected static function newFactory() + protected static function newFactory(): Factory { return FlightFactory::new(); } @@ -110,12 +109,12 @@ State manipulation methods allow you to define discrete modifications that can b State transformation methods typically call the `state` method provided by Laravel's base factory class. The `state` method accepts a closure which will receive the array of raw attributes defined for the factory and should return an array of attributes to modify: + use Illuminate\Database\Eloquent\Factories\Factory; + /** * Indicate that the user is suspended. - * - * @return \Illuminate\Database\Eloquent\Factories\Factory */ - public function suspended() + public function suspended(): Factory { return $this->state(function (array $attributes) { return [ @@ -150,12 +149,12 @@ Factory callbacks are registered using the `afterMaking` and `afterCreating` met * * @return $this */ - public function configure() + public function configure(): static { return $this->afterMaking(function (User $user) { - // + // ... })->afterCreating(function (User $user) { - // + // ... }); } @@ -242,10 +241,12 @@ In this example, five users will be created with an `admin` value of `Y` and fiv If necessary, you may include a closure as a sequence value. The closure will be invoked each time the sequence needs a new value: + use Illuminate\Database\Eloquent\Factories\Sequence; + $users = User::factory() ->count(10) ->state(new Sequence( - fn ($sequence) => ['role' => UserRoles::all()->random()], + fn (Sequence $sequence) => ['role' => UserRoles::all()->random()], )) ->create(); @@ -253,7 +254,7 @@ Within a sequence closure, you may access the `$index` or `$count` properties on $users = User::factory() ->count(10) - ->sequence(fn ($sequence) => ['name' => 'Name '.$sequence->index]) + ->sequence(fn (Sequence $sequence) => ['name' => 'Name '.$sequence->index]) ->create(); @@ -459,9 +460,9 @@ To define a relationship within your model factory, you will typically assign a /** * Define the model's default state. * - * @return array + * @return array */ - public function definition() + public function definition(): array { return [ 'user_id' => User::factory(), @@ -475,9 +476,9 @@ If the relationship's columns depend on the factory that defines it you may assi /** * Define the model's default state. * - * @return array + * @return array */ - public function definition() + public function definition(): array { return [ 'user_id' => User::factory(), diff --git a/eloquent-mutators.md b/eloquent-mutators.md index f1dfbfd4a3a..33642f5ec5d 100644 --- a/eloquent-mutators.md +++ b/eloquent-mutators.md @@ -43,13 +43,11 @@ In this example, we'll define an accessor for the `first_name` attribute. The ac { /** * Get the user's first name. - * - * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function firstName(): Attribute { return Attribute::make( - get: fn ($value) => ucfirst($value), + get: fn (string $value) => ucfirst($value), ); } } @@ -78,13 +76,11 @@ use Illuminate\Database\Eloquent\Casts\Attribute; /** * Interact with the user's address. - * - * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function address(): Attribute { return Attribute::make( - get: fn ($value, $attributes) => new Address( + get: fn (mixed $value, array $attributes) => new Address( $attributes['address_line_one'], $attributes['address_line_two'], ), @@ -112,7 +108,7 @@ However, you may sometimes wish to enable caching for primitive values like stri protected function hash(): Attribute { return Attribute::make( - get: fn ($value) => bcrypt(gzuncompress($value)), + get: fn (string $value) => bcrypt(gzuncompress($value)), )->shouldCache(); } ``` @@ -122,13 +118,11 @@ If you would like to disable the object caching behavior of attributes, you may ```php /** * Interact with the user's address. - * - * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function address(): Attribute { return Attribute::make( - get: fn ($value, $attributes) => new Address( + get: fn (mixed $value, array $attributes) => new Address( $attributes['address_line_one'], $attributes['address_line_two'], ), @@ -152,14 +146,12 @@ A mutator transforms an Eloquent attribute value when it is set. To define a mut { /** * Interact with the user's first name. - * - * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function firstName(): Attribute { return Attribute::make( - get: fn ($value) => ucfirst($value), - set: fn ($value) => strtolower($value), + get: fn (string $value) => ucfirst($value), + set: fn (string $value) => strtolower($value), ); } } @@ -185,13 +177,11 @@ use Illuminate\Database\Eloquent\Casts\Attribute; /** * Interact with the user's address. - * - * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function address(): Attribute { return Attribute::make( - get: fn ($value, $attributes) => new Address( + get: fn (mixed $value, array $attributes) => new Address( $attributes['address_line_one'], $attributes['address_line_two'], ), @@ -260,7 +250,7 @@ After defining the cast, the `is_admin` attribute will always be cast to a boole $user = App\Models\User::find(1); if ($user->is_admin) { - // + // ... } If you need to add a new, temporary cast at runtime, you may use the `mergeCasts` method. These cast definitions will be added to any of the casts already defined on the model: @@ -397,11 +387,8 @@ You may customize the default serialization format for all of your model's dates /** * Prepare a date for array / JSON serialization. - * - * @param \DateTimeInterface $date - * @return string */ - protected function serializeDate(DateTimeInterface $date) + protected function serializeDate(DateTimeInterface $date): string { return $date->format('Y-m-d'); } @@ -501,19 +488,17 @@ All custom cast classes implement the `CastsAttributes` interface. Classes that namespace App\Casts; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; + use Illuminate\Database\Eloquent\Model; class Json implements CastsAttributes { /** * Cast the given value. * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return array + * @param array $attributes + * @return array */ - public function get($model, $key, $value, $attributes) + public function get(Model $model, string $key, mixed $value, array $attributes): array { return json_decode($value, true); } @@ -521,13 +506,9 @@ All custom cast classes implement the `CastsAttributes` interface. Classes that /** * Prepare the given value for storage. * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param array $value - * @param array $attributes - * @return string + * @param array $attributes */ - public function set($model, $key, $value, $attributes) + public function set(Model $model, string $key, mixed $value, array $attributes): string { return json_encode($value); } @@ -567,6 +548,7 @@ As an example, we will define a custom cast class that casts multiple model valu use App\ValueObjects\Address as AddressValueObject; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; + use Illuminate\Database\Eloquent\Model; use InvalidArgumentException; class Address implements CastsAttributes @@ -574,13 +556,9 @@ As an example, we will define a custom cast class that casts multiple model valu /** * Cast the given value. * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return \App\ValueObjects\Address + * @param array $attributes */ - public function get($model, $key, $value, $attributes) + public function get(Model $model, string $key, mixed $value, array $attributes): AddressValueObject { return new AddressValueObject( $attributes['address_line_one'], @@ -591,13 +569,10 @@ As an example, we will define a custom cast class that casts multiple model valu /** * Prepare the given value for storage. * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param \App\ValueObjects\Address $value - * @param array $attributes - * @return array + * @param array $attributes + * @return array */ - public function set($model, $key, $value, $attributes) + public function set(Model $model, string $key, mixed $value, array $attributes): array { if (! $value instanceof AddressValueObject) { throw new InvalidArgumentException('The given value is not an Address instance.'); @@ -633,13 +608,9 @@ Therefore, you may specify that your custom cast class will be responsible for s /** * Get the serialized representation of the value. * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return mixed + * @param array $attributes */ - public function serialize($model, string $key, $value, array $attributes) + public function serialize(Model $model, string $key, mixed $value, array $attributes): string { return (string) $value; } @@ -662,6 +633,7 @@ A classic example of an inbound only cast is a "hashing" cast. For example, we m namespace App\Casts; use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes; + use Illuminate\Database\Eloquent\Model; class Hash implements CastsInboundAttributes { @@ -674,11 +646,8 @@ A classic example of an inbound only cast is a "hashing" cast. For example, we m /** * Create a new cast class instance. - * - * @param string|null $algorithm - * @return void */ - public function __construct($algorithm = null) + public function __construct(string $algorithm = null) { $this->algorithm = $algorithm; } @@ -686,13 +655,9 @@ A classic example of an inbound only cast is a "hashing" cast. For example, we m /** * Prepare the given value for storage. * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param array $value - * @param array $attributes - * @return string + * @param array $attributes */ - public function set($model, $key, $value, $attributes) + public function set(Model $model, string $key, mixed $value, array $attributes): string { return is_null($this->algorithm) ? bcrypt($value) @@ -739,10 +704,9 @@ Objects that implement the `Castable` interface must define a `castUsing` method /** * Get the name of the caster class to use when casting from / to this cast target. * - * @param array $arguments - * @return string + * @param array $arguments */ - public static function castUsing(array $arguments) + public static function castUsing(array $arguments): string { return AddressCast::class; } @@ -767,6 +731,7 @@ By combining "castables" with PHP's [anonymous classes](https://www.php.net/manu use Illuminate\Contracts\Database\Eloquent\Castable; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; + use Illuminate\Database\Eloquent\Model; class Address implements Castable { @@ -775,14 +740,13 @@ By combining "castables" with PHP's [anonymous classes](https://www.php.net/manu /** * Get the caster class to use when casting from / to this cast target. * - * @param array $arguments - * @return object|string + * @param array $arguments */ - public static function castUsing(array $arguments) + public static function castUsing(array $arguments): CastsAttributes { return new class implements CastsAttributes { - public function get($model, $key, $value, $attributes) + public function get(Model $model, string $key, mixed $value, array $attributes): Address { return new Address( $attributes['address_line_one'], @@ -790,7 +754,7 @@ By combining "castables" with PHP's [anonymous classes](https://www.php.net/manu ); } - public function set($model, $key, $value, $attributes) + public function set(Model $model, string $key, mixed $value, array $attributes): array { return [ 'address_line_one' => $value->lineOne, diff --git a/eloquent-relationships.md b/eloquent-relationships.md index 95d66119eac..372f4e424f9 100644 --- a/eloquent-relationships.md +++ b/eloquent-relationships.md @@ -77,13 +77,14 @@ A one-to-one relationship is a very basic type of database relationship. For exa namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\HasOne; class User extends Model { /** * Get the phone associated with the user. */ - public function phone() + public function phone(): HasOne { return $this->hasOne(Phone::class); } @@ -111,13 +112,14 @@ So, we can access the `Phone` model from our `User` model. Next, let's define a namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsTo; class Phone extends Model { /** * Get the user that owns the phone. */ - public function user() + public function user(): BelongsTo { return $this->belongsTo(User::class); } @@ -130,7 +132,7 @@ Eloquent determines the foreign key name by examining the name of the relationsh /** * Get the user that owns the phone. */ - public function user() + public function user(): BelongsTo { return $this->belongsTo(User::class, 'foreign_key'); } @@ -140,7 +142,7 @@ If the parent model does not use `id` as its primary key, or you wish to find th /** * Get the user that owns the phone. */ - public function user() + public function user(): BelongsTo { return $this->belongsTo(User::class, 'foreign_key', 'owner_key'); } @@ -155,13 +157,14 @@ A one-to-many relationship is used to define relationships where a single model namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\HasMany; class Post extends Model { /** * Get the comments for the blog post. */ - public function comments() + public function comments(): HasMany { return $this->hasMany(Comment::class); } @@ -176,7 +179,7 @@ Once the relationship method has been defined, we can access the [collection](/d $comments = Post::find(1)->comments; foreach ($comments as $comment) { - // + // ... } Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the `comments` method and continuing to chain conditions onto the query: @@ -201,13 +204,14 @@ Now that we can access all of a post's comments, let's define a relationship to namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsTo; class Comment extends Model { /** * Get the post that owns the comment. */ - public function post() + public function post(): BelongsTo { return $this->belongsTo(Post::class); } @@ -230,7 +234,7 @@ However, if the foreign key for your relationship does not follow these conventi /** * Get the post that owns the comment. */ - public function post() + public function post(): BelongsTo { return $this->belongsTo(Post::class, 'foreign_key'); } @@ -240,7 +244,7 @@ If your parent model does not use `id` as its primary key, or you wish to find t /** * Get the post that owns the comment. */ - public function post() + public function post(): BelongsTo { return $this->belongsTo(Post::class, 'foreign_key', 'owner_key'); } @@ -253,7 +257,7 @@ The `belongsTo`, `hasOne`, `hasOneThrough`, and `morphOne` relationships allow y /** * Get the author of the post. */ - public function user() + public function user(): BelongsTo { return $this->belongsTo(User::class)->withDefault(); } @@ -263,7 +267,7 @@ To populate the default model with attributes, you may pass an array or closure /** * Get the author of the post. */ - public function user() + public function user(): BelongsTo { return $this->belongsTo(User::class)->withDefault([ 'name' => 'Guest Author', @@ -273,9 +277,9 @@ To populate the default model with attributes, you may pass an array or closure /** * Get the author of the post. */ - public function user() + public function user(): BelongsTo { - return $this->belongsTo(User::class)->withDefault(function ($user, $post) { + return $this->belongsTo(User::class)->withDefault(function (User $user, Post $post) { $user->name = 'Guest Author'; }); } @@ -312,7 +316,7 @@ Sometimes a model may have many related models, yet you want to easily retrieve /** * Get the user's most recent order. */ -public function latestOrder() +public function latestOrder(): HasOne { return $this->hasOne(Order::class)->latestOfMany(); } @@ -324,7 +328,7 @@ Likewise, you may define a method to retrieve the "oldest", or first, related mo /** * Get the user's oldest order. */ -public function oldestOrder() +public function oldestOrder(): HasOne { return $this->hasOne(Order::class)->oldestOfMany(); } @@ -338,7 +342,7 @@ For example, using the `ofMany` method, you may retrieve the user's most expensi /** * Get the user's largest order. */ -public function largestOrder() +public function largestOrder(): HasOne { return $this->hasOne(Order::class)->ofMany('price', 'max'); } @@ -358,12 +362,12 @@ So, in summary, we need to retrieve the latest published pricing where the publi /** * Get the current pricing for the product. */ -public function currentPricing() +public function currentPricing(): HasOne { return $this->hasOne(Price::class)->ofMany([ 'published_at' => 'max', 'id' => 'max', - ], function ($query) { + ], function (Builder $query) { $query->where('published_at', '<', now()); }); } @@ -397,13 +401,14 @@ Now that we have examined the table structure for the relationship, let's define namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\HasOneThrough; class Mechanic extends Model { /** * Get the car's owner. */ - public function carOwner() + public function carOwner(): HasOneThrough { return $this->hasOneThrough(Owner::class, Car::class); } @@ -421,7 +426,7 @@ Typical Eloquent foreign key conventions will be used when performing the relati /** * Get the car's owner. */ - public function carOwner() + public function carOwner(): HasOneThrough { return $this->hasOneThrough( Owner::class, @@ -460,13 +465,14 @@ Now that we have examined the table structure for the relationship, let's define namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\HasManyThrough; class Project extends Model { /** * Get all of the deployments for the project. */ - public function deployments() + public function deployments(): HasManyThrough { return $this->hasManyThrough(Deployment::class, Environment::class); } @@ -483,7 +489,7 @@ Typical Eloquent foreign key conventions will be used when performing the relati class Project extends Model { - public function deployments() + public function deployments(): HasOneThrough { return $this->hasManyThrough( Deployment::class, @@ -530,13 +536,14 @@ Many-to-many relationships are defined by writing a method that returns the resu namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsToMany; class User extends Model { /** * The roles that belong to the user. */ - public function roles() + public function roles(): BelongsToMany { return $this->belongsToMany(Role::class); } @@ -549,7 +556,7 @@ Once the relationship is defined, you may access the user's roles using the `rol $user = User::find(1); foreach ($user->roles as $role) { - // + // ... } Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the `roles` method and continuing to chain conditions onto the query: @@ -574,13 +581,14 @@ To define the "inverse" of a many-to-many relationship, you should define a meth namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Role extends Model { /** * The users that belong to the role. */ - public function users() + public function users(): BelongsToMany { return $this->belongsToMany(User::class); } @@ -684,13 +692,14 @@ Custom many-to-many pivot models should extend the `Illuminate\Database\Eloquent namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Role extends Model { /** * The users that belong to the role. */ - public function users() + public function users(): BelongsToMany { return $this->belongsToMany(User::class)->using(RoleUser::class); } @@ -706,7 +715,7 @@ When defining the `RoleUser` model, you should extend the `Illuminate\Database\E class RoleUser extends Pivot { - // + // ... } > **Warning** @@ -763,35 +772,42 @@ Next, let's examine the model definitions needed to build this relationship: namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphTo; class Image extends Model { /** * Get the parent imageable model (user or post). */ - public function imageable() + public function imageable(): MorphTo { return $this->morphTo(); } } + use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphOne; + class Post extends Model { /** * Get the post's image. */ - public function image() + public function image(): MorphOne { return $this->morphOne(Image::class, 'imageable'); } } + use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphOne; + class User extends Model { /** * Get the user's image. */ - public function image() + public function image(): MorphOne { return $this->morphOne(Image::class, 'imageable'); } @@ -826,7 +842,7 @@ If necessary, you may specify the name of the "id" and "type" columns utilized b /** * Get the model that the image belongs to. */ - public function imageable() + public function imageable(): MorphTo { return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id'); } @@ -865,35 +881,42 @@ Next, let's examine the model definitions needed to build this relationship: namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphTo; class Comment extends Model { /** * Get the parent commentable model (post or video). */ - public function commentable() + public function commentable(): MorphTo { return $this->morphTo(); } } + use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphMany; + class Post extends Model { /** * Get all of the post's comments. */ - public function comments() + public function comments(): MorphMany { return $this->morphMany(Comment::class, 'commentable'); } } + use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphMany; + class Video extends Model { /** * Get all of the video's comments. */ - public function comments() + public function comments(): MorphMany { return $this->morphMany(Comment::class, 'commentable'); } @@ -909,7 +932,7 @@ Once your database table and models are defined, you may access the relationship $post = Post::find(1); foreach ($post->comments as $comment) { - // + // ... } You may also retrieve the parent of a polymorphic child model by accessing the name of the method that performs the call to `morphTo`. In this case, that is the `commentable` method on the `Comment` model. So, we will access that method as a dynamic relationship property in order to access the comment's parent model: @@ -931,7 +954,7 @@ Sometimes a model may have many related models, yet you want to easily retrieve /** * Get the user's most recent image. */ -public function latestImage() +public function latestImage(): MorphOne { return $this->morphOne(Image::class, 'imageable')->latestOfMany(); } @@ -943,7 +966,7 @@ Likewise, you may define a method to retrieve the "oldest", or first, related mo /** * Get the user's oldest image. */ -public function oldestImage() +public function oldestImage(): MorphOne { return $this->morphOne(Image::class, 'imageable')->oldestOfMany(); } @@ -957,7 +980,7 @@ For example, using the `ofMany` method, you may retrieve the user's most "liked" /** * Get the user's most popular image. */ -public function bestImage() +public function bestImage(): MorphOne { return $this->morphOne(Image::class, 'imageable')->ofMany('likes', 'max'); } @@ -1006,13 +1029,14 @@ The `morphToMany` method accepts the name of the related model as well as the "r namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphToMany; class Post extends Model { /** * Get all of the tags for the post. */ - public function tags() + public function tags(): MorphToMany { return $this->morphToMany(Tag::class, 'taggable'); } @@ -1030,13 +1054,14 @@ The `morphedByMany` method accepts the name of the related model as well as the namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\MorphToMany; class Tag extends Model { /** * Get all of the posts that are assigned this tag. */ - public function posts() + public function posts(): MorphToMany { return $this->morphedByMany(Post::class, 'taggable'); } @@ -1044,7 +1069,7 @@ The `morphedByMany` method accepts the name of the related model as well as the /** * Get all of the videos that are assigned this tag. */ - public function videos() + public function videos(): MorphToMany { return $this->morphedByMany(Video::class, 'taggable'); } @@ -1060,7 +1085,7 @@ Once your database table and models are defined, you may access the relationship $post = Post::find(1); foreach ($post->tags as $tag) { - // + // ... } You may retrieve the parent of a polymorphic relation from the polymorphic child model by accessing the name of the method that performs the call to `morphedByMany`. In this case, that is the `posts` or `videos` methods on the `Tag` model: @@ -1070,11 +1095,11 @@ You may retrieve the parent of a polymorphic relation from the polymorphic child $tag = Tag::find(1); foreach ($tag->posts as $post) { - // + // ... } foreach ($tag->videos as $video) { - // + // ... } @@ -1114,7 +1139,7 @@ The `resolveRelationUsing` method accepts the desired relationship name as its f use App\Models\Order; use App\Models\Customer; - Order::resolveRelationUsing('customer', function ($orderModel) { + Order::resolveRelationUsing('customer', function (Order $orderModel) { return $orderModel->belongsTo(Customer::class, 'customer_id'); }); @@ -1133,13 +1158,14 @@ For example, imagine a blog application in which a `User` model has many associa namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\HasMany; class User extends Model { /** * Get all of the posts for the user. */ - public function posts() + public function posts(): HasMany { return $this->hasMany(Post::class); } @@ -1202,7 +1228,7 @@ If you do not need to add additional constraints to an Eloquent relationship que $user = User::find(1); foreach ($user->posts as $post) { - // + // ... } Dynamic relationship properties perform "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use [eager loading](#eager-loading) to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations. @@ -1319,7 +1345,7 @@ You may occasionally need to add query constraints based on the "type" of the re $comments = Comment::whereHasMorph( 'commentable', [Post::class, Video::class], - function (Builder $query, $type) { + function (Builder $query, string $type) { $column = $type === Post::class ? 'content' : 'title'; $query->where($column, 'like', 'code%'); @@ -1389,7 +1415,7 @@ Using the `loadCount` method, you may load a relationship count after the parent If you need to set additional query constraints on the count query, you may pass an array keyed by the relationships you wish to count. The array values should be closures which receive the query builder instance: - $book->loadCount(['reviews' => function ($query) { + $book->loadCount(['reviews' => function (Builder $query) { $query->where('rating', 5); }]) @@ -1476,13 +1502,14 @@ When accessing Eloquent relationships as properties, the related models are "laz namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsTo; class Book extends Model { /** * Get the author that wrote the book. */ - public function author() + public function author(): BelongsTo { return $this->belongsTo(Author::class); } @@ -1547,13 +1574,14 @@ If you would like to eager load a `morphTo` relationship, as well as nested rela morphTo(); } @@ -1594,6 +1622,7 @@ Sometimes you might want to always load some relationships when retrieving a mod namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsTo; class Book extends Model { @@ -1607,7 +1636,7 @@ Sometimes you might want to always load some relationships when retrieving a mod /** * Get the author that wrote the book. */ - public function author() + public function author(): BelongsTo { return $this->belongsTo(Author::class); } @@ -1615,7 +1644,7 @@ Sometimes you might want to always load some relationships when retrieving a mod /** * Get the genre of the book. */ - public function genre() + public function genre(): BelongsTo { return $this->belongsTo(Genre::class); } @@ -1636,13 +1665,13 @@ Sometimes you may wish to eager load a relationship but also specify additional use App\Models\User; - $users = User::with(['posts' => function ($query) { + $users = User::with(['posts' => function (Builder $query) { $query->where('title', 'like', '%code%'); }])->get(); In this example, Eloquent will only eager load posts where the post's `title` column contains the word `code`. You may call other [query builder](/docs/{{version}}/queries) methods to further customize the eager loading operation: - $users = User::with(['posts' => function ($query) { + $users = User::with(['posts' => function (Builder $query) { $query->orderBy('created_at', 'desc'); }])->get(); @@ -1676,8 +1705,9 @@ In this example, Eloquent will only eager load posts that have not been hidden a You may sometimes find yourself needing to check for the existence of a relationship while simultaneously loading the relationship based on the same conditions. For example, you may wish to only retrieve `User` models that have child `Post` models matching a given query condition while also eager loading the matching posts. You may accomplish this using the `withWhereHas` method: use App\Models\User; - - $users = User::withWhereHas('posts', function ($query) { + use Illuminate\Database\Eloquent\Builder; + + $users = User::withWhereHas('posts', function (Builder $query) { $query->where('featured', true); })->get(); @@ -1696,7 +1726,7 @@ Sometimes you may need to eager load a relationship after the parent model has a If you need to set additional query constraints on the eager loading query, you may pass an array keyed by the relationships you wish to load. The array values should be closure instances which receive the query instance: - $author->load(['books' => function ($query) { + $author->load(['books' => function (Builder $query) { $query->orderBy('published_date', 'asc'); }]); @@ -1714,13 +1744,14 @@ This method accepts the name of the `morphTo` relationship as its first argument morphTo(); } @@ -1750,10 +1781,8 @@ use Illuminate\Database\Eloquent\Model; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Model::preventLazyLoading(! $this->app->isProduction()); } @@ -1764,7 +1793,7 @@ After preventing lazy loading, Eloquent will throw a `Illuminate\Database\LazyLo You may customize the behavior of lazy loading violations using the `handleLazyLoadingViolationsUsing` method. For example, using this method, you may instruct lazy loading violations to only be logged instead of interrupting the application's execution with exceptions: ```php -Model::handleLazyLoadingViolationUsing(function ($model, $relation) { +Model::handleLazyLoadingViolationUsing(function (Model $model, string $relation) { $class = get_class($model); info("Attempted to lazy load [{$relation}] on model [{$class}]."); @@ -1959,6 +1988,7 @@ For example, when a `Comment` model is updated, you may want to automatically "t namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Illuminate\Database\Eloquent\Relations\BelongsTo; class Comment extends Model { @@ -1972,7 +2002,7 @@ For example, when a `Comment` model is updated, you may want to automatically "t /** * Get the post that the comment belongs to. */ - public function post() + public function post(): BelongsTo { return $this->belongsTo(Post::class); } diff --git a/eloquent-resources.md b/eloquent-resources.md index 978d7fb6737..e04d9fbafa6 100644 --- a/eloquent-resources.md +++ b/eloquent-resources.md @@ -53,6 +53,7 @@ Before diving into all of the options available to you when writing resources, l namespace App\Http\Resources; + use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class UserResource extends JsonResource @@ -60,10 +61,9 @@ Before diving into all of the options available to you when writing resources, l /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -82,7 +82,7 @@ Note that we can access model properties directly from the `$this` variable. Thi use App\Http\Resources\UserResource; use App\Models\User; - Route::get('/user/{id}', function ($id) { + Route::get('/user/{id}', function (string $id) { return new UserResource(User::findOrFail($id)); }); @@ -110,6 +110,7 @@ Once the resource collection class has been generated, you may easily define any namespace App\Http\Resources; + use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\ResourceCollection; class UserCollection extends ResourceCollection @@ -117,10 +118,9 @@ Once the resource collection class has been generated, you may easily define any /** * Transform the resource collection into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'data' => $this->collection, @@ -205,6 +205,7 @@ In essence, resources are simple. They only need to transform a given model into namespace App\Http\Resources; + use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class UserResource extends JsonResource @@ -212,10 +213,9 @@ In essence, resources are simple. They only need to transform a given model into /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -232,7 +232,7 @@ Once a resource has been defined, it may be returned directly from a route or co use App\Http\Resources\UserResource; use App\Models\User; - Route::get('/user/{id}', function ($id) { + Route::get('/user/{id}', function (string $id) { return new UserResource(User::findOrFail($id)); }); @@ -242,14 +242,14 @@ Once a resource has been defined, it may be returned directly from a route or co If you would like to include related resources in your response, you may add them to the array returned by your resource's `toArray` method. In this example, we will use the `PostResource` resource's `collection` method to add the user's blog posts to the resource response: use App\Http\Resources\PostResource; + use Illuminate\Http\Request; /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -289,10 +289,9 @@ However, if you need to customize the meta data returned with the collection, it /** * Transform the resource collection into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'data' => $this->collection, @@ -365,20 +364,16 @@ If you would like to disable the wrapping of the outermost resource, you should { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { JsonResource::withoutWrapping(); } @@ -405,10 +400,9 @@ You may be wondering if this will cause your outermost resource to be wrapped in /** * Transform the resource collection into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return ['data' => $this->collection]; } @@ -505,10 +499,9 @@ Sometimes you may wish to only include an attribute in a resource response if a /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -540,10 +533,9 @@ Sometimes you may have several attributes that should only be included in the re /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -575,10 +567,9 @@ The `whenLoaded` method may be used to conditionally load a relationship. In ord /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -604,10 +595,9 @@ The `whenCounted` method may be used to conditionally include a relationship's c /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -629,10 +619,9 @@ In addition to conditionally including relationship information in your resource /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -654,10 +643,9 @@ If your intermediate table is using an accessor other than `pivot`, you may use /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -676,10 +664,9 @@ Some JSON API standards require the addition of meta data to your resource and r /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'data' => $this->collection, @@ -707,10 +694,9 @@ Sometimes you may wish to only include certain meta data with a resource respons /** * Transform the resource collection into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return parent::toArray($request); } @@ -718,10 +704,9 @@ Sometimes you may wish to only include certain meta data with a resource respons /** * Get additional data that should be returned with the resource array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function with($request) + public function with(Request $request): array { return [ 'meta' => [ @@ -749,7 +734,7 @@ As you have already read, resources may be returned directly from routes and con use App\Http\Resources\UserResource; use App\Models\User; - Route::get('/user/{id}', function ($id) { + Route::get('/user/{id}', function (string $id) { return new UserResource(User::findOrFail($id)); }); @@ -770,6 +755,8 @@ Alternatively, you may define a `withResponse` method within the resource itself namespace App\Http\Resources; + use Illuminate\Http\JsonResponse; + use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class UserResource extends JsonResource @@ -777,10 +764,9 @@ Alternatively, you may define a `withResponse` method within the resource itself /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request - * @return array + * @return array */ - public function toArray($request) + public function toArray(Request $request): array { return [ 'id' => $this->id, @@ -789,12 +775,8 @@ Alternatively, you may define a `withResponse` method within the resource itself /** * Customize the outgoing response for the resource. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Http\Response $response - * @return void */ - public function withResponse($request, $response) + public function withResponse(Request $request, JsonResponse $response): void { $response->header('X-Value', 'True'); } diff --git a/eloquent-serialization.md b/eloquent-serialization.md index d1fabbef9d6..578fa911fc7 100644 --- a/eloquent-serialization.md +++ b/eloquent-serialization.md @@ -139,8 +139,6 @@ Occasionally, when converting models to arrays or JSON, you may wish to add attr { /** * Determine if the user is an administrator. - * - * @return \Illuminate\Database\Eloquent\Casts\Attribute */ protected function isAdmin(): Attribute { @@ -189,11 +187,8 @@ You may customize the default serialization format by overriding the `serializeD /** * Prepare a date for array / JSON serialization. - * - * @param \DateTimeInterface $date - * @return string */ - protected function serializeDate(DateTimeInterface $date) + protected function serializeDate(DateTimeInterface $date): string { return $date->format('Y-m-d'); } diff --git a/eloquent.md b/eloquent.md index d2fa4d2f1d1..ede927c60cd 100644 --- a/eloquent.md +++ b/eloquent.md @@ -119,7 +119,7 @@ Models generated by the `make:model` command will be placed in the `app/Models` class Flight extends Model { - // + // ... } @@ -228,10 +228,8 @@ You can override the UUID generation process for a given model by defining a `ne /** * Generate a new UUID for the model. - * - * @return string */ - public function newUniqueId() + public function newUniqueId(): string { return (string) Uuid::uuid4(); } @@ -239,9 +237,9 @@ You can override the UUID generation process for a given model by defining a `ne /** * Get the columns that should receive a unique identifier. * - * @return array + * @return array */ - public function uniqueIds() + public function uniqueIds(): array { return ['id', 'discount_code']; } @@ -371,10 +369,8 @@ use Illuminate\Database\Eloquent\Model; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Model::preventLazyLoading(! $this->app->isProduction()); } @@ -454,7 +450,7 @@ The Eloquent `Collection` class extends Laravel's base `Illuminate\Support\Colle ```php $flights = Flight::where('destination', 'Paris')->get(); -$flights = $flights->reject(function ($flight) { +$flights = $flights->reject(function (Flight $flight) { return $flight->cancelled; }); ``` @@ -478,10 +474,11 @@ The `chunk` method will retrieve a subset of Eloquent models, passing them to a ```php use App\Models\Flight; +use Illuminate\Database\Eloquent\Collection; -Flight::chunk(200, function ($flights) { +Flight::chunk(200, function (Collection $flights) { foreach ($flights as $flight) { - // + // ... } }); ``` @@ -492,7 +489,7 @@ If you are filtering the results of the `chunk` method based on a column that yo ```php Flight::where('departed', true) - ->chunkById(200, function ($flights) { + ->chunkById(200, function (Collection $flights) { $flights->each->update(['departed' => false]); }, $column = 'id'); ``` @@ -506,7 +503,7 @@ The `lazy` method works similarly to [the `chunk` method](#chunking-results) in use App\Models\Flight; foreach (Flight::lazy() as $flight) { - // + // ... } ``` @@ -536,7 +533,7 @@ Internally, the `cursor` method uses PHP [generators](https://www.php.net/manual use App\Models\Flight; foreach (Flight::where('destination', 'Zurich')->cursor() as $flight) { - // + // ... } ``` @@ -545,7 +542,7 @@ The `cursor` returns an `Illuminate\Support\LazyCollection` instance. [Lazy coll ```php use App\Models\User; -$users = User::cursor()->filter(function ($user) { +$users = User::cursor()->filter(function (User $user) { return $user->id > 500; }); @@ -626,7 +623,7 @@ If the `ModelNotFoundException` is not caught, a 404 HTTP response is automatica use App\Models\Flight; - Route::get('/api/flights/{id}', function ($id) { + Route::get('/api/flights/{id}', function (string $id) { return Flight::findOrFail($id); }); @@ -685,16 +682,14 @@ Of course, when using Eloquent, we don't only need to retrieve models from the d use App\Http\Controllers\Controller; use App\Models\Flight; use Illuminate\Http\Request; + use Illuminate\Http\Response; class FlightController extends Controller { /** * Store a new flight in the database. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { // Validate the request... @@ -703,6 +698,8 @@ Of course, when using Eloquent, we don't only need to retrieve models from the d $flight->name = $request->name; $flight->save(); + + return response()->noContent(); } } @@ -886,10 +883,8 @@ If you wish, you may instruct Laravel to throw an exception when attempting to f /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Model::preventSilentlyDiscardingAttributes($this->app->isLocal()); } @@ -995,7 +990,7 @@ Now, when you call the `delete` method on the model, the `deleted_at` column wil To determine if a given model instance has been soft deleted, you may use the `trashed` method: if ($flight->trashed()) { - // + // ... } @@ -1062,6 +1057,7 @@ Sometimes you may want to periodically delete models that are no longer needed. namespace App\Models; + use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Prunable; @@ -1071,10 +1067,8 @@ Sometimes you may want to periodically delete models that are no longer needed. /** * Get the prunable model query. - * - * @return \Illuminate\Database\Eloquent\Builder */ - public function prunable() + public function prunable(): Builder { return static::where('created_at', '<=', now()->subMonth()); } @@ -1084,23 +1078,18 @@ When marking models as `Prunable`, you may also define a `pruning` method on the /** * Prepare the model for pruning. - * - * @return void */ - protected function pruning() + protected function pruning(): void { - // + // ... } After configuring your prunable model, you should schedule the `model:prune` Artisan command in your application's `App\Console\Kernel` class. You are free to choose the appropriate interval at which this command should be run: /** * Define the application's command schedule. - * - * @param \Illuminate\Console\Scheduling\Schedule $schedule - * @return void */ - protected function schedule(Schedule $schedule) + protected function schedule(Schedule $schedule): void { $schedule->command('model:prune')->daily(); } @@ -1135,6 +1124,7 @@ When models are marked with the `Illuminate\Database\Eloquent\MassPrunable` trai namespace App\Models; + use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\MassPrunable; @@ -1144,10 +1134,8 @@ When models are marked with the `Illuminate\Database\Eloquent\MassPrunable` trai /** * Get the prunable model query. - * - * @return \Illuminate\Database\Eloquent\Builder */ - public function prunable() + public function prunable(): Builder { return static::where('created_at', '<=', now()->subMonth()); } @@ -1215,12 +1203,8 @@ The `Scope` interface requires you to implement one method: `apply`. The `apply` { /** * Apply the scope to a given Eloquent query builder. - * - * @param \Illuminate\Database\Eloquent\Builder $builder - * @param \Illuminate\Database\Eloquent\Model $model - * @return void */ - public function apply(Builder $builder, Model $model) + public function apply(Builder $builder, Model $model): void { $builder->where('created_at', '<', now()->subYears(2000)); } @@ -1245,10 +1229,8 @@ To assign a global scope to a model, you should override the model's `booted` me { /** * The "booted" method of the model. - * - * @return void */ - protected static function booted() + protected static function booted(): void { static::addGlobalScope(new AncientScope); } @@ -1276,10 +1258,8 @@ Eloquent also allows you to define global scopes using closures, which is partic { /** * The "booted" method of the model. - * - * @return void */ - protected static function booted() + protected static function booted(): void { static::addGlobalScope('ancient', function (Builder $builder) { $builder->where('created_at', '<', now()->subYears(2000)); @@ -1319,28 +1299,23 @@ Scopes should always return the same query builder instance or `void`: namespace App\Models; + use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * Scope a query to only include popular users. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder */ - public function scopePopular($query) + public function scopePopular(Builder $query): void { - return $query->where('votes', '>', 100); + $query->where('votes', '>', 100); } /** * Scope a query to only include active users. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return void */ - public function scopeActive($query) + public function scopeActive(Builder $query): void { $query->where('active', 1); } @@ -1380,14 +1355,10 @@ Sometimes you may wish to define a scope that accepts parameters. To get started { /** * Scope a query to only include users of a given type. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param mixed $type - * @return \Illuminate\Database\Eloquent\Builder */ - public function scopeOfType($query, $type) + public function scopeOfType(Builder $query, string $type): void { - return $query->where('type', $type); + $query->where('type', $type); } } @@ -1401,17 +1372,17 @@ Once the expected arguments have been added to your scope method's signature, yo Sometimes you may need to determine if two models are the "same" or not. The `is` and `isNot` methods may be used to quickly verify two models have the same primary key, table, and database connection or not: if ($post->is($anotherPost)) { - // + // ... } if ($post->isNot($anotherPost)) { - // + // ... } The `is` and `isNot` methods are also available when using the `belongsTo`, `hasOne`, `morphTo`, and `morphOne` [relationships](/docs/{{version}}/eloquent-relationships). This method is particularly helpful when you would like to compare a related model without issuing a query to retrieve that model: if ($post->author()->is($user)) { - // + // ... } @@ -1470,13 +1441,11 @@ Instead of using custom event classes, you may register closures that execute wh { /** * The "booted" method of the model. - * - * @return void */ - protected static function booted() + protected static function booted(): void { - static::created(function ($user) { - // + static::created(function (User $user) { + // ... }); } } @@ -1485,8 +1454,8 @@ If needed, you may utilize [queueable anonymous event listeners](/docs/{{version use function Illuminate\Events\queueable; - static::created(queueable(function ($user) { - // + static::created(queueable(function (User $user) { + // ... })); @@ -1513,57 +1482,42 @@ This command will place the new observer in your `App/Observers` directory. If t { /** * Handle the User "created" event. - * - * @param \App\Models\User $user - * @return void */ - public function created(User $user) + public function created(User $user): void { - // + // ... } /** * Handle the User "updated" event. - * - * @param \App\Models\User $user - * @return void */ - public function updated(User $user) + public function updated(User $user): void { - // + // ... } /** * Handle the User "deleted" event. - * - * @param \App\Models\User $user - * @return void */ - public function deleted(User $user) + public function deleted(User $user): void { - // + // ... } /** * Handle the User "restored" event. - * - * @param \App\Models\User $user - * @return void */ - public function restored(User $user) + public function restored(User $user): void { - // + // ... } /** * Handle the User "forceDeleted" event. - * - * @param \App\Models\User $user - * @return void */ - public function forceDeleted(User $user) + public function forceDeleted(User $user): void { - // + // ... } } @@ -1574,10 +1528,8 @@ To register an observer, you need to call the `observe` method on the model you /** * Register any events for your application. - * - * @return void */ - public function boot() + public function boot(): void { User::observe(UserObserver::class); } @@ -1621,13 +1573,10 @@ When models are being created within a database transaction, you may want to ins /** * Handle the User "created" event. - * - * @param \App\Models\User $user - * @return void */ - public function created(User $user) + public function created(User $user): void { - // + // ... } } diff --git a/encryption.md b/encryption.md index 42cc97df4d1..b46f17d074c 100644 --- a/encryption.md +++ b/encryption.md @@ -29,21 +29,21 @@ You may encrypt a value using the `encryptString` method provided by the `Crypt` use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; + use Illuminate\Http\Response; use Illuminate\Support\Facades\Crypt; class DigitalOceanTokenController extends Controller { /** * Store a DigitalOcean API token for the user. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function storeSecret(Request $request) + public function storeSecret(Request $request): Response { $request->user()->fill([ 'token' => Crypt::encryptString($request->token), ])->save(); + + return response()->noContent(); } } @@ -58,5 +58,5 @@ You may decrypt values using the `decryptString` method provided by the `Crypt` try { $decrypted = Crypt::decryptString($encryptedValue); } catch (DecryptException $e) { - // + // ... } diff --git a/errors.md b/errors.md index 60690789777..d9df978c035 100644 --- a/errors.md +++ b/errors.md @@ -37,20 +37,18 @@ For example, if you need to report different types of exceptions in different wa /** * Register the exception handling callbacks for the application. - * - * @return void */ - public function register() + public function register(): void { $this->reportable(function (InvalidOrderException $e) { - // + // ... }); } When you register a custom exception reporting callback using the `reportable` method, Laravel will still log the exception using the default logging configuration for the application. If you wish to stop the propagation of the exception to the default logging stack, you may use the `stop` method when defining your reporting callback or return `false` from the callback: $this->reportable(function (InvalidOrderException $e) { - // + // ... })->stop(); $this->reportable(function (InvalidOrderException $e) { @@ -68,9 +66,9 @@ If available, Laravel automatically adds the current user's ID to every exceptio /** * Get the default context variables for logging. * - * @return array + * @return array */ - protected function context() + protected function context(): array { return array_merge(parent::context(), [ 'foo' => 'bar', @@ -95,9 +93,9 @@ While adding context to every log message can be useful, sometimes a particular /** * Get the exception's context information. * - * @return array + * @return array */ - public function context() + public function context(): array { return ['order_id' => $this->orderId]; } @@ -108,7 +106,7 @@ While adding context to every log message can be useful, sometimes a particular Sometimes you may need to report an exception but continue handling the current request. The `report` helper function allows you to quickly report an exception via the exception handler without rendering an error page to the user: - public function isValid($value) + public function isValid(string $value): bool { try { // Validate the value... @@ -167,31 +165,29 @@ By default, the Laravel exception handler will convert exceptions into an HTTP r The closure passed to the `renderable` method should return an instance of `Illuminate\Http\Response`, which may be generated via the `response` helper. Laravel will deduce what type of exception the closure renders by examining the type-hint of the closure: use App\Exceptions\InvalidOrderException; + use Illuminate\Http\Request; /** * Register the exception handling callbacks for the application. - * - * @return void */ - public function register() + public function register(): void { - $this->renderable(function (InvalidOrderException $e, $request) { + $this->renderable(function (InvalidOrderException $e, Request $request) { return response()->view('errors.invalid-order', [], 500); }); } You may also use the `renderable` method to override the rendering behavior for built-in Laravel or Symfony exceptions such as `NotFoundHttpException`. If the closure given to the `renderable` method does not return a value, Laravel's default exception rendering will be utilized: + use Illuminate\Http\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Register the exception handling callbacks for the application. - * - * @return void */ - public function register() + public function register(): void { - $this->renderable(function (NotFoundHttpException $e, $request) { + $this->renderable(function (NotFoundHttpException $e, Request $request) { if ($request->is('api/*')) { return response()->json([ 'message' => 'Record not found.' @@ -210,26 +206,23 @@ Instead of type-checking exceptions in the exception handler's `register` method namespace App\Exceptions; use Exception; + use Illuminate\Http\Request; + use Illuminate\Http\Response; class InvalidOrderException extends Exception { /** * Report the exception. - * - * @return bool|null */ - public function report() + public function report(): void { - // + // ... } /** * Render the exception into an HTTP response. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function render($request) + public function render(Request $request): Response { return response(/* ... */); } @@ -239,13 +232,13 @@ If your exception extends an exception that is already renderable, such as a bui /** * Render the exception into an HTTP response. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function render($request) + public function render(Request $request): Response|bool { - // Determine if the exception needs custom rendering... + if (/** Determine if the exception needs custom rendering */) { + + return response(/* ... */); + } return false; } @@ -254,12 +247,15 @@ If your exception contains custom reporting logic that is only necessary when ce /** * Report the exception. - * - * @return bool|null */ - public function report() + public function report(): bool { - // Determine if the exception needs custom reporting... + if (/** Determine if the exception needs custom reporting */) { + + // ... + + return true; + } return false; } diff --git a/events.md b/events.md index 10faa6c872a..1161f461c7a 100644 --- a/events.md +++ b/events.md @@ -73,10 +73,8 @@ Typically, events should be registered via the `EventServiceProvider` `$listen` /** * Register any other events for your application. - * - * @return void */ - public function boot() + public function boot(): void { Event::listen( PodcastProcessed::class, @@ -84,7 +82,7 @@ Typically, events should be registered via the `EventServiceProvider` `$listen` ); Event::listen(function (PodcastProcessed $event) { - // + // ... }); } @@ -99,20 +97,18 @@ When registering closure based event listeners manually, you may wrap the listen /** * Register any other events for your application. - * - * @return void */ - public function boot() + public function boot(): void { Event::listen(queueable(function (PodcastProcessed $event) { - // + // ... })); } Like queued jobs, you may use the `onConnection`, `onQueue`, and `delay` methods to customize the execution of the queued listener: Event::listen(queueable(function (PodcastProcessed $event) { - // + // ... })->onConnection('redis')->onQueue('podcasts')->delay(now()->addSeconds(10))); If you would like to handle anonymous queued listener failures, you may provide a closure to the `catch` method while defining the `queueable` listener. This closure will receive the event instance and the `Throwable` instance that caused the listener's failure: @@ -123,7 +119,7 @@ If you would like to handle anonymous queued listener failures, you may provide use Throwable; Event::listen(queueable(function (PodcastProcessed $event) { - // + // ... })->catch(function (PodcastProcessed $event, Throwable $e) { // The queued listener failed... })); @@ -133,8 +129,8 @@ If you would like to handle anonymous queued listener failures, you may provide You may even register listeners using the `*` as a wildcard parameter, allowing you to catch multiple events on the same listener. Wildcard listeners receive the event name as their first argument and the entire event data array as their second argument: - Event::listen('event.*', function ($eventName, array $data) { - // + Event::listen('event.*', function (string $eventName, array $data) { + // ... }); @@ -150,13 +146,10 @@ Laravel finds event listeners by scanning the listener classes using PHP's refle { /** * Handle the given event. - * - * @param \App\Events\PodcastProcessed $event - * @return void */ - public function handle(PodcastProcessed $event) + public function handle(PodcastProcessed $event): void { - // + // ... } } @@ -164,10 +157,8 @@ Event discovery is disabled by default, but you can enable it by overriding the /** * Determine if events and listeners should be automatically discovered. - * - * @return bool */ - public function shouldDiscoverEvents() + public function shouldDiscoverEvents(): bool { return true; } @@ -177,9 +168,9 @@ By default, all listeners within your application's `app/Listeners` directory wi /** * Get the listener directories that should be used to discover events. * - * @return array + * @return array */ - protected function discoverEventsWithin() + protected function discoverEventsWithin(): array { return [ $this->app->path('Listeners'), @@ -218,9 +209,6 @@ An event class is essentially a data container which holds the information relat /** * Create a new event instance. - * - * @param \App\Models\Order $order - * @return void */ public function __construct(Order $order) { @@ -245,21 +233,16 @@ Next, let's take a look at the listener for our example event. Event listeners r { /** * Create the event listener. - * - * @return void */ public function __construct() { - // + // ... } /** * Handle the event. - * - * @param \App\Events\OrderShipped $event - * @return void */ - public function handle(OrderShipped $event) + public function handle(OrderShipped $event): void { // Access the order using $event->order... } @@ -289,7 +272,7 @@ To specify that a listener should be queued, add the `ShouldQueue` interface to class SendShipmentNotification implements ShouldQueue { - // + // ... } That's it! Now, when an event handled by this listener is dispatched, the listener will automatically be queued by the event dispatcher using Laravel's [queue system](/docs/{{version}}/queues). If no exceptions are thrown when the listener is executed by the queue, the queued job will automatically be deleted after it has finished processing. @@ -334,20 +317,16 @@ If you would like to define the listener's queue connection or queue name at run /** * Get the name of the listener's queue connection. - * - * @return string */ - public function viaConnection() + public function viaConnection(): string { return 'sqs'; } /** * Get the name of the listener's queue. - * - * @return string */ - public function viaQueue() + public function viaQueue(): string { return 'listeners'; } @@ -368,22 +347,16 @@ Sometimes, you may need to determine whether a listener should be queued based o { /** * Reward a gift card to the customer. - * - * @param \App\Events\OrderCreated $event - * @return void */ - public function handle(OrderCreated $event) + public function handle(OrderCreated $event): void { - // + // ... } /** * Determine whether the listener should be queued. - * - * @param \App\Events\OrderCreated $event - * @return bool */ - public function shouldQueue(OrderCreated $event) + public function shouldQueue(OrderCreated $event): bool { return $event->order->subtotal >= 5000; } @@ -408,11 +381,8 @@ If you need to manually access the listener's underlying queue job's `delete` an /** * Handle the event. - * - * @param \App\Events\OrderShipped $event - * @return void */ - public function handle(OrderShipped $event) + public function handle(OrderShipped $event): void { if (true) { $this->release(30); @@ -456,6 +426,7 @@ Sometimes your queued event listeners may fail. If the queued listener exceeds t use App\Events\OrderShipped; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; + use Throwable; class SendShipmentNotification implements ShouldQueue { @@ -463,25 +434,18 @@ Sometimes your queued event listeners may fail. If the queued listener exceeds t /** * Handle the event. - * - * @param \App\Events\OrderShipped $event - * @return void */ - public function handle(OrderShipped $event) + public function handle(OrderShipped $event): void { - // + // ... } /** * Handle a job failure. - * - * @param \App\Events\OrderShipped $event - * @param \Throwable $exception - * @return void */ - public function failed(OrderShipped $event, $exception) + public function failed(OrderShipped $event, Throwable $exception): void { - // + // ... } } @@ -514,12 +478,12 @@ You may define a `$tries` property on your listener class to specify how many ti As an alternative to defining how many times a listener may be attempted before it fails, you may define a time at which the listener should no longer be attempted. This allows a listener to be attempted any number of times within a given time frame. To define the time at which a listener should no longer be attempted, add a `retryUntil` method to your listener class. This method should return a `DateTime` instance: + use DateTime; + /** * Determine the time at which the listener should timeout. - * - * @return \DateTime */ - public function retryUntil() + public function retryUntil(): DateTime { return now()->addMinutes(5); } @@ -537,22 +501,22 @@ To dispatch an event, you may call the static `dispatch` method on the event. Th use App\Http\Controllers\Controller; use App\Models\Order; use Illuminate\Http\Request; + use Illuminate\Http\Response; class OrderShipmentController extends Controller { /** * Ship the given order. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $order = Order::findOrFail($request->order_id); // Order shipment logic... OrderShipped::dispatch($order); + + return response()->noContent(); } } @@ -579,26 +543,24 @@ Event subscribers are classes that may subscribe to multiple events from within use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Logout; + use Illuminate\Events\Dispatcher; class UserEventSubscriber { /** * Handle user login events. */ - public function handleUserLogin($event) {} + public function handleUserLogin(string $event): void {} /** * Handle user logout events. */ - public function handleUserLogout($event) {} + public function handleUserLogout(string $event): void {} /** * Register the listeners for the subscriber. - * - * @param \Illuminate\Events\Dispatcher $events - * @return void */ - public function subscribe($events) + public function subscribe(Dispatcher $events): void { $events->listen( Login::class, @@ -620,26 +582,26 @@ If your event listener methods are defined within the subscriber itself, you may use Illuminate\Auth\Events\Login; use Illuminate\Auth\Events\Logout; + use Illuminate\Events\Dispatcher; class UserEventSubscriber { /** * Handle user login events. */ - public function handleUserLogin($event) {} + public function handleUserLogin(string $event): void {} /** * Handle user logout events. */ - public function handleUserLogout($event) {} + public function handleUserLogout(string $event): void {} /** * Register the listeners for the subscriber. * - * @param \Illuminate\Events\Dispatcher $events - * @return array + * @return array */ - public function subscribe($events) + public function subscribe(Dispatcher $events): array { return [ Login::class => 'handleUserLogin', @@ -668,7 +630,7 @@ After writing the subscriber, you are ready to register it with the event dispat * @var array */ protected $listen = [ - // + // ... ]; /** diff --git a/facades.md b/facades.md index 0744ae0d0ed..4cb4db031c7 100644 --- a/facades.md +++ b/facades.md @@ -73,10 +73,8 @@ Using Laravel's facade testing methods, we can write the following test to verif /** * A basic functional test example. - * - * @return void */ - public function testBasicExample() + public function test_basic_example(): void { Cache::shouldReceive('get') ->with('key') @@ -108,10 +106,8 @@ The `cache` helper is going to call the `get` method on the class underlying the /** * A basic functional test example. - * - * @return void */ - public function testBasicExample() + public function test_basic_example(): void { Cache::shouldReceive('get') ->with('key') @@ -135,16 +131,14 @@ The `Facade` base class makes use of the `__callStatic()` magic-method to defer use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Cache; + use Illuminate\View\View; class UserController extends Controller { /** * Show the profile for the given user. - * - * @param int $id - * @return Response */ - public function showProfile($id) + public function showProfile(string $id): View { $user = Cache::get('user:'.$id); @@ -160,10 +154,11 @@ If we look at that `Illuminate\Support\Facades\Cache` class, you'll see that the { /** * Get the registered name of the component. - * - * @return string */ - protected static function getFacadeAccessor() { return 'cache'; } + protected static function getFacadeAccessor(): string + { + return 'cache'; + } } Instead, the `Cache` facade extends the base `Facade` class and defines the method `getFacadeAccessor()`. This method's job is to return the name of a service container binding. When a user references any static method on the `Cache` facade, Laravel resolves the `cache` binding from the [service container](/docs/{{version}}/container) and runs the requested method (in this case, `get`) against that object. @@ -184,11 +179,8 @@ Using real-time facades, you may treat any class in your application as if it wa { /** * Publish the podcast. - * - * @param Publisher $publisher - * @return void */ - public function publish(Publisher $publisher) + public function publish(Publisher $publisher): void { $this->update(['publishing' => now()]); @@ -209,10 +201,8 @@ Injecting a publisher implementation into the method allows us to easily test th { /** * Publish the podcast. - * - * @return void */ - public function publish() + public function publish(): void { $this->update(['publishing' => now()]); @@ -237,10 +227,8 @@ When the real-time facade is used, the publisher implementation will be resolved /** * A test example. - * - * @return void */ - public function test_podcast_can_be_published() + public function test_podcast_can_be_published(): void { $podcast = Podcast::factory()->create(); diff --git a/filesystem.md b/filesystem.md index c82b29ffe40..2ac2cb80c01 100644 --- a/filesystem.md +++ b/filesystem.md @@ -286,6 +286,7 @@ If you need to customize how temporary URLs are created for a specific storage d namespace App\Providers; + use DateTime; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; @@ -294,12 +295,10 @@ If you need to customize how temporary URLs are created for a specific storage d { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - Storage::disk('local')->buildTemporaryUrlsUsing(function ($path, $expiration, $options) { + Storage::disk('local')->buildTemporaryUrlsUsing(function (string $path, DateTime $expiration, array $options) { return URL::temporarySignedRoute( 'files.download', $expiration, @@ -425,11 +424,8 @@ In web applications, one of the most common use-cases for storing files is stori { /** * Update the avatar for the user. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function update(Request $request) + public function update(Request $request): string { $path = $request->file('avatar')->store('avatars'); @@ -613,6 +609,7 @@ Next, you can register the driver within the `boot` method of one of your applic namespace App\Providers; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Support\Facades\Storage; use Illuminate\Support\ServiceProvider; @@ -624,22 +621,18 @@ Next, you can register the driver within the `boot` method of one of your applic { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - Storage::extend('dropbox', function ($app, $config) { + Storage::extend('dropbox', function (Application $app, array $config) { $adapter = new DropboxAdapter(new DropboxClient( $config['authorization_token'] )); diff --git a/fortify.md b/fortify.md index f811d79bc97..ddb88916361 100644 --- a/fortify.md +++ b/fortify.md @@ -134,10 +134,8 @@ All of the authentication view's rendering logic may be customized using the app /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Fortify::loginView(function () { return view('auth.login'); @@ -167,10 +165,8 @@ use Laravel\Fortify\Fortify; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Fortify::authenticateUsing(function (Request $request) { $user = User::where('email', $request->email)->first(); @@ -226,16 +222,16 @@ If you need advanced customization of this behavior, you may bind implementation ```php use Laravel\Fortify\Contracts\LogoutResponse; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; /** * Register any application services. - * - * @return void */ -public function register() +public function register(): void { $this->app->instance(LogoutResponse::class, new class implements LogoutResponse { - public function toResponse($request) + public function toResponse(Request $request): RedirectResponse { return redirect('/'); } @@ -334,10 +330,8 @@ use Laravel\Fortify\Fortify; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Fortify::twoFactorChallengeView(function () { return view('auth.two-factor-challenge'); @@ -370,10 +364,8 @@ use Laravel\Fortify\Fortify; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Fortify::registerView(function () { return view('auth.register'); @@ -411,10 +403,8 @@ use Laravel\Fortify\Fortify; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Fortify::requestPasswordResetLinkView(function () { return view('auth.forgot-password'); @@ -454,15 +444,14 @@ All of Fortify's view rendering logic may be customized using the appropriate me ```php use Laravel\Fortify\Fortify; +use Illuminate\Http\Request; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { - Fortify::resetPasswordView(function ($request) { + Fortify::resetPasswordView(function (Request $request) { return view('auth.reset-password', ['request' => $request]); }); @@ -510,10 +499,8 @@ use Laravel\Fortify\Fortify; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Fortify::verifyEmailView(function () { return view('auth.verify-email'); @@ -567,10 +554,8 @@ use Laravel\Fortify\Fortify; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Fortify::confirmPasswordView(function () { return view('auth.confirm-password'); diff --git a/frontend.md b/frontend.md index 50174564a90..cce5b1a053f 100644 --- a/frontend.md +++ b/frontend.md @@ -128,16 +128,14 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Models\User; use Inertia\Inertia; +use Inertia\Response; class UserController extends Controller { /** * Show the profile for a given user. - * - * @param int $id - * @return \Inertia\Response */ - public function show($id) + public function show(string $id): Response { return Inertia::render('Users/Profile', [ 'user' => User::findOrFail($id) diff --git a/hashing.md b/hashing.md index d3f278d254f..91c5109c1f5 100644 --- a/hashing.md +++ b/hashing.md @@ -33,23 +33,23 @@ You may hash a password by calling the `make` method on the `Hash` facade: use App\Http\Controllers\Controller; use Illuminate\Http\Request; + use Illuminate\Http\Response; use Illuminate\Support\Facades\Hash; class PasswordController extends Controller { /** * Update the password for the user. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function update(Request $request) + public function update(Request $request): Response { // Validate the new password length... $request->user()->fill([ 'password' => Hash::make($request->newPassword) ])->save(); + + return response()->noContent(); } } diff --git a/helpers.md b/helpers.md index ef6082f0930..4e4ce7f7752 100644 --- a/helpers.md +++ b/helpers.md @@ -502,7 +502,7 @@ The `Arr::first` method returns the first element of an array passing a given tr $array = [100, 200, 300]; - $first = Arr::first($array, function ($value, $key) { + $first = Arr::first($array, function (int $value, int $key) { return $value >= 150; }); @@ -676,7 +676,7 @@ The `Arr::last` method returns the last element of an array passing a given trut $array = [100, 200, 300, 110]; - $last = Arr::last($array, function ($value, $key) { + $last = Arr::last($array, function (int $value, int $key) { return $value >= 150; }); @@ -697,7 +697,7 @@ The `Arr::map` method iterates through the array and passes each value and key t $array = ['first' => 'james', 'last' => 'kirk']; - $mapped = Arr::map($array, function ($value, $key) { + $mapped = Arr::map($array, function (string $value, string $key) { return ucfirst($value); }); @@ -892,7 +892,7 @@ You may also sort the array by the results of a given closure: ['name' => 'Chair'], ]; - $sorted = array_values(Arr::sort($array, function ($value) { + $sorted = array_values(Arr::sort($array, function (array $value) { return $value['name']; })); @@ -972,7 +972,7 @@ The `Arr::where` method filters an array using the given closure: $array = [100, '200', 300, '400', 500]; - $filtered = Arr::where($array, function ($value, $key) { + $filtered = Arr::where($array, function (string|int $value, int $key) { return is_string($value); }); @@ -2727,12 +2727,13 @@ The `padRight` method wraps PHP's `str_pad` function, padding the right side of The `pipe` method allows you to transform the string by passing its current value to the given callable: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; $hash = Str::of('Laravel')->pipe('md5')->prepend('Checksum: '); // 'Checksum: a5c95b86291ea299fcbe64458ed12702' - $closure = Str::of('foo')->pipe(function ($str) { + $closure = Str::of('foo')->pipe(function (Stringable $str) { return 'bar'; }); @@ -2849,8 +2850,9 @@ The `replaceMatches` method replaces all portions of a string matching a pattern The `replaceMatches` method also accepts a closure that will be invoked with each portion of the string matching the given pattern, allowing you to perform the replacement logic within the closure and return the replaced value: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $replaced = Str::of('123')->replaceMatches('/\d/', function ($match) { + $replaced = Str::of('123')->replaceMatches('/\d/', function (Stringable $match) { return '['.$match[0].']'; }); @@ -3029,10 +3031,11 @@ The `swap` method replaces multiple values in the string using PHP's `strtr` fun The `tap` method passes the string to the given closure, allowing you to examine and interact with the string while not affecting the string itself. The original string is returned by the `tap` method regardless of what is returned by the closure: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; $string = Str::of('Laravel') ->append(' Framework') - ->tap(function ($string) { + ->tap(function (Stringable $string) { dump('String after append: '.$string); }) ->upper(); @@ -3115,9 +3118,10 @@ The `upper` method converts the given string to uppercase: The `when` method invokes the given closure if a given condition is `true`. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; $string = Str::of('Taylor') - ->when(true, function ($string) { + ->when(true, function (Stringable $string) { return $string->append(' Otwell'); }); @@ -3131,9 +3135,10 @@ If necessary, you may pass another closure as the third parameter to the `when` The `whenContains` method invokes the given closure if the string contains the given value. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; $string = Str::of('tony stark') - ->whenContains('tony', function ($string) { + ->whenContains('tony', function (Stringable $string) { return $string->title(); }); @@ -3144,9 +3149,10 @@ If necessary, you may pass another closure as the third parameter to the `when` You may also pass an array of values to determine if the given string contains any of the values in the array: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; $string = Str::of('tony stark') - ->whenContains(['tony', 'hulk'], function ($string) { + ->whenContains(['tony', 'hulk'], function (Stringable $string) { return $string->title(); }); @@ -3158,9 +3164,10 @@ You may also pass an array of values to determine if the given string contains a The `whenContainsAll` method invokes the given closure if the string contains all of the given sub-strings. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; $string = Str::of('tony stark') - ->whenContainsAll(['tony', 'stark'], function ($string) { + ->whenContainsAll(['tony', 'stark'], function (Stringable $string) { return $string->title(); }); @@ -3174,8 +3181,9 @@ If necessary, you may pass another closure as the third parameter to the `when` The `whenEmpty` method invokes the given closure if the string is empty. If the closure returns a value, that value will also be returned by the `whenEmpty` method. If the closure does not return a value, the fluent string instance will be returned: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of(' ')->whenEmpty(function ($string) { + $string = Str::of(' ')->whenEmpty(function (Stringable $string) { return $string->trim()->prepend('Laravel'); }); @@ -3187,8 +3195,9 @@ The `whenEmpty` method invokes the given closure if the string is empty. If the The `whenNotEmpty` method invokes the given closure if the string is not empty. If the closure returns a value, that value will also be returned by the `whenNotEmpty` method. If the closure does not return a value, the fluent string instance will be returned: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('Framework')->whenNotEmpty(function ($string) { + $string = Str::of('Framework')->whenNotEmpty(function (Stringable $string) { return $string->prepend('Laravel '); }); @@ -3200,8 +3209,9 @@ The `whenNotEmpty` method invokes the given closure if the string is not empty. The `whenStartsWith` method invokes the given closure if the string starts with the given sub-string. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('disney world')->whenStartsWith('disney', function ($string) { + $string = Str::of('disney world')->whenStartsWith('disney', function (Stringable $string) { return $string->title(); }); @@ -3213,8 +3223,9 @@ The `whenStartsWith` method invokes the given closure if the string starts with The `whenEndsWith` method invokes the given closure if the string ends with the given sub-string. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('disney world')->whenEndsWith('world', function ($string) { + $string = Str::of('disney world')->whenEndsWith('world', function (Stringable $string) { return $string->title(); }); @@ -3226,8 +3237,9 @@ The `whenEndsWith` method invokes the given closure if the string ends with the The `whenExactly` method invokes the given closure if the string exactly matches the given string. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('laravel')->whenExactly('laravel', function ($string) { + $string = Str::of('laravel')->whenExactly('laravel', function (Stringable $string) { return $string->title(); }); @@ -3239,8 +3251,9 @@ The `whenExactly` method invokes the given closure if the string exactly matches The `whenNotExactly` method invokes the given closure if the string does not exactly match the given string. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('framework')->whenNotExactly('laravel', function ($string) { + $string = Str::of('framework')->whenNotExactly('laravel', function (Stringable $string) { return $string->title(); }); @@ -3252,8 +3265,9 @@ The `whenNotExactly` method invokes the given closure if the string does not exa The `whenIs` method invokes the given closure if the string matches a given pattern. Asterisks may be used as wildcard values. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('foo/bar')->whenIs('foo/*', function ($string) { + $string = Str::of('foo/bar')->whenIs('foo/*', function (Stringable $string) { return $string->append('/baz'); }); @@ -3265,8 +3279,9 @@ The `whenIs` method invokes the given closure if the string matches a given patt The `whenIsAscii` method invokes the given closure if the string is 7 bit ASCII. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('laravel')->whenIsAscii(function ($string) { + $string = Str::of('laravel')->whenIsAscii(function (Stringable $string) { return $string->title(); }); @@ -3279,7 +3294,7 @@ The `whenIsUlid` method invokes the given closure if the string is a valid ULID. use Illuminate\Support\Str; - $string = Str::of('01gd6r360bp37zj17nxb55yv40')->whenIsUlid(function ($string) { + $string = Str::of('01gd6r360bp37zj17nxb55yv40')->whenIsUlid(function (Stringable $string) { return $string->substr(0, 8); }); @@ -3291,8 +3306,9 @@ The `whenIsUlid` method invokes the given closure if the string is a valid ULID. The `whenIsUuid` method invokes the given closure if the string is a valid UUID. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('a0a2a2d2-0b87-4a18-83f2-2529882be2de')->whenIsUuid(function ($string) { + $string = Str::of('a0a2a2d2-0b87-4a18-83f2-2529882be2de')->whenIsUuid(function (Stringable $string) { return $string->substr(0, 8); }); @@ -3304,8 +3320,9 @@ The `whenIsUuid` method invokes the given closure if the string is a valid UUID. The `whenTest` method invokes the given closure if the string matches the given regular expression. The closure will receive the fluent string instance: use Illuminate\Support\Str; + use Illuminate\Support\Stringable; - $string = Str::of('laravel framework')->whenTest('/laravel/', function ($string) { + $string = Str::of('laravel framework')->whenTest('/laravel/', function (Stringable $string) { return $string->title(); }); @@ -3756,7 +3773,7 @@ The `optional` function accepts any argument and allows you to access properties The `optional` function also accepts a closure as its second argument. The closure will be invoked if the value provided as the first argument is not null: - return optional(User::find($id), function ($user) { + return optional(User::find($id), function (User $user) { return $user->name; }); @@ -3864,9 +3881,11 @@ The `retry` function attempts to execute the given callback until the given maxi If you would like to manually calculate the number of milliseconds to sleep between attempts, you may pass a closure as the third argument to the `retry` function: + use Exception; + return retry(5, function () { // ... - }, function ($attempt, $exception) { + }, function (int $attempt, Exception $exception) { return $attempt * 100; }); @@ -3878,9 +3897,11 @@ For convenience, you may provide an array as the first argument to the `retry` f To only retry under specific conditions, you may pass a closure as the fourth argument to the `retry` function: + use Exception; + return retry(5, function () { // ... - }, 100, function ($exception) { + }, 100, function (Exception $exception) { return $exception instanceof RetryException; }); @@ -3906,7 +3927,7 @@ The session store will be returned if no value is passed to the function: The `tap` function accepts two arguments: an arbitrary `$value` and a closure. The `$value` will be passed to the closure and then be returned by the `tap` function. The return value of the closure is irrelevant: - $user = tap(User::first(), function ($user) { + $user = tap(User::first(), function (User $user) { $user->name = 'taylor'; $user->save(); @@ -3921,8 +3942,8 @@ If no closure is passed to the `tap` function, you may call any method on the gi To add a `tap` method to a class, you may add the `Illuminate\Support\Traits\Tappable` trait to the class. The `tap` method of this trait accepts a Closure as its only argument. The object instance itself will be passed to the Closure and then be returned by the `tap` method: - return $user->tap(function ($user) { - // + return $user->tap(function (User $user) { + // ... }); @@ -3970,7 +3991,7 @@ The `trait_uses_recursive` function returns all traits used by a trait: The `transform` function executes a closure on a given value if the value is not [blank](#method-blank) and then returns the return value of the closure: - $callback = function ($value) { + $callback = function (int $value) { return $value * 2; }; @@ -4018,7 +4039,7 @@ The `view` function retrieves a [view](/docs/{{version}}/views) instance: The `with` function returns the value it is given. If a closure is passed as the second argument to the function, the closure will be executed and its returned value will be returned: - $callback = function ($value) { + $callback = function (mixed $value) { return is_numeric($value) ? $value * 2 : 0; }; diff --git a/horizon.md b/horizon.md index b83ee868230..b94d401718d 100644 --- a/horizon.md +++ b/horizon.md @@ -129,12 +129,10 @@ Horizon exposes a dashboard at the `/horizon` URI. By default, you will only be * Register the Horizon gate. * * This gate determines who can access Horizon in non-local environments. - * - * @return void */ - protected function gate() + protected function gate(): void { - Gate::define('viewHorizon', function ($user) { + Gate::define('viewHorizon', function (User $user) { return in_array($user->email, [ 'taylor@laravel.com', ]); @@ -294,9 +292,6 @@ Horizon allows you to assign “tags” to jobs, including mailables, broadcast /** * Create a new job instance. - * - * @param \App\Models\Video $video - * @return void */ public function __construct(Video $video) { @@ -305,12 +300,10 @@ Horizon allows you to assign “tags” to jobs, including mailables, broadcast /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { - // + // ... } } @@ -333,9 +326,9 @@ If you would like to manually define the tags for one of your queueable objects, /** * Get the tags that should be assigned to the job. * - * @return array + * @return array */ - public function tags() + public function tags(): array { return ['render', 'video:'.$this->video->id]; } @@ -351,10 +344,8 @@ If you would like to be notified when one of your queues has a long wait time, y /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { parent::boot(); @@ -380,11 +371,8 @@ Horizon includes a metrics dashboard which provides information regarding your j /** * Define the application's command schedule. - * - * @param \Illuminate\Console\Scheduling\Schedule $schedule - * @return void */ - protected function schedule(Schedule $schedule) + protected function schedule(Schedule $schedule): void { $schedule->command('horizon:snapshot')->everyFiveMinutes(); } diff --git a/http-client.md b/http-client.md index df368b092e9..c4380c3f9d4 100644 --- a/http-client.md +++ b/http-client.md @@ -183,13 +183,19 @@ If you would like the HTTP client to automatically retry the request if a client If needed, you may pass a third argument to the `retry` method. The third argument should be a callable that determines if the retries should actually be attempted. For example, you may wish to only retry the request if the initial request encounters an `ConnectionException`: - $response = Http::retry(3, 100, function ($exception, $request) { + use Exception; + use Illuminate\Http\Client\PendingRequest; + + $response = Http::retry(3, 100, function (Exception $exception, PendingRequest $request) { return $exception instanceof ConnectionException; })->post(/* ... */); If a request attempt fails, you may wish to make a change to the request before a new attempt is made. You can achieve this by modifying the request argument provided to the callable you provided to the `retry` method. For example, you might want to retry the request with a new authorization token if the first attempt returned an authentication error: - $response = Http::withToken($this->getToken())->retry(2, 0, function ($exception, $request) { + use Exception; + use Illuminate\Http\Client\PendingRequest; + + $response = Http::withToken($this->getToken())->retry(2, 0, function (Exception $exception, PendingRequest $request) { if (! $exception instanceof RequestException || $exception->response->status() !== 401) { return false; } @@ -231,6 +237,8 @@ Unlike Guzzle's default behavior, Laravel's HTTP client wrapper does not throw e If you have a response instance and would like to throw an instance of `Illuminate\Http\Client\RequestException` if the response status code indicates a client or server error, you may use the `throw` or `throwIf` methods: + use Illuminate\Http\Client\Response; + $response = Http::post(/* ... */); // Throw an exception if a client or server error occurred... @@ -240,13 +248,13 @@ If you have a response instance and would like to throw an instance of `Illumina $response->throwIf($condition); // Throw an exception if an error occurred and the given closure resolves to true... - $response->throwIf(fn ($response) => true); + $response->throwIf(fn (Response $response) => true); // Throw an exception if an error occurred and the given condition is false... $response->throwUnless($condition); // Throw an exception if an error occurred and the given closure resolves to false... - $response->throwUnless(fn ($response) => false); + $response->throwUnless(fn (Response $response) => false); return $response['user']['id']; @@ -258,8 +266,11 @@ The `throw` method returns the response instance if no error occurred, allowing If you would like to perform some additional logic before the exception is thrown, you may pass a closure to the `throw` method. The exception will be thrown automatically after the closure is invoked, so you do not need to re-throw the exception from within the closure: - return Http::post(/* ... */)->throw(function ($response, $e) { - // + use Illuminate\Http\Client\Response; + use Illuminate\Http\Client\RequestException; + + return Http::post(/* ... */)->throw(function (Response $response, RequestException $e) { + // ... })->json(); @@ -347,10 +358,8 @@ use Illuminate\Support\Facades\Http; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Http::macro('github', function () { return Http::withHeaders([ diff --git a/http-tests.md b/http-tests.md index 8426cc1de8d..20d484b5552 100644 --- a/http-tests.md +++ b/http-tests.md @@ -33,10 +33,8 @@ Laravel provides a very fluent API for making HTTP requests to your application { /** * A basic test example. - * - * @return void */ - public function test_a_basic_request() + public function test_a_basic_request(): void { $response = $this->get('/'); @@ -65,10 +63,8 @@ Instead of returning an `Illuminate\Http\Response` instance, test request method { /** * A basic test example. - * - * @return void */ - public function test_a_basic_request() + public function test_a_basic_request(): void { $response = $this->get('/'); @@ -96,10 +92,8 @@ You may use the `withHeaders` method to customize the request's headers before i { /** * A basic functional test example. - * - * @return void */ - public function test_interacting_with_headers() + public function test_interacting_with_headers(): void { $response = $this->withHeaders([ 'X-Header' => 'Value', @@ -122,7 +116,7 @@ You may use the `withCookie` or `withCookies` methods to set cookie values befor class ExampleTest extends TestCase { - public function test_interacting_with_cookies() + public function test_interacting_with_cookies(): void { $response = $this->withCookie('color', 'blue')->get('/'); @@ -146,7 +140,7 @@ Laravel provides several helpers for interacting with the session during HTTP te class ExampleTest extends TestCase { - public function test_interacting_with_the_session() + public function test_interacting_with_the_session(): void { $response = $this->withSession(['banned' => false])->get('/'); } @@ -163,7 +157,7 @@ Laravel's session is typically used to maintain state for the currently authenti class ExampleTest extends TestCase { - public function test_an_action_that_requires_authentication() + public function test_an_action_that_requires_authentication(): void { $user = User::factory()->create(); @@ -192,10 +186,8 @@ After making a test request to your application, the `dump`, `dumpHeaders`, and { /** * A basic test example. - * - * @return void */ - public function test_basic_test() + public function test_basic_test(): void { $response = $this->get('/'); @@ -219,10 +211,8 @@ Alternatively, you may use the `dd`, `ddHeaders`, and `ddSession` methods to dum { /** * A basic test example. - * - * @return void */ - public function test_basic_test() + public function test_basic_test(): void { $response = $this->get('/'); @@ -260,10 +250,8 @@ Laravel also provides several helpers for testing JSON APIs and their responses. { /** * A basic functional test example. - * - * @return void */ - public function test_making_an_api_request() + public function test_making_an_api_request(): void { $response = $this->postJson('/api/user', ['name' => 'Sally']); @@ -297,10 +285,8 @@ As previously mentioned, the `assertJson` method may be used to assert that a fr { /** * A basic functional test example. - * - * @return void */ - public function test_asserting_an_exact_json_match() + public function test_asserting_an_exact_json_match(): void { $response = $this->postJson('/user', ['name' => 'Sally']); @@ -327,10 +313,8 @@ If you would like to verify that the JSON response contains the given data at a { /** * A basic functional test example. - * - * @return void */ - public function test_asserting_a_json_paths_value() + public function test_asserting_a_json_paths_value(): void { $response = $this->postJson('/user', ['name' => 'Sally']); @@ -342,7 +326,7 @@ If you would like to verify that the JSON response contains the given data at a The `assertJsonPath` method also accepts a closure, which may be used to dynamically determine if the assertion should pass: - $response->assertJsonPath('team.owner.name', fn ($name) => strlen($name) >= 3); + $response->assertJsonPath('team.owner.name', fn (string $name) => strlen($name) >= 3); ### Fluent JSON Testing @@ -353,10 +337,8 @@ Laravel also offers a beautiful way to fluently test your application's JSON res /** * A basic functional test example. - * - * @return void */ - public function test_fluent_json() + public function test_fluent_json(): void { $response = $this->getJson('/users/1'); @@ -364,7 +346,7 @@ Laravel also offers a beautiful way to fluently test your application's JSON res ->assertJson(fn (AssertableJson $json) => $json->where('id', 1) ->where('name', 'Victoria Faith') - ->where('email', fn ($email) => str($email)->is('victoria@gmail.com')) + ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com')) ->whereNot('status', 'pending') ->missing('password') ->etc() @@ -417,10 +399,10 @@ In these situations, we may use the fluent JSON object's `has` method to make as $response ->assertJson(fn (AssertableJson $json) => $json->has(3) - ->first(fn ($json) => + ->first(fn (AssertableJson $json) => $json->where('id', 1) ->where('name', 'Victoria Faith') - ->where('email', fn ($email) => str($email)->is('victoria@gmail.com')) + ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com')) ->missing('password') ->etc() ) @@ -444,10 +426,10 @@ When testing these routes, you may use the `has` method to assert against the nu ->assertJson(fn (AssertableJson $json) => $json->has('meta') ->has('users', 3) - ->has('users.0', fn ($json) => + ->has('users.0', fn (AssertableJson $json) => $json->where('id', 1) ->where('name', 'Victoria Faith') - ->where('email', fn ($email) => str($email)->is('victoria@gmail.com')) + ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com')) ->missing('password') ->etc() ) @@ -458,10 +440,10 @@ However, instead of making two separate calls to the `has` method to assert agai $response ->assertJson(fn (AssertableJson $json) => $json->has('meta') - ->has('users', 3, fn ($json) => + ->has('users', 3, fn (AssertableJson $json) => $json->where('id', 1) ->where('name', 'Victoria Faith') - ->where('email', fn ($email) => str($email)->is('victoria@gmail.com')) + ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com')) ->missing('password') ->etc() ) @@ -506,7 +488,7 @@ The `Illuminate\Http\UploadedFile` class provides a `fake` method which may be u class ExampleTest extends TestCase { - public function test_avatars_can_be_uploaded() + public function test_avatars_can_be_uploaded(): void { Storage::fake('avatars'); @@ -558,7 +540,7 @@ Laravel also allows you to render a view without making a simulated HTTP request class ExampleTest extends TestCase { - public function test_a_welcome_view_can_be_rendered() + public function test_a_welcome_view_can_be_rendered(): void { $view = $this->view('welcome', ['name' => 'Taylor']); diff --git a/localization.md b/localization.md index 784b53dc382..a94f45c60e7 100644 --- a/localization.md +++ b/localization.md @@ -41,14 +41,14 @@ You may modify the default language for a single HTTP request at runtime using t use Illuminate\Support\Facades\App; - Route::get('/greeting/{locale}', function ($locale) { + Route::get('/greeting/{locale}', function (string $locale) { if (! in_array($locale, ['en', 'es', 'fr'])) { abort(400); } App::setLocale($locale); - // + // ... }); You may configure a "fallback language", which will be used when the active language does not contain a given translation string. Like the default language, the fallback language is also configured in the `config/app.php` configuration file: @@ -65,7 +65,7 @@ You may use the `currentLocale` and `isLocale` methods on the `App` facade to de $locale = App::currentLocale(); if (App::isLocale('en')) { - // + // ... } @@ -77,10 +77,8 @@ You may instruct Laravel's "pluralizer", which is used by Eloquent and other por /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Pluralizer::useLanguage('spanish'); diff --git a/logging.md b/logging.md index 6986755e2b5..228f399fdba 100644 --- a/logging.md +++ b/logging.md @@ -179,16 +179,14 @@ You may call any of these methods to log a message for the corresponding level. use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Support\Facades\Log; + use Illuminate\View\View; class UserController extends Controller { /** * Show the profile for the given user. - * - * @param int $id - * @return \Illuminate\Http\Response */ - public function show($id) + public function show(string $id): View { Log::info('Showing the user profile for user: '.$id); @@ -214,19 +212,19 @@ Occasionally, you may wish to specify some contextual information that should be namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; + use Symfony\Component\HttpFoundation\Response; class AssignRequestId { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { $requestId = (string) Str::uuid(); @@ -247,10 +245,8 @@ If you would like to share contextual information across _all_ logging channels, { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Log::shareContext([ 'invocation-id' => (string) Str::uuid(), @@ -317,17 +313,15 @@ Once you have configured the `tap` option on your channel, you're ready to defin namespace App\Logging; + use Illuminate\Log\Logger; use Monolog\Formatter\LineFormatter; class CustomizeFormatter { /** * Customize the given logger instance. - * - * @param \Illuminate\Log\Logger $logger - * @return void */ - public function __invoke($logger) + public function __invoke(Logger $logger): void { foreach ($logger->getHandlers() as $handler) { $handler->setFormatter(new LineFormatter( @@ -402,11 +396,8 @@ Once you have configured the `custom` driver channel, you're ready to define the { /** * Create a custom Monolog instance. - * - * @param array $config - * @return \Monolog\Logger */ - public function __invoke(array $config) + public function __invoke(array $config): Logger { return new Logger(/* ... */); } diff --git a/mail.md b/mail.md index 51d681044f9..227662214fc 100644 --- a/mail.md +++ b/mail.md @@ -188,10 +188,8 @@ First, let's explore configuring the sender of the email. Or, in other words, wh /** * Get the message envelope. - * - * @return \Illuminate\Mail\Mailables\Envelope */ - public function envelope() + public function envelope(): Envelope { return new Envelope( from: new Address('jeffrey@example.com', 'Jeffrey Way'), @@ -227,10 +225,8 @@ Within a mailable class' `content` method, you may define the `view`, or which t /** * Get the message content definition. - * - * @return \Illuminate\Mail\Mailables\Content */ - public function content() + public function content(): Content { return new Content( view: 'emails.orders.shipped', @@ -247,10 +243,8 @@ If you would like to define a plain-text version of your email, you may specify /** * Get the message content definition. - * - * @return \Illuminate\Mail\Mailables\Content */ - public function content() + public function content(): Content { return new Content( view: 'emails.orders.shipped', @@ -296,9 +290,6 @@ Typically, you will want to pass some data to your view that you can utilize whe /** * Create a new message instance. - * - * @param \App\Models\Order $order - * @return void */ public function __construct(Order $order) { @@ -307,10 +298,8 @@ Typically, you will want to pass some data to your view that you can utilize whe /** * Get the message content definition. - * - * @return \Illuminate\Mail\Mailables\Content */ - public function content() + public function content(): Content { return new Content( view: 'emails.orders.shipped', @@ -352,9 +341,6 @@ If you would like to customize the format of your email's data before it is sent /** * Create a new message instance. - * - * @param \App\Models\Order $order - * @return void */ public function __construct(Order $order) { @@ -363,10 +349,8 @@ If you would like to customize the format of your email's data before it is sent /** * Get the message content definition. - * - * @return \Illuminate\Mail\Mailables\Content */ - public function content() + public function content(): Content { return new Content( view: 'emails.orders.shipped', @@ -394,9 +378,9 @@ To add attachments to an email, you will add attachments to the array returned b /** * Get the attachments for the message. * - * @return \Illuminate\Mail\Mailables\Attachment[] + * @return array */ - public function attachments() + public function attachments(): array { return [ Attachment::fromPath('/path/to/file'), @@ -408,9 +392,9 @@ When attaching files to a message, you may also specify the display name and / o /** * Get the attachments for the message. * - * @return \Illuminate\Mail\Mailables\Attachment[] + * @return array */ - public function attachments() + public function attachments(): array { return [ Attachment::fromPath('/path/to/file') @@ -427,9 +411,9 @@ If you have stored a file on one of your [filesystem disks](/docs/{{version}}/fi /** * Get the attachments for the message. * - * @return \Illuminate\Mail\Mailables\Attachment[] + * @return array */ - public function attachments() + public function attachments(): array { return [ Attachment::fromStorage('/path/to/file'), @@ -441,9 +425,9 @@ Of course, you may also specify the attachment's name and MIME type: /** * Get the attachments for the message. * - * @return \Illuminate\Mail\Mailables\Attachment[] + * @return array */ - public function attachments() + public function attachments(): array { return [ Attachment::fromStorage('/path/to/file') @@ -457,9 +441,9 @@ The `fromStorageDisk` method may be used if you need to specify a storage disk o /** * Get the attachments for the message. * - * @return \Illuminate\Mail\Mailables\Attachment[] + * @return array */ - public function attachments() + public function attachments(): array { return [ Attachment::fromStorageDisk('s3', '/path/to/file') @@ -476,9 +460,9 @@ The `fromData` attachment method may be used to attach a raw string of bytes as /** * Get the attachments for the message. * - * @return \Illuminate\Mail\Mailables\Attachment[] + * @return array */ - public function attachments() + public function attachments(): array { return [ Attachment::fromData(fn () => $this->pdf, 'Report.pdf') @@ -534,10 +518,8 @@ To get started, implement the `Illuminate\Contracts\Mail\Attachable` interface o { /** * Get the attachable representation of the model. - * - * @return \Illuminate\Mail\Attachment */ - public function toMailAttachment() + public function toMailAttachment(): Attachment { return Attachment::fromPath('/path/to/file'); } @@ -548,9 +530,9 @@ Once you have defined your attachable object, you may return an instance of that /** * Get the attachments for the message. * - * @return array + * @return array */ - public function attachments() + public function attachments(): array { return [$this->photo]; } @@ -584,10 +566,8 @@ To accomplish this, define a `headers` method on your mailable. The `headers` me /** * Get the message headers. - * - * @return \Illuminate\Mail\Mailables\Headers */ - public function headers() + public function headers(): Headers { return new Headers( messageId: 'custom-message-id@example.com', @@ -610,7 +590,7 @@ Some third-party email providers such as Mailgun and Postmark support message "t * * @return \Illuminate\Mail\Mailables\Envelope */ - public function envelope() + public function envelope(): Envelope { return new Envelope( subject: 'Order Shipped', @@ -635,10 +615,8 @@ Laravel's mail capabilities are powered by Symfony Mailer. Laravel allows you to /** * Get the message envelope. - * - * @return \Illuminate\Mail\Mailables\Envelope */ - public function envelope() + public function envelope(): Envelope { return new Envelope( subject: 'Order Shipped', @@ -670,10 +648,8 @@ Then, when configuring the mailable `Content` definition within its `content` me /** * Get the message content definition. - * - * @return \Illuminate\Mail\Mailables\Content */ - public function content() + public function content(): Content { return new Content( markdown: 'emails.orders.shipped', @@ -775,23 +751,23 @@ To send a message, use the `to` method on the `Mail` [facade](/docs/{{version}}/ use App\Mail\OrderShipped; use App\Models\Order; use Illuminate\Http\Request; + use Illuminate\Http\Response; use Illuminate\Support\Facades\Mail; class OrderShipmentController extends Controller { /** * Ship the given order. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $order = Order::findOrFail($request->order_id); // Ship the order... Mail::to($request->user())->send(new OrderShipped($order)); + + return response()->noContent(); } } @@ -868,7 +844,7 @@ If you have mailable classes that you want to always be queued, you may implemen class OrderShipped extends Mailable implements ShouldQueue { - // + // ... } @@ -899,8 +875,6 @@ Alternatively, you may call the `afterCommit` method from your mailable's constr /** * Create a new message instance. - * - * @return void */ public function __construct() { @@ -959,10 +933,8 @@ Sometimes, applications store each user's preferred locale. By implementing the { /** * Get the user's preferred locale. - * - * @return string */ - public function preferredLocale() + public function preferredLocale(): string { return $this->locale; } @@ -982,7 +954,7 @@ As you might expect, the "HTML" assertions assert that the HTML version of your use App\Mail\InvoicePaid; use App\Models\User; - public function test_mailable_content() + public function test_mailable_content(): void { $user = User::factory()->create(); @@ -1042,10 +1014,8 @@ Finally, you may specify a global "to" address by invoking the `alwaysTo` method /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { if ($this->app->environment('local')) { Mail::alwaysTo('taylor@example.com'); @@ -1061,7 +1031,7 @@ Laravel fires two events during the process of sending mail messages. The `Messa use App\Listeners\LogSentMessage; use Illuminate\Mail\Events\MessageSending; use Illuminate\Mail\Events\MessageSent; - + /** * The event listener mappings for the application. * @@ -1098,9 +1068,6 @@ Laravel includes a variety of mail transports; however, you may wish to write yo /** * Create a new Mailchimp transport instance. - * - * @param \MailchimpTransactional\ApiClient $client - * @return void */ public function __construct(ApiClient $client) { @@ -1126,8 +1093,6 @@ Laravel includes a variety of mail transports; however, you may wish to write yo /** * Get the string representation of the transport. - * - * @return string */ public function __toString(): string { @@ -1142,10 +1107,8 @@ Once you've defined your custom transport, you may register it via the `extend` /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Mail::extend('mailchimp', function (array $config = []) { return new MailchimpTransport(/* ... */); @@ -1182,10 +1145,8 @@ Finally, you may use the `Mail` facade's `extend` method to register the transpo /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Mail::extend('sendinblue', function () { return (new SendinblueTransportFactory)->create( diff --git a/middleware.md b/middleware.md index 94061ba4d65..d71c797e4eb 100644 --- a/middleware.md +++ b/middleware.md @@ -33,17 +33,17 @@ This command will place a new `EnsureTokenIsValid` class within your `app/Http/M namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; class EnsureTokenIsValid { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { if ($request->input('token') !== 'my-secret-token') { return redirect('home'); @@ -71,10 +71,12 @@ Of course, a middleware can perform tasks before or after passing the request de namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; class BeforeMiddleware { - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { // Perform action @@ -89,10 +91,12 @@ However, this middleware would perform its task **after** the request is handled namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; class AfterMiddleware { - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { $response = $next($request); @@ -132,13 +136,13 @@ If you would like to assign middleware to specific routes, you should first assi Once the middleware has been defined in the HTTP kernel, you may use the `middleware` method to assign middleware to a route: Route::get('/profile', function () { - // + // ... })->middleware('auth'); You may assign multiple middleware to the route by passing an array of middleware names to the `middleware` method: Route::get('/', function () { - // + // ... })->middleware(['first', 'second']); When assigning middleware, you may also pass the fully qualified class name: @@ -146,7 +150,7 @@ When assigning middleware, you may also pass the fully qualified class name: use App\Http\Middleware\EnsureTokenIsValid; Route::get('/profile', function () { - // + // ... })->middleware(EnsureTokenIsValid::class); @@ -158,11 +162,11 @@ When assigning middleware to a group of routes, you may occasionally need to pre Route::middleware([EnsureTokenIsValid::class])->group(function () { Route::get('/', function () { - // + // ... }); Route::get('/profile', function () { - // + // ... })->withoutMiddleware([EnsureTokenIsValid::class]); }); @@ -172,7 +176,7 @@ You may also exclude a given set of middleware from an entire [group](/docs/{{ve Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () { Route::get('/profile', function () { - // + // ... }); }); @@ -209,11 +213,11 @@ Laravel includes predefined `web` and `api` middleware groups that contain commo Middleware groups may be assigned to routes and controller actions using the same syntax as individual middleware. Again, middleware groups make it more convenient to assign many middleware to a route at once: Route::get('/', function () { - // + // ... })->middleware('web'); Route::middleware(['web'])->group(function () { - // + // ... }); > **Note** @@ -256,18 +260,17 @@ Additional middleware parameters will be passed to the middleware after the `$ne namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; class EnsureUserHasRole { /** - * Handle the incoming request. + * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @param string $role - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next, $role) + public function handle(Request $request, Closure $next, string $role): Response { if (! $request->user()->hasRole($role)) { // Redirect... @@ -280,8 +283,8 @@ Additional middleware parameters will be passed to the middleware after the `$ne Middleware parameters may be specified when defining the route by separating the middleware name and parameters with a `:`. Multiple parameters should be delimited by commas: - Route::put('/post/{id}', function ($id) { - // + Route::put('/post/{id}', function (string $id) { + // ... })->middleware('role:editor'); @@ -294,29 +297,25 @@ Sometimes a middleware may need to do some work after the HTTP response has been namespace Illuminate\Session\Middleware; use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; class TerminatingMiddleware { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { return $next($request); } /** * Handle tasks after the response has been sent to the browser. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Http\Response $response - * @return void */ - public function terminate($request, $response) + public function terminate(Request $request, Response $response): void { // ... } @@ -330,10 +329,8 @@ When calling the `terminate` method on your middleware, Laravel will resolve a f /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { $this->app->singleton(TerminatingMiddleware::class); } diff --git a/migrations.md b/migrations.md index a207f28965d..1bb2f509faf 100644 --- a/migrations.md +++ b/migrations.md @@ -90,10 +90,8 @@ Within both of these methods, you may use the Laravel schema builder to expressi { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('flights', function (Blueprint $table) { $table->id(); @@ -105,10 +103,8 @@ Within both of these methods, you may use the Laravel schema builder to expressi /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::drop('flights'); } @@ -128,12 +124,10 @@ If your migration will be interacting with a database connection other than your /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { - // + // ... } @@ -992,10 +986,8 @@ The `default` modifier accepts a value or an `Illuminate\Database\Query\Expressi { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('flights', function (Blueprint $table) { $table->id(); @@ -1013,7 +1005,7 @@ The `default` modifier accepts a value or an `Illuminate\Database\Query\Expressi When using the MySQL database, the `after` method may be used to add columns after an existing column in the schema: - $table->after('password', function ($table) { + $table->after('password', function (Blueprint $table) { $table->string('address_line1'); $table->string('address_line2'); $table->string('city'); @@ -1170,10 +1162,8 @@ By default, Laravel uses the `utf8mb4` character set. If you are running a versi /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Schema::defaultStringLength(191); } diff --git a/mocking.md b/mocking.md index 70f1c3510b3..6fb684a7cda 100644 --- a/mocking.md +++ b/mocking.md @@ -33,7 +33,7 @@ When mocking an object that is going to be injected into your application via La use Mockery; use Mockery\MockInterface; - public function test_something_can_be_mocked() + public function test_something_can_be_mocked(): void { $this->instance( Service::class, @@ -86,14 +86,14 @@ Unlike traditional static method calls, [facades](/docs/{{version}}/facades) (in { /** * Retrieve a list of all users of the application. - * - * @return \Illuminate\Http\Response */ - public function index() + public function index(): array { $value = Cache::get('key'); - // + return [ + // ... + ]; } } @@ -110,7 +110,7 @@ We can mock the call to the `Cache` facade by using the `shouldReceive` method, class UserControllerTest extends TestCase { - public function testGetIndex() + public function test_get_index(): void { Cache::shouldReceive('get') ->once() @@ -133,7 +133,7 @@ If you would like to [spy](http://docs.mockery.io/en/latest/reference/spies.html use Illuminate\Support\Facades\Cache; - public function test_values_are_be_stored_in_cache() + public function test_values_are_be_stored_in_cache(): void { Cache::spy(); @@ -163,7 +163,7 @@ You may use the `Bus` facade's `fake` method to prevent jobs from being dispatch class ExampleTest extends TestCase { - public function test_orders_can_be_shipped() + public function test_orders_can_be_shipped(): void { Bus::fake(); @@ -291,7 +291,7 @@ When testing code that dispatches events, you may wish to instruct Laravel to no /** * Test order shipping. */ - public function test_orders_can_be_shipped() + public function test_orders_can_be_shipped(): void { Event::fake(); @@ -335,7 +335,7 @@ If you only want to fake event listeners for a specific set of events, you may p /** * Test order process. */ - public function test_orders_can_be_processed() + public function test_orders_can_be_processed(): void { Event::fake([ OrderCreated::class, @@ -376,7 +376,7 @@ If you only want to fake event listeners for a portion of your test, you may use /** * Test order process. */ - public function test_orders_can_be_processed() + public function test_orders_can_be_processed(): void { $order = Event::fakeFor(function () { $order = Order::factory()->create(); @@ -415,7 +415,7 @@ After calling the `Mail` facade's `fake` method, you may then assert that [maila class ExampleTest extends TestCase { - public function test_orders_can_be_shipped() + public function test_orders_can_be_shipped(): void { Mail::fake(); @@ -451,7 +451,7 @@ You may pass a closure to the `assertSent`, `assertNotSent`, `assertQueued`, or When calling the `Mail` facade's assertion methods, the mailable instance accepted by the provided closure exposes helpful methods for examining the mailable: - Mail::assertSent(OrderShipped::class, function ($mail) use ($user) { + Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($user) { return $mail->hasTo($user->email) && $mail->hasCc('...') && $mail->hasBcc('...') && @@ -464,7 +464,7 @@ The mailable instance also includes several helpful methods for examining the at use Illuminate\Mail\Mailables\Attachment; - Mail::assertSent(OrderShipped::class, function ($mail) { + Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) { return $mail->hasAttachment( Attachment::fromPath('/path/to/file') ->as('name.pdf') @@ -472,13 +472,13 @@ The mailable instance also includes several helpful methods for examining the at ); }); - Mail::assertSent(OrderShipped::class, function ($mail) { + Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) { return $mail->hasAttachment( Attachment::fromStorageDisk('s3', '/path/to/file') ); }); - Mail::assertSent(OrderShipped::class, function ($mail) use ($pdfData) { + Mail::assertSent(OrderShipped::class, function (OrderShipped $mail) use ($pdfData) { return $mail->hasAttachment( Attachment::fromData(fn () => $pdfData, 'name.pdf') ); @@ -516,7 +516,7 @@ After calling the `Notification` facade's `fake` method, you may then assert tha class ExampleTest extends TestCase { - public function test_orders_can_be_shipped() + public function test_orders_can_be_shipped(): void { Notification::fake(); @@ -544,7 +544,7 @@ You may pass a closure to the `assertSentTo` or `assertNotSentTo` methods in ord Notification::assertSentTo( $user, - function (OrderShipped $notification, $channels) use ($order) { + function (OrderShipped $notification, array $channels) use ($order) { return $notification->order->id === $order->id; } ); @@ -560,7 +560,7 @@ By passing a closure as the second argument to the `assertSentOnDemand` method, Notification::assertSentOnDemand( OrderShipped::class, - function ($notification, $channels, $notifiable) use ($user) { + function (OrderShipped $notification, array $channels, object $notifiable) use ($user) { return $notifiable->routes['mail'] === $user->email; } ); @@ -586,7 +586,7 @@ After calling the `Queue` facade's `fake` method, you may then assert that the a class ExampleTest extends TestCase { - public function test_orders_can_be_shipped() + public function test_orders_can_be_shipped(): void { Queue::fake(); @@ -614,7 +614,7 @@ You may pass a closure to the `assertPushed` or `assertNotPushed` methods in ord If you only need to fake specific jobs while allowing your other jobs to execute normally, you may pass the class names of the jobs that should be faked to the `fake` method: - public function test_orders_can_be_shipped() + public function test_orders_can_be_shipped(): void { Queue::fake([ ShipOrder::class, @@ -669,7 +669,7 @@ The `Storage` facade's `fake` method allows you to easily generate a fake disk t class ExampleTest extends TestCase { - public function test_albums_can_be_uploaded() + public function test_albums_can_be_uploaded(): void { Storage::fake('photos'); @@ -703,7 +703,7 @@ When testing, you may occasionally need to modify the time returned by helpers s use Illuminate\Support\Carbon; - public function testTimeCanBeManipulated() + public function test_time_can_be_manipulated(): void { // Travel into the future... $this->travel(5)->milliseconds(); diff --git a/notifications.md b/notifications.md index 0f0119f8acb..8a26a2ec4a4 100644 --- a/notifications.md +++ b/notifications.md @@ -122,10 +122,9 @@ The `via` method receives a `$notifiable` instance, which will be an instance of /** * Get the notification's delivery channels. * - * @param mixed $notifiable - * @return array + * @return array */ - public function via($notifiable) + public function via(object $notifiable): array { return $notifiable->prefers_sms ? ['vonage'] : ['mail', 'database']; } @@ -183,10 +182,9 @@ Alternatively, you may define a `withDelay` method on the notification class its /** * Determine the notification's delivery delay. * - * @param mixed $notifiable - * @return array + * @return array */ - public function withDelay($notifiable) + public function withDelay(object $notifiable): array { return [ 'mail' => now()->addMinutes(5), @@ -229,9 +227,9 @@ If you would like to specify a specific queue that should be used for each notif /** * Determine which queues should be used for each notification channel. * - * @return array + * @return array */ - public function viaQueues() + public function viaQueues(): array { return [ 'mail' => 'mail-queue', @@ -266,8 +264,6 @@ Alternatively, you may call the `afterCommit` method from your notification's co /** * Create a new notification instance. - * - * @return void */ public function __construct() { @@ -287,12 +283,8 @@ However, if you would like to make the final determination on whether the queued /** * Determine if the notification should be sent. - * - * @param mixed $notifiable - * @param string $channel - * @return bool */ - public function shouldSend($notifiable, $channel) + public function shouldSend(object $notifiable, string $channel): bool { return $this->invoice->isPaid(); } @@ -328,11 +320,8 @@ The `MailMessage` class contains a few simple methods to help you build transact /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { $url = url('/invoice/'.$this->invoice->id); @@ -361,11 +350,8 @@ Some notifications inform users of errors, such as a failed invoice payment. You /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->error() @@ -380,11 +366,8 @@ Instead of defining the "lines" of text in the notification class, you may use t /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage)->view( 'emails.name', ['invoice' => $this->invoice] @@ -395,11 +378,8 @@ You may specify a plain-text view for the mail message by passing the view name /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage)->view( ['emails.name.html', 'emails.name.plain'], @@ -414,11 +394,8 @@ By default, the email's sender / from address is defined in the `config/mail.php /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->from('barrett@example.com', 'Barrett Blair') @@ -436,6 +413,7 @@ When sending notifications via the `mail` channel, the notification system will use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; + use Illuminate\Notifications\Notification; class User extends Authenticatable { @@ -444,10 +422,9 @@ When sending notifications via the `mail` channel, the notification system will /** * Route notifications for the mail channel. * - * @param \Illuminate\Notifications\Notification $notification - * @return array|string + * @return array|string */ - public function routeNotificationForMail($notification) + public function routeNotificationForMail(Notification $notification): array|string { // Return email address only... return $this->email_address; @@ -464,11 +441,8 @@ By default, the email's subject is the class name of the notification formatted /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->subject('Notification Subject') @@ -482,11 +456,8 @@ By default, the email notification will be sent using the default mailer defined /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->mailer('postmark') @@ -509,11 +480,8 @@ To add attachments to an email notification, use the `attach` method while build /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('Hello!') @@ -527,11 +495,8 @@ When attaching files to a message, you may also specify the display name and / o /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('Hello!') @@ -547,11 +512,8 @@ Unlike attaching files in mailable objects, you may not attach a file directly f /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return Mailable */ - public function toMail($notifiable) + public function toMail(object $notifiable): Mailable { return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email) @@ -562,11 +524,8 @@ When necessary, multiple files may be attached to a message using the `attachMan /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('Hello!') @@ -586,11 +545,8 @@ The `attachData` method may be used to attach a raw string of bytes as an attach /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('Hello!') @@ -606,11 +562,8 @@ Some third-party email providers such as Mailgun and Postmark support message "t /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->greeting('Comment Upvoted!') @@ -631,11 +584,8 @@ The `withSymfonyMessage` method of the `MailMessage` class allows you to registe /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->withSymfonyMessage(function (Email $message) { @@ -651,14 +601,12 @@ The `withSymfonyMessage` method of the `MailMessage` class allows you to registe If needed, you may return a full [mailable object](/docs/{{version}}/mail) from your notification's `toMail` method. When returning a `Mailable` instead of a `MailMessage`, you will need to specify the message recipient using the mailable object's `to` method: use App\Mail\InvoicePaid as InvoicePaidMailable; + use Illuminate\Mail\Mailable; /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return Mailable */ - public function toMail($notifiable) + public function toMail(object $notifiable): Mailable { return (new InvoicePaidMailable($this->invoice)) ->to($notifiable->email); @@ -671,14 +619,12 @@ If you are sending an [on-demand notification](#on-demand-notifications), the `$ use App\Mail\InvoicePaid as InvoicePaidMailable; use Illuminate\Notifications\AnonymousNotifiable; + use Illuminate\Mail\Mailable; /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return Mailable */ - public function toMail($notifiable) + public function toMail(object $notifiable): Mailable { $address = $notifiable instanceof AnonymousNotifiable ? $notifiable->routeNotificationFor('mail') @@ -721,11 +667,8 @@ Like all other mail notifications, notifications that use Markdown templates sho /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { $url = url('/invoice/'.$this->invoice->id); @@ -812,11 +755,8 @@ To customize the theme for an individual notification, you may call the `theme` /** * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage */ - public function toMail($notifiable) + public function toMail(object $notifiable): MailMessage { return (new MailMessage) ->theme('invoice') @@ -848,10 +788,9 @@ If a notification supports being stored in a database table, you should define a /** * Get the array representation of the notification. * - * @param mixed $notifiable - * @return array + * @return array */ - public function toArray($notifiable) + public function toArray(object $notifiable): array { return [ 'invoice_id' => $this->invoice->id, @@ -928,11 +867,8 @@ The `broadcast` channel broadcasts notifications using Laravel's [event broadcas /** * Get the broadcastable representation of the notification. - * - * @param mixed $notifiable - * @return BroadcastMessage */ - public function toBroadcast($notifiable) + public function toBroadcast(object $notifiable): BroadcastMessage { return new BroadcastMessage([ 'invoice_id' => $this->invoice->id, @@ -954,14 +890,10 @@ All broadcast notifications are queued for broadcasting. If you would like to co In addition to the data you specify, all broadcast notifications also have a `type` field containing the full class name of the notification. If you would like to customize the notification `type`, you may define a `broadcastType` method on the notification class: - use Illuminate\Notifications\Messages\BroadcastMessage; - /** * Get the type of the notification being broadcast. - * - * @return string */ - public function broadcastType() + public function broadcastType(): string { return 'broadcast.message'; } @@ -995,10 +927,8 @@ If you would like to customize which channel that an entity's broadcast notifica /** * The channels the user receives notification broadcasts on. - * - * @return string */ - public function receivesBroadcastNotificationsOn() + public function receivesBroadcastNotificationsOn(): string { return 'users.'.$this->id; } @@ -1025,13 +955,12 @@ After defining your keys, you may set a `VONAGE_SMS_FROM` environment variable t If a notification supports being sent as an SMS, you should define a `toVonage` method on the notification class. This method will receive a `$notifiable` entity and should return an `Illuminate\Notifications\Messages\VonageMessage` instance: + use Illuminate\Notifications\Messages\VonageMessage; + /** * Get the Vonage / SMS representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\VonageMessage */ - public function toVonage($notifiable) + public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('Your SMS message content'); @@ -1042,13 +971,12 @@ If a notification supports being sent as an SMS, you should define a `toVonage` If your SMS message will contain unicode characters, you should call the `unicode` method when constructing the `VonageMessage` instance: + use Illuminate\Notifications\Messages\VonageMessage; + /** * Get the Vonage / SMS representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\VonageMessage */ - public function toVonage($notifiable) + public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('Your unicode message') @@ -1060,13 +988,12 @@ If your SMS message will contain unicode characters, you should call the `unicod If you would like to send some notifications from a phone number that is different from the phone number specified by your `VONAGE_SMS_FROM` environment variable, you may call the `from` method on a `VonageMessage` instance: + use Illuminate\Notifications\Messages\VonageMessage; + /** * Get the Vonage / SMS representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\VonageMessage */ - public function toVonage($notifiable) + public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->content('Your SMS message content') @@ -1078,13 +1005,12 @@ If you would like to send some notifications from a phone number that is differe If you would like to keep track of costs per user, team, or client, you may add a "client reference" to the notification. Vonage will allow you to generate reports using this client reference so that you can better understand a particular customer's SMS usage. The client reference can be any string up to 40 characters: + use Illuminate\Notifications\Messages\VonageMessage; + /** * Get the Vonage / SMS representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\VonageMessage */ - public function toVonage($notifiable) + public function toVonage(object $notifiable): VonageMessage { return (new VonageMessage) ->clientReference((string) $notifiable->id) @@ -1102,6 +1028,7 @@ To route Vonage notifications to the proper phone number, define a `routeNotific use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; + use Illuminate\Notifications\Notification; class User extends Authenticatable { @@ -1109,11 +1036,8 @@ To route Vonage notifications to the proper phone number, define a `routeNotific /** * Route notifications for the Vonage channel. - * - * @param \Illuminate\Notifications\Notification $notification - * @return string */ - public function routeNotificationForVonage($notification) + public function routeNotificationForVonage(Notification $notification): string { return $this->phone_number; } @@ -1138,13 +1062,12 @@ You will also need to create a [Slack App](https://api.slack.com/apps?new_app=1) If a notification supports being sent as a Slack message, you should define a `toSlack` method on the notification class. This method will receive a `$notifiable` entity and should return an `Illuminate\Notifications\Messages\SlackMessage` instance. Slack messages may contain text content as well as an "attachment" that formats additional text or an array of fields. Let's take a look at a basic `toSlack` example: + use Illuminate\Notifications\Messages\SlackMessage; + /** * Get the Slack representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\SlackMessage */ - public function toSlack($notifiable) + public function toSlack(object $notifiable): SlackMessage { return (new SlackMessage) ->content('One of your invoices has been paid!'); @@ -1155,20 +1078,20 @@ If a notification supports being sent as a Slack message, you should define a `t You may also add "attachments" to Slack messages. Attachments provide richer formatting options than simple text messages. In this example, we will send an error notification about an exception that occurred in an application, including a link to view more details about the exception: + use Illuminate\Notifications\Messages\SlackAttachment; + use Illuminate\Notifications\Messages\SlackMessage; + /** * Get the Slack representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\SlackMessage */ - public function toSlack($notifiable) + public function toSlack(object $notifiable): SlackMessage { $url = url('/exceptions/'.$this->exception->id); return (new SlackMessage) ->error() ->content('Whoops! Something went wrong.') - ->attachment(function ($attachment) use ($url) { + ->attachment(function (SlackAttachment $attachment) use ($url) { $attachment->title('Exception: File Not Found', $url) ->content('File [background.jpg] was not found.'); }); @@ -1176,20 +1099,20 @@ You may also add "attachments" to Slack messages. Attachments provide richer for Attachments also allow you to specify an array of data that should be presented to the user. The given data will be presented in a table-style format for easy reading: + use Illuminate\Notifications\Messages\SlackAttachment; + use Illuminate\Notifications\Messages\SlackMessage; + /** * Get the Slack representation of the notification. - * - * @param mixed $notifiable - * @return SlackMessage */ - public function toSlack($notifiable) + public function toSlack(object $notifiable): SlackMessage { $url = url('/invoices/'.$this->invoice->id); return (new SlackMessage) ->success() ->content('One of your invoices has been paid!') - ->attachment(function ($attachment) use ($url) { + ->attachment(function (SlackAttachment $attachment) use ($url) { $attachment->title('Invoice 1322', $url) ->fields([ 'Title' => 'Server Expenses', @@ -1205,20 +1128,20 @@ Attachments also allow you to specify an array of data that should be presented If some of your attachment fields contain Markdown, you may use the `markdown` method to instruct Slack to parse and display the given attachment fields as Markdown formatted text. The values accepted by this method are: `pretext`, `text`, and / or `fields`. For more information about Slack attachment formatting, check out the [Slack API documentation](https://api.slack.com/docs/message-formatting#message_formatting): + use Illuminate\Notifications\Messages\SlackAttachment; + use Illuminate\Notifications\Messages\SlackMessage; + /** * Get the Slack representation of the notification. - * - * @param mixed $notifiable - * @return SlackMessage */ - public function toSlack($notifiable) + public function toSlack(object $notifiable): SlackMessage { $url = url('/exceptions/'.$this->exception->id); return (new SlackMessage) ->error() ->content('Whoops! Something went wrong.') - ->attachment(function ($attachment) use ($url) { + ->attachment(function (SlackAttachment $attachment) use ($url) { $attachment->title('Exception: File Not Found', $url) ->content('File [background.jpg] was *not found*.') ->markdown(['text']); @@ -1236,6 +1159,7 @@ To route Slack notifications to the proper Slack team and channel, define a `rou use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; + use Illuminate\Notifications\Notification; class User extends Authenticatable { @@ -1243,11 +1167,8 @@ To route Slack notifications to the proper Slack team and channel, define a `rou /** * Route notifications for the Slack channel. - * - * @param \Illuminate\Notifications\Notification $notification - * @return string */ - public function routeNotificationForSlack($notification) + public function routeNotificationForSlack(Notification $notification): string { return 'https://hooks.slack.com/services/...'; } @@ -1279,10 +1200,8 @@ Sometimes, applications store each user's preferred locale. By implementing the { /** * Get the user's preferred locale. - * - * @return string */ - public function preferredLocale() + public function preferredLocale(): string { return $this->locale; } @@ -1320,11 +1239,8 @@ The notification will not be sent if an event listener for the `NotificationSend /** * Handle the event. - * - * @param \Illuminate\Notifications\Events\NotificationSending $event - * @return void */ - public function handle(NotificationSending $event) + public function handle(NotificationSending $event): void { return false; } @@ -1333,11 +1249,8 @@ Within an event listener, you may access the `notifiable`, `notification`, and ` /** * Handle the event. - * - * @param \Illuminate\Notifications\Events\NotificationSending $event - * @return void */ - public function handle(NotificationSending $event) + public function handle(NotificationSending $event): void { // $event->channel // $event->notifiable @@ -1370,11 +1283,8 @@ Within an event listener, you may access the `notifiable`, `notification`, `chan /** * Handle the event. - * - * @param \Illuminate\Notifications\Events\NotificationSent $event - * @return void */ - public function handle(NotificationSent $event) + public function handle(NotificationSent $event): void { // $event->channel // $event->notifiable @@ -1399,12 +1309,8 @@ Within the `send` method, you may call methods on the notification to retrieve a { /** * Send the given notification. - * - * @param mixed $notifiable - * @param \Illuminate\Notifications\Notification $notification - * @return void */ - public function send($notifiable, Notification $notification) + public function send(object $notifiable, Notification $notification): void { $message = $notification->toVoice($notifiable); @@ -1430,22 +1336,16 @@ Once your notification channel class has been defined, you may return the class /** * Get the notification channels. - * - * @param mixed $notifiable - * @return array|string */ - public function via($notifiable) + public function via(object $notifiable): string { - return [VoiceChannel::class]; + return VoiceChannel::class; } /** * Get the voice representation of the notification. - * - * @param mixed $notifiable - * @return VoiceMessage */ - public function toVoice($notifiable) + public function toVoice(object $notifiable): VoiceMessage { // ... } diff --git a/octane.md b/octane.md index c4086d8f539..ef6f596e0bb 100644 --- a/octane.md +++ b/octane.md @@ -309,15 +309,14 @@ In general, you should avoid injecting the application service container or HTTP ```php use App\Service; +use Illuminate\Contracts\Foundation\Application; /** * Register any application services. - * - * @return void */ -public function register() +public function register(): void { - $this->app->singleton(Service::class, function ($app) { + $this->app->singleton(Service::class, function (Application $app) { return new Service($app); }); } @@ -330,8 +329,9 @@ As a work-around, you could either stop registering the binding as a singleton, ```php use App\Service; use Illuminate\Container\Container; +use Illuminate\Contracts\Foundation\Application; -$this->app->bind(Service::class, function ($app) { +$this->app->bind(Service::class, function (Application $app) { return new Service($app); }); @@ -349,15 +349,14 @@ In general, you should avoid injecting the application service container or HTTP ```php use App\Service; +use Illuminate\Contracts\Foundation\Application; /** * Register any application services. - * - * @return void */ -public function register() +public function register(): void { - $this->app->singleton(Service::class, function ($app) { + $this->app->singleton(Service::class, function (Application $app) { return new Service($app['request']); }); } @@ -369,12 +368,13 @@ As a work-around, you could either stop registering the binding as a singleton, ```php use App\Service; +use Illuminate\Contracts\Foundation\Application; -$this->app->bind(Service::class, function ($app) { +$this->app->bind(Service::class, function (Application $app) { return new Service($app['request']); }); -$this->app->singleton(Service::class, function ($app) { +$this->app->singleton(Service::class, function (Application $app) { return new Service(fn () => $app['request']); }); @@ -395,15 +395,14 @@ In general, you should avoid injecting the configuration repository instance int ```php use App\Service; +use Illuminate\Contracts\Foundation\Application; /** * Register any application services. - * - * @return void */ -public function register() +public function register(): void { - $this->app->singleton(Service::class, function ($app) { + $this->app->singleton(Service::class, function (Application $app) { return new Service($app->make('config')); }); } @@ -416,8 +415,9 @@ As a work-around, you could either stop registering the binding as a singleton, ```php use App\Service; use Illuminate\Container\Container; +use Illuminate\Contracts\Foundation\Application; -$this->app->bind(Service::class, function ($app) { +$this->app->bind(Service::class, function (Application $app) { return new Service($app->make('config')); }); @@ -440,15 +440,14 @@ use Illuminate\Support\Str; /** * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @return void */ -public function index(Request $request) +public function index(Request $request): array { Service::$data[] = Str::random(10); - // ... + return [ + // ... + ]; } ``` diff --git a/packages.md b/packages.md index 427459334e9..5b558b92ac0 100644 --- a/packages.md +++ b/packages.md @@ -94,10 +94,8 @@ Typically, you will need to publish your package's configuration file to the app /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->publishes([ __DIR__.'/../config/courier.php' => config_path('courier.php'), @@ -120,10 +118,8 @@ The `mergeConfigFrom` method accepts the path to your package's configuration fi /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { $this->mergeConfigFrom( __DIR__.'/../config/courier.php', 'courier' @@ -140,10 +136,8 @@ If your package contains routes, you may load them using the `loadRoutesFrom` me /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->loadRoutesFrom(__DIR__.'/../routes/web.php'); } @@ -155,10 +149,8 @@ If your package contains [database migrations](/docs/{{version}}/migrations), yo /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); } @@ -172,10 +164,8 @@ If your package contains [translation files](/docs/{{version}}/localization), yo /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier'); } @@ -191,10 +181,8 @@ If you would like to publish your package's translations to the application's `l /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->loadTranslationsFrom(__DIR__.'/../lang', 'courier'); @@ -212,10 +200,8 @@ To register your package's [views](/docs/{{version}}/views) with Laravel, you ne /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier'); } @@ -238,10 +224,8 @@ If you would like to make your views available for publishing to the application /** * Bootstrap the package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->loadViewsFrom(__DIR__.'/../resources/views', 'courier'); @@ -262,10 +246,8 @@ If you are building a package that utilizes Blade components or placing componen /** * Bootstrap your package's services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::component('package-alert', AlertComponent::class); } @@ -285,10 +267,8 @@ Alternatively, you may use the `componentNamespace` method to autoload component /** * Bootstrap your package's services. - * - * @return void */ - public function boot() + public function boot(): void { Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade'); } @@ -320,10 +300,8 @@ Laravel's built-in `about` Artisan command provides a synopsis of the applicatio /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']); } @@ -338,10 +316,8 @@ To register your package's Artisan commands with Laravel, you may use the `comma /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { if ($this->app->runningInConsole()) { $this->commands([ @@ -358,10 +334,8 @@ Your package may have assets such as JavaScript, CSS, and images. To publish the /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->publishes([ __DIR__.'/../public' => public_path('vendor/courier'), @@ -381,10 +355,8 @@ You may want to publish groups of package assets and resources separately. For i /** * Bootstrap any package services. - * - * @return void */ - public function boot() + public function boot(): void { $this->publishes([ __DIR__.'/../config/package.php' => config_path('package.php') diff --git a/pagination.md b/pagination.md index a8c231b217f..9d8783fd746 100644 --- a/pagination.md +++ b/pagination.md @@ -52,15 +52,14 @@ In this example, the only argument passed to the `paginate` method is the number use App\Http\Controllers\Controller; use Illuminate\Support\Facades\DB; + use Illuminate\View\View; class UserController extends Controller { /** * Show all application users. - * - * @return \Illuminate\Http\Response */ - public function index() + public function index(): View { return view('user.index', [ 'users' => DB::table('users')->paginate(15) @@ -178,7 +177,7 @@ By default, links generated by the paginator will match the current request's UR $users->withPath('/admin/users'); - // + // ... }); @@ -193,7 +192,7 @@ You may append to the query string of pagination links using the `appends` metho $users->appends(['sort' => 'votes']); - // + // ... }); You may use the `withQueryString` method if you would like to append all of the current request's query string values to the pagination links: @@ -303,10 +302,8 @@ If you would like to designate a different file as the default pagination view, { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Paginator::defaultView('view-name'); @@ -323,10 +320,8 @@ Laravel includes pagination views built using [Bootstrap CSS](https://getbootstr /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Paginator::useBootstrapFive(); Paginator::useBootstrapFour(); diff --git a/passport.md b/passport.md index 8ae80964ab2..53a46f98948 100644 --- a/passport.md +++ b/passport.md @@ -135,10 +135,8 @@ If necessary, you may define the path where Passport's keys should be loaded fro /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -201,10 +199,8 @@ By default, Passport issues long-lived access tokens that expire after one year. /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -237,10 +233,8 @@ After defining your model, you may instruct Passport to use your custom model vi /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -375,7 +369,7 @@ This route is used to delete clients: ```js axios.delete('/oauth/clients/' + clientId) .then(response => { - // + // ... }); ``` @@ -437,10 +431,8 @@ Sometimes you may wish to skip the authorization prompt, such as when authorizin { /** * Determine if the client should skip the authorization prompt. - * - * @return bool */ - public function skipsAuthorization() + public function skipsAuthorization(): bool { return $this->firstParty(); } @@ -560,11 +552,8 @@ You may also configure a [scheduled job](/docs/{{version}}/scheduling) in your a /** * Define the application's command schedule. - * - * @param \Illuminate\Console\Scheduling\Schedule $schedule - * @return void */ - protected function schedule(Schedule $schedule) + protected function schedule(Schedule $schedule): void { $schedule->command('passport:purge')->hourly(); } @@ -741,11 +730,8 @@ When authenticating using the password grant, Passport will use the `email` attr /** * Find the user instance for the given username. - * - * @param string $username - * @return \App\Models\User */ - public function findForPassport($username) + public function findForPassport(string $username): User { return $this->where('username', $username)->first(); } @@ -771,11 +757,8 @@ When authenticating using the password grant, Passport will use the `password` a /** * Validate the password of the user for the Passport password grant. - * - * @param string $password - * @return bool */ - public function validateForPassportPasswordGrant($password) + public function validateForPassportPasswordGrant(string $password): bool { return Hash::check($password, $this->password); } @@ -791,10 +774,8 @@ The implicit grant is similar to the authorization code grant; however, the toke /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -978,7 +959,7 @@ axios.delete('/oauth/personal-access-tokens/' + tokenId); Passport includes an [authentication guard](/docs/{{version}}/authentication#adding-custom-guards) that will validate access tokens on incoming requests. Once you have configured the `api` guard to use the `passport` driver, you only need to specify the `auth:api` middleware on any routes that should require a valid access token: Route::get('/user', function () { - // + // ... })->middleware('auth:api'); > **Warning** @@ -1002,7 +983,7 @@ If your application authenticates different types of users that perhaps use enti The following route will utilize the `api-customers` guard, which uses the `customers` user provider, to authenticate incoming requests: Route::get('/customer', function () { - // + // ... })->middleware('auth:api-customers'); > **Note** @@ -1034,10 +1015,8 @@ You may define your API's scopes using the `Passport::tokensCan` method in the ` /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -1128,7 +1107,7 @@ Once an access token authenticated request has entered your application, you may Route::get('/orders', function (Request $request) { if ($request->user()->tokenCan('place-orders')) { - // + // ... } }); @@ -1182,10 +1161,8 @@ If needed, you can customize the `laravel_token` cookie's name using the `Passpo /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); @@ -1228,7 +1205,7 @@ Passport's `actingAs` method may be used to specify the currently authenticated use App\Models\User; use Laravel\Passport\Passport; - public function test_servers_can_be_created() + public function test_servers_can_be_created(): void { Passport::actingAs( User::factory()->create(), @@ -1245,7 +1222,7 @@ Passport's `actingAsClient` method may be used to specify the currently authenti use Laravel\Passport\Client; use Laravel\Passport\Passport; - public function test_orders_can_be_retrieved() + public function test_orders_can_be_retrieved(): void { Passport::actingAsClient( Client::factory()->create(), diff --git a/passwords.md b/passwords.md index fb1efd6cc17..31993dbf810 100644 --- a/passwords.md +++ b/passwords.md @@ -99,7 +99,7 @@ You may be wondering how Laravel knows how to retrieve the user record from your Next, we will define the routes necessary to actually reset the password once the user clicks on the password reset link that has been emailed to them and provides a new password. First, let's define the route that will display the reset password form that is displayed when the user clicks the reset password link. This route will receive a `token` parameter that we will use later to verify the password reset request: - Route::get('/reset-password/{token}', function ($token) { + Route::get('/reset-password/{token}', function (string $token) { return view('auth.reset-password', ['token' => $token]); })->middleware('guest')->name('password.reset'); @@ -110,6 +110,7 @@ The view that is returned by this route should display a form containing an `ema Of course, we need to define a route to actually handle the password reset form submission. This route will be responsible for validating the incoming request and updating the user's password in the database: + use App\Models\User; use Illuminate\Auth\Events\PasswordReset; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; @@ -125,7 +126,7 @@ Of course, we need to define a route to actually handle the password reset form $status = Password::reset( $request->only('email', 'password', 'password_confirmation', 'token'), - function ($user, $password) { + function (User $user, string $password) { $user->forceFill([ 'password' => Hash::make($password) ])->setRememberToken(Str::random(60)); @@ -170,18 +171,17 @@ If you would like to automate this process, consider adding the command to your You may customize the password reset link URL using the `createUrlUsing` method provided by the `ResetPassword` notification class. This method accepts a closure which receives the user instance that is receiving the notification as well as the password reset link token. Typically, you should call this method from your `App\Providers\AuthServiceProvider` service provider's `boot` method: + use App\Models\User; use Illuminate\Auth\Notifications\ResetPassword; /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { $this->registerPolicies(); - ResetPassword::createUrlUsing(function ($user, string $token) { + ResetPassword::createUrlUsing(function (User $user, string $token) { return 'https://example.com/reset-password?token='.$token; }); } @@ -197,9 +197,8 @@ You may easily modify the notification class used to send the password reset lin * Send a password reset notification to the user. * * @param string $token - * @return void */ - public function sendPasswordResetNotification($token) + public function sendPasswordResetNotification($token): void { $url = 'https://example.com/reset-password?token='.$token; diff --git a/providers.md b/providers.md index 69aa92f8ffa..2d507902568 100644 --- a/providers.md +++ b/providers.md @@ -44,18 +44,17 @@ Let's take a look at a basic service provider. Within any of your service provid namespace App\Providers; use App\Services\Riak\Connection; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\ServiceProvider; class RiakServiceProvider extends ServiceProvider { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - $this->app->singleton(Connection::class, function ($app) { + $this->app->singleton(Connection::class, function (Application $app) { return new Connection(config('riak')); }); } @@ -117,13 +116,11 @@ So, what if we need to register a [view composer](/docs/{{version}}/views#view-c { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { View::composer('view', function () { - // + // ... }); } } @@ -137,14 +134,11 @@ You may type-hint dependencies for your service provider's `boot` method. The [s /** * Bootstrap any application services. - * - * @param \Illuminate\Contracts\Routing\ResponseFactory $response - * @return void */ - public function boot(ResponseFactory $response) + public function boot(ResponseFactory $response): void { - $response->macro('serialized', function ($value) { - // + $response->macro('serialized', function (mixed $value) { + // ... }); } @@ -175,6 +169,7 @@ To defer the loading of a provider, implement the `\Illuminate\Contracts\Support namespace App\Providers; use App\Services\Riak\Connection; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider; @@ -182,12 +177,10 @@ To defer the loading of a provider, implement the `\Illuminate\Contracts\Support { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - $this->app->singleton(Connection::class, function ($app) { + $this->app->singleton(Connection::class, function (Application $app) { return new Connection($app['config']['riak']); }); } @@ -195,9 +188,9 @@ To defer the loading of a provider, implement the `\Illuminate\Contracts\Support /** * Get the services provided by the provider. * - * @return array + * @return array */ - public function provides() + public function provides(): array { return [Connection::class]; } diff --git a/queries.md b/queries.md index d6739a652ba..fdd7fadd5fa 100644 --- a/queries.md +++ b/queries.md @@ -58,15 +58,14 @@ You may use the `table` method provided by the `DB` facade to begin a query. The use App\Http\Controllers\Controller; use Illuminate\Support\Facades\DB; + use Illuminate\View\View; class UserController extends Controller { /** * Show a list of all of the application's users. - * - * @return \Illuminate\Http\Response */ - public function index() + public function index(): View { $users = DB::table('users')->get(); @@ -130,17 +129,18 @@ If you would like to retrieve an `Illuminate\Support\Collection` instance contai If you need to work with thousands of database records, consider using the `chunk` method provided by the `DB` facade. This method retrieves a small chunk of results at a time and feeds each chunk into a closure for processing. For example, let's retrieve the entire `users` table in chunks of 100 records at a time: + use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; - DB::table('users')->orderBy('id')->chunk(100, function ($users) { + DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) { foreach ($users as $user) { - // + // ... } }); You may stop further chunks from being processed by returning `false` from the closure: - DB::table('users')->orderBy('id')->chunk(100, function ($users) { + DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) { // Process the records... return false; @@ -149,7 +149,7 @@ You may stop further chunks from being processed by returning `false` from the c If you are updating database records while chunking results, your chunk results could change in unexpected ways. If you plan to update the retrieved records while chunking, it is always best to use the `chunkById` method instead. This method will automatically paginate the results based on the record's primary key: DB::table('users')->where('active', false) - ->chunkById(100, function ($users) { + ->chunkById(100, function (Collection $users) { foreach ($users as $user) { DB::table('users') ->where('id', $user->id) @@ -168,8 +168,8 @@ The `lazy` method works similarly to [the `chunk` method](#chunking-results) in ```php use Illuminate\Support\Facades\DB; -DB::table('users')->orderBy('id')->lazy()->each(function ($user) { - // +DB::table('users')->orderBy('id')->lazy()->each(function (object $user) { + // ... }); ``` @@ -177,7 +177,7 @@ Once again, if you plan to update the retrieved records while iterating over the ```php DB::table('users')->where('active', false) - ->lazyById()->each(function ($user) { + ->lazyById()->each(function (object $user) { DB::table('users') ->where('id', $user->id) ->update(['active' => true]); @@ -352,7 +352,7 @@ You may use the `crossJoin` method to perform a "cross join". Cross joins genera You may also specify more advanced join clauses. To get started, pass a closure as the second argument to the `join` method. The closure will receive a `Illuminate\Database\Query\JoinClause` instance which allows you to specify constraints on the "join" clause: DB::table('users') - ->join('contacts', function ($join) { + ->join('contacts', function (JoinClause $join) { $join->on('users.id', '=', 'contacts.user_id')->orOn(/* ... */); }) ->get(); @@ -360,7 +360,7 @@ You may also specify more advanced join clauses. To get started, pass a closure If you would like to use a "where" clause on your joins, you may use the `where` and `orWhere` methods provided by the `JoinClause` instance. Instead of comparing two columns, these methods will compare the column against a value: DB::table('users') - ->join('contacts', function ($join) { + ->join('contacts', function (JoinClause $join) { $join->on('users.id', '=', 'contacts.user_id') ->where('contacts.user_id', '>', 5); }) @@ -377,7 +377,7 @@ You may use the `joinSub`, `leftJoinSub`, and `rightJoinSub` methods to join a q ->groupBy('user_id'); $users = DB::table('users') - ->joinSub($latestPosts, 'latest_posts', function ($join) { + ->joinSub($latestPosts, 'latest_posts', function (JoinClause $join) { $join->on('users.id', '=', 'latest_posts.user_id'); })->get(); @@ -455,7 +455,7 @@ If you need to group an "or" condition within parentheses, you may pass a closur $users = DB::table('users') ->where('votes', '>', 100) - ->orWhere(function($query) { + ->orWhere(function(Builder $query) { $query->where('name', 'Abigail') ->where('votes', '>', 50); }) @@ -476,7 +476,7 @@ select * from users where votes > 100 or (name = 'Abigail' and votes > 50) The `whereNot` and `orWhereNot` methods may be used to negate a given group of query constraints. For example, the following query excludes products that are on clearance or which have a price that is less than ten: $products = DB::table('products') - ->whereNot(function ($query) { + ->whereNot(function (Builder $query) { $query->where('clearance', true) ->orWhere('price', '<', 10); }) @@ -638,7 +638,7 @@ Sometimes you may need to group several "where" clauses within parentheses in or $users = DB::table('users') ->where('name', '=', 'John') - ->where(function ($query) { + ->where(function (Builder $query) { $query->where('votes', '>', 100) ->orWhere('title', '=', 'Admin'); }) @@ -662,7 +662,7 @@ select * from users where name = 'John' and (votes > 100 or title = 'Admin') The `whereExists` method allows you to write "where exists" SQL clauses. The `whereExists` method accepts a closure which will receive a query builder instance, allowing you to define the query that should be placed inside of the "exists" clause: $users = DB::table('users') - ->whereExists(function ($query) { + ->whereExists(function (Builder $query) { $query->select(DB::raw(1)) ->from('orders') ->whereColumn('orders.user_id', 'users.id'); @@ -686,8 +686,9 @@ where exists ( Sometimes you may need to construct a "where" clause that compares the results of a subquery to a given value. You may accomplish this by passing a closure and a value to the `where` method. For example, the following query will retrieve all users who have a recent "membership" of a given type; use App\Models\User; + use Illuminate\Database\Query\Builder; - $users = User::where(function ($query) { + $users = User::where(function (Builder $query) { $query->select('type') ->from('membership') ->whereColumn('membership.user_id', 'users.id') @@ -698,8 +699,9 @@ Sometimes you may need to construct a "where" clause that compares the results o Or, you may need to construct a "where" clause that compares a column to the results of a subquery. You may accomplish this by passing a column, operator, and closure to the `where` method. For example, the following query will retrieve all income records where the amount is less than average; use App\Models\Income; + use Illuminate\Database\Query\Builder; - $incomes = Income::where('amount', '<', function ($query) { + $incomes = Income::where('amount', '<', function (Builder $query) { $query->selectRaw('avg(i.amount)')->from('incomes as i'); })->get(); @@ -822,10 +824,10 @@ Alternatively, you may use the `limit` and `offset` methods. These methods are f Sometimes you may want certain query clauses to apply to a query based on another condition. For instance, you may only want to apply a `where` statement if a given input value is present on the incoming HTTP request. You may accomplish this using the `when` method: - $role = $request->input('role'); + $role = $request->string('role'); $users = DB::table('users') - ->when($role, function ($query, $role) { + ->when($role, function (Builder $query, string $role) { $query->where('role_id', $role); }) ->get(); @@ -834,12 +836,12 @@ The `when` method only executes the given closure when the first argument is `tr You may pass another closure as the third argument to the `when` method. This closure will only execute if the first argument evaluates as `false`. To illustrate how this feature may be used, we will use it to configure the default ordering of a query: - $sortByVotes = $request->input('sort_by_votes'); + $sortByVotes = $request->boolean('sort_by_votes'); $users = DB::table('users') - ->when($sortByVotes, function ($query, $sortByVotes) { + ->when($sortByVotes, function (Builder $query, bool $sortByVotes) { $query->orderBy('votes'); - }, function ($query) { + }, function (Builder $query) { $query->orderBy('name'); }) ->get(); diff --git a/queues.md b/queues.md index 7b250d8c058..f21e7334f78 100644 --- a/queues.md +++ b/queues.md @@ -190,9 +190,6 @@ Job classes are very simple, normally containing only a `handle` method that is /** * Create a new job instance. - * - * @param App\Models\Podcast $podcast - * @return void */ public function __construct(Podcast $podcast) { @@ -201,11 +198,8 @@ Job classes are very simple, normally containing only a `handle` method that is /** * Execute the job. - * - * @param App\Services\AudioProcessor $processor - * @return void */ - public function handle(AudioProcessor $processor) + public function handle(AudioProcessor $processor): void { // Process uploaded podcast... } @@ -224,8 +218,9 @@ If you would like to take total control over how the container injects dependenc use App\Jobs\ProcessPodcast; use App\Services\AudioProcessor; + use Illuminate\Contracts\Foundation\Application; - $this->app->bindMethod([ProcessPodcast::class, 'handle'], function ($job, $app) { + $this->app->bindMethod([ProcessPodcast::class, 'handle'], function (ProcessPodcast $job, Application $app) { return $job->handle($app->make(AudioProcessor::class)); }); @@ -239,9 +234,6 @@ Because loaded relationships also get serialized, the serialized job string can /** * Create a new job instance. - * - * @param \App\Models\Podcast $podcast - * @return void */ public function __construct(Podcast $podcast) { @@ -296,10 +288,8 @@ In certain cases, you may want to define a specific "key" that makes the job uni /** * The unique ID of the job. - * - * @return string */ - public function uniqueId() + public function uniqueId(): string { return $this->product->id; } @@ -331,6 +321,7 @@ By default, unique jobs are "unlocked" after a job completes processing or fails Behind the scenes, when a `ShouldBeUnique` job is dispatched, Laravel attempts to acquire a [lock](/docs/{{version}}/cache#atomic-locks) with the `uniqueId` key. If the lock is not acquired, the job is not dispatched. This lock is released when the job completes processing or fails all of its retry attempts. By default, Laravel will use the default cache driver to obtain this lock. However, if you wish to use another driver for acquiring the lock, you may define a `uniqueVia` method that returns the cache driver that should be used: + use Illuminate\Contracts\Cache\Repository; use Illuminate\Support\Facades\Cache; class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique @@ -339,10 +330,8 @@ Behind the scenes, when a `ShouldBeUnique` job is dispatched, Laravel attempts t /** * Get the cache driver for the unique job lock. - * - * @return \Illuminate\Contracts\Cache\Repository */ - public function uniqueVia() + public function uniqueVia(): Repository { return Cache::driver('redis'); } @@ -360,10 +349,8 @@ Job middleware allow you to wrap custom logic around the execution of queued job /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () { info('Lock obtained...'); @@ -384,6 +371,7 @@ Instead of rate limiting in the handle method, we could define a job middleware namespace App\Jobs\Middleware; + use Closure; use Illuminate\Support\Facades\Redis; class RateLimited @@ -391,15 +379,13 @@ Instead of rate limiting in the handle method, we could define a job middleware /** * Process the queued job. * - * @param mixed $job - * @param callable $next - * @return mixed + * @param \Closure(object): void $next */ - public function handle($job, $next) + public function handle(object $job, Closure $next): void { Redis::throttle('key') ->block(0)->allow(1)->every(5) - ->then(function () use ($job, $next) { + ->then(function () use (object $job, Closure $next) { // Lock obtained... $next($job); @@ -420,9 +406,9 @@ After creating job middleware, they may be attached to a job by returning them f /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [new RateLimited]; } @@ -442,12 +428,10 @@ For example, you may wish to allow users to backup their data once per hour whil /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - RateLimiter::for('backups', function ($job) { + RateLimiter::for('backups', function (object $job) { return $job->user->vipCustomer() ? Limit::none() : Limit::perHour(1)->by($job->user->id); @@ -465,9 +449,9 @@ Once you have defined your rate limit, you may attach the rate limiter to your b /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [new RateLimited('backups')]; } @@ -479,9 +463,9 @@ If you do not want a job to be retried when it is rate limited, you may use the /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [(new RateLimited('backups'))->dontRelease()]; } @@ -501,9 +485,9 @@ For example, let's imagine you have a queued job that updates a user's credit sc /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [new WithoutOverlapping($this->user->id)]; } @@ -513,9 +497,9 @@ Any overlapping jobs of the same type will be released back to the queue. You ma /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [(new WithoutOverlapping($this->order->id))->releaseAfter(60)]; } @@ -525,9 +509,9 @@ If you wish to immediately delete any overlapping jobs so that they will not be /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [(new WithoutOverlapping($this->order->id))->dontRelease()]; } @@ -537,9 +521,9 @@ The `WithoutOverlapping` middleware is powered by Laravel's atomic lock feature. /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [(new WithoutOverlapping($this->order->id))->expireAfter(180)]; } @@ -560,7 +544,7 @@ class ProviderIsDown // ... - public function middleware() + public function middleware(): array { return [ (new WithoutOverlapping("status:{$this->provider}"))->shared(), @@ -573,7 +557,7 @@ class ProviderIsUp // ... - public function middleware() + public function middleware(): array { return [ (new WithoutOverlapping("status:{$this->provider}"))->shared(), @@ -589,24 +573,23 @@ Laravel includes a `Illuminate\Queue\Middleware\ThrottlesExceptions` middleware For example, let's imagine a queued job that interacts with a third-party API that begins throwing exceptions. To throttle exceptions, you can return the `ThrottlesExceptions` middleware from your job's `middleware` method. Typically, this middleware should be paired with a job that implements [time based attempts](#time-based-attempts): + use DateTime; use Illuminate\Queue\Middleware\ThrottlesExceptions; /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [new ThrottlesExceptions(10, 5)]; } /** * Determine the time at which the job should timeout. - * - * @return \DateTime */ - public function retryUntil() + public function retryUntil(): DateTime { return now()->addMinutes(5); } @@ -620,9 +603,9 @@ When a job throws an exception but the exception threshold has not yet been reac /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [(new ThrottlesExceptions(10, 5))->backoff(5)]; } @@ -634,9 +617,9 @@ Internally, this middleware uses Laravel's cache system to implement rate limiti /** * Get the middleware the job should pass through. * - * @return array + * @return array */ - public function middleware() + public function middleware(): array { return [(new ThrottlesExceptions(10, 10))->by('key')]; } @@ -657,22 +640,22 @@ Once you have written your job class, you may dispatch it using the `dispatch` m use App\Jobs\ProcessPodcast; use App\Models\Podcast; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PodcastController extends Controller { /** * Store a new podcast. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $podcast = Podcast::create(/* ... */); // ... ProcessPodcast::dispatch($podcast); + + return response()->noContent(); } } @@ -697,16 +680,14 @@ If you would like to specify that a job should not be immediately available for use App\Jobs\ProcessPodcast; use App\Models\Podcast; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PodcastController extends Controller { /** * Store a new podcast. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $podcast = Podcast::create(/* ... */); @@ -714,6 +695,8 @@ If you would like to specify that a job should not be immediately available for ProcessPodcast::dispatch($podcast) ->delay(now()->addMinutes(10)); + + return response()->noContent(); } } @@ -751,22 +734,22 @@ If you would like to dispatch a job immediately (synchronously), you may use the use App\Jobs\ProcessPodcast; use App\Models\Podcast; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PodcastController extends Controller { /** * Store a new podcast. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatchSync($podcast); + + return response()->noContent(); } } @@ -877,22 +860,22 @@ By pushing jobs to different queues, you may "categorize" your queued jobs and e use App\Jobs\ProcessPodcast; use App\Models\Podcast; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PodcastController extends Controller { /** * Store a new podcast. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatch($podcast)->onQueue('processing'); + + return response()->noContent(); } } @@ -914,8 +897,6 @@ Alternatively, you may specify the job's queue by calling the `onQueue` method w /** * Create a new job instance. - * - * @return void */ public function __construct() { @@ -936,22 +917,22 @@ If your application interacts with multiple queue connections, you may specify w use App\Jobs\ProcessPodcast; use App\Models\Podcast; use Illuminate\Http\Request; + use Illuminate\Http\Response; class PodcastController extends Controller { /** * Store a new podcast. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatch($podcast)->onConnection('sqs'); + + return response()->noContent(); } } @@ -979,10 +960,8 @@ Alternatively, you may specify the job's connection by calling the `onConnection /** * Create a new job instance. - * - * @return void */ - public function __construct() + public function __construct(): void { $this->onConnection('sqs'); } @@ -1025,12 +1004,12 @@ You may take a more granular approach by defining the maximum number of times a As an alternative to defining how many times a job may be attempted before it fails, you may define a time at which the job should no longer be attempted. This allows a job to be attempted any number of times within a given time frame. To define the time at which a job should no longer be attempted, add a `retryUntil` method to your job class. This method should return a `DateTime` instance: + use DateTime; + /** * Determine the time at which the job should timeout. - * - * @return \DateTime */ - public function retryUntil() + public function retryUntil(): DateTime { return now()->addMinutes(10); } @@ -1067,10 +1046,8 @@ Sometimes you may wish to specify that a job may be attempted many times, but sh /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { Redis::throttle('key')->allow(10)->every(60)->then(function () { // Lock obtained, process the podcast... @@ -1143,10 +1120,8 @@ Sometimes you may wish to manually release a job back onto the queue so that it /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { // ... @@ -1164,10 +1139,8 @@ Occasionally you may need to manually mark a job as "failed". To do so, you may /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { // ... @@ -1214,10 +1187,8 @@ To define a batchable job, you should [create a queueable job](#creating-jobs) a /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { if ($this->batch()->cancelled()) { // Determine if the batch has been cancelled... @@ -1325,10 +1296,8 @@ In this example, we will use the `LoadImportBatch` job to hydrate the batch with /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { if ($this->batch()->cancelled()) { return; @@ -1398,10 +1367,8 @@ Sometimes you may need to cancel a given batch's execution. This can be accompli /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { if ($this->user->exceedsImportLimit()) { return $this->batch()->cancel(); @@ -1416,10 +1383,8 @@ As you may have noticed in previous examples, batched jobs should typically chec /** * Execute the job. - * - * @return void */ - public function handle() + public function handle(): void { if ($this->batch()->cancelled()) { return; @@ -1741,10 +1706,8 @@ If you require more complex logic for determining the job's backoff time, you ma /** * Calculate the number of seconds to wait before retrying the job. - * - * @return int */ - public function backoff() + public function backoff(): int { return 3; } @@ -1754,9 +1717,9 @@ You may easily configure "exponential" backoffs by returning an array of backoff /** * Calculate the number of seconds to wait before retrying the job. * - * @return array + * @return array */ - public function backoff() + public function backoff(): array { return [1, 5, 10]; } @@ -1791,9 +1754,6 @@ When a particular job fails, you may want to send an alert to your users or reve /** * Create a new job instance. - * - * @param \App\Models\Podcast $podcast - * @return void */ public function __construct(Podcast $podcast) { @@ -1802,22 +1762,16 @@ When a particular job fails, you may want to send an alert to your users or reve /** * Execute the job. - * - * @param \App\Services\AudioProcessor $processor - * @return void */ - public function handle(AudioProcessor $processor) + public function handle(AudioProcessor $processor): void { // Process uploaded podcast... } /** * Handle a job failure. - * - * @param \Throwable $exception - * @return void */ - public function failed(Throwable $exception) + public function failed(Throwable $exception): void { // Send user notification of failure, etc... } @@ -1954,20 +1908,16 @@ If you would like to register an event listener that will be invoked when a job { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Queue::failing(function (JobFailed $event) { // $event->connectionName @@ -2019,10 +1969,8 @@ use Illuminate\Support\Facades\Notification; /** * Register any other events for your application. - * - * @return void */ -public function boot() +public function boot(): void { Event::listen(function (QueueBusy $event) { Notification::route('mail', 'dev@example.com') @@ -2053,20 +2001,16 @@ Using the `before` and `after` methods on the `Queue` [facade](/docs/{{version}} { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Queue::before(function (JobProcessing $event) { // $event->connectionName diff --git a/rate-limiting.md b/rate-limiting.md index 6800b986016..b659e3778f9 100644 --- a/rate-limiting.md +++ b/rate-limiting.md @@ -88,11 +88,8 @@ You may reset the number of attempts for a given rate limiter key using the `cle /** * Mark the message as read. - * - * @param \App\Models\Message $message - * @return \App\Models\Message */ - public function read(Message $message) + public function read(Message $message): Message { $message->markAsRead(); diff --git a/redirects.md b/redirects.md index 260f6729336..faf87ebc15c 100644 --- a/redirects.md +++ b/redirects.md @@ -48,10 +48,8 @@ If you would like to customize the value that is placed in the route parameter, /** * Get the value of the model's route key. - * - * @return mixed */ - public function getRouteKey() + public function getRouteKey(): mixed { return $this->slug; } diff --git a/redis.md b/redis.md index 7f46e144571..0bd05fb9638 100644 --- a/redis.md +++ b/redis.md @@ -212,16 +212,14 @@ You may interact with Redis by calling various methods on the `Redis` [facade](/ use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Redis; + use Illuminate\View\View; class UserController extends Controller { /** * Show the profile for the given user. - * - * @param int $id - * @return \Illuminate\Http\Response */ - public function show($id) + public function show(string $id): View { return view('user.profile', [ 'user' => Redis::get('user:profile:'.$id) @@ -257,9 +255,10 @@ To obtain an instance of the default Redis connection, you may call the `connect The `Redis` facade's `transaction` method provides a convenient wrapper around Redis' native `MULTI` and `EXEC` commands. The `transaction` method accepts a closure as its only argument. This closure will receive a Redis connection instance and may issue any commands it would like to this instance. All of the Redis commands issued within the closure will be executed in a single, atomic transaction: - use Illuminate\Support\Facades\Redis; + use Redis; + use Illuminate\Support\Facades; - Redis::transaction(function ($redis) { + Facades\Redis::transaction(function (Redis $redis) { $redis->incr('user_visits', 1); $redis->incr('total_visits', 1); }); @@ -293,9 +292,10 @@ In this example, we will increment a counter, inspect its new value, and increme Sometimes you may need to execute dozens of Redis commands. Instead of making a network trip to your Redis server for each command, you may use the `pipeline` method. The `pipeline` method accepts one argument: a closure that receives a Redis instance. You may issue all of your commands to this Redis instance and they will all be sent to the Redis server at the same time to reduce network trips to the server. The commands will still be executed in the order they were issued: - use Illuminate\Support\Facades\Redis; + use Redis; + use Illuminate\Support\Facades; - Redis::pipeline(function ($pipe) { + Facades\Redis::pipeline(function (Redis $pipe) { for ($i = 0; $i < 1000; $i++) { $pipe->set("key:$i", $i); } @@ -333,12 +333,10 @@ First, let's setup a channel listener using the `subscribe` method. We'll place /** * Execute the console command. - * - * @return mixed */ - public function handle() + public function handle(): void { - Redis::subscribe(['test-channel'], function ($message) { + Redis::subscribe(['test-channel'], function (string $message) { echo $message; }); } @@ -361,10 +359,10 @@ Now we may publish messages to the channel using the `publish` method: Using the `psubscribe` method, you may subscribe to a wildcard channel, which may be useful for catching all messages on all channels. The channel name will be passed as the second argument to the provided closure: - Redis::psubscribe(['*'], function ($message, $channel) { + Redis::psubscribe(['*'], function (string $message, string $channel) { echo $message; }); - Redis::psubscribe(['users.*'], function ($message, $channel) { + Redis::psubscribe(['users.*'], function (string $message, string $channel) { echo $message; }); diff --git a/releases.md b/releases.md index 7b40db04f9d..2e49441fde3 100644 --- a/releases.md +++ b/releases.md @@ -333,10 +333,8 @@ Laravel now includes pagination views built using [Bootstrap 5](https://getboots /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Paginator::useBootstrapFive(); } diff --git a/requests.md b/requests.md index 191d41c1dd9..45991c6fa29 100644 --- a/requests.md +++ b/requests.md @@ -39,20 +39,20 @@ To obtain an instance of the current HTTP request via dependency injection, you namespace App\Http\Controllers; use Illuminate\Http\Request; + use Illuminate\Http\Response; class UserController extends Controller { /** * Store a new user. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $name = $request->input('name'); - // + // ... + + return response()->noContent(); } } @@ -61,7 +61,7 @@ As mentioned, you may also type-hint the `Illuminate\Http\Request` class on a ro use Illuminate\Http\Request; Route::get('/', function (Request $request) { - // + // ... }); @@ -80,19 +80,18 @@ You may still type-hint the `Illuminate\Http\Request` and access your `id` route namespace App\Http\Controllers; use Illuminate\Http\Request; + use Illuminate\Http\Response; class UserController extends Controller { /** * Update the specified user. - * - * @param \Illuminate\Http\Request $request - * @param string $id - * @return \Illuminate\Http\Response */ - public function update(Request $request, $id) + public function update(Request $request, string $id): Response { - // + // ... + + return response()->noContent(); } } @@ -114,13 +113,13 @@ The `path` method returns the request's path information. So, if the incoming re The `is` method allows you to verify that the incoming request path matches a given pattern. You may use the `*` character as a wildcard when utilizing this method: if ($request->is('admin/*')) { - // + // ... } Using the `routeIs` method, you may determine if the incoming request has matched a [named route](/docs/{{version}}/routing#named-routes): if ($request->routeIs('admin.*')) { - // + // ... } @@ -153,7 +152,7 @@ The `method` method will return the HTTP verb for the request. You may use the ` $method = $request->method(); if ($request->isMethod('post')) { - // + // ... } @@ -168,7 +167,7 @@ You may retrieve a request header from the `Illuminate\Http\Request` instance us The `hasHeader` method may be used to determine if the request contains a given header: if ($request->hasHeader('X-Header-Name')) { - // + // ... } For convenience, the `bearerToken` method may be used to retrieve a bearer token from the `Authorization` header. If no such header is present, an empty string will be returned: @@ -220,7 +219,7 @@ Once you have installed these libraries, you may obtain a PSR-7 request by type- use Psr\Http\Message\ServerRequestInterface; Route::get('/', function (ServerRequestInterface $request) { - // + // ... }); > **Note** @@ -245,7 +244,7 @@ Using the `collect` method, you may retrieve all of the incoming request's input The `collect` method also allows you to retrieve a subset of the incoming request input as a collection: - $request->collect('users')->each(function ($user) { + $request->collect('users')->each(function (string $user) { // ... }); @@ -359,24 +358,24 @@ If you need to retrieve a subset of the input data, you may use the `only` and ` You may use the `has` method to determine if a value is present on the request. The `has` method returns `true` if the value is present on the request: if ($request->has('name')) { - // + // ... } When given an array, the `has` method will determine if all of the specified values are present: if ($request->has(['name', 'email'])) { - // + // ... } The `whenHas` method will execute the given closure if a value is present on the request: - $request->whenHas('name', function ($input) { - // + $request->whenHas('name', function (string $input) { + // ... }); A second closure may be passed to the `whenHas` method that will be executed if the specified value is not present on the request: - $request->whenHas('name', function ($input) { + $request->whenHas('name', function (string $input) { // The "name" value is present... }, function () { // The "name" value is not present... @@ -385,24 +384,24 @@ A second closure may be passed to the `whenHas` method that will be executed if The `hasAny` method returns `true` if any of the specified values are present: if ($request->hasAny(['name', 'email'])) { - // + // ... } If you would like to determine if a value is present on the request and is not an empty string, you may use the `filled` method: if ($request->filled('name')) { - // + // ... } The `whenFilled` method will execute the given closure if a value is present on the request and is not an empty string: - $request->whenFilled('name', function ($input) { - // + $request->whenFilled('name', function (string $input) { + // ... }); A second closure may be passed to the `whenFilled` method that will be executed if the specified value is not "filled": - $request->whenFilled('name', function ($input) { + $request->whenFilled('name', function (string $input) { // The "name" value is filled... }, function () { // The "name" value is not filled... @@ -411,10 +410,10 @@ A second closure may be passed to the `whenFilled` method that will be executed To determine if a given key is absent from the request, you may use the `missing` and `whenMissing` methods: if ($request->missing('name')) { - // + // ... } - $request->whenMissing('name', function ($input) { + $request->whenMissing('name', function (array $input) { // The "name" value is missing... }, function () { // The "name" value is present... @@ -496,20 +495,19 @@ If you would like to disable string trimming and empty string conversion for a s ```php use App\Http\Middleware\TrimStrings; +use Illuminate\Http\Request; use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { - TrimStrings::skipWhen(function ($request) { + TrimStrings::skipWhen(function (Request $request) { return $request->is('admin/*'); }); - ConvertEmptyStringsToNull::skipWhen(function ($request) { + ConvertEmptyStringsToNull::skipWhen(function (Request $request) { // ... }); } @@ -530,7 +528,7 @@ You may retrieve uploaded files from an `Illuminate\Http\Request` instance using You may determine if a file is present on the request using the `hasFile` method: if ($request->hasFile('photo')) { - // + // ... } @@ -539,7 +537,7 @@ You may determine if a file is present on the request using the `hasFile` method In addition to checking if the file is present, you may verify that there were no problems uploading the file via the `isValid` method: if ($request->file('photo')->isValid()) { - // + // ... } @@ -639,9 +637,9 @@ The `TrustHosts` middleware is already included in the `$middleware` stack of yo /** * Get the host patterns that should be trusted. * - * @return array + * @return array */ - public function hosts() + public function hosts(): array { return [ 'laravel.test', diff --git a/responses.md b/responses.md index 06b232abd95..0981a591710 100644 --- a/responses.md +++ b/responses.md @@ -192,10 +192,8 @@ If you would like to customize the value that is placed in the route parameter, /** * Get the value of the model's route key. - * - * @return mixed */ - public function getRouteKey() + public function getRouteKey(): mixed { return $this->slug; } @@ -330,12 +328,10 @@ If you would like to define a custom response that you can re-use in a variety o { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - Response::macro('caps', function ($value) { + Response::macro('caps', function (string $value) { return Response::make(strtoupper($value)); }); } diff --git a/routing.md b/routing.md index 4aa397aab80..82dffc5d3dc 100644 --- a/routing.md +++ b/routing.md @@ -67,11 +67,11 @@ The router allows you to register routes that respond to any HTTP verb: Sometimes you may need to register a route that responds to multiple HTTP verbs. You may do so using the `match` method. Or, you may even register a route that responds to all HTTP verbs using the `any` method: Route::match(['get', 'post'], '/', function () { - // + // ... }); Route::any('/', function () { - // + // ... }); > **Note** @@ -169,14 +169,14 @@ php artisan route:list --only-vendor Sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters: - Route::get('/user/{id}', function ($id) { + Route::get('/user/{id}', function (string $id) { return 'User '.$id; }); You may define as many route parameters as required by your route: - Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) { - // + Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) { + // ... }); Route parameters are always encased within `{}` braces and should consist of alphabetic characters. Underscores (`_`) are also acceptable within route parameter names. Route parameters are injected into route callbacks / controllers based on their order - the names of the route callback / controller arguments do not matter. @@ -188,7 +188,7 @@ If your route has dependencies that you would like the Laravel service container use Illuminate\Http\Request; - Route::get('/user/{id}', function (Request $request, $id) { + Route::get('/user/{id}', function (Request $request, string $id) { return 'User '.$id; }); @@ -197,11 +197,11 @@ If your route has dependencies that you would like the Laravel service container Occasionally you may need to specify a route parameter that may not always be present in the URI. You may do so by placing a `?` mark after the parameter name. Make sure to give the route's corresponding variable a default value: - Route::get('/user/{name?}', function ($name = null) { + Route::get('/user/{name?}', function (string $name = null) { return $name; }); - Route::get('/user/{name?}', function ($name = 'John') { + Route::get('/user/{name?}', function (string $name = 'John') { return $name; }); @@ -210,38 +210,38 @@ Occasionally you may need to specify a route parameter that may not always be pr You may constrain the format of your route parameters using the `where` method on a route instance. The `where` method accepts the name of the parameter and a regular expression defining how the parameter should be constrained: - Route::get('/user/{name}', function ($name) { - // + Route::get('/user/{name}', function (string $name) { + // ... })->where('name', '[A-Za-z]+'); - Route::get('/user/{id}', function ($id) { - // + Route::get('/user/{id}', function (string $id) { + // ... })->where('id', '[0-9]+'); - Route::get('/user/{id}/{name}', function ($id, $name) { - // + Route::get('/user/{id}/{name}', function (string $id, string $name) { + // ... })->where(['id' => '[0-9]+', 'name' => '[a-z]+']); For convenience, some commonly used regular expression patterns have helper methods that allow you to quickly add pattern constraints to your routes: - Route::get('/user/{id}/{name}', function ($id, $name) { - // + Route::get('/user/{id}/{name}', function (string $id, string $name) { + // ... })->whereNumber('id')->whereAlpha('name'); - Route::get('/user/{name}', function ($name) { - // + Route::get('/user/{name}', function (string $name) { + // ... })->whereAlphaNumeric('name'); - Route::get('/user/{id}', function ($id) { - // + Route::get('/user/{id}', function (string $id) { + // ... })->whereUuid('id'); - Route::get('/user/{id}', function ($id) { + Route::get('/user/{id}', function (string $id) { // })->whereUlid('id'); - Route::get('/category/{category}', function ($category) { - // + Route::get('/category/{category}', function (string $category) { + // ... })->whereIn('category', ['movie', 'song', 'painting']); If the incoming request does not match the route pattern constraints, a 404 HTTP response will be returned. @@ -253,17 +253,15 @@ If you would like a route parameter to always be constrained by a given regular /** * Define your route model bindings, pattern filters, etc. - * - * @return void */ - public function boot() + public function boot(): void { Route::pattern('id', '[0-9]+'); } Once the pattern has been defined, it is automatically applied to all routes using that parameter name: - Route::get('/user/{id}', function ($id) { + Route::get('/user/{id}', function (string $id) { // Only executed if {id} is numeric... }); @@ -272,7 +270,7 @@ Once the pattern has been defined, it is automatically applied to all routes usi The Laravel routing component allows all characters except `/` to be present within route parameter values. You must explicitly allow `/` to be part of your placeholder using a `where` condition regular expression: - Route::get('/search/{search}', function ($search) { + Route::get('/search/{search}', function (string $search) { return $search; })->where('search', '.*'); @@ -285,7 +283,7 @@ The Laravel routing component allows all characters except `/` to be present wit Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route by chaining the `name` method onto the route definition: Route::get('/user/profile', function () { - // + // ... })->name('profile'); You may also specify route names for controller actions: @@ -313,16 +311,16 @@ Once you have assigned a name to a given route, you may use the route's name whe If the named route defines parameters, you may pass the parameters as the second argument to the `route` function. The given parameters will automatically be inserted into the generated URL in their correct positions: - Route::get('/user/{id}/profile', function ($id) { - // + Route::get('/user/{id}/profile', function (string $id) { + // ... })->name('profile'); $url = route('profile', ['id' => 1]); If you pass additional parameters in the array, those key / value pairs will automatically be added to the generated URL's query string: - Route::get('/user/{id}/profile', function ($id) { - // + Route::get('/user/{id}/profile', function (string $id) { + // ... })->name('profile'); $url = route('profile', ['id' => 1, 'photos' => 'yes']); @@ -337,17 +335,19 @@ If you pass additional parameters in the array, those key / value pairs will aut If you would like to determine if the current request was routed to a given named route, you may use the `named` method on a Route instance. For example, you may check the current route name from a route middleware: + use Closure; + use Illuminate\Http\Request; + use Symfony\Component\HttpFoundation\Response; + /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { if ($request->route()->named('profile')) { - // + // ... } return $next($request); @@ -393,8 +393,8 @@ If a group of routes all utilize the same [controller](/docs/{{version}}/control Route groups may also be used to handle subdomain routing. Subdomains may be assigned route parameters just like route URIs, allowing you to capture a portion of the subdomain for usage in your route or controller. The subdomain may be specified by calling the `domain` method before defining the group: Route::domain('{account}.example.com')->group(function () { - Route::get('user/{id}', function ($account, $id) { - // + Route::get('user/{id}', function (string $account, string $id) { + // ... }); }); @@ -482,10 +482,8 @@ If you would like model binding to always use a database column other than `id` /** * Get the route key for the model. - * - * @return string */ - public function getRouteKeyName() + public function getRouteKeyName(): string { return 'slug'; } @@ -580,10 +578,8 @@ You are not required to use Laravel's implicit, convention based model resolutio /** * Define your route model bindings, pattern filters, etc. - * - * @return void */ - public function boot() + public function boot(): void { Route::model('user', User::class); @@ -595,7 +591,7 @@ Next, define a route that contains a `{user}` parameter: use App\Models\User; Route::get('/users/{user}', function (User $user) { - // + // ... }); Since we have bound all `{user}` parameters to the `App\Models\User` model, an instance of that class will be injected into the route. So, for example, a request to `users/1` will inject the `User` instance from the database which has an ID of `1`. @@ -612,12 +608,10 @@ If you wish to define your own model binding resolution logic, you may use the ` /** * Define your route model bindings, pattern filters, etc. - * - * @return void */ - public function boot() + public function boot(): void { - Route::bind('user', function ($value) { + Route::bind('user', function (string $value) { return User::where('name', $value)->firstOrFail(); }); @@ -659,7 +653,7 @@ If a route is utilizing [implicit binding scoping](#implicit-model-binding-scopi Using the `Route::fallback` method, you may define a route that will be executed when no other route matches the incoming request. Typically, unhandled requests will automatically render a "404" page via your application's exception handler. However, since you would typically define the `fallback` route within your `routes/web.php` file, all middleware in the `web` middleware group will apply to the route. You are free to add additional middleware to this route as needed: Route::fallback(function () { - // + // ... }); > **Warning** @@ -681,10 +675,8 @@ Rate limiters are defined using the `RateLimiter` facade's `for` method. The `fo /** * Configure the rate limiters for the application. - * - * @return void */ - protected function configureRateLimiting() + protected function configureRateLimiting(): void { RateLimiter::for('global', function (Request $request) { return Limit::perMinute(1000); @@ -745,11 +737,11 @@ Rate limiters may be attached to routes or route groups using the `throttle` [mi Route::middleware(['throttle:uploads'])->group(function () { Route::post('/audio', function () { - // + // ... }); Route::post('/video', function () { - // + // ... }); }); diff --git a/sanctum.md b/sanctum.md index 0d901c8ee3c..88571900424 100644 --- a/sanctum.md +++ b/sanctum.md @@ -110,10 +110,8 @@ Then, you may instruct Sanctum to use your custom model via the `usePersonalAcce /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class); } @@ -151,7 +149,7 @@ To issue a token, you may use the `createToken` method. The `createToken` method You may access all of the user's tokens using the `tokens` Eloquent relationship provided by the `HasApiTokens` trait: foreach ($user->tokens as $token) { - // + // ... } @@ -164,7 +162,7 @@ Sanctum allows you to assign "abilities" to tokens. Abilities serve a similar pu When handling an incoming request authenticated by Sanctum, you may determine if the token has a given ability using the `tokenCan` method: if ($user->tokenCan('server:update')) { - // + // ... } @@ -436,7 +434,7 @@ While testing, the `Sanctum::actingAs` method may be used to authenticate a user use App\Models\User; use Laravel\Sanctum\Sanctum; - public function test_task_list_can_be_retrieved() + public function test_task_list_can_be_retrieved(): void { Sanctum::actingAs( User::factory()->create(), diff --git a/scheduling.md b/scheduling.md index 3ff6f1bbdeb..6c0e313b9f0 100644 --- a/scheduling.md +++ b/scheduling.md @@ -41,11 +41,8 @@ You may define all of your scheduled tasks in the `schedule` method of your appl { /** * Define the application's command schedule. - * - * @param \Illuminate\Console\Scheduling\Schedule $schedule - * @return void */ - protected function schedule(Schedule $schedule) + protected function schedule(Schedule $schedule): void { $schedule->call(function () { DB::table('recent_users')->delete(); @@ -142,7 +139,7 @@ These methods may be combined with additional constraints to create even more fi // Run once per week on Monday at 1 PM... $schedule->call(function () { - // + // ... })->weekly()->mondays()->at('13:00'); // Run hourly from 8 AM to 5 PM on weekdays... @@ -240,12 +237,12 @@ Using the `timezone` method, you may specify that a scheduled task's time should If you are repeatedly assigning the same timezone to all of your scheduled tasks, you may wish to define a `scheduleTimezone` method in your `App\Console\Kernel` class. This method should return the default timezone that should be assigned to all scheduled tasks: + use DateTimeZone; + /** * Get the timezone that should be used by default for scheduled events. - * - * @return \DateTimeZone|string|null */ - protected function scheduleTimezone() + protected function scheduleTimezone(): DateTimeZone|string|null { return 'America/Chicago'; } diff --git a/scout.md b/scout.md index a391bf20c1f..66642ef9811 100644 --- a/scout.md +++ b/scout.md @@ -141,10 +141,8 @@ Each Eloquent model is synced with a given search "index", which contains all of /** * Get the name of the index associated with the model. - * - * @return string */ - public function searchableAs() + public function searchableAs(): string { return 'posts_index'; } @@ -169,9 +167,9 @@ By default, the entire `toArray` form of a given model will be persisted to its /** * Get the indexable data array for the model. * - * @return array + * @return array */ - public function toSearchableArray() + public function toSearchableArray(): array { $array = $this->toArray(); @@ -252,20 +250,16 @@ By default, Scout will use the primary key of the model as the model's unique ID /** * Get the value used to index the model. - * - * @return mixed */ - public function getScoutKey() + public function getScoutKey(): mixed { return $this->email; } /** * Get the key name used to index the model. - * - * @return mixed */ - public function getScoutKeyName() + public function getScoutKeyName(): mixed { return 'email'; } @@ -281,6 +275,7 @@ When searching, Scout will typically use the default search engine specified in namespace App\Models; use Illuminate\Database\Eloquent\Model; + use Laravel\Scout\Engines\Engine; use Laravel\Scout\EngineManager; use Laravel\Scout\Searchable; @@ -290,10 +285,8 @@ When searching, Scout will typically use the default search engine specified in /** * Get the engine used to index the model. - * - * @return \Laravel\Scout\Engines\Engine */ - public function searchableUsing() + public function searchableUsing(): Engine { return app(EngineManager::class)->engine('meilisearch'); } @@ -342,11 +335,11 @@ use Laravel\Scout\Attributes\SearchUsingPrefix; /** * Get the indexable data array for the model. * - * @return array + * @return array */ #[SearchUsingPrefix(['id', 'email'])] #[SearchUsingFullText(['bio'])] -public function toSearchableArray() +public function toSearchableArray(): array { return [ 'id' => $this->id, @@ -404,11 +397,8 @@ If you would like to modify the query that is used to retrieve all of your model /** * Modify the query used to retrieve models when making all of the models searchable. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @return \Illuminate\Database\Eloquent\Builder */ - protected function makeAllSearchableUsing($query) + protected function makeAllSearchableUsing(Builder $query): Builder { return $query->with('author'); } @@ -512,10 +502,8 @@ Sometimes you may need to only make a model searchable under certain conditions. /** * Determine if the model should be searchable. - * - * @return bool */ - public function shouldBeSearchable() + public function shouldBeSearchable(): bool { return $this->isPublished(); } @@ -660,9 +648,10 @@ After Scout retrieves a list of matching Eloquent models from your application's ```php use App\Models\Order; +use Illuminate\Database\Eloquent\Builder; $orders = Order::search('Star Trek') - ->query(fn ($query) => $query->with('invoices')) + ->query(fn (Builder $query) => $query->with('invoices')) ->get(); ``` @@ -694,15 +683,13 @@ You may find it helpful to review the implementations of these methods on the `L Once you have written your custom engine, you may register it with Scout using the `extend` method of the Scout engine manager. Scout's engine manager may be resolved from the Laravel service container. You should call the `extend` method from the `boot` method of your `App\Providers\AppServiceProvider` class or any other service provider used by your application: - use App\ScoutExtensions\MySqlSearchEngine + use App\ScoutExtensions\MySqlSearchEngine; use Laravel\Scout\EngineManager; /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { resolve(EngineManager::class)->extend('mysql', function () { return new MySqlSearchEngine; @@ -724,10 +711,8 @@ If you would like to define a custom Scout search builder method, you may use th /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Builder::macro('count', function () { return $this->engine()->getTotalCount( diff --git a/seeding.md b/seeding.md index aa3cee553dd..5f305e2a1b7 100644 --- a/seeding.md +++ b/seeding.md @@ -41,10 +41,8 @@ As an example, let's modify the default `DatabaseSeeder` class and add a databas { /** * Run the database seeders. - * - * @return void */ - public function run() + public function run(): void { DB::table('users')->insert([ 'name' => Str::random(10), @@ -68,10 +66,8 @@ For example, let's create 50 users that each has one related post: /** * Run the database seeders. - * - * @return void */ - public function run() + public function run(): void { User::factory() ->count(50) @@ -86,10 +82,8 @@ Within the `DatabaseSeeder` class, you may use the `call` method to execute addi /** * Run the database seeders. - * - * @return void */ - public function run() + public function run(): void { $this->call([ UserSeeder::class, @@ -116,10 +110,8 @@ While running seeds, you may want to prevent models from dispatching events. You /** * Run the database seeders. - * - * @return void */ - public function run() + public function run(): void { $this->call([ UserSeeder::class, diff --git a/session.md b/session.md index 086ef9f070d..5b6cc64e12c 100644 --- a/session.md +++ b/session.md @@ -50,7 +50,10 @@ The session `driver` configuration option defines where session data will be sto When using the `database` session driver, you will need to create a table to contain the session records. An example `Schema` declaration for the table may be found below: - Schema::create('sessions', function ($table) { + use Illuminate\Database\Schema\Blueprint; + use Illuminate\Support\Facades\Schema; + + Schema::create('sessions', function (Blueprint $table) { $table->string('id')->primary(); $table->foreignId('user_id')->nullable()->index(); $table->string('ip_address', 45)->nullable(); @@ -89,21 +92,22 @@ There are two primary ways of working with session data in Laravel: the global ` use App\Http\Controllers\Controller; use Illuminate\Http\Request; + use Illuminate\View\View; class UserController extends Controller { /** * Show the profile for the given user. - * - * @param Request $request - * @param int $id - * @return Response */ - public function show(Request $request, $id) + public function show(Request $request, string $id): View { $value = $request->session()->get('key'); - // + // ... + + $user = $this->users->find($id); + + return view('user.profile', ['user' => $user]); } } @@ -147,19 +151,19 @@ If you would like to retrieve all the data in the session, you may use the `all` To determine if an item is present in the session, you may use the `has` method. The `has` method returns `true` if the item is present and is not `null`: if ($request->session()->has('users')) { - // + // ... } To determine if an item is present in the session, even if its value is `null`, you may use the `exists` method: if ($request->session()->exists('users')) { - // + // ... } To determine if an item is not present in the session, you may use the `missing` method. The `missing` method returns `true` if the item is not present: if ($request->session()->missing('users')) { - // + // ... } @@ -254,11 +258,11 @@ By default, Laravel allows requests using the same session to execute concurrent To mitigate this, Laravel provides functionality that allows you to limit concurrent requests for a given session. To get started, you may simply chain the `block` method onto your route definition. In this example, an incoming request to the `/profile` endpoint would acquire a session lock. While this lock is being held, any incoming requests to the `/profile` or `/order` endpoints which share the same session ID will wait for the first request to finish executing before continuing their execution: Route::post('/profile', function () { - // + // ... })->block($lockSeconds = 10, $waitSeconds = 10) Route::post('/order', function () { - // + // ... })->block($lockSeconds = 10, $waitSeconds = 10) The `block` method accepts two optional arguments. The first argument accepted by the `block` method is the maximum number of seconds the session lock should be held for before it is released. Of course, if the request finishes executing before this time the lock will be released earlier. @@ -268,7 +272,7 @@ The second argument accepted by the `block` method is the number of seconds a re If neither of these arguments is passed, the lock will be obtained for a maximum of 10 seconds and requests will wait a maximum of 10 seconds while attempting to obtain a lock: Route::post('/profile', function () { - // + // ... })->block() @@ -319,6 +323,7 @@ Once your driver has been implemented, you are ready to register it with Laravel namespace App\Providers; use App\Extensions\MongoSessionHandler; + use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Facades\Session; use Illuminate\Support\ServiceProvider; @@ -326,22 +331,18 @@ Once your driver has been implemented, you are ready to register it with Laravel { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - Session::extend('mongo', function ($app) { + Session::extend('mongo', function (Application $app) { // Return an implementation of SessionHandlerInterface... return new MongoSessionHandler; }); diff --git a/telescope.md b/telescope.md index 77d2fd39fe4..a9f0858400a 100644 --- a/telescope.md +++ b/telescope.md @@ -78,10 +78,8 @@ After running `telescope:install`, you should remove the `TelescopeServiceProvid /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { if ($this->app->environment('local')) { $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class); @@ -126,16 +124,16 @@ By default, all entries older than 24 hours will be pruned. You may use the `hou The Telescope dashboard may be accessed at the `/telescope` route. By default, you will only be able to access this dashboard in the `local` environment. Within your `app/Providers/TelescopeServiceProvider.php` file, there is an [authorization gate](/docs/{{version}}/authorization#gates) definition. This authorization gate controls access to Telescope in **non-local** environments. You are free to modify this gate as needed to restrict access to your Telescope installation: + use App\Models\User; + /** * Register the Telescope gate. * * This gate determines who can access Telescope in non-local environments. - * - * @return void */ - protected function gate() + protected function gate(): void { - Gate::define('viewTelescope', function ($user) { + Gate::define('viewTelescope', function (User $user) { return in_array($user->email, [ 'taylor@laravel.com', ]); @@ -181,10 +179,8 @@ You may filter the data that is recorded by Telescope via the `filter` closure t /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { $this->hideSensitiveRequestDetails(); @@ -207,14 +203,13 @@ You may filter the data that is recorded by Telescope via the `filter` closure t While the `filter` closure filters data for individual entries, you may use the `filterBatch` method to register a closure that filters all data for a given request or console command. If the closure returns `true`, all of the entries are recorded by Telescope: use Illuminate\Support\Collection; + use Laravel\Telescope\IncomingEntry; use Laravel\Telescope\Telescope; /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { $this->hideSensitiveRequestDetails(); @@ -223,7 +218,7 @@ While the `filter` closure filters data for individual entries, you may use the return true; } - return $entries->contains(function ($entry) { + return $entries->contains(function (IncomingEntry $entry) { return $entry->isReportableException() || $entry->isFailedJob() || $entry->isScheduledTask() || @@ -243,10 +238,8 @@ Telescope allows you to search entries by "tag". Often, tags are Eloquent model /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { $this->hideSensitiveRequestDetails(); @@ -429,14 +422,12 @@ The Telescope dashboard displays the user avatar for the user that was authentic /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { // ... - Telescope::avatar(function ($id, $email) { + Telescope::avatar(function (string $id, string $email) { return '/avatars/'.User::find($id)->avatar_path; }); } diff --git a/testing.md b/testing.md index 886cc133f5b..00572e4881f 100644 --- a/testing.md +++ b/testing.md @@ -72,10 +72,8 @@ Once the test has been generated, you may define test methods as you normally wo { /** * A basic test example. - * - * @return void */ - public function test_basic_test() + public function test_basic_test(): void { $this->assertTrue(true); } @@ -148,34 +146,33 @@ Using the `ParallelTesting` facade, you may specify code to be executed on the ` use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\ParallelTesting; use Illuminate\Support\ServiceProvider; + use PHPUnit\Framework\TestCase; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - ParallelTesting::setUpProcess(function ($token) { + ParallelTesting::setUpProcess(function (int $token) { // ... }); - ParallelTesting::setUpTestCase(function ($token, $testCase) { + ParallelTesting::setUpTestCase(function (int $token, TestCase $testCase) { // ... }); // Executed when a test database is created... - ParallelTesting::setUpTestDatabase(function ($database, $token) { + ParallelTesting::setUpTestDatabase(function (string $database, int $token) { Artisan::call('db:seed'); }); - ParallelTesting::tearDownTestCase(function ($token, $testCase) { + ParallelTesting::tearDownTestCase(function (int $token, TestCase $testCase) { // ... }); - ParallelTesting::tearDownProcess(function ($token) { + ParallelTesting::tearDownProcess(function (int $token) { // ... }); } diff --git a/urls.md b/urls.md index 504081eb9f4..26c655fc46d 100644 --- a/urls.md +++ b/urls.md @@ -54,7 +54,7 @@ Each of these methods may also be accessed via the `URL` [facade](/docs/{{versio The `route` helper may be used to generate URLs to [named routes](/docs/{{version}}/routing#named-routes). Named routes allow you to generate URLs without being coupled to the actual URL defined on the route. Therefore, if the route's URL changes, no changes need to be made to your calls to the `route` function. For example, imagine your application contains a route defined like the following: Route::get('/post/{post}', function (Post $post) { - // + // ... })->name('post.show'); To generate a URL to this route, you may use the `route` helper like so: @@ -66,7 +66,7 @@ To generate a URL to this route, you may use the `route` helper like so: Of course, the `route` helper may also be used to generate URLs for routes with multiple parameters: Route::get('/post/{post}/comment/{comment}', function (Post $post, Comment $comment) { - // + // ... })->name('comment.show'); echo route('comment.show', ['post' => 1, 'comment' => 3]); @@ -154,10 +154,8 @@ When someone visits a signed URL that has expired, they will receive a generic e /** * Register the exception handling callbacks for the application. - * - * @return void */ - public function register() + public function register(): void { $this->renderable(function (InvalidSignatureException $e) { return response()->view('error.link-expired', [], 403); @@ -183,7 +181,7 @@ If the controller method accepts route parameters, you may pass an associative a For some applications, you may wish to specify request-wide default values for certain URL parameters. For example, imagine many of your routes define a `{locale}` parameter: Route::get('/{locale}/posts', function () { - // + // ... })->name('post.index'); It is cumbersome to always pass the `locale` every time you call the `route` helper. So, you may use the `URL::defaults` method to define a default value for this parameter that will always be applied during the current request. You may wish to call this method from a [route middleware](/docs/{{version}}/middleware#assigning-middleware-to-routes) so that you have access to the current request: @@ -193,18 +191,18 @@ It is cumbersome to always pass the `locale` every time you call the `route` hel namespace App\Http\Middleware; use Closure; + use Illuminate\Http\Request; use Illuminate\Support\Facades\URL; + use Symfony\Component\HttpFoundation\Response; class SetDefaultLocaleForUrls { /** - * Handle the incoming request. + * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return \Illuminate\Http\Response + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next): Response { URL::defaults(['locale' => $request->user()->locale]); diff --git a/validation.md b/validation.md index 71d22e45726..518cb7da21a 100644 --- a/validation.md +++ b/validation.md @@ -70,29 +70,30 @@ Next, let's take a look at a simple controller that handles incoming requests to namespace App\Http\Controllers; use App\Http\Controllers\Controller; + use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; + use Illuminate\View\View; class PostController extends Controller { /** * Show the form to create a new blog post. - * - * @return \Illuminate\View\View */ - public function create() + public function create(): View { return view('post.create'); } /** * Store a new blog post. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): RedirectResponse { // Validate and store the blog post... + + $post = /** ... */ + + return to_route('post.show', ['post' => $post->id]); } } @@ -107,11 +108,8 @@ To get a better understanding of the `validate` method, let's jump back into the /** * Store a new blog post. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ - public function store(Request $request) + public function store(Request $request): Response { $validated = $request->validate([ 'title' => 'required|unique:posts|max:255', @@ -119,6 +117,8 @@ To get a better understanding of the `validate` method, let's jump back into the ]); // The blog post is valid... + + return response()->noContent(); } As you can see, the validation rules are passed into the `validate` method. Don't worry - all available validation rules are [documented](#available-validation-rules). Again, if the validation fails, the proper response will automatically be generated. If the validation passes, our controller will continue executing normally. @@ -307,9 +307,9 @@ As you might have guessed, the `authorize` method is responsible for determining /** * Get the validation rules that apply to the request. * - * @return array + * @return array */ - public function rules() + public function rules(): array { return [ 'title' => 'required|unique:posts|max:255', @@ -324,11 +324,8 @@ So, how are the validation rules evaluated? All you need to do is type-hint the /** * Store a new blog post. - * - * @param \App\Http\Requests\StorePostRequest $request - * @return Illuminate\Http\Response */ - public function store(StorePostRequest $request) + public function store(StorePostRequest $request): Response { // The incoming request is valid... @@ -338,6 +335,10 @@ So, how are the validation rules evaluated? All you need to do is type-hint the // Retrieve a portion of the validated input data... $validated = $request->safe()->only(['name', 'email']); $validated = $request->safe()->except(['name', 'email']); + + // Store the blog post... + + return response()->noContent(); } If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an XHR request, an HTTP response with a 422 status code will be returned to the user including a [JSON representation of the validation errors](#validation-error-response-format). @@ -347,15 +348,14 @@ If validation fails, a redirect response will be generated to send the user back If you would like to add an "after" validation hook to a form request, you may use the `withValidator` method. This method receives the fully constructed validator, allowing you to call any of its methods before the validation rules are actually evaluated: + use Illuminate\Validation\Validator; + /** * Configure the validator instance. - * - * @param \Illuminate\Validation\Validator $validator - * @return void */ - public function withValidator($validator) + public function withValidator(Validator $validator): void { - $validator->after(function ($validator) { + $validator->after(function (Validator $validator) { if ($this->somethingElseIsInvalid()) { $validator->errors()->add('field', 'Something is wrong with this field!'); } @@ -405,10 +405,8 @@ The form request class also contains an `authorize` method. Within this method, /** * Determine if the user is authorized to make this request. - * - * @return bool */ - public function authorize() + public function authorize(): bool { $comment = Comment::find($this->route('comment')); @@ -429,10 +427,8 @@ If you plan to handle authorization logic for the request in another part of you /** * Determine if the user is authorized to make this request. - * - * @return bool */ - public function authorize() + public function authorize(): bool { return true; } @@ -448,9 +444,9 @@ You may customize the error messages used by the form request by overriding the /** * Get the error messages for the defined validation rules. * - * @return array + * @return array */ - public function messages() + public function messages(): array { return [ 'title.required' => 'A title is required', @@ -466,9 +462,9 @@ Many of Laravel's built-in validation rule error messages contain an `:attribute /** * Get custom attributes for validator errors. * - * @return array + * @return array */ - public function attributes() + public function attributes(): array { return [ 'email' => 'email address', @@ -484,10 +480,8 @@ If you need to prepare or sanitize any data from the request before you apply yo /** * Prepare the data for validation. - * - * @return void */ - protected function prepareForValidation() + protected function prepareForValidation(): void { $this->merge([ 'slug' => Str::slug($this->slug), @@ -505,17 +499,15 @@ If you do not want to use the `validate` method on the request, you may create a use App\Http\Controllers\Controller; use Illuminate\Http\Request; + use Illuminate\Http\Response; use Illuminate\Support\Facades\Validator; class PostController extends Controller { /** * Store a new blog post. - * - * @param Request $request - * @return Response */ - public function store(Request $request) + public function store(Request $request): Response { $validator = Validator::make($request->all(), [ 'title' => 'required|unique:posts|max:255', @@ -536,6 +528,8 @@ If you do not want to use the `validate` method on the request, you may create a $validated = $validator->safe()->except(['name', 'email']); // Store the blog post... + + return response()->noContent(); } } @@ -622,9 +616,12 @@ Many of Laravel's built-in error messages include an `:attribute` placeholder th You may also attach callbacks to be run after validation is completed. This allows you to easily perform further validation and even add more error messages to the message collection. To get started, call the `after` method on a validator instance: - $validator = Validator::make(/* ... */); + use Illuminate\Support\Facades; + use Illuminate\Validation\Validator; - $validator->after(function ($validator) { + $validator = Facades\Validator::make(/* ... */); + + $validator->after(function (Validator $validator) { if ($this->somethingElseIsInvalid()) { $validator->errors()->add( 'field', 'Something is wrong with this field!' @@ -633,7 +630,7 @@ You may also attach callbacks to be run after validation is completed. This allo }); if ($validator->fails()) { - // + // ... } @@ -657,7 +654,7 @@ In addition, the `Illuminate\Support\ValidatedInput` instance may be iterated ov // Validated data may be iterated... foreach ($request->safe() as $key => $value) { - // + // ... } // Validated data may be accessed as an array... @@ -693,13 +690,13 @@ To retrieve the first error message for a given field, use the `first` method: If you need to retrieve an array of all the messages for a given field, use the `get` method: foreach ($errors->get('email') as $message) { - // + // ... } If you are validating an array form field, you may retrieve all of the messages for each of the array elements using the `*` character: foreach ($errors->get('attachments.*') as $message) { - // + // ... } @@ -708,7 +705,7 @@ If you are validating an array form field, you may retrieve all of the messages To retrieve an array of all messages for all fields, use the `all` method: foreach ($errors->all() as $message) { - // + // ... } @@ -717,7 +714,7 @@ To retrieve an array of all messages for all fields, use the `all` method: The `has` method may be used to determine if any error messages exist for a given field: if ($errors->has('email')) { - // + // ... } @@ -1220,13 +1217,14 @@ Instead of specifying the table name directly, you may specify the Eloquent mode If you would like to customize the query executed by the validation rule, you may use the `Rule` class to fluently define the rule. In this example, we'll also specify the validation rules as an array instead of using the `|` character to delimit them: + use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; Validator::make($data, [ 'email' => [ 'required', - Rule::exists('staff')->where(function ($query) { + Rule::exists('staff')->where(function (Builder $query) { return $query->where('account_id', 1); }), ], @@ -1613,6 +1611,7 @@ Sometimes, you may wish to ignore a given ID during unique validation. For examp To instruct the validator to ignore the user's ID, we'll use the `Rule` class to fluently define the rule. In this example, we'll also specify the validation rules as an array instead of using the `|` character to delimit the rules: + use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; @@ -1636,13 +1635,13 @@ If your table uses a primary key column name other than `id`, you may specify th By default, the `unique` rule will check the uniqueness of the column matching the name of the attribute being validated. However, you may pass a different column name as the second argument to the `unique` method: - Rule::unique('users', 'email_address')->ignore($user->id), + Rule::unique('users', 'email_address')->ignore($user->id) **Adding Additional Where Clauses:** You may specify additional query conditions by customizing the query using the `where` method. For example, let's add a query condition that scopes the query to only search records that have an `account_id` column value of `1`: - 'email' => Rule::unique('users')->where(fn ($query) => $query->where('account_id', 1)) + 'email' => Rule::unique('users')->where(fn (Builder $query) => $query->where('account_id', 1)) #### uppercase @@ -1716,13 +1715,15 @@ Sometimes you may wish to add validation rules based on more complex conditional Let's assume our web application is for game collectors. If a game collector registers with our application and they own more than 100 games, we want them to explain why they own so many games. For example, perhaps they run a game resale shop, or maybe they just enjoy collecting games. To conditionally add this requirement, we can use the `sometimes` method on the `Validator` instance. - $validator->sometimes('reason', 'required|max:500', function ($input) { + use Illuminate\Support\Fluent; + + $validator->sometimes('reason', 'required|max:500', function (Fluent $input) { return $input->games >= 100; }); The first argument passed to the `sometimes` method is the name of the field we are conditionally validating. The second argument is a list of the rules we want to add. If the closure passed as the third argument returns `true`, the rules will be added. This method makes it a breeze to build complex conditional validations. You may even add conditional validations for several fields at once: - $validator->sometimes(['reason', 'cost'], 'required', function ($input) { + $validator->sometimes(['reason', 'cost'], 'required', function (Fluent $input) { return $input->games >= 100; }); @@ -1747,11 +1748,11 @@ Sometimes you may want to validate a field based on another field in the same ne ], ]; - $validator->sometimes('channels.*.address', 'email', function ($input, $item) { + $validator->sometimes('channels.*.address', 'email', function (Fluent $input, Fluent $item) { return $item->type === 'email'; }); - $validator->sometimes('channels.*.address', 'url', function ($input, $item) { + $validator->sometimes('channels.*.address', 'url', function (Fluent $input, Fluent $item) { return $item->type !== 'email'; }); @@ -1814,7 +1815,7 @@ Sometimes you may need to access the value for a given nested array element when use Illuminate\Validation\Rule; $validator = Validator::make($request->all(), [ - 'companies.*.id' => Rule::forEach(function ($value, $attribute) { + 'companies.*.id' => Rule::forEach(function (string|null $value, string $attribute) { return [ Rule::exists(Company::class, 'id'), new HasPermission('manage-company', $value), @@ -1951,10 +1952,8 @@ use Illuminate\Validation\Rules\Password; /** * Bootstrap any application services. - * - * @return void */ -public function boot() +public function boot(): void { Password::defaults(function () { $rule = Password::min(8); @@ -1998,19 +1997,15 @@ Once the rule has been created, we are ready to define its behavior. A rule obje namespace App\Rules; + use Closure; use Illuminate\Contracts\Validation\InvokableRule; class Uppercase implements InvokableRule { /** * Run the validation rule. - * - * @param string $attribute - * @param mixed $value - * @param \Closure $fail - * @return void */ - public function __invoke($attribute, $value, $fail) + public function __invoke(string $attribute, mixed $value, Closure $fail): void { if (strtoupper($value) !== $value) { $fail('The :attribute must be uppercase.'); @@ -2056,7 +2051,7 @@ If your custom validation rule class needs to access all of the other data under /** * All of the data under validation. * - * @var array + * @var array */ protected $data = []; @@ -2065,10 +2060,10 @@ If your custom validation rule class needs to access all of the other data under /** * Set the data under validation. * - * @param array $data + * @param array $data * @return $this */ - public function setData($data) + public function setData(array $data): static { $this->data = $data; @@ -2084,6 +2079,7 @@ Or, if your validation rule requires access to the validator instance performing use Illuminate\Contracts\Validation\InvokableRule; use Illuminate\Contracts\Validation\ValidatorAwareRule; + use Illuminate\Validation\Validator; class Uppercase implements InvokableRule, ValidatorAwareRule { @@ -2098,11 +2094,8 @@ Or, if your validation rule requires access to the validator instance performing /** * Set the current validator. - * - * @param \Illuminate\Validation\Validator $validator - * @return $this */ - public function setValidator($validator) + public function setValidator(Validator $validator): static { $this->validator = $validator; @@ -2121,7 +2114,7 @@ If you only need the functionality of a custom rule once throughout your applica 'title' => [ 'required', 'max:255', - function ($attribute, $value, $fail) { + function (string $attribute, string|null $value, Closure $fail) { if ($value === 'foo') { $fail('The '.$attribute.' is invalid.'); } diff --git a/verification.md b/verification.md index 3b489041d27..2e0c85b2c64 100644 --- a/verification.md +++ b/verification.md @@ -135,14 +135,12 @@ To get started, pass a closure to the `toMailUsing` method provided by the `Illu /** * Register any authentication / authorization services. - * - * @return void */ - public function boot() + public function boot(): void { // ... - VerifyEmail::toMailUsing(function ($notifiable, $url) { + VerifyEmail::toMailUsing(function (object $notifiable, string $url) { return (new MailMessage) ->subject('Verify Email Address') ->line('Click the button below to verify your email address.') diff --git a/views.md b/views.md index f3c0da56b50..e0ad54f993a 100644 --- a/views.md +++ b/views.md @@ -91,7 +91,7 @@ If you need to determine if a view exists, you may use the `View` facade. The `e use Illuminate\Support\Facades\View; if (View::exists('emails.customer')) { - // + // ... } @@ -124,20 +124,16 @@ Occasionally, you may need to share data with all views that are rendered by you { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { View::share('key', 'value'); } @@ -157,34 +153,35 @@ We'll use the `View` facade's `composer` method to register the view composer. L namespace App\Providers; use App\View\Composers\ProfileComposer; - use Illuminate\Support\Facades\View; + use Illuminate\Support\Facades; use Illuminate\Support\ServiceProvider; + use Illuminate\View\View; class ViewServiceProvider extends ServiceProvider { /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { - // + // ... } /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { // Using class based composers... - View::composer('profile', ProfileComposer::class); + Facades\View::composer('profile', ProfileComposer::class); // Using closure based composers... - View::composer('dashboard', function ($view) { - // + Facades\View::composer('welcome', function (View $view) { + // ... + }); + + Facades\View::composer('dashboard', function (View $view) { + // ... }); } } @@ -212,9 +209,6 @@ Now that we have registered the composer, the `compose` method of the `App\View\ /** * Create a new profile composer. - * - * @param \App\Repositories\UserRepository $users - * @return void */ public function __construct(UserRepository $users) { @@ -223,11 +217,8 @@ Now that we have registered the composer, the `compose` method of the `App\View\ /** * Bind data to the view. - * - * @param \Illuminate\View\View $view - * @return void */ - public function compose(View $view) + public function compose(View $view): void { $view->with('count', $this->users->count()); } @@ -241,6 +232,7 @@ As you can see, all view composers are resolved via the [service container](/doc 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: use App\Views\Composers\MultiComposer; + use Illuminate\Support\Facades\View; View::composer( ['profile', 'dashboard'], @@ -249,8 +241,11 @@ You may attach a view composer to multiple views at once by passing an array of The `composer` method also accepts the `*` character as a wildcard, allowing you to attach a composer to all views: - View::composer('*', function ($view) { - // + use Illuminate\Support\Facades; + use Illuminate\View\View; + + Facades\View::composer('*', function (View $view) { + // ... }); diff --git a/vite.md b/vite.md index df2b312df80..7e1214c109e 100644 --- a/vite.md +++ b/vite.md @@ -471,12 +471,10 @@ It is common in JavaScript applications to [create aliases](#aliases) to regular /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { - Vite::macro('image', fn ($asset) => $this->asset("resources/images/{$asset}")); + Vite::macro('image', fn (string $asset) => $this->asset("resources/images/{$asset}")); } Once a macro has been defined, it can be invoked within your templates. For example, we can use the `image` macro defined above to reference an asset located at `resources/images/logo.png`: @@ -529,7 +527,7 @@ use Tests\TestCase; class ExampleTest extends TestCase { - public function test_without_vite_example() + public function test_without_vite_example(): void { $this->withoutVite(); @@ -613,18 +611,18 @@ If you wish to include a [`nonce` attribute](https://developer.mozilla.org/en-US namespace App\Http\Middleware; use Closure; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Vite; +use Symfony\Component\HttpFoundation\Response; class AddContentSecurityPolicyHeaders { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed + * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next, string $role): Response { Vite::useCspNonce();