Completed
Push — master ( 66d97d...3ff11a )
by Jonathan
13:26 queued 09:11
created

AbstractReportingCloud   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 509
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 97.06%

Importance

Changes 18
Bugs 0 Features 0
Metric Value
wmc 41
c 18
b 0
f 0
lcom 2
cbo 6
dl 0
loc 509
ccs 132
cts 136
cp 0.9706
rs 8.2769

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 3
A getClient() 0 21 2
A setClient() 0 6 1
A getBaseUri() 0 8 2
A setBaseUri() 0 6 1
A getTimeout() 0 8 2
A setTimeout() 0 6 1
A getUsername() 0 4 1
A setUsername() 0 6 1
A getPassword() 0 4 1
A setPassword() 0 6 1
A getTest() 0 8 2
A setTest() 0 6 1
A getDebug() 0 8 2
A setDebug() 0 6 1
A getVersion() 0 8 2
A setVersion() 0 6 1
A uri() 0 4 1
A buildPropertyMapArray() 0 17 4
B buildMergeSettingsArray() 0 22 5
A buildFindAndReplaceDataArray() 0 10 2
B request() 0 31 4

How to fix   Complexity   

Complex Class

Complex classes like AbstractReportingCloud 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 AbstractReportingCloud, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * ReportingCloud PHP Wrapper
5
 *
6
 * PHP wrapper for ReportingCloud Web API. Authored and supported by Text Control GmbH.
7
 *
8
 * @link      http://www.reporting.cloud to learn more about ReportingCloud
9
 * @link      https://github.com/TextControl/txtextcontrol-reportingcloud-php for the canonical source repository
10
 * @license   https://raw.githubusercontent.com/TextControl/txtextcontrol-reportingcloud-php/master/LICENSE.md
11
 * @copyright © 2016 Text Control GmbH
12
 */
13
namespace TxTextControl\ReportingCloud;
14
15
use GuzzleHttp\Client;
16
use GuzzleHttp\RequestOptions;
17
use TxTextControl\ReportingCloud\Exception\RuntimeException;
18
use TxTextControl\ReportingCloud\Filter\StaticFilter;
19
use TxTextControl\ReportingCloud\PropertyMap\AbstractPropertyMap as PropertyMap;
20
use TxTextControl\ReportingCloud\PropertyMap\MergeSettings as MergeSettingsPropertyMap;
21
use TxTextControl\ReportingCloud\Validator\StaticValidator;
22
23
/**
24
 * Abstract ReportingCloud
25
 *
26
 * @package TxTextControl\ReportingCloud
27
 * @author  Jonathan Maron (@JonathanMaron)
28
 */
29
abstract class AbstractReportingCloud
30
{
31
32
    /**
33
     * Default date/time format of backend is 'ISO 8601'
34
     *
35
     * Note, last letter is 'P' and not 'O':
36
     *
37
     * O - Difference to Greenwich time (GMT) in hours (e.g. +0200)
38
     * P - Difference to Greenwich time (GMT) with colon between hours and minutes (e.g. +02:00)
39
     *
40
     * Backend uses the 'P' variant
41
     *
42
     * @const DEFAULT_DATE_FORMAT
43
     */
44
    const DEFAULT_DATE_FORMAT = 'Y-m-d\TH:i:sP';
45
46
    /**
47
     * Default time zone of backend
48
     *
49
     * @const DEFAULT_TIME_ZONE
50
     */
51
    const DEFAULT_TIME_ZONE = 'UTC';
52
53
    /**
54
     * Default base URI of backend
55
     *
56
     * @const DEFAULT_BASE_URI
57
     */
58
    const DEFAULT_BASE_URI = 'https://api.reporting.cloud';
59
60
    /**
61
     * Default version string of backend
62
     *
63
     * @const DEFAULT_VERSION
64
     */
65
    const DEFAULT_VERSION = 'v1';
66
67
    /**
68
     * Default timeout of backend in seconds
69
     *
70
     * @const DEFAULT_TIMEOUT
71
     */
72
    const DEFAULT_TIMEOUT = 120; // seconds
73
74
    /**
75
     * Default test flag of backend
76
     *
77
     * @const DEFAULT_TEST
78
     */
79
    const DEFAULT_TEST = false;
80
81
    /**
82
     * Default debug flag of REST client
83
     *
84
     * @const DEFAULT_DEBUG
85
     */
86
    const DEFAULT_DEBUG = false;
87
88
    /**
89
     * Backend username
90
     *
91
     * @var string
92
     */
93
    protected $username;
94
95
    /**
96
     * Backend password
97
     *
98
     * @var string
99
     */
100
    protected $password;
101
102
    /**
103
     * When true, backend prints "TEST MODE" water mark into output document, and API call does not count against quota
104
     *
105
     * @var boolean
106
     */
107
    protected $test;
108
109
    /**
110
     * Backend base URI
111
     *
112
     * @var string
113
     */
114
    protected $baseUri;
115
116
    /**
117
     * Backend version string
118
     *
119
     * @var string
120
     */
121
    protected $version;
122
123
    /**
124
     * Backend timeout in seconds
125
     *
126
     * @var integer
127
     */
128
    protected $timeout;
129
130
    /**
131
     * REST client to backend
132
     *
133
     * @var Client
134
     */
135
    protected $client;
136
137
    /**
138
     * Debug flag of REST client
139
     *
140
     * @var boolean
141
     */
142
    protected $debug;
143
144
    /**
145
     * AbstractReportingCloud constructor
146
     *
147
     * @param array $options
148
     */
149 57
    public function __construct(array $options = [])
150
    {
151
        $methods = [
152 57
            'base_uri' => 'setBaseUri',
153 57
            'debug'    => 'setDebug',
154 57
            'password' => 'setPassword',
155 57
            'test'     => 'setTest',
156 57
            'timeout'  => 'setTimeout',
157 57
            'username' => 'setUsername',
158 57
            'version'  => 'setVersion',
159 57
        ];
160
161 57
        foreach ($methods as $key => $method) {
162 57
            if (array_key_exists($key, $options)) {
163 1
                $this->$method($options[$key]);
164 1
            }
165 57
        }
166 57
    }
167
168
    /**
169
     * Setters and getters
170
     * =================================================================================================================
171
     */
172
173
    /**
174
     * Return the REST client of the backend web service
175
     *
176
     * @return \GuzzleHttp\Client
177
     */
178 16
    public function getClient()
179
    {
180 16
        if (null === $this->client) {
181
182 16
            $credentials   = sprintf('%s:%s', $this->getUsername(), $this->getPassword());
183 16
            $authorization = sprintf('Basic %s', base64_encode($credentials));
184
185 16
            $client = new Client([
186 16
                'base_uri'              => $this->getBaseUri(),
187 16
                RequestOptions::TIMEOUT => $this->getTimeout(),
188 16
                RequestOptions::DEBUG   => $this->getDebug(),
189 16
                RequestOptions::HEADERS => [
190 16
                    'Authorization' => $authorization,
191 16
                ],
192 16
            ]);
193
194 16
            $this->setClient($client);
195 16
        }
196
197 16
        return $this->client;
198
    }
199
200
    /**
201
     * Set the REST client of the backend web service
202
     *
203
     * @param Client $client REST client
204
     *
205
     * @return ReportingCloud
206
     */
207 16
    public function setClient(Client $client)
208
    {
209 16
        $this->client = $client;
210
211 16
        return $this;
212
    }
213
214
    /**
215
     * Return the base URI of the backend web service
216
     *
217
     * @return string
218
     */
219 20
    public function getBaseUri()
220
    {
221 20
        if (null === $this->baseUri) {
222 18
            $this->setBaseUri(self::DEFAULT_BASE_URI);
223 18
        }
224
225 20
        return $this->baseUri;
226
    }
227
228
    /**
229
     * Set the base URI of the backend web service
230
     *
231
     * @param string $baseUri Base URI
232
     *
233
     * @return ReportingCloud
234
     */
235 20
    public function setBaseUri($baseUri)
236
    {
237 20
        $this->baseUri = $baseUri;
238
239 20
        return $this;
240
    }
241
242
    /**
243
     * Get the timeout (in seconds) of the backend web service
244
     *
245
     * @return integer
246
     */
247 19
    public function getTimeout()
248
    {
249 19
        if (null === $this->timeout) {
250 17
            $this->setTimeout(self::DEFAULT_TIMEOUT);
251 17
        }
252
253 19
        return $this->timeout;
254
    }
255
256
    /**
257
     * Set the timeout (in seconds) of the backend web service
258
     *
259
     * @param integer $timeout Timeout
260
     *
261
     * @return ReportingCloud
262
     */
263 19
    public function setTimeout($timeout)
264
    {
265 19
        $this->timeout = (integer) $timeout;
266
267 19
        return $this;
268
    }
269
270
    /**
271
     * Return the username
272
     *
273
     * @return string
274
     */
275 19
    public function getUsername()
276
    {
277 19
        return $this->username;
278
    }
279
280
    /**
281
     * Set the username
282
     *
283
     * @param string $username Username
284
     *
285
     * @return ReportingCloud
286
     */
287 54
    public function setUsername($username)
288
    {
289 54
        $this->username = $username;
290
291 54
        return $this;
292
    }
293
294
    /**
295
     * Return the password
296
     *
297
     * @return string
298
     */
299 19
    public function getPassword()
300
    {
301 19
        return $this->password;
302
    }
303
304
    /**
305
     * Set the password
306
     *
307
     * @param string $password Password
308
     *
309
     * @return ReportingCloud
310
     */
311 54
    public function setPassword($password)
312
    {
313 54
        $this->password = $password;
314
315 54
        return $this;
316
    }
317
318
    /**
319
     * Return the test flag
320
     *
321
     * @return mixed
322
     */
323 17
    public function getTest()
324
    {
325 17
        if (null === $this->test) {
326 15
            $this->setTest(self::DEFAULT_TEST);
327 15
        }
328
329 17
        return $this->test;
330
    }
331
332
    /**
333
     * Set the test flag
334
     *
335
     * @param boolean $test Test flag
336
     *
337
     * @return ReportingCloud
338
     */
339 17
    public function setTest($test)
340
    {
341 17
        $this->test = (boolean) $test;
342
343 17
        return $this;
344
    }
345
346
    /**
347
     * Return the debug flag
348
     *
349
     * @return mixed
350
     */
351 19
    public function getDebug()
352
    {
353 19
        if (null === $this->debug) {
354 17
            $this->setDebug(self::DEFAULT_DEBUG);
355 17
        }
356
357 19
        return $this->debug;
358
    }
359
360
    /**
361
     * Set the debug flag
362
     *
363
     * @param boolean $debug Debug flag
364
     *
365
     * @return ReportingCloud
366
     */
367 19
    public function setDebug($debug)
368
    {
369 19
        $this->debug = (boolean) $debug;
370
371 19
        return $this;
372
    }
373
374
    /**
375
     * Get the version string of the backend web service
376
     *
377
     * @return string
378
     */
379 18
    public function getVersion()
380
    {
381 18
        if (null === $this->version) {
382 16
            $this->version = self::DEFAULT_VERSION;
383 16
        }
384
385 18
        return $this->version;
386
    }
387
388
    /**
389
     * Set the version string of the backend web service
390
     *
391
     * @param string $version Version string
392
     *
393
     * @return ReportingCloud
394
     */
395 2
    public function setVersion($version)
396
    {
397 2
        $this->version = $version;
398
399 2
        return $this;
400
    }
401
402
403
    /**
404
     * Utility methods
405
     * =================================================================================================================
406
     */
407
408
    /**
409
     * Request the URI with options
410
     *
411
     * @param string $method  HTTP method
412
     * @param string $uri     URI
413
     * @param array  $options Options
414
     *
415
     * @return mixed|null|\Psr\Http\Message\ResponseInterface
416
     *
417
     * @throws RuntimeException
418
     */
419 15
    protected function request($method, $uri, $options)
420
    {
421 15
        $ret = null;
422
423 15
        $client = $this->getClient();
424
425
        try {
426
427 15
            if (getenv('TRAVIS')) {
428
                $options['curl'][CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_1;
429
            }
430
431 15
            if ($this->getTest()) {
432
                $options[RequestOptions::QUERY]['test'] = StaticFilter::execute($this->getTest(), 'BooleanToString');
433
            }
434
435 15
            $ret = $client->request($method, $uri, $options);
436
437 15
        } catch (\Exception $exception) {
438
439
            // \GuzzleHttp\Exception\ClientException
440
            // \GuzzleHttp\Exception\ServerException
441
442 1
            $message = (string)  $exception->getMessage();
443 1
            $code    = (integer) $exception->getCode();
444
445 1
            throw new RuntimeException($message, $code);
446
        }
447
448 14
        return $ret;
449
    }
450
451
    /**
452
     * Construct URI with version number
453
     *
454
     * @param string $uri URI
455
     *
456
     * @return string
457
     */
458 15
    protected function uri($uri)
459
    {
460 15
        return sprintf('/%s%s', $this->getVersion(), $uri);
461
    }
462
463
    /**
464
     * Using the passed propertyMap, recursively build array
465
     *
466
     * @param array       $array       Array
467
     * @param PropertyMap $propertyMap PropertyMap
468
     *
469
     * @return array
470
     */
471 3
    protected function buildPropertyMapArray(array $array, PropertyMap $propertyMap)
472
    {
473 3
        $ret = [];
474
475 3
        foreach ($array as $key => $value) {
476 3
            $map = $propertyMap->getMap();
477 3
            if (isset($map[$key])) {
478 3
                $key = $map[$key];
479 3
            }
480 3
            if (is_array($value)) {
481 2
                $value = $this->buildPropertyMapArray($value, $propertyMap);
482 2
            }
483 3
            $ret[$key] = $value;
484 3
        }
485
486 3
        return $ret;
487
    }
488
489
    /**
490
     * Using passed mergeSettings array, build array for backend
491
     *
492
     * @param array $array MergeSettings array
493
     *
494
     * @return array
495
     */
496 8
    protected function buildMergeSettingsArray(array $array)
497
    {
498 8
        $ret = [];
499
500 8
        $propertyMap = new MergeSettingsPropertyMap();
501
502 8
        foreach ($propertyMap->getMap() as $property => $key) {
503 8
            if (isset($array[$key])) {
504 8
                $value = $array[$key];
505 8
                if ('remove_' == substr($key, 0, 7)) {
506 6
                    StaticValidator::execute($value, 'TypeBoolean');
507 4
                }
508 8
                if ('_date' == substr($key, -5)) {
509 8
                    StaticValidator::execute($value, 'Timestamp');
510 6
                    $value = StaticFilter::execute($value, 'TimestampToDateTime');
511 6
                }
512 8
                $ret[$property] = $value;
513 8
            }
514 8
        }
515
516 4
        return $ret;
517
    }
518
519
    /**
520
     * Using passed findAndReplaceData associative array (key-value), build array for backend (list of string arrays)
521
     *
522
     * @param array $array FindAndReplaceData array
523
     *
524
     * @return array
525
     */
526 4
    protected function buildFindAndReplaceDataArray(array $array)
527
    {
528 4
        $ret = [];
529
530 4
        foreach ($array as $search => $replace) {
531 4
            array_push($ret, [$search, $replace]);
532 4
        }
533
534 4
        return $ret;
535
    }
536
537
}