I am trying to have one validation function for both store and update. So I don't repeat code. It works well. The problem is testing 'unique'. I worked around with this idea. But feels long-winded. Is there a better way to do it?
I want to check for unique at the store.
At update, unique check ignores own id.
I don't want different validations like I did as the user will be
first notified of the unique error, he will fix it. then something
else might be wrong and he has to fix again.
.
public function validateRequest($request){
if($request->method() == "PUT")
{
$val = $this->validate($request, [
'name' => 'unique:customers,id',
'phone' => 'unique:customers,id',
]);
}
if($request->method() == "POST"){
$val = $this->validate($request, [
'name' => 'unique:customers',
'phone' => 'unique:customers'
]);
}
$validation = $this->validate($request, [
'name' => 'required',
'phone' => 'required|integer|gt:0',
'phone2' => 'nullable|integer|gt:0|',
'email' => 'email|nullable',
'note' => 'nullable',
],
[
'phone.integer' => "Invalid phone format. Use international format. Eg: 971550000000",
'phone2.integer' => "Invalid phone format. Use international format. Eg: 971550000000",
'required' => "Required Field",
]);
return $validation;
}
Related
I am building a Book Portal with Laravel. I have a unique validation rule on name to books.
$request->validate([
'name' => 'required|unique:books',
'about' => 'required',
'dsecription' => 'required',
'image' => 'required|mimes:jpeg,bmp,jpg,png|between:1, 6000',
'author_id' => 'required',
'publisher' => 'required',
'recommended' => 'required',
'epub_url' => 'required',
'year'=> 'required',
'pages' => 'required',
]);
I found out that an Author can have the same book name. Using unique on the name, will not allow me to upload.
I am thinking, if there is a way, I can check the author and the name of the book i.e
Check if the author has the same name, then apply the unique rule on name else upload.
I didn't find any solution for this. That's why I made my own custom validation like this :
$request->validate([
'name' => 'required|unique:books',
'author_id' => 'required',
// ...
]);
$data = Book::where('author_id', $request->author_id)->where('name', $request->name)->first();
if(!empty($data)) {
return redirect()->back()->withErrors('This name already taken'); // error message
}
You can try using the extra where conditions that can be passed to the unique rule to apply the unique constraint under certain conditions:
// we will make sure 'author_id' is an existing value
'author_id' => 'bail|required|integer|exists:authors,id',
'name' => [
'bail',
'required',
Rule::unique('books')
->where('author_id', (int) $request->input('author_id')),
],
Assuming author_id is on the books table.
Laravel 7.x Docs - Validation - Rules - unique
In ContactsRequest.php
public function rules()
{
return [
'org_id' => 'required',
'name' => 'required',
'office' => 'required',
'mobile' => 'required_without:home',
'home' => 'required_without:mobile'
];
}
So basically what i want is , i have a form which will be taking the attributes specified in the code. But i want to modify code so that entering either one of 'home' or 'mobile' will allow me to create the new user.
What should be done.Any help would be appreciated
I am new to learning Laravel and still trying to learn beautiful coding.
I have a code like this that validates the input fields upon submitting the update form and it has many unnecessary codes that can be modified to make it short and better.
So my question is, what is an approach or technique should I take to rewrite my codes to make it short and beautiful.
public function update(Request $request, $id)
{
$product = Product::find($id);
if ($product->name != $request->name AND $product->sku != $request->sku AND $product->description != $request->description) {
$this->validate($request, [
'name' => 'required|unique:products,name',
'sku' => 'required|unique:products,sku',
'description' => 'required'
]);
} elseif ($product->name != $request->name AND $product->sku != $request->sku) {
$this->validate($request, [
'name' => 'required|unique:products,name',
'sku' => 'required|unique:products,sku'
]);
} elseif ($product->name != $request->name AND $product->description != $request->description) {
$this->validate($request, [
'name' => 'required|unique:products,name',
'description' => 'required'
]);
} elseif ($product->description != $request->description AND $product->sku != $request->sku) {
$this->validate($request, [
'description' => 'required',
'sku' => 'required|unique:products,sku'
]);
} elseif ($product->name != $request->name) {
$this->validate($request, [
'name' => 'required|unique:products,name'
]);
} elseif ($product->description != $request->description) {
$this->validate($request, [
'description' => 'required'
]);
} elseif ($product->sku != $request->sku) {
$this->validate($request, [
'sku' => 'required|unique:products,sku'
]);
} else {
return redirect('products/' . $product->id)->with('info', 'Product does not changed!');
}
}
Looks like you have two issues that you need to address to shorten your code:
1) The product name and sku fields are required but you want to avoid collisions with the values that exist on the product that you plan to update.
2) The description field isn't actually required but when it is present it must be not be validated. (shouldn't there be a min:1 validation or something?)
So to solve #1 you need to write your own unique rule to ignore the current $product which you are trying to update when determining a unique value. See Forcing A Unique Rule To Ignore A Given ID -- Laravel Docs
And to solve #2 you can use the sometimes validation Conditionally Adding Rules -- Laravel Docs
Combining those should allow you to use a single validation statement like this:
use Illuminate\Validation\Rule;
...
$this->validate($request, [
'name' => [
'required',
Rule::unique('products')->ignore($product->id)
],
'sku' => [
'required',
Rule::unique('products')->ignore($product->id)
],
'description' => Rule::sometimes('description', 'required', function($input){
return $input->description !== $product->description;
});
]);
If this is not correct please, update this answer for the next person who stumbles by. Hope this helps.
[Tip:] It seems like a long shot but if the description field is a WYSIWYG field on the client interface I have had them hit the max length of a text field as they can convert images into base64, so even although it's unlikely for most situations I try to incorporate max:65535 in the validation so that it does gracefully fail. (65535 is the max length of a MySQL text field other databases are different sizes)
I have 1 form, with multiple inputs. each section can have multiple inputs, I want to create a Form Validator inside Requests for they, but don't know how to do it... This is currently how I am doing it:
public function postCreateResume(Request $request, Resume $resume, Education $education)
{
/*
* begin a transaction, because we
* are doing multiple queries
*/
DB::beginTransaction();
/*
* first we must create the resume, then we
* can use the id for the following rows
*/
$this->validate($education, [
'resume_title' => 'required',
'expected_level' => 'required',
'salary' => 'required',
'work_location' => 'required',
'year_experience' => 'required',
'about' => 'required',
]);
$resume->name = $request['resume_title'];
$resume->work_level = $request['expected_level'];
$resume->salary = $request['expected_salary'];
$resume->country = $request['work_location'];
$resume->total_experience = $request['year_experience'];
$resume->about = $request['about'];
$resume->save();
// a user can have multiple educations on their cv
foreach($request->input('education') as $education){
$this->validate($education, [
'institution' => 'required',
'degree' => 'required',
'year_begin' => 'required',
'year_finish' => 'required',
'about' => 'required',
]);
// passed our checks, insert
$education->resume_id = $resume->id;
$education->user_id = Auth::user()->id;
$education->institute = $education['institution'];
$education->degree = $education['degree'];
$education->summary = $education['about'];
$education->started = $education['year_begin'];
$education->ended = $education['year_finish'];
if(!$education->save()){
DB::rollback();
return redirect()->back()->withErrors("There was an error creating this resume")->withInput();
}
}
// a user can have multiple employment on their cv
foreach($request->input('experience') as $employment){
$this->validate($employment, [
'company' => 'required',
'title' => 'required',
'country' => 'required',
'year_begin' => 'required',
'year_finish' => 'required',
'notes' => 'required',
]);
// passed our checks, insert
$employment->resume_id = $resume->id;
$employment->user_id = Auth::user()->id;
$employment->name = $employment['title'];
$employment->company = $employment['company'];
$employment->country = $employment['country'];
$employment->started = $employment['year_begin'];
$employment->ended = $employment['year_finish'];
$employment->summary = $employment['notes'];
if(!$employment->save()){
DB::rollback();
return redirect()->back()->withErrors("There was an error creating this resume")->withInput();
}
}
return redirect()->back()->withSuccess("You have created a resume")->withInput();
}
Notice I have the validate inside each of the foreach in case the user has chosen more than 1 (in this example) work experience, or education, what I am trying to do is move the $this->validate inside the Requests folder, how can I achieve this?
I am using a foreach because I can have unlimited sections, see the image as to why;
Since laravel 5.4 you can pass arrays to the validator itself, for exaple
<input name="myarray[0]['test'] type="text">
Can now be validated like so
$this->validate($request, [
'myarray.*.test' => 'required'
]);
https://laravel.com/docs/5.4/validation#validating-arrays
Validating array based form input fields doesn't have to be a pain. For example, to validate that each e-mail in a given array input field is unique, you may do the following:
$validator = Validator::make($request->all(), [
'person.*.email' => 'email|unique:users',
'person.*.first_name' => 'required_with:person.*.last_name',
]);
Likewise, you may use the * character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields:
'custom' => [
'person.*.email' => [
'unique' => 'Each person must have a unique e-mail address',
]
],
This my request class rules.
return [
'title' => 'required|unique:event_cals,title',
'eventDate' => 'required|date|after:yesterday',
'venue' => 'required',
'time' => 'required',
'type' => 'required',
'unique:event_cals,eventDate,NULL,id,venue,$request->venue,time,$request->time'
];
I want to validate a rule like below.
'eventDate' && 'venue' && 'time' => 'unique'
There I need to check if there any row without same eventDate, venue and time altogether. Anyone knows how to declare such a rule?
This is the snapshot of db table.
Here is the possible solution:
<?php
return [
'title' => 'required|unique:event_cals,title',
'eventDate' => 'required|date|after:yesterday',
'venue' => 'required',
'time' => 'required',
'type' => 'required',
'event_date' => "unique:event_cals,event_date,NULL,id,venue,{$request->venue},time,{$request->time}",
];
I again want to highlight that; if you want that validator to work, you should make sure that the event_date and time should be correctly formatted.
An example unique check with additional wheres from our running project's update requests:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$id = $this->route('money');
return $rules = [
'name' => "required|string|min:3|max:255|unique:moneys,name,{$id},id,deleted_at,NULL,access,public",
];
}