Skip to content

Commit 3501f82

Browse files
authored
Merge pull request #3 from zef-dev/develop
Develop v1.2.0
2 parents 4f8cf0b + eb15a6c commit 3501f82

File tree

4 files changed

+158
-8
lines changed

4 files changed

+158
-8
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# CHANGELOG
22

3+
## 1.2.0 - 2022-12-27
4+
5+
* Allow method calls
6+
7+
38
## 1.1.0 - 2021-05-14
49

510
* Use Smfony 5

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"type": "library",
44
"description" : "A JUEL like extension for Symfony Expression Language",
55
"homepage": "https://github.com/zef-dev/zef-expression-language",
6-
"version": "1.1.0",
6+
"version": "1.2.0",
77
"keywords" : [
88
"symfony", "expression-language"
99
],

src/Zef/Zel/Symfony/GetAttrNode.php

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@ public function evaluate( $functions, $values)
2424
}
2525

2626
$property = $this->nodes['attribute']->attributes['value'];
27-
27+
28+
if (!$this->_shouldCallMethod($this->attributes['type'], $obj, $property)) {
29+
return null;
30+
}
31+
2832
return $obj->$property;
2933

3034
case self::METHOD_CALL:
3135
$obj = $this->nodes['node']->evaluate($functions, $values);
32-
36+
$method = $this->nodes['attribute']->attributes['value'];
37+
3338
if ( is_null( $obj)) {
3439
return null;
3540
}
@@ -41,6 +46,10 @@ public function evaluate( $functions, $values)
4146
throw new \RuntimeException(sprintf('Unable to call method "%s" of object "%s".', $this->nodes['attribute']->attributes['value'], \get_class($obj)));
4247
}
4348

49+
if (!$this->_shouldCallMethod($this->attributes['type'], $obj, $method)) {
50+
return null;
51+
}
52+
4453
return $toCall(...array_values($this->nodes['arguments']->evaluate($functions, $values)));
4554

4655
case self::ARRAY_CALL:
@@ -57,5 +66,62 @@ public function evaluate( $functions, $values)
5766
return $array[$this->nodes['attribute']->evaluate($functions, $values)] ?? null;
5867
}
5968
}
60-
61-
}
69+
70+
private function _shouldCallMethod($callType, $object, $value) {
71+
$isAccessible = 0;
72+
if (is_array($object)) {
73+
return true;
74+
}
75+
if (is_a($object, 'Zef\Zel\IValueAdapter') && is_array($object->get())) {
76+
return true;
77+
}
78+
switch ($callType) {
79+
case self::PROPERTY_CALL:
80+
if (in_array($value, array_keys(get_object_vars($object)))) {
81+
$isAccessible++;
82+
}
83+
84+
if (is_a($object, 'Zef\Zel\IValueAdapter') && in_array($value, array_keys(get_object_vars($object->get())))) {
85+
$isAccessible++;
86+
}
87+
88+
$wrappedClassMethods = get_class_methods($object);
89+
90+
foreach ($wrappedClassMethods as $wrappedClassMethod) {
91+
if (str_contains(strtolower($wrappedClassMethod), strtolower($value))) {
92+
$isAccessible++;
93+
}
94+
}
95+
96+
if (is_a( $object, 'Zef\Zel\IValueAdapter')) {
97+
$originalClassMethods = get_class_methods($object->get());
98+
foreach ($originalClassMethods as $originalClassMethod) {
99+
if (str_contains(strtolower($originalClassMethod), strtolower($value))) {
100+
$isAccessible++;
101+
}
102+
}
103+
}
104+
105+
break;
106+
case self::METHOD_CALL:
107+
if (in_array($value, get_class_methods($object))) {
108+
$isAccessible++;
109+
}
110+
111+
if (is_a( $object, 'Zef\Zel\IValueAdapter') && in_array($value, get_class_methods($object->get()))) {
112+
$isAccessible++;
113+
}
114+
115+
break;
116+
default:
117+
break;
118+
}
119+
120+
if (empty($isAccessible)) {
121+
return false;
122+
}
123+
124+
return true;
125+
}
126+
127+
}

tests/CorrectEvaluationTest.php

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,57 @@ public function getFunctions()
3939
$this->assertEquals( $expected, $expressionLanguage->evaluate( $expression, $values));
4040
}
4141

42+
/**
43+
* @dataProvider provideAlsoNonPublicObjectMethods
44+
*/
45+
public function testResolveWrappedNonPublicProperties( $expression, array $values, $expected)
46+
{
47+
$provider = new class() implements ExpressionFunctionProviderInterface {
48+
public function getFunctions()
49+
{
50+
$functions = [];
51+
$functions[] = ExpressionFunction::fromPhp( 'stripos');
52+
return $functions;
53+
}
54+
};
55+
56+
$expressionLanguage = new ExpressionLanguage( null, [$provider]);
57+
$resolver = new ObjectResolver( $values);
58+
$values = $resolver->get();
59+
60+
$this->assertEquals( $expected, $expressionLanguage->evaluate( $expression, $values));
61+
}
62+
63+
public function testResolveWrappedPrivateMethodCall()
64+
{
65+
$child = new class() {
66+
public function greet($name) { return "Hello $name"; }
67+
};
68+
$user = new class($child)
69+
{
70+
private $test = 'Another Test';
71+
72+
private $_name = 'Test';
73+
74+
private $_child;
75+
76+
public function __construct($child)
77+
{
78+
$this->_child = $child;
79+
}
80+
81+
private function sayHi() { return 'Hi'; }
82+
83+
public function getName() { return $this->_name; }
84+
85+
public function getChild() { return $this->_child; }
86+
};
87+
88+
$this->expectException('RuntimeException');
89+
$el = new ExpressionLanguage();
90+
$el->evaluate('foo.sayHi()', ['foo' => $user]);
91+
}
92+
4293
/**
4394
* @dataProvider provideSimpleValues
4495
* @dataProvider provideArrayValues
@@ -160,8 +211,36 @@ public function getChild() { return $this->_child; }
160211

161212

162213
return [
163-
['user.getName()', ['user' => $user], 'Test'],
164-
['user.getChild().greet(\'Goofus\')', ['user' => $user], 'Hello Goofus']
214+
['user.get().getName()', ['user' => $user], 'Test'],
215+
['user.get().getChild().greet(\'Goofus\')', ['user' => $user], 'Hello Goofus']
216+
];
217+
}
218+
219+
public function provideAlsoNonPublicObjectMethods()
220+
{
221+
$child = new class() {
222+
public function greet($name) { return "Hello $name"; }
223+
};
224+
$user = new class($child)
225+
{
226+
private $test = 'Another Test';
227+
228+
private $_name = 'Test';
229+
230+
private $_child;
231+
232+
public function __construct($child)
233+
{
234+
$this->_child = $child;
235+
}
236+
237+
public function getName() { return $this->_name; }
238+
239+
public function getChild() { return $this->_child; }
240+
};
241+
242+
return [
243+
['user.test', ['user' => $user], null]
165244
];
166245
}
167-
}
246+
}

0 commit comments

Comments
 (0)