‪TYPO3CMS  ‪main
StorageRepositoryTest.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;
36 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
37 
38 final class ‪StorageRepositoryTest extends FunctionalTestCase
39 {
40  protected function ‪tearDown(): void
41  {
43  mkdir(‪Environment::getPublicPath() . '/fileadmin');
44  ‪GeneralUtility::rmdir(‪Environment::getPublicPath() . '/typo3temp/assets/_processed_', true);
45  parent::tearDown();
46  }
47 
48  public static function ‪bestStorageIsResolvedDataProvider(): iterable
49  {
50  // `{public}` will be replaced by public project path (not having trailing slash)
51  // double slashes `//` are used on purpose for given file identifiers
52 
53  // legacy storage
54  yield ['/favicon.ico', '0:/favicon.ico'];
55  yield ['/favicon.ico', '0:/favicon.ico'];
56 
57  yield ['favicon.ico', '0:/favicon.ico'];
58  yield ['{public}//favicon.ico', '0:/favicon.ico'];
59  yield ['{public}/favicon.ico', '0:/favicon.ico'];
60 
61  // using storages with relative path
62  yield ['/fileadmin/img.png', '1:/img.png'];
63  yield ['fileadmin/img.png', '1:/img.png'];
64  yield ['/fileadmin/images/img.png', '1:/images/img.png'];
65  yield ['fileadmin/images/img.png', '1:/images/img.png'];
66  yield ['/documents/doc.pdf', '2:/doc.pdf'];
67  yield ['documents/doc.pdf', '2:/doc.pdf'];
68  yield ['/fileadmin/nested/images/img.png', '3:/images/img.png'];
69  yield ['fileadmin/nested/images/img.png', '3:/images/img.png'];
70 
71  yield ['{public}//fileadmin/img.png', '1:/img.png'];
72  yield ['{public}/fileadmin/img.png', '1:/img.png'];
73  yield ['{public}//fileadmin/images/img.png', '1:/images/img.png'];
74  yield ['{public}/fileadmin/images/img.png', '1:/images/img.png'];
75  yield ['{public}//documents/doc.pdf', '2:/doc.pdf'];
76  yield ['{public}/documents/doc.pdf', '2:/doc.pdf'];
77  yield ['{public}//fileadmin/nested/images/img.png', '3:/images/img.png'];
78  yield ['{public}/fileadmin/nested/images/img.png', '3:/images/img.png'];
79 
80  // using storages with absolute path
81  yield ['/files/img.png', '4:/img.png'];
82  yield ['files/img.png', '4:/img.png'];
83  yield ['/files/images/img.png', '4:/images/img.png'];
84  yield ['files/images/img.png', '4:/images/img.png'];
85  yield ['/docs/doc.pdf', '5:/doc.pdf'];
86  yield ['docs/doc.pdf', '5:/doc.pdf'];
87  yield ['/files/nested/images/img.png', '6:/images/img.png'];
88  yield ['files/nested/images/img.png', '6:/images/img.png'];
89 
90  yield ['{public}//files/img.png', '4:/img.png'];
91  yield ['{public}/files/img.png', '4:/img.png'];
92  yield ['{public}//files/images/img.png', '4:/images/img.png'];
93  yield ['{public}/files/images/img.png', '4:/images/img.png'];
94  yield ['{public}//docs/doc.pdf', '5:/doc.pdf'];
95  yield ['{public}/docs/doc.pdf', '5:/doc.pdf'];
96  yield ['{public}//files/nested/images/img.png', '6:/images/img.png'];
97  yield ['{public}/files/nested/images/img.png', '6:/images/img.png'];
98  }
99 
100  #[DataProvider('bestStorageIsResolvedDataProvider')]
101  #[Test]
102  public function ‪bestStorageIsResolved(string $sourceIdentifier, string $expectedCombinedIdentifier): void
103  {
104  $subject = GeneralUtility::makeInstance(StorageRepository::class);
105  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
106  $this->setUpBackendUser(1);
107  $publicPath = ‪Environment::getPublicPath();
108  $prefixDelegate = static function (string $value) use ($publicPath): string {
109  return $publicPath . '/' . $value;
110  };
111  // array indexes are not relevant here, but are those expected to be used as storage UID (`1:/file.png`)
112  // @todo it is possible to create ambiguous storages, e.g. `fileadmin/` AND `/fileadmin/`
113  $relativeNames = [1 => 'fileadmin/', 2 => 'documents/', 3 => 'fileadmin/nested/'];
114  // @todo: All these directories must exist. This is because createLocalStorage() calls testCaseSensitivity()
115  // which creates a file in each directory without checking if the directory does exist. Arguably, this
116  // should be handled in testCaseSensitivity(). For now, we create the directories in question and
117  // suppress errors so only the first test creates them and subsequent tests don't emit a warning here.
118  @mkdir($this->instancePath . '/documents');
119  @mkdir($this->instancePath . '/fileadmin/nested');
120  $absoluteNames = array_map($prefixDelegate, [4 => 'files/', 5 => 'docs/', 6 => 'files/nested']);
121  @mkdir($this->instancePath . '/files');
122  @mkdir($this->instancePath . '/docs');
123  @mkdir($this->instancePath . '/files/nested');
124  foreach ($relativeNames as $relativeName) {
125  $subject->createLocalStorage('rel:' . $relativeName, $relativeName, 'relative');
126  }
127  foreach ($absoluteNames as $absoluteName) {
128  $subject->createLocalStorage('abs:' . $absoluteName, $absoluteName, 'absolute');
129  }
130  $sourceIdentifier = str_replace('{public}', ‪Environment::getPublicPath(), $sourceIdentifier);
131  $storage = $subject->getStorageObject(0, [], $sourceIdentifier);
132  $combinedIdentifier = sprintf('%d:%s', $storage->getUid(), $sourceIdentifier);
133  self::assertSame(
134  $expectedCombinedIdentifier,
135  $combinedIdentifier,
136  sprintf('Given identifier "%s"', $sourceIdentifier)
137  );
138  }
139 
140  #[Test]
141  public function ‪getNestedProcessingFolderTest(): void
142  {
143  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
144  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
145  $this->setUpBackendUser(1);
146  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
147  $subject->setEvaluatePermissions(false);
148  mkdir(‪Environment::getPublicPath() . '/fileadmin/_processed_');
149  mkdir(‪Environment::getPublicPath() . '/fileadmin/aDirectory');
150  mkdir(‪Environment::getPublicPath() . '/typo3temp/assets/_processed_');
151  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/aDirectory/bar.txt', 'myData');
152  $subject->addFileMount('/aDirectory/', ['read_only' => false]);
153  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/aDirectory/bar.txt');
154  $rootProcessingFolder = $subject->getProcessingFolder();
155  $processingFolder = $subject->getProcessingFolder($file);
156  self::assertInstanceOf(Folder::class, $processingFolder);
157  self::assertNotEquals($rootProcessingFolder, $processingFolder);
158  for ($i = ‪ResourceStorage::PROCESSING_FOLDER_LEVELS; $i > 0; $i--) {
159  $processingFolder = $processingFolder->getParentFolder();
160  }
161  self::assertEquals($rootProcessingFolder, $processingFolder);
162  }
163 
164  public static function ‪isWithinFileMountBoundariesDataProvider(): array
165  {
166  return [
167  'Access to file in ro file mount denied for write request' => [
168  'targetDirectory' => 'fooBaz',
169  'fileMountFolder' => 'fooBaz',
170  'isFileMountReadOnly' => true,
171  'checkWriteAccess' => true,
172  'expectedResult' => false,
173  ],
174  'Access to file in ro file mount allowed for read request' => [
175  'targetDirectory' => 'fooBaz',
176  'fileMountFolder' => 'fooBaz',
177  'isFileMountReadOnly' => true,
178  'checkWriteAccess' => false,
179  'expectedResult' => true,
180  ],
181  'Access to file in rw file mount allowed for write request' => [
182  'targetDirectory' => 'fooBaz',
183  'fileMountFolder' => 'fooBaz',
184  'isFileMountReadOnly' => false,
185  'checkWriteAccess' => true,
186  'expectedResult' => true,
187  ],
188  'Access to file in rw file mount allowed for read request' => [
189  'targetDirectory' => 'fooBaz',
190  'fileMountFolder' => 'fooBaz',
191  'isFileMountReadOnly' => false,
192  'checkWriteAccess' => false,
193  'expectedResult' => true,
194  ],
195  'Access to file not in file mount denied for write request' => [
196  'targetDirectory' => 'fooBaz',
197  'fileMountFolder' => 'barBaz',
198  'isFileMountReadOnly' => false,
199  'checkWriteAccess' => true,
200  'expectedResult' => false,
201  ],
202  'Access to file not in file mount denied for read request' => [
203  'targetDirectory' => 'fooBaz',
204  'fileMountFolder' => 'barBaz',
205  'isFileMountReadOnly' => false,
206  'checkWriteAccess' => false,
207  'expectedResult' => false,
208  ],
209  ];
210  }
211 
212  #[DataProvider('isWithinFileMountBoundariesDataProvider')]
213  #[Test]
214  public function ‪isWithinFileMountBoundariesRespectsReadOnlyFileMounts(string $targetDirectory, string $fileMountFolder, bool $isFileMountReadOnly, bool $checkWriteAccess, bool $expectedResult): void
215  {
216  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
217  $fileName = 'bar.txt';
218  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
219  $this->setUpBackendUser(1);
220  mkdir(‪Environment::getPublicPath() . '/fileadmin/_processed_');
221  mkdir(‪Environment::getPublicPath() . '/fileadmin/' . $targetDirectory);
222  if ($fileMountFolder !== $targetDirectory) {
223  mkdir(‪Environment::getPublicPath() . '/fileadmin/' . $fileMountFolder);
224  }
225  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/' . $targetDirectory . '/' . $fileName, 'myData');
226  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/' . $targetDirectory . '/' . $fileName);
227  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
228  $subject->setEvaluatePermissions(true);
229  // read_only = true -> no write access for user, so checking for second argument true should assert false
230  $subject->addFileMount('/' . $fileMountFolder . '/', ['read_only' => $isFileMountReadOnly]);
231  self::assertSame($expectedResult, $subject->isWithinFileMountBoundaries($file, $checkWriteAccess));
232  }
233 
234  #[Test]
235  public function ‪getProcessingRootFolderTest(): void
236  {
237  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
238  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
239  $this->setUpBackendUser(1);
240  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
241  $processingFolder = $subject->getProcessingFolder();
242  self::assertInstanceOf(Folder::class, $processingFolder);
243  }
244 
245  #[Test]
247  {
248  $folderIdentifier = ‪StringUtility::getUniqueId();
249  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
250  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
251  $this->setUpBackendUser(1);
252  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
253  $folder = new ‪Folder($subject, '/foo/' . $folderIdentifier . '/', $folderIdentifier);
254  $role = $subject->getRole($folder);
255  self::assertSame(‪FolderInterface::ROLE_DEFAULT, $role);
256  }
257 
258  #[Test]
260  {
261  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
262  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
263  $this->setUpBackendUser(1);
264  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
265  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
266  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt', 'myData');
267  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/foo/bar.txt');
268  $this->expectException(\InvalidArgumentException::class);
269  $this->expectExceptionCode(1325842622);
270  $subject->replaceFile($file, ‪Environment::getPublicPath() . '/' . ‪StringUtility::getUniqueId());
271  }
272 
273  #[Test]
275  {
276  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
277  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
278  $this->setUpBackendUser(1);
279  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
280  $this->expectException(\InvalidArgumentException::class);
281  $this->expectExceptionCode(1325689164);
282  $subject->createFolder('newFolder', new ‪Folder($subject, '/foo/', 'foo'));
283  }
284 
285  #[Test]
287  {
288  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
289  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
290  $this->setUpBackendUser(1);
291  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
292  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
293  mkdir(‪Environment::getPublicPath() . '/fileadmin/_recycler_');
294  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt', 'myData');
295  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/foo/bar.txt');
296  $subject->deleteFile($file);
297  self::assertFileExists(‪Environment::getPublicPath() . '/fileadmin/_recycler_/bar.txt');
298  self::assertFileDoesNotExist(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt');
299  }
300 
301  #[Test]
303  {
304  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
305  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
306  $this->setUpBackendUser(1);
307  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
308  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
309  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt', 'myData');
310  $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/foo/bar.txt');
311  $subject->deleteFile($file);
312  self::assertFileDoesNotExist(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt');
313  }
314 
315  public static function ‪searchFilesFindsFilesInFolderDataProvider(): array
316  {
317  return [
318  'Finds foo recursive by name' => [
319  'foo',
320  '/bar/',
321  true,
322  [],
323  [
324  '/bar/bla/foo.txt',
325  ],
326  ],
327  'Finds foo not recursive by name' => [
328  'foo',
329  '/bar/bla/',
330  false,
331  [],
332  [
333  '/bar/bla/foo.txt',
334  ],
335  ],
336  'Finds nothing when not recursive for top level folder' => [
337  'foo',
338  '/bar/',
339  false,
340  [],
341  [],
342  ],
343  'Finds foo by description' => [
344  'fodescrip',
345  '/bar/',
346  true,
347  [],
348  [
349  '/bar/bla/foo.txt',
350  ],
351  ],
352  'Finds foo by translated description' => [
353  'fotranslated',
354  '/bar/',
355  true,
356  [],
357  [
358  '/bar/bla/foo.txt',
359  ],
360  ],
361  'Finds blupp by name' => [
362  'blupp',
363  '/bar/',
364  false,
365  [],
366  [
367  '/bar/blupp.txt',
368  ],
369  ],
370  'Finds only blupp by title for non recursive' => [
371  'title',
372  '/bar/',
373  false,
374  [],
375  [
376  '/bar/blupp.txt',
377  ],
378  ],
379  'Finds foo and blupp by title for recursive' => [
380  'title',
381  '/bar/',
382  true,
383  [],
384  [
385  '/bar/blupp.txt',
386  '/bar/bla/foo.txt',
387  ],
388  ],
389  'Finds foo, baz and blupp with no folder' => [
390  'title',
391  null,
392  true,
393  [],
394  [
395  '/baz/bla/baz.txt',
396  '/bar/blupp.txt',
397  '/bar/bla/foo.txt',
398  ],
399  ],
400  'Finds nothing for not existing' => [
401  'baz',
402  '/bar/',
403  true,
404  [],
405  [],
406  ],
407  'Finds nothing in root, when not recursive' => [
408  'title',
409  '/',
410  false,
411  [],
412  [],
413  ],
414  'Finds nothing, when not recursive and no folder given' => [
415  'title',
416  null,
417  false,
418  [],
419  [],
420  ],
421  'Filter is applied to result' => [
422  'title',
423  null,
424  true,
425  [
426  static function ($itemName) {
427  return str_contains($itemName, 'blupp') ? true : -1;
428  },
429  ],
430  [
431  '/bar/blupp.txt',
432  ],
433  ],
434  ];
435  }
436 
440  #[DataProvider('searchFilesFindsFilesInFolderDataProvider')]
441  #[Test]
442  public function ‪searchFilesFindsFilesInFolder(string $searchTerm, ?string $searchFolder, bool $recursive, array $filters, array $expectedIdentifiers): void
443  {
444  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
445  $this->importCSVDataSet(__DIR__ . '/Fixtures/FileSearch.csv');
446  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
447  $this->setUpBackendUser(1);
448  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
449  $subject->setFileAndFolderNameFilters($filters);
450  mkdir(‪Environment::getPublicPath() . '/fileadmin/bar');
451  mkdir(‪Environment::getPublicPath() . '/fileadmin/bar/bla');
452  mkdir(‪Environment::getPublicPath() . '/fileadmin/baz');
453  mkdir(‪Environment::getPublicPath() . '/fileadmin/baz/bla');
454  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/bar/bla/foo.txt', 'myData');
455  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/baz/bla/baz.txt', 'myData');
456  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/bar/blupp.txt', 'myData');
457  $folder = $searchFolder ? GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:' . $searchFolder) : null;
458  $search = ‪FileSearchDemand::createForSearchTerm($searchTerm);
459  if ($recursive) {
460  $search = $search->withRecursive();
461  }
462  $result = $subject->searchFiles($search, $folder);
463  $expectedFiles = array_map([$subject, 'getFile'], $expectedIdentifiers);
464  self::assertSame($expectedFiles, iterator_to_array($result));
465  // Check if search also works for non-hierarchical storages/drivers
466  // This is a hack, as capabilities is not settable from the outside
467  $objectReflection = new \ReflectionObject($subject);
468  $property = $objectReflection->getProperty('capabilities');
469  $property->setValue($subject, $subject->getCapabilities()->addCapabilities(‪Capabilities::CAPABILITY_BROWSABLE, ‪Capabilities::CAPABILITY_PUBLIC, ‪Capabilities::CAPABILITY_WRITABLE));
470  $result = $subject->searchFiles($search, $folder);
471  $expectedFiles = array_map([$subject, 'getFile'], $expectedIdentifiers);
472  self::assertSame($expectedFiles, iterator_to_array($result));
473  }
474 
475  #[Test]
477  {
478  $conflictMode = DuplicationBehavior::CANCEL;
479  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
480  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
481  $this->setUpBackendUser(1);
482  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
483  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
484  $folderToCopy = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/foo');
485  $targetParentFolder = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/');
486  $this->expectException(InvalidTargetFolderException::class);
487  $this->expectExceptionCode(1422723059);
488  $subject->copyFolder($folderToCopy, $targetParentFolder, null, $conflictMode);
489  }
490 
491  #[Test]
493  {
494  $conflictMode = DuplicationBehavior::RENAME;
495  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
496  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
497  $this->setUpBackendUser(1);
498  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
499  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
500  $folderToCopy = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/foo');
501  $targetParentFolder = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/');
502  $subject->copyFolder($folderToCopy, $targetParentFolder, null, $conflictMode);
503  $newFolder = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/foo_01');
504  self::assertInstanceOf(Folder::class, $newFolder);
505  }
506 
507  #[Test]
509  {
510  $conflictMode = DuplicationBehavior::CANCEL;
511  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
512  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
513  $this->setUpBackendUser(1);
514  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
515  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt', 'Temp file 1');
516  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/bar.txt', 'Temp file 2');
517  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
518  $fileToCopy = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/foo/bar.txt');
519  $targetParentFolder = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/');
520  $this->expectException(ExistingTargetFileNameException::class);
521  $this->expectExceptionCode(1320291064);
522  $subject->copyFile($fileToCopy, $targetParentFolder, null, $conflictMode);
523  }
524 
525  #[Test]
527  {
528  $conflictMode = DuplicationBehavior::RENAME;
529  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
530  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
531  $this->setUpBackendUser(1);
532  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
533  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt', 'Temp file 1');
534  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/bar.txt', 'Temp file 2');
535  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
536  $fileToCopy = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/foo/bar.txt');
537  $targetParentFolder = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/');
538  $subject->copyFile($fileToCopy, $targetParentFolder, null, $conflictMode);
539  $newFile = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/bar_01.txt');
540  self::assertInstanceOf(File::class, $newFile);
541  }
542 
543  #[Test]
544  public function ‪copyFileCopiesMetadata(): void
545  {
546  $this->importCSVDataSet(__DIR__ . '/../Fixtures/sys_file_storage.csv');
547  $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv');
548  $this->setUpBackendUser(1);
549  mkdir(‪Environment::getPublicPath() . '/fileadmin/foo');
550  file_put_contents(‪Environment::getPublicPath() . '/fileadmin/foo/bar.txt', 'Temp file');
551  $subject = GeneralUtility::makeInstance(StorageRepository::class)->findByUid(1);
552  $fileToCopyMetaData = [
553  'title' => 'Temp file title',
554  'description' => 'Temp file description',
555  ];
557  $fileToCopy = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier('1:/foo/bar.txt');
558  $fileToCopy->getMetaData()->add($fileToCopyMetaData);
559  $targetParentFolder = GeneralUtility::makeInstance(ResourceFactory::class)->getFolderObjectFromCombinedIdentifier('1:/');
561  $newFile = $subject->copyFile($fileToCopy, $targetParentFolder);
562  self::assertNotEquals($fileToCopy->getMetaData()->get()['file'], $newFile->getMetaData()->get()['file']);
563  self::assertNotEquals($fileToCopy->getMetaData()->get()['uid'], $newFile->getMetaData()->get()['uid']);
564  self::assertEquals($fileToCopyMetaData['title'], $newFile->getMetaData()->get()['title']);
565  self::assertEquals($fileToCopyMetaData['description'], $newFile->getMetaData()->get()['description']);
566  }
567 }
‪TYPO3\CMS\Core\Resource\Capabilities\CAPABILITY_PUBLIC
‪const CAPABILITY_PUBLIC
Definition: Capabilities.php:31
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest
Definition: StorageRepositoryTest.php:39
‪TYPO3\CMS\Core\Resource\ResourceStorage\PROCESSING_FOLDER_LEVELS
‪const PROCESSING_FOLDER_LEVELS
Definition: ResourceStorage.php:211
‪TYPO3\CMS\Core\Tests\Functional\Resource
Definition: DefaultUploadFolderResolverTest.php:18
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\bestStorageIsResolved
‪bestStorageIsResolved(string $sourceIdentifier, string $expectedCombinedIdentifier)
Definition: StorageRepositoryTest.php:102
‪TYPO3\CMS\Core\Resource\Capabilities
Definition: Capabilities.php:23
‪TYPO3\CMS\Core\Resource\FolderInterface\ROLE_DEFAULT
‪const ROLE_DEFAULT
Definition: FolderInterface.php:28
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static getPublicPath()
Definition: Environment.php:187
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\copyFileCopiesMetadata
‪copyFileCopiesMetadata()
Definition: StorageRepositoryTest.php:544
‪TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException
Definition: ExistingTargetFileNameException.php:23
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\tearDown
‪tearDown()
Definition: StorageRepositoryTest.php:40
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\replaceFileFailsIfLocalFileDoesNotExist
‪replaceFileFailsIfLocalFileDoesNotExist()
Definition: StorageRepositoryTest.php:259
‪TYPO3\CMS\Core\Resource\Exception\InvalidTargetFolderException
Definition: InvalidTargetFolderException.php:23
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\isWithinFileMountBoundariesRespectsReadOnlyFileMounts
‪isWithinFileMountBoundariesRespectsReadOnlyFileMounts(string $targetDirectory, string $fileMountFolder, bool $isFileMountReadOnly, bool $checkWriteAccess, bool $expectedResult)
Definition: StorageRepositoryTest.php:214
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\getProcessingRootFolderTest
‪getProcessingRootFolderTest()
Definition: StorageRepositoryTest.php:235
‪TYPO3\CMS\Core\Resource\Capabilities\CAPABILITY_BROWSABLE
‪const CAPABILITY_BROWSABLE
Definition: Capabilities.php:27
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\createFolderThrowsExceptionIfParentFolderDoesNotExist
‪createFolderThrowsExceptionIfParentFolderDoesNotExist()
Definition: StorageRepositoryTest.php:274
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\searchFilesFindsFilesInFolderDataProvider
‪static searchFilesFindsFilesInFolderDataProvider()
Definition: StorageRepositoryTest.php:315
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\getNestedProcessingFolderTest
‪getNestedProcessingFolderTest()
Definition: StorageRepositoryTest.php:141
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\copyFileGeneratesNewFileNameWhenFileAlreadyExistsInTargetFolderAndConflictModeIsRename
‪copyFileGeneratesNewFileNameWhenFileAlreadyExistsInTargetFolderAndConflictModeIsRename()
Definition: StorageRepositoryTest.php:526
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\searchFilesFindsFilesInFolder
‪searchFilesFindsFilesInFolder(string $searchTerm, ?string $searchFolder, bool $recursive, array $filters, array $expectedIdentifiers)
Definition: StorageRepositoryTest.php:442
‪TYPO3\CMS\Core\Resource\Search\FileSearchDemand
Definition: FileSearchDemand.php:26
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:38
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:42
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\copyFolderGeneratesNewFolderNameWhenFolderAlreadyExistsInTargetFolderAndConflictModeIsRename
‪copyFolderGeneratesNewFolderNameWhenFolderAlreadyExistsInTargetFolderAndConflictModeIsRename()
Definition: StorageRepositoryTest.php:492
‪TYPO3\CMS\Core\Resource\StorageRepository
Definition: StorageRepository.php:38
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:26
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\copyFileThrowsErrorWhenFileWithSameNameAlreadyExistsInTargetFolderAndConflictModeIsCancel
‪copyFileThrowsErrorWhenFileWithSameNameAlreadyExistsInTargetFolderAndConflictModeIsCancel()
Definition: StorageRepositoryTest.php:508
‪TYPO3\CMS\Core\Utility\GeneralUtility\rmdir
‪static bool rmdir(string $path, bool $removeNonEmpty=false)
Definition: GeneralUtility.php:1697
‪TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior
‪DuplicationBehavior
Definition: DuplicationBehavior.php:28
‪TYPO3\CMS\Core\Resource\Capabilities\CAPABILITY_WRITABLE
‪const CAPABILITY_WRITABLE
Definition: Capabilities.php:36
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\bestStorageIsResolvedDataProvider
‪static bestStorageIsResolvedDataProvider()
Definition: StorageRepositoryTest.php:48
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\copyFolderThrowsErrorWhenFolderAlreadyExistsInTargetFolderAndConflictModeIsCancel
‪copyFolderThrowsErrorWhenFolderAlreadyExistsInTargetFolderAndConflictModeIsCancel()
Definition: StorageRepositoryTest.php:476
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:128
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Core\Resource\FolderInterface
Definition: FolderInterface.php:24
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\deleteFileUnlinksFileIfNoRecyclerFolderAvailable
‪deleteFileUnlinksFileIfNoRecyclerFolderAvailable()
Definition: StorageRepositoryTest.php:302
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Resource\Search\FileSearchDemand\createForSearchTerm
‪static createForSearchTerm(string $searchTerm)
Definition: FileSearchDemand.php:70
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\getRoleReturnsDefaultForRegularFolders
‪getRoleReturnsDefaultForRegularFolders()
Definition: StorageRepositoryTest.php:246
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\deleteFileMovesFileToRecyclerFolderIfAvailable
‪deleteFileMovesFileToRecyclerFolderIfAvailable()
Definition: StorageRepositoryTest.php:286
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static getUniqueId(string $prefix='')
Definition: StringUtility.php:57
‪TYPO3\CMS\Core\Tests\Functional\Resource\StorageRepositoryTest\isWithinFileMountBoundariesDataProvider
‪static isWithinFileMountBoundariesDataProvider()
Definition: StorageRepositoryTest.php:164