Skip to content
Snippets Groups Projects
Commit 034f67e5 authored by Reiter, Christoph's avatar Reiter, Christoph :snake:
Browse files

expression language: inject an object providing helper functions/methods

instead of injecting global functions inject an object. Mainly to
have some namespacing in case the official language gains new functions
and to make it clear which function are from us and where the documentation
for thenm needs to be looked up.
parent 0652267b
No related branches found
No related tags found
1 merge request!210expression language: inject an object providing helper functions/methods
<?php
declare(strict_types=1);
namespace Dbp\Relay\CoreBundle\ExpressionLanguage;
/**
* This Type gets injected into our expression language variant with the name
* 'relay'. This allows us to add functions/methods with some kind of namespacing,
* instead of polluting the global namespace.
*/
class ExpressionExtension
{
/**
* @var ExpressionLanguage
*/
private $lang;
public function __construct(ExpressionLanguage $lang)
{
$this->lang = $lang;
}
public static function str_starts_with()
{
$args = func_get_args();
return call_user_func_array('str_starts_with', $args);
}
public static function str_ends_with()
{
$args = func_get_args();
return call_user_func_array('str_ends_with', $args);
}
public static function substr()
{
$args = func_get_args();
return call_user_func_array('substr', $args);
}
public static function strpos()
{
$args = func_get_args();
return call_user_func_array('strpos', $args);
}
public static function strlen()
{
$args = func_get_args();
return call_user_func_array('strlen', $args);
}
public static function ceil()
{
$args = func_get_args();
return call_user_func_array('ceil', $args);
}
public static function floor()
{
$args = func_get_args();
return call_user_func_array('floor', $args);
}
public static function round()
{
$args = func_get_args();
return call_user_func_array('round', $args);
}
public static function max()
{
$args = func_get_args();
return call_user_func_array('max', $args);
}
public static function min()
{
$args = func_get_args();
return call_user_func_array('min', $args);
}
public static function count()
{
$args = func_get_args();
return call_user_func_array('count', $args);
}
public static function implode()
{
$args = func_get_args();
return call_user_func_array('implode', $args);
}
public static function explode()
{
$args = func_get_args();
return call_user_func_array('explode', $args);
}
public static function empty($value): bool
{
// empty is not a real function, so call_user_func_array doesn't work
return empty($value);
}
public function map(iterable $iterable, string $expression): array
{
$transformedResult = [];
foreach ($iterable as $key => $value) {
$transformedResult[$key] = $this->lang->evaluate($expression, ['key' => $key, 'value' => $value, 'relay' => $this]);
}
return $transformedResult;
}
public function filter(iterable $iterable, string $expression): array
{
$filteredResult = [];
foreach ($iterable as $key => $value) {
if ($this->lang->evaluate($expression, ['key' => $key, 'value' => $value])) {
$filteredResult[] = $value;
}
}
return $filteredResult;
}
}
...@@ -30,4 +30,15 @@ class ExpressionLanguage extends SymfonyExpressionLanguage ...@@ -30,4 +30,15 @@ class ExpressionLanguage extends SymfonyExpressionLanguage
parent::__construct($cache, $providers); parent::__construct($cache, $providers);
} }
/**
* @return mixed
*/
public function evaluate($expression, array $values = [])
{
$ext = new ExpressionExtension($this);
$values['relay'] = $ext;
return parent::evaluate($expression, $values);
}
} }
...@@ -25,6 +25,15 @@ class ExpressionLanguageTest extends TestCase ...@@ -25,6 +25,15 @@ class ExpressionLanguageTest extends TestCase
$this->assertSame([1, 5, 2, 4], $lang->evaluate('filter([1, 5, 2, 4], "42")')); $this->assertSame([1, 5, 2, 4], $lang->evaluate('filter([1, 5, 2, 4], "42")'));
$this->assertSame([5, 4], $lang->evaluate('filter([1, 5, 2, 4], "value > 2")')); $this->assertSame([5, 4], $lang->evaluate('filter([1, 5, 2, 4], "value > 2")'));
$this->assertSame([2, 4], $lang->evaluate('filter({1: 2, 3: 4}, "true")')); $this->assertSame([2, 4], $lang->evaluate('filter({1: 2, 3: 4}, "true")'));
$this->assertSame([5, 2, 4], $lang->evaluate('filter([0.5, 5, 2, 4], "floor(value)")'));
$this->assertSame([], $lang->evaluate('relay.filter([], "true")'));
$this->assertSame([], $lang->evaluate('relay.filter([1, 5, 2, 4], "false")'));
$this->assertSame([1, 5, 2, 4], $lang->evaluate('relay.filter([1, 5, 2, 4], "true")'));
$this->assertSame([1, 5, 2, 4], $lang->evaluate('relay.filter([1, 5, 2, 4], "42")'));
$this->assertSame([5, 4], $lang->evaluate('relay.filter([1, 5, 2, 4], "value > 2")'));
$this->assertSame([2, 4], $lang->evaluate('relay.filter({1: 2, 3: 4}, "true")'));
$this->assertSame([5, 2, 4], $lang->evaluate('relay.filter([0.5, 5, 2, 4], "relay.floor(value)")'));
} }
public function testMap() public function testMap()
...@@ -35,6 +44,14 @@ class ExpressionLanguageTest extends TestCase ...@@ -35,6 +44,14 @@ class ExpressionLanguageTest extends TestCase
$this->assertSame([2, 6, 3, 5], $lang->evaluate('map([1, 5, 2, 4], "value + 1")')); $this->assertSame([2, 6, 3, 5], $lang->evaluate('map([1, 5, 2, 4], "value + 1")'));
$this->assertSame([1 => 3, 3 => 7], $lang->evaluate('map({1: 2, 3: 4}, "key + value")')); $this->assertSame([1 => 3, 3 => 7], $lang->evaluate('map({1: 2, 3: 4}, "key + value")'));
$this->assertSame([1 => 42, 3 => 42], $lang->evaluate('map({1: 2, 3: 4}, "42")')); $this->assertSame([1 => 42, 3 => 42], $lang->evaluate('map({1: 2, 3: 4}, "42")'));
$this->assertSame([1.0], $lang->evaluate('map([0.5], "ceil(value)")'));
$this->assertSame([], $lang->evaluate('relay.map([], "true")'));
$this->assertSame([false], $lang->evaluate('relay.map([1], "false")'));
$this->assertSame([2, 6, 3, 5], $lang->evaluate('relay.map([1, 5, 2, 4], "value + 1")'));
$this->assertSame([1 => 3, 3 => 7], $lang->evaluate('relay.map({1: 2, 3: 4}, "key + value")'));
$this->assertSame([1 => 42, 3 => 42], $lang->evaluate('relay.map({1: 2, 3: 4}, "42")'));
$this->assertSame([1.0], $lang->evaluate('relay.map([0.5], "relay.ceil(value)")'));
} }
public function testEmpty() public function testEmpty()
...@@ -45,6 +62,12 @@ class ExpressionLanguageTest extends TestCase ...@@ -45,6 +62,12 @@ class ExpressionLanguageTest extends TestCase
$this->assertTrue($lang->evaluate('empty("0")')); $this->assertTrue($lang->evaluate('empty("0")'));
$this->assertFalse($lang->evaluate('empty(42)')); $this->assertFalse($lang->evaluate('empty(42)'));
$this->assertFalse($lang->evaluate('empty([42])')); $this->assertFalse($lang->evaluate('empty([42])'));
$this->assertTrue($lang->evaluate('relay.empty([])'));
$this->assertTrue($lang->evaluate('relay.empty(0)'));
$this->assertTrue($lang->evaluate('relay.empty("0")'));
$this->assertFalse($lang->evaluate('relay.empty(42)'));
$this->assertFalse($lang->evaluate('relay.empty([42])'));
} }
public function testPhp() public function testPhp()
...@@ -53,6 +76,10 @@ class ExpressionLanguageTest extends TestCase ...@@ -53,6 +76,10 @@ class ExpressionLanguageTest extends TestCase
$this->assertSame(2, $lang->evaluate('count([1, 2])')); $this->assertSame(2, $lang->evaluate('count([1, 2])'));
$this->assertSame('1-2', $lang->evaluate('implode("-", ["1", "2"])')); $this->assertSame('1-2', $lang->evaluate('implode("-", ["1", "2"])'));
$this->assertSame(['1', '2'], $lang->evaluate('explode("-", "1-2")')); $this->assertSame(['1', '2'], $lang->evaluate('explode("-", "1-2")'));
$this->assertSame(2, $lang->evaluate('relay.count([1, 2])'));
$this->assertSame('1-2', $lang->evaluate('relay.implode("-", ["1", "2"])'));
$this->assertSame(['1', '2'], $lang->evaluate('relay.explode("-", "1-2")'));
} }
public function testNumeric() public function testNumeric()
...@@ -63,6 +90,12 @@ class ExpressionLanguageTest extends TestCase ...@@ -63,6 +90,12 @@ class ExpressionLanguageTest extends TestCase
$this->assertSame(1.0, $lang->evaluate('round(0.5)')); $this->assertSame(1.0, $lang->evaluate('round(0.5)'));
$this->assertSame(42, $lang->evaluate('max([2, 42])')); $this->assertSame(42, $lang->evaluate('max([2, 42])'));
$this->assertSame(2, $lang->evaluate('min([2, 42])')); $this->assertSame(2, $lang->evaluate('min([2, 42])'));
$this->assertSame(2.0, $lang->evaluate('relay.ceil(1.2)'));
$this->assertSame(1.0, $lang->evaluate('relay.floor(1.9)'));
$this->assertSame(1.0, $lang->evaluate('relay.round(0.5)'));
$this->assertSame(42, $lang->evaluate('relay.max([2, 42])'));
$this->assertSame(2, $lang->evaluate('relay.min([2, 42])'));
} }
public function testString() public function testString()
...@@ -75,5 +108,13 @@ class ExpressionLanguageTest extends TestCase ...@@ -75,5 +108,13 @@ class ExpressionLanguageTest extends TestCase
$this->assertSame('foo', $lang->evaluate('substr("foobar", 0, 3)')); $this->assertSame('foo', $lang->evaluate('substr("foobar", 0, 3)'));
$this->assertSame(1, $lang->evaluate('strpos("foobar", "oo")')); $this->assertSame(1, $lang->evaluate('strpos("foobar", "oo")'));
$this->assertSame(6, $lang->evaluate('strlen("foobar")')); $this->assertSame(6, $lang->evaluate('strlen("foobar")'));
$this->assertTrue($lang->evaluate('relay.str_starts_with("foo", "fo")'));
$this->assertFalse($lang->evaluate('relay.str_starts_with("foo", "xo")'));
$this->assertTrue($lang->evaluate('relay.str_ends_with("foo", "oo")'));
$this->assertFalse($lang->evaluate('relay.str_ends_with("foo", "of")'));
$this->assertSame('foo', $lang->evaluate('relay.substr("foobar", 0, 3)'));
$this->assertSame(1, $lang->evaluate('relay.strpos("foobar", "oo")'));
$this->assertSame(6, $lang->evaluate('relay.strlen("foobar")'));
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment