Reputation: 4783
Is it possible to transform Illuminate\Http\Request
to custom validation request you made with php artisan make:request MyRequest
?
I would like validation to take place in a method down the road so that I have:
protected function register(Request $request)
{
...
$this->userRepository->signup($request)
...
}
User repository:
public function signup(MyRequest $request)
{
...
}
Is this possible? I am getting an error now because one class is expected. Only thing that comes to mind is to make an interface, but I'm not sure if that could function.
Error I get
Type error: Argument 1 passed to UserRepository::signup() must be an instance of App\Http\Requests\MyRequest, instance of Illuminate\Http\Request given
Upvotes: 2
Views: 2710
Reputation: 1
I know this is an old topic, but I will solve this problem so that other friends who come across this issue know how it can be solved.
protected function register(Request $request)
{
$request = MyRequest ::createFrom($request);
$this->userRepository->signup($request)
}
User repository:
public function signup(MyRequest $request)
{
$this->validate($request, $request->rules(),$request->messages());
...
}
Upvotes: 0
Reputation: 180
like @dbf answer but with automatic validation
use App\Http\Requests\MyRequest;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
public function someControllerMethod(Request $Request) {
//this make your request class do validation
try{
app(MyRequest::class);
} catch (ValidationException $ex){
throw $ex;
}
//if no error you can continue to convert the request
$MyRequest = MyRequest::createFrom($Request);
// .. or
$MyRequest = MyRequest::createFromBase($Request);
}
Upvotes: 1
Reputation: 3463
Well, you can convert any request to any other request, as long as it extends from Illuminate\Http\Request
.
There are basically two methods Laravel uses to convert one request to another. The problem here is that it will never get a validation object or trigger the validation automatically, as part of the injection when MyRequest
was passed as an argument. It might also miss a message bag and the error handler, but nothing you can fix by initializing the request just like Laravel does when injecting it.
So you still have to trigger all the sequences the FormRequest
(if it extends FromRequest rather than Request) normally does when booting the trait, but still, it's entirely possible and with some little extra work, you could convert any request to any other request.
For example; I'm using this setup to call just one route profile/{section}/save
for saving my profile settings. Depending on $section
's value, I convert the given $Request
to any of my custom form requests for that particular $section
.
use App\Http\Requests\MyRequest;
use Illuminate\Http\Request;
...
public function someControllerMethod(Request $Request) {
$MyRequest = MyRequest::createFrom($Request);
// .. or
$MyRequest = MyRequest::createFromBase($Request);
}
...
So to get people started with using a FormRequest
as an example, it basically comes to this.
Instead of extending all your custom requests from the default Illuminate\Foundation\Http\FormRequest
, use a base class which extends from FormRequest
and add a custom method to transform and boot the request as if it were passed as an argument.
namespace App\Http\Requests;
use Illuminate\Routing\Redirector;
use Illuminate\Foundation\Http\FormRequest;
class BaseFormRequest extends FormRequest {
public function convertRequest(string $request_class) : BaseFormRequest {
$Request = $request_class::createFrom($this);
$app = app();
$Request
->setContainer($app)
->setRedirector($app->make(Redirector::class));
$Request->prepareForValidation();
$Request->getValidatorInstance();
return $Request;
}
public function authorize() {
return true;
}
public function rules() {
return [];
}
}
Let all your custom FormRequest
extend your BaseFormRequest
namespace App\Http\Requests;
class MyRequest extends BaseFormRequest {
...
}
Now anywhere you want to convert
a request, use the base class in your controller method and convert it using convertRequest
with the custom request class you wish to convert.
public function someControllerMethod(BaseFormRequest $Request) {
$MyRequest = $Request->convertRequest(MyRequest::class);
}
Upvotes: 3
Reputation: 4783
I didn't find it was possible to do what I wanted even with my custom class extending the Request
because naturally one method expects an instance of one class while getting another one.
Maybe it would be possible to extract an interface out and wrap and bind it but that would be in my opinion a quickfix.
My opinion is that concept I had was wrong from the start, and it was more of an architecture problem so I transformed my app to a different approach and manage to avoid such issues in the first place.
Upvotes: 0
Reputation: 111859
Yes, there is no problem with that, you should create:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyRequest extends FormRequest
{
public function rules() {
// here you put rules
}
}
and in your controller:
public function signup(\App\Http\Requests\MyRequest $request)
{
...
}
Be aware you should also adjust authorize
method in your request class (to return true or false depending on user access)
EDIT
After update - you should type hint your custom class in controller and in repository - it's up to you - I often use generic Illuminate\Http\Request
, so you should do:
in controller:
public function controllerMethod(\App\Http\Requests\MyRequest $request)
in repository:
public function signup(\App\Http\Requests\MyRequest $request)
or
public function signup(\Illuminate\Http\Request $request)
So to sum up you should use Form request classes in controller - this is the place where validation will be made and later you can use either same class or generic \Illuminate\Http\Request
- I personally often use in repositories or services just \Illuminate\Http\Request
because they usually don't care about other things put into MyRequest
class - they just want to get data from request class and that's it.
Upvotes: 0