Container   C
last analyzed

Complexity

Total Complexity 56

Size/Duplication

Total Lines 619
Duplicated Lines 1.94 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 10
Bugs 3 Features 0
Metric Value
wmc 56
c 10
b 3
f 0
lcom 1
cbo 4
dl 12
loc 619
rs 6.376

26 Methods

Rating   Name   Duplication   Size   Complexity  
C __construct() 0 32 7
A getConnection() 0 4 1
A getName() 0 4 1
A getNbObjects() 0 4 1
A getSizeUsed() 0 4 1
A getMetadata() 0 4 1
A updateMetadata() 0 12 2
C enableStaticWeb() 0 27 7
A disableStaticWeb() 0 4 1
A enableObjectVersioning() 0 4 1
A disableObjectVersioning() 0 4 1
B makePublic() 0 26 3
A makePrivate() 0 13 2
A purgeFromCdn() 0 13 3
A logRetention() 0 15 3
A isPublic() 0 8 2
A getPublicUri() 0 8 2
A getPublicSslUri() 0 8 2
A getPublicStreamingUri() 0 8 2
A createObject() 0 4 1
A getObject() 0 4 1
A deleteObject() 0 8 3
A getObjects() 0 10 2
A getObjectsInfo() 0 6 1
A getObjectsList() 0 6 1
A getObjectsRawData() 12 19 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Container often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Container, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * For the full copyright and license information, please view the LICENSE
4
 * file that was distributed with this source code.
5
 *
6
 * @author Nikita Vershinin <[email protected]>
7
 * @license MIT
8
 */
9
namespace OpenStackStorage;
10
11
/**
12
 * \OpenStackStorage\Container object and \OpenStackStorage\Object
13
 * instance factory.
14
 *
15
 * If your account has the feature enabled, containers can be publically
16
 * shared over a global content delivery network.
17
 */
18
class Container
19
{
20
21
    /**
22
     * Connection object.
23
     *
24
     * @var \OpenStackStorage\Connection
25
     */
26
    protected $connection = null;
27
28
    /**
29
     * Container name.
30
     *
31
     * @var string
32
     */
33
    protected $name = null;
34
35
    /**
36
     * Number of objects in container.
37
     *
38
     * @var integer
39
     */
40
    protected $nbObjects = 0;
41
42
    /**
43
     * The sum of the sizes of all objects in this container (in bytes).
44
     *
45
     * @var integer
46
     */
47
    protected $sizeUsed = 0;
48
49
    /**
50
     * Metadata.
51
     *
52
     * @var array
53
     */
54
    protected $metadata = array();
55
56
    /**
57
     * URI for this container, if it is publically accessible via the CDN.
58
     *
59
     * @var string
60
     */
61
    protected $cdnUri = null;
62
63
    /**
64
     * SSL URI for this container, if it is publically accessible via the CDN.
65
     *
66
     * @var string
67
     */
68
    protected $cdnSslUri = null;
69
70
    /**
71
     * Streaming URI for this container, if it is publically accessible
72
     * via the CDN.
73
     *
74
     * @var string
75
     */
76
    protected $cdnStreamingUri = null;
77
78
    /**
79
     * The time-to-live of the CDN's public cache of this container.
80
     *
81
     * @var integer
82
     */
83
    protected $cdnTtl = null;
84
85
    /**
86
     * Retention of the logs in the container.
87
     *
88
     * @var boolean
89
     */
90
    protected $cdnLogRetention = false;
91
92
    /**
93
     * List of parameters that are allowed to be used in the GET-requests to
94
     * fetch
95
     * information about the objects in this container:
96
     *  — limit      For an integer value n, limits the number of results to at
97
     *               most n values.
98
     *  — marker     Given a string value x, return object names greater in
99
     *               value than the specified marker.
100
     *  — end_marker Given a string value x, return object names less in
101
     *               value than the specified marker.
102
     *  — prefix     For a string value x, causes the results to be limited to
103
     *               object names beginning with the substring x.
104
     *  — format     Response format (json, xml, plain).
105
     *  — delimiter  For a character c, return all the object names nested in
106
     *               the container (without the need for the directory marker
107
     *               objects).
108
     *
109
     * @link http://docs.openstack.org/api/openstack-object-storage/1.0/content/list-objects.html
110
     * @var array
111
     */
112
    protected static $allowedParameters = array(
113
        'limit',
114
        'marker',
115
        'end_marker',
116
        'prefix',
117
        'format',
118
        'delimiter',
119
    );
120
121
    /**
122
     * Local cache of requests to fetch list of objects in this container.
123
     *
124
     * @var array
125
     */
126
    protected static $listObjectsCache = array();
127
128
    /**
129
     * The class constructor.
130
     *
131
     * Containers will rarely if ever need to be instantiated directly by
132
     * the user.
133
     *
134
     * Instead, use the \OpenStackStorage\OpenStackStorage\Connection
135
     * object methods:
136
     * <code>
137
     * $connection->createContainer('test');
138
     * $connection->getContainer('test');
139
     * $connection->getContainers();
140
     * </code>
141
     *
142
     * @param \OpenStackStorage\Connection $connection
143
     * @param string                       $name
144
     * @param integer                      $nbObjects
145
     * @param integer                      $sizeUsed
146
     * @param array                        $metadata
147
     */
148
    public function __construct(Connection $connection, $name, $nbObjects = 0, $sizeUsed = 0, array $metadata = array())
149
    {
150
        $this->connection = $connection;
151
        $this->name       = $name;
152
153
        if ($nbObjects > 0) {
154
            $this->nbObjects = intval($nbObjects);
155
        }
156
157
        if ($sizeUsed > 0) {
158
            $this->sizeUsed = intval($sizeUsed);
159
        }
160
161
        if (!empty($metadata)) {
162
            $this->metadata = $metadata;
163
        }
164
165
        // Fetch the CDN data from the CDN service
166
        if ($connection->getCdnEnabled()) {
167
            $response = $connection->makeCdnRequest(Client::HEAD, array($name));
168
169
            $this->cdnUri          = $response['headers']['x-cdn-uri'];
170
            $this->cdnTtl          = $response['headers']['x-ttl'];
0 ignored issues
show
Documentation Bug introduced by
The property $cdnTtl was declared of type integer, but $response['headers']['x-ttl'] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
171
            $this->cdnSslUri       = $response['headers']['x-cdn-ssl-uri'];
172
            $this->cdnStreamingUri = $response['headers']['x-cdn-streaming-uri'];
173
174
            $logRetention = $response['headers']['x-log-retention'];
175
            if ($logRetention && (0 === strcasecmp($logRetention, 'true'))) {
176
                $this->cdnLogRetention = true;
177
            }
178
        }
179
    }
180
181
    /**
182
     * Return the value of the $connection property.
183
     *
184
     * @return \OpenStackStorage\Connection
185
     */
186
    public function getConnection()
187
    {
188
        return $this->connection;
189
    }
190
191
    /**
192
     * Return the value of the $name property.
193
     *
194
     * @return string
195
     */
196
    public function getName()
197
    {
198
        return $this->name;
199
    }
200
201
    /**
202
     * Returns number of objects in container.
203
     *
204
     * @return integer
205
     */
206
    public function getNbObjects()
207
    {
208
        return $this->nbObjects;
209
    }
210
211
    /**
212
     * Returns the sum of the sizes of all objects in this container (in bytes).
213
     *
214
     * @return int
215
     */
216
    public function getSizeUsed()
217
    {
218
        return $this->sizeUsed;
219
    }
220
221
    /**
222
     * Return the value of the $metadata property.
223
     *
224
     * @return array
225
     */
226
    public function getMetadata()
227
    {
228
        return $this->metadata;
229
    }
230
231
    /**
232
     * Updates container metadata.
233
     *
234
     * Example:
235
     * <code>
236
     * $container->updateMetadata(array(
237
     *     'foo' => 'bar',
238
     * ));
239
     * </code>
240
     *
241
     * @param array $metadata
242
     */
243
    public function updateMetadata(array $metadata)
244
    {
245
        $processed = array();
246
247
        foreach ($metadata as $k => $v) {
248
            $processed[strtolower(str_ireplace('X-Container-Meta-', '', $k))] = $v;
249
        }
250
251
        $this->connection->makeRequest(Client::POST, array($this->name), $processed);
252
253
        $this->metadata = $processed;
254
    }
255
256
    /**
257
     * Enable static web for this container.
258
     *
259
     * Example:
260
     * <code>
261
     * $container->enableStaticWeb('index.html', true, 'error.html', 'style.css');
262
     * </code>
263
     *
264
     * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/StaticWeb.html
265
     * @param string  $index
266
     * @param boolean $enableListings
267
     * @param string  $error
268
     * @param string  $listingsCss
269
     */
270
    public function enableStaticWeb($index = null, $enableListings = null, $error = null, $listingsCss = null)
271
    {
272
        $metadata = array(
273
            'X-Container-Meta-Web-Index'        => '',
274
            'X-Container-Meta-Web-Listings'     => '',
275
            'X-Container-Meta-Web-Error'        => '',
276
            'X-Container-Meta-Web-Listings-CSS' => '',
277
        );
278
279
        if (null !== $index) {
280
            $metadata['X-Container-Meta-Web-Index'] = strval($index);
281
        }
282
283
        if (null !== $enableListings && is_bool($enableListings)) {
284
            $metadata['X-Container-Meta-Web-Listings'] = $enableListings ? 'True' : 'False';
285
        }
286
287
        if (null !== $error) {
288
            $metadata['X-Container-Meta-Web-Error'] = strval($error);
289
        }
290
291
        if (null !== $listingsCss) {
292
            $metadata['X-Container-Meta-Listings-CSS'] = strval($listingsCss);
293
        }
294
295
        $this->updateMetadata($metadata);
296
    }
297
298
    /**
299
     * Disable static web for this container.
300
     */
301
    public function disableStaticWeb()
302
    {
303
        $this->enableStaticWeb();
304
    }
305
306
    /**
307
     * Enable object versioning on this container.
308
     *
309
     * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/Object_Versioning-e1e3230.html
310
     * @param string $containerName The container where versions will be stored
311
     */
312
    public function enableObjectVersioning($containerName)
313
    {
314
        $this->updateMetadata(array('X-Versions-Location' => strval($containerName)));
315
    }
316
317
    /**
318
     * Disable object versioning on this container.
319
     */
320
    public function disableObjectVersioning()
321
    {
322
        $this->updateMetadata(array('X-Versions-Location' => ''));
323
    }
324
325
    /**
326
     * Either publishes the current container to the CDN or updates its
327
     * CDN attributes.
328
     * Requires CDN be enabled on the account.
329
     *
330
     * @param  integer                                    $ttl cache duration in seconds of the CDN server
331
     * @throws \OpenStackStorage\Exceptions\CDNNotEnabled
332
     */
333
    public function makePublic($ttl = 86400)
334
    {
335
        if (!$this->connection->getCdnEnabled()) {
336
            throw new Exceptions\CDNNotEnabled();
337
        }
338
339
        if ($this->cdnUri) {
340
            $requestMethod = Client::POST;
341
        } else {
342
            $requestMethod = Client::PUT;
343
        }
344
345
        $response = $this->connection->makeCdnRequest(
346
            $requestMethod,
347
            array($this->name),
348
            array(
349
                'X-TTL'          => strval($ttl),
350
                'X-CDN-Enabled'  => 'True',
351
                'Content-Length' => 0,
352
            )
353
        );
354
355
        $this->cdnTtl    = $ttl;
356
        $this->cdnUri    = $response['headers']['x-cdn-uri'];
357
        $this->cdnSslUri = $response['headers']['x-cdn-ssl-uri'];
358
    }
359
360
    /**
361
     * Disables CDN access to this container.
362
     * It may continue to be available until its TTL expires.
363
     *
364
     * @throws \OpenStackStorage\Exceptions\CDNNotEnabled
365
     */
366
    public function makePrivate()
367
    {
368
        if (!$this->connection->getCdnEnabled()) {
369
            throw new Exceptions\CDNNotEnabled();
370
        }
371
372
        $this->cdnUri = null;
373
        $this->connection->makeCdnRequest(
374
            Client::POST,
375
            array($this->name),
376
            array('X-CDN-Enabled' => 'False')
377
        );
378
    }
379
380
    /**
381
     * Purge Edge cache for all object inside of this container.
382
     * You will be notified by email if one is provided when the
383
     * job completes.
384
     *
385
     * <code>
386
     * $container1->purgeFromCdn();
387
     * $container2->purgeFromCdn('[email protected]');
388
     * $container3->purgeFromCdn('[email protected],[email protected]);
389
     * </code>
390
     *
391
     * @param  string                                     $email
392
     * @throws \OpenStackStorage\Exceptions\CDNNotEnabled
393
     */
394
    public function purgeFromCdn($email = null)
395
    {
396
        if (!$this->connection->getCdnEnabled()) {
397
            throw new Exceptions\CDNNotEnabled();
398
        }
399
400
        $headers = array();
401
        if (null !== $email) {
402
            $headers['X-Purge-Email'] = $email;
403
        }
404
405
        $this->connection->makeCdnRequest(Client::DELETE, array($this->name), $headers);
406
    }
407
408
    /**
409
     * Enable CDN log retention on the container. If enabled logs will be
410
     * periodically (at unpredictable intervals) compressed and uploaded to
411
     * a ".CDN_ACCESS_LOGS" container in the form of
412
     * "container_name/YYYY/MM/DD/HH/XXXX.gz". Requires CDN be enabled on
413
     * the account.
414
     *
415
     * @param  boolean                                    $logRetention
416
     * @throws \OpenStackStorage\Exceptions\CDNNotEnabled
417
     */
418
    public function logRetention($logRetention = false)
419
    {
420
        if (!$this->connection->getCdnEnabled()) {
421
            throw new Exceptions\CDNNotEnabled();
422
        }
423
424
        $logRetention = (boolean) $logRetention;
425
        $this->connection->makeCdnRequest(
426
            Client::POST,
427
            array($this->name),
428
            array('X-Log-Retention' => $logRetention ? 'True' : 'False')
429
        );
430
431
        $this->cdnLogRetention = $logRetention;
432
    }
433
434
    /**
435
     * Return a boolean indicating whether or not this container is
436
     * publically accessible via the CDN.
437
     *
438
     * Example:
439
     * <code>
440
     * $container->isPublic(); // false
441
     * $container->makePublic();
442
     * $container->isPublic(); // true
443
     * </code>
444
     *
445
     * @return boolean
446
     * @throws \OpenStackStorage\Exceptions\CDNNotEnabled
447
     */
448
    public function isPublic()
449
    {
450
        if (!$this->connection->getCdnEnabled()) {
451
            throw new Exceptions\CDNNotEnabled();
452
        }
453
454
        return null !== $this->cdnUri;
455
    }
456
457
    /**
458
     * Return the URI for this container, if it is publically
459
     * accessible via the CDN.
460
     *
461
     * Example:
462
     * <code>
463
     * echo $container->getPublicUri();
464
     * // Outputs "http://c00061.cdn.cloudfiles.rackspacecloud.com"
465
     * </code>
466
     *
467
     * @return string
468
     * @throws \OpenStackStorage\Exceptions\ContainerNotPublic
469
     */
470
    public function getPublicUri()
471
    {
472
        if (!$this->isPublic()) {
473
            throw new Exceptions\ContainerNotPublic();
474
        }
475
476
        return $this->cdnUri;
477
    }
478
479
    /**
480
     * Return the SSL URI for this container, if it is publically
481
     * accessible via the CDN.
482
     *
483
     * Example:
484
     * <code>
485
     * echo $container->getPublicSslUri();
486
     * // Outputs "https://c61.ssl.cf0.rackcdn.com"
487
     * </code>
488
     *
489
     * @return string
490
     * @throws \OpenStackStorage\Exceptions\ContainerNotPublic
491
     */
492
    public function getPublicSslUri()
493
    {
494
        if (!$this->isPublic()) {
495
            throw new Exceptions\ContainerNotPublic();
496
        }
497
498
        return $this->cdnSslUri;
499
    }
500
501
    /**
502
     * Return the Streaming URI for this container, if it is publically
503
     * accessible via the CDN.
504
     *
505
     * Example:
506
     * <code>
507
     * echo $container->getPublicStreamingUri();
508
     * // Outputs "https://c61.stream.rackcdn.com"
509
     * </code>
510
     *
511
     * @return string
512
     * @throws \OpenStackStorage\Exceptions\ContainerNotPublic
513
     */
514
    public function getPublicStreamingUri()
515
    {
516
        if (!$this->isPublic()) {
517
            throw new Exceptions\ContainerNotPublic();
518
        }
519
520
        return $this->cdnStreamingUri;
521
    }
522
523
    /**
524
     * Return an \OpenStackStorage\Object instance, creating it if necessary.
525
     *
526
     * When passed the name of an existing object, this method will
527
     * return an instance of that object, otherwise it will create a
528
     * new one
529
     *
530
     * @param  string                   $name
531
     * @return \OpenStackStorage\Object
532
     */
533
    public function createObject($name)
534
    {
535
        return new Object($this, $name);
536
    }
537
538
    /**
539
     * Return an \OpenStackStorage\Object instance for an existing storage object.
540
     *
541
     * @param  string                                    $name
542
     * @return \OpenStackStorage\Object
543
     * @throws \OpenStackStorage\Exceptions\NoSuchObject
544
     */
545
    public function getObject($name)
546
    {
547
        return new Object($this, $name, true);
548
    }
549
550
    /**
551
     * Permanently remove a storage object.
552
     *
553
     * @param string|\OpenStackStorage\Object $name
554
     */
555
    public function deleteObject($name)
556
    {
557
        if (is_object($name) && $name instanceof Object) {
558
            $name = $name->getName();
559
        }
560
561
        $this->connection->makeRequest(Client::DELETE, array($this->name, $name));
562
    }
563
564
    /**
565
     * Return array with objects of container.
566
     *
567
     * @see \OpenStackStorage\Container::$allowedParameters
568
     * @param  array                      $parameters
569
     * @return \OpenStackStorage\Object[]
570
     */
571
    public function getObjects(array $parameters = array())
572
    {
573
        $objects = array();
574
575
        foreach ($this->getObjectsInfo($parameters) as $record) {
0 ignored issues
show
Bug introduced by
The expression $this->getObjectsInfo($parameters) of type string is not traversable.
Loading history...
576
            $objects[] = new Object($this, null, false, $record);
577
        }
578
579
        return $objects;
580
    }
581
582
    /**
583
     * Return information about objects in container.
584
     *
585
     * @see \OpenStackStorage\Container::$allowedParameters
586
     * @param  array $parameters
587
     * @return array
588
     */
589
    public function getObjectsInfo(array $parameters = array())
590
    {
591
        $parameters['format'] = 'json';
592
593
        return $this->getObjectsRawData($parameters);
594
    }
595
596
    /**
597
     * Return names of objects in container.
598
     *
599
     * @see \OpenStackStorage\Container::$allowedParameters
600
     * @param  array $parameters
601
     * @return array
602
     */
603
    public function getObjectsList(array $parameters = array())
604
    {
605
        $parameters['format'] = 'plain';
606
607
        return array_filter(explode("\n", trim($this->getObjectsRawData($parameters))));
608
    }
609
610
    /**
611
     * Return a raw response string with information about container objects.
612
     *
613
     * @see \OpenStackStorage\Container::$allowedParameters
614
     * @param  array  $parameters
615
     * @return string
616
     */
617
    protected function getObjectsRawData(array $parameters = array())
618
    {
619
        $cacheKey = md5(json_encode(array($this->getName(), $parameters)));
620
621 View Code Duplication
        if (!array_key_exists($cacheKey, self::$listObjectsCache)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
622
            $tmp = array();
623
624
            foreach ($parameters as $k => $v) {
625
                if (in_array($k, self::$allowedParameters)) {
626
                    $tmp[$k] = $v;
627
                }
628
            }
629
630
            $response = $this->connection->makeRequest(Client::GET, array($this->name), array(), $tmp);
631
            self::$listObjectsCache[$cacheKey] = $response['body'];
632
        }
633
634
        return self::$listObjectsCache[$cacheKey];
635
    }
636
}
637