Skip to content

Commit 67741ad

Browse files
Merge branch '4.4' into 5.0
* 4.4: (25 commits) [DoctrineBridge] Use new Types::* constants and support new json type [Debug][ErrorHandler] improved deprecation notices for methods new args and return type [BrowserKit] Nested file array prevents uploading file [ExpressionLanguage] Fixed collisions of character operators with object properties [Validator] Remove specific check for Valid targets [PhpUnitBridge] Use trait instead of extending deprecated class Fix versioned namespace clears fix remember me Use strict assertion in asset tests [DoctrineBridge][DoctrineExtractor] Fix indexBy with custom and some core types Do not rely on the current locale when dumping a Graphviz object fix typo [Ldap] force default network timeout [Config] don't throw on missing excluded paths Docs: Typo, grammar [Validator] Add the missing translations for the Polish ("pl") locale [PhpUnitBridge] Add compatibility to PHPUnit 9 #35662 [Routing] Add locale requirement for localized routes [Console] Inline exact-match handling with 4.4 Set previous exception when rethrown from controller resolver ...
2 parents c0eda2a + 70649e0 commit 67741ad

File tree

5 files changed

+64
-4
lines changed

5 files changed

+64
-4
lines changed

Lexer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public function tokenize(string $expression)
7171
// strings
7272
$tokens[] = new Token(Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)), $cursor + 1);
7373
$cursor += \strlen($match[0]);
74-
} elseif (preg_match('/not in(?=[\s(])|\!\=\=|not(?=[\s(])|and(?=[\s(])|\=\=\=|\>\=|or(?=[\s(])|\<\=|\*\*|\.\.|in(?=[\s(])|&&|\|\||matches|\=\=|\!\=|\*|~|%|\/|\>|\||\!|\^|&|\+|\<|\-/A', $expression, $match, 0, $cursor)) {
74+
} elseif (preg_match('/(?<=^|[\s(])not in(?=[\s(])|\!\=\=|(?<=^|[\s(])not(?=[\s(])|(?<=^|[\s(])and(?=[\s(])|\=\=\=|\>\=|(?<=^|[\s(])or(?=[\s(])|\<\=|\*\*|\.\.|(?<=^|[\s(])in(?=[\s(])|&&|\|\||(?<=^|[\s(])matches|\=\=|\!\=|\*|~|%|\/|\>|\||\!|\^|&|\+|\<|\-/A', $expression, $match, 0, $cursor)) {
7575
// operators
7676
$tokens[] = new Token(Token::OPERATOR_TYPE, $match[0], $cursor + 1);
7777
$cursor += \strlen($match[0]);

Resources/bin/generate_operator_regex.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515

1616
$regex = [];
1717
foreach ($operators as $operator => $length) {
18-
// an operator that ends with a character must be followed by
19-
// a whitespace or a parenthesis
20-
$regex[] = preg_quote($operator, '/').(ctype_alpha($operator[$length - 1]) ? '(?=[\s(])' : '');
18+
// Collisions of character operators:
19+
// - an operator that begins with a character must have a space or a parenthesis before or starting at the beginning of a string
20+
// - an operator that ends with a character must be followed by a whitespace or a parenthesis
21+
$regex[] =
22+
(ctype_alpha($operator[0]) ? '(?<=^|[\s(])' : '')
23+
.preg_quote($operator, '/')
24+
.(ctype_alpha($operator[$length - 1]) ? '(?=[\s(])' : '');
2125
}
2226

2327
echo '/'.implode('|', $regex).'/A';

Tests/ExpressionLanguageTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,17 @@ public function testCachingWithDifferentNamesOrder()
195195
$expressionLanguage->compile($expression, ['B' => 'b', 'a']);
196196
}
197197

198+
public function testOperatorCollisions()
199+
{
200+
$expressionLanguage = new ExpressionLanguage();
201+
$expression = 'foo.not in [bar]';
202+
$compiled = $expressionLanguage->compile($expression, ['foo', 'bar']);
203+
$this->assertSame('in_array($foo->not, [0 => $bar])', $compiled);
204+
205+
$result = $expressionLanguage->evaluate($expression, ['foo' => (object) ['not' => 'test'], 'bar' => 'test']);
206+
$this->assertTrue($result);
207+
}
208+
198209
/**
199210
* @dataProvider getRegisterCallbacks
200211
*/

Tests/LexerTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ public function getTokenizeData()
114114
[new Token('string', '#foo', 1)],
115115
'"#foo"',
116116
],
117+
[
118+
[
119+
new Token('name', 'foo', 1),
120+
new Token('punctuation', '.', 4),
121+
new Token('name', 'not', 5),
122+
new Token('operator', 'in', 9),
123+
new Token('punctuation', '[', 12),
124+
new Token('name', 'bar', 13),
125+
new Token('punctuation', ']', 16),
126+
],
127+
'foo.not in [bar]',
128+
],
117129
];
118130
}
119131
}

Tests/ParserTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ public function getParseData()
5353
$arguments->addElement(new Node\ConstantNode(2));
5454
$arguments->addElement(new Node\ConstantNode(true));
5555

56+
$arrayNode = new Node\ArrayNode();
57+
$arrayNode->addElement(new Node\NameNode('bar'));
58+
5659
return [
5760
[
5861
new Node\NameNode('a'),
@@ -151,6 +154,36 @@ public function getParseData()
151154
'bar',
152155
['foo' => 'bar'],
153156
],
157+
158+
// Operators collisions
159+
[
160+
new Node\BinaryNode(
161+
'in',
162+
new Node\GetAttrNode(
163+
new Node\NameNode('foo'),
164+
new Node\ConstantNode('not', true),
165+
new Node\ArgumentsNode(),
166+
Node\GetAttrNode::PROPERTY_CALL
167+
),
168+
$arrayNode
169+
),
170+
'foo.not in [bar]',
171+
['foo', 'bar'],
172+
],
173+
[
174+
new Node\BinaryNode(
175+
'or',
176+
new Node\UnaryNode('not', new Node\NameNode('foo')),
177+
new Node\GetAttrNode(
178+
new Node\NameNode('foo'),
179+
new Node\ConstantNode('not', true),
180+
new Node\ArgumentsNode(),
181+
Node\GetAttrNode::PROPERTY_CALL
182+
)
183+
),
184+
'not foo or foo.not',
185+
['foo'],
186+
],
154187
];
155188
}
156189

0 commit comments

Comments
 (0)