Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Required rule flawed #321

Open
plasid opened this issue Sep 16, 2020 · 4 comments
Open

Required rule flawed #321

plasid opened this issue Sep 16, 2020 · 4 comments

Comments

@plasid
Copy link

plasid commented Sep 16, 2020

Field country_province_id should only be required when field country_id is present in the input data and country_id value is 23.
Custom rule "requiredIfOther" does not work because you will have to make country_province_id required for the custom rule to run, else it will never run.
Rule optional also does not work because then country_province_id is not enforced.
Rule requiredWith also does not help because you cannot specify the value (23) of the "with" field.

So it looks like it boils down to Valitron not processing custom rules when the field is not set to required.

What am I missing, or is this a shortcoming of the Valitron package?

@willemwollebrants
Copy link
Collaborator

Can you provide a short code sample please?

@plasid
Copy link
Author

plasid commented Sep 16, 2020

`Valitron\Validator::addRule('requiredIfOther', function($field, $value, array $params, array $fields) {
//Do some checks here to see of country_id is in $fields and its value is 23
//and if $value is set
//return true|false
}, 'field is required');

$rules = [
'country_province_id' => ['requiredIfOther', 'integer'],
'country_id' => ['required', 'integer']
];

$v = new Valitron\Validator(['country_id' => 23, 'country_province_id' => '']);
$v->mapFieldsRules($rules);
//requiredIfOther will never be called because country_province_id does not have a rule 'required'
$v->validate();`

@golee
Copy link

golee commented Oct 22, 2020

It's similar to what I've been through.

I just inherited Validator class and wrote my own class.

public function validate()
{
//...
    if (($this->hasRule('optional', $field) && isset($values))
        || ($this->hasRule('requiredWith', $field) || $this->hasRule('requiredWithout', $field)
        || $this->hasRule('requiredIf', $field))   /// ADD THIS LINE
    ) {
       //Continue with execution below if statement
    } 
//...
}

@pdscopes
Copy link

pdscopes commented Mar 3, 2021

One really simple solution to this would be to, now that validationMustBeExcecuted exists in v1.4.x would be to make it a protected function rather than private so we could extend it to add our own logic.

A more complex solution would be to add a new function to either update Validator::addRule to have a new boolean parameter called $mustBeExecuted which defaults to false. Then we could:

// ...

    /**
     * Always execute requiredWith(out) rules
     *
     * @var array
     */
    protected $_mustBeExecuted = array('requiredWith', 'requiredWithout');

// ...

    /**
     * Register new validation rule callback
     *
     * @param string $name
     * @param callable $callback
     * @param string $message
     * @param boolean $mustBeExecuted
     * @throws \InvalidArgumentException
     */
    public static function addRule($name, $callback, $message = null, $mustBeExecuted = false)
    {
        if ($message === null) {
            $message = static::ERROR_DEFAULT;
        }

        static::assertRuleCallback($callback);

        static::$_rules[$name] = $callback;
        static::$_ruleMessages[$name] = $message;

        if ($mustBeExecuted) {
            static::$_mustBeExecuted[] = $name;
        }
    }

// ...

    private function validationMustBeExcecuted($validation, $field, $values, $multiple){
        //always excecute must be executed rules
        if (in_array($validation['rule'], static::$_mustBeExecuted)){
            return true;
        }

        //do not execute if the field is optional and not set
        if($this->hasRule('optional', $field) && ! isset($values)){
            return false;
        }

        //ignore empty input, except for required and accepted rule
        if (! $this->hasRule('required', $field) && ! in_array($validation['rule'], array('required', 'accepted'))){
            if($multiple){
                return count($values) != 0;
            }
            return (isset($values) && $values !== '');
        }

        return true;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants