Custom validation rule with request class not working laravel 7 - php

Below is my code;
FruitRequest.php
class FruitRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|alpha',
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048'
];
}
public function messages()
{
return ['name.required' => response("Name should be mandatory", 404),
'name.alpha' => response("Name should be contains only letters", 404),
'image.required' => response("Foto should be mandatory", 404),
'image.mimes' => response('Foto should be jpeg,png,jpg,gif,svg', 404),
'image.max' => response('Foto size should be blow 2 MB', 404),
];
}
}
FruitController.php
use App\Http\Controllers\Controller;
use App\Http\Requests\FruitRequest;
class FruitController extends Controller
{
public function store(FruitRequest $request)
{
echo $request->input('name');
//above line gives nothing to me
}
}
If I use extends Request instead of extends FruitRequest then this gives me value which is passed by user in postman. I don't know why this custom Request class not working.I attached screenshot. Please help....

extend your request class with FormRequest
use Illuminate\Foundation\Http\FormRequest;
class FruitRequest extends FormRequest
for more details visit official doc of laravel: https://laravel.com/docs/7.x/validation#creating-form-requests

long time not using postman, i'm testing with my code
I'm using FormRequest like this:
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
class YourRequest extends FormRequest
{
//this function called if Validator::make()->fails();
//here where you can modifying your message
protected function failedValidation(Validator $validator)
{
//note this only for API, for formData use \Illuminate\Validation\ValidationException($validator)
throw new HttpResponseException(response()->json($validator->errors()->all(), 422));
//this will get parameter attribute set from FormRequest
//attributes() along with the error message,
//or $validator->errors()->all() to get messages only like my screenshot
//or modify message with your logic
}
public function authorize() { return true; }
public function rules() { return []; }
public function attributes() { return []; }
public function messages() { return []; }
}
in controller :
use YourRequest;
public function store(YourRequest $req)
{
return response($req->all())->setStatusCode(200);
}
in your FormRequest replace response(), just text:
public function messages()
{
return ['name.required' => "Name should be mandatory"],
}
2nd, validation alpha only accepts alphabet, which your name is numeric,
result from my code(i use default validator message which in array of messages) :

Related

Laravel Validator Not Returning Key

I am creating a new API call for our project.
We have a table with different locales. Ex:
ID Code
1 fr_CA
2 en_CA
However, when we are calling the API to create Invoices, we do not want to send the id but the code.
Here's a sample of the object we are sending:
{
"locale_code": "fr_CA",
"billing_first_name": "David",
"billing_last_name": "Etc"
}
In our controller, we are modifying the locale_code to locale_id using a function with an extension of FormRequest:
// This function is our method in the controller
public function createInvoice(InvoiceCreateRequest $request)
{
$validated = $request->convertLocaleCodeToLocaleId()->validated();
}
// this function is part of ApiRequest which extend FormRequest
// InvoiceCreateRequest extend ApiRequest
// So it goes FormRequest -> ApiRequest -> InvoiceCreateRequest
public function convertLocaleCodeToLocaleId()
{
if(!$this->has('locale_code'))
return $this;
$localeCode = $this->input('locale_code');
if(empty($localeCode))
return $this['locale_id'] = NULL;
$locale = Locale::where(Locale::REFERENCE_COLUMN, $localeCode)->firstOrFail();
$this['locale_id'] = $locale['locale_id'];
return $this;
}
If we do a dump of $this->input('locale_id') inside the function, it return the proper ID (1). However, when it goes through validated();, it doesn't return locale_id even if it's part of the rules:
public function rules()
{
return [
'locale_id' => 'sometimes'
];
}
I also tried the function merge, add, set, etc and nothing work.
Any ideas?
The FormRequest will run before it ever gets to the controller. So trying to do this in the controller is not going to work.
The way you can do this is to use the prepareForValidation() method in the FormRequest class.
// InvoiceCreateRequest
protected function prepareForValidation()
{
// logic here
$this->merge([
'locale_id' => $localeId,
]);
}

Laravel - requests validation loose errors on redirect

I have a custom request file in http/requests which handles validation.
If validation does not pass, by default it should redirect back with $errors in the view (which are generated by \Illuminate\View\Middleware\ShareErrorsFromSession::class) and I see that the errors are in the session while debuging, but after this request with code 302 finishes and 200 request is generated, errors in the session are lost.
What might cause this issue? Thanks
Code:
<?php
namespace App\Http\Requests;
<..>
class AnswerQuestionnaireRequest extends FormRequest
{
private $questionRepository;
/**
* AnswerQuestionnaireRequest constructor.
*/
public function __construct(QuestionRepository $qs)
{
parent::__construct();
$this->questionRepository = $qs;
}
public function authorize()
{
return true;
}
public function rules()
{
$rules = [];
foreach ($this->questionRepository->getAll() as $question){
$index = "question-" . $question->id;
$rules[$index] = "required|in:1,2";
}
return $rules;
}
public function messages()
{
return [
'question-1.required' => __("Incorrect value"),
'question-2.required' => __("Incorrect value"),
];
}
}
class QuestionnairesController extends Controller
{
public function __construct(QuestionnairesService $questionnairesService, QuestionRepository $questionRepository)
{
$this->questionnairesService = $questionnairesService;
$this->questionRepository = $questionRepository;
}
public function show(Request $request){
$questions = $this->questionRepository->getAll();
return view("client/questionnaire", compact("questions"));
}
public function store(AnswerQuestionnaireRequest $request){
var_dump($request);
}
EDIT:
Checking with Xdebug you can see, that the validation worked, but it's only for the request, that return code 302 and redirects back. https://gyazo.com/231c83910f6e57748e1b705ade74e383
And when the request 200 is loading, this error bag is already empty there.
In your controller try this, assuming the function is create
use Illuminate\Http\Request;
public function create(Request $request){
$this->validate($request,[
'field'=>'required|present',
'another_field'=>'required|present',
]);
Post::create($request);
}
Do note that the $this->validate(), if there is a validation error it is automatically redirected back to the previous url with the error messages sent.
Blade
You can then check for errors this way
#if($errors->has('fieldName'))
<small class="text-danger form-text">{{$errors->first('fieldName')}}</small>
#endif
Wrapping everything in routes/web.php to "Route::group(['middleware' => ['web']], function () {" fixed the issue.
I thought that everything in web.php file is already assigned to "WEB" middleware...

is it better to create separate request class for each new method in controller, or edit existing request class in laravel or any better idea?

Is it better to create separate request class for each new method in controller or edit existing request class in laravel or any better idea ?
example
class fooBarController {
public function a(fooBarARequest $r) {
}
public function b(fooBarBrequest $r) {
}
public function c(fooBarCDRequest $r) {
}
public function d(fooBarCDRequest $r) {
}
}
Using extra request classes allows you to define validation rules which your request is checked against before it reaches your controller. You can also handle authorization in the request class. An example would be:
class UpdateAccountEmail extends FormRequest
{
public function authorize()
{
return true; // authorization is handled on route/middleware level
}
public function rules()
{
return [
'new_email' => 'required|email|confirmed',
'new_email_confirmation' => 'required',
];
}
}
So, to sum it up: it does not make sense to use a custom request class for requests which do not have payload that needs to be validated. This means, for a normal GET request we most likely (of course there are exceptions) want to use the normal Request class provided by laravel. A controller like this would be quite normal:
class AccountController
{
public function show(Request $request)
{
return view('account.show', ['user' => $request->user()]);
}
public function edit()
{
return view('account.edit', ['user' => \Auth::user()]);
}
public function updateEmail(UpdateAccountEmail $request)
{
$user = $request->user();
$user->email = $request->input('new_email');
$user->save();
return redirect()->route('account.index');
}
public function logins(Request $request)
{
$logins = $request->user()->logins()
->when($request->get('filter_from'), function ($query, $from) {
$query->where('created_at', '>=', $from);
})
->when($request->get('filter_until'), function ($query, $until) {
$query->where('created_at', '<=', $until);
})
->get();
return view('account.logins', ['logins' => $logins]);
}
}
As you can see, for the GET request that is handled by logins(Request $request), we do not use a custom request class because we don't need to validate anything (well, we could validate the filter parameters, but for simplicity we don't).
The example above also shows different methods of retrieving the current user. Even for that you don't need a request at all.
This is no actual production code, just something off the top of my head...

Laravel custom validation error messages

I have a custom "base" validator
class BaseUserRequest extends FormRequest
{
...
public function messages()
{
return [
'password.min' => 'Custom error',
];
}
}
And other validator extends "base" class
class RegisterUserRequest extends BaseUserRequest
{
...
public function messages()
{
return parent::messages();
}
}
When I try to trigger password:min error on form, which uses RegisterUserRequest, I get default message instead "Custom error" message. What's wrong with my RegisterUserRequest class?
If I use BaseUserRequest, I get my "Custom error" message. Something is wrong with class inheritance.
UPDATE (QUESTION SOLVED): I forgot to register rules on validation
not
return Validator::make($data, (new RegisterUserRequest())->rules());
but
return Validator::make($data, (new RegisterUserRequest())->rules(), (new RegisterUserRequest())->messages());
try this way
php artisan make:request BaseUserRequest
// app/Http/Requests/BaseUserRequest.php
public function messages()
{
return [
'password.min' => 'Custom error',
];
}
// app/Http/Controllers/UserController.php
use App\Http\Requests\BaseUserRequest;
public function register(BaseUserRequest $request)
{
// register code here
}

Route not found in custom form request

I use laravel custom form request with command php artisan make:request AddressBookRequest
And use that request in my controller like :
public function add_address_book($lang,$user_id,AddressBookRequest $request){
dd($request);
}
And when i run api route laravel shows :
NotFoundHttpException in RouteCollection.php line 161:
But when i change that AddressBookRequest to Request like :
public function add_address_book($lang,$user_id,Request $request){
dd($request);
}
Api works fine
AddressBookRequest :
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
class AddressBookRequest 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 [
'title' => 'required',
'address' => 'required',
'latitude' => 'required',
'longitude' => 'required'
];
}
public function messages()
{
return [
'title.required' => trans('address_book.title_required'),
'address.required' => trans('address_book.address_required'),
'latitude.required' => trans('address_book.latitude_required'),
'longitude.required' => trans('address_book.longitude_required'),
];
}
}
AddressBookController usecases:
<?php namespace App\Http\Aggregate\Address_book\Controller\v1_0;
use App\Http\Requests\AddressBookRequest;
use Illuminate\Routing\Controller as BaseController;
use EventHomes\Api\ApiController;
use JWTAuth;
class AddressBookController extends BaseController
{
And route :
Route::group(['namespace' => 'Aggregate\Address_book\Controller\v1_0', 'middleware' => 'jwt.auth', 'prefix' => 'api/v1.0/{lang}'], function () {
Route::post('customer/{id}/address_book', 'AddressBookController#add_address_book');
});
How can i fix it to use custom request?
Any help will be appreciated
You should add this line to the top of the controller:
use App\Http\Requests\AddressBookRequest;
Also, make sure authorize() method inside custom request class returns true:
public function authorize()
{
return true;
}
I fix it by adding :
use Illuminate\Foundation\Http\FormRequest;
use EventHomes\Api\ApiController;
abstract class Request extends FormRequest
{
use ApiController;
public function response(array $errors)
{
foreach($errors as $key=>$error)
{
return $this->respondUnprocessable(1004,'validation',$errors[$key][0]);
}
}
}
In requst.php

Categories