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

fix: required_without rule logic in Validation class. #6589

Merged

Conversation

ping-yee
Copy link
Contributor

@ping-yee ping-yee commented Sep 26, 2022

Description
Fixed the logic to support #5922 and #5942.

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@ping-yee ping-yee changed the title Modify required_without Rule logic in Validation class. Modify required_without rule logic in Validation class. Sep 26, 2022
@ping-yee
Copy link
Contributor Author

I have been implement the logic to support the #5922 case logic but I forget to change the PC to commit with GPG sign.
I will fix these commit that without GPG sign.

@kenjis kenjis added the bug Verified issues on the current code behavior or pull requests that will fix them label Sep 26, 2022
@kenjis kenjis changed the title Modify required_without rule logic in Validation class. fix: required_without rule logic in Validation class. Sep 26, 2022
@kenjis
Copy link
Member

kenjis commented Sep 26, 2022

Thank you!
See https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/workflow.md#gpg-signing-old-commits

@ping-yee ping-yee force-pushed the modify-validation-required_without branch from 3e7a9bd to 5cb0c8d Compare September 26, 2022 10:05
Copy link
Member

@MGatner MGatner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much easier to comprehend! Thank you. Awaiting GPG

Comment on lines 285 to 286
if ($fields === null || empty($data) || $keyField === null) {
throw new InvalidArgumentException('You must supply the parameters: fields, data, keyField.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this a breaking change? If I am using the rules programmatically, like (new Rules())->required_without(/* .. */), then the addition of an optional parameter that is required inside the body will break my app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it seems a breaking change.

 $this->validation->setRules([
    'a.*.c' => 'required_without[a.*.b]',
])->run($data);

But I think this param is needed because this rule need to know what the key field is being passed in now (like: a.0.c, a.1.c...etc), otherwise it will only be passed the asterisk field (like: a.*.c).

@@ -296,11 +296,28 @@ public function required_without($str = null, ?string $fields = null, array $dat
return true;
}

$nowKeyField = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the implication of the $now? We have a $keyField then $nowKeyField. Then we have a $nowField and $nowFieldValue

Copy link
Contributor Author

@ping-yee ping-yee Sep 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 $this->validation->setRules([
    'a.*.c' => 'required_without[a.*.b]',
])->run($data);

Like this scenario, the implication of these name I set show as below .

a.*.c => key

$keyField => the key field is being passed in now (like: a.0.c, a.1.c).
$nowKeyField => the index of key field is being passed in now (like: 1 of a.1.c, 2 of a.2.c).

required_without[a.*.b] => the param field of required_without[]

$nowField => the field of required_without is changed from asterisk field to current field (like: a.*.b => a.0.b, a.1.b...etc).
$nowFieldValue => the value of current field in data set.

I think the name of these variables aren't the best, or are there more suitable names?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly don't understand what the variable names mean. Variable names need to be changed.

Copy link
Contributor Author

@ping-yee ping-yee Sep 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable names need to be changed.

I agree with you, do you guys have any suggestion for these variable names?

Copy link
Member

@kenjis kenjis Sep 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this?

    /**
     * The field is required when any of other fields do not pass `required` checks.
     *
     * Example (field is required when the id or email field is missing):
     *     required_without[id,email]
     *
     * @param string|null $value       The value to check
     * @param string|null $otherFields The rule parameter fields. List of other fields to check if present
     * @param array       $data        All data to validate
     * @param string|null $field       The field name to check. If the rule parameter fields aren't present, this field is required.
     */
    public function required_without(
        $value = null,
        ?string $otherFields = null,
        array $data = [],
        ?string $error = null,
        ?string $field = null
    ): bool {
        if ($otherFields === null || empty($data)) {
            throw new InvalidArgumentException('You must supply the parameters: otherFields, data.');
        }

        // If the field is present we can safely assume that
        // the field is here, no matter whether the corresponding
        // search field is present or not.
        $otherFields = explode(',', $otherFields);
        $present     = $this->required($value ?? '');

        if ($present) {
            return true;
        }

        $otherFieldKey = 0;

        // Still here? Then we fail this test if
        // any of the fields are not present in $data
        foreach ($otherFields as $otherField) {
            if ((strpos($otherField, '.') === false) && (! array_key_exists($otherField, $data) || empty($data[$otherField]))) {
                return false;
            }
            if (strpos($otherField, '.') !== false) {
                if ($field === null) {
                    throw new InvalidArgumentException('You must supply the parameters: field.');
                }

                $otherFieldValue = dot_array_search($otherField, $data);
                $fieldArray      = explode('.', $field);
                $otherFieldKey   = $fieldArray[1];

                if (is_array($otherFieldValue)) {
                    return ! empty(dot_array_search($otherField, $data)[$otherFieldKey]);
                }

                $currentField      = str_replace('*', $otherFieldKey, $otherField);
                $currentFieldValue = dot_array_search($currentField, $data);

                return null !== $currentFieldValue;
            }
        }

        return true;
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this naming is ok, more readability.
I change it immediately.

Copy link
Contributor Author

@ping-yee ping-yee Sep 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name of $fieldIndex is more appropriate to show the index of the field.
More readability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been modified, review please.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

index implies 0, 1, 2, ...
But it is an array key and is a string.
$fieldKey is better?

Copy link
Contributor Author

@ping-yee ping-yee Sep 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$fieldKey is better?

I agree with you.
I will change that.

@kenjis kenjis added the breaking change Pull requests that may break existing functionalities label Sep 26, 2022
@kenjis
Copy link
Member

kenjis commented Sep 27, 2022

Please fix errors and failures in PHPUnit testing.

ERRORS!
Tests: 5329, Assertions: 8867, Errors: 25, Failures: 3, Skipped: 14.
https://github.com/codeigniter4/CodeIgniter4/actions/runs/3126902870/jobs/5072927529

@ping-yee ping-yee force-pushed the modify-validation-required_without branch from d4b2a33 to 0277595 Compare September 27, 2022 17:51
Copy link
Member

@kenjis kenjis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests: 5329, Assertions: 8869, Errors: 3, Skipped: 15.

@ping-yee
Copy link
Contributor Author

All of Errors are fixed!

system/Validation/Rules.php Outdated Show resolved Hide resolved
system/Validation/Rules.php Outdated Show resolved Hide resolved
@kenjis
Copy link
Member

kenjis commented Sep 28, 2022

Please add the test case:

    public function testRequireWithoutWithWildCard()
    {
        $data = [
            'a' => [
                ['b' => 1, 'c' => 2],
                ['c' => ''],
            ],
        ];

        $this->validation->setRules([
            'a.*.c' => 'required_without[a.*.b]',
        ])->run($data);

        $this->assertSame(
            'The a.*.c field is required when a.*.b is not present.',
            $this->validation->getError('a.1.c')
        );
    }

@ping-yee
Copy link
Contributor Author

Already made up the comment out, the dot of throw and test case!
Appreciated that! @kenjis

system/Validation/Rules.php Outdated Show resolved Hide resolved
@kenjis kenjis added the docs needed Pull requests needing documentation write-ups and/or revisions. label Sep 29, 2022
system/Validation/Rules.php Outdated Show resolved Hide resolved
system/Validation/Rules.php Outdated Show resolved Hide resolved
system/Validation/Rules.php Outdated Show resolved Hide resolved
@ping-yee ping-yee force-pushed the modify-validation-required_without branch from c1faf88 to cb5d045 Compare September 29, 2022 03:20
@ping-yee
Copy link
Contributor Author

@kenjis All required changes have been corrected.
The changelog and upgrade-guide are also added.

@kenjis
Copy link
Member

kenjis commented Sep 30, 2022

@ping-yee Thank you for updating!
I added suggestions for the docs.
Other things seem to be good.

@kenjis kenjis removed the docs needed Pull requests needing documentation write-ups and/or revisions. label Sep 30, 2022
@ping-yee
Copy link
Contributor Author

I have been modified the docs.
I really appreciate your help and support during these days!

Copy link
Member

@kenjis kenjis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@kenjis kenjis merged commit ed0cdd0 into codeigniter4:develop Sep 30, 2022
@MGatner
Copy link
Member

MGatner commented Oct 1, 2022

Thank you both! This one ended up being a lot of work, with many improvements along the way. Happy to see it closed up! 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change Pull requests that may break existing functionalities bug Verified issues on the current code behavior or pull requests that will fix them
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants