Completed
Push — master ( 681930...3c9969 )
by Cedric
01:48
created

FlysystemDriver::createFile()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.3332

Importance

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