Extend Request Class in Laravel 5

Extend Request class in Laravel 5

Here is Official Document: Request Lifecycle

Content of app/Http/CustomRequest.php

<?php namespace App\Http;

use Illuminate\Http\Request as BaseRequest;

class CustomRequest extends BaseRequest {
// coding
}

add this line to public/index.php

$app->alias('request', 'App\Http\CustomRequest');

after

app = require_once __DIR__.'/../bootstrap/app.php';

change the code at public/index.php

Illuminate\Http\Request::capture()

to

App\Http\CustomRequest::capture()

How to extend validation form request in Laravel 5.2?

You can extend your CreateUserRequest class like this:

<?php

namespace App\Http\Requests;

use CreateUserRequest;

Class OtherCreateUserRequest extends CreateUserRequest {

public function rules()
{
return parent::rules() + [
'additional' => 'rule',
];
}
}

How to set custom response for selected Request class in Laravel 5.5

If you want to customize validation response only for selected Request class, you need to add failedValidation() message to this class:

protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
$response = new JsonResponse(['data' => [],
'meta' => [
'message' => 'The given data is invalid',
'errors' => $validator->errors()
]], 422);

throw new \Illuminate\Validation\ValidationException($validator, $response);
}

This way you don't need to change anything in Handler and have this custom response only for this single class.

And if you want to change format globally for all responses you should add to app\Exceptions\Handler.php file the following method:

protected function invalidJson($request, ValidationException $exception)
{
return response()->json([
'data' => [],
'meta' => [
'message' => 'The given data is invalid',
'errors' => $exception->errors()
]
], $exception->status);
}

You can read about this also in Upgrade guide in Exception Format section

Extended Request class's attributes are empty - Laravel

Found the solution:

You have to use FormRequest not Request

use Illuminate\Foundation\Http\FormRequest;

Extended Request missing data when reaching controller with type-hint

This is kind of tricky.

First of all, you need to be familiar with the service container and dependency injection. Here is the full doc: https://laravel.com/docs/8.x/container


When you type hint a class inside a controller method, Laravel will try to understand what it should do with it.

If nothing is registered inside the service container, it will try to make a new instance of it.

\Illuminate\Http\Request is bound as a singleton (https://laravel.com/docs/8.x/container#binding-a-singleton).

While a simple bind will return a new instance at each call, a singleton will always return the exact same instance.

Here is a quick demo:

\App\Models\User::class is a class that is not explicitly bound.

When you try to resolve it using the service container, it will not find it and will try to make a new instance:

$u1 = app(\App\Models\User::class);
// Searching \App\Models\User::class...
// Cannot find \App\Models\User::class...
// returning new \App\Models\User();

$u2 = app(\App\Models\User::class);
// same process again

$u3 = app(\App\Models\User::class);
// and again

// You can check these instances are indeed different by checking their hash:
dd(
spl_object_hash($u1), // 000000004af5213500000000220f0bc0 (52135)
spl_object_hash($u2), // 000000004af5213400000000220f0bc0 (52134)
spl_object_hash($u3) // 000000004af5213700000000220f0bc0 (52137)
);

But since \Illuminate\Http\Request::class is bound by Laravel, it follows a different path:

$r1 = app(\Illuminate\Http\Request::class);
// Searching \Illuminate\Http\Request::class...
// Found it! Bound as a singleton.
// returning new \Illuminate\Http\Request() and storing the
// instance in case it is required again later;

$r2 = app(\Illuminate\Http\Request::class);
// Searching \Illuminate\Http\Request::class...
// Found it and already called! Returning the stored instance ($r1)

$r3 = app(\Illuminate\Http\Request::class);
// Searching \Illuminate\Http\Request::class...
// Found it and already called! Returning the stored instance ($r1)

// Their hash are the same
dd(
spl_object_hash($u1), // 0000000011f522cf0000000077704cd1
spl_object_hash($u2), // 0000000011f522cf0000000077704cd1
spl_object_hash($u3) // 0000000011f522cf0000000077704cd1
);

Now, what's happening?

Under the hood, when a new request is made to your app and before hitting the controller method, Laravel will do a lot of things to prepare the \Illuminate\Http\Request instance.

For instance, it will setup the route resolver inside Illuminate\Routing\Router:

/**
* Return the response for the given route.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Routing\Route $route
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function runRoute(Request $request, Route $route)
{

// here

$request->setRouteResolver(function () use ($route) {
return $route;
});

//

$this->events->dispatch(new RouteMatched($route, $request));

return $this->prepareResponse($request,
$this->runRouteWithinStack($route, $request)
);
}

Each time Laravel internally call a method like this:

protected function method(Request $request){
// do something to $request
}

$request is always the same instance, because it is bound as a singleton.


We are now in your controller.

    public function frontend1(\Illuminate\Http\Request $request){
// Searching \Illuminate\Http\Request::class...
// Found it and already called!
// Returning the stored instance that has been prepared through all
// Laravel core classes

dump($request);
dump($request->all()); //well prepared
dump($request->route('id')); //well setup
return Book::all();
}

public function frontend2(\App\Http\Request $request){
// Searching \App\Http\Request::class...
// Cannot find \App\Http\Request::class...
// returning new \App\Http\Request();

dump($request);
dump($request->all()); //nothing
dump($request->route('id')); //empty
return Book::all();
}

If you are still here, how to solve this problem?

The easiest way is to use a FormRequest, initially designed to handle form validation, but if you return an empty rules array, you should be able to do everything you did with your custom \App\Http\Request instance:

<?php

namespace App\Http;

use Illuminate\Foundation\Http\FormRequest;

class Request extends FormRequest
{
public function rules()
{
return [];
}
}

Try again, everything should work fine, since this is a feature specially designed to replace the initial \Illuminate\Http\Request object.

The full doc is here: https://laravel.com/docs/8.x/validation#creating-form-requests



Related Topics



Leave a reply



Submit