How to get error validation data in Custom Form Request - laravel

I have created a custom request form for login validation, It works fine if I put email and password field that's what I set for rules, email and password is required, but the problem is, I can't use the errors data,
/**
* Signin Controller
*
* #param \App\Http\Requests\Auth\Signin $request
*/
public function signin(Signin $request)
{
if ($request->validated()) {
return response()->json(['hello' => 'hi']);
} else {
return response()->json(['error' => $request->errors()]);
}
}
This is the Request form
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
class Signin 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<string, mixed>
*/
public function messages()
{
return [
'email.required' => 'Email field is required.'
];
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
'email' => 'required',
'password' => 'required'
];
}
}
Now when I try to make a post request to the signin controller, if email and password included then its return a json response, but if I only use email or password then it response a 405 method not allowed I'm expecting a json response with error data like errors()

As I understood, failedValidation would help you
use Illuminate\Http\JsonResponse;
class Signin extends FormRequest
{
public function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json($validator->errors(), JsonResponse::HTTP_UNPROCESSABLE_ENTITY));
}
}
This return the JSON object with 422 error(default error code for validation)

Related

Laravel: Using policy on FormRequest always returns false

I'm trying to authorize whether a user is allowed to invite other users.
InvitedUserController
public function store(InvitedUserRequest $request)
{
$data = $request->all();
$data['user_id'] = auth()->user()->id;
$data['account_id'] = $request->session()->get('account_id');
InvitedUser::create($data);
}
I created a FormRequest class to handle validation:
class InvitedUser extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize(Request $request)
{
$account = Account::find($request->session()->get('account_id'));
return $this->user()->can('manageUsers', $account);
}
/**
* Validation error message
*/
public function messages() {
return [
'max' => 'You may only enter up to :max characters'
];
}
public function invalid() {
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required|max:255|email',
'role_id' => 'required|exists:roles,id',
];
}
}
Then my policy to handle authorization:
class InvitedUserPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\User $user
* #return mixed
*/
public function manageUsers(User $user, Account $account)
{
dd('test');
$role = $user->roles()->wherePivot('account_id', $account->id)->first();
return $role->manage_users;
}
}
I registered the policy:
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
'App\InvitedUser' => 'App\Policies\InvitedUserPolicy'
];
For some reason, that dd() call doesn't even occur. So it's not reaching my policy and all requests are returning unauthorized.
even if i changed my policy to return true
public function manageUsers(User $user, Account $account)
{
return true;
}
I would still get unauthorized
How Can I call my policy from a FormRequest? Why is this not working?
So, while this is confusing to me, I've figured out the issue.
I needed to change my registered policies to the following:
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
'App\Account' => 'App\Policies\InvitedUserPolicy'
];
It's using the Account model instead of InvitedUser model. I think because that's what I'm passing in as a model?

Call to a member function fails() on array error when using laravel Request classses

I'm using a custom request class for laravel form validations.
This is my request class
class ContactUsRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'lname' => 'required'
];
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'lname.required' => 'please enter the last name'
];
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
}
And this is where I call it,
public function send(ContactUsRequest $request) {
$validator = $request->validated();
if ($validator->fails()) {
return redirect('/contactus')
->withErrors($validator)
->withInput();
} else {
ContactUs::create($request->all());
return redirect('/contactus');
}
}
But when I input correct values I get this,
Symfony \ Component \ Debug \ Exception \ FatalThrowableError
(E_ERROR) Call to a member function fails() on array
That's because request object automatically do that for you and you don't need to redirect back manually and $validator variable contains validated inputs so in your case you don't need to do anything and you can remove if and redirect safely
public function send(ContactUsRequest $request) {
ContactUs::create($request->validated());
return redirect('/contactus');
}
}
Using form request classes
If validation fails, a redirect response will be generated automatically 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 AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.
In order to capture validation failure you may use the Validator facade
E.g
use Illuminate\Support\Facades\Validator;
//...
public function send(Request $request) {
$validator = Validator::make($request->all(), [
'lname' => 'required'
// ...
]);
if ($validator->fails()) {
return redirect('/contactus')
->withErrors($validator)
->withInput();
}
ContactUs::create($request->all());
return redirect('/contactus');
}
Form Request Validation Documentation
Manually Creating Validators Documentation
And we can keep ContactUsRequest like this.
public function send(ContactUsRequest $request) {
$validator = $request->validated();
ContactUs::create($request->all());
return redirect('/contactus');
}

Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL)

I am trying to back and implement FormRequest objects for validation. I have successfully setup the form requests for all of my models except for the User model. I am getting the following error Declaration of App\Http\Requests\UserUpdateRequest::user() should be compatible with Illuminate\Http\Request::user($guard = NULL). Researching this error it seems like it may be an issue with the way that I'm handling the authorization through Policies. Note that the UserStoreRequest works but the UserUpdateRequest returns the error.
UserStoreRequest
<?php
namespace App\Http\Requests;
use App\User;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - create-user
return Gate::allows('create', User::class);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
'markets' => 'required|array',
'roles' => 'required|array',
];
}
/**
* Save the user.
*
* #return \App\User
*/
public function save()
{
// Create the user
$user = new User($this->validated());
// Set the password
$user->password = Hash::make($this->validated()['password']);
$user->setRememberToken(Str::random(60));
// Save the user
$user->save();
// Set users markets
$user->markets()->sync($this->validated()['markets']);
// Update the users role if included in the request
if ($this->validated()['roles']) {
foreach ($this->validated()['roles'] as $role) {
$user->roles()->sync($role);
if ($user->hasRole('admin')) {
$user->markets()->sync(Market::all());
}
}
}
return $user;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'password.required' => 'The password is required.',
'password.confirmed' => 'The passwords do not match.',
'password.min' => 'The password must be at least 8 characters.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
UserUpdateRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - update-user
return Gate::allows('update', $this->user);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
];
}
/**
* Get the user from the route.
*
* #return \App\User
*/
public function user()
{
return $this->route('user');
}
/**
* Save the email role.
*
* #return \App\Role
*/
public function save()
{
// Update the user
$this->user->update($this->validated());
// // Check to see if password is being updated
// if ($this->validated()['password']) {
// $this->user->password = Hash::make($this->validated()['password']);
// $this->user->setRememberToken(Str::random(60));
// }
// // Set users markets
// $this->user->markets()->sync($this->validated()['markets']);
// // Set users roles
// // // Update the users role if included in the request
// if ($this->validated()['roles']) {
// foreach ($this->validated()['roles'] as $role) {
// $this->user->roles()->sync($role);
// if ($this->user->hasRole('admin')) {
// $this->user->markets()->sync(Market::all());
// }
// }
// }
// // Save the user
// $this->user->save();
return $this->user;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
As you can see I have commented out most of the code for the UpdateRequest for troubleshooting. It seems that the issue is with the authorize() method. Below is the code from the UserPolicy
UserPolicy
/**
* Determine whether the user can create models.
*
* #param \App\User $user
*
* #return mixed
*/
public function create(User $user)
{
return $user->hasPermission('create-user');
}
/**
* Determine whether the user can update the model.
*
* #param \App\User $user
* #param \App\User $model
*
* #return mixed
*/
public function update(User $user, User $model)
{
return $user->hasPermission('update-user');
}
UserController
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\UserStoreRequest $request
*
* #return \Illuminate\Http\Response
*/
public function store(UserStoreRequest $request)
{
return redirect($request->save()->path());
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\UserUpdateRequest $request
* #param \App\User $user
*
* #return \Illuminate\Http\Response
*/
public function update(UserUpdateRequest $request, User $user)
{
return redirect($request->save()->path());
}
I'm using a permission based authorization for this system. The user has the hasPermission() method on it to verify if the user has the required permission to perform the action. I fear that I've confused myself on this setup and that I am not validating correctly. Everything has worked up until trying to implement this on the User model.
hasPermission()
/**
* Check to see if the model has a permission assigned.
*
* #param string $permission
*
* #return bool
*/
public function hasPermission($permission)
{
if (is_string($permission)) {
if (is_null(Permission::whereName($permission)->first())) {
return false;
} else {
return $this->hasRole(Permission::where('name', $permission)->first()->roles);
}
}
return $this->hasRole($permission->roles);
}
hasRole()
/**
* Check to see if model has a role assigned.
*
* #param string $role
*
* #return bool
*/
public function hasRole($role)
{
if (is_string($role)) {
return $this->roles->contains('name', $role);
}
return (bool) $role->intersect($this->roles)->count();
}
Update
I have tried renaming the user() method in UserUpdateRequest to frank() to resolve any issues overriding the Request user. This clears up the error listed above, but then the response is returned unauthorized. The logged in user has permissions set to allow updating users. This is called in the authorize() method using Gate::allows. I'm just not sure if it's checking the logged in user or the model user.
I investigated further and found that there is a new error after changing the method to frank(). I am getting Call to a member function update() on null. I should be returning the user pulled from the route from the frank method but it seems to be returning null.
Updated UserUpdateRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UserUpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// Authorize action - update-user
return Gate::allows('update', $this->frank);
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|string',
];
}
/**
* Get the user from the route.
*
* #return \App\User
*/
public function frank()
{
return $this->route('user');
}
/**
* Save the email role.
*
* #return \App\Role
*/
public function save()
{
// Update the user
$this->frank->update($this->validated());
// // Check to see if password is being updated
// if ($this->validated()['password']) {
// $this->user->password = Hash::make($this->validated()['password']);
// $this->user->setRememberToken(Str::random(60));
// }
// // Set users markets
// $this->user->markets()->sync($this->validated()['markets']);
// // Set users roles
// // // Update the users role if included in the request
// if ($this->validated()['roles']) {
// foreach ($this->validated()['roles'] as $role) {
// $this->user->roles()->sync($role);
// if ($this->user->hasRole('admin')) {
// $this->user->markets()->sync(Market::all());
// }
// }
// }
// // Save the user
// $this->user->save();
return $this->frank;
}
/**
* Get the error messages for the defined validation rules.
*
* #return array
*/
public function messages()
{
return [
'name.required' => 'The name is required.',
'email.required' => 'The email is required.',
'email.unique' => 'The email must be unique.',
'markets.required' => 'A market is required.',
'roles.required' => 'A role is required.',
];
}
}
The issue is the user() method you defined on your UserUpdateRequest class.
UserUpdateRequest extends Illuminate\Foundation\Http\FormRequest, which in turn extends Illuminate\Http\Request. Illuminate\Http\Request already has a user() method defined, so the user() method in your UserUpdateRequest class is attempting to override this definition.
Since your UserUpdateRequest::user() method doesn't match the Illuminate\Http\Request::user($guard = null) signature, you're getting that error.
You can either:
Remove the user() method from your UserUpdateRequest class, or
Rename your user() method on your UserUpdateRequest class, or
Add the $guard = null parameter to your user() method on your UserUpdateRequest class, so that it matches the signature of the base user() method.

How to validate images array type using rule object with custom message in Laravel

Actually, I tried to create rule object which is able to validate every image type in array of images and not only enough but also, I must to show custom message in override message function in rule object.
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class ImagesArray implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
return [$attribute => 'mimes:jpeg,jpg,png' ];
here i need to validate these file types.
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The validation error message.';
here, I need to show my custom messgae.
}
}
You should use Request.
For example, create q request class: php artisan make:request MyRequest.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class MyRequest 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 [
'image' => 'mimes:jpeg,jpg,png',
];
}
public function messages()
{
return [
'image.mimes' => 'This image is not supported.',
];
}
}
In your controller import class MyRequest and in the method use MyRequest
e.g:
public function store(MyRequest $request)
{ // your code
}
Let me know if that was helpful. Thanks!
When validating arrays or nested parameters, you should use . in your rules access a specific array index. but if you want to apply a rule to every index on that array, you can use .*.
$validator = Validator::make($request->all(), [
'image.*' => 'mimes:jpeg,jpg,png',
], [
'image.*' => 'Invalid file type.',
]);
Or if you're using Request Forms
public function rules(){
return [
'image.*' => 'mimes:jpeg,jpg,png',
];
}
public function mesages(){
return [
'image.*' => 'Invalid file type.',
];
}
For more info, see Laravel's Documentation on Validation Arrays

Unable to overwrite authorized method in policy

I want to respond with a custom message when authorization fails.
I've overwritten the method in the Policy class but it does not return the custom message.
Policy:
class PostPolicy
{
use HandlesAuthorization;
/**
* Determine if user can view post
* #param User $user
* #param Post $post
* #return bool
*/
public function view(User $user, Post $post)
{
return $user
->posts()
->where('post_id', $post->id)
->exists();
}
/**
* [deny description]
* #return [type] [description]
*/
protected function deny()
{
return response()->json([
'message' => 'My custom unauthorized message'
], 401);
}
}
Implementing in PostController:
...
public function show(Post $post)
{
$this->authorize('view', $post);
...
}
The response still returns whats defined in the HandlesAuthorization trait, i.e.:
protected function deny($message = 'This action is unauthorized.')
{
throw new AuthorizationException($message);
}
You can simply add this code inside the AuthorizationException.php
/**
* Render the exception into an HTTP response.
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function render(Request $request)
{
if ($request->is('api/*')) {
$response = [
'message' => $this->message,
'status' => 403,
];
return response()->json($response, 403);
}
}

Resources