Completed
Branch develop (c2aa4c)
by Anton
05:17
created

StorageBucket::getPrefix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\Storage\Entities;
9
10
use Psr\Http\Message\UploadedFileInterface;
11
use Psr\Log\LoggerAwareInterface;
12
use Spiral\Core\Component;
13
use Spiral\Core\Container\InjectableInterface;
14
use Spiral\Debug\Traits\BenchmarkTrait;
15
use Spiral\Debug\Traits\LoggerTrait;
16
use Spiral\Files\FilesInterface;
17
use Spiral\Files\Streams\StreamableInterface;
18
use Spiral\Storage\BucketInterface;
19
use Spiral\Storage\ServerInterface;
20
use Spiral\Storage\StorageInterface;
21
use Spiral\Storage\StorageManager;
22
23
/**
24
 * Default implementation of storage bucket.
25
 */
26
class StorageBucket extends Component implements
27
    BucketInterface,
28
    LoggerAwareInterface,
29
    InjectableInterface
30
{
31
    /**
32
     * Most of storage operations are pretty slow, we might record and explain all of them.
33
     */
34
    use BenchmarkTrait, LoggerTrait;
35
36
    /**
37
     * This is magick constant used by Spiral Constant, it helps system to resolve controllable
38
     * injections, once set - Container will ask specific binding for injection.
39
     */
40
    const INJECTOR = StorageManager::class;
41
42
    /**
43
     * @var string
44
     */
45
    private $name = '';
46
47
    /**
48
     * @var string
49
     */
50
    private $prefix = '';
51
52
    /**
53
     * @var ServerInterface
54
     */
55
    private $server = null;
56
57
    /**
58
     * @var array
59
     */
60
    private $options = [];
61
62
    /**
63
     * @invisible
64
     * @var StorageInterface
65
     */
66
    protected $storage = null;
67
68
    /**
69
     * @invisible
70
     * @var FilesInterface
71
     */
72
    protected $files = null;
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function __construct(
78
        $name,
79
        $prefix,
80
        array $options,
81
        ServerInterface $server,
82
        StorageInterface $storage,
83
        FilesInterface $files
84
    ) {
85
        $this->name = $name;
86
        $this->prefix = $prefix;
87
        $this->options = $options;
88
        $this->server = $server;
89
        $this->storage = $storage;
90
        $this->files = $files;
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function getName()
97
    {
98
        return $this->name;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    public function server()
105
    {
106
        return $this->server;
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    public function getOption($name, $default = null)
113
    {
114
        return isset($this->options[$name]) ? $this->options[$name] : $default;
115
    }
116
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function getPrefix()
122
    {
123
        return $this->prefix;
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function hasAddress($address)
130
    {
131
        if (strpos($address, $this->prefix) === 0) {
132
            return strlen($this->prefix);
133
        }
134
135
        return false;
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    public function buildAddress($name)
142
    {
143
        return $this->prefix . $name;
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149 View Code Duplication
    public function exists($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
    {
151
        $this->logger()->info(
152
            "Check existence of '{$this->buildAddress($name)}' at '{$this->getName()}'."
153
        );
154
155
        $benchmark = $this->benchmark($this->getName(), "exists::{$this->buildAddress($name)}");
156
        try {
157
            return (bool)$this->server->exists($this, $name);
158
        } finally {
159
            $this->benchmark($benchmark);
160
        }
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166 View Code Duplication
    public function size($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
167
    {
168
        $this->logger()->info(
169
            "Get size of '{$this->buildAddress($name)}' at '{$this->getName()}'."
170
        );
171
172
        $benchmark = $this->benchmark($this->getName(), "size::{$this->buildAddress($name)}");
173
        try {
174
            return $this->server->size($this, $name);
175
        } finally {
176
            $this->benchmark($benchmark);
177
        }
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183
    public function put($name, $source)
184
    {
185
        $this->logger()->info(
186
            "Put '{$this->buildAddress($name)}' at '{$this->getName()}' server."
187
        );
188
189
        if ($source instanceof UploadedFileInterface || $source instanceof StreamableInterface) {
190
            //Known simplification for UploadedFile
191
            $source = $source->getStream();
192
        }
193
194
        if (is_resource($source)) {
195
            $source = \GuzzleHttp\Psr7\stream_for($source);
196
        }
197
198
        $benchmark = $this->benchmark($this->getName(), "put::{$this->buildAddress($name)}");
199
        try {
200
            $this->server->put($this, $name, $source);
201
202
            //Reopening
203
            return $this->storage->open($this->buildAddress($name));
204
        } finally {
205
            $this->benchmark($benchmark);
206
        }
207
    }
208
209
    /**
210
     * {@inheritdoc}
211
     */
212 View Code Duplication
    public function allocateFilename($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
213
    {
214
        $this->logger()->info(
215
            "Allocate filename of '{$this->buildAddress($name)}' at '{$this->getName()}' server."
216
        );
217
218
        $benchmark = $this->benchmark(
219
            $this->getName(), "filename::{$this->buildAddress($name)}"
220
        );
221
222
        try {
223
            return $this->server()->allocateFilename($this, $name);
224
        } finally {
225
            $this->benchmark($benchmark);
226
        }
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232 View Code Duplication
    public function allocateStream($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
233
    {
234
        $this->logger()->info(
235
            "Get stream for '{$this->buildAddress($name)}' at '{$this->server}' server."
236
        );
237
238
        $benchmark = $this->benchmark(
239
            $this->getName(), "stream::{$this->buildAddress($name)}"
240
        );
241
242
        try {
243
            return $this->server()->allocateStream($this, $name);
244
        } finally {
245
            $this->benchmark($benchmark);
246
        }
247
    }
248
249
    /**
250
     * {@inheritdoc}
251
     */
252 View Code Duplication
    public function delete($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
253
    {
254
        $this->logger()->info(
255
            "Delete '{$this->buildAddress($name)}' at '{$this->server}' server."
256
        );
257
258
        $benchmark = $this->benchmark(
259
            $this->getName(), "delete::{$this->buildAddress($name)}"
260
        );
261
262
        try {
263
            $this->server->delete($this, $name);
264
        } finally {
265
            $this->benchmark($benchmark);
266
        }
267
    }
268
269
    /**
270
     * {@inheritdoc}
271
     */
272
    public function rename($oldname, $newname)
273
    {
274
        if ($oldname == $newname) {
275
            return true;
276
        }
277
278
        $this->logger()->info(
279
            "Rename '{$this->buildAddress($oldname)}' to '{$this->buildAddress($newname)}' "
280
            . "at '{$this->server}' server."
281
        );
282
283
        $benchmark = $this->benchmark(
284
            $this->getName(), "rename::{$this->buildAddress($oldname)}"
285
        );
286
287
        try {
288
            $this->server->rename($this, $oldname, $newname);
289
290
            return $this->buildAddress($newname);
291
        } finally {
292
            $this->benchmark($benchmark);
293
        }
294
    }
295
296
    /**
297
     * {@inheritdoc}
298
     */
299
    public function copy(BucketInterface $destination, $name)
300
    {
301
        if ($destination == $this) {
302
            return $this->buildAddress($name);
303
        }
304
305
        //Internal copying
306
        if ($this->server() === $destination->server()) {
307
            $this->logger()->info(
308
                "Internal copy of '{$this->buildAddress($name)}' "
309
                . "to '{$destination->buildAddress($name)}' at '{$this->server}' server."
310
            );
311
312
            $benchmark = $this->benchmark(
313
                $this->getName(), "copy::{$this->buildAddress($name)}"
314
            );
315
316
            try {
317
                $this->server()->copy($this, $destination, $name);
318
            } finally {
319
                $this->benchmark($benchmark);
320
            }
321
        } else {
322
            $this->logger()->info(
323
                "External copy of '{$this->getName()}'.'{$this->buildAddress($name)}' "
324
                . "to '{$destination->getName()}'.'{$destination->buildAddress($name)}'."
325
            );
326
327
            $destination->put($name, $this->allocateStream($name));
328
        }
329
330
        return $destination->buildAddress($name);
331
    }
332
333
    /**
334
     * {@inheritdoc}
335
     */
336
    public function replace(BucketInterface $destination, $name)
337
    {
338
        if ($destination == $this) {
339
            return $this->buildAddress($name);
340
        }
341
342
        //Internal copying
343
        if ($this->getName() == $destination->getName()) {
344
            $this->logger()->info(
345
                "Internal move '{$this->buildAddress($name)}' "
346
                . "to '{$destination->buildAddress($name)}' at '{$this->getName()}' server."
347
            );
348
349
            $benchmark = $this->benchmark(
350
                $this->getName(), "replace::{$this->buildAddress($name)}"
351
            );
352
353
            try {
354
                $this->server()->replace($this, $destination, $name);
355
            } finally {
356
                $this->benchmark($benchmark);
357
            }
358
        } else {
359
            $this->logger()->info(
360
                "External move '{$this->getName()}'.'{$this->buildAddress($name)}'"
361
                . " to '{$destination->getName()}'.'{$destination->buildAddress($name)}'."
362
            );
363
364
            //Copying using temporary stream (buffer)
365
            $destination->put($name, $stream = $this->allocateStream($name));
366
367
            if ($stream->detach()) {
368
                //Dropping temporary stream
369
                $this->delete($name);
370
            }
371
        }
372
373
        return $destination->buildAddress($name);
374
    }
375
}