-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[#3044] Furthering @WouterJ's work on the ExpressionLanguage component #3191
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,30 +10,57 @@ The ExpressionLanguage Component | |
(mostly, but not limited to, Booleans). | ||
|
||
.. versionadded:: 2.4 | ||
The ExpressionLanguage component was new in Symfony 2.4. | ||
The ExpressionLanguage component was introduced in Symfony 2.4. | ||
|
||
Installation | ||
------------ | ||
|
||
You can install the component in 2 different ways: | ||
|
||
* Use the official Git repository (https://github.com/symfony/expression-language); | ||
* :doc:`Install it via Composer </components/using_components>` (``symfony/expression-language`` on `Packagist`_). | ||
* :doc:`Install it via Composer </components/using_components>` (``symfony/expression-language`` on `Packagist`_); | ||
* Use the official Git repository (https://github.com/symfony/expression-language). | ||
|
||
How can the Expression Engine Help Me? | ||
-------------------------------------- | ||
|
||
The purpose of the component is to allow users to use expressions inside | ||
configuration for more complex logic. For some examples, the Symfony2 Framework | ||
uses expressions in security, for validation rules and in route matching. | ||
|
||
Besides using the component in the framework itself, the ExpressionLanguage | ||
component is a perfect candidate for the foundation of a *business rule engine*. | ||
The idea is to let the webmaster of a website configure things in a dynamic | ||
way without using PHP and without introducing security problems: | ||
|
||
.. code-block:: text | ||
|
||
# Get the special price if | ||
user.getGroup() in ['good_customers', 'collaborator'] | ||
|
||
# Promote article to the homepage when | ||
article.commentCount > 100 and article.category not in ["misc"] | ||
|
||
# Send an alert when | ||
product.stock < 15 | ||
|
||
Expressions can be seen as a very restricted PHP sandbox and are immune to | ||
external injections as you must explicitly declare which variables are available | ||
in an expression. | ||
|
||
Usage | ||
----- | ||
|
||
The ExpressionLanguage component can compile and evaluate expressions. | ||
Expressions are one-liners which most of the time return a boolean, you can | ||
compare them to the expression in an ``if`` statement. A simple example of an | ||
expression is ``1 + 2``. You can also use more complicated expressions, such | ||
as ``someArray[3].someMethod('bar')``. | ||
Expressions are one-liners that often return a Boolean, which can be used | ||
by the code executing the expression in an ``if`` statement. A simple example | ||
of an expression is ``1 + 2``. You can also use more complicated expressions, | ||
such as ``someArray[3].someMethod('bar')``. | ||
|
||
The component provides 2 ways to work with expressions: | ||
|
||
* **evaluation**: the expression is evaluated without being compiled to PHP; | ||
* **compile**: the expression is compiled to PHP, so it can be cached and | ||
evaluated; | ||
* **evaluation**: the expression is evaluated without being compiled to PHP. | ||
evaluated. | ||
|
||
The main class of the component is | ||
:class:`Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage`:: | ||
|
@@ -49,7 +76,35 @@ The main class of the component is | |
Expression Syntax | ||
----------------- | ||
|
||
See ":doc:`/components/expression_language/syntax`" to learn the syntax of the | ||
See :doc:`/components/expression_language/syntax` to learn the syntax of the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. -1 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the current form. I don't think that we need to highlight the section's name with quotes as this is already achieved by the link. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree - sometimes I add commas for more emphasis when something is hidden inside a paragraph. |
||
ExpressionLanguage component. | ||
|
||
Passing in Variables | ||
-------------------- | ||
|
||
You can also pass variables into the expression, which can be of any valid | ||
PHP type (including objects):: | ||
|
||
use Symfony\Component\ExpressionLanguage\ExpressionLanguage; | ||
|
||
$language = new ExpressionLanguage(); | ||
|
||
class Apple | ||
{ | ||
public $variety; | ||
} | ||
|
||
$apple = new Apple(); | ||
$apple->variety = 'Honeycrisp'; | ||
|
||
echo $language->evaluate( | ||
'fruit.variety', | ||
array( | ||
'fruit' => $apple, | ||
) | ||
); | ||
|
||
This will print "Honeycrisp". For more information, see the :doc:`/components/expression_language/syntax` | ||
entry, especially :ref:`component-expression-objects` and :ref:`component-expression-arrays`. | ||
|
||
.. _Packagist: https://packagist.org/packages/symfony/expression-language |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,24 +9,104 @@ expression syntax of Twig. In this document, you can find all supported | |
syntaxes. | ||
|
||
Supported Literals | ||
~~~~~~~~~~~~~~~~~~ | ||
------------------ | ||
|
||
The component supports: | ||
|
||
* **strings** - single and double quotes (e.g. ``'hello'``) | ||
* **numbers** - e.g. ``103`` | ||
* **arrays** - using twig notation (e.g. ``[1, 2]``) | ||
* **hashes** - using twig notation (e.g. ``{ foo: 'bar' }``) | ||
* **arrays** - using JSON-like notation (e.g. ``[1, 2]``) | ||
* **hashes** - using JSON-like notation (e.g. ``{ foo: 'bar' }``) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does key foo here require quotes (e.g. "foo") here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, not in the expression syntax. |
||
* **booleans** - ``true`` and ``false`` | ||
* **null** - ``null`` | ||
|
||
.. _component-expression-objects: | ||
|
||
Working with Objects | ||
-------------------- | ||
|
||
When passing objects into an expression, you can use different syntaxes to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. those into's should be changed to just to's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 for |
||
access properties and call methods on the object. | ||
|
||
Accessing Public Methods | ||
~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
Public properties on objects can be accessed by using the ``.`` syntax, similar | ||
to JavaScript:: | ||
|
||
class Apple | ||
{ | ||
public $variety; | ||
} | ||
|
||
$apple = new Apple(); | ||
$apple->variety = 'Honeycrisp'; | ||
|
||
echo $language->evaluate( | ||
'fruit.variety', | ||
array( | ||
'fruit' => $apple, | ||
) | ||
); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing sample output as in the examples below. |
||
This will print ``Honeycrisp``; | ||
|
||
Calling Methods | ||
~~~~~~~~~~~~~~~ | ||
|
||
The ``.`` syntax can also be used to call methods on an object, similar to | ||
JavaScript:: | ||
|
||
class Robot | ||
{ | ||
public function sayHi($times) | ||
{ | ||
$greetings = array(); | ||
for ($i = 0; $i < $times; $i++) { | ||
$greetings[] = 'Hi'; | ||
} | ||
|
||
return implode(' ', $greetings).'!'; | ||
} | ||
} | ||
|
||
$robot = new Robot(); | ||
|
||
echo $language->evaluate( | ||
'robot.sayHi(3)', | ||
array( | ||
'robot' => $robot, | ||
) | ||
); | ||
|
||
This will print ``Hi Hi Hi!``. | ||
|
||
.. _component-expression-arrays: | ||
|
||
Working with Arrays | ||
------------------- | ||
|
||
If you pass an array into an expression, use the ``[]`` syntax to access | ||
array keys, similar to JavaScript:: | ||
|
||
$data = array('life' => 10, 'universe' => 10, 'everything' => 22); | ||
|
||
echo $language->evaluate( | ||
'data["life"] + data["universe"] + data["everything"]', | ||
array( | ||
'data' => $data, | ||
) | ||
); | ||
|
||
This will print ``42``. | ||
|
||
Supported Operators | ||
~~~~~~~~~~~~~~~~~~~ | ||
------------------- | ||
|
||
The component comes with a lot of operators: | ||
|
||
Arithmetic Operators | ||
.................... | ||
~~~~~~~~~~~~~~~~~~~~ | ||
|
||
* ``+`` (addition) | ||
* ``-`` (subtraction) | ||
|
@@ -35,20 +115,33 @@ Arithmetic Operators | |
* ``%`` (modulus) | ||
* ``**`` (pow) | ||
|
||
For example:: | ||
|
||
echo $language->evaluate( | ||
'life + universe + everything', | ||
array( | ||
'life' => 10, | ||
'universe' => 10, | ||
'everything' => 22, | ||
) | ||
); | ||
|
||
This will print out ``42``. | ||
|
||
Assignment Operators | ||
.................... | ||
~~~~~~~~~~~~~~~~~~~~ | ||
|
||
* ``=`` | ||
|
||
Bitwise Operators | ||
................. | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
* ``&`` (and) | ||
* ``|`` (or) | ||
* ``^`` (xor) | ||
|
||
Comparison Operators | ||
.................... | ||
~~~~~~~~~~~~~~~~~~~~ | ||
|
||
* ``==`` (equal) | ||
* ``===`` (identical) | ||
|
@@ -67,31 +160,97 @@ Comparison Operators | |
|
||
$language->evaluate('not "foo" matches "/bar/"'); // returns true | ||
|
||
Examples:: | ||
|
||
$ret1 = $language->evaluate( | ||
'life == everything', | ||
array( | ||
'life' => 10, | ||
'universe' => 10, | ||
'everything' => 22, | ||
) | ||
); | ||
|
||
$ret2 = $language->evaluate( | ||
'life > everything', | ||
array( | ||
'life' => 10, | ||
'universe' => 10, | ||
'everything' => 22, | ||
) | ||
); | ||
|
||
Both variables would be set to ``false``. | ||
|
||
Logical Operators | ||
................. | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
* ``not`` or ``!`` | ||
* ``and`` or ``&&`` | ||
* ``or`` or ``||`` | ||
|
||
For example:: | ||
|
||
$ret = $language->evaluate( | ||
'life < universe or life < everything', | ||
array( | ||
'life' => 10, | ||
'universe' => 10, | ||
'everything' => 22, | ||
) | ||
); | ||
|
||
This ``$ret`` variable will be set to ``true``. | ||
|
||
String Operators | ||
................ | ||
~~~~~~~~~~~~~~~~ | ||
|
||
* ``~`` (concatenation) | ||
|
||
For example:: | ||
|
||
echo $language->evaluate( | ||
'firstName~" "~lastName', | ||
array( | ||
'firstName' => 'Arthur', | ||
'lastName' => 'Dent', | ||
) | ||
); | ||
|
||
This would print out ``Arthur Dent``. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. being really strict, it would not print anything There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true - but the other examples evaluating to a string are echo'd in the end. So I think it is all about consistency, i.e. all examples should follow the same structure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. only one example prints something, the other examples say 'it returns ...' There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see five descriptions (including the introduction page) where it "prints" something (even without There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've changed this to echo and killed the variable - it was more of some copy-and-paste from a file where I was trying these out :). |
||
|
||
Array Operators | ||
............... | ||
~~~~~~~~~~~~~~~ | ||
|
||
* ``in`` (contain) | ||
* ``not in`` (does not contain) | ||
|
||
For example:: | ||
|
||
class User | ||
{ | ||
public $group; | ||
} | ||
|
||
$user = new User(); | ||
$user->group = 'human_resources'; | ||
|
||
$inGroup = $language->evaluate( | ||
'user.group in ["human_resources", "marketing"]', | ||
array( | ||
'user' => $user | ||
) | ||
); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing description of return value as in the examples before and maybe |
||
The ``$inGroup`` would evaluate to ``true``. | ||
|
||
Numeric Operators | ||
................. | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
* ``..`` (range) | ||
|
||
Ternary Operators | ||
................. | ||
~~~~~~~~~~~~~~~~~ | ||
|
||
* ``foo ? 'yes' : 'no'`` | ||
* ``foo ?: 'no'`` (equal to ``foo ? foo : 'no'``) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using the word 'expressions' here seems a bit vague, most people do not know what we mean by 'expressions'. I think we should provide 2 examples of the component in action:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reworded this paragraph and my initial thought (once we have the framework docs) is to make
security
,validation rules
androute matching
links to the framework docs where you can see the examples. Then we can keep this paragraph short, which is something I want.