These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Gaufrette\Adapter; |
||
4 | |||
5 | use Gaufrette\Adapter; |
||
6 | use Gaufrette\Util; |
||
7 | use Gaufrette\Adapter\AzureBlobStorage\BlobProxyFactoryInterface; |
||
8 | use MicrosoftAzure\Storage\Blob\Models\Blob; |
||
9 | use MicrosoftAzure\Storage\Blob\Models\Container; |
||
10 | use MicrosoftAzure\Storage\Blob\Models\CreateBlobOptions; |
||
11 | use MicrosoftAzure\Storage\Blob\Models\CreateBlockBlobOptions; |
||
12 | use MicrosoftAzure\Storage\Blob\Models\CreateContainerOptions; |
||
13 | use MicrosoftAzure\Storage\Blob\Models\DeleteContainerOptions; |
||
14 | use MicrosoftAzure\Storage\Blob\Models\ListBlobsOptions; |
||
15 | use MicrosoftAzure\Storage\Common\Exceptions\ServiceException; |
||
16 | |||
17 | /** |
||
18 | * Microsoft Azure Blob Storage adapter. |
||
19 | * |
||
20 | * @author Luciano Mammino <[email protected]> |
||
21 | * @author Paweł Czyżewski <[email protected]> |
||
22 | */ |
||
23 | class AzureBlobStorage implements Adapter, |
||
24 | MetadataSupporter, |
||
25 | SizeCalculator |
||
26 | |||
27 | { |
||
28 | /** |
||
29 | * Error constants. |
||
30 | */ |
||
31 | const ERROR_CONTAINER_ALREADY_EXISTS = 'ContainerAlreadyExists'; |
||
32 | const ERROR_CONTAINER_NOT_FOUND = 'ContainerNotFound'; |
||
33 | |||
34 | /** |
||
35 | * @var AzureBlobStorage\BlobProxyFactoryInterface |
||
36 | */ |
||
37 | protected $blobProxyFactory; |
||
38 | |||
39 | /** |
||
40 | * @var string |
||
41 | */ |
||
42 | protected $containerName; |
||
43 | |||
44 | /** |
||
45 | * @var bool |
||
46 | */ |
||
47 | protected $detectContentType; |
||
48 | |||
49 | /** |
||
50 | * @var \MicrosoftAzure\Storage\Blob\Internal\IBlob |
||
51 | */ |
||
52 | protected $blobProxy; |
||
53 | |||
54 | /** |
||
55 | * @var bool |
||
56 | */ |
||
57 | protected $multiContainerMode = false; |
||
58 | |||
59 | /** |
||
60 | * @var CreateContainerOptions |
||
61 | */ |
||
62 | protected $createContainerOptions; |
||
63 | |||
64 | /** |
||
65 | * @param AzureBlobStorage\BlobProxyFactoryInterface $blobProxyFactory |
||
66 | * @param string|null $containerName |
||
67 | * @param bool $create |
||
68 | * @param bool $detectContentType |
||
69 | * |
||
70 | * @throws \RuntimeException |
||
71 | */ |
||
72 | public function __construct(BlobProxyFactoryInterface $blobProxyFactory, $containerName = null, $create = false, $detectContentType = true) |
||
73 | { |
||
74 | $this->blobProxyFactory = $blobProxyFactory; |
||
75 | $this->containerName = $containerName; |
||
76 | $this->detectContentType = $detectContentType; |
||
77 | if (null === $containerName) { |
||
78 | $this->multiContainerMode = true; |
||
79 | } elseif ($create) { |
||
80 | $this->createContainer($containerName); |
||
81 | } |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * @return CreateContainerOptions |
||
86 | */ |
||
87 | public function getCreateContainerOptions() |
||
88 | { |
||
89 | return $this->createContainerOptions; |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * @param CreateContainerOptions $options |
||
94 | */ |
||
95 | public function setCreateContainerOptions(CreateContainerOptions $options) |
||
96 | { |
||
97 | $this->createContainerOptions = $options; |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * Creates a new container. |
||
102 | * |
||
103 | * @param string $containerName |
||
104 | * @param \MicrosoftAzure\Storage\Blob\Models\CreateContainerOptions $options |
||
105 | * |
||
106 | * @throws \RuntimeException if cannot create the container |
||
107 | */ |
||
108 | View Code Duplication | public function createContainer($containerName, CreateContainerOptions $options = null) |
|
0 ignored issues
–
show
|
|||
109 | { |
||
110 | $this->init(); |
||
111 | |||
112 | if (null === $options) { |
||
113 | $options = $this->getCreateContainerOptions(); |
||
114 | } |
||
115 | |||
116 | try { |
||
117 | $this->blobProxy->createContainer($containerName, $options); |
||
118 | } catch (ServiceException $e) { |
||
119 | $errorCode = $this->getErrorCodeFromServiceException($e); |
||
120 | |||
121 | if ($errorCode !== self::ERROR_CONTAINER_ALREADY_EXISTS) { |
||
122 | throw new \RuntimeException(sprintf( |
||
123 | 'Failed to create the configured container "%s": %s (%s).', |
||
124 | $containerName, |
||
125 | $e->getErrorText(), |
||
126 | $errorCode |
||
127 | )); |
||
128 | } |
||
129 | } |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * Deletes a container. |
||
134 | * |
||
135 | * @param string $containerName |
||
136 | * @param DeleteContainerOptions $options |
||
137 | * |
||
138 | * @throws \RuntimeException if cannot delete the container |
||
139 | */ |
||
140 | View Code Duplication | public function deleteContainer($containerName, DeleteContainerOptions $options = null) |
|
0 ignored issues
–
show
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...
|
|||
141 | { |
||
142 | $this->init(); |
||
143 | |||
144 | try { |
||
145 | $this->blobProxy->deleteContainer($containerName, $options); |
||
146 | } catch (ServiceException $e) { |
||
147 | $errorCode = $this->getErrorCodeFromServiceException($e); |
||
148 | |||
149 | if ($errorCode !== self::ERROR_CONTAINER_NOT_FOUND) { |
||
150 | throw new \RuntimeException(sprintf( |
||
151 | 'Failed to delete the configured container "%s": %s (%s).', |
||
152 | $containerName, |
||
153 | $e->getErrorText(), |
||
154 | $errorCode |
||
155 | ), $e->getCode()); |
||
156 | } |
||
157 | } |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * {@inheritdoc} |
||
162 | * @throws \RuntimeException |
||
163 | * @throws \InvalidArgumentException |
||
164 | */ |
||
165 | View Code Duplication | public function read($key) |
|
0 ignored issues
–
show
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...
|
|||
166 | { |
||
167 | $this->init(); |
||
168 | list($containerName, $key) = $this->tokenizeKey($key); |
||
169 | |||
170 | try { |
||
171 | $blob = $this->blobProxy->getBlob($containerName, $key); |
||
172 | |||
173 | return stream_get_contents($blob->getContentStream()); |
||
174 | } catch (ServiceException $e) { |
||
175 | $this->failIfContainerNotFound($e, sprintf('read key "%s"', $key), $containerName); |
||
176 | |||
177 | return false; |
||
178 | } |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * {@inheritdoc} |
||
183 | * @throws \RuntimeException |
||
184 | * @throws \InvalidArgumentException |
||
185 | */ |
||
186 | public function write($key, $content) |
||
187 | { |
||
188 | $this->init(); |
||
189 | list($containerName, $key) = $this->tokenizeKey($key); |
||
190 | |||
191 | if (class_exists(CreateBlockBlobOptions::class)) { |
||
192 | $options = new CreateBlockBlobOptions(); |
||
193 | } else { |
||
194 | // for microsoft/azure-storage < 1.0 |
||
195 | $options = new CreateBlobOptions(); |
||
196 | } |
||
197 | |||
198 | if ($this->detectContentType) { |
||
199 | $contentType = $this->guessContentType($content); |
||
200 | |||
201 | $options->setContentType($contentType); |
||
202 | } |
||
203 | |||
204 | try { |
||
205 | if ($this->multiContainerMode) { |
||
206 | $this->createContainer($containerName); |
||
207 | } |
||
208 | |||
209 | $this->blobProxy->createBlockBlob($containerName, $key, $content, $options); |
||
0 ignored issues
–
show
$options is of type object<MicrosoftAzure\St...dels\CreateBlobOptions> , but the function expects a null|object<MicrosoftAzu...CreateBlockBlobOptions> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
210 | } catch (ServiceException $e) { |
||
211 | $this->failIfContainerNotFound($e, sprintf('write content for key "%s"', $key), $containerName); |
||
212 | |||
213 | return false; |
||
214 | } |
||
215 | if (is_resource($content)) { |
||
216 | return Util\Size::fromResource($content); |
||
0 ignored issues
–
show
The return type of
return \Gaufrette\Util\S...fromResource($content); (string ) is incompatible with the return type declared by the interface Gaufrette\Adapter::write of type integer|boolean .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
217 | } |
||
218 | |||
219 | return Util\Size::fromContent($content); |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * {@inheritdoc} |
||
224 | * @throws \RuntimeException |
||
225 | * @throws \InvalidArgumentException |
||
226 | */ |
||
227 | public function exists($key) |
||
228 | { |
||
229 | $this->init(); |
||
230 | list($containerName, $key) = $this->tokenizeKey($key); |
||
231 | |||
232 | $listBlobsOptions = new ListBlobsOptions(); |
||
233 | $listBlobsOptions->setPrefix($key); |
||
234 | |||
235 | try { |
||
236 | $blobsList = $this->blobProxy->listBlobs($containerName, $listBlobsOptions); |
||
237 | |||
238 | foreach ($blobsList->getBlobs() as $blob) { |
||
239 | if ($key === $blob->getName()) { |
||
240 | return true; |
||
241 | } |
||
242 | } |
||
243 | } catch (ServiceException $e) { |
||
244 | $errorCode = $this->getErrorCodeFromServiceException($e); |
||
245 | if ($this->multiContainerMode && self::ERROR_CONTAINER_NOT_FOUND === $errorCode) { |
||
246 | return false; |
||
247 | } |
||
248 | $this->failIfContainerNotFound($e, 'check if key exists', $containerName); |
||
249 | |||
250 | throw new \RuntimeException(sprintf( |
||
251 | 'Failed to check if key "%s" exists in container "%s": %s (%s).', |
||
252 | $key, |
||
253 | $containerName, |
||
254 | $e->getErrorText(), |
||
255 | $errorCode |
||
256 | ), $e->getCode()); |
||
257 | } |
||
258 | |||
259 | return false; |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * {@inheritdoc} |
||
264 | * @throws \RuntimeException |
||
265 | */ |
||
266 | public function keys() |
||
267 | { |
||
268 | $this->init(); |
||
269 | |||
270 | try { |
||
271 | if ($this->multiContainerMode) { |
||
272 | $containersList = $this->blobProxy->listContainers(); |
||
273 | return call_user_func_array('array_merge', array_map( |
||
274 | function(Container $container) { |
||
275 | $containerName = $container->getName(); |
||
276 | return $this->fetchBlobs($containerName, $containerName); |
||
277 | }, |
||
278 | $containersList->getContainers() |
||
279 | )); |
||
280 | } |
||
281 | |||
282 | return $this->fetchBlobs($this->containerName); |
||
283 | } catch (ServiceException $e) { |
||
284 | $this->failIfContainerNotFound($e, 'retrieve keys', $this->containerName); |
||
285 | $errorCode = $this->getErrorCodeFromServiceException($e); |
||
286 | |||
287 | throw new \RuntimeException(sprintf( |
||
288 | 'Failed to list keys for the container "%s": %s (%s).', |
||
289 | $this->containerName, |
||
290 | $e->getErrorText(), |
||
291 | $errorCode |
||
292 | ), $e->getCode()); |
||
293 | } |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * {@inheritdoc} |
||
298 | * @throws \RuntimeException |
||
299 | * @throws \InvalidArgumentException |
||
300 | */ |
||
301 | View Code Duplication | public function mtime($key) |
|
0 ignored issues
–
show
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...
|
|||
302 | { |
||
303 | $this->init(); |
||
304 | list($containerName, $key) = $this->tokenizeKey($key); |
||
305 | |||
306 | try { |
||
307 | $properties = $this->blobProxy->getBlobProperties($containerName, $key); |
||
308 | |||
309 | return $properties->getProperties()->getLastModified()->getTimestamp(); |
||
310 | } catch (ServiceException $e) { |
||
311 | $this->failIfContainerNotFound($e, sprintf('read mtime for key "%s"', $key), $containerName); |
||
312 | |||
313 | return false; |
||
314 | } |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * {@inheritdoc} |
||
319 | */ |
||
320 | View Code Duplication | public function size($key) |
|
0 ignored issues
–
show
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...
|
|||
321 | { |
||
322 | $this->init(); |
||
323 | list($containerName, $key) = $this->tokenizeKey($key); |
||
324 | |||
325 | try { |
||
326 | $properties = $this->blobProxy->getBlobProperties($containerName, $key); |
||
327 | |||
328 | return $properties->getProperties()->getContentLength(); |
||
329 | } catch (ServiceException $e) { |
||
330 | $this->failIfContainerNotFound($e, sprintf('read content length for key "%s"', $key), $containerName); |
||
331 | |||
332 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type declared by the interface Gaufrette\Adapter\SizeCalculator::size of type integer .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
333 | } |
||
334 | |||
335 | } |
||
336 | |||
337 | /** |
||
338 | * {@inheritdoc} |
||
339 | * @throws \RuntimeException |
||
340 | * @throws \InvalidArgumentException |
||
341 | */ |
||
342 | View Code Duplication | public function delete($key) |
|
0 ignored issues
–
show
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...
|
|||
343 | { |
||
344 | $this->init(); |
||
345 | list($containerName, $key) = $this->tokenizeKey($key); |
||
346 | |||
347 | try { |
||
348 | $this->blobProxy->deleteBlob($containerName, $key); |
||
349 | |||
350 | return true; |
||
351 | } catch (ServiceException $e) { |
||
352 | $this->failIfContainerNotFound($e, sprintf('delete key "%s"', $key), $containerName); |
||
353 | |||
354 | return false; |
||
355 | } |
||
356 | } |
||
357 | |||
358 | /** |
||
359 | * {@inheritdoc} |
||
360 | * @throws \RuntimeException |
||
361 | * @throws \InvalidArgumentException |
||
362 | */ |
||
363 | public function rename($sourceKey, $targetKey) |
||
364 | { |
||
365 | $this->init(); |
||
366 | |||
367 | list($sourceContainerName, $sourceKey) = $this->tokenizeKey($sourceKey); |
||
368 | list($targetContainerName, $targetKey) = $this->tokenizeKey($targetKey); |
||
369 | |||
370 | try { |
||
371 | if ($this->multiContainerMode) { |
||
372 | $this->createContainer($targetContainerName); |
||
373 | } |
||
374 | $this->blobProxy->copyBlob($targetContainerName, $targetKey, $sourceContainerName, $sourceKey); |
||
375 | $this->blobProxy->deleteBlob($sourceContainerName, $sourceKey); |
||
376 | |||
377 | return true; |
||
378 | } catch (ServiceException $e) { |
||
379 | $this->failIfContainerNotFound($e, sprintf('rename key "%s"', $sourceKey), $sourceContainerName); |
||
380 | |||
381 | return false; |
||
382 | } |
||
383 | } |
||
384 | |||
385 | /** |
||
386 | * {@inheritdoc} |
||
387 | */ |
||
388 | public function isDirectory($key) |
||
389 | { |
||
390 | // Windows Azure Blob Storage does not support directories |
||
391 | return false; |
||
392 | } |
||
393 | |||
394 | /** |
||
395 | * {@inheritdoc} |
||
396 | * @throws \RuntimeException |
||
397 | * @throws \InvalidArgumentException |
||
398 | */ |
||
399 | View Code Duplication | public function setMetadata($key, $content) |
|
0 ignored issues
–
show
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...
|
|||
400 | { |
||
401 | $this->init(); |
||
402 | list($containerName, $key) = $this->tokenizeKey($key); |
||
403 | |||
404 | try { |
||
405 | $this->blobProxy->setBlobMetadata($containerName, $key, $content); |
||
406 | } catch (ServiceException $e) { |
||
407 | $errorCode = $this->getErrorCodeFromServiceException($e); |
||
408 | |||
409 | throw new \RuntimeException(sprintf( |
||
410 | 'Failed to set metadata for blob "%s" in container "%s": %s (%s).', |
||
411 | $key, |
||
412 | $containerName, |
||
413 | $e->getErrorText(), |
||
414 | $errorCode |
||
415 | ), $e->getCode()); |
||
416 | } |
||
417 | } |
||
418 | |||
419 | /** |
||
420 | * {@inheritdoc} |
||
421 | * @throws \RuntimeException |
||
422 | * @throws \InvalidArgumentException |
||
423 | */ |
||
424 | View Code Duplication | public function getMetadata($key) |
|
0 ignored issues
–
show
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...
|
|||
425 | { |
||
426 | $this->init(); |
||
427 | list($containerName, $key) = $this->tokenizeKey($key); |
||
428 | |||
429 | try { |
||
430 | $properties = $this->blobProxy->getBlobProperties($containerName, $key); |
||
431 | |||
432 | return $properties->getMetadata(); |
||
433 | } catch (ServiceException $e) { |
||
434 | $errorCode = $this->getErrorCodeFromServiceException($e); |
||
435 | |||
436 | throw new \RuntimeException(sprintf( |
||
437 | 'Failed to get metadata for blob "%s" in container "%s": %s (%s).', |
||
438 | $key, |
||
439 | $containerName, |
||
440 | $e->getErrorText(), |
||
441 | $errorCode |
||
442 | ), $e->getCode()); |
||
443 | } |
||
444 | } |
||
445 | |||
446 | /** |
||
447 | * Lazy initialization, automatically called when some method is called after construction. |
||
448 | */ |
||
449 | protected function init() |
||
450 | { |
||
451 | if ($this->blobProxy === null) { |
||
452 | $this->blobProxy = $this->blobProxyFactory->create(); |
||
453 | } |
||
454 | } |
||
455 | |||
456 | /** |
||
457 | * Throws a runtime exception if a give ServiceException derived from a "container not found" error. |
||
458 | * |
||
459 | * @param ServiceException $exception |
||
460 | * @param string $action |
||
461 | * @param string $containerName |
||
462 | * |
||
463 | * @throws \RuntimeException |
||
464 | */ |
||
465 | protected function failIfContainerNotFound(ServiceException $exception, $action, $containerName) |
||
466 | { |
||
467 | $errorCode = $this->getErrorCodeFromServiceException($exception); |
||
468 | |||
469 | if ($errorCode === self::ERROR_CONTAINER_NOT_FOUND) { |
||
470 | throw new \RuntimeException(sprintf( |
||
471 | 'Failed to %s: container "%s" not found.', |
||
472 | $action, |
||
473 | $containerName |
||
474 | ), $exception->getCode()); |
||
475 | } |
||
476 | } |
||
477 | |||
478 | /** |
||
479 | * Extracts the error code from a service exception. |
||
480 | * |
||
481 | * @param ServiceException $exception |
||
482 | * |
||
483 | * @return string |
||
484 | */ |
||
485 | protected function getErrorCodeFromServiceException(ServiceException $exception) |
||
486 | { |
||
487 | $xml = @simplexml_load_string($exception->getResponse()->getBody()); |
||
488 | |||
489 | if ($xml && isset($xml->Code)) { |
||
490 | return (string) $xml->Code; |
||
491 | } |
||
492 | |||
493 | return $exception->getErrorText(); |
||
494 | } |
||
495 | |||
496 | /** |
||
497 | * @param string|resource $content |
||
498 | * |
||
499 | * @return string |
||
500 | */ |
||
501 | View Code Duplication | private function guessContentType($content) |
|
0 ignored issues
–
show
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...
|
|||
502 | { |
||
503 | $fileInfo = new \finfo(FILEINFO_MIME_TYPE); |
||
504 | |||
505 | if (is_resource($content)) { |
||
506 | return $fileInfo->file(stream_get_meta_data($content)['uri']); |
||
507 | } |
||
508 | |||
509 | return $fileInfo->buffer($content); |
||
510 | } |
||
511 | |||
512 | /** |
||
513 | * @param string $key |
||
514 | * |
||
515 | * @return array |
||
516 | * @throws \InvalidArgumentException |
||
517 | */ |
||
518 | private function tokenizeKey($key) |
||
519 | { |
||
520 | $containerName = $this->containerName; |
||
521 | if (false === $this->multiContainerMode) { |
||
522 | return [$containerName, $key]; |
||
523 | } |
||
524 | |||
525 | if (false === ($index = strpos($key, '/'))) { |
||
526 | throw new \InvalidArgumentException(sprintf( |
||
527 | 'Failed to establish container name from key "%s", container name is required in multi-container mode', |
||
528 | $key |
||
529 | )); |
||
530 | } |
||
531 | $containerName = substr($key, 0, $index); |
||
532 | $key = substr($key, $index + 1); |
||
533 | |||
534 | return [$containerName, $key]; |
||
535 | } |
||
536 | |||
537 | /** |
||
538 | * @param string $containerName |
||
539 | * @param null $prefix |
||
540 | * |
||
541 | * @return array |
||
542 | */ |
||
543 | private function fetchBlobs($containerName, $prefix = null) |
||
544 | { |
||
545 | $blobList = $this->blobProxy->listBlobs($containerName); |
||
546 | return array_map( |
||
547 | function (Blob $blob) use ($prefix) { |
||
548 | $name = $blob->getName(); |
||
549 | if (null !== $prefix) { |
||
550 | $name = $prefix .'/'. $name; |
||
551 | } |
||
552 | return $name; |
||
553 | }, |
||
554 | $blobList->getBlobs() |
||
555 | ); |
||
556 | } |
||
557 | } |
||
558 |
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.