Completed
Pull Request — develop (#70)
by A.
02:39
created

JsonApiClient::post()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 38
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 22
nc 4
nop 2
1
<?php
2
3
/**
4
 * Copyright 2015 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\EngineBlockApiClientBundle\Http;
20
21
use GuzzleHttp\ClientInterface;
22
use OpenConext\EngineBlockApiClientBundle\Exception\InvalidArgumentException;
23
use OpenConext\EngineBlockApiClientBundle\Exception\InvalidResponseException;
24
use OpenConext\EngineBlockApiClientBundle\Exception\MalformedResponseException;
25
use OpenConext\EngineBlockApiClientBundle\Exception\ResourceNotFoundException;
26
use OpenConext\EngineBlockApiClientBundle\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
        $resource = $this->buildResourcePath($path, $parameters);
56
57
        $response = $this->httpClient->request('GET', $resource, ['exceptions' => false]);
58
59
        $statusCode = $response->getStatusCode();
60
61
        if ($statusCode === 404) {
62
            throw new ResourceNotFoundException(sprintf('Resource "%s" not found', $resource));
63
        }
64
65
        if ($statusCode !== 200) {
66
            throw new InvalidResponseException(
67
                sprintf(
68
                    'Request to resource "%s" returned an invalid response with status code %s',
69
                    $resource,
70
                    $statusCode
71
                )
72
            );
73
        }
74
75
        try {
76
            $data = $this->parseJson((string) $response->getBody());
77
        } catch (InvalidArgumentException $e) {
78
            throw new MalformedResponseException(
79
                sprintf('Cannot read resource "%s": malformed JSON returned', $resource)
80
            );
81
        }
82
83
        return $data;
84
    }
85
86
    public function post($resource, array $data)
87
    {
88
        $response = $this->httpClient->request(
89
            'POST',
90
            $resource,
91
            [
92
                'exceptions' => false,
93
                'body' => json_encode($data)
94
            ]
95
        );
96
97
        $statusCode = $response->getStatusCode();
98
99
        if ($statusCode === 404) {
100
            throw new ResourceNotFoundException(sprintf('Resource "%s" not found', $resource));
101
        }
102
103
        if ($statusCode !== 200) {
104
            throw new InvalidResponseException(
105
                sprintf(
106
                    'Request to resource "%s" returned an invalid response with status code %s',
107
                    $resource,
108
                    $statusCode,
109
                    $response->getBody()
110
                )
111
            );
112
        }
113
114
        try {
115
            $data = $this->parseJson((string) $response->getBody());
116
        } catch (InvalidArgumentException $e) {
117
            throw new MalformedResponseException(
118
                sprintf('Cannot read resource "%s": malformed JSON returned', $resource)
119
            );
120
        }
121
122
        return $data;
123
    }
124
125
    /**
126
     * @param       $path
127
     * @param array $parameters
128
     * @return string
129
     * @throws RuntimeException
130
     */
131
    private function buildResourcePath($path, array $parameters)
132
    {
133
        if (count($parameters) > 0) {
134
            $resource = vsprintf($path, array_map('urlencode', $parameters));
135
        } else {
136
            $resource = $path;
137
        }
138
139
        if (empty($resource)) {
140
            throw new RuntimeException(
141
                sprintf(
142
                    'Could not construct resource path from path "%s", parameters "%s"',
143
                    $path,
144
                    implode('","', $parameters)
145
                )
146
            );
147
        }
148
149
        return $resource;
150
    }
151
152
    /**
153
     * Function to provide functionality common to Guzzle 5 Response's json method,
154
     * without config options as they are not needed.
155
     *
156
     * @param string $json
157
     * @return mixed
158
     * @throws InvalidArgumentException
159
     */
160
    private function parseJson($json)
161
    {
162
        static $jsonErrors = [
163
            JSON_ERROR_DEPTH          => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
164
            JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
165
            JSON_ERROR_CTRL_CHAR      => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
166
            JSON_ERROR_SYNTAX         => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
167
            JSON_ERROR_UTF8           => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded',
168
        ];
169
170
        $data = json_decode($json, true);
171
172
        if (JSON_ERROR_NONE !== json_last_error()) {
173
            $last = json_last_error();
174
175
            $errorMessage = $jsonErrors[$last];
176
177
            if (!isset($errorMessage)) {
178
                $errorMessage = 'Unknown error';
179
            }
180
181
            throw new InvalidArgumentException(sprintf('Unable to parse JSON data: %s', $errorMessage));
182
        }
183
184
        return $data;
185
    }
186
}
187