error messge output not displaying correctly - laravel

could someone show me how to get the :other or :after_field to display in the error message.
$messages = ["after_field" => "The :attribute must be greater than the :other."];
validation rule:
$rules = ['sale_end' => 'date|after_field:sale_start']
protected function validateAfterField($attribute, $value, $parameters)
{
return Carbon::parse($value) > Carbon::parse($this->data[$parameters[0]]);
}

I don't see much point to creating custom validation rule for this.
You can change those rules this way:
public function rules()
{
$date = $this->data[$parameters[0]];
// here you need to change $date format to be valid according to http://php.net/manual/en/datetime.formats.php
$rules = ['sale_end' => 'date|after:'.$date];
// ...
return $rules;
}

Related

Why is my validation rule not working in my Laravel Controller?

I am trying to write a test that checks that a date is formatted correctly. Looking at the docs it seems pretty straight-forward.
Here is my test. I am submitting an invalid date format to my controller:
MyTest.php
/** #test */
public function a_date_must_be_formatted_correctly()
{
$foo = factory(Foo::class)->raw([
'date' => date('d/m/Y'),
]);
$response = $this->postJson('api/v1/foo', $foo)
->assertStatus(422)
->assertJsonValidationErrors('date');
}
Here is my controller method:
public function store(Request $request)
{
$attributes = $request->validate([
'date' => 'required|date_format:Y-m-d',
]);
...
}
I get a passing test each time.
I have also tried wrapping the format in quotes: 'date' => 'required|date_format:"Y-m-d"',
I'm expecting to get a 422 back saying my date is invalid. What am I doing wrong?
Well, I ended up writing a custom rule. I don't think this is the correct solution though given that Laravel has the handy built-in stuff. I feel like I should be leveraging that instead. In my case I am working with Blackout date(s).
Hers is what I ended up with. If there is a way to make the built-in methods work, please let me know so I can update the answer.
MyTest.php
/** #test */
public function a_blackout_date_must_be_formatted_correctly()
{
$blackout = factory(Blackout::class)->raw([
'date' => date('d/m/Y'),
]);
$response = $this->postJson('api/v1/blackouts', $blackout)
->assertStatus(422)
->assertJsonValidationErrors('date');
}
MyController.php
public function store(Request $request)
{
$attributes = $request->validate([
'date' => ['required', new DateFormatRule],
...
]);
$blackout = new Blackout($attributes);
...
}
DateFormatRule.php
public function passes($attribute, $value)
{
// The format we're looking for.
$format = 'Y-m-d';
// Create a new DateTime object.
$date = DateTime::createFromFormat($format, $value);
// Verify that the date provided is formatted correctly.
return $date && $date->format($format) === $value;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'Invalid date format.';
}
In my test I am getting a 422 response as expected. I can verify things are working by changing the name of the expected error from date to date123 and I'll get an error -- saying It was expecting date not date123.
Hope this helps someone!

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],
]);

Laravel Custom validation rule with parameters

I have write this function rule in CustomRequest to check checkHackInputUser rule that define in provider:
Actually i want to check the value that pass in route
for example :
http://www.somedomain.com/user/{id}
I what do some operation on this $id variable
with my checkHackInputUser rule
Here is CustomRequest:
public function rules()
{
$request_id = $this->route('user');
$rules = [];
if($this->method() == "DELETE" || $this->method() == "GET" )
$rules = [
'role_list' => 'required|checkHackInputUser:'.$request_id,
];
return $rules;
}
The problem is,this rule(checkHackInputUser) doesn't work if i remove required role.
Here is the checkHackInputUser validation function in provider:
public function boot()
{
$this->app['validator']->extend('checkHackInputUser',function($attr,$value,$params){
//Some validation
return false or true;
});
}
You can conditionally validate input when present using sometimes.
In some situations, you may wish to run validation checks against a field only if that field is present in the input array. To quickly accomplish this, add the sometimes rule to your rule list:
$v = Validator::make($data, [
'email' => 'sometimes|required|email',
]);

laravel array validation only one required

Hello i have a form for image upload
<input type="file" name="ad_image[]">
i want only one image to be required and others to be optional.
This is my validation rule and is not working:
'ad_image.*' => 'required|min:1|mimes:png,gif,jpeg,jpg|max:300',
i have tryed this:
'ad_image' => 'required|array|min:1|mimes:png,gif,jpeg,jpg|max:300',
also not working, when i upload jpg file there is error "The ad image must be a file of type: png, gif, jpeg, jpg."
please help with this issue
You can try:
public function rules()
{
$rules = [
'ad_image0'=> 'image|required|mimes:png,gif,jpeg,jpg|max:300'
];
$nbr = count($this->input('ad_image')) - 1;
foreach(range(0, $nbr) as $index) {
$rules['ad_image.' . $index] ='image|mimes:png,gif,jpeg,jpg|max:300';
}
return $rules;
}
I have decided to make my own custom validation rule:
This code is in boot method of the AppServiceProvider
public function boot()
{
Validator::extend('require_one_of_array', function($attribute, $value, $parameters, $validator) {
if(!is_array($value)){
return false;
}
foreach ($value as $k => $v){
if(!empty($v)){
return true;
}
}
return false;
});
}
The validation message is manualy added as third parameter of the validator
$messages = [
'require_one_of_array' => 'You need to upload at least one pic.',
];
And this is how is used to make sure at lease one image is uploaded (this is in rules array):
'ad_image' => 'require_one_of_array',
'ad_image.*' => 'mimes:jpeg,bmp,png|max:300',

yii2 custom validation not working

I need to compare 2 attribute value in the model and only if first value is lower than second value form can validate.I try with below code but it not worked.
controller
public function actionOpanningBalance(){
$model = new Bill();
if ($model->load(Yii::$app->request->post())) {
$model->created_at = \Yii::$app->user->identity->id;
$model->save();
}else{
return $this->render('OpanningBalance', [
'model' => $model,
]);
}
}
Model
public function rules()
{
return [
[['outlet_id', 'sr_id', 'bill_number', 'bill_date', 'created_at', 'created_date','bill_amount','credit_amount'], 'required'],
[['outlet_id', 'sr_id', 'created_at', 'updated_at'], 'integer'],
[['bill_date', 'd_slip_date', 'cheque_date', 'created_date', 'updated_date','status'], 'safe'],
[['bill_amount', 'cash_amount', 'cheque_amount', 'credit_amount'], 'number'],
[['comment'], 'string'],
['credit_amount',function compareValue($attribute,$param){
if($this->$attribute > $this->bill_amount){
$this->addError($attribute, 'Credit amount should less than Bill amount');
}],
[['bill_number', 'd_slip_no', 'bank', 'branch'], 'string', 'max' => 225],
[['cheque_number'], 'string', 'max' => 100],
[['bill_number'], 'unique']
];
}
}
It's going in to the validator function but not add the error like i wanted
$this->addError($attribute, 'Credit amount should less than Bill amount');
anyone can help me with this?
If the validation is not adding any error, it's most likely being skipped. The issue is most likely becasue of default rules behaviour whereby it skips empty or already error given values as per here: https://www.yiiframework.com/doc/guide/2.0/en/input-validation#inline-validators
Specifically:
By default, inline validators will not be applied if their associated attributes receive empty inputs or if they have already failed some validation rules. If you want to make sure a rule is always applied, you may configure the skipOnEmpty and/or skipOnError properties to be false in the rule declarations.
So you would need to set up the skipOnEmpty or skipOnError values depending on what works for you:
[
['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
]
Try this:
public function actionOpanningBalance(){
$model = new Bill();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->created_at = \Yii::$app->user->identity->id;
$model->save();
}else{
return $this->render('OpanningBalance', [
'model' => $model,
]);
}
}
For Validation
You can use anonymous function :
['credit_amount',function ($attribute, $params) {
if ($this->$attribute > $this->bill_amount)) {
$this->addError($attribute, 'Credit amount should less than Bill amount.');
return false;
}
}],
you can use like this below answer is also write
public function rules(){
return [
['credit_amount','custom_function_validation', 'on' =>'scenario'];
}
public function custom_function_validation($attribute){
// add custom validation
if ($this->$attribute < $this->cash_amount)
$this->addError($attribute,'Credit amount should less than Bill amount.');
}
I've made custom_function_validation working using 3rd params like this:
public function is18yo($attribute, $params, $validator)
{
$dobDate = new DateTime($this->$attribute);
$now = new DateTime();
if ($now->diff($dobDate)->y < 18) {
$validator->addError($this, $attribute, 'At least 18 years old');
return false;
}
}
This is a back end validation and it will trigger on submit only. So you can try something like this inside your validation function.
if (!$this->hasErrors()) {
// Your validation code goes here.
}
If you check the basic Yii2 app generated you can see that example in file models/LoginForm.php, there is a function named validatePassword.
Validation will trigger only after submitting the form.

Resources