Completed
Pull Request — master (#15)
by Mischa
04:22
created

ContentApiSdk::processParameters()   C

Complexity

Conditions 22
Paths 25

Size

Total Lines 53
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 53
rs 6.1683
cc 22
eloc 39
nc 25
nop 2

3 Methods

Rating   Name   Duplication   Size   Complexity  
A ContentApiSdk::getAvailableEndpoints() 0 7 1
A ContentApiSdk::getValidJsonObj() 0 9 3
A ContentApiSdk::getVersionURL() 0 4 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of the PHP SDK library for the Superdesk Content API.
5
 *
6
 * Copyright 2015 Sourcefabric z.u. and contributors.
7
 *
8
 * For the full copyright and license information, please see the
9
 * AUTHORS and LICENSE files distributed with this source code.
10
 *
11
 * @copyright 2015 Sourcefabric z.ú.
12
 * @license http://www.superdesk.org/license
13
 */
14
15
namespace Superdesk\ContentApiSdk;
16
17
use Superdesk\ContentApiSdk\API\Request;
18
use Superdesk\ContentApiSdk\API\Request\VersionDecorator;
19
use Superdesk\ContentApiSdk\API\Response;
20
use Superdesk\ContentApiSdk\API\Pagerfanta\ItemAdapter;
21
use Superdesk\ContentApiSdk\API\Pagerfanta\PackageAdapter;
22
use Superdesk\ContentApiSdk\API\Pagerfanta\ResourceCollection;
23
use Superdesk\ContentApiSdk\Client\ApiClientInterface;
24
use Superdesk\ContentApiSdk\Data\Item;
25
use Superdesk\ContentApiSdk\Data\Package;
26
use Superdesk\ContentApiSdk\Exception\ClientException;
27
use Superdesk\ContentApiSdk\Exception\ContentApiException;
28
use Superdesk\ContentApiSdk\Exception\InvalidArgumentException;
29
use Superdesk\ContentApiSdk\Exception\InvalidDataException;
30
use Exception;
31
use stdClass;
32
33
/**
34
 * Superdesk ContentApi class.
35
 */
36
class ContentApiSdk
37
{
38
    /**
39
     * Items endpoint
40
     */
41
    const SUPERDESK_ENDPOINT_ITEMS = '/items';
42
43
    /**
44
     * Package endpoint
45
     */
46
    const SUPERDESK_ENDPOINT_PACKAGES = '/packages';
47
48
    /**
49
     * Type indication for packages
50
     */
51
    const PACKAGE_TYPE_COMPOSITE = 'composite';
52
53
    /**
54
     * Supported API version by this SDK version
55
     */
56
    const API_VERSION = 1;
57
58
    /**
59
     * Useragent string sent to the API when making requests.
60
     */
61
    const USERAGENT = 'Content API SDK v1';
62
63
    /**
64
     * Any (http) client that implements ClientInterface.
65
     *
66
     * @var ApiClientInterface
67
     */
68
    protected $client;
69
70
    /**
71
     * Protocol to reach the api instance.
72
     *
73
     * @var string|null
74
     */
75
    protected $protocol = null;
76
77
    /**
78
     * Hostname of the api instance.
79
     *
80
     * @var string|null
81
     */
82
    protected $host = null;
83
84
    /**
85
     * Port of the api instance.
86
     *
87
     * @var int|null
88
     */
89
    protected $port = null;
90
91
    /**
92
     * Authentication object.
93
     *
94
     * @var AuthenticationInterface
95
     */
96
    protected $authentication = null;
97
98
    /**
99
     * Construct method for class.
100
     *
101
     * @param ApiClientInterface $client
102
     * @param string|null $host
103
     * @param int|null $port
104
     * @param string|null $protocol
105
     */
106
    public function __construct(
107
        ApiClientInterface $client,
108
        $host = null,
109
        $port = null,
110
        $protocol = null
111
    ) {
112
        $this->client = $client;
113
114
        if (!is_null($host)) {
115
            $this->setHost($host);
116
        }
117
118
        if (!is_null($port)) {
119
            $this->setPort($port);
120
        }
121
122
        if (!is_null($protocol)) {
123
            $this->setProtocol($protocol);
124
        }
125
    }
126
127
    /**
128
     * Gets the value of client.
129
     *
130
     * @return ApiClientInterface
131
     */
132
    public function getClient()
133
    {
134
        return $this->client;
135
    }
136
137
    /**
138
     * Sets the value of client.
139
     *
140
     * @param ApiClientInterface $client Value to set
141
     *
142
     * @return self
143
     */
144
    public function setClient(ApiClientInterface $client)
145
    {
146
        $this->client = $client;
147
148
        return $this;
149
    }
150
151
    /**
152
     * Gets the value of apiHost.
153
     *
154
     * @return string|null
155
     */
156
    public function getHost()
157
    {
158
        return $this->host;
159
    }
160
161
    /**
162
     * Sets the value of host.
163
     *
164
     * @param string|null $host Value to set
165
     *
166
     * @return self
167
     */
168
    public function setHost($host)
169
    {
170
        $this->host = $host;
171
172
        return $this;
173
    }
174
175
    /**
176
     * Gets the value of port.
177
     *
178
     * @return int|null
179
     */
180
    public function getPort()
181
    {
182
        return $this->port;
183
    }
184
185
    /**
186
     * Sets the value of port.
187
     *
188
     * @param int|null $port Value to set
189
     *
190
     * @return self
191
     */
192
    public function setPort($port)
193
    {
194
        $this->port = $port;
195
196
        return $this;
197
    }
198
199
    /**
200
     * Gets the value of protocol.
201
     *
202
     * @return string|null
203
     */
204
    public function getProtocol()
205
    {
206
        return $this->protocol;
207
    }
208
209
    /**
210
     * Sets the value of protocol.
211
     *
212
     * @param string|null $protocol Value to set
213
     *
214
     * @return self
215
     */
216
    public function setProtocol($protocol)
217
    {
218
        $this->protocol = $protocol;
219
220
        return $this;
221
    }
222
223
    /**
224
     * Get a single item via id.
225
     *
226
     * @param string $itemId Identifier for item
227
     *
228
     * @return Item
229
     */
230
    public function getItem($itemId)
231
    {
232
        $request = $this->getNewRequest(sprintf('%s/%s', self::SUPERDESK_ENDPOINT_ITEMS, $itemId));
233
234
        try {
235
            $response = $this->client->makeApiCall($request);
236
            $item = new Item($response->getResources());
237
238
            return $item;
239
        } catch (ClientException $e) {
240
            throw new ContentApiException($e->getMessage(), $e->getCode(), $e);
241
        }
242
    }
243
244
    /**
245
     * Get multiple items based on a filter.
246
     *
247
     * @param array $params Filter parameters
248
     *
249
     * @return ResourceCollection
250
     */
251 View Code Duplication
    public function getItems($params)
0 ignored issues
show
Duplication introduced by
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...
252
    {
253
        $itemCollection = new ResourceCollection(
254
            new ItemAdapter(
255
                $this->client,
256
                $this->getNewRequest(self::SUPERDESK_ENDPOINT_ITEMS, $params)
257
            )
258
        );
259
260
        $page = (isset($params['page'])) ? $params['page'] : 1;
261
        $maxResults = (isset($params['max_results'])) ? $params['max_results'] : 25;
262
263
        $itemCollection->setCurrentPage($page);
264
        $itemCollection->setMaxPerPage($maxResults);
265
266
        return $itemCollection;
267
    }
268
269
    /**
270
     * Get package by identifier.
271
     *
272
     * @param string $packageId Package identifier
273
     * @param bool   $resolveAssociations Inject full associations recursively
274
     *                                    instead of references by uri.
275
     *
276
     * @return Package
277
     */
278
    public function getPackage($packageId, $resolveAssociations = false)
279
    {
280
        $request = $this->getNewRequest(sprintf('%s/%s', self::SUPERDESK_ENDPOINT_PACKAGES, $packageId));
281
        $response = $this->client->makeApiCall($request);
282
283
        $package = new Package($response->getResources());
284
285
        // This can be removed once the API fully supports retrieving package associations
286
        if ($resolveAssociations) {
287
            $associations = $this->getAssociationsFromPackage($package);
288
            $package = $this->injectAssociations($package, $associations);
289
        }
290
291
        return $package;
292
    }
293
294
    /**
295
     * Get multiple packages based on a filter.
296
     *
297
     * @param array $params Filter parameters
298
     * @param bool  $resolveAssociations Inject full associations recursively
299
     *                                   instead of references by uri.
300
     *
301
     * @return ResourceCollection
302
     */
303 View Code Duplication
    public function getPackages($params, $resolveAssociations = false)
0 ignored issues
show
Duplication introduced by
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...
304
    {
305
        $packageCollection = new ResourceCollection(
306
            new PackageAdapter(
307
                $this->client,
308
                $this->getNewRequest(self::SUPERDESK_ENDPOINT_PACKAGES, $params),
309
                $this,
310
                $resolveAssociations
311
            )
312
        );
313
314
        // TODO: Check if we actually need these 5 lines of code
315
        $page = (isset($params['page'])) ? $params['page'] : 1;
316
        $maxResults = (isset($params['max_results'])) ? $params['max_results'] : 25;
317
318
        $packageCollection->setCurrentPage($page);
319
        $packageCollection->setMaxPerPage($maxResults);
320
321
        return $packageCollection;
322
    }
323
324
    /**
325
     * Gets full objects for all associations for a package.
326
     *
327
     * @param Package $package A package
328
     *
329
     * @return stdClass List of associations
330
     */
331
    public function getAssociationsFromPackage(Package $package)
332
    {
333
        $associations = new stdClass();
334
335
        if (isset($package->associations)) {
336
            foreach ($package->associations as $associationGroupName => $associationGroupItems) {
337
338
                $groupAssociations = new stdClass();
339
340
                foreach ($associationGroupItems AS $associatedName => $associatedItem) {
341
                    $associatedId = $this->getIdFromUri($associatedItem->uri);
342
343
                    try {
344
                        if ($associatedItem->type == self::PACKAGE_TYPE_COMPOSITE) {
345
                            $associatedObj = $this->getPackage($associatedId, true);
346
                        } else {
347
                            $associatedObj = $this->getItem($associatedId);
348
                            $associatedObj->type = $associatedItem->type;
349
                        }
350
                    } catch (ContentApiException $e) {
351
                        // If subrequests fail, dont fail main request
352
                    }
353
354
                    $groupAssociations->$associatedName = $associatedObj;
355
                }
356
357
                $associations->$associationGroupName = $groupAssociations;
358
            }
359
        }
360
361
        return $associations;
362
    }
363
364
    /**
365
     * Overwrite the associations links in a packages with the actual association
366
     * data.
367
     *
368
     * @param Package  $package      Package
369
     * @param stdClass $associations Multiple items or packages
370
     *
371
     * @return Package Package with data injected
372
     */
373
    public function injectAssociations(Package $package, stdClass $associations)
374
    {
375
        if (count($package->associations) > 0 && count($associations) > 0) {
376
            $package->associations = $associations;
377
        }
378
379
        return $package;
380
    }
381
382
    /**
383
     * Shortcut method to create new class.
384
     *
385
     * @param  string $uri Uri of the request
386
     * @param  array $parameters Parameters for the request object
387
     *
388
     * @return Request
389
     */
390
    public function getNewRequest($uri, array $parameters = array())
391
    {
392
        try {
393
            $request = new Request($this->host, $uri, $parameters, $this->port, $this->protocol);
394
            $versionedRequest = new VersionDecorator($request);
395
            $versionedRequest->addVersion();
396
        } catch (ContentApiException $e) {
397
            throw new ContentApiException($e->getMessage(), $e->getCode(), $e);
398
        }
399
400
        return $versionedRequest;
401
    }
402
403
    /**
404
     * Tries to find a valid id in an uri, both item as package uris. The id
405
     * is returned urldecoded.
406
     *
407
     * @param string $uri Item or package uri
408
     *
409
     * @return string Urldecoded id
410
     */
411
    public static function getIdFromUri($uri)
412
    {
413
        /*
414
         * Works for package and item uris
415
         *   http://publicapi:5050/packages/tag%3Ademodata.org%2C0012%3Aninjs_XYZ123
416
         *   http://publicapi:5050/items/tag%3Ademodata.org%2C0003%3Aninjs_XYZ123
417
         */
418
419
        $uriPath = parse_url($uri, PHP_URL_PATH);
420
        $objectId = str_replace(self::getAvailableEndpoints(), '', $uriPath);
421
        // Remove possible slashes and spaces, since we're working with urls
422
        $objectId = trim($objectId, '/ ');
423
        $objectId = urldecode($objectId);
424
425
        return $objectId;
426
    }
427
428
    /**
429
     * Returns a list of all supported endpoints for the Superdesk Content API.
430
     *
431
     * @return string[]
432
     */
433
    public static function getAvailableEndpoints()
434
    {
435
        return array(
436
            self::SUPERDESK_ENDPOINT_ITEMS,
437
            self::SUPERDESK_ENDPOINT_PACKAGES,
438
        );
439
    }
440
441
    /**
442
     * Converts json string into StdClass object. Throws an InvalidDataException
443
     * when string could not be converted to object.
444
     *
445
     * @param string $jsonString JSON string
446
     *
447
     * @return object
448
     * @throws Exception|InvalidDataException
449
     */
450
    public static function getValidJsonObj($jsonString)
451
    {
452
        $jsonObj = json_decode($jsonString);
453
        if (is_null($jsonObj) || json_last_error() !== JSON_ERROR_NONE) {
454
            throw new InvalidDataException('Response body is not (valid) json.', json_last_error());
455
        }
456
457
        return $jsonObj;
458
    }
459
460
    /**
461
     * Returns version of api for creating verioned url.
462
     *
463
     * @return string
464
     */
465
    public static function getVersionURL()
466
    {
467
        return sprintf('v%d', self::API_VERSION);
468
    }
469
}
470