Passed
Pull Request — master (#407)
by Kirill
05:39
created

Storage   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
c 1
b 0
f 0
dl 0
loc 151
rs 10
wmc 21

9 Methods

Rating   Name   Duplication   Size   Complexity  
A add() 0 7 3
A file() 0 5 1
A getIterator() 0 3 1
A uriToString() 0 14 6
A count() 0 3 1
A parseUri() 0 21 5
A withDefault() 0 6 1
A bucket() 0 9 2
A __construct() 0 3 1
1
<?php
2
3
/**
4
 * This file is part of Spiral Framework package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Storage;
13
14
use Psr\Http\Message\UriInterface;
15
use Spiral\Storage\Exception\InvalidArgumentException;
16
use Spiral\Storage\Storage\ReadableTrait;
17
use Spiral\Storage\Storage\WritableTrait;
18
19
/**
20
 * @psalm-import-type IdType from StorageInterface
21
 * @see StorageInterface
22
 */
23
final class Storage implements MutableStorageInterface
24
{
25
    use ReadableTrait;
26
    use WritableTrait;
27
28
    /**
29
     * @var string
30
     */
31
    public const DEFAULT_STORAGE = 'default';
32
33
    /**
34
     * @var string
35
     */
36
    private const ERROR_REDEFINITION = 'Can not redefine already defined bucket `%s`';
37
38
    /**
39
     * @var string
40
     */
41
    private const ERROR_NOT_FOUND = 'Bucket `%s` has not been defined';
42
43
    /**
44
     * @var array<string, BucketInterface>
45
     */
46
    private $buckets = [];
47
48
    /**
49
     * @var string
50
     */
51
    private $default;
52
53
    /**
54
     * @param string $name
55
     */
56
    public function __construct(string $name = self::DEFAULT_STORAGE)
57
    {
58
        $this->default = $name;
59
    }
60
61
    /**
62
     * @param string $name
63
     * @return $this
64
     */
65
    public function withDefault(string $name): StorageInterface
66
    {
67
        $self = clone $this;
68
        $self->default = $name;
69
70
        return $self;
71
    }
72
73
    /**
74
     * {@inheritDoc}
75
     */
76
    public function bucket(string $name = null): BucketInterface
77
    {
78
        $name = $name ?? $this->default;
79
80
        if (!isset($this->buckets[$name])) {
81
            throw new InvalidArgumentException(\sprintf(self::ERROR_NOT_FOUND, $name));
82
        }
83
84
        return $this->buckets[$name];
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     */
90
    public function file($id): FileInterface
91
    {
92
        [$bucket, $file] = $this->parseUri($id);
93
94
        return $this->bucket($bucket)->file($file);
95
    }
96
97
    /**
98
     * {@inheritDoc}
99
     */
100
    public function add(string $name, BucketInterface $storage, bool $overwrite = false): void
101
    {
102
        if ($overwrite === false && isset($this->buckets[$name])) {
103
            throw new \InvalidArgumentException(\sprintf(self::ERROR_REDEFINITION, $name));
104
        }
105
106
        $this->buckets[$name] = $storage;
107
    }
108
109
    /**
110
     * {@inheritDoc}
111
     */
112
    public function getIterator(): \Traversable
113
    {
114
        return new \ArrayIterator($this->buckets);
115
    }
116
117
    /**
118
     * {@inheritDoc}
119
     */
120
    public function count(): int
121
    {
122
        return \count($this->buckets);
123
    }
124
125
    /**
126
     * @param IdType $uri
0 ignored issues
show
Bug introduced by
The type Spiral\Storage\IdType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
127
     * @param bool $withScheme
128
     * @return array{0: string|null, 1: string}
129
     * @throws InvalidArgumentException
130
     */
131
    protected function parseUri($uri, bool $withScheme = true): array
132
    {
133
        $uri = $this->uriToString($uri);
134
        $result = \parse_url($uri);
135
136
        if ($result === false) {
137
            $message = 'URI argument must be a valid URI in "[STORAGE]://[PATH_TO_FILE]" format, but `%s` given';
138
            throw new InvalidArgumentException(\sprintf($message, $uri));
139
        }
140
141
        if (!isset($result['scheme'])) {
142
            $result['scheme'] = $withScheme ? $this->default : null;
143
        }
144
145
        if (!isset($result['host'])) {
146
            $result['host'] = '';
147
        }
148
149
        return [
150
            $result['scheme'] ?? null,
151
            $result['host'] . \rtrim($result['path'] ?? '', '/'),
152
        ];
153
    }
154
155
    /**
156
     * @param IdType $uri
157
     * @return string
158
     * @throws InvalidArgumentException
159
     */
160
    private function uriToString($uri): string
161
    {
162
        switch (true) {
163
            case $uri instanceof UriInterface:
164
            case $uri instanceof \Stringable:
165
            case \is_object($uri) && \method_exists($uri, '__toString'):
166
                return (string)$uri;
167
168
            case \is_string($uri):
169
                return $uri;
170
171
            default:
172
                $message = 'File URI must be a string or instance of Stringable interface, but %s given';
173
                throw new InvalidArgumentException(\sprintf($message, \get_debug_type($uri)));
174
        }
175
    }
176
}
177