Completed
Pull Request — master (#437)
by Albin
13:34 queued 06:13
created

BlobStorage::keys()   B

Complexity

Conditions 2
Paths 3

Size

Total Lines 25
Code Lines 17

Duplication

Lines 25
Ratio 100 %

Importance

Changes 0
Metric Value
dl 25
loc 25
rs 8.8571
c 0
b 0
f 0
cc 2
eloc 17
nc 3
nop 0
1
<?php
2
3
namespace Gaufrette\Adapter\Azure;
4
5
use Gaufrette\Adapter;
6
use Gaufrette\Util;
7
use MicrosoftAzure\Storage\Blob\Internal\IBlob;
8
use MicrosoftAzure\Storage\Blob\Models\CreateBlobOptions;
9
use MicrosoftAzure\Storage\Blob\Models\CreateContainerOptions;
10
use MicrosoftAzure\Storage\Blob\Models\DeleteContainerOptions;
11
use MicrosoftAzure\Storage\Blob\Models\ListBlobsOptions;
12
use WindowsAzure\Common\ServiceException;
13
14
/**
15
 * Microsoft Azure Blob Storage adapter.
16
 *
17
 * @author Luciano Mammino <[email protected]>
18
 * @author Paweł Czyżewski <[email protected]>
19
 */
20 View Code Duplication
class BlobStorage implements Adapter, Adapter\MetadataSupporter
0 ignored issues
show
Duplication introduced by
This class 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...
21
{
22
    /**
23
     * Error constants.
24
     */
25
    const ERROR_CONTAINER_ALREADY_EXISTS = 'ContainerAlreadyExists';
26
    const ERROR_CONTAINER_NOT_FOUND = 'ContainerNotFound';
27
28
    /**
29
     * @var BlobProxyFactoryInterface
30
     */
31
    protected $blobProxyFactory;
32
33
    /**
34
     * @var string
35
     */
36
    protected $containerName;
37
38
    /**
39
     * @var bool
40
     */
41
    protected $detectContentType;
42
43
    /**
44
     * @var IBlob
45
     */
46
    protected $blobProxy;
47
48
    /**
49
     * @param BlobProxyFactoryInterface $blobProxyFactory
50
     * @param string                    $containerName
51
     * @param bool                      $create
52
     * @param bool                      $detectContentType
53
     */
54
    public function __construct(BlobProxyFactoryInterface $blobProxyFactory, $containerName, $create = false, $detectContentType = true)
55
    {
56
        $this->blobProxyFactory = $blobProxyFactory;
57
        $this->containerName = $containerName;
58
        $this->detectContentType = $detectContentType;
59
        if ($create) {
60
            $this->createContainer($containerName);
61
        }
62
    }
63
64
    /**
65
     * Creates a new container.
66
     *
67
     * @param string                      $containerName
68
     * @param CreateContainerOptions|null $options
69
     *
70
     * @throws \RuntimeException if cannot create the container
71
     */
72
    public function createContainer($containerName, CreateContainerOptions $options = null)
73
    {
74
        $this->init();
75
76
        try {
77
            $this->blobProxy->createContainer($containerName, $options);
78
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
79
            $errorCode = $this->getErrorCodeFromServiceException($e);
80
81
            if ($errorCode != self::ERROR_CONTAINER_ALREADY_EXISTS) {
82
                throw new \RuntimeException(sprintf(
83
                    'Failed to create the configured container "%s": %s (%s).',
84
                    $containerName,
85
                    $e->getErrorText(),
86
                    $errorCode
87
                ));
88
            }
89
        }
90
    }
91
92
    /**
93
     * Deletes a container.
94
     *
95
     * @param string                 $containerName
96
     * @param DeleteContainerOptions $options
97
     *
98
     * @throws \RuntimeException if cannot delete the container
99
     */
100
    public function deleteContainer($containerName, DeleteContainerOptions $options = null)
101
    {
102
        $this->init();
103
104
        try {
105
            $this->blobProxy->deleteContainer($containerName, $options);
106
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
107
            $errorCode = $this->getErrorCodeFromServiceException($e);
108
109
            if ($errorCode != self::ERROR_CONTAINER_NOT_FOUND) {
110
                throw new \RuntimeException(sprintf(
111
                    'Failed to delete the configured container "%s": %s (%s).',
112
                    $containerName,
113
                    $e->getErrorText(),
114
                    $errorCode
115
                ), $e->getCode());
116
            }
117
        }
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function read($key)
124
    {
125
        $this->init();
126
127
        try {
128
            $blob = $this->blobProxy->getBlob($this->containerName, $key);
129
130
            return stream_get_contents($blob->getContentStream());
131
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
132
            $this->failIfContainerNotFound($e, sprintf('read key "%s"', $key));
133
134
            return false;
135
        }
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    public function write($key, $content)
142
    {
143
        $this->init();
144
145
        try {
146
            $options = new CreateBlobOptions();
147
148
            if ($this->detectContentType) {
149
                $fileInfo = new \finfo(FILEINFO_MIME_TYPE);
150
                $contentType = $fileInfo->buffer($content);
151
                $options->setContentType($contentType);
152
            }
153
154
            $this->blobProxy->createBlockBlob($this->containerName, $key, $content, $options);
155
156
            return Util\Size::fromContent($content);
157
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
158
            $this->failIfContainerNotFound($e, sprintf('write content for key "%s"', $key));
159
160
            return false;
161
        }
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function exists($key)
168
    {
169
        $this->init();
170
171
        $listBlobsOptions = new ListBlobsOptions();
172
        $listBlobsOptions->setPrefix($key);
173
174
        try {
175
            $blobsList = $this->blobProxy->listBlobs($this->containerName, $listBlobsOptions);
176
177
            foreach ($blobsList->getBlobs() as $blob) {
178
                if ($key === $blob->getName()) {
179
                    return true;
180
                }
181
            }
182
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
183
            $this->failIfContainerNotFound($e, 'check if key exists');
184
            $errorCode = $this->getErrorCodeFromServiceException($e);
185
186
            throw new \RuntimeException(sprintf(
187
                'Failed to check if key "%s" exists in container "%s": %s (%s).',
188
                $key,
189
                $this->containerName,
190
                $e->getErrorText(),
191
                $errorCode
192
            ), $e->getCode());
193
        }
194
195
        return false;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function keys()
202
    {
203
        $this->init();
204
205
        try {
206
            $blobList = $this->blobProxy->listBlobs($this->containerName);
207
208
            return array_map(
209
                function ($blob) {
210
                    return $blob->getName();
211
                },
212
                $blobList->getBlobs()
213
            );
214
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
215
            $this->failIfContainerNotFound($e, 'retrieve keys');
216
            $errorCode = $this->getErrorCodeFromServiceException($e);
217
218
            throw new \RuntimeException(sprintf(
219
                'Failed to list keys for the container "%s": %s (%s).',
220
                $this->containerName,
221
                $e->getErrorText(),
222
                $errorCode
223
            ), $e->getCode());
224
        }
225
    }
226
227
    /**
228
     * {@inheritdoc}
229
     */
230
    public function mtime($key)
231
    {
232
        $this->init();
233
234
        try {
235
            $properties = $this->blobProxy->getBlobProperties($this->containerName, $key);
236
237
            return $properties->getProperties()->getLastModified()->getTimestamp();
238
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
239
            $this->failIfContainerNotFound($e, sprintf('read mtime for key "%s"', $key));
240
241
            return false;
242
        }
243
    }
244
245
    /**
246
     * {@inheritdoc}
247
     */
248
    public function delete($key)
249
    {
250
        $this->init();
251
252
        try {
253
            $this->blobProxy->deleteBlob($this->containerName, $key);
254
255
            return true;
256
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
257
            $this->failIfContainerNotFound($e, sprintf('delete key "%s"', $key));
258
259
            return false;
260
        }
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266
    public function rename($sourceKey, $targetKey)
267
    {
268
        $this->init();
269
270
        try {
271
            $this->blobProxy->copyBlob($this->containerName, $targetKey, $this->containerName, $sourceKey);
272
            $this->blobProxy->deleteBlob($this->containerName, $sourceKey);
273
274
            return true;
275
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
276
            $this->failIfContainerNotFound($e, sprintf('rename key "%s"', $sourceKey));
277
278
            return false;
279
        }
280
    }
281
282
    /**
283
     * {@inheritdoc}
284
     */
285
    public function isDirectory($key)
286
    {
287
        // Windows Azure Blob Storage does not support directories
288
        return false;
289
    }
290
291
    /**
292
     * {@inheritdoc}
293
     */
294
    public function setMetadata($key, $content)
295
    {
296
        $this->init();
297
298
        try {
299
            $this->blobProxy->setBlobMetadata($this->containerName, $key, $content);
300
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
301
            $errorCode = $this->getErrorCodeFromServiceException($e);
302
303
            throw new \RuntimeException(sprintf(
304
                'Failed to set metadata for blob "%s" in container "%s": %s (%s).',
305
                $key,
306
                $this->containerName,
307
                $e->getErrorText(),
308
                $errorCode
309
            ), $e->getCode());
310
        }
311
    }
312
313
    /**
314
     * {@inheritdoc}
315
     */
316
    public function getMetadata($key)
317
    {
318
        $this->init();
319
320
        try {
321
            $properties = $this->blobProxy->getBlobProperties($this->containerName, $key);
322
323
            return $properties->getMetadata();
324
        } catch (ServiceException $e) {
0 ignored issues
show
Bug introduced by
The class WindowsAzure\Common\ServiceException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
325
            $errorCode = $this->getErrorCodeFromServiceException($e);
326
327
            throw new \RuntimeException(sprintf(
328
                'Failed to get metadata for blob "%s" in container "%s": %s (%s).',
329
                $key,
330
                $this->containerName,
331
                $e->getErrorText(),
332
                $errorCode
333
            ), $e->getCode());
334
        }
335
    }
336
337
    /**
338
     * Lazy initialization, automatically called when some method is called after construction.
339
     */
340
    protected function init()
341
    {
342
        if ($this->blobProxy == null) {
343
            $this->blobProxy = $this->blobProxyFactory->create();
344
        }
345
    }
346
347
    /**
348
     * Throws a runtime exception if a give ServiceException derived from a "container not found" error.
349
     *
350
     * @param ServiceException $exception
351
     * @param string           $action
352
     *
353
     * @throws \RuntimeException
354
     */
355
    protected function failIfContainerNotFound(ServiceException $exception, $action)
356
    {
357
        $errorCode = $this->getErrorCodeFromServiceException($exception);
358
359
        if ($errorCode == self::ERROR_CONTAINER_NOT_FOUND) {
360
            throw new \RuntimeException(sprintf(
361
                'Failed to %s: container "%s" not found.',
362
                $action,
363
                $this->containerName
364
            ), $exception->getCode());
365
        }
366
    }
367
368
    /**
369
     * Extracts the error code from a service exception.
370
     *
371
     * @param ServiceException $exception
372
     *
373
     * @return string
374
     */
375
    protected function getErrorCodeFromServiceException(ServiceException $exception)
376
    {
377
        $xml = @simplexml_load_string($exception->getErrorReason());
378
379
        if ($xml && isset($xml->Code)) {
380
            return (string) $xml->Code;
381
        }
382
383
        return $exception->getErrorReason();
384
    }
385
}
386