Code Duplication    Length = 366-367 lines in 2 locations

src/Gaufrette/Adapter/Azure/src/BlobStorage.php 1 location

@@ 20-385 (lines=366) @@
17
 * @author Luciano Mammino <[email protected]>
18
 * @author Paweł Czyżewski <[email protected]>
19
 */
20
class BlobStorage implements Adapter, Adapter\MetadataSupporter
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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

src/Gaufrette/Adapter/AzureBlobStorage.php 1 location

@@ 20-386 (lines=367) @@
17
 * @author Luciano Mammino <[email protected]>
18
 * @author Paweł Czyżewski <[email protected]>
19
 */
20
class AzureBlobStorage implements Adapter,
21
                                  MetadataSupporter
22
{
23
    /**
24
     * Error constants.
25
     */
26
    const ERROR_CONTAINER_ALREADY_EXISTS = 'ContainerAlreadyExists';
27
    const ERROR_CONTAINER_NOT_FOUND = 'ContainerNotFound';
28
29
    /**
30
     * @var AzureBlobStorage\BlobProxyFactoryInterface
31
     */
32
    protected $blobProxyFactory;
33
34
    /**
35
     * @var string
36
     */
37
    protected $containerName;
38
39
    /**
40
     * @var bool
41
     */
42
    protected $detectContentType;
43
44
    /**
45
     * @var \MicrosoftAzure\Storage\Blob\Internal\IBlob
46
     */
47
    protected $blobProxy;
48
49
    /**
50
     * @param AzureBlobStorage\BlobProxyFactoryInterface $blobProxyFactory
51
     * @param string                                     $containerName
52
     * @param bool                                       $create
53
     * @param bool                                       $detectContentType
54
     */
55
    public function __construct(BlobProxyFactoryInterface $blobProxyFactory, $containerName, $create = false, $detectContentType = true)
56
    {
57
        $this->blobProxyFactory = $blobProxyFactory;
58
        $this->containerName = $containerName;
59
        $this->detectContentType = $detectContentType;
60
        if ($create) {
61
            $this->createContainer($containerName);
62
        }
63
    }
64
65
    /**
66
     * Creates a new container.
67
     *
68
     * @param string                                                     $containerName
69
     * @param \MicrosoftAzure\Storage\Blob\Models\CreateContainerOptions $options
70
     *
71
     * @throws \RuntimeException if cannot create the container
72
     */
73
    public function createContainer($containerName, CreateContainerOptions $options = null)
74
    {
75
        $this->init();
76
77
        try {
78
            $this->blobProxy->createContainer($containerName, $options);
79
        } catch (ServiceException $e) {
80
            $errorCode = $this->getErrorCodeFromServiceException($e);
81
82
            if ($errorCode != self::ERROR_CONTAINER_ALREADY_EXISTS) {
83
                throw new \RuntimeException(sprintf(
84
                    'Failed to create the configured container "%s": %s (%s).',
85
                    $containerName,
86
                    $e->getErrorText(),
87
                    $errorCode
88
                ));
89
            }
90
        }
91
    }
92
93
    /**
94
     * Deletes a container.
95
     *
96
     * @param string                 $containerName
97
     * @param DeleteContainerOptions $options
98
     *
99
     * @throws \RuntimeException if cannot delete the container
100
     */
101
    public function deleteContainer($containerName, DeleteContainerOptions $options = null)
102
    {
103
        $this->init();
104
105
        try {
106
            $this->blobProxy->deleteContainer($containerName, $options);
107
        } catch (ServiceException $e) {
108
            $errorCode = $this->getErrorCodeFromServiceException($e);
109
110
            if ($errorCode != self::ERROR_CONTAINER_NOT_FOUND) {
111
                throw new \RuntimeException(sprintf(
112
                    'Failed to delete the configured container "%s": %s (%s).',
113
                    $containerName,
114
                    $e->getErrorText(),
115
                    $errorCode
116
                ), $e->getCode());
117
            }
118
        }
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function read($key)
125
    {
126
        $this->init();
127
128
        try {
129
            $blob = $this->blobProxy->getBlob($this->containerName, $key);
130
131
            return stream_get_contents($blob->getContentStream());
132
        } catch (ServiceException $e) {
133
            $this->failIfContainerNotFound($e, sprintf('read key "%s"', $key));
134
135
            return false;
136
        }
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    public function write($key, $content)
143
    {
144
        $this->init();
145
146
        try {
147
            $options = new CreateBlobOptions();
148
149
            if ($this->detectContentType) {
150
                $fileInfo = new \finfo(FILEINFO_MIME_TYPE);
151
                $contentType = $fileInfo->buffer($content);
152
                $options->setContentType($contentType);
153
            }
154
155
            $this->blobProxy->createBlockBlob($this->containerName, $key, $content, $options);
156
157
            return Util\Size::fromContent($content);
158
        } catch (ServiceException $e) {
159
            $this->failIfContainerNotFound($e, sprintf('write content for key "%s"', $key));
160
161
            return false;
162
        }
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function exists($key)
169
    {
170
        $this->init();
171
172
        $listBlobsOptions = new ListBlobsOptions();
173
        $listBlobsOptions->setPrefix($key);
174
175
        try {
176
            $blobsList = $this->blobProxy->listBlobs($this->containerName, $listBlobsOptions);
177
178
            foreach ($blobsList->getBlobs() as $blob) {
179
                if ($key === $blob->getName()) {
180
                    return true;
181
                }
182
            }
183
        } catch (ServiceException $e) {
184
            $this->failIfContainerNotFound($e, 'check if key exists');
185
            $errorCode = $this->getErrorCodeFromServiceException($e);
186
187
            throw new \RuntimeException(sprintf(
188
                'Failed to check if key "%s" exists in container "%s": %s (%s).',
189
                $key,
190
                $this->containerName,
191
                $e->getErrorText(),
192
                $errorCode
193
            ), $e->getCode());
194
        }
195
196
        return false;
197
    }
198
199
    /**
200
     * {@inheritdoc}
201
     */
202
    public function keys()
203
    {
204
        $this->init();
205
206
        try {
207
            $blobList = $this->blobProxy->listBlobs($this->containerName);
208
209
            return array_map(
210
                function ($blob) {
211
                    return $blob->getName();
212
                },
213
                $blobList->getBlobs()
214
            );
215
        } catch (ServiceException $e) {
216
            $this->failIfContainerNotFound($e, 'retrieve keys');
217
            $errorCode = $this->getErrorCodeFromServiceException($e);
218
219
            throw new \RuntimeException(sprintf(
220
                'Failed to list keys for the container "%s": %s (%s).',
221
                $this->containerName,
222
                $e->getErrorText(),
223
                $errorCode
224
            ), $e->getCode());
225
        }
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    public function mtime($key)
232
    {
233
        $this->init();
234
235
        try {
236
            $properties = $this->blobProxy->getBlobProperties($this->containerName, $key);
237
238
            return $properties->getProperties()->getLastModified()->getTimestamp();
239
        } catch (ServiceException $e) {
240
            $this->failIfContainerNotFound($e, sprintf('read mtime for key "%s"', $key));
241
242
            return false;
243
        }
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249
    public function delete($key)
250
    {
251
        $this->init();
252
253
        try {
254
            $this->blobProxy->deleteBlob($this->containerName, $key);
255
256
            return true;
257
        } catch (ServiceException $e) {
258
            $this->failIfContainerNotFound($e, sprintf('delete key "%s"', $key));
259
260
            return false;
261
        }
262
    }
263
264
    /**
265
     * {@inheritdoc}
266
     */
267
    public function rename($sourceKey, $targetKey)
268
    {
269
        $this->init();
270
271
        try {
272
            $this->blobProxy->copyBlob($this->containerName, $targetKey, $this->containerName, $sourceKey);
273
            $this->blobProxy->deleteBlob($this->containerName, $sourceKey);
274
275
            return true;
276
        } catch (ServiceException $e) {
277
            $this->failIfContainerNotFound($e, sprintf('rename key "%s"', $sourceKey));
278
279
            return false;
280
        }
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function isDirectory($key)
287
    {
288
        // Windows Azure Blob Storage does not support directories
289
        return false;
290
    }
291
292
    /**
293
     * {@inheritdoc}
294
     */
295
    public function setMetadata($key, $content)
296
    {
297
        $this->init();
298
299
        try {
300
            $this->blobProxy->setBlobMetadata($this->containerName, $key, $content);
301
        } catch (ServiceException $e) {
302
            $errorCode = $this->getErrorCodeFromServiceException($e);
303
304
            throw new \RuntimeException(sprintf(
305
                'Failed to set metadata for blob "%s" in container "%s": %s (%s).',
306
                $key,
307
                $this->containerName,
308
                $e->getErrorText(),
309
                $errorCode
310
            ), $e->getCode());
311
        }
312
    }
313
314
    /**
315
     * {@inheritdoc}
316
     */
317
    public function getMetadata($key)
318
    {
319
        $this->init();
320
321
        try {
322
            $properties = $this->blobProxy->getBlobProperties($this->containerName, $key);
323
324
            return $properties->getMetadata();
325
        } catch (ServiceException $e) {
326
            $errorCode = $this->getErrorCodeFromServiceException($e);
327
328
            throw new \RuntimeException(sprintf(
329
                'Failed to get metadata for blob "%s" in container "%s": %s (%s).',
330
                $key,
331
                $this->containerName,
332
                $e->getErrorText(),
333
                $errorCode
334
            ), $e->getCode());
335
        }
336
    }
337
338
    /**
339
     * Lazy initialization, automatically called when some method is called after construction.
340
     */
341
    protected function init()
342
    {
343
        if ($this->blobProxy == null) {
344
            $this->blobProxy = $this->blobProxyFactory->create();
345
        }
346
    }
347
348
    /**
349
     * Throws a runtime exception if a give ServiceException derived from a "container not found" error.
350
     *
351
     * @param ServiceException $exception
352
     * @param string           $action
353
     *
354
     * @throws \RuntimeException
355
     */
356
    protected function failIfContainerNotFound(ServiceException $exception, $action)
357
    {
358
        $errorCode = $this->getErrorCodeFromServiceException($exception);
359
360
        if ($errorCode == self::ERROR_CONTAINER_NOT_FOUND) {
361
            throw new \RuntimeException(sprintf(
362
                'Failed to %s: container "%s" not found.',
363
                $action,
364
                $this->containerName
365
            ), $exception->getCode());
366
        }
367
    }
368
369
    /**
370
     * Extracts the error code from a service exception.
371
     *
372
     * @param ServiceException $exception
373
     *
374
     * @return string
375
     */
376
    protected function getErrorCodeFromServiceException(ServiceException $exception)
377
    {
378
        $xml = @simplexml_load_string($exception->getErrorReason());
379
380
        if ($xml && isset($xml->Code)) {
381
            return (string) $xml->Code;
382
        }
383
384
        return $exception->getErrorReason();
385
    }
386
}
387