How to validate a post request without a specific attribute to validate - php

I have a time tracking application where every time that a new Time Entry is about to be added, I must first verify that all the previous time entries have been closed (meaning that an ending date has been set) and throw and error message using the validate() method.
I don't know how feasable this is or how to do it, reading the documentation it seems that most custome rules require that an attribute be given, but in this case it's more about validating the logical requirements rather than the form of the post request.
When I receive a post request I fetch all previous time entries which come before the post request starting time and have not yet been given an ending time.
Ideally, if I get any time entries returned I would throw an error saying 'You need to close the previous time entry before opening a new one'.
For more clarity, here is what I want to do in code :
$timeEntry= new TimeEntry;
$openTimeEntries = $timeEntry->Where('start_time', '<', $request->startTime)->Where('end_time', 0)->get();
$count = $openTimeEntries->count();
$request->validate([
'comment' => 'string',
'candidateId' => 'required',
'startTime' => 'required|date',
'endTime' => 'date|nullable|after:startTime',
'CustomeTimeEntryRule' => $openTimeEntries->count() > 0, // If false I want this rule to add the message to the validate error array
]);

You are on the right track.
However, If you really customize validation you should create a request for here you can read more about it.
Simply call php artisan make:request TimeEntryStoreRequest
public function rules()
{
return [
'CustomeTimeEntryRule' => $openTimeEntries->count() > 0,
];
}
/**
* #return array|string[]
*/
public function messages(): array
{
return [
'CustomeTimeEntryRule.*' => 'Custom message',
];
}
However, if it is not a form input from a user I think you should check it inside your controller not in the form.
Also you can simplify your code like this:
use App\Models\TimeEntry;
$openTimeEntriesCount = TimeEntry::select('id')->where('start_time', '<', $request->startTime)->where('end_time', 0)->count();

A simple way to do this is to merge the custom attribute to the request :
$timeEntry= new TimeEntry;
$openTimeEntries = $timeEntry->Where('start_time', '<', $request->startTime)->Where('end_time', 0)->get();
$count = $openTimeEntries->count();
$request->merge([
'CustomeTimeEntryRule' => $count,
]);
Then we can validate the attribute using the in rule, which will return a custom validation message which we can specify as a second argument, when the count is not equal to 0:
$request->validate([
'comment' => 'string',
'candidateId' => 'required',
'startTime' => 'required|date',
'endTime' => 'date|nullable|after:startTime',
'CustomeTimeEntryRule' => 'in:0',
], [
'CustomeTimeEntryRule.in' => 'You need to close the previous time entry before opening a new one'
]);

Related

Laravel Rules Unique if

I have some hard times with Laravel Rules (importing csv file).
I'm trying to use the Rule::unique function but when another field is not empty, for example:
public function rules(): array
{
return [
'code' => ['required', 'string', Rule::unique('product_gift_cards', 'code')],
'pin' => ['nullable'],
'sequence_number' => ['nullable']
];
}
So this code, should be unique only when sequence_number is not filled. When sequence_number is filled with something, the code should not be unique. I have deleted the unique index in the database, so it will work if I write is as needed, any suggestions?
These are the validation rules in Laravel: https://laravel.com/docs/9.x/validation#available-validation-rules
Sadly there's no unique_if rule here.
One possible solution here is you have to validate it manually. You check if the input has file uploaded using $this->hasFile('sequence_number').
$code_rules = ['required', 'string'];
// Check if sequence_number is NOT uploaded
if (! $this->hasFile('sequence_number')) {
$code_rules[] = Rule::unique('product_gift_cards', 'code');
}
return [
'code' => $code_rules,
'pin' => ['nullable'],
'sequence_number' => ['nullable']
];

How to check whether array elements are empty in Laravel? [duplicate]

This question already has answers here:
Validate array of inputs in form in Laravel 5.7
(6 answers)
Closed 3 years ago.
I am storing data from a form through an array to mysql database. Now I want to alert the user if he missed any field. So how can I alert him?
public function store(Request $request)
{
$holiday = array (
'firstname' => $request->firstname,
'lastname' => $request->lastname,
'startdate' => $request->startdate,
'enddate' => $request->enddate
);
Holiday::create($holiday);
return redirect()->route('holiday.index');
}
You can use Laravel's built in validation functionality for this. In your case, you might want to do something like this:
public function store(Request $request)
{
$holiday = $request->validate([
'firstname' => 'required',
'lastname' => 'required',
'startdate' => 'required',
'enddate' => 'required'
]);
Holiday::create($holiday);
return redirect()->route('holiday.index');
}
Laravel will then ensure that those fields have been provided and if they haven't it will return the appropriate response. For example, if this is an API call it will return a 422 response with the error messages in. Or, if it is not an API call, it will return the user to the previous page and store the errors in the session for you to retrieve.
I'd recommend reading more about Laravel's validation techniques and all the things you can do with it. You can find more information about it here - https://laravel.com/docs/6.x/validation

How to get validation message in laravel 5.5

hi folks I'm working on Laravel 5.5 and here I need to display validation messages for my API upto now I have done like this
$validator = Validator::make($request->all(),[
'first_name' => 'email|required',
'last_name' => 'nullable',
'email' => 'email|required',
'mobile_no' => 'nullable|regex:/^[0-9]+$/',
'password' => 'required',
]);
if($validator->fails)
{
$this->setMeta('status', AppConstant::STATUS_FAIL);
$this->setMeta('message', $validator->messages()->first());
return response()->json($this->setResponse(), AppConstant::UNPROCESSABLE_REQUEST);
}
Since Laravel 5.5 has some awesome validation features I am looking to validate my request like this
request()->validate([
'first_name' => 'email|required',
'last_name' => 'nullable',
'email' => 'email|required',
'mobile_no' => 'nullable|regex:/^[0-9]+$/',
'password' => 'required',
]);
But I am facing issue here what should I do to check if the validation fails? Like I was doing by if($validator->fails)
In Laravel 5.5, like the documentation mention, the validation process is very easy :
Displaying The Validation Errors :
So, what if the incoming request parameters do not pass the given
validation rules? As mentioned previously, Laravel will automatically
redirect the user back to their previous location. In addition, all of
the validation errors will automatically be flashed to the session.
Again, notice that we did not have to explicitly bind the error
messages to the view in our GET route. This is because Laravel will
check for errors in the session data, and automatically bind them to
the view if they are available.
AJAX Requests & Validation :
In this example, we used a traditional form to send data to the
application. However, many applications use AJAX requests. When using
the validate method during an AJAX request, Laravel will not generate
a redirect response. Instead, Laravel generates a JSON response
containing all of the validation errors. This JSON response will be
sent with a 422 HTTP status code.
So as you said : that means you don't need to put your ifs to handle validation laravel will take care of them itself great :)
here is some syntax that i use
public static $user_rule = array(
'user_id' => 'required',
'token' => 'required',
);
public static function user($data)
{
try{
$rules = User::$user_rule;
$validation = validator::make($data,$rules);
if($validation->passes())
{
}
else
{
return Response::json(array('success' => 0, 'msg'=> $validation->getMessageBag()->first()),200);
}
return 1;
}
catch(\Illuminate\Databas\QueryException $e) {
return Response::json(array('success' => 0, 'msg' => $e->getMessage()),200);
}
}
hope this will help you!
Please add Accept: application/json in you header.
Laravel automatically send an error message with response code.
As per 2019 Laravel 5.8 it is as easy as this:
// create the validator and make a validation here...
if ($validator->fails()) {
$fieldsWithErrorMessagesArray = $validator->messages()->get('*');
}
You will get the array of arrays of the fields' names and error messages.
You can show first error.
if ($validator->fails()) {
$error = $validator->errors()->first();
}
For all error :
$validator->errors()

Add a validation which is not related to the form

I want to add a validation on a form. My actual form works, here it is:
public function store(Request $request, $id)
{
$this->validate($request, [
'subject' => 'required',
'body' => 'required',
]);
// Do something if everything is OK.
}
Now, I want to check if the user is "active" too. So something like:
\Auth::user()->isActive();
And return an error with the other validation errors if the user is not active.
Can I append something to the validator that has no relation with the form itself? I mean I want to add an error to the other errors if the user is not active.
That code is only validating the request variable (first argument of validate() function). So you will have to put someting in the request to validate it. It applies the rules to the object/array given.
$request->is_active = Auth::user()->isActive();
$this->validate($request, [
'subject' => 'required',
'body' => 'required',
'is_active' => true //or whatever rule you want
]);
Anyways, I never tried that so not sure it will work. The usual way is to do an if
if ( !Auth::user()->isActive() ) {
return redirect->back()->withErrors(['account' => 'Your account is not active, please activate it']);
}
//continue here

Laravel 5.2 validator: Validate Array request parameter, at least one value must be selected

I am having a form where i am having title, body, answers[][answer] and options[][option].
I want atleast one answer must be selected for the given question, for example:
i have ABC question and having 5 options for that question,now atleast one answer must be checked or all for given question.
Efforts
protected $rules = [
'title' => 'required|unique:contents|max:255',
'body' => 'required|min:10',
'type' => 'required',
'belongsto' => 'sometimes|required',
'options.*.option' => 'required|max:100',
'answers.*.answer' => 'required',
];
But this is not working. i want atleast one answer must be selected.
Please help me.
The problem is that on $_POST an array filled with empty strings will be passed if no answer is selected.
$answers[0][0] = ''
$answers[0][1] = ''
$answers[0][2] = ''
Hence the following will not work since array count will be greater than zero due to the empty strings:
$validator = Validator::make($request->all(), [
'answers.*' => 'required'
]);
The easiest way to solve this is to create a custom Validator rule by using Laravel's Validator::extend function.
Validator::extendImplicit('arrayRequireMin', function($attribute, $values, $parameters)
{
$countFilled = count(array_filter($values));
return ($countFilled >= $parameters[0]);
});
And then call it in your Validation request:
$validator = Validator::make($request->all(), [
'answers.*' => 'arrayRequireMin:1'
]);
The magic happens in array_filter() which removes all empty attributes from the array. Now you can set any minimum number of answers required.
Validator::extendImplicit() vs Validator::extend()
For a rule to run even when an attribute is empty, the rule must imply that the attribute is required. To create such an "implicit" extension, use the Validator::extendImplicit() method:
Laravel's validation docs
Try this,
'answer.0' => 'required'
it will help you. I think.

Categories