📜 ⬆️ ⬇️

New in symfony 2.4: the ExpressionLanguage component

In Symfony 2.4 there will be a new component - ExpressionLanguage . The component is the engine for compiling and executing "expressions".
This language is a truncated version of the thrig. Expressions fit into one line and usually return a boolean value, but are not limited to this.
Unlike a twig, ExpressionLanguage works in two modes:

To make it possible to compile expressions in PHP code that does not need modification at runtime, an operator . should be explicit and mean only one possible behavior: foo.bar - for object properties, foo['bar'] for access to an array, foo.getBar() for calling methods.
Using the component is as simple as possible:
 use Symfony\Component\ExpressionLanguage\ExpressionLanguage; $language = new ExpressionLanguage(); echo $language->evaluate('1 + 1'); // echo 2 echo $language->compile('1 + 2'); // echo "(1 + 2)" 

The expression language supports everything the same as a twig: mathematical operators, strings, numbers, arrays, hashes, boolean variables ... Expressions can be considered as a very limited PHP sandbox, in which external influences are impossible, all variables must be declared in advance of compilation or execution expressions.
 $language->evaluate('a.b', array('a' => new stdClass())); $language->compile('a.b', array('a')); 

Last but not least, you can easily extend the language with functions. They work just like their analogs in tweig (for details, see the register() method)
What about usage examples? We have embedded the component into many other components used in symfony.


Service Container


You can use expressions anywhere you can pass an argument to a container:
 $c->register('foo', 'Foo')->addArgument(new Expression('bar.getvalue()')); 

In the container, expressions are complemented by two functions: service() to get the service, and parameter to get the value of the parameter:
 service("bar").getValue(parameter("value")) 

In XML:
 <service id="foo" class="Foo"> <argument type="expression">service('bar').getvalue(parameter('value'))</argument> </service> 

There is no overhead at runtime, as the PHP dumper compiles expressions. The previous example will compile to the following PHP code:
 $this->get("bar")->getvalue($this->getParameter("value")) 


Access Control Rules


Setting access rules can be confusing, which can lead to an unprotected application.
The new allow_if directive simplifies setting up access rules in your application:
 access_control: - { path: ^/_internal/secure, allow_if: "'127.0.0.1' == request.getClientIp() or has_role('ROLE_ADMIN')" } 

This rule restricts paths starting with /_internal/secure for users who are not logged on from localhost or who do not have administrator rights.
request , token and user are variables to which you have access, is_anonymous() , is_authenticated() , is_fully_authenticated() , is_rememberme() , and has_role() - functions available in expressions when setting access rules.
')

Twig


You can also use expressions in your templates using the expression function.
 {% if is_granted(expression('has_role("FOO")')) %} ... {% endif %} 


If you use SensioFrameworkExtraBundle , you also have the option to secure the controllers, with the @ Security annotation
 /** * @Route("/post/{id}") * @Security("has_role('ROLE_ADMIN')") */ public function showAction(Post $post) { } 

Note : Annotation @ Security will be part of version 3 of the bundle, which will be released before Symfony 2.4

Caching


In the third version of SensioFrameworkExtraBundle, the @Cache annotation will also be available, which gives access to HTTP caching. Instead of writing template code over and over in simple situations:
 /** * @Route("/post/{id}") * @Cache(smaxage="15") */ public function showAction(Request $request, Post $post) { $response = new Response(); $response->setLastModified($post->getUpdated()); if ($response->isNotModified($request)) { return $response; } // ... } 

You can configure everything in the annotation (this also works for the ETag):
 /** * @Route("/post/{id}") * @Cache(smaxage="15", lastModified="post.getUpdatedAt()") */ public function showAction(Post $post) { // ... } 

Routing


Out of the box, symfony can choose a route based on predefined variables (such as info , method , sheme ), but some need more complex logic based on information from the request ( Request object)
To cover these special cases, you can use the condition , which allows you to add any expression using the request and routing context variables:
 hello: path: /hello/{name} condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') =~ '/firefox/i'" 

And again, using the PHP routing rules dumper (URL matcher), there is no overhead project, since all expressions are compiled into PHP code:
 // hello if (0 === strpos($pathinfo, '/hello') && preg_match('#^/hello/(?P<name>[^/]++)$#s', $pathinfo, $matches) && (in_array($context->getMethod(), array(0 => "GET", 1 => "HEAD")) && preg_match("/firefox/i", $request->headers->get("User-Agent"))) ) { return $this->mergeDefaults(array_replace($matches, array('_route' => 'hello')), array ()); } 

Please note that these conditions will not be used when generating URLs.

Validation


The new Expression condition allows you to use expressions for validation:
 use Symfony\Component\Validator\Constraints as Assert; /** * @Assert\Expression("this.getFoo() == 'fo'", message="Not good!") */ class Obj { public function getFoo() { return 'foo'; } } 

In validator expressions, this refers to the current validation object.

Business Rule Engine


In addition, using the component in the framework of the expression language is an excellent candidate for creating a business rule engine. The idea is that the webmaster (administrator) of the site can flexibly customize the site, without using PHP and without dedicating themselves to security issues:
 # 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 


This is the last post in which I consider new features in symfony 2.4. The first release candidate will be available for several days.

I feel that not everyone would like this use of PHP, but please consider that I am a translator, articles, and not the creator of this component, and until I figured out whether I like it or not (especially what was struck by the expressions embedded in the word).
All comments and suggestions please in PM

Source: https://habr.com/ru/post/202058/


All Articles