Completed
Pull Request — master (#15)
by Mischa
11:40 queued 04:07
created

ContentApiSdk::getValidParameters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
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
     * Hostname of the api instance
72
     *
73
     * @var string
74
     */
75
    protected $host;
76
77
    /**
78
     * Port of the api instalce
79
     *
80
     * @var int
81
     */
82
    protected $port = null;
83
84
    /**
85
     * Authentication object.
86
     *
87
     * @var AuthenticationInterface
88
     */
89
    protected $authentication = null;
90
91
    /**
92
     * Construct method for class.
93
     *
94
     * @param ApiClientInterface $client
95
     * @param string|null $host
96
     * @param int|null $port
97
     */
98
    public function __construct(ApiClientInterface $client, $host = null, $port = null)
99
    {
100
        $this->client = $client;
101
102
        if (!is_null($host)) {
103
            $this->setHost($host);
104
        }
105
106
        if (!is_null($port)) {
107
            $this->setPort($port);
108
        }
109
    }
110
111
    /**
112
     * Gets the value of client.
113
     *
114
     * @return ApiClientInterface
115
     */
116
    public function getClient()
117
    {
118
        return $this->client;
119
    }
120
121
    /**
122
     * Sets the value of client.
123
     *
124
     * @param ApiClientInterface $client Value to set
125
     *
126
     * @return self
127
     */
128
    public function setClient(ApiClientInterface $client)
129
    {
130
        $this->client = $client;
131
132
        return $this;
133
    }
134
135
    /**
136
     * Gets the value of apiHost.
137
     *
138
     * @return string
139
     */
140
    public function getHost()
141
    {
142
        return $this->host;
143
    }
144
145
    /**
146
     * Sets the value of host.
147
     *
148
     * @param string $host Value to set
149
     *
150
     * @return self
151
     */
152
    public function setHost($host)
153
    {
154
        if (!is_string($host)) {
155
            throw new ContentApiException('The property host should be of type integer.');
156
        }
157
158
        $this->host = $host;
159
160
        return $this;
161
    }
162
163
    /**
164
     * Gets the value of port.
165
     *
166
     * @return int
167
     */
168
    public function getPort()
169
    {
170
        return $this->port;
171
    }
172
173
    /**
174
     * Sets the value of port.
175
     *
176
     * @param int $port Value to set
177
     *
178
     * @return self
179
     */
180
    public function setPort($port)
181
    {
182
        if (!is_int($port)) {
183
            throw new ContentApiException('The property port should be of type integer.');
184
        }
185
186
        $this->port = $port;
187
188
        return $this;
189
    }
190
191
    /**
192
     * Get a single item via id.
193
     *
194
     * @param string $itemId Identifier for item
195
     *
196
     * @return Item
197
     */
198
    public function getItem($itemId)
199
    {
200
        $request = $this->getNewRequest(sprintf('%s/%s', self::SUPERDESK_ENDPOINT_ITEMS, $itemId));
201
202
        try {
203
            $response = $this->client->makeApiCall($request);
204
            $item = new Item($response->getResources());
205
206
            return $item;
207
        } catch (ClientException $e) {
208
            throw new ContentApiException($e->getMessage(), $e->getCode(), $e);
209
        }
210
    }
211
212
    /**
213
     * Get multiple items based on a filter.
214
     *
215
     * @param array $params Filter parameters
216
     *
217
     * @return ResourceCollection
218
     */
219 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...
220
    {
221
        $itemCollection = new ResourceCollection(
222
            new ItemAdapter(
223
                $this->client,
224
                $this->getNewRequest(self::SUPERDESK_ENDPOINT_ITEMS, $params)
225
            )
226
        );
227
228
        $page = (isset($params['page'])) ? $params['page'] : 1;
229
        $maxResults = (isset($params['max_results'])) ? $params['max_results'] : 25;
230
231
        $itemCollection->setCurrentPage($page);
232
        $itemCollection->setMaxPerPage($maxResults);
233
234
        return $itemCollection;
235
    }
236
237
    /**
238
     * Get package by identifier.
239
     *
240
     * @param string $packageId Package identifier
241
     * @param bool   $resolveAssociations Inject full associations recursively
242
     *                                    instead of references by uri.
243
     *
244
     * @return Package
245
     */
246
    public function getPackage($packageId, $resolveAssociations = false)
247
    {
248
        $request = $this->getNewRequest(sprintf('%s/%s', self::SUPERDESK_ENDPOINT_PACKAGES, $packageId));
249
        $response = $this->client->makeApiCall($request);
250
251
        $package = new Package($response->getResources());
252
253
        // This can be removed once the API fully supports retrieving package associations
254
        if ($resolveAssociations) {
255
            $associations = $this->getAssociationsFromPackage($package);
256
            $package = $this->injectAssociations($package, $associations);
257
        }
258
259
        return $package;
260
    }
261
262
    /**
263
     * Get multiple packages based on a filter.
264
     *
265
     * @param array $params Filter parameters
266
     * @param bool  $resolveAssociations Inject full associations recursively
267
     *                                   instead of references by uri.
268
     *
269
     * @return ResourceCollection
270
     */
271 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...
272
    {
273
        $packageCollection = new ResourceCollection(
274
            new PackageAdapter(
275
                $this->client,
276
                $this->getNewRequest(self::SUPERDESK_ENDPOINT_PACKAGES, $params),
277
                $this,
278
                $resolveAssociations
279
            )
280
        );
281
282
        // TODO: Check if we actually need these 5 lines of code
283
        $page = (isset($params['page'])) ? $params['page'] : 1;
284
        $maxResults = (isset($params['max_results'])) ? $params['max_results'] : 25;
285
286
        $packageCollection->setCurrentPage($page);
287
        $packageCollection->setMaxPerPage($maxResults);
288
289
        return $packageCollection;
290
    }
291
292
    /**
293
     * Gets full objects for all associations for a package.
294
     *
295
     * @param Package $package A package
296
     *
297
     * @return stdClass List of associations
298
     */
299
    public function getAssociationsFromPackage(Package $package)
300
    {
301
        $associations = new stdClass();
302
303
        if (isset($package->associations)) {
304
            foreach ($package->associations as $associationGroupName => $associationGroupItems) {
305
306
                $groupAssociations = new stdClass();
307
308
                foreach ($associationGroupItems AS $associatedName => $associatedItem) {
309
                    $associatedId = $this->getIdFromUri($associatedItem->uri);
310
311
                    try {
312
                        if ($associatedItem->type == self::PACKAGE_TYPE_COMPOSITE) {
313
                            $associatedObj = $this->getPackage($associatedId, true);
314
                        } else {
315
                            $associatedObj = $this->getItem($associatedId);
316
                            $associatedObj->type = $associatedItem->type;
317
                        }
318
                    } catch (ContentApiException $e) {
319
                        // If subrequests fail, dont fail main request
320
                    }
321
322
                    $groupAssociations->$associatedName = $associatedObj;
323
                }
324
325
                $associations->$associationGroupName = $groupAssociations;
326
            }
327
        }
328
329
        return $associations;
330
    }
331
332
    /**
333
     * Overwrite the associations links in a packages with the actual association
334
     * data.
335
     *
336
     * @param Package  $package      Package
337
     * @param stdClass $associations Multiple items or packages
338
     *
339
     * @return Package Package with data injected
340
     */
341
    public function injectAssociations(Package $package, stdClass $associations)
342
    {
343
        if (count($package->associations) > 0 && count($associations) > 0) {
344
            $package->associations = $associations;
345
        }
346
347
        return $package;
348
    }
349
350
    /**
351
     * Shortcut method to create new class.
352
     *
353
     * @param  string $uri Uri of the request
354
     * @param  array $parameters Parameters for the request object
355
     *
356
     * @return Request
357
     */
358
    public function getNewRequest($uri, array $parameters = array())
359
    {
360
        $request = new Request($this->host, $uri, $parameters, $this->port);
361
        $versionedRequest = new VersionDecorator($request);
362
        $versionedRequest->addVersion();
363
364
        return $versionedRequest;
365
    }
366
367
    /**
368
     * Tries to find a valid id in an uri, both item as package uris. The id
369
     * is returned urldecoded.
370
     *
371
     * @param string $uri Item or package uri
372
     *
373
     * @return string Urldecoded id
374
     */
375
    public static function getIdFromUri($uri)
376
    {
377
        /*
378
         * Works for package and item uris
379
         *   http://publicapi:5050/packages/tag%3Ademodata.org%2C0012%3Aninjs_XYZ123
380
         *   http://publicapi:5050/items/tag%3Ademodata.org%2C0003%3Aninjs_XYZ123
381
         */
382
383
        $uriPath = parse_url($uri, PHP_URL_PATH);
384
        $objectId = str_replace(self::getAvailableEndpoints(), '', $uriPath);
385
        // Remove possible slashes and spaces, since we're working with urls
386
        $objectId = trim($objectId, '/ ');
387
        $objectId = urldecode($objectId);
388
389
        return $objectId;
390
    }
391
392
    /**
393
     * Returns a list of all supported endpoints for the Superdesk Content API.
394
     *
395
     * @return string[]
396
     */
397
    public static function getAvailableEndpoints()
398
    {
399
        return array(
400
            self::SUPERDESK_ENDPOINT_ITEMS,
401
            self::SUPERDESK_ENDPOINT_PACKAGES,
402
        );
403
    }
404
405
    /**
406
     * Converts json string into StdClass object. Throws an InvalidDataException
407
     * when string could not be converted to object.
408
     *
409
     * @param string $jsonString JSON string
410
     *
411
     * @return object
412
     * @throws Exception|InvalidDataException
413
     */
414
    public static function getValidJsonObj($jsonString)
415
    {
416
        $jsonObj = json_decode($jsonString);
417
        if (is_null($jsonObj) || json_last_error() !== JSON_ERROR_NONE) {
418
            throw new InvalidDataException('Response body is not (valid) json.', json_last_error());
419
        }
420
421
        return $jsonObj;
422
    }
423
424
    /**
425
     * Returns version of api for creating verioned url.
426
     *
427
     * @return string
428
     */
429
    public static function getVersionURL()
430
    {
431
        return sprintf('v%d', self::API_VERSION);
432
    }
433
}
434