Laravel validation with custom condition - validation

I'm trying to setup validation rule with condition but have no idea how to do following:
In my form I have title_url (array for multiple language versions). I want to have unique title_url but only when module_cat_id in the form has same value as existing rows in DB.
This is my rule:
'title_url.*' => 'required|min:3|unique:modules_cat_lang,title_url'
Any ideas how to solve this?

You can define your custom similar to code below:
\Validator::extend('custom_validator', function ($attribute, $value, $parameters) {
foreach ($value as $v) {
$query = \DB::table('modules_cat_lang') // use model if you have
->where('title_url', $v)
->where('module_cat_id', \Input::get('module_cat_id'));
if ($query->exists()) {
return false;
}
}
});
'title_url.*' => 'required|min:3|custom_validator'
Read more here https://laravel.com/docs/5.3/validation#custom-validation-rules .

If you want to add your own custom validation logic to the existing laravel validator then You can use after hooks. Please have a look at the below examples.
Reference : https://laravel.com/docs/8.x/validation#adding-after-hooks-to-form-requests
Example 1(Without Parameter)
$validator->after(function ($validator) {
if ('your condition') {
$validator->errors()->add('field', 'Something went wrong!');
}
});
Example 2(With Parameter) // Here you can pass a custom parameter($input)
$validator->after(function ($validator) use ($input) {
if ($input) {
$validator->errors()->add('field', 'Something went wrong!');
}
});

Related

Laravel - request validation

I extedned request class to create my own valdiation rules. In that class I added my custom validation function. In function I check if tags are pass regEx and I would like to filter tags to remove tags shorter then 2 characters.
And later keep in request only tags that passed validation.
public function createPost(PostRequest $request)
{
dd($request->all()); //In this place I would like to keep only tags passed through validation not all tags recived in request
}
Is it possibile to do it? How to set it in Request class?
'tags' => [
'nullable',
'string',
function ($attribute, $value, $fail){
$tagsArray = explode(',', $value);
if(count($tagsArray) > 5) {
$fail(__('place.tags_max_limit'));
}
$tagsFiltered = [];
foreach ($tagsArray as $tag){
$tag = trim($tag);
if(preg_match('/^[a-zA-Z]+$/',$tag)){
$tagsFiltered[] = $tag;
};
}
return $tagsFiltered;
}
],
EDIT:
I think we miss understanding. I would like to after validation have only tags that returned in variable $tagsFiltered; Not the same as recived in input.
You have to create this custom regex rule and use it into rules() function.
Like so:
public function rules()
{
return [
'tag' => 'regex:/[^]{2,}/'
];
}
public function createPost(PostRequest $request)
{
$request->validated();
}
And then just call it via validated() function wherever you want.
first define validation rule with this command:
php artisan make:rule TagsFilter
navigate to TagsFilter rule file and define your filter on passes method:
public function passes($attribute, $value)
{
$tagsArray = explode(',', $value);
$tagsFiltered = [];
foreach ($tagsArray as $tag){
$tag = trim($tag);
if(preg_match('/^[a-zA-Z]+$/',$tag)){
$tagsFiltered[] = $tag;
};
}
return count($tagsArray) > 5 && count($tagsFiltered) > 0;
}
then include your rule in your validation on controller:
$request->validate([
'tags' => ['required', new TagsFilter],
]);

How to check data exists in the database

I have a function to add new property. But i want to check for duplicate data at column "code" before add new data into database. If data exists will appear a message error.
function addPro(Request $req)
{
$id = $req->type_id;
$type = AssetType::find($id);
if($req->save == 'save'){
$pro = new TypeProperties;
$pro->name = $req->name;
$pro->code = $req->code;
$pro->type = $req->type;
$pro->assettype_id = $req->type_id;
$pro->save();
Schema::table($type->code, function ($table) use ($pro) {
if ($pro->type == "textbox")
$table->string($pro->code )->nullable();
if ($pro->type == "textarea")
$table->text($pro->code )->nullable();
});
return redirect(url($type->id.'/add/property'))->with('message','Save successful');
}
return redirect(url('asset/type/'.$type->id));
}
You can use laravel Request Validation
function addPro(Request $req)
{
$id = $req->type_id;
$type = AssetType::find($id);
if($req->save == 'save'){
$req->validate([
'code' => 'required|unique:tablename'
]);
$pro = new TypeProperties;
$pro->name = $req->name;
$pro->code = $req->code;
$pro->type = $req->type;
$pro->assettype_id = $req->type_id;
$pro->save();
Schema::table($type->code, function ($table) use ($pro) {
if ($pro->type == "textbox")
$table->string($pro->code )->nullable();
if ($pro->type == "textarea")
$table->text($pro->code )->nullable();
});
return redirect(url($type->id.'/add/property'))->with('message','Save successful');
}
return redirect(url('asset/type/'.$type->id));
}
The most simple way to do this is by checking if code is_null :
if (is_null($pro->code)) {
// It does not exist
} else {
// It exists
}
The other way is to make a validation using Laravel's built in ValidateRequest class. The most simple use-case for this validation, is to call it directly in your store() method like this:
$this->validate($req, [
'code' => 'required|unique,
//... and so on
], $this->messages);
With this, you're validating users $req by saying that specified columns are required and that they need to be unique, in order for validation to pass. In your controller, you can also create messages function to display error messages, if the condition isn't met:
private $messages = [
'code.required' => 'Code is required',
'code.unique' => 'Code already exists',
//... and so on
];
You can also achieve this by creating a new custom validation class:
php artisan make:request StorePro
The generated class will be placed in the app/Http/Requests directory. Now, you can add a few validation rules to the rules method:
public function rules()
{
return [
'code' => 'required|unique,
//... and so on
];
}
All you need to do now is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic:
public function store(StorePro $req)
{
// The incoming request is valid...
// Retrieve the validated input data...
$validated = $req->validated();
}
If you have any additional question about this, feel free to ask. Source: Laravel official documentation.
What does your migration look like for AssetType?
I ask because you can do this in the schema with ->unique() added to the column on the creation or make a migration to add the constraint.
You can also check with something like this:
// Search database table for entry
$entry = AssetType::where('code', '=', $pro->code)->first();
// If not found
if ($entry === null) {
// Save method here.
}
Otherwise, you can use the manual validator or create a Request with validation
References:
https://laravel.com/docs/5.8/queries#where-clauses
https://laravel.com/docs/5.8/validation#creating-form-requests
https://laravel.com/docs/5.8/validation#manually-creating-validators

Retrieve parameters from custom validation object

I have basic custom validation rule. In
public function passes($attribute, $value)
{
foreach ($parameters as $key)
{
if ( ! empty(Input::get($key)) )
{
return false;
}
}
return true;
}
I have my rule defined. I, although need to retrieve parameters from the rule but the passes method does not provide it as an argument.
If I would use the style Validator:extends... that provides 4 arguments: $attribute, $value, $parameters, $validator. Then I could use the parameters easily, unfortunatelly I have to use this way.
EDIT:
To clear the question. I want to retrieve the parameters of the rule, like so in other way of coding it:
'not_empty:user_id'. The array of values behind the colon.
Edit:---
The custom rule object is simply an object. If you want to pass it any more parameters you can in it's constructor:
$request->validate([
'name' => ['required', new MyCustomRule('param', true, $foo)],
]);
Then save those and use them in your passes function.
public function __construct($myCustomParam){
$this->myCustomParam = $myCustomParam;
}
Then in your passes function use:
$this->myCustomParam
I believe the only way is to retrieve it from the request when using rule objects.
For example:
public function passes($attribute, $value)
{
foreach ($parameters as $key) {
// Or using \Request::input($key) if you want to use the facade
if (!empty(request()->input($key)) {
return false;
}
}
return true;
}

Laravel 5.5 / Validator / Custom rules

(edited to clearer purpose)
I discovered Laravel some months ago and I followed some Laracast videos. Now, I'm stuck with a problem of custom Validator.
I've got normal and permanent rules (date | required | min / max) to verify my form request. This part works.
But I've got a custom validation which could be verified as a normal rule IF one of the request parameter - select1 - is set to 1 (for exemple).
I read a dozen of explanation but nothing clear enough.
So, let start with my code. Thank you for your indulgence...
My question is into the customTest function on the bottom.
Thank you,
1/ I made a new Request with
php artisan make:controller priceRequest.php
2/ I made some rules and changed some lines.
public function authorize()
{
return true;
}
// Permanent RULES
public function rules()
{
$rules = [
'field1' => 'required|min:1|max:15',
'field2' => 'required',
'date1' => 'required|date',
'select1' => 'required',
];
return $rules;
}
Then I integrated a new function to perform a custom verification
public function withValidator($validator) {
$validator->after(function ($validator) {
if (!$this->customTests($this->request->get('data'))){
$validator->errors()->add('custom', 'Something is wrong');
}
});
}
Finally, I wrote the customTests function and it is inside this one I'm stuck !!
public function customTests($data) {
if ($data['select1'] == 1) {
// HERE MY QUESTION
// I'd like to verify that $data['date2']
// is a date and is set. So, I'd like to
// add a rule to rules (has I made with
// 'date1' => 'required|date',
// and return TRUE if the rule match or
// FALSE
}
}
So, I found the solution to my problem.
I made a mistake and a confusion because I tried to add the new rule into the ->after() function.
So, the correct code is the following :
public function withValidator($validator)
{
$validator->sometimes('ticket.price', 'required|integer|min:0.1', function ($input) {
if ($any_condition_who_need_to_verify_new_rule) {
return true;
}
else {
# Everything is perfect, this rule cas be omitted
}
$validator->after(function ($validator) use ($ticket) {
/* New test more complicated which cannot be
tested with a rule */
if ($this_test_is_complex_and_fails) {
$validator->errors()->add('validateTicket', 'This is another problem');
return false;
}
});
return $validator;
}

Yii2 custom validation rule not working

I'm trying to write some custom validation for a model in yii2, but I can't figure out why the validation always is positive, although my validation function always adds an error.
for example the rules
public function rules()
{
return [
...
[['myattribute'], 'myvalidation'],
];
}
public function myvalidation($attribute, $params)
{
$this->addError($attribute, "error");
}
the validate() function still returns true. What's the problem?
In validation rule add skipOnError => false
[
['myattribute', 'myvalidation', 'skipOnError' => false],
]
Then
$model->validate(); // should return false;
What I will recommend you is watch this lesson on custom roles and
read docs on it. It's not the best video tutorial, but this guy made it work correctly.
In your case :
1.In [['myattribute'], 'myvalidation'], remove extra array from here, make your model rules and custom valdation function look like this
public function rules()
{
return [
...
['myattribute', 'myvalidation'],
];
}
public function myvalidation($attribute, $params)
{
$this->addError($attribute, "error");
}
it's not wrong, but it's used when you have more than one attribute.
2.Then go to your form and put `` to your ActiveForm so it will look like this
<?php $form = ActiveForm::begin(['enableAjaxValidation' => true]); ?>
I mean, your need to do it in case if you want to validate it without reloading (using ajax).
3.Also add this to your controller's action that is connected to your view
if(Yii::$app->request->isAjax && $model->load($_POST)) {
Yii::$app->response->format = 'json';
return \yii\widgets\ActiveForm::validate($model);
}
This will validate your input in the form via ajax, if it's not ajax, this will not work.
['reg_date','validateDate', 'skipOnEmpty' => false, 'skipOnError' => false]
add this to your rules
public function validateDate($attribute,$params,$validator)
{
$validator->addError($this,$attribute,"Bugungi sana bo'lishi kerak!");
}
check this in your controller side like this
if($model->validate()){
echo "validate works";
}

Resources