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

Skip to content

[Expression language]Trying to evaluate expression with a not existing variable in the array #21691

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
hab92 opened this issue Feb 20, 2017 · 14 comments
Labels
ExpressionLanguage Help wanted Issues and PRs which are looking for volunteers to complete them.

Comments

@hab92
Copy link

hab92 commented Feb 20, 2017

Q A
Bug report? no
Feature request? yes
BC Break report? no
RFC? no
Symfony version 2.8

I'm trying to evaluate an expression with an array not containing all variables of the expression.

When i evaluate the expression with my array, the evaluation return a exception :

Variable XXXX is not valid around position 1.

My problem is when i have a expression like

( ( var1 != 2 ) or ( var2 != 2 ) ),

and an array

array(
        'var1' => 3,
) 

this evaluation throw an exception. Should we not return a boolean instead of an exception ?

For exemple if we have the expression :

(a and b and c) or (d and e and f)

and e does not exist in the array, the expression (d and e and f) return false and not an exception.

@steve-todorov
Copy link

I'm hitting this issue as well but from another angle with upgrading an old Symfony 3.4 to 4.3. There is a deprecation notice regarding @ParamConverter which suggests this:

@Route(methods={"GET", "POST"}, path="/create", name="_create")
@Route(methods={"GET", "POST"}, path="/update/{activity}", name="_update", requirements={"activity": "\d+"})
@ParamConverter("activity", class="App\Entity\Activity", options={"repository_method": "findActivityWithJoins"})

should be converted into this:

@Route(methods={"GET", "POST"}, path="/create", name="_create")
@Route(methods={"GET", "POST"}, path="/update/{activity}", name="_update", requirements={"activity": "\d+"})
@Entity("activity", class="App\Entity\Activity", expr="repository.findActivityWithJoins(activity)")

However this won't work, because the activity variable is not available when you enter the controller method from the _create route. I can't use expr="activity ? repository.findActivity(activity)" and it's also not possible to use expr="_route_params in ['activity'] ? repository.findActivityWithJoins(activity)") so there is no workaround so far that I've found to work.

Is there any progress on this issue or maybe a workaround that I am missing somehow?

//cc @nicolas-grekas

@WubbleWobble
Copy link

@steve-todorov Coincidentally - I've just encountered this same problem whilst trying to resolve deprecations. I think I might have figured a workaround tho' :)

Old:

     * @Route("/add")
     * @Route("/edit/{id}")
     * @ParamConverter("client", options={"repository_method"="findApproved"})

New:

     * @Route("/add", defaults={"id"=null})
     * @Route("/edit/{id}")
     * @Entity("client", expr="repository.findApproved(id)")

The defaults option means that there is an "id" declared even on the /add route, avoiding the explosion.

This does mean that the repository method is getting passed a null, and needs to be able to handle that, but it seemed to already handle that in my case.

@steve-todorov
Copy link

Ha! I haven't thought of that! Thanks for sharing this workaround - works just fine! :)

@tolecar
Copy link

tolecar commented Apr 27, 2020

We encountered the same issue when trying to use ExpressionLanguage in our project.

I would just like to point out few things/ideas

  • parser should only parse exprerssion (as it name is suggesting) and not checkng for it's existance/value
  • when encountering the non existing value, it should evaluate to null (as in Javas's EL/JUEL which has much in common with Symfony's EL)
  • it would be the best to have optional parameter in ExpressionLanguage (e.g. strictMode=true) to preserve backcompatibility

@SimonSpi
Copy link

SimonSpi commented Sep 17, 2020

In Contao CMS Version 4.10 ExpressionLanguage is now used also for evaluating some input fields. Here one will have the same issue as described by tolecar:

We encountered the same issue when trying to use ExpressionLanguage in our project.

I would just like to point out few things/ideas

  • parser should only parse exprerssion (as it name is suggesting) and not checkng for it's existance/value
  • when encountering the non existing value, it should evaluate to null (as in Javas's EL/JUEL which has much in common with Symfony's EL)
  • it would be the best to have optional parameter in ExpressionLanguage (e.g. strictMode=true) to preserve backcompatibility

I thus support the opinion that a non existing value should evaluate to null instead of throwing an exception.

@tolecar
Copy link

tolecar commented Sep 21, 2020

We solved the issue by extending ExpressionLanguage class and a few more. It is not a beauty, but the classes are written in such a way that we didn't have much options.

Few days ago I published it on the github & packagist as separate library so you can try to use it.
So far seems that we haven't lost any of original Symfony EL features.

You can check it up on https://github.com/zef-dev/zef-expression-language and https://packagist.org/packages/zef-dev/zef-expression-language

@stof
Copy link
Member

stof commented Sep 21, 2020

it's also not possible to use expr="_route_params in ['activity'] ? repository.findActivityWithJoins(activity)") so there is no workaround so far that I've found to work.

what you want is actually checking that 'activity' is in the route params keys, not that the array of route params is the string activity.

what you could do is add a default of null for activity in the first route.

@carsonbot
Copy link

Thank you for this issue.
There has not been a lot of activity here for a while. Has this been resolved?

@broberts-dev
Copy link

broberts-dev commented Mar 26, 2021 via email

@carsonbot carsonbot removed the Stalled label Mar 26, 2021
@fsuter
Copy link

fsuter commented Aug 14, 2021

It's definitely not resolved, I just stumbled on it too while using the Expression Language in a custom project.

@broberts-dev
Copy link

Yes, our workaround has been to completely side step use of Expression Language if/when a given key in the expression isn't "guaranteed" in the data available/provided for evaluation. From the consumer-side of this package, I do think evaluating non-existent identifiers to NULL might be a better design choice than throwing an exception or, at least, better as EL behavior controlled through a configurable option.

@prof83
Copy link

prof83 commented Aug 30, 2021

My only workaround to this issue is to specifically catch the exception message and try again, which is really dirty code but at least allows you to use the expression language on arrays that may have missing keys. I hope this helps someone:

tryagain:

try {

    if ($expressionLanguage->evaluate($expression, $data)) {
        // Success
    }

}

catch (\Symfony\Component\ExpressionLanguage\SyntaxError $e) {

    // Match the error message and variable name
    if (preg_match('/^Variable "(?<var>[^"]+)" is not valid around position [0-9]+ for expression/', $e->getMessage(), $matched)) {

        // Check that it is not in the data array (likely the cause)
        if (!array_key_exists($matched['var'], $data)) {
            $data[$matched['var']] = null;
            goto tryagain;
        } else {
            throw $e;
        }
    } else {
        throw $e;
    }

}

@broberts-dev
Copy link

broberts-dev commented Aug 30, 2021

@prof83 That your workaround is coded using GOTO (lots of passion around this one on both sides) and regular expression pattern matching on the exception message itself just makes this all the more interesting, I think. It could probably be refactored as a DO-WHILE as a peace offering.

I think this Symfony Expression Language behavior is the subject other other issues that have been opened (e.g. #41306), although referencing different Symfony versions (2.8 versus 5.2.7).

@nicolas-grekas
Copy link
Member

I think we should keep the generated code as simple as possible. Thus not do anything to prevent the notice in the generated code.

BUT I would suggest adding support for the nullsafe operator and the null coalescing!

Anyone up for giving it a try?

@nicolas-grekas nicolas-grekas added the Help wanted Issues and PRs which are looking for volunteers to complete them. label Feb 23, 2022
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 fabpot closed this as completed Jul 20, 2022
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
Labels
ExpressionLanguage Help wanted Issues and PRs which are looking for volunteers to complete them.
Projects
None yet
Development

No branches or pull requests