Laravel form validation: same as field a or b - php

I have 3 fields: player1, player2 and winner. I want to validate that winner is equal to either player1 or player 2.
I tried looking for a way to add an 'or' clause to the validation but couldn't find anything, only workarounds for different problems.

You can use a custom validation rule to do this. There's nothing built in that allows comparison to one of many other fields. The closest is the same check, but it only checks against one other field.
(I've added dd() to dump data, you can remove them)
The $values will be what comes from your input.
The $validationRules can be adjusted for your needs.
Validator::extend('equals_one_of', function($attribute, $value, $parameters, \Illuminate\Validation\Validator $validator) {
$fields = $validator->getData(); // all posted values
foreach($parameters as $param) { // this is each of the comma separated fields in the validationRules array
if ($value == $fields[$param]) {
dd("matched");
return true;
}
}
dd("no match");
return false;
});
$values = [
'player1' => 'test1',
'player2' => 'test2',
'winner' => 'test1'
];
$validationRules = [
'player1' => 'required',
'player2' => 'required',
'winner' => 'required|equals_one_of:player1,player2'
];
$validate = Validator::make($values, $validationRules);
// use your validator as normal.
dd($validate->validate());

Actually this rule should be registered with extendDependent to correctly resolve parameter names when used with arrays.
Final code:
class OneOfRule
{
public function validate($attribute, $value, $parameters, $validator) {
if(is_null($value)) return true;
foreach($parameters as $param) {
$other = Arr::get($validator->getData(), $param);
if ($value === $other) {
return true;
}
}
return false;
}
}
public function boot()
{
Validator::extendDependent('one_of', 'App\Http\Validation\Rules\OneOfRule#validate');
}

Related

improve Laravel array validation rule

I am searching for a improvement to this Laravel FormRequest rule set:
protected $stopOnFirstFailure = true;
public function rules()
{
return [
'reasons' => ['required', 'array'],
'reasons.*.id' => ['exists:reject_reasons,id'],
'reasons.*.text' => Rule::forEach(function ($value, $attribute, $data) {
// get the key from the array attribute
list(, $key) = explode('.', $attribute);
$reason = RejectReason::find($this->reasons[$key]['id']);
return [
Rule::requiredIf(optional($reason)->with_additional_entry),
'max:255'
];
}),
];
}
The .text element should only be required and checked if the id element exists in the database and the attribute with_additional_entry is true.
Things that could be improved:
If the id is not in the database the validator does not stop after the reasons.*.id rule, so I have to check for the $reason Object -> optional()
Get the key of the form array list(, $key) = explode('.', $attribute);
Does anyone have a better solution to this?

How to deal with conditioned based validation in laravel?

I have a situation and unfortunately not sure how to sort it out in proper way. I have below script
$validator = Validator::make(
$request->all(),
[
'game_id' => 'required|integer'
],
$messages
);
if ($validator->fails()) {
$response = $validator->messages();
}else{
$response = $gameService->setStatus($request);
}
Now each game has different type, I wanted to add validation on behalf of type. For example if a game is Task Based then I would add validation for time which would be mandatory only for Task based game otherwise it would be an optional for other types.
I have three types of games
1 - level_based
2 - task_based
3 - time_based
In the type table, each game has type.
So is there any way to add validation? I want to do it, inside validation function.
Thank you so much.
You can write your conditions before the validation.
$data = $request->all();
if ($data['game_id'] == 1) {
$rules = [
// level_based validation
];
} else if($data['game_id'] == 2) {
$rules = [
// task_based validation
];
} else {
$rules = [
// time_based validation
];
}
$validator = Validator::make($data, $rules);
Hope it helps. Cheers.
I would go with the required_if validation rule.
So in your case, will send two fields, the type can be a hidden field for example, then on the game_id you will add
'game_id' => 'required_if:type,1'
and so on.. And of course you can customize the error messages.
Try this code snippet
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class CreateGameRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
try {
$request = $this->request->all();
$rule_array = collect();
$rule1 = [
'game_id' => 'required|integer'
]
$rule_array = $rule_array->merge($rule1);
if(isset($request->task_id))
{
$rule2 = [
'task_id' => 'required|integer'
]
}
$rule_array = $rule_array->merge($rule2);
return $rule_array->all();
} catch (Exception $e) {
return $e;
}
}
public function messages(){
return [
'game_id' => 'Please select valid game',
'task_id' => 'Please select valid task'
];
}
}
then invoke this request class in controller function as
use App\Http\Requests\CreateGameRequest;
public function game(CreateGameRequest $request)
{
}

Validate Arabic Numbers in Laravel 5

I have a form that contains a field for user to enter amount value of certain payment. This field is input of type number.
The validation rule in Laravel for this input is:
'amount' => 'required|numeric'
When I enter the amount in English as: 1500 => The validation passes and everything is OK.
But when I enter the amount in Arabic as: ١٥٠٠ => The validation fails with the following error message:
"validation.numeric"
Should I validate this field manually or is there another solution to this problem?
Maybe you can create your own validation type.
You can add something like this to your boot method in app/Providers/AppServiceProvider.php.
Validator::extend('arabic_numbers', function ($attributes, $value, $parameters, $validation) {
$arabic_numbers = [
'٥',
'١',
// add more
];
$input = $value;
if (!$input) {
return false;
}
$chars = preg_split('//u', $input, -1, PREG_SPLIT_NO_EMPTY);
foreach ($chars as $char) {
if (!in_array($char, $arabic_numbers)) {
return false;
}
}
return true;
});
You can add to your existing rule, e.g. required|arabic_numbers.
Or use something like this:
$input = '١';
$validator = Validator::make([
'user_input' => $input,
], [
'user_input' => 'required|arabic_numbers'
];
if ($validator->fails()) {
//
}
Also you can use in many other ways for example in a custom request:
public function rules()
{
return [
'something' => 'required|arabic_numbers',
];
}
Hope this helps.

Laravel Validation between not converting comma separated string to array?

Just trying to do some tags validation. First checking for number of tags (as comma separated list of id's).
class SomePostRequest extends Request
{
public function rules()
{
return [
'tags' => 'between:2,5'
];
}
public function all()
{
$input = parent::all();
$input['tags'] = explode(',', #$input['tags']);
return $input;
}
}
It keeps spititing out the message as
The tags must be between 2 and 5 characters.
Instead of the proper array message:
The :attribute must have between :min and :max items.
Try to use custom validation rule for you requirement:
$this->app['validator']->extend('tag', function ($attribute, $value, $parameters)
{
$tags = explode(',', $value);
if(count($tags) >= 2 || count($tags) <= 5)){
return false;
}
});
and then rules would be
public function rules(){
return [
'tags' => ['tag']
];
}
and message can update by
public function messages() {
return [
'tags.tag' => 'The :attribute must have between :min and :max items.'];
}
I hope, you get basic idea to achieve this requirement, let me know if its helps.

Laravel 4 Validation

I use the following rules for validation on creating a new user:
protected $rules= [
'name' => 'required',
'email' => [
'required',
'unique:user',
'email'
]
];
When updating an existing user I use the same ruleset as shown above
but don't want a validation error if the user didn't change his email at all.
I currently resolve this by using the following:
if (!User::changed('email')) {
unset($user->email);
}
It feels like a dirty workaround to me so I was wondering if there are better alternatives.
Also note that the changed method is something I wrote myself. Does anyone know if there
is a native Laravel 4 method for checking whether a model property has changed?
Thanks!
The unique validation rule allows to ignore a given ID, which in your case is the ID of the data set you are updating.
'email' => 'unique:users,email_address,10'
http://four.laravel.com/docs/validation#rule-unique
One approach is to create a validation function in the model and call it with the controller passing in the input, scenario and id (to ignore).
public function validate($input, $scenario, $id = null)
{
$rules = [];
switch($scenario)
{
case 'store':
$rules = [
'name' => 'required|min:5|unique:users',
'email' => 'required|email|unique:users',
'password' => 'required|min:4|confirmed'
];
break;
case 'update';
$rules = [
'name' => 'required|min:5|unique:users' .',name,' . $id,
'email' => 'required|email|unique:users' .',email,' . $id,
'password' => 'min:4|confirmed'
];
break;
}
return Validator::make($input, $rules);
}
Then in the controller:
$input = Input::all();
$validation = $user->validate($input, 'update', $user->id);
if ($validation->fails())
{
// Do stuff
}
else
{
// Validation passes
// Do other stuff
}
As others mentioned, the 3rd parameter of the unique rule specifies an id to ignore. You can add other cases, such as 'login' to reuse the validation function.
Alternatively, Jeffrey Way at Tuts Premium has a great series of lessons in "What's New In Laravel 4" which includes a couple of other approaches to handling validation using services and listeners.
See the documentation on http://four.laravel.com/docs/validation#rule-unique
You can exclude the users own id
protected $rules= [
'name' => 'required',
'email' => [
'required',
'unique:user,email,THE_USERS_USER_ID',
'email'
]
];
As of 2014-01-14, you can use sometimes attribute, I believe Taylor added them 2 days ago to Laravel 4.1
$v = Validator::make($data, array(
'email' => 'sometimes|required|email',
));
sometimes only validate input if it exists. this may or may not suit your exact scenario, if you don't have a default value for insert.
http://laravel.com/docs/validation#conditionally-adding-rules
I handle this sort of thing in my validator function. My validators array is setup as a class variable. I then do something like this:
public function validate()
{
//exclude the current user id from 'unqiue' validators
if( $this->id > 0 )
{
$usernameUnique = 'unique:users,username,'.$this->id;
$emailUnique = 'unique:users,email,'.$this->id;
$apiUnique = 'unique:users,api_key,'.$this->id;
}
else
{
$usernameUnique = 'unique:users,username';
$emailUnique = 'unique:users,email';
$apiUnique = 'unique:users,api_key';
}
$this->validators['username'] = array('required', 'max:32', $usernameUnique);
$this->validators['email'] = array('required', 'max:32', $emailUnique);
$this->validators['api_key'] = array('required', 'max:32', $apiUnique);
$val = Validator::make($this->attributes, $this->validators);
if ($val->fails())
{
throw new ValidationException($val);
}
}
I have solved this by having different rules for update and create on models that need to do so, like Users.
I have a Model class that extends Eloquent, where I define the validation, and then all child models that extend the Model can have have both the $rules and $update_rules defined. If you define only $rules, it will be used both for create and update.
class Model extends Eloquent {
protected $errors;
protected static $rules = array();
protected $validator;
public function __construct(array $attributes = array(), Validator $validator = null) {
parent::__construct($attributes);
$this->validator = $validator ?: \App::make('validator');
}
protected static function boot() {
parent::boot();
# call validatie when createing
static::creating(function($model) {
return $model->validate();
});
# call validatie when updating with $is_update = true param
static::updating(function($model) {
return $model->validate(true);
});
}
public function validate($is_update = false) {
# if we have $update_rules defined in the child model, and save is an update
if ($is_update and isset(static::$update_rules)) {
$v = $this->validator->make($this->attributes, static::$update_rules);
}
else {
$v = $this->validator->make($this->attributes, static::$rules);
}
if ($v->passes()) {
return true;
}
$this->setErrors($v->messages());
return false;
}
protected function setErrors($errors) {
$this->errors = $errors;
}
public function getErrors() {
return $this->errors;
}
public function hasErrors() {
return ! empty($this->errors);
}
}

Categories