TYPO3  7.6
TemplateParserPatternTest.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Fluid\Tests\Unit\Core\Parser;
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 
17 class TemplateParserPatternTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
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, array('typo3', 't3', 'f'));
51 
52  $source = '<html><head> <f:a.testing /> <f:blablubb> {testing}</f4:blz> </t3:hi.jo>';
53  $expected = array('<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 = array('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 = array('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 = array('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 = array('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 = array('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 = array($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 = array('<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  {
91  $pattern = $this->insertNamespaceIntoRegularExpression(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SCAN_PATTERN_TEMPLATE_VIEWHELPERTAG, array('f'));
92  $source = '<f:crop attribute="Hallo">';
93  $expected = array(
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, array('f'));
108  $source = '<f:crop data-attribute="Hallo">';
109  $expected = array(
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 = array(
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 = array(
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 = array(
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  {
185  $pattern = \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SPLIT_PATTERN_TAGARGUMENTS;
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  {
196  $pattern = $this->insertNamespaceIntoRegularExpression(\TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SPLIT_PATTERN_SHORTHANDSYNTAX, array('f'));
197 
198  $source = 'some string{Object.bla}here as well';
199  $expected = array('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 = array('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 = array('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 = array('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 = array('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 
219  $source = 'abc {f:for(bla:"post{{")} def';
220  $expected = array('abc ', '{f:for(bla:"post{{")}', ' def');
221  $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)');
222 
223  $source = 'abc {f:for(param:"abc\\"abc")} def';
224  $expected = array('abc ', '{f:for(param:"abc\\"abc")}', ' def');
225  $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)');
226  }
227 
232  {
233  $pattern = \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER;
234 
235  $source = 'f:for(each: bla)';
236  $expected = array(
237  0 => array(
238  0 => 'f:for(each: bla)',
239  1 => 'f',
240  'NamespaceIdentifier' => 'f',
241  2 => 'for',
242  'MethodIdentifier' => 'for',
243  3 => 'each: bla',
244  'ViewHelperArguments' => 'each: bla'
245  )
246  );
247  preg_match_all($pattern, $source, $matches, PREG_SET_ORDER);
248  $this->assertEquals($matches, $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER');
249 
250  $source = 'f:for(each: bla)->g:bla(a:"b\\"->(f:a()", cd: {a:b})';
251  $expected = array(
252  0 => array(
253  0 => 'f:for(each: bla)',
254  1 => 'f',
255  'NamespaceIdentifier' => 'f',
256  2 => 'for',
257  'MethodIdentifier' => 'for',
258  3 => 'each: bla',
259  'ViewHelperArguments' => 'each: bla'
260  ),
261  1 => array(
262  0 => 'g:bla(a:"b\\"->(f:a()", cd: {a:b})',
263  1 => 'g',
264  'NamespaceIdentifier' => 'g',
265  2 => 'bla',
266  'MethodIdentifier' => 'bla',
267  3 => 'a:"b\\"->(f:a()", cd: {a:b}',
268  'ViewHelperArguments' => 'a:"b\\"->(f:a()", cd: {a:b}'
269  )
270  );
271  preg_match_all($pattern, $source, $matches, PREG_SET_ORDER);
272  $this->assertEquals($matches, $expected, 'The SPLIT_PATTERN_SHORTHANDSYNTAX_VIEWHELPER');
273  }
274 
279  {
280  $pattern = \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SCAN_PATTERN_SHORTHANDSYNTAX_OBJECTACCESSORS;
281  $this->assertEquals(preg_match($pattern, '{object}'), 1, 'Object accessor not identified!');
282  $this->assertEquals(preg_match($pattern, '{oBject1}'), 1, 'Object accessor not identified if there is a number and capitals inside!');
283  $this->assertEquals(preg_match($pattern, '{object.recursive}'), 1, 'Object accessor not identified if there is a dot inside!');
284  $this->assertEquals(preg_match($pattern, '{object-with-dash.recursive_value}'), 1, 'Object accessor not identified if there is a _ or - inside!');
285  $this->assertEquals(preg_match($pattern, '{f:for()}'), 1, 'Object accessor not identified if it contains only of a ViewHelper.');
286  $this->assertEquals(preg_match($pattern, '{f:for()->f:for2()}'), 1, 'Object accessor not identified if it contains only of a ViewHelper (nested).');
287  $this->assertEquals(preg_match($pattern, '{abc->f:for()}'), 1, 'Object accessor not identified if there is a ViewHelper inside!');
288  $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!');
289  $this->assertEquals(preg_match($pattern, '{f:for(arg1:arg1value, arg2: "bla\\"blubb")}'), 1, 'Object accessor not identified if there is an argument inside!');
290  $this->assertEquals(preg_match($pattern, '{dash:value}'), 0, 'Object accessor identified, but was array!');
291  //$this->assertEquals(preg_match($pattern, '{}'), 0, 'Object accessor identified, and it was empty!');
292  }
293 
298  {
299  $pattern = \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SCAN_PATTERN_SHORTHANDSYNTAX_ARRAYS;
300  $this->assertEquals(preg_match($pattern, '{a:b}'), 1, 'Array syntax not identified!');
301  $this->assertEquals(preg_match($pattern, '{a:b, c : d}'), 1, 'Array syntax not identified in case there are multiple properties!');
302  $this->assertEquals(preg_match($pattern, '{a : 123}'), 1, 'Array syntax not identified when a number is passed as argument!');
303  $this->assertEquals(preg_match($pattern, '{a:"String"}'), 1, 'Array syntax not identified in case of a double quoted string!');
304  $this->assertEquals(preg_match($pattern, '{a:\'String\'}'), 1, 'Array syntax not identified in case of a single quoted string!');
305 
306  $expected = '{a:{bla:{x:z}, b: a}}';
307  preg_match($pattern, $expected, $match);
308  $this->assertEquals($match[0], $expected, 'If nested arrays appear, the string is not parsed correctly.');
309 
310  $expected = '{a:"{bla{{}"}';
311  preg_match($pattern, $expected, $match);
312  $this->assertEquals($match[0], $expected, 'If nested strings with {} inside appear, the string is not parsed correctly.');
313  }
314 
319  {
320  $pattern = \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SPLIT_PATTERN_SHORTHANDSYNTAX_ARRAY_PARTS;
321 
322  $source = '{a: b, e: {c:d, e:f}}';
323  preg_match_all($pattern, $source, $matches, PREG_SET_ORDER);
324 
325  $expected = array(
326  0 => array(
327  0 => 'a: b',
328  'ArrayPart' => 'a: b',
329  1 => 'a: b',
330  'Key' => 'a',
331  2 => 'a',
332  'QuotedString' => '',
333  3 => '',
334  'VariableIdentifier' => 'b',
335  4 => 'b'
336  ),
337  1 => array(
338  0 => 'e: {c:d, e:f}',
339  'ArrayPart' => 'e: {c:d, e:f}',
340  1 => 'e: {c:d, e:f}',
341  'Key' => 'e',
342  2 => 'e',
343  'QuotedString' => '',
344  3 => '',
345  'VariableIdentifier' => '',
346  4 => '',
347  'Number' => '',
348  5 => '',
349  'Subarray' => 'c:d, e:f',
350  6 => 'c:d, e:f'
351  )
352  );
353  $this->assertEquals($matches, $expected, 'The regular expression splitting the array apart does not work!');
354  }
355 
361  public function testSCAN_PATTERN_CDATA()
362  {
363  $pattern = \TYPO3\CMS\Fluid\Core\Parser\TemplateParser::$SCAN_PATTERN_CDATA;
364  $this->assertEquals(preg_match($pattern, '<!-- Test -->'), 0, 'The SCAN_PATTERN_CDATA matches a comment, but it should not.');
365  $this->assertEquals(preg_match($pattern, '<![CDATA[This is some ]]>'), 1, 'The SCAN_PATTERN_CDATA does not match a simple CDATA string.');
366  $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..');
367  }
368 
376  protected function insertNamespaceIntoRegularExpression($regularExpression, $namespace)
377  {
378  return str_replace('NAMESPACE', implode('|', $namespace), $regularExpression);
379  }
380 }