TYPO3 CMS  TYPO3_7-6
TemplateParserPatternTest.php
Go to the documentation of this file.
1 <?php
3 
4 /* *
5  * This script is backported from the TYPO3 Flow package "TYPO3.Fluid". *
6  * *
7  * It is free software; you can redistribute it and/or modify it under *
8  * the terms of the GNU Lesser General Public License, either version 3 *
9  * of the License, or (at your option) any later version. *
10  * *
11  * The TYPO3 project - inspiring people to share! *
12  * */
13 
18 {
23  {
24  $pattern = str_replace('FLUID_NAMESPACE_SEPARATOR', preg_quote(\TYPO3\CMS\Fluid\Fluid::LEGACY_NAMESPACE_SEPARATOR), \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SCAN_PATTERN_NAMESPACEDECLARATION);
25  $this->assertEquals(preg_match($pattern, '{namespace acme=Tx_AcmeMyPackage_Bla_blubb}'), 1, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did not match a namespace declaration (1).');
26  $this->assertEquals(preg_match($pattern, '{namespace acme=Tx_AcmeMyPackage_Bla_Blubb }'), 1, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did not match a namespace declaration (2).');
27  $this->assertEquals(preg_match($pattern, ' {namespace foo = Tx_Foo_Bla3_Blubb } '), 1, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did not match a namespace declaration (3).');
28  $this->assertEquals(preg_match($pattern, ' \\{namespace fblubb = Tx_Fluid_Bla3_Blubb }'), 0, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did match a namespace declaration even if it was escaped. (1)');
29  $this->assertEquals(preg_match($pattern, '\\{namespace typo3 = Tx_TYPO3_Bla3_Blubb }'), 0, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did match a namespace declaration even if it was escaped. (2)');
30  }
31 
36  {
37  $pattern = str_replace('FLUID_NAMESPACE_SEPARATOR', preg_quote(\TYPO3\CMS\Fluid\Fluid::NAMESPACE_SEPARATOR), \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SCAN_PATTERN_NAMESPACEDECLARATION);
38  $this->assertEquals(preg_match($pattern, '{namespace acme=Acme.MyPackage\Bla\blubb}'), 1, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did not match a namespace declaration (1).');
39  $this->assertEquals(preg_match($pattern, '{namespace acme=Acme.MyPackage\Bla\Blubb }'), 1, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did not match a namespace declaration (2).');
40  $this->assertEquals(preg_match($pattern, ' {namespace foo = Foo\Bla3\Blubb } '), 1, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did not match a namespace declaration (3).');
41  $this->assertEquals(preg_match($pattern, ' \\{namespace fblubb = TYPO3.Fluid\Bla3\Blubb }'), 0, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did match a namespace declaration even if it was escaped. (1)');
42  $this->assertEquals(preg_match($pattern, '\\{namespace typo3 = TYPO3.TYPO3\Bla3\Blubb }'), 0, 'The SCAN_PATTERN_NAMESPACEDECLARATION pattern did match a namespace declaration even if it was escaped. (2)');
43  }
44 
49  {
50  $pattern = $this->insertNamespaceIntoRegularExpression(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SPLIT_PATTERN_TEMPLATE_DYNAMICTAGS, ['typo3', 't3', 'f']);
51 
52  $source = '<html><head> <f:a.testing /> <f:blablubb> {testing}</f4:blz> </t3:hi.jo>';
53  $expected = ['<html><head> ', '<f:a.testing />', ' ', '<f:blablubb>', ' {testing}</f4:blz> ', '</t3:hi.jo>'];
54  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly with simple tags.');
55 
56  $source = 'hi<f:testing attribute="Hallo>{yep}" nested:attribute="jup" />ja';
57  $expected = ['hi', '<f:testing attribute="Hallo>{yep}" nested:attribute="jup" />', 'ja'];
58  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly with > inside an attribute.');
59 
60  $source = 'hi<f:testing attribute="Hallo\\"{yep}" nested:attribute="jup" />ja';
61  $expected = ['hi', '<f:testing attribute="Hallo\\"{yep}" nested:attribute="jup" />', 'ja'];
62  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly if a " is inside a double-quoted string.');
63 
64  $source = 'hi<f:testing attribute=\'Hallo>{yep}\' nested:attribute="jup" />ja';
65  $expected = ['hi', '<f:testing attribute=\'Hallo>{yep}\' nested:attribute="jup" />', 'ja'];
66  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly with single quotes as attribute delimiters.');
67 
68  $source = 'hi<f:testing attribute=\'Hallo\\\'{yep}\' nested:attribute="jup" />ja';
69  $expected = ['hi', '<f:testing attribute=\'Hallo\\\'{yep}\' nested:attribute="jup" />', 'ja'];
70  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly if \' is inside a single-quoted attribute.');
71 
72  $source = 'Hallo <f:testing><![CDATA[<f:notparsed>]]></f:testing>';
73  $expected = ['Hallo ', '<f:testing>', '<![CDATA[<f:notparsed>]]>', '</f:testing>'];
74  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly if there is a CDATA section the parser should ignore.');
75 
76  $veryLongViewHelper ='<f:form enctype="multipart/form-data" onsubmit="void(0)" onreset="void(0)" action="someAction" arguments="{arg1: \'val1\', arg2: \'val2\'}" controller="someController" package="YourCompanyName.somePackage" subpackage="YourCompanyName.someSubpackage" section="someSection" format="txt" additionalParams="{param1: \'val1\', param2: \'val2\'}" absolute="true" addQueryString="true" argumentsToBeExcludedFromQueryString="{0: \'foo\'}" />';
77  $source = $veryLongViewHelper . 'Begin' . $veryLongViewHelper . 'End';
78  $expected = [$veryLongViewHelper, 'Begin', $veryLongViewHelper, 'End'];
79  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly if the VH has lots of arguments.');
80 
81  $source = '<f:a.testing data-bar="foo"> <f:a.testing>';
82  $expected = ['<f:a.testing data-bar="foo">', ' ', '<f:a.testing>'];
83  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_DYNAMICTAGS pattern did not split the input string correctly with data- attribute.');
84  }
85 
89  public function testSCAN_PATTERN_DYNAMICTAG()
90  {
92  $source = '<f:crop attribute="Hallo">';
93  $expected = [
94  0 => '<f:crop attribute="Hallo">',
95  'NamespaceIdentifier' => 'f',
96  1 => 'f',
97  'MethodIdentifier' => 'crop',
98  2 => 'crop',
99  'Attributes' => ' attribute="Hallo"',
100  3 => ' attribute="Hallo"',
101  'Selfclosing' => '',
102  4 => ''
103  ];
104  preg_match($pattern, $source, $matches);
105  $this->assertEquals($expected, $matches, 'The SCAN_PATTERN_DYNAMICTAG does not match correctly.');
106 
107  $pattern = $this->insertNamespaceIntoRegularExpression(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SCAN_PATTERN_TEMPLATE_VIEWHELPERTAG, ['f']);
108  $source = '<f:crop data-attribute="Hallo">';
109  $expected = [
110  0 => '<f:crop data-attribute="Hallo">',
111  'NamespaceIdentifier' => 'f',
112  1 => 'f',
113  'MethodIdentifier' => 'crop',
114  2 => 'crop',
115  'Attributes' => ' data-attribute="Hallo"',
116  3 => ' data-attribute="Hallo"',
117  'Selfclosing' => '',
118  4 => ''
119  ];
120  preg_match($pattern, $source, $matches);
121  $this->assertEquals($expected, $matches, 'The SCAN_PATTERN_DYNAMICTAG does not match correctly with data- attributes.');
122 
123  $source = '<f:base />';
124  $expected = [
125  0 => '<f:base />',
126  'NamespaceIdentifier' => 'f',
127  1 => 'f',
128  'MethodIdentifier' => 'base',
129  2 => 'base',
130  'Attributes' => '',
131  3 => '',
132  'Selfclosing' => '/',
133  4 => '/'
134  ];
135  preg_match($pattern, $source, $matches);
136  $this->assertEquals($expected, $matches, 'The SCAN_PATTERN_DYNAMICTAG does not match correctly when there is a space before the self-closing tag.');
137 
138  $source = '<f:crop attribute="Ha\\"llo"/>';
139  $expected = [
140  0 => '<f:crop attribute="Ha\\"llo"/>',
141  'NamespaceIdentifier' => 'f',
142  1 => 'f',
143  'MethodIdentifier' => 'crop',
144  2 => 'crop',
145  'Attributes' => ' attribute="Ha\\"llo"',
146  3 => ' attribute="Ha\\"llo"',
147  'Selfclosing' => '/',
148  4 => '/'
149  ];
150  preg_match($pattern, $source, $matches);
151  $this->assertEquals($expected, $matches, 'The SCAN_PATTERN_DYNAMICTAG does not match correctly with self-closing tags.');
152 
153  $source = '<f:link.uriTo complex:attribute="Ha>llo" a="b" c=\'d\'/>';
154  $expected = [
155  0 => '<f:link.uriTo complex:attribute="Ha>llo" a="b" c=\'d\'/>',
156  'NamespaceIdentifier' => 'f',
157  1 => 'f',
158  'MethodIdentifier' => 'link.uriTo',
159  2 => 'link.uriTo',
160  'Attributes' => ' complex:attribute="Ha>llo" a="b" c=\'d\'',
161  3 => ' complex:attribute="Ha>llo" a="b" c=\'d\'',
162  'Selfclosing' => '/',
163  4 => '/'
164  ];
165  preg_match($pattern, $source, $matches);
166  $this->assertEquals($expected, $matches, 'The SCAN_PATTERN_DYNAMICTAG does not match correctly with complex attributes and > inside the attributes.');
167  }
168 
173  {
175  $this->assertEquals(preg_match($pattern, '</f:bla>'), 1, 'The SCAN_PATTERN_CLOSINGDYNAMICTAG does not match a tag it should match.');
176  $this->assertEquals(preg_match($pattern, '</f:bla.a >'), 1, 'The SCAN_PATTERN_CLOSINGDYNAMICTAG does not match a tag (with spaces included) it should match.');
177  $this->assertEquals(preg_match($pattern, '</t:bla>'), 0, 'The SCAN_PATTERN_CLOSINGDYNAMICTAG does match match a tag it should not match.');
178  }
179 
184  {
186  $source = ' test="Hallo" argument:post="\'Web" other=\'Single"Quoted\' data-foo="bar"';
187  $this->assertEquals(preg_match_all($pattern, $source, $matches, PREG_SET_ORDER), 4, 'The SPLIT_PATTERN_TAGARGUMENTS does not match correctly.');
188  $this->assertEquals('data-foo', $matches[3]['Argument']);
189  }
190 
195  {
197 
198  $source = 'some string{Object.bla}here as well';
199  $expected = ['some string', '{Object.bla}', 'here as well'];
200  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX pattern did not split the input string correctly with a simple example.');
201 
202  $source = 'some {}string\\{Object.bla}here as well';
203  $expected = ['some {}string\\', '{Object.bla}', 'here as well'];
204  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX pattern did not split the input string correctly with an escaped example. (1)');
205 
206  $source = 'some {f:viewHelper()} as well';
207  $expected = ['some ', '{f:viewHelper()}', ' as well'];
208  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX pattern did not split the input string correctly with an escaped example. (2)');
209 
210  $source = 'abc {f:for(arg1: post)} def';
211  $expected = ['abc ', '{f:for(arg1: post)}', ' def'];
212  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX pattern did not split the input string correctly with an escaped example.(3)');
213 
214  $source = 'abc {bla.blubb->f:for(param:42)} def';
215  $expected = ['abc ', '{bla.blubb->f:for(param:42)}', ' def'];
216  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX pattern did not split the input string correctly with an escaped example.(4)');
217 
218  $source = 'abc {f:for(bla:"post{{")} def';
219  $expected = ['abc ', '{f:for(bla:"post{{")}', ' def'];
220  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX pattern did not split the input string correctly with an escaped example.(5)');
221 
222  $source = 'abc {f:for(param:"abc\\"abc")} def';
223  $expected = ['abc ', '{f:for(param:"abc\\"abc")}', ' def'];
224  $this->assertEquals(preg_split($pattern, $source, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY), $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX pattern did not split the input string correctly with an escaped example.(6)');
225  }
226 
231  {
233 
234  $source = 'f:for(each: bla)';
235  $expected = [
236  0 => [
237  0 => 'f:for(each: bla)',
238  1 => 'f',
239  'NamespaceIdentifier' => 'f',
240  2 => 'for',
241  'MethodIdentifier' => 'for',
242  3 => 'each: bla',
243  'ViewHelperArguments' => 'each: bla'
244  ]
245  ];
246  preg_match_all($pattern, $source, $matches, PREG_SET_ORDER);
247  $this->assertEquals($matches, $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER');
248 
249  $source = 'f:for(each: bla)->g:bla(a:"b\\"->(f:a()", cd: {a:b})';
250  $expected = [
251  0 => [
252  0 => 'f:for(each: bla)',
253  1 => 'f',
254  'NamespaceIdentifier' => 'f',
255  2 => 'for',
256  'MethodIdentifier' => 'for',
257  3 => 'each: bla',
258  'ViewHelperArguments' => 'each: bla'
259  ],
260  1 => [
261  0 => 'g:bla(a:"b\\"->(f:a()", cd: {a:b})',
262  1 => 'g',
263  'NamespaceIdentifier' => 'g',
264  2 => 'bla',
265  'MethodIdentifier' => 'bla',
266  3 => 'a:"b\\"->(f:a()", cd: {a:b}',
267  'ViewHelperArguments' => 'a:"b\\"->(f:a()", cd: {a:b}'
268  ]
269  ];
270  preg_match_all($pattern, $source, $matches, PREG_SET_ORDER);
271  $this->assertEquals($matches, $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER');
272  }
273 
278  {
280  $this->assertEquals(preg_match($pattern, '{object}'), 1, 'Object accessor not identified!');
281  $this->assertEquals(preg_match($pattern, '{oBject1}'), 1, 'Object accessor not identified if there is a number and capitals inside!');
282  $this->assertEquals(preg_match($pattern, '{object.recursive}'), 1, 'Object accessor not identified if there is a dot inside!');
283  $this->assertEquals(preg_match($pattern, '{object-with-dash.recursive_value}'), 1, 'Object accessor not identified if there is a _ or - inside!');
284  $this->assertEquals(preg_match($pattern, '{f:for()}'), 1, 'Object accessor not identified if it contains only of a ViewHelper.');
285  $this->assertEquals(preg_match($pattern, '{f:for()->f:for2()}'), 1, 'Object accessor not identified if it contains only of a ViewHelper (nested).');
286  $this->assertEquals(preg_match($pattern, '{abc->f:for()}'), 1, 'Object accessor not identified if there is a ViewHelper inside!');
287  $this->assertEquals(preg_match($pattern, '{bla-blubb.recursive_value->f:for()->f:for()}'), 1, 'Object accessor not identified if there is a recursive ViewHelper inside!');
288  $this->assertEquals(preg_match($pattern, '{f:for(arg1:arg1value, arg2: "bla\\"blubb")}'), 1, 'Object accessor not identified if there is an argument inside!');
289  $this->assertEquals(preg_match($pattern, '{dash:value}'), 0, 'Object accessor identified, but was array!');
290  //$this->assertEquals(preg_match($pattern, '{}'), 0, 'Object accessor identified, and it was empty!');
291  }
292 
297  {
299  $this->assertEquals(preg_match($pattern, '{a:b}'), 1, 'Array syntax not identified!');
300  $this->assertEquals(preg_match($pattern, '{a:b, c : d}'), 1, 'Array syntax not identified in case there are multiple properties!');
301  $this->assertEquals(preg_match($pattern, '{a : 123}'), 1, 'Array syntax not identified when a number is passed as argument!');
302  $this->assertEquals(preg_match($pattern, '{a:"String"}'), 1, 'Array syntax not identified in case of a double quoted string!');
303  $this->assertEquals(preg_match($pattern, '{a:\'String\'}'), 1, 'Array syntax not identified in case of a single quoted string!');
304 
305  $expected = '{a:{bla:{x:z}, b: a}}';
306  preg_match($pattern, $expected, $match);
307  $this->assertEquals($match[0], $expected, 'If nested arrays appear, the string is not parsed correctly.');
308 
309  $expected = '{a:"{bla{{}"}';
310  preg_match($pattern, $expected, $match);
311  $this->assertEquals($match[0], $expected, 'If nested strings with {} inside appear, the string is not parsed correctly.');
312  }
313 
318  {
320 
321  $source = '{a: b, e: {c:d, e:f}}';
322  preg_match_all($pattern, $source, $matches, PREG_SET_ORDER);
323 
324  $expected = [
325  0 => [
326  0 => 'a: b',
327  'ArrayPart' => 'a: b',
328  1 => 'a: b',
329  'Key' => 'a',
330  2 => 'a',
331  'QuotedString' => '',
332  3 => '',
333  'VariableIdentifier' => 'b',
334  4 => 'b'
335  ],
336  1 => [
337  0 => 'e: {c:d, e:f}',
338  'ArrayPart' => 'e: {c:d, e:f}',
339  1 => 'e: {c:d, e:f}',
340  'Key' => 'e',
341  2 => 'e',
342  'QuotedString' => '',
343  3 => '',
344  'VariableIdentifier' => '',
345  4 => '',
346  'Number' => '',
347  5 => '',
348  'Subarray' => 'c:d, e:f',
349  6 => 'c:d, e:f'
350  ]
351  ];
352  $this->assertEquals($matches, $expected, 'The regular expression splitting the array apart does not work!');
353  }
354 
360  public function testSCAN_PATTERN_CDATA()
361  {
363  $this->assertEquals(preg_match($pattern, '<!-- Test -->'), 0, 'The SCAN_PATTERN_CDATA matches a comment, but it should not.');
364  $this->assertEquals(preg_match($pattern, '<![CDATA[This is some ]]>'), 1, 'The SCAN_PATTERN_CDATA does not match a simple CDATA string.');
365  $this->assertEquals(preg_match($pattern, '<![CDATA[This is<bla:test> some ]]>'), 1, 'The SCAN_PATTERN_CDATA does not match a CDATA string with tags inside..');
366  }
367 
375  protected function insertNamespaceIntoRegularExpression($regularExpression, $namespace)
376  {
377  return str_replace('NAMESPACE', implode('|', $namespace), $regularExpression);
378  }
379 }
const NAMESPACE_SEPARATOR
Definition: Fluid.php:19
const LEGACY_NAMESPACE_SEPARATOR
Definition: Fluid.php:18