I've been trying to add a FormRequest with rules and message to my delete method, but the request is coming back empty and the rules are failing every time.
Is it possible to get the request data in a delete method?
Here's my request class:
use App\Http\Requests\Request;
class DeleteRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'staff_id' => ['required', 'exists:users,uid'],
'reason' => ['required', 'string'],
];
}
/**
* Get custom messages for validator errors.
*
* #return array
*/
public function messages()
{
return [
'staff_id.required' => staticText('errors.staff_id.required'),
'staff_id.exists' => staticText('errors.staff_id.exists'),
'reason.required' => staticText('errors.reason.required'),
'reason.string' => staticText('errors.reason.string'),
];
}
}
And the controller:
/**
* Handle the 'code' delete request.
*
* #param integer $id The id of the code to fetch.
* #param DeleteRequest $request The request to handle the data.
* #return response
*/
public function deleteCode($id, DeleteRequest $request)
{
dd($request->all());
}
Even though the HTTP/1.1 spec does not explicitly state that DELETE requests should not have an entity body, some implementations completely ignore the body which contains your data, e.g. some versions of Jetty and Tomcat. On the other hand, some clients do not support sending it as well.
Think of it as a GET request. Have you seen any with form data? DELETE requests are almost the same.
You can read a LOT on the subject. Start here:
RESTful Alternatives to DELETE Request Body
It seems like that you want to alter the state of the resource rather than destroying it. Soft-deleting is not deleting and thus requires either a PUT or a PATCH method which both support entity bodies. If soft-deleting is not the case, you're doing two operations through one call.
Related
I created a custom form request named ClientStoreRequest with the following code:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ClientStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
// return $this->user()->can('add-clients');
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|unique:clients|max:255',
'website' => 'required|url',
'street' => 'required',
'town' => 'required',
'postcode' => 'required|max:8',
'county' => 'required',
'country' => 'required'
];
}
}
I then modified my ClientController's store method to look like this:
/**
* Store a newly created resource in storage.
*
* #param ClientStoreRequest $request
* #return \Illuminate\Http\Response
*/
public function store(ClientStoreRequest $request)
{
dd(1);
}
So when the form is submitted, it should kill the page and print a 1 to the screen. When I use ClientStoreRequest $request, it just sends me back to the page where I submitted the form with no errors and no dd(1) result, however when I utilise Request $request it prints 1 to the screen.
Am I missing something really obvious? I've followed the docs to make this.
Edit: I'm using a resource controller so the route is Route::resource('clients', 'ClientController');
A bit embarrassing but this one was purely down to developer error. The custom form request is actually working correctly... just my rules are referencing one field that I forgot to put into my form so isn't showing the errors to the screen! Once I echoed the usual $errors array I could see my error - I'll blame the late night coding!
I'm using laravel 5.5
I have a Request that I've built but the required rule is not working correctly.
Route
Route::get('v1/learning_centre/user/{userId}/course/list', 'API\LearningCentre#userCourses');
Controller
public function userCourses(GetUserCourses $request)
{
$courses = User::findOrFail($request->userId)
->courses()
->get();
return new CourseResourceCollection($courses);
}
Request
namespace App\Http\Requests\LearningCentre;
use Illuminate\Foundation\Http\FormRequest;
class GetUserCourses extends FormRequest {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'userId' => 'required|integer'
];
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'userId.required' => 'A User is required',
];
} }
If I turn off the required rule I can get to the controller. If I have the required rule in the request I get a 302. I am passing in a valid userId in phpunit. Without the request rules my code works as intended.
Any ideas?
You should be using route model binding to validate a required GET parameter in this situation, not a FormRequest class, which, as the name should indicate, are intended for form requests.
Your route:
Route::get('v1/learning_centre/user/{user}/course/list', 'API\LearningCentre#userCourses');
Your controller:
public function userCourses(User $user) {
If a user ID is missing (or an invalid one used), your controller will automatically throw a ModelNotFoundException, which Laravel by default returns as a 404.
I'm using dingo/api package.
Controller:
public function register(RegisterUserRequest $request)
{
dd('a');
}
And for example the email field is required:
<?php namespace App\Http\Requests;
class RegisterUserRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required'
];
}
}
So I send a request without the email, and still getting the "a" response.
I also tried to extend Dingo\Api\Http\Request instead of App\Http\Request, but still the same.
For Dingo to work at all with the FormRequest, by experience (and from this Issue), you have to use Dingo's Form request i.e Dingo\Api\Http\FormRequest; , so you'll have something similar to:
<?
namespace App\Http\Requests;
use Dingo\Api\Http\FormRequest;
use Symfony\Component\HttpKernel\Exception\HttpException;
class RegisterUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required'
];
}
// In case you need to customize the authorization response
// although it should give a general '403 Forbidden' error message
/**
* Handle a failed authorization attempt.
*
* #return mixed
*/
protected function failedAuthorization()
{
if ($this->container['request'] instanceof \Dingo\Api\Http\Request) {
throw new HttpException(403, 'You cannot access this resource'); //not a user?
}
}
}
PS: This is tested on Laravel 5.2.*
Hope it helps :)
According to the Wiki
you must overload the failedValidation and failedAuthorization methods.
These methods must throw one of the above mentioned exceptions and not the response HTTP exceptions that Laravel throws.
If you take a look at Dingo\Api\Http\FormRequest.php, you'll see:
class FormRequest extends IlluminateFormRequest
{
/**
* Handle a failed validation attempt.
*
* #param \Illuminate\Contracts\Validation\Validator $validator
*
* #return mixed
*/
protected function failedValidation(Validator $validator)
{
if ($this->container['request'] instanceof Request) {
throw new ValidationHttpException($validator->errors());
}
parent::failedValidation($validator);
}
/**
* Handle a failed authorization attempt.
*
* #return mixed
*/
protected function failedAuthorization()
{
if ($this->container['request'] instanceof Request) {
throw new HttpException(403);
}
parent::failedAuthorization();
}
}
Hence, you need to change the names of your methods appropriately, and have them throw the appropriate exceptions, instead of returning a boolean.
you need to call the validate function explicitly when you run it under an Dingo API setup, try something like this (for L5.2):
Probably a few extra providers
...
Illuminate\Validation\ValidationServiceProvider::class,
Dingo\Api\Provider\LaravelServiceProvider::class,
...
Aliases
...
'Validator' => Illuminate\Support\Facades\Validator::class,
...
I'm also pretty much sure that you really don't want to use this below as suggested here and there, It will expect form(encoded) input and will also probably fail on CSRF token as it expects it, so it will fail right after validating (form input). But make sure to test behavior with this on/off.
use Dingo\Api\Http\FormRequest;
Make your headers:
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Dingo\Api\Exception\ValidationHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/* This can be a tricky one, if you haven't split up your
dingo api from the http endpoint, there are plenty
of validators around in laravel package
*/
use Validator;
Then the actual code (if you adhere to cors standard,
this should be a POST and that commonly translates to a store request)
...
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function register(RegisterUserRequest $request) {
$validator = Validator::make($request->all(), $this->rules());
if ($validator->fails()) {
$reply = $validator->messages();
return response()->json($reply,428);
};
dd('OK!');
};
...
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required'
// or/and 'userid' => 'required'
];
}
That will give you back the response you expect from the validator. If you use this with pregenerated forms, it does not need this fix, there the validator will kick in automatically. (not under Dingo Api).
you probably also need these in composer.json
"dingo/api": "1.0.*#dev",
"barryvdh/laravel-cors": "^0.7.1",
This is untested, by heart, it took me 2 days to figure this out but I have a separate namespace for API specific and authenticated with middleware. success
I'm using Laravel 5.1 and I'm unable to use its Request injection.
If I print_r($request->all()), I get an empty array:
Array
(
[\] =>
)
But when I check Request::getContent(), it shows that I have content.
{"test": "test"}
Why is this? I have never had this problem before.
My controller method
public function state(Requests\CheckState $request) {
print_r($request->all());
print_r($request->getContent());
}
My Request
class CheckState extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
];
}
}
When sending raw JSON data to Laravel, be sure to specify Content-Type: application/json
This is because the Request class checks for JSON content this way:
/**
* Determine if the request is sending JSON.
*
* #return bool
*/
public function isJson()
{
return Str::contains($this->header('CONTENT_TYPE'), '/json');
}
If the header is omitted, the framework assumes the request is plaintext.
I would like to keep my authorization as DRY as possibile.
Currently for my update method I am using Laravel 5 FormRequest.
Example:
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
$commentId = $this->route('comment');
return Comment::where('id', $commentId)
->where('user_id', Auth::id())->exists();
}
The problem is that this gets triggered just for update method:
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update(UpdateRequest $request, $id)
{
// ...
}
How can I use the same authorize logic for edit method?
Otherwise everyone can just type:
/resources/ID/edit
^
not allowed
Only the owner should see that page, not everyone
Note I can't add that same UpdateForm to the edit method, because otherwise validation could be triggered too
/**
* Show edit form for the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function edit(UpdateRequest $request, $id)
{
// ...
}
You have something called middleware in laravel 5.
You can use it in the route so that it gets executed before the action has been called.
I think for what you need you will have to create your own middleware.
http://laravel.com/docs/master/middleware
After you created one you have to tell laravel to use the middleware and then add it to your route like so
route::get('test', ['middleware' => 'yourmiddleware', 'uses' => 'yourController#index']);