‪TYPO3CMS  ‪main
LegacyLinkNotationConverterTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use PHPUnit\Framework\Attributes\DataProvider;
21 use PHPUnit\Framework\Attributes\Test;
31 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
32 
33 final class ‪LegacyLinkNotationConverterTest extends UnitTestCase
34 {
35  protected bool ‪$resetSingletonInstances = true;
36 
40  public static function ‪resolveParametersForNonFilesDataProvider(): array
41  {
42  return [
43  'simple page - old style' => [
44  // original input value
45  '13',
46  // split values
47  [
48  'type' => ‪LinkService::TYPE_PAGE,
49  'pageuid' => 13,
50  ],
51  // final unified URN
52  't3://page?uid=13',
53  ],
54  'simple page - old style with appended comma' => [
55  '13,',
56  [
57  'type' => ‪LinkService::TYPE_PAGE,
58  'pageuid' => 13,
59  ],
60  't3://page?uid=13',
61  ],
62  'page with type - old style' => [
63  '13,31',
64  [
65  'type' => ‪LinkService::TYPE_PAGE,
66  'pageuid' => 13,
67  'pagetype' => '31',
68  ],
69  't3://page?uid=13&type=31',
70  ],
71  'page with type and fragment - old style' => [
72  '13,31#uncool',
73  [
74  'type' => ‪LinkService::TYPE_PAGE,
75  'pageuid' => 13,
76  'pagetype' => '31',
77  'fragment' => 'uncool',
78  ],
79  't3://page?uid=13&type=31#uncool',
80  ],
81  'page with type and parameters and fragment - old style' => [
82  '13,31?unbel=ievable#uncool',
83  [
84  'type' => ‪LinkService::TYPE_PAGE,
85  'pageuid' => 13,
86  'pagetype' => '31',
87  'parameters' => 'unbel=ievable',
88  'fragment' => 'uncool',
89  ],
90  't3://page?uid=13&type=31&unbel=ievable#uncool',
91  ],
92  'page with type and parameters as another parameter and fragment - old style' => [
93  '13,31,&unbel=ievable&but=possibly#uncool',
94  [
95  'type' => ‪LinkService::TYPE_PAGE,
96  'pageuid' => 13,
97  'pagetype' => '31',
98  'parameters' => 'unbel=ievable&but=possibly',
99  'fragment' => 'uncool',
100  ],
101  't3://page?uid=13&type=31&unbel=ievable&but=possibly#uncool',
102  ],
103  'page with type and parameters as third parameter and explicitly allow type=0' => [
104  '1,0,&param=2',
105  [
106  'type' => ‪LinkService::TYPE_PAGE,
107  'pageuid' => 1,
108  'pagetype' => '0',
109  'parameters' => 'param=2',
110  ],
111  't3://page?uid=1&type=0&param=2',
112  ],
113  'record of table - old 2-part identifier' => [
114  'record:tx_myext_entity:456',
115  [
116  'type' => ‪LinkService::TYPE_RECORD,
117  'identifier' => 'tx_myext_entity',
118  'table' => 'tx_myext_entity',
119  'uid' => 456,
120  'url' => 'record:tx_myext_entity:456',
121  'value' => 'tx_myext_entity:456',
122  ],
123  't3://record?identifier=tx_myext_entity&uid=456',
124  ],
125  'record of table - old 3-part identifier' => [
126  'record:usage1:tx_myext_entity:456',
127  [
128  'type' => ‪LinkService::TYPE_RECORD,
129  'identifier' => 'usage1',
130  'table' => 'tx_myext_entity',
131  'uid' => 456,
132  'url' => 'record:usage1:tx_myext_entity:456',
133  'value' => 'usage1:tx_myext_entity:456',
134  ],
135  't3://record?identifier=usage1&uid=456',
136  ],
137  ];
138  }
139 
140  #[DataProvider('resolveParametersForNonFilesDataProvider')]
141  #[Test]
142  public function ‪resolveReturnsSplitParameters(string $input, array $expected): void
143  {
144  $subject = new ‪LegacyLinkNotationConverter();
145  ksort($expected);
146  $result = $subject->resolve($input);
147  ksort($result);
148 
149  self::assertSame($expected, $result);
150  }
151 
155  #[DataProvider('resolveParametersForNonFilesDataProvider')]
156  #[Test]
157  public function ‪splitParametersToUnifiedIdentifier(string $input, array $parameters, string $expected): void
158  {
159  $subject = new ‪LinkService();
160  self::assertEquals($expected, $subject->asString($parameters));
161  }
162 
173  public static function ‪resolveParametersForFilesDataProvider(): array
174  {
175  return [
176  'file without FAL - VERY old style' => [
177  'fileadmin/on/steroids.png',
178  [
179  'type' => ‪LinkService::TYPE_FILE,
180  'file' => 'fileadmin/on/steroids.png',
181  ],
182  't3://file?identifier=fileadmin%2Fon%2Fsteroids.png',
183  ],
184  'file without FAL and anchor - VERY old style' => [
185  'fileadmin/on/steroids.png#page-23',
186  [
187  'type' => ‪LinkService::TYPE_FILE,
188  'file' => 'fileadmin/on/steroids.png',
189  'fragment' => 'page-23',
190  ],
191  't3://file?identifier=fileadmin%2Fon%2Fsteroids.png#page-23',
192  ],
193  'file without FAL with file prefix - VERY old style' => [
194  'file:fileadmin/on/steroids.png',
195  [
196  'type' => ‪LinkService::TYPE_FILE,
197  'file' => 'fileadmin/on/steroids.png',
198  ],
199  't3://file?identifier=fileadmin%2Fon%2Fsteroids.png',
200  ],
201  'file without FAL with file prefix and anchor - VERY old style' => [
202  'file:fileadmin/on/steroids.png#page-13',
203  [
204  'type' => ‪LinkService::TYPE_FILE,
205  'file' => 'fileadmin/on/steroids.png',
206  'fragment' => 'page-13',
207  ],
208  't3://file?identifier=fileadmin%2Fon%2Fsteroids.png#page-13',
209  ],
210  'file with FAL uid - old style' => [
211  'file:23',
212  [
213  'type' => ‪LinkService::TYPE_FILE,
214  'file' => '23',
215  ],
216  't3://file?uid=23',
217  ],
218  'file with FAL uid and anchor - old style' => [
219  'file:23#page-13',
220  [
221  'type' => ‪LinkService::TYPE_FILE,
222  'file' => '23',
223  'fragment' => 'page-13',
224  ],
225  't3://file?uid=23#page-13',
226  ],
227  'folder without FAL - VERY old style' => [
228  'fileadmin/myimages/',
229  [
230  'type' => ‪LinkService::TYPE_FOLDER,
231  'folder' => 'fileadmin/myimages/',
232  ],
233  't3://folder?storage=0&identifier=%2Ffileadmin%2Fmyimages%2F',
234  ],
235  'folder with combined identifier and file prefix (FAL) - old style' => [
236  'file:2:/myimages/',
237  [
238  'type' => ‪LinkService::TYPE_FOLDER,
239  'folder' => '2:/myimages/',
240  ],
241  't3://folder?storage=2&identifier=%2Fmyimages%2F',
242  ],
243  ];
244  }
245 
249  #[DataProvider('resolveParametersForFilesDataProvider')]
250  #[Test]
251  public function ‪resolveFileReferencesToSplitParameters(string $input, array $expected): void
252  {
253  $storage = $this->getMockBuilder(ResourceStorage::class)
254  ->disableOriginalConstructor()
255  ->getMock();
256 
257  $factory = $this->getMockBuilder(ResourceFactory::class)
258  ->disableOriginalConstructor()
259  ->getMock();
260 
261  // fake methods to return proper objects
262  if ($expected['type'] === ‪LinkService::TYPE_FILE) {
263  $fileObject = new ‪File(['identifier' => $expected['file']], $storage);
264  $factory->method('getFileObjectFromCombinedIdentifier')->with($expected['file'])
265  ->willReturn($fileObject);
266  $factory->method('retrieveFileOrFolderObject')->with($expected['file'])
267  ->willReturn($fileObject);
268  $factory->method('getFileObject')->with($expected['file'])->willReturn($fileObject);
269  $expected['file'] = $fileObject;
270  }
271  // fake methods to return proper objects
272  if ($expected['type'] === ‪LinkService::TYPE_FOLDER) {
273  if (str_starts_with($expected['folder'], 'file:')) {
274  $expected['folder'] = substr($expected['folder'], 5);
275  }
276  $folderObject = new ‪Folder($storage, $expected['folder'], $expected['folder']);
277  $factory->method('retrieveFileOrFolderObject')->with($expected['folder'])
278  ->willReturn($folderObject);
279  $factory->method('getFolderObjectFromCombinedIdentifier')->with($expected['folder'])
280  ->willReturn($folderObject);
281  $expected['folder'] = $folderObject;
282  }
283  GeneralUtility::setSingletonInstance(ResourceFactory::class, $factory);
284 
285  $subject = new ‪LegacyLinkNotationConverter();
286 
287  self::assertEquals($expected, $subject->resolve($input));
288  }
289 
296  #[DataProvider('resolveParametersForFilesDataProvider')]
297  #[Test]
298  public function ‪splitParametersToUnifiedIdentifierForFiles(string $input, array $parameters, string $expected): void
299  {
300  // fake methods to return proper objects
301  if ($parameters['type'] === ‪LinkService::TYPE_FILE) {
302  $fileObject = $this->getMockBuilder(File::class)
303  ->onlyMethods(['getUid', 'getIdentifier'])
304  ->disableOriginalConstructor()
305  ->getMock();
306  ‪$uid = 0;
307  if (‪MathUtility::canBeInterpretedAsInteger($parameters['file'])) {
308  ‪$uid = $parameters['file'];
309  }
310  $fileObject->expects(self::once())->method('getUid')->willReturn(‪$uid);
311  $fileObject->method('getIdentifier')->willReturn($parameters['file']);
312  $parameters['file'] = $fileObject;
313  }
314  // fake methods to return proper objects
315  if ($parameters['type'] === ‪LinkService::TYPE_FOLDER) {
316  if (str_starts_with($parameters['folder'], 'file:')) {
317  $parameters['folder'] = substr($parameters['folder'], 5);
318  }
319  // fake "0" storage
320  if (!‪MathUtility::canBeInterpretedAsInteger($parameters['folder'][0])) {
321  $parameters['folder'] = '0:' . $parameters['folder'];
322  }
323  $folderObject = $this->getMockBuilder(Folder::class)
324  ->onlyMethods(['getCombinedIdentifier', 'getStorage', 'getIdentifier'])
325  ->disableOriginalConstructor()
326  ->getMock();
327  $folderObject->method('getCombinedIdentifier')->willReturn($parameters['folder']);
328  $folderData = explode(':', $parameters['folder']);
329  $storage = $this->getMockBuilder(ResourceStorage::class)
330  ->onlyMethods(['getUid'])
331  ->disableOriginalConstructor()
332  ->getMock();
333  $storage->method('getUid')->willReturn($folderData[0]);
334  $folderObject->method('getStorage')->willReturn($storage);
335  $folderObject->method('getIdentifier')->willReturn($folderData[1]);
336  $parameters['folder'] = $folderObject;
337  }
338 
339  $subject = new ‪LinkService();
340  self::assertEquals($expected, $subject->asString($parameters));
341  }
342 
344  {
345  return [
346  'URL encoded local' => [
347  'phar%3a//some-file.jpg',
348  ],
349  'URL encoded absolute' => [
350  'phar%3a///path/some-file.jpg',
351  ],
352  'not URL encoded local' => [
353  'phar://some-file.jpg',
354  ],
355  'not URL encoded absolute' => [
356  'phar:///path/some-file.jpg',
357  ],
358  ];
359  }
360 
361  #[DataProvider('resolveThrowExceptionWithPharReferencesDataProvider')]
362  #[Test]
363  public function ‪resolveThrowExceptionWithPharReferences(string $pharUrl): void
364  {
365  $this->expectException(\RuntimeException::class);
366  $this->expectExceptionCode(1530030673);
367  (new ‪LegacyLinkNotationConverter())->resolve($pharUrl);
368  }
369 }
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:38
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:42
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:26
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:128
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52