Completed
Push — master ( ea16a4...1abcaf )
by Cedric
01:52
created

FlysystemDriver   C

Complexity

Total Complexity 73

Size/Duplication

Total Lines 754
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 5

Test Coverage

Coverage 38.75%

Importance

Changes 17
Bugs 2 Features 4
Metric Value
wmc 73
c 17
b 2
f 4
lcom 2
cbo 5
dl 0
loc 754
ccs 93
cts 240
cp 0.3875
rs 5

40 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A processConfiguration() 0 4 1
A mergeConfigurationCapabilities() 0 4 1
A getRootLevelFolder() 0 4 1
A getDefaultFolder() 0 9 2
A folderExists() 0 8 2
A createFolder() 0 16 2
A getPublicUrl() 0 7 1
A renameFolder() 0 10 2
A deleteFolder() 0 4 1
A fileExists() 0 7 3
A isFolderEmpty() 0 4 1
B addFile() 0 26 6
A createFile() 0 8 1
A copyFileWithinStorage() 0 9 1
A renameFile() 0 8 1
A replaceFile() 0 8 1
A deleteFile() 0 4 1
A hash() 0 4 1
A moveFileWithinStorage() 0 4 1
A moveFolderWithinStorage() 0 4 1
A copyFolderWithinStorage() 0 4 1
A getFileContents() 0 4 1
A setFileContents() 0 6 1
A fileExistsInFolder() 0 6 1
A folderExistsInFolder() 0 4 1
A getFileForLocalProcessing() 0 8 1
A getPermissions() 0 7 1
A dumpFileContents() 0 7 1
A isWithin() 0 14 3
A getFileInfoByIdentifier() 0 10 3
A getFileInFolder() 0 4 1
B getFilesInFolder() 0 24 3
A getFolderInFolder() 0 5 1
B getFoldersInFolder() 0 25 3
A countFilesInFolder() 0 5 1
A countFoldersInFolder() 0 13 3
A extractFileInformation() 0 23 3
C getSpecificFileInformation() 0 30 11
A getFolderInfoByIdentifier() 0 10 1

How to fix   Complexity   

Complex Class

Complex classes like FlysystemDriver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FlysystemDriver, and based on these observations, apply Extract Interface, too.

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 39
    public function __construct(array $configuration = [])
42
    {
43 39
        parent::__construct($configuration);
44
        // The capabilities default of this driver. See CAPABILITY_* constants for possible values
45 39
        $this->capabilities =
46 13
            ResourceStorage::CAPABILITY_BROWSABLE
47 39
            | ResourceStorage::CAPABILITY_PUBLIC
48 39
            | ResourceStorage::CAPABILITY_WRITABLE;
49 39
    }
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
        if ($this->filesystem->has($fileIdentifier) && !$this->filesystem->get($fileIdentifier)->isDir()) {
193 6
            return true;
194
        }
195 3
        return false;
196
    }
197
198
    /**
199
     * Checks if a folder contains files and (if supported) other folders.
200
     *
201
     * @param string $folderIdentifier
202
     * @return bool TRUE if there are no files and folders within $folder
203
     */
204 3
    public function isFolderEmpty($folderIdentifier)
205
    {
206 3
        return 0 === count($this->filesystem->listContents($folderIdentifier));
207
    }
208
209
    /**
210
     * Adds a file from the local server hard disk to a given path in TYPO3s
211
     * virtual file system. This assumes that the local file exists, so no
212
     * further check is done here! After a successful the original file must
213
     * not exist anymore.
214
     *
215
     * @param string $localFilePath (within PATH_site)
216
     * @param string $targetFolderIdentifier
217
     * @param string $newFileName optional, if not given original name is used
218
     * @param bool $removeOriginal if set the original file will be removed
219
     *                                after successful operation
220
     * @return string the identifier of the new file
221
     */
222 3
    public function addFile($localFilePath, $targetFolderIdentifier, $newFileName = '', $removeOriginal = true)
223
    {
224 3
        $localFilePath = $this->canonicalizeAndCheckFilePath($localFilePath);
225 3
        $newFileName = $this->sanitizeFileName($newFileName !== '' ? $newFileName : PathUtility::basename($localFilePath));
226 3
        $newFileIdentifier = $this->canonicalizeAndCheckFolderIdentifier($targetFolderIdentifier) . $newFileName;
227
228 3
        $targetPath = ltrim($newFileIdentifier, '/');
229
230 3
        $content = file_get_contents($localFilePath);
231
232 3
        if ($removeOriginal) {
233
            if (is_uploaded_file($localFilePath)) {
234
                $result = $this->filesystem->put($targetPath, $content);
235
            } else {
236
                $result = rename($localFilePath, $targetPath);
237
            }
238
            unlink($localFilePath);
239
        } else {
240 3
            $result = $this->filesystem->put($targetPath, $content);
241
        }
242 3
        if ($result === false || !$this->filesystem->has($targetPath)) {
243
            throw new \RuntimeException('Adding file ' . $localFilePath . ' at ' . $newFileIdentifier . ' failed.');
244
        }
245 3
        clearstatcache();
246 3
        return $newFileIdentifier;
247
    }
248
249
    /**
250
     * Creates a new (empty) file and returns the identifier.
251
     *
252
     * @param string $fileName
253
     * @param string $parentFolderIdentifier
254
     * @return string
255
     */
256
    public function createFile($fileName, $parentFolderIdentifier)
257
    {
258
        // TODO: Implement createFile() method.
259
        DebuggerUtility::var_dump([
260
            '$fileName' => $fileName,
261
            '$parentFolderIdentifier' => $parentFolderIdentifier
262
        ], 'createFile');
263
    }
264
265
    /**
266
     * Copies a file *within* the current storage.
267
     * Note that this is only about an inner storage copy action,
268
     * where a file is just copied to another folder in the same storage.
269
     *
270
     * @param string $fileIdentifier
271
     * @param string $targetFolderIdentifier
272
     * @param string $fileName
273
     * @return string the Identifier of the new file
274
     */
275
    public function copyFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $fileName)
276
    {
277
        // TODO: Implement copyFileWithinStorage() method.
278
        DebuggerUtility::var_dump([
279
            '$fileIdentifier' => $fileIdentifier,
280
            '$targetFolderIdentifier' => $targetFolderIdentifier,
281
            '$fileName' => $fileName
282
        ], 'copyFileWithinStorage');
283
    }
284
285
    /**
286
     * Renames a file in this storage.
287
     *
288
     * @param string $fileIdentifier
289
     * @param string $newName The target path (including the file name!)
290
     * @return string The identifier of the file after renaming
291
     */
292
    public function renameFile($fileIdentifier, $newName)
293
    {
294
        // TODO: Implement renameFile() method.
295
        DebuggerUtility::var_dump([
296
            '$fileIdentifier' => $fileIdentifier,
297
            '$newName' => $newName
298
        ], 'renameFile');
299
    }
300
301
    /**
302
     * Replaces a file with file in local file system.
303
     *
304
     * @param string $fileIdentifier
305
     * @param string $localFilePath
306
     * @return bool TRUE if the operation succeeded
307
     */
308
    public function replaceFile($fileIdentifier, $localFilePath)
309
    {
310
        // TODO: Implement replaceFile() method.
311
        DebuggerUtility::var_dump([
312
            '$fileIdentifier' => $fileIdentifier,
313
            '$localFilePath' => $localFilePath
314
        ], 'replaceFile');
315
    }
316
317
    /**
318
     * Removes a file from the filesystem. This does not check if the file is
319
     * still used or if it is a bad idea to delete it for some other reason
320
     * this has to be taken care of in the upper layers (e.g. the Storage)!
321
     *
322
     * @param string $fileIdentifier
323
     * @return bool TRUE if deleting the file succeeded
324
     */
325
    public function deleteFile($fileIdentifier)
326
    {
327
        return $this->filesystem->delete($fileIdentifier);
328
    }
329
330
    /**
331
     * Creates a hash for a file.
332
     *
333
     * @param string $fileIdentifier
334
     * @param string $hashAlgorithm The hash algorithm to use
335
     * @return string
336
     */
337
    public function hash($fileIdentifier, $hashAlgorithm)
338
    {
339
        // TODO: Implement hash() method.
340
    }
341
342
    /**
343
     * Moves a file *within* the current storage.
344
     * Note that this is only about an inner-storage move action,
345
     * where a file is just moved to another folder in the same storage.
346
     *
347
     * @param string $fileIdentifier
348
     * @param string $targetFolderIdentifier
349
     * @param string $newFileName
350
     * @return string
351
     */
352
    public function moveFileWithinStorage($fileIdentifier, $targetFolderIdentifier, $newFileName)
353
    {
354
        // TODO: Implement moveFileWithinStorage() method.
355
    }
356
357
    /**
358
     * Folder equivalent to moveFileWithinStorage().
359
     *
360
     * @param string $sourceFolderIdentifier
361
     * @param string $targetFolderIdentifier
362
     * @param string $newFolderName
363
     * @return array All files which are affected, map of old => new file identifiers
364
     */
365
    public function moveFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
366
    {
367
        // TODO: Implement moveFolderWithinStorage() method.
368
    }
369
370
    /**
371
     * Folder equivalent to copyFileWithinStorage().
372
     *
373
     * @param string $sourceFolderIdentifier
374
     * @param string $targetFolderIdentifier
375
     * @param string $newFolderName
376
     * @return bool
377
     */
378
    public function copyFolderWithinStorage($sourceFolderIdentifier, $targetFolderIdentifier, $newFolderName)
379
    {
380
        // TODO: Implement copyFolderWithinStorage() method.
381
    }
382
383
    /**
384
     * Returns the contents of a file. Beware that this requires to load the
385
     * complete file into memory and also may require fetching the file from an
386
     * external location. So this might be an expensive operation (both in terms
387
     * of processing resources and money) for large files.
388
     *
389
     * @param string $fileIdentifier
390
     * @return string The file contents
391
     */
392 3
    public function getFileContents($fileIdentifier)
393
    {
394 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 394 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...
395
    }
396
397
    /**
398
     * Sets the contents of a file to the specified value.
399
     *
400
     * @param string $fileIdentifier
401
     * @param string $contents
402
     * @return int The number of bytes written to the file
403
     */
404 3
    public function setFileContents($fileIdentifier, $contents)
405
    {
406 3
        $this->filesystem->put($fileIdentifier, $contents);
407
408 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 408 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...
409
    }
410
411
    /**
412
     * Checks if a file inside a folder exists
413
     *
414
     * @param string $fileName
415
     * @param string $folderIdentifier
416
     * @return bool
417
     */
418 3
    public function fileExistsInFolder($fileName, $folderIdentifier)
419
    {
420 3
        $identifier = $folderIdentifier . '/' . $fileName;
421 3
        $identifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
422 3
        return $this->fileExists($identifier);
423
    }
424
425
    /**
426
     * Checks if a folder inside a folder exists.
427
     *
428
     * @param string $folderName
429
     * @param string $folderIdentifier
430
     * @return bool
431
     */
432
    public function folderExistsInFolder($folderName, $folderIdentifier)
433
    {
434
        return $this->filesystem->has($folderIdentifier . $folderName);
435
    }
436
437
    /**
438
     * Returns a path to a local copy of a file for processing it. When changing the
439
     * file, you have to take care of replacing the current version yourself!
440
     *
441
     * @param string $fileIdentifier
442
     * @param bool $writable Set this to FALSE if you only need the file for read
443
     *                       operations. This might speed up things, e.g. by using
444
     *                       a cached local version. Never modify the file if you
445
     *                       have set this flag!
446
     * @return string The path to the file on the local disk
447
     */
448
    public function getFileForLocalProcessing($fileIdentifier, $writable = true)
449
    {
450
        // TODO: Implement getFileForLocalProcessing() method.
451
        DebuggerUtility::var_dump([
452
            '$fileIdentifier' => $fileIdentifier,
453
            '$writable' => $writable,
454
        ], 'getFileForLocalProcessing');
455
    }
456
457
    /**
458
     * Returns the permissions of a file/folder as an array
459
     * (keys r, w) of boolean flags
460
     *
461
     * @param string $identifier
462
     * @return array
463
     */
464
    public function getPermissions($identifier)
465
    {
466
        return array(
467
            'r' => true,
468
            'w' => true,
469
        );
470
    }
471
472
    /**
473
     * Directly output the contents of the file to the output
474
     * buffer. Should not take care of header files or flushing
475
     * buffer before. Will be taken care of by the Storage.
476
     *
477
     * @param string $identifier
478
     * @return void
479
     */
480
    public function dumpFileContents($identifier)
481
    {
482
        // TODO: Implement dumpFileContents() method.
483
        DebuggerUtility::var_dump([
484
            '$identifier' => $identifier,
485
        ], 'dumpFileContents');
486
    }
487
488
    /**
489
     * Checks if a given identifier is within a container, e.g. if
490
     * a file or folder is within another folder.
491
     * This can e.g. be used to check for web-mounts.
492
     *
493
     * Hint: this also needs to return TRUE if the given identifier
494
     * matches the container identifier to allow access to the root
495
     * folder of a filemount.
496
     *
497
     * @param string $folderIdentifier
498
     * @param string $identifier identifier to be checked against $folderIdentifier
499
     * @return bool TRUE if $content is within or matches $folderIdentifier
500
     */
501
    public function isWithin($folderIdentifier, $identifier)
502
    {
503
        $folderIdentifier = $this->canonicalizeAndCheckFileIdentifier($folderIdentifier);
504
        $entryIdentifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
505
        if ($folderIdentifier === $entryIdentifier) {
506
            return true;
507
        }
508
        // File identifier canonicalization will not modify a single slash so
509
        // we must not append another slash in that case.
510
        if ($folderIdentifier !== '/') {
511
            $folderIdentifier .= '/';
512
        }
513
        return GeneralUtility::isFirstPartOfStr($entryIdentifier, $folderIdentifier);
514
    }
515
516
    /**
517
     * Returns information about a file.
518
     *
519
     * @param string $fileIdentifier
520
     * @param array $propertiesToExtract Array of properties which are be extracted
521
     *                                   If empty all will be extracted
522
     * @return array
523
     */
524
    public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = [])
525
    {
526
        $relativeDriverPath = ltrim($fileIdentifier, '/');
527
        if (!$this->filesystem->has($relativeDriverPath) || !$this->filesystem->get($relativeDriverPath)->isFile()) {
528
            throw new \InvalidArgumentException('File ' . $fileIdentifier . ' does not exist.', 1314516809);
529
        }
530
        $dirPath = PathUtility::dirname($fileIdentifier);
531
        $dirPath = $this->canonicalizeAndCheckFolderIdentifier($dirPath);
532
        return $this->extractFileInformation($relativeDriverPath, $dirPath, $propertiesToExtract);
533
    }
534
535
    /**
536
     * Returns information about a file.
537
     *
538
     * @param string $folderIdentifier
539
     * @return array
540
     */
541 3
    public function getFolderInfoByIdentifier($folderIdentifier)
542
    {
543 3
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier);
544
545
        return [
546 3
            'identifier' => $folderIdentifier,
547 3
            'name' => PathUtility::basename($folderIdentifier),
548 3
            'storage' => $this->storageUid
549 2
        ];
550
    }
551
552
    /**
553
     * Returns the identifier of a file inside the folder
554
     *
555
     * @param string $fileName
556
     * @param string $folderIdentifier
557
     * @return string file identifier
558
     */
559
    public function getFileInFolder($fileName, $folderIdentifier)
560
    {
561
        return $this->canonicalizeAndCheckFileIdentifier($folderIdentifier . '/' . $fileName);
562
    }
563
564
    /**
565
     * Returns a list of files inside the specified path
566
     *
567
     * @param string $folderIdentifier
568
     * @param int $start
569
     * @param int $numberOfItems
570
     * @param bool $recursive
571
     * @param array $filenameFilterCallbacks callbacks for filtering the items
572
     * @param string $sort Property name used to sort the items.
573
     *                     Among them may be: '' (empty, no sorting), name,
574
     *                     fileext, size, tstamp and rw.
575
     *                     If a driver does not support the given property, it
576
     *                     should fall back to "name".
577
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
578
     * @return array of FileIdentifiers
579
     */
580 3
    public function getFilesInFolder(
581
        $folderIdentifier,
582
        $start = 0,
583
        $numberOfItems = 0,
584
        $recursive = false,
585
        array $filenameFilterCallbacks = [],
586
        $sort = '',
587
        $sortRev = false
588
    ) {
589 3
        $calculatedFolderIdentifier = ltrim($this->canonicalizeAndCheckFolderIdentifier($folderIdentifier), '/');
590 3
        $contents = $this->filesystem->listContents($calculatedFolderIdentifier);
591 3
        $files = [];
592
593
        /*
594
         * Filter directories
595
         */
596 3
        foreach ($contents as $directoryItem) {
597 3
            if ('file' === $directoryItem['type']) {
598 3
                $files['/' . $directoryItem['path']] = '/' . $directoryItem['path'];
599 2
            }
600 2
        }
601
602 3
        return $files;
603
    }
604
605
    /**
606
     * Returns the identifier of a folder inside the folder
607
     *
608
     * @param string $folderName The name of the target folder
609
     * @param string $folderIdentifier
610
     * @return string folder identifier
611
     */
612
    public function getFolderInFolder($folderName, $folderIdentifier)
613
    {
614
        $folderIdentifier = $this->canonicalizeAndCheckFolderIdentifier($folderIdentifier . '/' . $folderName);
615
        return $folderIdentifier;
616
    }
617
618
    /**
619
     * Returns a list of folders inside the specified path
620
     *
621
     * @param string $folderIdentifier
622
     * @param int $start
623
     * @param int $numberOfItems
624
     * @param bool $recursive
625
     * @param array $folderNameFilterCallbacks callbacks for filtering the items
626
     * @param string $sort Property name used to sort the items.
627
     *                     Among them may be: '' (empty, no sorting), name,
628
     *                     fileext, size, tstamp and rw.
629
     *                     If a driver does not support the given property, it
630
     *                     should fall back to "name".
631
     * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
632
     * @return array of Folder Identifier
633
     * @TODO: Implement pagination with $start and $numberOfItems
634
     * @TODO: Implement directory filter callbacks
635
     * @TODO: Implement sorting
636
     */
637 3
    public function getFoldersInFolder(
638
        $folderIdentifier,
639
        $start = 0,
640
        $numberOfItems = 0,
641
        $recursive = false,
642
        array $folderNameFilterCallbacks = [],
643
        $sort = '',
644
        $sortRev = false
645
    ) {
646 3
        $calculatedFolderIdentifier = ltrim($this->canonicalizeAndCheckFolderIdentifier($folderIdentifier), '/');
647 3
        $contents = $this->filesystem->listContents($calculatedFolderIdentifier);
648 3
        $directories = [];
649
650
        /*
651
         * Filter directories
652
         */
653 3
        foreach ($contents as $directoryItem) {
654 3
            if ('dir' === $directoryItem['type']) {
655 3
                $directories['/' . $directoryItem['path']]
656 3
                    = '/' . $directoryItem['path'];
657 2
            }
658 2
        }
659
660 3
        return $directories;
661
    }
662
663
    /**
664
     * Returns the number of files inside the specified path
665
     *
666
     * @param string $folderIdentifier
667
     * @param bool $recursive
668
     * @param array $filenameFilterCallbacks callbacks for filtering the items
669
     * @return int Number of files in folder
670
     * @TODO: Implement recursive count
671
     * @TODO: Implement filename filtering
672
     */
673
    public function countFilesInFolder($folderIdentifier, $recursive = false, array $filenameFilterCallbacks = [])
674
    {
675
676
        return count($this->getFilesInFolder($folderIdentifier, 0, 0, $recursive, $filenameFilterCallbacks));
677
    }
678
679
    /**
680
     * Returns the number of folders inside the specified path
681
     *
682
     * @param string $folderIdentifier
683
     * @param bool $recursive
684
     * @param array $folderNameFilterCallbacks callbacks for filtering the items
685
     * @return int Number of folders in folder
686
     */
687 3
    public function countFoldersInFolder($folderIdentifier, $recursive = false, array $folderNameFilterCallbacks = [])
688
    {
689 3
        $count = 0;
690 3
        $filesystemRelativeIdentifier = ltrim($folderIdentifier, '/');
691 3
        $directoryListing = $this->filesystem->listContents($filesystemRelativeIdentifier);
692 3
        foreach ($directoryListing as $entry) {
693 3
            if ('dir' === $entry['type']) {
694 3
                $count++;
695 2
            }
696 2
        }
697
698 3
        return $count;
699
    }
700
701
    /**
702
     * Extracts information about a file from the filesystem.
703
     *
704
     * @param string $filePath The absolute path to the file
705
     * @param string $containerPath The relative path to the file's container
706
     * @param array $propertiesToExtract array of properties which should be returned, if empty all will be extracted
707
     * @return array
708
     */
709
    protected function extractFileInformation($filePath, $containerPath, array $propertiesToExtract = array())
710
    {
711
        if (empty($propertiesToExtract)) {
712
            $propertiesToExtract = array(
713
                'size',
714
                'atime',
715
                'atime',
716
                'mtime',
717
                'ctime',
718
                'mimetype',
719
                'name',
720
                'identifier',
721
                'identifier_hash',
722
                'storage',
723
                'folder_hash'
724
            );
725
        }
726
        $fileInformation = array();
727
        foreach ($propertiesToExtract as $property) {
728
            $fileInformation[$property] = $this->getSpecificFileInformation($filePath, $containerPath, $property);
729
        }
730
        return $fileInformation;
731
    }
732
733
    /**
734
     * Extracts a specific FileInformation from the FileSystems.
735
     *
736
     * @param string $fileIdentifier
737
     * @param string $containerPath
738
     * @param string $property
739
     *
740
     * @return bool|int|string
741
     * @throws \InvalidArgumentException
742
     */
743
    public function getSpecificFileInformation($fileIdentifier, $containerPath, $property)
744
    {
745
        $identifier = $this->canonicalizeAndCheckFileIdentifier($containerPath . PathUtility::basename($fileIdentifier));
746
        $file = $this->filesystem->getMetadata($fileIdentifier);
747
748
        switch ($property) {
749
            case 'size':
750
                return $file['size'];
751
            case 'atime':
752
                return $file['timestamp'];
753
            case 'mtime':
754
                return $file['timestamp'];
755
            case 'ctime':
756
                return $file['timestamp'];
757
            case 'name':
758
                return PathUtility::basename($fileIdentifier);
759
            case 'mimetype':
760
                return $file['mimetype'];
761
            case 'identifier':
762
                return $identifier;
763
            case 'storage':
764
                return $this->storageUid;
765
            case 'identifier_hash':
766
                return $this->hashIdentifier($identifier);
767
            case 'folder_hash':
768
                return $this->hashIdentifier($this->getParentFolderIdentifierOfIdentifier($identifier));
769
            default:
770
                throw new \InvalidArgumentException(sprintf('The information "%s" is not available.', $property));
771
        }
772
    }
773
}
774