Add error to validation errors using formRequest - laravel

i'm trying to figure out how to add a error message to the default $error generated by the Illuminate\Support\MessageBag when using validation trough requests.
I've searched on google and the laravel docs and not really found information clarifying this for me.
AuthController
<?php
namespace App\Http\Controllers\Auth;
use Auth;
use App\User;
use App\Http\Requests\LoginFormRequest;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
/*
* AuthController
*/
class AuthController extends Controller {
/*
* Create view
*
* #return View
*/
public function getLogin() {
return view('auth.login');
}
/*
* Validate Login
*
* #return Redirect route
*/
public function postLogin(LoginFormRequest $request) {
if (Auth::attempt(array('email' => $request->email, 'password' => $request->password), $request->remember)) {
return redirect()->intended('home')->with('success-message', 'Succesfully authenticated');
} else {
$validator->addMessage('Incorrect email and password combination');
return redirect('account.login')->withErrors($validator)->withInput();
}
}
}
LoginFormRequest
<?php
namespace App\Http\Requests;
use Response;
use Illuminate\Foundation\Http\FormRequest;
class LoginFormRequest extends FormRequest {
public function rules() {
return array(
'email' => 'required|email',
'password' => 'required|between:8,20'
);
}
public function authorize() {
return true;
}
}
Hopefully someone has encountered this problem before and can help me!

Just add the messsages() function to your LoginFormRequest class:
public function messages()
{
return array(
'email.required' => 'The email address is required.',
'password.required' => 'The password is required.',
'password.between' => 'The password should be between 8 and 20 characters.',
);
}
Using the dot notation, you specify the field first and then the type of validator.

$validator->getMessageBag()->add("password", "Username and/or password don't match.");
Will add an error for this field.

Related

How to use the ignore rule in Form Request Validation

this is PostsRequest.php in http/request:
<?php
namespace App\Http\Requests;
use App\Post;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class PostsRequest 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 [
'title' => ['required','max:255', Rule::unique('posts')->ignore($this->id)],
'slug' => ['required', Rule::unique('posts')->ignore($this->id),],
'content' => 'required',
'type' => 'required|in:blog,download,page',
'status' => 'required',
];
}
}
and this is edit() method in PostController.php
public function update(PostsRequest $request, $id)
{
$validated = $request->validated();
$validated['user_id'] = auth()->user()->id;
$post = Post::find($id)->fill($validated);
$post->save();
return redirect()->action('PostController#index');
}
Problem: show error in update page that this value is already exists.
who to resolve problem unique fields in edit form?
Problem Solved
change:
Rule::unique('posts')->ignore($this->route('id'))
with:
Rule::unique('posts')->ignore($this->route('post'))
If you're wanting to resolve the $id from the route then you can use the route() method in your request class e.g.
Rule::unique('posts')->ignore($this->route('id'))

How to add errors after FormRequests validation?

How to add errors after FormRequests validation?
password_repository->update() will return an error if the current passwords entered do not match.
password_repository->update() calls an external API.
I want to add an error in the controller depending on the return value of the repository.
In PasswordRequest, validation after calling the external API cannot be described, so I am in trouble.
For this reason I want to add an error in the controller after doing password_repository->update().
PasswordController.php
public function completeEdit(PasswordRequest $request)
{
$input = $request->only(['password', 'new_password']);
$data = $this->password_repository->update($input);
//I want to add an error at this point!!!
return view('pages.password.edit.complete');
}
}
PasswordRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PasswordRequest 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 [
'password' => 'required',
'new_password' => 'required|confirmed',
'new_password_confirmation' => 'required',
];
}
}
Redirect with errors could help you.
return redirect()->back()->withErrors([
'Password not correct',
]);
Or return to a specific route.
return redirect()->route('password.create')->withErrors([
'Password not correct',
]);

Url for API to login and get access token

I want to validate the email and password of someone connecting through an API.
The idea is that they login through POST to site.com/api/v1/token?email=foo#bar.com&password=foobar
I was reading that best practices should be to make a https://laravel.com/docs/7.x/validation#creating-form-requests to handle the validation, but I couldn't understand how to validate the $user, because when I created the new Class there wasn't any request there.
I'm not sure if I'm missing something.
I was able to do it through the Controller just checking if the user exists and the password is valid.
The app would ping this URL with email/password, then get a Token as a response with the $user information and use this token to post/edit/delete other data
First you have to create a FormRequest class by using artisan command:
php artisan make:request ApiLoginRequest
After artisan command, it will create a new file inside you app/Http/Request with name ApiLoginRequest.php.
Inside this file you have to define validation rules like this.
<?php
namespace App\Http\Request;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
class ApiLoginRequest 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(Request $request)
{
$rules = [
'email' => 'required|email|exists:users,email',
'password' => 'required'
];
return $rules;
}
/**
* #name messages
*
* #description
*/
public function messages() {
return [
'email.required' => 'Required',
'password.required' => 'Required',
'email.email' => 'Must be a valid email address',
'email.exists' => 'Email address not found'
];
}
}
Then after you have to use this Request class inside your controller.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Request\ApiLoginRequest;
class ApiLoginController extends Controller {
public function login ( ApiLoginRequest $request ){
$user = \App\User::where('email', $request->get('email'))->find();
if( \Hash::check( $user>password, $request->password ) ){
// Do Login processed
}else{
$data = [
'success' => false,
'message' => 'Password dows not match'
];
return response()->json( $data, 500);
}
}
}
Like this you can use FormRequest class and benefit of this FormRequest class you can reuse this validation rules and also your controller looks good.

laravel api not showing message from request validation

im having problems with error handler in my backend laravel api, don't show error message from validation.
routes/api
<?php
Route::group([
'middleware' => 'api',
], function ($router) {
Route::post('access/sign-up', 'AuthenticationController#signUp');
});
AuthenticationController
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\SignUpRequest;
use Illuminate\Http\Request;
use App\User;
class AuthenticationController extends Controller
{
/**
* Create a new AuthenticationController instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['signUp']]);
}
/**
*
*
* #return \Illuminate\Http\JsonResponse
*/
public function signUp(SignUpRequest $request)
{
//User::create($request->all());
return response()->json([
'data' => 'Usuario creado correctamente.'
]);
}
}
SignUpRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SignUpRequest 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|email|unique:users',
'firstName' => 'required',
'password' => 'required',
];
}
}
The thing is that when by postman i send password in blank or not send mail for example it send me to main page insted of sending me a json with all the errors like before. I don't know what to do.
I tryed with custom message in SignUpRequest, but that's not the problem, think some kind of redirect in error handler.
You need to check just one setting must add Accept Type in header data in Postman
Accept : application/json
that is work in my case...
Just add that code to SignUpRequest
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json($validator->errors(), 422));
}
Using the Form request; If validation fails, a redirect response will be generated to send the user back to their previous location. That's why you are redirecting back to the page instead of the response JSON.
Laravel have one protected method "failedValidation" method. Overwrite this method in your form request class.
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
throw new \Illuminate\Validation\ValidationException(response()->json($validator->errors(), 422));
}
Update for laravel 8, the first parameter in ValidationException is the Validator class:
protected function failedValidation(Validator $validator)
{
throw new ValidationException($validator, response()->json($validator->errors(), 422));
}
TL;DR Add the following header: Accept: application/json
As mentioned by a few users over here, by default, when a Form Request fails, the application will attempt to redirect the user back to their previous location. That's why you're receiving a webpage instead of a JSON response.
We can also override the "failedValidation" method. But I would recommend setting the following header on the request Accept: application/json.
Laravel will return the appropriate response based on Accept header. For application/json Laravel will return a JSON response with form errors.
Simply, in your App\Exceptions\Handler, you have to register your custom exception handling in register() method:
public function register() {
$this->renderable( function ( ValidationException $ex, $request ) {
$response = [
'ErrorCode' => 'my_error_code',
'ErrorMessage' => $ex->validator->errors()
];
return response()->json( $response );
} );
}
add this method to your formRequest class. It works in laravel 9
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class PostRequest extends FormRequest
{
protected function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json([
'success' => false,
'message' => 'Validation errors',
'data' => $validator->errors(),
]));
}
/**
* 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()
{
switch ($this->method()) {
case 'GET':
case 'DELETE':{
return [];
}
case 'POST':{
return [
'title' => 'string|unique:posts|required',
'body' => 'required',
'image' => 'string|nullable',
];
}
case 'PUT':{
return [
'title' => 'string|unique:posts|required',
'body' => 'required',
'image' => 'string|nullable',
];
}
}
}
}
Just add that code to App\Exceptions\Handler:
public function render($request, Exception $exception)
{
if ($exception instanceof ValidationException) {
return response()->json([
'status' => false,
'error' => [
'type' => 'form',
'code' => 400,
'description' => 'Bad request.',
'detail' => $exception->validator->errors()
]
], 422);
}
return parent::render($request, $exception);
}

Default controller in Route::group for routing purposes?

I want to show some user data by id. Simple.
user/{id} -> get data from a Controller's method.
I have this:
Route::group(['prefix' => 'user/{id}', 'where' => ['id' => '[0-9]+']], function() {
Route::get('delete', 'UserController#delete')->name('admin.access.user.delete-permanently');
Route::get('restore', 'UserController#restore')->name('admin.access.user.restore');
Route::get('mark/{status}', 'UserController#mark')->name('admin.access.user.mark')->where(['status' => '[0,1]']);
Route::get('password/change', 'UserController#changePassword')->name('admin.access.user.change-password');
Route::post('password/change', 'UserController#updatePassword')->name('admin.access.user.change-password');
});
How can I access a method as a default for user/{id}?
You can do this in your controller
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* #param int $id
* #return Response
*/
public function show($id)
{
//Fetch and send the user to the "profile" blade file in the folder "resources/views/user"
return view('user.profile', ['user' => User::findOrFail($id)]);
}
public function changePassword($id)
{
$user = User::findOrFail($id);
return $user->update(
'password' => bcrypt(123456)
);
}
}

Resources