1 <?php
2 /**
3 * Copyright 2014 Klarna AB
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * File containing the abstract base resource class.
18 */
19
20 namespace Klarna\Rest;
21
22 use GuzzleHttp\Exception\RequestException;
23 use Klarna\Rest\Transport\Connector;
24 use Klarna\Rest\Transport\Exception\ConnectorException;
25 use Klarna\Rest\Transport\ResponseValidator;
26
27 /**
28 * Abstract resource class.
29 */
30 abstract class Resource extends \ArrayObject
31 {
32 /**
33 * Id property field name.
34 */
35 const ID_FIELD = 'id';
36
37 /**
38 * Path to the resource endpoint.
39 *
40 * @var string
41 */
42 public static $path;
43
44 /**
45 * HTTP transport connector instance.
46 *
47 * @var Connector
48 */
49 protected $connector;
50
51 /**
52 * Url to the resource.
53 *
54 * @var string
55 */
56 protected $url;
57
58 /**
59 * Constructs a resource instance.
60 *
61 * @param Connector $connector HTTP transport instance.
62 */
63 public function __construct(Connector $connector)
64 {
65 $this->connector = $connector;
66 }
67
68 /**
69 * Gets the resource id.
70 *
71 * @return string|null
72 */
73 public function getId()
74 {
75 return isset($this[static::ID_FIELD]) ? $this[static::ID_FIELD] : null;
76 }
77
78 /**
79 * Gets the resource location.
80 *
81 * @return string|null
82 */
83 public function getLocation()
84 {
85 return $this->url;
86 }
87
88 /**
89 * Sets the resource location.
90 *
91 * @param string $url Url to the resource
92 *
93 * @return self
94 */
95 public function setLocation($url)
96 {
97 $this->url = $url;
98
99 return $this;
100 }
101
102 /**
103 * Fetches the resource.
104 *
105 * @throws ConnectorException When the API replies with an error response
106 * @throws RequestException When an error is encountered
107 * @throws \RuntimeException On an unexpected API response
108 * @throws \RuntimeException If the response content type is not JSON
109 * @throws \InvalidArgumentException If the JSON cannot be parsed
110 * @throws \LogicException When Guzzle cannot populate the response
111 *
112 * @return self
113 */
114 public function fetch()
115 {
116 $data = $this->get($this->getLocation())
117 ->status('200')
118 ->contentType('application/json')
119 ->getJson();
120
121 $this->exchangeArray($data);
122
123 return $this;
124 }
125
126 /**
127 * Sends a HTTP request to the specified url.
128 *
129 * @param string $method HTTP method, e.g. 'GET'
130 * @param string $url Request destination
131 * @param array $headers
132 * @param string $body
133 *
134 * @throws ConnectorException When the API replies with an error response
135 * @throws RequestException When an error is encountered
136 * @throws \LogicException When Guzzle cannot populate the response'
137 * @return ResponseValidator When the API replies with an error response
138 *
139 */
140 protected function request($method, $url, array $headers = [], $body = '')
141 {
142 $debug = getenv('DEBUG_SDK') || defined('DEBUG_SDK');
143
144 $request = $this->connector->createRequest($url, $method, $headers, $body);
145 if ($debug) {
146 $clientConfig = $this->connector->getClient()->getConfig();
147 $baseUri = isset($clientConfig['base_uri']) ? $clientConfig['base_uri'] : '';
148 $debugHeaders = $request->getHeaders();
149 $debugHeaders = json_encode($debugHeaders);
150 echo <<<DEBUG_BODY
151 DEBUG MODE: Request
152 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
153 {$method} : {$baseUri}{$url}
154 Headers : $debugHeaders
155 Body : {$request->getBody()}
156 \n
157 DEBUG_BODY;
158 }
159
160 $response = $this->connector->send($request);
161
162 if ($debug) {
163 $debugHeaders = json_encode($response->getHeaders());
164 echo <<<DEBUG_BODY
165 DEBUG MODE: Response
166 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
167 Headers : $debugHeaders
168 Body : {$response->getBody()}
169 \n
170 DEBUG_BODY;
171 }
172
173 return new ResponseValidator($response);
174 }
175
176 /**
177 * Sends a HTTP GET request to the specified url.
178 *
179 * @param string $url Request destination
180 *
181 * @throws ConnectorException When the API replies with an error response
182 * @throws RequestException When an error is encountered
183 * @throws \LogicException When Guzzle cannot populate the response
184 *
185 * @return ResponseValidator
186 */
187 protected function get($url)
188 {
189 return $this->request('GET', $url);
190 }
191
192 /**
193 * Sends a HTTP DELETE request to the specified url.
194 *
195 * @param string $url Request destination
196 * @param array $data Data to be JSON encoded
197 *
198 * @throws ConnectorException When the API replies with an error response
199 * @throws RequestException When an error is encountered
200 * @throws \LogicException When Guzzle cannot populate the response
201 *
202 * @return ResponseValidator
203 */
204 protected function delete($url, array $data = null)
205 {
206 return $this->request(
207 'DELETE',
208 $url,
209 ['Content-Type' => 'application/json'],
210 $data !== null ? json_encode($data) : null
211 );
212 }
213
214 /**
215 * Sends a HTTP PATCH request to the specified url.
216 *
217 * @param string $url Request destination
218 * @param array $data Data to be JSON encoded
219 *
220 * @throws ConnectorException When the API replies with an error response
221 * @throws RequestException When an error is encountered
222 * @throws \LogicException When Guzzle cannot populate the response
223 *
224 * @return ResponseValidator
225 */
226 protected function patch($url, array $data)
227 {
228 return $this->request('PATCH', $url, ['Content-Type' => 'application/json'], json_encode($data));
229 }
230
231 /**
232 * Sends a HTTP POST request to the specified url.
233 *
234 * @param string $url Request destination
235 * @param array $data Data to be JSON encoded
236 *
237 * @throws ConnectorException When the API replies with an error response
238 * @throws RequestException When an error is encountered
239 * @throws \LogicException When Guzzle cannot populate the response
240 *
241 * @return ResponseValidator
242 */
243 protected function post($url, array $data = null)
244 {
245 return $this->request(
246 'POST',
247 $url,
248 ['Content-Type' => 'application/json'],
249 $data !== null ? \json_encode($data) : null
250 );
251 }
252 }
253