Completed
Push — master ( 1a0eba...384b36 )
by Xu
09:28 queued 03:48
created

FilesystemManager::getVisibility()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @link http://www.tintsoft.com/
4
 * @copyright Copyright (c) 2012 TintSoft Technology Co. Ltd.
5
 * @license http://www.tintsoft.com/license/
6
 */
7
8
namespace yuncms\filesystem;
9
10
use Closure;
11
use Yii;
12
use yii\base\Component;
13
use yii\base\InvalidArgumentException;
14
use yii\base\InvalidConfigException;
15
use League\Flysystem\FilesystemNotFoundException;
16
17
/**
18
 * Class Storage
19
 *
20
 * @author Tongle Xu <[email protected]>
21
 * @since 3.0
22
 */
23
class FilesystemManager extends Component
24
{
25
26
    public $default = 'local';
27
28
    /**
29
     * @var array filesystem parameters (name => value).
30
     */
31
    public $params = [];
32
33
    /**
34
     * @var array shared disk instances indexed by their IDs
35
     */
36
    private $_filesystems = [];
37
38
    /**
39
     * @var array filesystem definitions indexed by their IDs
40
     */
41
    private $_definitions = [];
42
43
    /**
44
     * Getter magic method.
45
     * This method is overridden to support accessing filesystems like reading properties.
46
     * @param string $name filesystem or property name
47
     * @return mixed the named property value
48
     * @throws InvalidConfigException
49
     * @throws \yii\base\UnknownPropertyException
50
     */
51
    public function __get($name)
52
    {
53
        if ($this->has($name)) {
54
            return $this->get($name);
55
        }
56
57
        return parent::__get($name);
58
    }
59
60
    /**
61
     * Checks if a property value is null.
62
     * This method overrides the parent implementation by checking if the named filesystem is loaded.
63
     * @param string $name the property name or the event name
64
     * @return bool whether the property value is null
65
     */
66
    public function __isset($name)
67
    {
68
        if ($this->has($name)) {
69
            return true;
70
        }
71
72
        return parent::__isset($name);
73
    }
74
75
    /**
76
     * Returns a value indicating whether the locator has the specified filesystem definition or has instantiated the filesystem.
77
     * This method may return different results depending on the value of `$checkInstance`.
78
     *
79
     * - If `$checkInstance` is false (default), the method will return a value indicating whether the locator has the specified
80
     *   filesystem definition.
81
     * - If `$checkInstance` is true, the method will return a value indicating whether the locator has
82
     *   instantiated the specified filesystem.
83
     *
84
     * @param string $id filesystem ID (e.g. `local`).
85
     * @param bool $checkInstance whether the method should check if the filesystem is shared and instantiated.
86
     * @return bool whether the locator has the specified filesystem definition or has instantiated the filesystem.
87
     * @see set()
88
     */
89
    public function has($id, $checkInstance = false)
90
    {
91
        return $checkInstance ? isset($this->_filesystems[$id]) : isset($this->_definitions[$id]);
92
    }
93
94
    /**
95
     * Returns the filesystem instance with the specified ID.
96
     *
97
     * @param string $id filesystem ID (e.g. `db`).
98
     * @param bool $throwException whether to throw an exception if `$id` is not registered with the locator before.
99
     * @return \League\Flysystem\Filesystem|object|null the filesystem of the specified ID. If `$throwException` is false and `$id`
100
     * is not registered before, null will be returned.
101
     * @throws InvalidConfigException if `$id` refers to a nonexistent filesystem ID
102
     * @see has()
103
     * @see set()
104
     */
105
    public function get($id, $throwException = true)
106
    {
107
        if (isset($this->_filesystems[$id])) {
108
            return $this->_filesystems[$id];
109
        }
110
111
        if (isset($this->_definitions[$id])) {
112
            $definition = $this->_definitions[$id];
113
            if (is_object($definition) && !$definition instanceof Closure) {
114
                return $this->_filesystems[$id] = $definition;
115
            }
116
117
            return $this->_filesystems[$id] = Yii::createObject($definition);
118
        } elseif ($throwException) {
119
            throw new InvalidConfigException("Unknown filesystem ID: $id");
120
        }
121
122
        return null;
123
    }
124
125
    /**
126
     * Registers a filesystem definition with this locator.
127
     *
128
     * For example,
129
     *
130
     * ```php
131
     * // a class name
132
     * $locator->set('cache', 'yii\caching\FileCache');
133
     *
134
     * // a configuration array
135
     * $locator->set('db', [
136
     *     'class' => 'yii\db\Connection',
137
     *     'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
138
     *     'username' => 'root',
139
     *     'password' => '',
140
     *     'charset' => 'utf8',
141
     * ]);
142
     *
143
     * // an anonymous function
144
     * $locator->set('cache', function ($params) {
145
     *     return new \yii\caching\FileCache;
146
     * });
147
     *
148
     * // an instance
149
     * $locator->set('cache', new \yii\caching\FileCache);
150
     * ```
151
     *
152
     * If a filesystem definition with the same ID already exists, it will be overwritten.
153
     *
154
     * @param string $id filesystem ID (e.g. `db`).
155
     * @param mixed $definition the filesystem definition to be registered with this locator.
156
     * It can be one of the following:
157
     *
158
     * - a class name
159
     * - a configuration array: the array contains name-value pairs that will be used to
160
     *   initialize the property values of the newly created object when [[get()]] is called.
161
     *   The `class` element is required and stands for the the class of the object to be created.
162
     * - a PHP callable: either an anonymous function or an array representing a class method (e.g. `['Foo', 'bar']`).
163
     *   The callable will be called by [[get()]] to return an object associated with the specified filesystem ID.
164
     * - an object: When [[get()]] is called, this object will be returned.
165
     *
166
     * @throws InvalidConfigException if the definition is an invalid configuration array
167
     */
168
    public function set($id, $definition)
169
    {
170
        unset($this->_filesystems[$id]);
171
172
        if ($definition === null) {
173
            unset($this->_definitions[$id]);
174
            return;
175
        }
176
177
        if (is_object($definition) || is_callable($definition, true)) {
178
            // an object, a class name, or a PHP callable
179
            $this->_definitions[$id] = $definition;
180
        } elseif (is_array($definition)) {
181
            // a configuration array
182
            if (isset($definition['class'])) {
183
                $this->_definitions[$id] = $definition;
184
            } else {
185
                throw new InvalidConfigException("The configuration for the \"$id\" filesystem must contain a \"class\" element.");
186
            }
187
        } else {
188
            throw new InvalidConfigException("Unexpected configuration type for the \"$id\" filesystem: " . gettype($definition));
189
        }
190
    }
191
192
    /**
193
     * Removes the filesystem from the locator.
194
     * @param string $id the filesystem ID
195
     */
196
    public function clear($id)
197
    {
198
        unset($this->_definitions[$id], $this->_filesystems[$id]);
199
    }
200
201
    /**
202
     * 获取磁盘
203
     * @param string|null $filesystem
204
     * @return \League\Flysystem\Filesystem
205
     * @throws InvalidConfigException
206
     */
207
    public function disk($filesystem = null)
208
    {
209
        $filesystem = !is_null($filesystem) ? $filesystem : $this->default;
210
        return $this->get($filesystem);
211
    }
212
213
    /**
214
     * Returns the list of the filesystem definitions or the loaded filesystem instances.
215
     * @param bool $returnDefinitions whether to return filesystem definitions instead of the loaded filesystem instances.
216
     * @return array the list of the filesystem definitions or the loaded filesystem instances (ID => definition or instance).
217
     */
218
    public function getFilesystems($returnDefinitions = true)
219
    {
220
        return $returnDefinitions ? $this->_definitions : $this->_filesystems;
221
    }
222
223
    /**
224
     * Registers a set of filesystem definitions in this locator.
225
     *
226
     * This is the bulk version of [[set()]]. The parameter should be an array
227
     * whose keys are filesystem IDs and values the corresponding filesystem definitions.
228
     *
229
     * For more details on how to specify filesystem IDs and definitions, please refer to [[set()]].
230
     *
231
     * If a filesystem definition with the same ID already exists, it will be overwritten.
232
     *
233
     * The following is an example for registering two filesystem definitions:
234
     *
235
     * ```php
236
     * [
237
     *     'local' => [
238
     *         'class' => 'yuncms\filesystem\adapters\LocalAdapter',
239
     *         'path' => '@root/storage',
240
     *     ],
241
     * ]
242
     * ```
243
     *
244
     * @param array $filesystems filesystem definitions or instances
245
     * @throws InvalidConfigException
246
     */
247
    public function setFilesystems($filesystems)
248
    {
249
        foreach ($filesystems as $id => $filesystem) {
250
            $this->set($id, $filesystem);
251
        }
252
    }
253
254
    /**
255
     * Retrieve the prefix from an arguments array.
256
     *
257
     * @param array $arguments
258
     *
259
     * @throws InvalidArgumentException
260
     *
261
     * @return array [:prefix, :arguments]
262
     */
263
    public function filterPrefix(array $arguments)
264
    {
265
        if (empty($arguments)) {
266
            throw new InvalidArgumentException('At least one argument needed');
267
        }
268
269
        $path = array_shift($arguments);
270
271
        if (!is_string($path)) {
272
            throw new InvalidArgumentException('First argument should be a string');
273
        }
274
275
        list($prefix, $path) = $this->getPrefixAndPath($path);
276
        array_unshift($arguments, $path);
277
278
        return [$prefix, $arguments];
279
    }
280
281
    /**
282
     * 列出内容
283
     * @param string $directory
284
     * @param bool $recursive
285
     *
286
     * @throws InvalidArgumentException
287
     * @throws FilesystemNotFoundException
288
     *
289
     * @return array
290
     * @throws InvalidConfigException
291
     */
292
    public function listContents($directory = '', $recursive = false)
293
    {
294
        list($prefix, $directory) = $this->getPrefixAndPath($directory);
295
        $filesystem = $this->get($prefix);
296
        $result = $filesystem->listContents($directory, $recursive);
297
        foreach ($result as &$file) {
298
            $file['filesystem'] = $prefix;
299
        }
300
        return $result;
301
    }
302
303
    /**
304
     * 在两个磁盘之间复制文件
305
     * @param string $from
306
     * @param string $to
307
     * @param array $config
308
     *
309
     * @throws InvalidArgumentException
310
     * @throws FilesystemNotFoundException
311
     *
312
     * @return bool
313
     * @throws InvalidConfigException
314
     */
315
    public function copy($from, $to, array $config = [])
316
    {
317
        list($prefixFrom, $from) = $this->getPrefixAndPath($from);
318
        $buffer = $this->get($prefixFrom)->readStream($from);
319
        if ($buffer === false) {
320
            return false;
321
        }
322
        list($prefixTo, $to) = $this->getPrefixAndPath($to);
323
        $result = $this->get($prefixTo)->writeStream($to, $buffer, $config);
324
        if (is_resource($buffer)) {
325
            fclose($buffer);
326
        }
327
        return $result;
328
    }
329
330
    /**
331
     * 文件是否存在
332
     * @param string $path
333
     * @return bool
334
     * @throws InvalidConfigException
335
     */
336
    public function hasFile($path)
337
    {
338
        list($prefix, $path) = $this->getPrefixAndPath($path);
339
        return $this->get($prefix)->has($path);
340
    }
341
342
    /**
343
     * 移动文件
344
     *
345
     * @param string $from
346
     * @param string $to
347
     * @param array $config
348
     *
349
     * @return bool
350
     * @throws InvalidConfigException
351
     */
352
    public function move($from, $to, array $config = [])
353
    {
354
        list($prefixFrom, $pathFrom) = $this->getPrefixAndPath($from);
355
        list($prefixTo, $pathTo) = $this->getPrefixAndPath($to);
356
357
        if ($prefixFrom === $prefixTo) {
358
            $filesystem = $this->get($prefixFrom);
359
            $renamed = $filesystem->rename($pathFrom, $pathTo);
360
361
            if ($renamed && isset($config['visibility'])) {
362
                return $filesystem->setVisibility($pathTo, $config['visibility']);
363
            }
364
365
            return $renamed;
366
        }
367
368
        $copied = $this->copy($from, $to, $config);
369
370
        if ($copied) {
371
            return $this->delete($from);
372
        }
373
374
        return false;
375
    }
376
377
    /**
378
     * 向文件追加内容
379
     * @param string $path
380
     * @param string $contents
381
     * @param array $config
382
     * @return bool
383
     * @throws InvalidConfigException
384
     */
385
    public function put($path, $contents, $config = [])
386
    {
387
        list($prefix, $path) = $this->getPrefixAndPath($path);
388
        return $this->get($prefix)->put($path, $contents, $config);
389
    }
390
391
    /**
392
     * 向文件追加流内容
393
     * @param string $path
394
     * @param resource $contents
395
     * @param array $config
396
     * @return bool
397
     * @throws InvalidConfigException
398
     */
399
    public function putStream($path, $contents, $config = [])
400
    {
401
        list($prefix, $path) = $this->getPrefixAndPath($path);
402
        return $this->get($prefix)->putStream($path, $contents, $config);
403
    }
404
405
    /**
406
     * 读文件
407
     * @param string $path
408
     * @return bool|false|string
409
     * @throws InvalidConfigException
410
     */
411
    public function read($path)
412
    {
413
        list($prefix, $path) = $this->getPrefixAndPath($path);
414
        return $this->get($prefix)->read($path);
415
    }
416
417
    /**
418
     * 读取流
419
     * @param string $path
420
     * @return bool|false|resource
421
     * @throws InvalidConfigException
422
     */
423
    public function readStream($path)
424
    {
425
        list($prefix, $path) = $this->getPrefixAndPath($path);
426
        return $this->get($prefix)->readStream($path);
427
    }
428
429
    /**
430
     * 读取并删除文件
431
     * @param string $path
432
     * @return bool|false|string
433
     * @throws InvalidConfigException
434
     */
435
    public function readAndDelete($path)
436
    {
437
        list($prefix, $path) = $this->getPrefixAndPath($path);
438
        return $this->get($prefix)->readAndDelete($path);
439
    }
440
441
    /**
442
     * 更新文件
443
     * @param string $path
444
     * @param string $contents
445
     * @param array $config
446
     * @return bool
447
     * @throws InvalidConfigException
448
     */
449
    public function update($path, $contents, $config = [])
450
    {
451
        list($prefix, $path) = $this->getPrefixAndPath($path);
452
        return $this->get($prefix)->update($path, $contents, $config);
453
    }
454
455
    /**
456
     * 更新流
457
     * @param string $path
458
     * @param resource $resource
459
     * @param array $config
460
     * @return bool
461
     * @throws InvalidConfigException
462
     */
463
    public function updateStream($path, $resource, $config = [])
464
    {
465
        list($prefix, $path) = $this->getPrefixAndPath($path);
466
        return $this->get($prefix)->updateStream($path, $resource, $config);
467
    }
468
469
    /**
470
     * 重命名文件
471
     * @param string $path
472
     * @param string $newpath
473
     * @return bool
474
     * @throws InvalidConfigException
475
     */
476
    public function rename($path, $newpath)
477
    {
478
        return $this->move($path, $newpath);
479
    }
480
481
    /**
482
     * 删除目录
483
     * @param string $dirname
484
     * @return bool
485
     * @throws InvalidConfigException
486
     */
487
    public function deleteDir($dirname)
488
    {
489
        list($prefix, $path) = $this->getPrefixAndPath($dirname);
490
        return $this->get($prefix)->deleteDir($path);
491
    }
492
493
    /**
494
     * 写文件
495
     * @param string $path
496
     * @param string $contents
497
     * @param array $config
498
     * @return bool
499
     * @throws InvalidConfigException
500
     */
501
    public function write($path, $contents, array $config = [])
502
    {
503
        list($prefix, $path) = $this->getPrefixAndPath($path);
504
        return $this->get($prefix)->write($path, $contents, $config);
505
    }
506
507
    /**
508
     * 将流写入文件
509
     * @param string $path
510
     * @param resource $resource
511
     * @param array $config
512
     * @return bool
513
     * @throws InvalidConfigException
514
     */
515
    public function writeStream($path, $resource, array $config = [])
516
    {
517
        list($prefix, $path) = $this->getPrefixAndPath($path);
518
        return $this->get($prefix)->writeStream($path, $resource, $config);
519
    }
520
521
    /**
522
     * 删除文件
523
     * @param string $path
524
     * @return bool
525
     * @throws InvalidConfigException
526
     */
527
    public function delete($path)
528
    {
529
        list($prefix, $path) = $this->getPrefixAndPath($path);
530
        return $this->get($prefix)->delete($path);
531
    }
532
533
    /**
534
     * 创建目录
535
     * @param string $path
536
     * @param array $config
537
     * @return bool
538
     * @throws InvalidConfigException
539
     */
540
    public function createDir($path, $config = [])
541
    {
542
        list($prefix, $path) = $this->getPrefixAndPath($path);
543
        return $this->get($prefix)->createDir($path, $config);
544
    }
545
546
    /**
547
     * 列出指定路径文件
548
     * @param string $directory
549
     * @param bool $recursive
550
     * @return array
551
     * @throws InvalidConfigException
552
     */
553
    public function listFiles($directory = '', $recursive = false)
554
    {
555
        list($prefix, $path) = $this->getPrefixAndPath($directory);
556
        return $this->get($prefix)->listFiles($path, $recursive);
557
    }
558
559
    /**
560
     * 列出路径
561
     * @param string $directory
562
     * @param bool $recursive
563
     * @return array
564
     * @throws InvalidConfigException
565
     */
566
    public function listPaths($directory = '', $recursive = false)
567
    {
568
        list($prefix, $path) = $this->getPrefixAndPath($directory);
569
        return $this->get($prefix)->listPaths($path, $recursive);
570
    }
571
572
    /**
573
     * 获取 源数据
574
     * @param string $path
575
     * @param array $metadata
576
     * @return array
577
     * @throws InvalidConfigException
578
     */
579
    public function getWithMetadata($path, array $metadata)
580
    {
581
        list($prefix, $path) = $this->getPrefixAndPath($path);
582
        return $this->get($prefix)->getWithMetadata($path, $metadata);
583
    }
584
585
    /**
586
     * 获取文件 Mimetype
587
     * @param string $path
588
     * @return bool|false|string
589
     * @throws InvalidConfigException
590
     */
591
    public function getMimetype($path)
592
    {
593
        list($prefix, $path) = $this->getPrefixAndPath($path);
594
        return $this->get($prefix)->getMimetype($path);
595
    }
596
597
    /**
598
     * 获取文件创建的时间戳
599
     * @param string $path
600
     * @return bool|false|string
601
     * @throws InvalidConfigException
602
     */
603
    public function getTimestamp($path)
604
    {
605
        list($prefix, $path) = $this->getPrefixAndPath($path);
606
        return $this->get($prefix)->getTimestamp($path);
607
    }
608
609
    /**
610
     * 获取文件可见性
611
     * @param string $path
612
     * @return bool|false|string
613
     * @throws InvalidConfigException
614
     */
615
    public function getVisibility($path)
616
    {
617
        list($prefix, $path) = $this->getPrefixAndPath($path);
618
        return $this->get($prefix)->getVisibility($path);
619
    }
620
621
    /**
622
     * 获取文件大小
623
     * @param string $path
624
     * @return bool|false|int
625
     * @throws InvalidConfigException
626
     */
627
    public function getSize($path)
628
    {
629
        list($prefix, $path) = $this->getPrefixAndPath($path);
630
        return $this->get($prefix)->getSize($path);
631
    }
632
633
    /**
634
     * 设置文件可见性
635
     * @param string $path
636
     * @param string $visibility
637
     * @return bool
638
     * @throws InvalidConfigException
639
     */
640
    public function setVisibility($path, $visibility)
641
    {
642
        list($prefix, $path) = $this->getPrefixAndPath($path);
643
        return $this->get($prefix)->setVisibility($path, $visibility);
644
    }
645
646
    /**
647
     * 获取Metadata
648
     * @param string $path
649
     * @return array|false
650
     * @throws InvalidConfigException
651
     */
652
    public function getMetadata($path)
653
    {
654
        list($prefix, $path) = $this->getPrefixAndPath($path);
655
        return $this->get($prefix)->getMetadata($path);
656
    }
657
658
    /**
659
     * @param string $path
660
     *
661
     * @throws InvalidArgumentException
662
     *
663
     * @return string[] [:prefix, :path]
664
     */
665
    protected function getPrefixAndPath($path)
666
    {
667
        if (strpos($path, '://') < 1) {
668
            throw new InvalidArgumentException('No prefix detected in path: ' . $path);
669
        }
670
671
        return explode('://', $path, 2);
672
    }
673
}