Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Filesystem;
4
 
5
use Closure;
6
use Illuminate\Contracts\Filesystem\Cloud as CloudFilesystemContract;
7
use Illuminate\Contracts\Filesystem\Filesystem as FilesystemContract;
8
use Illuminate\Http\File;
9
use Illuminate\Http\UploadedFile;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Str;
12
use Illuminate\Support\Traits\Conditionable;
13
use Illuminate\Support\Traits\Macroable;
14
use InvalidArgumentException;
15
use League\Flysystem\FilesystemAdapter as FlysystemAdapter;
16
use League\Flysystem\FilesystemOperator;
17
use League\Flysystem\Ftp\FtpAdapter;
18
use League\Flysystem\Local\LocalFilesystemAdapter as LocalAdapter;
19
use League\Flysystem\PathPrefixer;
20
use League\Flysystem\PhpseclibV3\SftpAdapter;
21
use League\Flysystem\StorageAttributes;
22
use League\Flysystem\UnableToCopyFile;
23
use League\Flysystem\UnableToCreateDirectory;
24
use League\Flysystem\UnableToDeleteDirectory;
25
use League\Flysystem\UnableToDeleteFile;
26
use League\Flysystem\UnableToMoveFile;
27
use League\Flysystem\UnableToProvideChecksum;
28
use League\Flysystem\UnableToReadFile;
29
use League\Flysystem\UnableToRetrieveMetadata;
30
use League\Flysystem\UnableToSetVisibility;
31
use League\Flysystem\UnableToWriteFile;
32
use League\Flysystem\Visibility;
33
use PHPUnit\Framework\Assert as PHPUnit;
34
use Psr\Http\Message\StreamInterface;
35
use RuntimeException;
36
use Symfony\Component\HttpFoundation\StreamedResponse;
37
 
38
/**
39
 * @mixin \League\Flysystem\FilesystemOperator
40
 */
41
class FilesystemAdapter implements CloudFilesystemContract
42
{
43
    use Conditionable;
44
    use Macroable {
45
        __call as macroCall;
46
    }
47
 
48
    /**
49
     * The Flysystem filesystem implementation.
50
     *
51
     * @var \League\Flysystem\FilesystemOperator
52
     */
53
    protected $driver;
54
 
55
    /**
56
     * The Flysystem adapter implementation.
57
     *
58
     * @var \League\Flysystem\FilesystemAdapter
59
     */
60
    protected $adapter;
61
 
62
    /**
63
     * The filesystem configuration.
64
     *
65
     * @var array
66
     */
67
    protected $config;
68
 
69
    /**
70
     * The Flysystem PathPrefixer instance.
71
     *
72
     * @var \League\Flysystem\PathPrefixer
73
     */
74
    protected $prefixer;
75
 
76
    /**
77
     * The temporary URL builder callback.
78
     *
79
     * @var \Closure|null
80
     */
81
    protected $temporaryUrlCallback;
82
 
83
    /**
84
     * Create a new filesystem adapter instance.
85
     *
86
     * @param  \League\Flysystem\FilesystemOperator  $driver
87
     * @param  \League\Flysystem\FilesystemAdapter  $adapter
88
     * @param  array  $config
89
     * @return void
90
     */
91
    public function __construct(FilesystemOperator $driver, FlysystemAdapter $adapter, array $config = [])
92
    {
93
        $this->driver = $driver;
94
        $this->adapter = $adapter;
95
        $this->config = $config;
96
        $separator = $config['directory_separator'] ?? DIRECTORY_SEPARATOR;
97
 
98
        $this->prefixer = new PathPrefixer($config['root'] ?? '', $separator);
99
 
100
        if (isset($config['prefix'])) {
101
            $this->prefixer = new PathPrefixer($this->prefixer->prefixPath($config['prefix']), $separator);
102
        }
103
    }
104
 
105
    /**
106
     * Assert that the given file or directory exists.
107
     *
108
     * @param  string|array  $path
109
     * @param  string|null  $content
110
     * @return $this
111
     */
112
    public function assertExists($path, $content = null)
113
    {
114
        clearstatcache();
115
 
116
        $paths = Arr::wrap($path);
117
 
118
        foreach ($paths as $path) {
119
            PHPUnit::assertTrue(
120
                $this->exists($path), "Unable to find a file or directory at path [{$path}]."
121
            );
122
 
123
            if (! is_null($content)) {
124
                $actual = $this->get($path);
125
 
126
                PHPUnit::assertSame(
127
                    $content,
128
                    $actual,
129
                    "File or directory [{$path}] was found, but content [{$actual}] does not match [{$content}]."
130
                );
131
            }
132
        }
133
 
134
        return $this;
135
    }
136
 
137
    /**
138
     * Assert that the given file or directory does not exist.
139
     *
140
     * @param  string|array  $path
141
     * @return $this
142
     */
143
    public function assertMissing($path)
144
    {
145
        clearstatcache();
146
 
147
        $paths = Arr::wrap($path);
148
 
149
        foreach ($paths as $path) {
150
            PHPUnit::assertFalse(
151
                $this->exists($path), "Found unexpected file or directory at path [{$path}]."
152
            );
153
        }
154
 
155
        return $this;
156
    }
157
 
158
    /**
159
     * Assert that the given directory is empty.
160
     *
161
     * @param  string  $path
162
     * @return $this
163
     */
164
    public function assertDirectoryEmpty($path)
165
    {
166
        PHPUnit::assertEmpty(
167
            $this->allFiles($path), "Directory [{$path}] is not empty."
168
        );
169
 
170
        return $this;
171
    }
172
 
173
    /**
174
     * Determine if a file or directory exists.
175
     *
176
     * @param  string  $path
177
     * @return bool
178
     */
179
    public function exists($path)
180
    {
181
        return $this->driver->has($path);
182
    }
183
 
184
    /**
185
     * Determine if a file or directory is missing.
186
     *
187
     * @param  string  $path
188
     * @return bool
189
     */
190
    public function missing($path)
191
    {
192
        return ! $this->exists($path);
193
    }
194
 
195
    /**
196
     * Determine if a file exists.
197
     *
198
     * @param  string  $path
199
     * @return bool
200
     */
201
    public function fileExists($path)
202
    {
203
        return $this->driver->fileExists($path);
204
    }
205
 
206
    /**
207
     * Determine if a file is missing.
208
     *
209
     * @param  string  $path
210
     * @return bool
211
     */
212
    public function fileMissing($path)
213
    {
214
        return ! $this->fileExists($path);
215
    }
216
 
217
    /**
218
     * Determine if a directory exists.
219
     *
220
     * @param  string  $path
221
     * @return bool
222
     */
223
    public function directoryExists($path)
224
    {
225
        return $this->driver->directoryExists($path);
226
    }
227
 
228
    /**
229
     * Determine if a directory is missing.
230
     *
231
     * @param  string  $path
232
     * @return bool
233
     */
234
    public function directoryMissing($path)
235
    {
236
        return ! $this->directoryExists($path);
237
    }
238
 
239
    /**
240
     * Get the full path for the file at the given "short" path.
241
     *
242
     * @param  string  $path
243
     * @return string
244
     */
245
    public function path($path)
246
    {
247
        return $this->prefixer->prefixPath($path);
248
    }
249
 
250
    /**
251
     * Get the contents of a file.
252
     *
253
     * @param  string  $path
254
     * @return string|null
255
     */
256
    public function get($path)
257
    {
258
        try {
259
            return $this->driver->read($path);
260
        } catch (UnableToReadFile $e) {
261
            throw_if($this->throwsExceptions(), $e);
262
        }
263
    }
264
 
265
    /**
266
     * Create a streamed response for a given file.
267
     *
268
     * @param  string  $path
269
     * @param  string|null  $name
270
     * @param  array  $headers
271
     * @param  string|null  $disposition
272
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
273
     */
274
    public function response($path, $name = null, array $headers = [], $disposition = 'inline')
275
    {
276
        $response = new StreamedResponse;
277
 
278
        if (! array_key_exists('Content-Type', $headers)) {
279
            $headers['Content-Type'] = $this->mimeType($path);
280
        }
281
 
282
        if (! array_key_exists('Content-Length', $headers)) {
283
            $headers['Content-Length'] = $this->size($path);
284
        }
285
 
286
        if (! array_key_exists('Content-Disposition', $headers)) {
287
            $filename = $name ?? basename($path);
288
 
289
            $disposition = $response->headers->makeDisposition(
290
                $disposition, $filename, $this->fallbackName($filename)
291
            );
292
 
293
            $headers['Content-Disposition'] = $disposition;
294
        }
295
 
296
        $response->headers->replace($headers);
297
 
298
        $response->setCallback(function () use ($path) {
299
            $stream = $this->readStream($path);
300
            fpassthru($stream);
301
            fclose($stream);
302
        });
303
 
304
        return $response;
305
    }
306
 
307
    /**
308
     * Create a streamed download response for a given file.
309
     *
310
     * @param  string  $path
311
     * @param  string|null  $name
312
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
313
     */
314
    public function download($path, $name = null, array $headers = [])
315
    {
316
        return $this->response($path, $name, $headers, 'attachment');
317
    }
318
 
319
    /**
320
     * Convert the string to ASCII characters that are equivalent to the given name.
321
     *
322
     * @param  string  $name
323
     * @return string
324
     */
325
    protected function fallbackName($name)
326
    {
327
        return str_replace('%', '', Str::ascii($name));
328
    }
329
 
330
    /**
331
     * Write the contents of a file.
332
     *
333
     * @param  string  $path
334
     * @param  \Psr\Http\Message\StreamInterface|\Illuminate\Http\File|\Illuminate\Http\UploadedFile|string|resource  $contents
335
     * @param  mixed  $options
336
     * @return string|bool
337
     */
338
    public function put($path, $contents, $options = [])
339
    {
340
        $options = is_string($options)
341
                     ? ['visibility' => $options]
342
                     : (array) $options;
343
 
344
        // If the given contents is actually a file or uploaded file instance than we will
345
        // automatically store the file using a stream. This provides a convenient path
346
        // for the developer to store streams without managing them manually in code.
347
        if ($contents instanceof File ||
348
            $contents instanceof UploadedFile) {
349
            return $this->putFile($path, $contents, $options);
350
        }
351
 
352
        try {
353
            if ($contents instanceof StreamInterface) {
354
                $this->driver->writeStream($path, $contents->detach(), $options);
355
 
356
                return true;
357
            }
358
 
359
            is_resource($contents)
360
                ? $this->driver->writeStream($path, $contents, $options)
361
                : $this->driver->write($path, $contents, $options);
362
        } catch (UnableToWriteFile|UnableToSetVisibility $e) {
363
            throw_if($this->throwsExceptions(), $e);
364
 
365
            return false;
366
        }
367
 
368
        return true;
369
    }
370
 
371
    /**
372
     * Store the uploaded file on the disk.
373
     *
374
     * @param  string  $path
375
     * @param  \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string  $file
376
     * @param  mixed  $options
377
     * @return string|false
378
     */
379
    public function putFile($path, $file, $options = [])
380
    {
381
        $file = is_string($file) ? new File($file) : $file;
382
 
383
        return $this->putFileAs($path, $file, $file->hashName(), $options);
384
    }
385
 
386
    /**
387
     * Store the uploaded file on the disk with a given name.
388
     *
389
     * @param  string  $path
390
     * @param  \Illuminate\Http\File|\Illuminate\Http\UploadedFile|string  $file
391
     * @param  string  $name
392
     * @param  mixed  $options
393
     * @return string|false
394
     */
395
    public function putFileAs($path, $file, $name, $options = [])
396
    {
397
        $stream = fopen(is_string($file) ? $file : $file->getRealPath(), 'r');
398
 
399
        // Next, we will format the path of the file and store the file using a stream since
400
        // they provide better performance than alternatives. Once we write the file this
401
        // stream will get closed automatically by us so the developer doesn't have to.
402
        $result = $this->put(
403
            $path = trim($path.'/'.$name, '/'), $stream, $options
404
        );
405
 
406
        if (is_resource($stream)) {
407
            fclose($stream);
408
        }
409
 
410
        return $result ? $path : false;
411
    }
412
 
413
    /**
414
     * Get the visibility for the given path.
415
     *
416
     * @param  string  $path
417
     * @return string
418
     */
419
    public function getVisibility($path)
420
    {
421
        if ($this->driver->visibility($path) == Visibility::PUBLIC) {
422
            return FilesystemContract::VISIBILITY_PUBLIC;
423
        }
424
 
425
        return FilesystemContract::VISIBILITY_PRIVATE;
426
    }
427
 
428
    /**
429
     * Set the visibility for the given path.
430
     *
431
     * @param  string  $path
432
     * @param  string  $visibility
433
     * @return bool
434
     */
435
    public function setVisibility($path, $visibility)
436
    {
437
        try {
438
            $this->driver->setVisibility($path, $this->parseVisibility($visibility));
439
        } catch (UnableToSetVisibility $e) {
440
            throw_if($this->throwsExceptions(), $e);
441
 
442
            return false;
443
        }
444
 
445
        return true;
446
    }
447
 
448
    /**
449
     * Prepend to a file.
450
     *
451
     * @param  string  $path
452
     * @param  string  $data
453
     * @param  string  $separator
454
     * @return bool
455
     */
456
    public function prepend($path, $data, $separator = PHP_EOL)
457
    {
458
        if ($this->fileExists($path)) {
459
            return $this->put($path, $data.$separator.$this->get($path));
460
        }
461
 
462
        return $this->put($path, $data);
463
    }
464
 
465
    /**
466
     * Append to a file.
467
     *
468
     * @param  string  $path
469
     * @param  string  $data
470
     * @param  string  $separator
471
     * @return bool
472
     */
473
    public function append($path, $data, $separator = PHP_EOL)
474
    {
475
        if ($this->fileExists($path)) {
476
            return $this->put($path, $this->get($path).$separator.$data);
477
        }
478
 
479
        return $this->put($path, $data);
480
    }
481
 
482
    /**
483
     * Delete the file at a given path.
484
     *
485
     * @param  string|array  $paths
486
     * @return bool
487
     */
488
    public function delete($paths)
489
    {
490
        $paths = is_array($paths) ? $paths : func_get_args();
491
 
492
        $success = true;
493
 
494
        foreach ($paths as $path) {
495
            try {
496
                $this->driver->delete($path);
497
            } catch (UnableToDeleteFile $e) {
498
                throw_if($this->throwsExceptions(), $e);
499
 
500
                $success = false;
501
            }
502
        }
503
 
504
        return $success;
505
    }
506
 
507
    /**
508
     * Copy a file to a new location.
509
     *
510
     * @param  string  $from
511
     * @param  string  $to
512
     * @return bool
513
     */
514
    public function copy($from, $to)
515
    {
516
        try {
517
            $this->driver->copy($from, $to);
518
        } catch (UnableToCopyFile $e) {
519
            throw_if($this->throwsExceptions(), $e);
520
 
521
            return false;
522
        }
523
 
524
        return true;
525
    }
526
 
527
    /**
528
     * Move a file to a new location.
529
     *
530
     * @param  string  $from
531
     * @param  string  $to
532
     * @return bool
533
     */
534
    public function move($from, $to)
535
    {
536
        try {
537
            $this->driver->move($from, $to);
538
        } catch (UnableToMoveFile $e) {
539
            throw_if($this->throwsExceptions(), $e);
540
 
541
            return false;
542
        }
543
 
544
        return true;
545
    }
546
 
547
    /**
548
     * Get the file size of a given file.
549
     *
550
     * @param  string  $path
551
     * @return int
552
     */
553
    public function size($path)
554
    {
555
        return $this->driver->fileSize($path);
556
    }
557
 
558
    /**
559
     * Get the checksum for a file.
560
     *
561
     * @return string|false
562
     *
563
     * @throws UnableToProvideChecksum
564
     */
565
    public function checksum(string $path, array $options = [])
566
    {
567
        try {
568
            return $this->driver->checksum($path, $options);
569
        } catch (UnableToProvideChecksum $e) {
570
            throw_if($this->throwsExceptions(), $e);
571
 
572
            return false;
573
        }
574
    }
575
 
576
    /**
577
     * Get the mime-type of a given file.
578
     *
579
     * @param  string  $path
580
     * @return string|false
581
     */
582
    public function mimeType($path)
583
    {
584
        try {
585
            return $this->driver->mimeType($path);
586
        } catch (UnableToRetrieveMetadata $e) {
587
            throw_if($this->throwsExceptions(), $e);
588
        }
589
 
590
        return false;
591
    }
592
 
593
    /**
594
     * Get the file's last modification time.
595
     *
596
     * @param  string  $path
597
     * @return int
598
     */
599
    public function lastModified($path)
600
    {
601
        return $this->driver->lastModified($path);
602
    }
603
 
604
    /**
605
     * {@inheritdoc}
606
     */
607
    public function readStream($path)
608
    {
609
        try {
610
            return $this->driver->readStream($path);
611
        } catch (UnableToReadFile $e) {
612
            throw_if($this->throwsExceptions(), $e);
613
        }
614
    }
615
 
616
    /**
617
     * {@inheritdoc}
618
     */
619
    public function writeStream($path, $resource, array $options = [])
620
    {
621
        try {
622
            $this->driver->writeStream($path, $resource, $options);
623
        } catch (UnableToWriteFile|UnableToSetVisibility $e) {
624
            throw_if($this->throwsExceptions(), $e);
625
 
626
            return false;
627
        }
628
 
629
        return true;
630
    }
631
 
632
    /**
633
     * Get the URL for the file at the given path.
634
     *
635
     * @param  string  $path
636
     * @return string
637
     *
638
     * @throws \RuntimeException
639
     */
640
    public function url($path)
641
    {
642
        if (isset($this->config['prefix'])) {
643
            $path = $this->concatPathToUrl($this->config['prefix'], $path);
644
        }
645
 
646
        $adapter = $this->adapter;
647
 
648
        if (method_exists($adapter, 'getUrl')) {
649
            return $adapter->getUrl($path);
650
        } elseif (method_exists($this->driver, 'getUrl')) {
651
            return $this->driver->getUrl($path);
652
        } elseif ($adapter instanceof FtpAdapter || $adapter instanceof SftpAdapter) {
653
            return $this->getFtpUrl($path);
654
        } elseif ($adapter instanceof LocalAdapter) {
655
            return $this->getLocalUrl($path);
656
        } else {
657
            throw new RuntimeException('This driver does not support retrieving URLs.');
658
        }
659
    }
660
 
661
    /**
662
     * Get the URL for the file at the given path.
663
     *
664
     * @param  string  $path
665
     * @return string
666
     */
667
    protected function getFtpUrl($path)
668
    {
669
        return isset($this->config['url'])
670
                ? $this->concatPathToUrl($this->config['url'], $path)
671
                : $path;
672
    }
673
 
674
    /**
675
     * Get the URL for the file at the given path.
676
     *
677
     * @param  string  $path
678
     * @return string
679
     */
680
    protected function getLocalUrl($path)
681
    {
682
        // If an explicit base URL has been set on the disk configuration then we will use
683
        // it as the base URL instead of the default path. This allows the developer to
684
        // have full control over the base path for this filesystem's generated URLs.
685
        if (isset($this->config['url'])) {
686
            return $this->concatPathToUrl($this->config['url'], $path);
687
        }
688
 
689
        $path = '/storage/'.$path;
690
 
691
        // If the path contains "storage/public", it probably means the developer is using
692
        // the default disk to generate the path instead of the "public" disk like they
693
        // are really supposed to use. We will remove the public from this path here.
694
        if (str_contains($path, '/storage/public/')) {
695
            return Str::replaceFirst('/public/', '/', $path);
696
        }
697
 
698
        return $path;
699
    }
700
 
701
    /**
702
     * Determine if temporary URLs can be generated.
703
     *
704
     * @return bool
705
     */
706
    public function providesTemporaryUrls()
707
    {
708
        return method_exists($this->adapter, 'getTemporaryUrl') || isset($this->temporaryUrlCallback);
709
    }
710
 
711
    /**
712
     * Get a temporary URL for the file at the given path.
713
     *
714
     * @param  string  $path
715
     * @param  \DateTimeInterface  $expiration
716
     * @param  array  $options
717
     * @return string
718
     *
719
     * @throws \RuntimeException
720
     */
721
    public function temporaryUrl($path, $expiration, array $options = [])
722
    {
723
        if (method_exists($this->adapter, 'getTemporaryUrl')) {
724
            return $this->adapter->getTemporaryUrl($path, $expiration, $options);
725
        }
726
 
727
        if ($this->temporaryUrlCallback) {
728
            return $this->temporaryUrlCallback->bindTo($this, static::class)(
729
                $path, $expiration, $options
730
            );
731
        }
732
 
733
        throw new RuntimeException('This driver does not support creating temporary URLs.');
734
    }
735
 
736
    /**
621 lars 737
     * Get a temporary upload URL for the file at the given path.
738
     *
739
     * @param  string  $path
740
     * @param  \DateTimeInterface  $expiration
741
     * @param  array  $options
742
     * @return array
743
     *
744
     * @throws \RuntimeException
745
     */
746
    public function temporaryUploadUrl($path, $expiration, array $options = [])
747
    {
748
        if (method_exists($this->adapter, 'temporaryUploadUrl')) {
749
            return $this->adapter->temporaryUploadUrl($path, $expiration, $options);
750
        }
751
 
752
        throw new RuntimeException('This driver does not support creating temporary upload URLs.');
753
    }
754
 
755
    /**
148 lars 756
     * Concatenate a path to a URL.
757
     *
758
     * @param  string  $url
759
     * @param  string  $path
760
     * @return string
761
     */
762
    protected function concatPathToUrl($url, $path)
763
    {
764
        return rtrim($url, '/').'/'.ltrim($path, '/');
765
    }
766
 
767
    /**
768
     * Replace the scheme, host and port of the given UriInterface with values from the given URL.
769
     *
770
     * @param  \Psr\Http\Message\UriInterface  $uri
771
     * @param  string  $url
772
     * @return \Psr\Http\Message\UriInterface
773
     */
774
    protected function replaceBaseUrl($uri, $url)
775
    {
776
        $parsed = parse_url($url);
777
 
778
        return $uri
779
            ->withScheme($parsed['scheme'])
780
            ->withHost($parsed['host'])
781
            ->withPort($parsed['port'] ?? null);
782
    }
783
 
784
    /**
785
     * Get an array of all files in a directory.
786
     *
787
     * @param  string|null  $directory
788
     * @param  bool  $recursive
789
     * @return array
790
     */
791
    public function files($directory = null, $recursive = false)
792
    {
793
        return $this->driver->listContents($directory ?? '', $recursive)
794
            ->filter(function (StorageAttributes $attributes) {
795
                return $attributes->isFile();
796
            })
797
            ->sortByPath()
798
            ->map(function (StorageAttributes $attributes) {
799
                return $attributes->path();
800
            })
801
            ->toArray();
802
    }
803
 
804
    /**
805
     * Get all of the files from the given directory (recursive).
806
     *
807
     * @param  string|null  $directory
808
     * @return array
809
     */
810
    public function allFiles($directory = null)
811
    {
812
        return $this->files($directory, true);
813
    }
814
 
815
    /**
816
     * Get all of the directories within a given directory.
817
     *
818
     * @param  string|null  $directory
819
     * @param  bool  $recursive
820
     * @return array
821
     */
822
    public function directories($directory = null, $recursive = false)
823
    {
824
        return $this->driver->listContents($directory ?? '', $recursive)
825
            ->filter(function (StorageAttributes $attributes) {
826
                return $attributes->isDir();
827
            })
828
            ->map(function (StorageAttributes $attributes) {
829
                return $attributes->path();
830
            })
831
            ->toArray();
832
    }
833
 
834
    /**
835
     * Get all the directories within a given directory (recursive).
836
     *
837
     * @param  string|null  $directory
838
     * @return array
839
     */
840
    public function allDirectories($directory = null)
841
    {
842
        return $this->directories($directory, true);
843
    }
844
 
845
    /**
846
     * Create a directory.
847
     *
848
     * @param  string  $path
849
     * @return bool
850
     */
851
    public function makeDirectory($path)
852
    {
853
        try {
854
            $this->driver->createDirectory($path);
855
        } catch (UnableToCreateDirectory|UnableToSetVisibility $e) {
856
            throw_if($this->throwsExceptions(), $e);
857
 
858
            return false;
859
        }
860
 
861
        return true;
862
    }
863
 
864
    /**
865
     * Recursively delete a directory.
866
     *
867
     * @param  string  $directory
868
     * @return bool
869
     */
870
    public function deleteDirectory($directory)
871
    {
872
        try {
873
            $this->driver->deleteDirectory($directory);
874
        } catch (UnableToDeleteDirectory $e) {
875
            throw_if($this->throwsExceptions(), $e);
876
 
877
            return false;
878
        }
879
 
880
        return true;
881
    }
882
 
883
    /**
884
     * Get the Flysystem driver.
885
     *
886
     * @return \League\Flysystem\FilesystemOperator
887
     */
888
    public function getDriver()
889
    {
890
        return $this->driver;
891
    }
892
 
893
    /**
894
     * Get the Flysystem adapter.
895
     *
896
     * @return \League\Flysystem\FilesystemAdapter
897
     */
898
    public function getAdapter()
899
    {
900
        return $this->adapter;
901
    }
902
 
903
    /**
904
     * Get the configuration values.
905
     *
906
     * @return array
907
     */
908
    public function getConfig()
909
    {
910
        return $this->config;
911
    }
912
 
913
    /**
914
     * Parse the given visibility value.
915
     *
916
     * @param  string|null  $visibility
917
     * @return string|null
918
     *
919
     * @throws \InvalidArgumentException
920
     */
921
    protected function parseVisibility($visibility)
922
    {
923
        if (is_null($visibility)) {
924
            return;
925
        }
926
 
927
        return match ($visibility) {
928
            FilesystemContract::VISIBILITY_PUBLIC => Visibility::PUBLIC,
929
            FilesystemContract::VISIBILITY_PRIVATE => Visibility::PRIVATE,
930
            default => throw new InvalidArgumentException("Unknown visibility: {$visibility}."),
931
        };
932
    }
933
 
934
    /**
935
     * Define a custom temporary URL builder callback.
936
     *
937
     * @param  \Closure  $callback
938
     * @return void
939
     */
940
    public function buildTemporaryUrlsUsing(Closure $callback)
941
    {
942
        $this->temporaryUrlCallback = $callback;
943
    }
944
 
945
    /**
946
     * Determine if Flysystem exceptions should be thrown.
947
     *
948
     * @return bool
949
     */
950
    protected function throwsExceptions(): bool
951
    {
952
        return (bool) ($this->config['throw'] ?? false);
953
    }
954
 
955
    /**
956
     * Pass dynamic methods call onto Flysystem.
957
     *
958
     * @param  string  $method
959
     * @param  array  $parameters
960
     * @return mixed
961
     *
962
     * @throws \BadMethodCallException
963
     */
964
    public function __call($method, array $parameters)
965
    {
966
        if (static::hasMacro($method)) {
967
            return $this->macroCall($method, $parameters);
968
        }
969
 
970
        return $this->driver->{$method}(...$parameters);
971
    }
972
}