Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Expression Language package: doesn't handle the absence of the property and an error displays #45411

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

Closed
abeer93 opened this issue Feb 13, 2022 · 2 comments · Fixed by #45795 or #46142
Closed

Comments

@abeer93
Copy link

abeer93 commented Feb 13, 2022

Symfony version(s) affected

^6.0

Description

I'm using Expression Language Package with Laravel Framework
and I'm sending the rules object and data object to the package as mentioned in the documentation.

The issue is if the rules object checks property which does not exist in the data object the package displays an error.
"message": "Undefined property: App\\RulesEngine\\Conditions\\DataConditions::$scores", "exception": "ErrorException",
The idea is that I'm receiving the data object from an API and the object has different properties which not of it is required but I need to evaluate the properties in case of its existence.

I checked the package's code and I found that the code is calling the property directly without checking the existence of the property.

As example,
Rules object =>
data.scores = 20 || data.name = "abeer"
data object
data['name'] = "abeer";
and error will appear " Undefined property data.scores"

How to reproduce

My rules engine class
`

    class RulesEngine implements RulesEngineInterface
    {
        /** @var array<string> */
        private array $rules = [];

        public function __construct(public ExpressionLanguage $expressionLanguage)
        {
        }

        /**
        * @inheritdoc
        */
        public function addRules(array $expressions, bool $reset = false): void
        {
            $this->rules = $reset ?  [...$expressions] : [...$this->rules, ...$expressions];
        }

        /**
        * @inheritdoc
        */
        public function validateData(array $data): mixed
        {
            foreach ($this->rules as $rule) {
                $evaluated = $this->expressionLanguage->evaluate($rule, $data);
                if (! $evaluated) {
                    return false;
                }
            }

            return true;
        }
    }

`
Calling the class to handle rules evaluation

`

    public function evaluateRules(RulesEngineInterface $rulesEngine, Game $game, array $data): bool
    {
        $rulesEngine->addRules([$game->conditions], true);

        return $rulesEngine->validateData($data);
    }

`

Possible Solution

instead of return direct access to the property in the object return line in Evaluate function in call GetAttrNode
check the existence of the property object_get($obj, $property) !== null and return false to drop only one rules without stoping the code and keep evaluating the rest of the rules.

Additional Context

No response

@nicolas-grekas
Copy link
Member

I think we should keep the generated code as simple as possible. Adding the check you suggest here would make the generated code really clumsy.

Instead, what about adding support for the nullsafe operator and the null coalescing one?
If that makes sense to you, would you like working on a PR?

@nicolas-grekas
Copy link
Member

Actually, I just found #21691 which is describing the same issue.
Closing as duplicate. My previous comment still holds appropriate :)

nicolas-grekas added a commit that referenced this issue Apr 4, 2022
…r (mytuny)

This PR was merged into the 6.1 branch.

Discussion
----------

[ExpressionLanguage] Add support for null-safe operator

| Q             | A
| ------------- | ---
| Branch?       | 6.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #45411, #21691
| License       | MIT
| Doc PR        | symfony/symfony-docs#16630

This is a long-time-lasting feature for the `ExpressionLanguage` component. I've been waiting for the support of `Nullsafe operator` in expressions dealing with mutable objects, until I finally decided to work on it once for all 👍

The lack of [nullsafety feature](https://wiki.php.net/rfc/nullsafe_operator) has been repeatedly reported as a BUG several time  (e.g [#45411](#45411) & [#21691](#21691)) when it is actually a missing feature.

Currently, expressions like `foo.bar` assumes that the property `bar` "always" exists on the object `foo` and if doesn't the parser throws a `RuntimeException`. Although, sometimes, that's exactly the behavior we need, some other times we may work with mutable objects with uncontrolled structure, thus, such assumption is error-prone and will force adding extra checks making the expression uglier and less readable.

The proposed work, introduces the support for the `?.` syntax alongside with the usual `.` syntax to help working with objects with dynamic structure. The two notations works identically in all normal cases. The difference occurs when trying to access non-existant properties and/or methods where the `.` notation will throw a `RuntimeException` as usual and the `?.` notation will return `null` instead and no errors nor exceptions will be thrown. Hence the name "Null-Safe".

PS: This work account ONLY for accessing **object's** properties and methods. It does not account for non-existant **array** items which is a seperate problem that can be addressed by introducing the [null coalescing](https://wiki.php.net/rfc/isset_ternary) operator. Another feature that I'm currently working on as well 💯

Commits
-------

946c59f [ExpressionLanguage] Add support for null-safe operator
fabpot added a commit that referenced this issue Jul 25, 2022
…yntax (mytuny)

This PR was merged into the 6.2 branch.

Discussion
----------

[ExpressionLanguage] Add support for null coalescing syntax

| Q             | A
| ------------- | ---
| Branch?       | 6.1
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #45411, #21691
| License       | MIT
| Doc PR        | symfony/symfony-docs#16743

This is another waited feature for the syntax of the expression-language component. The [null-coalescing](https://wiki.php.net/rfc/isset_ternary) operator ``??`` becomes a need for variant programming needs these days.

Following my previous PR introducing the null-safe operator (#45795). I'm hereby introducing yet another essential operator to make the syntax even more complete.

The null-coalescing operator is a syntactic sugar for a common use of ternary in conjunction with ``isset()`` (in PHP) or equivalent in other languages. This is such a common use-case to the point that almost all majors programming syntax nowadays support a sort of a short-hand for that operation namely coalescing operator. Now it's time for the syntax of Expression-Language to do so!

Expressions like:

* ``foo.bar ?? 'default'``
* ``foo[3] ?? 'default'``
* ``foo.bar ?? foo['bar'] ?? 'default'``

will default to the expression in the right-hand-side of the ``??`` operator whenever the expression in the left-hand-side of it does not exist or it's ``null``. Note that this coalescing behavior can be chained and the validation logic takes decreasing priority from left to right.

Commits
-------

8e3c505 [ExpressionLanguage] Add support for null coalescing syntax
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants