Passed
Pull Request — master (#1115)
by Maxim
22:29
created

Storage   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Test Coverage

Coverage 23.08%

Importance

Changes 0
Metric Value
wmc 16
eloc 38
dl 0
loc 109
ccs 9
cts 39
cp 0.2308
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A count() 0 3 1
A add() 0 7 3
A file() 0 5 1
A withDefault() 0 6 1
A __construct() 0 3 1
A getIterator() 0 3 1
A parseUri() 0 21 5
A bucket() 0 9 2
A uriToString() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Storage;
6
7
use Psr\Http\Message\UriInterface;
8
use Spiral\Storage\Exception\InvalidArgumentException;
9
use Spiral\Storage\Storage\ReadableTrait;
10
use Spiral\Storage\Storage\WritableTrait;
11
12
/**
13
 * @see StorageInterface
14
 */
15
final class Storage implements MutableStorageInterface
16
{
17
    use ReadableTrait;
18
    use WritableTrait;
19
20
    /**
21
     * @var string
22
     */
23
    public const DEFAULT_STORAGE = 'default';
24
25
    /**
26
     * @var string
27
     */
28
    private const ERROR_REDEFINITION = 'Can not redefine already defined bucket `%s`';
29
30
    /**
31
     * @var string
32
     */
33
    private const ERROR_NOT_FOUND = 'Bucket `%s` has not been defined';
34
35
    /**
36
     * @var array<string, BucketInterface>
37
     */
38
    private array $buckets = [];
39
    private string $default;
40
41 5
    public function __construct(string $name = self::DEFAULT_STORAGE)
42
    {
43 5
        $this->default = $name;
44
    }
45
46
    public function withDefault(string $name): StorageInterface
47
    {
48
        $self = clone $this;
49
        $self->default = $name;
50
51
        return $self;
52
    }
53
54 1
    public function bucket(string $name = null): BucketInterface
55
    {
56 1
        $name ??= $this->default;
57
58 1
        if (!isset($this->buckets[$name])) {
59
            throw new InvalidArgumentException(\sprintf(self::ERROR_NOT_FOUND, $name));
60
        }
61
62 1
        return $this->buckets[$name];
63
    }
64
65
    public function file(string|\Stringable $id): FileInterface
66
    {
67
        [$bucket, $file] = $this->parseUri($id);
68
69
        return $this->bucket($bucket)->file($file);
70
    }
71
72 1
    public function add(string $name, BucketInterface $storage, bool $overwrite = false): void
73
    {
74 1
        if (!$overwrite && isset($this->buckets[$name])) {
75
            throw new \InvalidArgumentException(\sprintf(self::ERROR_REDEFINITION, $name));
76
        }
77
78 1
        $this->buckets[$name] = $storage;
79
    }
80
81
    public function getIterator(): \Traversable
82
    {
83
        return new \ArrayIterator($this->buckets);
84
    }
85
86
    public function count(): int
87
    {
88
        return \count($this->buckets);
89
    }
90
91
    /**
92
     * @return array{0: string|null, 1: string}
93
     * @throws InvalidArgumentException
94
     */
95
    protected function parseUri(string|\Stringable $uri, bool $withScheme = true): array
96
    {
97
        $uri = $this->uriToString($uri);
98
        $result = \parse_url($uri);
99
100
        if ($result === false) {
101
            $message = 'URI argument must be a valid URI in "[STORAGE]://[PATH_TO_FILE]" format, but `%s` given';
102
            throw new InvalidArgumentException(\sprintf($message, $uri));
103
        }
104
105
        if (!isset($result['scheme'])) {
106
            $result['scheme'] = $withScheme ? $this->default : null;
107
        }
108
109
        if (!isset($result['host'])) {
110
            $result['host'] = '';
111
        }
112
113
        return [
114
            $result['scheme'] ?? null,
115
            $result['host'] . \rtrim($result['path'] ?? '', '/'),
116
        ];
117
    }
118
119
    private function uriToString(string|\Stringable $uri): string
120
    {
121
        return match (true) {
122
            \is_string($uri) => $uri,
123
            default => (string) $uri
124
        };
125
    }
126
}
127