Validate if another field is empty laravel validation - laravel

I want to validate field if present and will fail if another field not present
How to do it ? I have create custom validation to get record based id on storage
I have field product_id and amount and the amount field validate between max and min based on product_id, if i present the amount = 100000 and not fill the product_id field the validating for amount field is passed and display error because i am not fill the product_id i want check before the custom validation execute will check if product_id empty or not..
I have read all validation method on laravel docs still didnt find the solution.
How to do it ?

Finally i found a solution...
on Form Request class i just add sometimes rule on validate instance so when the product_id field not present on amount field will not validate and when present it will validate using validation rules like this:
class StoreRequest extend FormRequest
{
protected function getValidatorInstance()
{
$validator = parent::getValidatorInstance();
$validator->sometimes('amount', 'required|numeric|max_amount:product_id', function ($input) {
return Arr::has($input, 'product_id');
});
return $validator;
}
}

Related

Laravel validation a field in an array

I'm building a farming app with Laravel and Vue. There are several activities that happen everyday in the farm and an activity might need to use products (fertilizers). In the Create.vue Activity page I'm generating multiple html inputs. A select to select a product an input to enter the quantity so I end up having a selected_products array in my request. Here's a data sample when I dd($request->all)
What is the problem?
The quantity entered in the selected_products array must be less than or equal to the quantity in stock. (can't have a product with id 9 with quantity 10 (liters or kilograms) when I only have 5 (liters or kilograms) in stock for that product)
So Product and Stock are one-to-one relationship
Product.php
public function stock () {
return $this->morphOne(Stock::class, 'stockable');
}
(I'm using morphOne here 'cause stock can also include the fuel quantity for tractors just in case you're curious)
Anyways I just want the validation to fail and return an Out of stock if the quantity in stock for that very product is less than the quantity entered
By the way after the validation I'm doing this sort of thing in my ActivityController store method so I can attach date in the activity_product table
attach_product_data = [];
foreach ($request->input('selected_products') as $product) {
$attach_product_data[$product['id']] = ['quantity' => $product['quantity']];
}
$activity->products()->attach($attach_product_data);
And this is what I'm trying to accomplish here but I have no idea how
StoreActivityRequest.php
public function rules()
{
return [
'selected_products.*.id' => ['nullable'],
'selected_products.*.quantity' => ['required_with:selected_products.*.id',
function () {
/* first we should find the product with the
`selected_products.*.id` id and check if the quantity in stock is
greater than or equal to the quanity in
`selected_products.*.quantity` */
}],
];
}
After taking a look at some data sample, you might access the ID of each field in the selected_products array in a slightly different manner than your current approach.
The idea here is to no longer validate each selected_products.*.id and selected_products.*.quantity separately but rather use a validation callback on selected_products.* key in the rules array.
Here's a code sample to explain more:
public function rules()
{
return [
'selected_products' => ['array'], // Tell Laravel that we're expecting an array
'selected_products.*' => [function ($attr, $val, $fail) {
// $val is an array that contains the "id" and "quantity" keys
// Only proceed validating when "id" is present (as i saw you're using "nullable" rule on "selected_products.*.id")
if (isset($val['id'])) {
// If no quantity is selected the raise a validation exception (based on your usage of "required_with" rule)
!isset($val['quantity']) && $fail('the quantity is required when id is present.');
// At this stage we're sure that both "id" and "quantity" are present and we might check the DB using the Product modal for example.
// If no product is found using the current "id" then raise a validation failure exception
!($prd = Product::whereId($val['id'])->first()) && fail('Unknown product with ID of ' . $val['id']);
// If the quantity in the DB is less than the selected quantity then a validation failure exception is raised as well
$prd->quantity < $val['quantity'] && fail('The selected quantity exceeds the product quantity in stock.');
}
// If no "id" is found on "selected_products.*" then nothing happens (based on your usage of "nullable" and "required_with" rules
}],
];
}
Because i have spoke of the usage of the explode function above in the comments, here's a code sample that demonstrates it's usage which cannot be applied to your current data structure by the way so I'll improvise my own structure just to demonstrate.
To use the explode function, the fields should be indexed by the IDs (9, 8 and 1 as your data sample), something like this:
With that structure we have greatly reduced the size of the data being sent in the form as we have ditched the id key entirely along with quantity key and instead we simply have Product ID => Selected Quantity.
Based on that structure, we might validate the data as follows:
public function rules()
{
return [
'selected_products' => ['array'],
'selected_products.*' => [function ($attr, $val, $fail) {
// $val contains the selected quantity and $attr can help us get the respective "id"
// We can use "explode" to get the "id"
// Based on my above data sample, $attr can be "selected_products.9", "selected_products.8" or "selected_products.1"
!($id = explode('.', $attr)[1] ?? null) && $fail('Unknown product id.');
// Fetch the DB
!($prd = Product::whereId($id) && fail('Unknown product with ID of ' . $val['id']);
// Validate the selected quantity against what we have in the DB
$prd->quantity < $val && fail('The selected quantity exceeds the product quantity in stock.');
}],
];
}
In the end, I hope i have managed to land some help. Feel free to ask for more details/explanations at any time and meanwhile here are some useful links:
explode function documentation on php.net
Laravel docs about using closures (callback functions) as custom validation rules.

How to validate a relation property in Laravel?

What I have
I have a Room model with a has many relation to Reservation. Room has a property is_open indicating that the given room is available.
Goal
I would like to be able to validate in the rules function of a FormRequest that a room is available when I store a new reservation based on the is_open property.
What I tried
The validated data is in an array so the rule key needs to be this: data.room_id. I know that exists can validate something in the database but I don't know how its syntax works. Also how can I validate a property of a relation?
class ReservationStoreRequest extends FormRequest {
public function authorize() {
return true;
}
public function rules() {
return [
'data.room_id' => 'exists:' // what goes here?
];
}
}
tl;dr
public function rules() {
return [
'data.room_id' => [
Rule::exists('rooms', 'id')->where(function ($query) {
$query->where('is_open', 1);
})
]
];
}
Validating with exists
There is documentation on the exists rule but it is really concise. Lets see what the commands in the docs actually mean. The point of this rule is that it can validate the existence of a field in a table in your db given by some criteria. For example, when you save a reservation you can validate that the room you are reserving is exists in the database.
Basic usage
'size' => 'exists:rooms'
This will check the rooms table if there is an entry where the size column contains the value that is the value under validation (in this case the corresponding value of key size which is large). This results in the following SQL query:
select count(*) as aggregate from `rooms` where `size` = "large";
Specifying a custom column name
In the previous section the validated column's name comes from the key of the validated property ('size'). You might want to give a different column name because you are validating a column that is named differently from your data's key (e.g. 'size' is stored in the 'category' column) another case is that your rooms table's primary key is just id instead of room_id like in the validated data. In your case the validated data's key is data.room_id but you would like to check the id column of rooms. You can specify the column's name separated by a comma:
'data.room_id' => 'exists:rooms,id'
This will check the rooms table if there is an entry where the id column contains the value under validation resulting in the following SQL query:
select count(*) as aggregate from `rooms` where `id` = 4;
Specify a custom column name with extra clauses
If you need to further filter the results you can use the Illuminate\Validation\Rule class. You pass the table and column name (the second being optional just like in the basic usage section) and in an anonymous function add the extra clauses to the query. You can use every input data in the request, just retrieve it with $this->input('propertyName') or $this->all() then processing it by hand:
'data.room_id' => [
Rule::exists('rooms', 'id')->where(function ($query) {
$query
->where('is_open', 1);
->where('size', $this->input('data.size'));
})
]
The resulting SQL query is this:
select count(*) as aggregate from `rooms` where `id` = 4 and (`is_open` = 1 and `size` = large);
The available clauses in the $query variable are where, whereNot, whereNull, whereNotNull, whereIn and whereNotIn. Check out the Illuminate/Validation/Rules/Exists class docs.

Laravel unique validation must include appended text when validating

I am using the Laravel tenancy package in which there is a domains table in my database and each value in the domain column within this table is appended with .test.co.uk.
When the user enters the URL in the form, they are presented with an input element (shown above) in which they enter a URL/Domain but the .test.co.uk is already appended so the only thing they need to enter is the text that goes before that, e.g. they would enter johnsmith and in the domain column it would store johnsmith.test.co.uk. The problem I have is that I need the validation on this column to be unique but also include the .test.co.uk when performing the validation so that it looks at the value stored in the table because if a user enters johnsmith and there is currently a record in the domains table where the value is johnsmith.test.co.uk then the validation would pass but I need the validation to fail in this scenario. I am currently using a Request class which is extending the FormRequest class and have this:
public function rules()
{
return [
'url' => 'required|string|unique:domains,domain',
];
}
I have also tried a rule object but I don't think a rule object is the correct solution to this problem. Is there a convenient "Laravel" way of doing this?
In your Request class use prepareForValidation()
Docs: https://laravel.com/docs/7.x/validation#prepare-input-for-validation
protected function prepareForValidation()
{
$this->merge([
'url' => $this->url . '.test.co.uk',
]);
}

Laravel Validator unique value

I am trying to validate an email address in my Customer table. There is a column in the Customer table called Brand where effectively the same email address could be registered to multiple brands for example:
Email Brand
me#mywebsite.com firstsite.com
me#mywebsite.com secondsite.com
When validating the email address I need to check the email is unique in the Customer table for the current Brand. Currently my validation rule looks like this
$rules = array('email' => 'required|email|unique:Customer,Email');
however Brand must appear in there someone to say the email must be unique to the customer for the current brand
Any help much appreciated
You can use the column and value parameter of the unique validation rule to add a condition to the rule.
'email' => 'required|email|unique:Customer,Email,null,null,column,value'
The problem is you need your Brand input in order to create your rule like this :
$rules['email'] = 'required|email|unique:Customer,Email,null,null,Brand,' . Input::get('Brand');
This rule will check if the email is unique where the brand has the given value.
More information here :
http://laravel.com/docs/validation#rule-unique
There is also a package that could help you :
https://github.com/felixkiss/uniquewith-validator
$rules = array('email' => 'required|email|unique:Customer,Email'); this will query your model for finding the entered email if the email is already present then an error message is raised. so this will not work with your app design flow. you have to run sql query to find out if the email is present with your current brand if yes return error message if not save the data. something like that
I would go for writing my own custom validation rule. Custom validation rule will be more common solution and you can name it as it suites you best. It can be created using the Validator::extend() and a closure, like this :
Validator::extend('awesome', function($field, $value, $params)
{
return $value == 'awesome';
});
or via validator class. Have a research at this topic, maybe here (scroll to custom rules section) or any other source you find.

Codeigniter check unique value when editing form without using callback function

Codeigniter check unique value while editing form.
When edit the form it checks for current row, and it give username already exist. so how to avoid it.and don't check for current record.
So how can i pass id to is_unique function in CI_Form_Validation class function and add condition?
See my below code:
$this->custom_validation->set_rules('username','Username',
'trim|required|max_length[30]|is_unique[adminuser.username]');
Simply put a unique validation only if value of that field is changed ie.
$old_value='old value';
if ($posted_value!=$old_value) {
$this->custom_validation->set_rules('username','Username',
'trim|required|max_length[30]|is_unique[adminuser.username]');
} else {
$this->custom_validation->set_rules('username','Username',
'trim|required|max_length[30]);
}

Resources