JsonApiClient   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 140
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 7
dl 0
loc 140
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A read() 0 4 1
A delete() 0 4 1
A handle() 0 32 4
A buildResourcePath() 0 20 3
A parseJson() 0 26 3
1
<?php
2
3
/**
4
 * Copyright 2017 SURFnet B.V.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace OpenConext\AttributeAggregationApiClientBundle\Http;
20
21
use GuzzleHttp\ClientInterface;
22
use OpenConext\AttributeAggregationApiClientBundle\Exception\InvalidArgumentException;
23
use OpenConext\AttributeAggregationApiClientBundle\Exception\InvalidResponseException;
24
use OpenConext\AttributeAggregationApiClientBundle\Exception\MalformedResponseException;
25
use OpenConext\AttributeAggregationApiClientBundle\Exception\ResourceNotFoundException;
26
use OpenConext\AttributeAggregationApiClientBundle\Exception\RuntimeException;
27
28
class JsonApiClient
29
{
30
    /**
31
     * @var ClientInterface
32
     */
33
    private $httpClient;
34
35
    /**
36
     * @param ClientInterface $httpClient
37
     */
38
    public function __construct(ClientInterface $httpClient)
39
    {
40
        $this->httpClient = $httpClient;
41
    }
42
43
    /**
44
     * @param string $path A URL path, optionally containing printf parameters. The parameters
45
     *               will be URL encoded and formatted into the path string.
46
     *               Example: "connections/%d.json"
47
     * @param array  $parameters
48
     * @return mixed $data
49
     * @throws InvalidResponseException
50
     * @throws MalformedResponseException
51
     * @throws ResourceNotFoundException
52
     */
53
    public function read($path, array $parameters = [])
54
    {
55
        return $this->handle('GET', $path, $parameters);
56
    }
57
58
    /**
59
     * @param string $path A URL path, optionally containing printf parameters. The parameters
60
     *               will be URL encoded and formatted into the path string.
61
     *               Example: "connections/%d.json"
62
     * @param array  $parameters
63
     * @return mixed $data
64
     * @throws InvalidResponseException
65
     * @throws MalformedResponseException
66
     * @throws ResourceNotFoundException
67
     */
68
    public function delete($path, array $parameters = [])
69
    {
70
        return $this->handle('DELETE', $path, $parameters);
71
    }
72
73
    private function handle($method, $path, array $parameters = [])
74
    {
75
        $resource = $this->buildResourcePath($path, $parameters);
76
77
        $response = $this->httpClient->request($method, $resource, ['exceptions' => false]);
78
79
        $statusCode = $response->getStatusCode();
80
81
        if ($statusCode === 404) {
82
            throw new ResourceNotFoundException(sprintf('Resource "%s" not found', $resource));
83
        }
84
85
        if ($statusCode !== 200) {
86
            throw new InvalidResponseException(
87
                sprintf(
88
                    'Request to resource "%s" returned an invalid response with status code %s',
89
                    $resource,
90
                    $statusCode
91
                )
92
            );
93
        }
94
95
        try {
96
            $data = $this->parseJson((string) $response->getBody());
97
        } catch (InvalidArgumentException $e) {
98
            throw new MalformedResponseException(
99
                sprintf('Cannot read resource "%s": malformed JSON returned', $resource)
100
            );
101
        }
102
103
        return $data;
104
    }
105
106
    /**
107
     * @param string $path
108
     * @param array $parameters
109
     * @return string
110
     * @throws RuntimeException
111
     */
112
    private function buildResourcePath($path, array $parameters)
113
    {
114
        if (count($parameters) > 0) {
115
            $resource = vsprintf($path, array_map('urlencode', $parameters));
116
        } else {
117
            $resource = $path;
118
        }
119
120
        if (empty($resource)) {
121
            throw new RuntimeException(
122
                sprintf(
123
                    'Could not construct resource path from path "%s", parameters "%s"',
124
                    $path,
125
                    implode('","', $parameters)
126
                )
127
            );
128
        }
129
130
        return $resource;
131
    }
132
133
    /**
134
     * Function to provide functionality common to Guzzle 5 Response's json method,
135
     * without config options as they are not needed.
136
     *
137
     * @param string $json
138
     * @return mixed
139
     * @throws InvalidArgumentException
140
     */
141
    private function parseJson($json)
142
    {
143
        static $jsonErrors = [
144
            JSON_ERROR_DEPTH          => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
145
            JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
146
            JSON_ERROR_CTRL_CHAR      => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
147
            JSON_ERROR_SYNTAX         => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
148
            JSON_ERROR_UTF8           => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded',
149
        ];
150
151
        $data = json_decode($json, true);
152
153
        if (JSON_ERROR_NONE !== json_last_error()) {
154
            $last = json_last_error();
155
156
            $errorMessage = $jsonErrors[$last];
157
158
            if (!isset($errorMessage)) {
159
                $errorMessage = 'Unknown error';
160
            }
161
162
            throw new InvalidArgumentException(sprintf('Unable to parse JSON data: %s', $errorMessage));
163
        }
164
165
        return $data;
166
    }
167
}
168