Completed
Push — master ( 9193e0...c22966 )
by Cedric
02:31
created

FlysystemDriver::extractFileInformation()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 23
ccs 0
cts 19
cp 0
rs 9.0856
cc 3
eloc 18
nc 4
nop 3
crap 12
1
<?php
2
3
namespace CedricZiel\FalFlysystem\Fal;
4
5
use League\Flysystem\Adapter\Local;
6
use League\Flysystem\AdapterInterface;
7
use League\Flysystem\Config;
8
use League\Flysystem\FilesystemInterface;
9
use TYPO3\CMS\Core\Resource\Driver\AbstractHierarchicalFilesystemDriver;
10
use TYPO3\CMS\Core\Resource\ResourceStorage;
11
use TYPO3\CMS\Core\Type\File\FileInfo;
12
use TYPO3\CMS\Core\Utility\GeneralUtility;
13
use TYPO3\CMS\Core\Utility\PathUtility;
14
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
15
16
/**
17
 * Class FlysystemDriver
18
 * @package CedricZiel\FalFlysystem\Fal
19
 */
20
abstract class FlysystemDriver extends AbstractHierarchicalFilesystemDriver
21
{
22
    /**
23
     * @var FilesystemInterface
24
     */
25
    protected $filesystem;
26
27
    /**
28
     * @var AdapterInterface
29
     */
30
    protected $adapter;
31
32
    /**
33
     * @var string
34
     */
35
    protected $entryPath;
36
37
    /**
38
     * FlysystemDriver constructor.
39
     * @param array $configuration
40
     */
41 36
    public function __construct(array $configuration = [])
42
    {
43 36
        parent::__construct($configuration);
44
        // The capabilities default of this driver. See CAPABILITY_* constants for possible values
45 36
        $this->capabilities =
46 12
            ResourceStorage::CAPABILITY_BROWSABLE
47 36
            | ResourceStorage::CAPABILITY_PUBLIC
48 36
            | ResourceStorage::CAPABILITY_WRITABLE;
49 36
    }
50
51
    /**
52
     * Processes the configuration for this driver.
53
     * @return void
54
     */
55
    public function processConfiguration()
56
    {
57
        $this->entryPath = $this->configuration['path'];
58
    }
59
60
    /**
61
     * Merges the capabilities merged by the user at the storage
62
     * configuration into the actual capabilities of the driver
63
     * and returns the result.
64
     *
65
     * @param int $capabilities
66
     * @return int
67
     */
68
    public function mergeConfigurationCapabilities($capabilities)
69
    {
70
        // TODO: Implement mergeConfigurationCapabilities() method.
71
    }
72
73
    /**
74
     * Returns the identifier of the root level folder of the storage.
75
     *
76
     * @return string
77
     */
78
    public function getRootLevelFolder()
79
    {
80
        return '/';
81
    }
82
83
    /**
84
     * Returns the identifier of the default folder new files should be put into.
85
     *
86
     * @return string
87
     */
88 3
    public function getDefaultFolder()
89
    {
90 3
        $identifier = '/user_upload/';
91 3
        $createFolder = !$this->folderExists($identifier);
92 3
        if (true === $createFolder) {
93 3
            $identifier = $this->createFolder('user_upload');
94 2
        }
95 3
        return $identifier;
96
    }
97
98
    /**
99
     * Checks if a folder exists.
100
     *
101
     * @param string $folderIdentifier
102
     * @return bool
103
     */
104 6
    public function folderExists($folderIdentifier)
105
    {
106 6
        if ('/' === $folderIdentifier) {
107
            return true;
108
        } else {
109 6
            return $this->filesystem->has('/' . $folderIdentifier);
110
        }
111
    }
112
113
    /**
114
     * Creates a folder, within a parent folder.
115
     * If no parent folder is given, a root level folder will be created
116
     *
117
     * @param string $newFolderName
118
     * @param string $parentFolderIdentifier
119
     * @param bool $recursive
120
     * @return string the Identifier of the new folder
121
     */
122 9
    public function createFolder($newFolderName, $parentFolderIdentifier = '', $recursive = false)
123
    {
124 9
        $parentFolderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($parentFolderIdentifier);
125 9
        $newFolderName = trim($newFolderName, '/');
126 9
        if (false === $recursive) {
127 9
            $newFolderName = $this->sanitizeFileName($newFolderName);
128 9
            $newIdentifier = $parentFolderIdentifier . $newFolderName . '/';
129 9
            $this->filesystem->createDir($newIdentifier);
130 6
        } else {
131
            $parts = GeneralUtility::trimExplode('/', $newFolderName);
132
            $parts = array_map(array($this, 'sanitizeFileName'), $parts);
133
            $newFolderName = implode('/', $parts);
134
            $newIdentifier = $parentFolderIdentifier . $newFolderName . '/';
135
        }
136 9
        return $newIdentifier;
137
    }
138
139
    /**
140
     * Returns the public URL to a file.
141
     * Either fully qualified URL or relative to PATH_site (rawurlencoded).
142
     *
143
     * @param string $identifier
144
     * @return string
145
     */
146
    public function getPublicUrl($identifier)
147
    {
148
        // TODO: Implement getPublicUrl() method.
149
        DebuggerUtility::var_dump([
150
            '$identifier' => $identifier
151
        ], 'getPublicUrl');
152
    }
153
154
    /**
155
     * Renames a folder in this storage.
156
     *
157
     * @param string $folderIdentifier
158
     * @param string $newName
159
     * @return array A map of old to new file identifiers of all affected resources
160
     */
161 3
    public function renameFolder($folderIdentifier, $newName)
162
    {
163 3
        $renameResult = $this->filesystem->rename($folderIdentifier, $newName);
164
165 3
        if (true === $renameResult) {
166 3
            return [$folderIdentifier => $newName];
167
        } else {
168
            return [$folderIdentifier => $folderIdentifier];
169
        }
170
    }
171
172
    /**
173
     * Removes a folder in filesystem.
174
     *
175
     * @param string $folderIdentifier
176
     * @param bool $deleteRecursively
177
     * @return bool
178
     */
179
    public function deleteFolder($folderIdentifier, $deleteRecursively = false)
180
    {
181
        return $this->filesystem->deleteDir($folderIdentifier);
182
    }
183
184
    /**
185
     * Checks if a file exists.
186
     *
187
     * @param string $fileIdentifier
188
     * @return bool
189
     */
190 6
    public function fileExists($fileIdentifier)
191
    {
192 6
        return $this->filesystem->has($fileIdentifier);
193
    }
194
195
    /**
196
     * Checks if a folder contains files and (if supported) other folders.
197
     *
198
     * @param string $folderIdentifier
199
     * @return bool TRUE if there are no files and folders within $folder
200
     */
201 3
    public function isFolderEmpty($folderIdentifier)
202
    {
203 3
        return 0 === count($this->filesystem->listContents($folderIdentifier));
204
    }
205
206
    /**
207
     * Adds a file from the local server hard disk to a given path in TYPO3s
208
     * virtual file system. This assumes that the local file exists, so no
209
     * further check is done here! After a successful the original file must
210
     * not exist anymore.
211
     *
212
     * @param string $localFilePath (within PATH_site)
213
     * @param string $targetFolderIdentifier
214
     * @param string $newFileName optional, if not given original name is used
215
     * @param bool $removeOriginal if set the original file will be removed
216
     *                                after successful operation
217
     * @return string the identifier of the new file
218
     */
219 3
    public function addFile($localFilePath, $targetFolderIdentifier, $newFileName = '', $removeOriginal = true)
220
    {
221 3
        $localFilePath = $this->canonicalizeAndCheckFilePath($localFilePath);
222 3
        $newFileName = $this->sanitizeFileName($newFileName !== '' ? $newFileName : PathUtility::basename($localFilePath));
223 3
        $newFileIdentifier = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier) . $newFileName;
224
225 3
        $targetPath = ltrim($newFileIdentifier, '/');
226
227 3
        $content = file_get_contents($localFilePath);
228
229 3
        if ($removeOriginal) {
230
            if (is_uploaded_file($localFilePath)) {
231
                $result = $this->filesystem->put($targetPath, $content);
232
            } else {
233
                $result = rename($localFilePath, $targetPath);
234
            }
235
            unlink($localFilePath);
236
        } else {
237 3
            $result = $this->filesystem->put($targetPath, $content);
238
        }
239 3
        if ($result === false || !$this->filesystem->has($targetPath)) {
240
            throw new \RuntimeException('Adding file ' . $localFilePath . ' at ' . $newFileIdentifier . ' failed.');
241
        }
242 3
        clearstatcache();
243 3
        return $newFileIdentifier;
244
    }
245
246
    /**
247
     * Creates a new (empty) file and returns the identifier.
248
     *
249
     * @param string $fileName
250
     * @param string $parentFolderIdentifier
251
     * @return string
252
     */
253
    public function createFile($fileName, $parentFolderIdentifier)
254
    {
255
        // TODO: Implement createFile() method.
256
        DebuggerUtility::var_dump([
257
            '$fileName' => $fileName,
258
            '$parentFolderIdentifier' => $parentFolderIdentifier
259
        ], 'createFile');
260
    }
261
262
    /**
263
     * Copies a file *within* the current storage.
264
     * Note that this is only about an inner storage copy action,
265
     * where a file is just copied to another folder in the same storage.
266
     *
267
     * @param string $fileIdentifier
268
     * @param string $targetFolderIdentifier
269
     * @param string $fileName
270
     * @return string the Identifier of the new file
271
     */
272
    public function copyFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $fileName)
273
    {
274
        // TODO: Implement copyFileWithinStorage() method.
275
        DebuggerUtility::var_dump([
276
            '$fileIdentifier' => $fileIdentifier,
277
            '$targetFolderIdentifier' => $targetFolderIdentifier,
278
            '$fileName' => $fileName
279
        ], 'copyFileWithinStorage');
280
    }
281
282
    /**
283
     * Renames a file in this storage.
284
     *
285
     * @param string $fileIdentifier
286
     * @param string $newName The target path (including the file name!)
287
     * @return string The identifier of the file after renaming
288
     */
289
    public function renameFile($fileIdentifier, $newName)
290
    {
291
        // TODO: Implement renameFile() method.
292
        DebuggerUtility::var_dump([
293
            '$fileIdentifier' => $fileIdentifier,
294
            '$newName' => $newName
295
        ], 'renameFile');
296
    }
297
298
    /**
299
     * Replaces a file with file in local file system.
300
     *
301
     * @param string $fileIdentifier
302
     * @param string $localFilePath
303
     * @return bool TRUE if the operation succeeded
304
     */
305
    public function replaceFile($fileIdentifier, $localFilePath)
306
    {
307
        // TODO: Implement replaceFile() method.
308
        DebuggerUtility::var_dump([
309
            '$fileIdentifier' => $fileIdentifier,
310
            '$localFilePath' => $localFilePath
311
        ], 'replaceFile');
312
    }
313
314
    /**
315
     * Removes a file from the filesystem. This does not check if the file is
316
     * still used or if it is a bad idea to delete it for some other reason
317
     * this has to be taken care of in the upper layers (e.g. the Storage)!
318
     *
319
     * @param string $fileIdentifier
320
     * @return bool TRUE if deleting the file succeeded
321
     */
322
    public function deleteFile($fileIdentifier)
323
    {
324
        return $this->filesystem->delete($fileIdentifier);
325
    }
326
327
    /**
328
     * Creates a hash for a file.
329
     *
330
     * @param string $fileIdentifier
331
     * @param string $hashAlgorithm The hash algorithm to use
332
     * @return string
333
     */
334
    public function hash($fileIdentifier, $hashAlgorithm)
335
    {
336
        // TODO: Implement hash() method.
337
    }
338
339
    /**
340
     * Moves a file *within* the current storage.
341
     * Note that this is only about an inner-storage move action,
342
     * where a file is just moved to another folder in the same storage.
343
     *
344
     * @param string $fileIdentifier
345
     * @param string $targetFolderIdentifier
346
     * @param string $newFileName
347
     * @return string
348
     */
349
    public function moveFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $newFileName)
350
    {
351
        // TODO: Implement moveFileWithinStorage() method.
352
    }
353
354
    /**
355
     * Folder equivalent to moveFileWithinStorage().
356
     *
357
     * @param string $sourceFolderIdentifier
358
     * @param string $targetFolderIdentifier
359
     * @param string $newFolderName
360
     * @return array All files which are affected, map of old => new file identifiers
361
     */
362
    public function moveFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
363
    {
364
        // TODO: Implement moveFolderWithinStorage() method.
365
    }
366
367
    /**
368
     * Folder equivalent to copyFileWithinStorage().
369
     *
370
     * @param string $sourceFolderIdentifier
371
     * @param string $targetFolderIdentifier
372
     * @param string $newFolderName
373
     * @return bool
374
     */
375
    public function copyFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
376
    {
377
        // TODO: Implement copyFolderWithinStorage() method.
378
    }
379
380
    /**
381
     * Returns the contents of a file. Beware that this requires to load the
382
     * complete file into memory and also may require fetching the file from an
383
     * external location. So this might be an expensive operation (both in terms
384
     * of processing resources and money) for large files.
385
     *
386
     * @param string $fileIdentifier
387
     * @return string The file contents
388
     */
389 3
    public function getFileContents($fileIdentifier)
390
    {
391 3
        return $this->filesystem->read($fileIdentifier);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression $this->filesystem->read($fileIdentifier); of type string|false adds false to the return on line 391 which is incompatible with the return type declared by the interface TYPO3\CMS\Core\Resource\...erface::getFileContents of type string. It seems like you forgot to handle an error condition.
Loading history...
392
    }
393
394
    /**
395
     * Sets the contents of a file to the specified value.
396
     *
397
     * @param string $fileIdentifier
398
     * @param string $contents
399
     * @return int The number of bytes written to the file
400
     */
401 3
    public function setFileContents($fileIdentifier, $contents)
402
    {
403 3
        $this->filesystem->put($fileIdentifier, $contents);
404
405 3
        return $this->filesystem->getSize($fileIdentifier);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression $this->filesystem->getSize($fileIdentifier); of type integer|false adds false to the return on line 405 which is incompatible with the return type declared by the interface TYPO3\CMS\Core\Resource\...erface::setFileContents of type integer. It seems like you forgot to handle an error condition.
Loading history...
406
    }
407
408
    /**
409
     * Checks if a file inside a folder exists
410
     *
411
     * @param string $fileName
412
     * @param string $folderIdentifier
413
     * @return bool
414
     */
415 3
    public function fileExistsInFolder($fileName, $folderIdentifier)
416
    {
417 3
        $identifier = $folderIdentifier . '/' . $fileName;
418 3
        $identifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
419 3
        return $this->fileExists($identifier);
420
    }
421
422
    /**
423
     * Checks if a folder inside a folder exists.
424
     *
425
     * @param string $folderName
426
     * @param string $folderIdentifier
427
     * @return bool
428
     */
429
    public function folderExistsInFolder($folderName, $folderIdentifier)
430
    {
431
        return $this->filesystem->has($folderIdentifier . $folderName);
432
    }
433
434
    /**
435
     * Returns a path to a local copy of a file for processing it. When changing the
436
     * file, you have to take care of replacing the current version yourself!
437
     *
438
     * @param string $fileIdentifier
439
     * @param bool $writable Set this to FALSE if you only need the file for read
440
     *                       operations. This might speed up things, e.g. by using
441
     *                       a cached local version. Never modify the file if you
442
     *                       have set this flag!
443
     * @return string The path to the file on the local disk
444
     */
445
    public function getFileForLocalProcessing($fileIdentifier, $writable = true)
446
    {
447
        // TODO: Implement getFileForLocalProcessing() method.
448
        DebuggerUtility::var_dump([
449
            '$fileIdentifier' => $fileIdentifier,
450
            '$writable' => $writable,
451
        ], 'getFileForLocalProcessing');
452
    }
453
454
    /**
455
     * Returns the permissions of a file/folder as an array
456
     * (keys r, w) of boolean flags
457
     *
458
     * @param string $identifier
459
     * @return array
460
     */
461
    public function getPermissions($identifier)
462
    {
463
        return array(
464
            'r' => true,
465
            'w' => true,
466
        );
467
    }
468
469
    /**
470
     * Directly output the contents of the file to the output
471
     * buffer. Should not take care of header files or flushing
472
     * buffer before. Will be taken care of by the Storage.
473
     *
474
     * @param string $identifier
475
     * @return void
476
     */
477
    public function dumpFileContents($identifier)
478
    {
479
        // TODO: Implement dumpFileContents() method.
480
        DebuggerUtility::var_dump([
481
            '$identifier' => $identifier,
482
        ], 'dumpFileContents');
483
    }
484
485
    /**
486
     * Checks if a given identifier is within a container, e.g. if
487
     * a file or folder is within another folder.
488
     * This can e.g. be used to check for web-mounts.
489
     *
490
     * Hint: this also needs to return TRUE if the given identifier
491
     * matches the container identifier to allow access to the root
492
     * folder of a filemount.
493
     *
494
     * @param string $folderIdentifier
495
     * @param string $identifier identifier to be checked against $folderIdentifier
496
     * @return bool TRUE if $content is within or matches $folderIdentifier
497
     */
498
    public function isWithin($folderIdentifier, $identifier)
499
    {
500
        $folderIdentifier = $this->canonicalizeAndCheckFileIdentifier($folderIdentifier);
501
        $entryIdentifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
502
        if ($folderIdentifier === $entryIdentifier) {
503
            return true;
504
        }
505
        // File identifier canonicalization will not modify a single slash so
506
        // we must not append another slash in that case.
507
        if ($folderIdentifier !== '/') {
508
            $folderIdentifier .= '/';
509
        }
510
        return GeneralUtility::isFirstPartOfStr($entryIdentifier, $folderIdentifier);
511
    }
512
513
    /**
514
     * Returns information about a file.
515
     *
516
     * @param string $fileIdentifier
517
     * @param array $propertiesToExtract Array of properties which are be extracted
518
     *                                   If empty all will be extracted
519
     * @return array
520
     */
521
    public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = [])
522
    {
523
        $relativeDriverPath = ltrim($fileIdentifier, '/');
524
        if (!$this->filesystem->has($relativeDriverPath) || !$this->filesystem->get($relativeDriverPath)->isFile()) {
525
            throw new \InvalidArgumentException('File ' . $fileIdentifier . ' does not exist.', 1314516809);
526
        }
527
        $dirPath = PathUtility::dirname($fileIdentifier);
528
        $dirPath = $this->canonicalizeAndCheckFolderIdentifier($dirPath);
529
        return $this->extractFileInformation($relativeDriverPath, $dirPath, $propertiesToExtract);
530
    }
531
532
    /**
533
     * Returns information about a file.
534
     *
535
     * @param string $folderIdentifier
536
     * @return array
537
     */
538
    public function getFolderInfoByIdentifier($folderIdentifier)
539
    {
540
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
541
542
        return [
543
            'identifier' => $folderIdentifier,
544
            'name' => PathUtility::basename($folderIdentifier),
545
            'storage' => $this->storageUid
546
        ];
547
    }
548
549
    /**
550
     * Returns the identifier of a file inside the folder
551
     *
552
     * @param string $fileName
553
     * @param string $folderIdentifier
554
     * @return string file identifier
555
     */
556
    public function getFileInFolder($fileName, $folderIdentifier)
557
    {
558
        return $this->canonicalizeAndCheckFileIdentifier($folderIdentifier . '/' . $fileName);
559
    }
560
561
    /**
562
     * Returns a list of files inside the specified path
563
     *
564
     * @param string $folderIdentifier
565
     * @param int $start
566
     * @param int $numberOfItems
567
     * @param bool $recursive
568
     * @param array $filenameFilterCallbacks callbacks for filtering the items
569
     * @param string $sort Property name used to sort the items.
570
     *                     Among them may be: '' (empty, no sorting), name,
571
     *                     fileext, size, tstamp and rw.
572
     *                     If a driver does not support the given property, it
573
     *                     should fall back to "name".
574
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
575
     * @return array of FileIdentifiers
576
     */
577 3
    public function getFilesInFolder(
578
        $folderIdentifier,
579
        $start = 0,
580
        $numberOfItems = 0,
581
        $recursive = false,
582
        array $filenameFilterCallbacks = [],
583
        $sort = '',
584
        $sortRev = false
585
    ) {
586 3
        $calculatedFolderIdentifier = ltrim($this->canonicalizeAndCheckFolderIdentifier($folderIdentifier), '/');
587 3
        $contents = $this->filesystem->listContents($calculatedFolderIdentifier);
588 3
        $files = [];
589
590
        /*
591
         * Filter directories
592
         */
593 3
        foreach ($contents as $directoryItem) {
594 3
            if ('file' === $directoryItem['type']) {
595 3
                $files['/' . $directoryItem['path']] = '/' . $directoryItem['path'];
596 2
            }
597 2
        }
598
599 3
        return $files;
600
    }
601
602
    /**
603
     * Returns the identifier of a folder inside the folder
604
     *
605
     * @param string $folderName The name of the target folder
606
     * @param string $folderIdentifier
607
     * @return string folder identifier
608
     */
609
    public function getFolderInFolder($folderName, $folderIdentifier)
610
    {
611
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier . '/' . $folderName);
612
        return $folderIdentifier;
613
    }
614
615
    /**
616
     * Returns a list of folders inside the specified path
617
     *
618
     * @param string $folderIdentifier
619
     * @param int $start
620
     * @param int $numberOfItems
621
     * @param bool $recursive
622
     * @param array $folderNameFilterCallbacks callbacks for filtering the items
623
     * @param string $sort Property name used to sort the items.
624
     *                     Among them may be: '' (empty, no sorting), name,
625
     *                     fileext, size, tstamp and rw.
626
     *                     If a driver does not support the given property, it
627
     *                     should fall back to "name".
628
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
629
     * @return array of Folder Identifier
630
     * @TODO: Implement pagination with $start and $numberOfItems
631
     * @TODO: Implement directory filter callbacks
632
     * @TODO: Implement sorting
633
     */
634 3
    public function getFoldersInFolder(
635
        $folderIdentifier,
636
        $start = 0,
637
        $numberOfItems = 0,
638
        $recursive = false,
639
        array $folderNameFilterCallbacks = [],
640
        $sort = '',
641
        $sortRev = false
642
    ) {
643 3
        $calculatedFolderIdentifier = ltrim($this->canonicalizeAndCheckFolderIdentifier($folderIdentifier), '/');
644 3
        $contents = $this->filesystem->listContents($calculatedFolderIdentifier);
645 3
        $directories = [];
646
647
        /*
648
         * Filter directories
649
         */
650 3
        foreach ($contents as $directoryItem) {
651 3
            if ('dir' === $directoryItem['type']) {
652 3
                $directories['/' . $directoryItem['path']]
653 3
                    = '/' . $directoryItem['path'];
654 2
            }
655 2
        }
656
657 3
        return $directories;
658
    }
659
660
    /**
661
     * Returns the number of files inside the specified path
662
     *
663
     * @param string $folderIdentifier
664
     * @param bool $recursive
665
     * @param array $filenameFilterCallbacks callbacks for filtering the items
666
     * @return int Number of files in folder
667
     * @TODO: Implement recursive count
668
     * @TODO: Implement filename filtering
669
     */
670
    public function countFilesInFolder($folderIdentifier, $recursive = false, array $filenameFilterCallbacks = [])
671
    {
672
673
        return count($this->getFilesInFolder($folderIdentifier, 0, 0, $recursive, $filenameFilterCallbacks));
674
    }
675
676
    /**
677
     * Returns the number of folders inside the specified path
678
     *
679
     * @param string $folderIdentifier
680
     * @param bool $recursive
681
     * @param array $folderNameFilterCallbacks callbacks for filtering the items
682
     * @return int Number of folders in folder
683
     */
684 3
    public function countFoldersInFolder($folderIdentifier, $recursive = false, array $folderNameFilterCallbacks = [])
685
    {
686 3
        $count = 0;
687 3
        $filesystemRelativeIdentifier = ltrim($folderIdentifier, '/');
688 3
        $directoryListing = $this->filesystem->listContents($filesystemRelativeIdentifier);
689 3
        foreach ($directoryListing as $entry) {
690 3
            if ('dir' === $entry['type']) {
691 3
                $count++;
692 2
            }
693 2
        }
694
695 3
        return $count;
696
    }
697
698
    /**
699
     * Extracts information about a file from the filesystem.
700
     *
701
     * @param string $filePath The absolute path to the file
702
     * @param string $containerPath The relative path to the file's container
703
     * @param array $propertiesToExtract array of properties which should be returned, if empty all will be extracted
704
     * @return array
705
     */
706
    protected function extractFileInformation($filePath, $containerPath, array $propertiesToExtract = array())
707
    {
708
        if (empty($propertiesToExtract)) {
709
            $propertiesToExtract = array(
710
                'size',
711
                'atime',
712
                'atime',
713
                'mtime',
714
                'ctime',
715
                'mimetype',
716
                'name',
717
                'identifier',
718
                'identifier_hash',
719
                'storage',
720
                'folder_hash'
721
            );
722
        }
723
        $fileInformation = array();
724
        foreach ($propertiesToExtract as $property) {
725
            $fileInformation[$property] = $this->getSpecificFileInformation($filePath, $containerPath, $property);
726
        }
727
        return $fileInformation;
728
    }
729
730
    /**
731
     * Extracts a specific FileInformation from the FileSystems.
732
     *
733
     * @param string $fileIdentifier
734
     * @param string $containerPath
735
     * @param string $property
736
     *
737
     * @return bool|int|string
738
     * @throws \InvalidArgumentException
739
     */
740
    public function getSpecificFileInformation($fileIdentifier, $containerPath, $property)
741
    {
742
        $identifier = $this->canonicalizeAndCheckFileIdentifier($containerPath . PathUtility::basename($fileIdentifier));
743
        $file = $this->filesystem->getMetadata($fileIdentifier);
744
745
        switch ($property) {
746
            case 'size':
747
                return $file['size'];
748
            case 'atime':
749
                return $file['timestamp'];
750
            case 'mtime':
751
                return $file['timestamp'];
752
            case 'ctime':
753
                return $file['timestamp'];
754
            case 'name':
755
                return PathUtility::basename($fileIdentifier);
756
            case 'mimetype':
757
                return $file['mimetype'];
758
            case 'identifier':
759
                return $identifier;
760
            case 'storage':
761
                return $this->storageUid;
762
            case 'identifier_hash':
763
                return $this->hashIdentifier($identifier);
764
            case 'folder_hash':
765
                return $this->hashIdentifier($this->getParentFolderIdentifierOfIdentifier($identifier));
766
            default:
767
                throw new \InvalidArgumentException(sprintf('The information "%s" is not available.', $property));
768
        }
769
    }
770
}
771