Overview
  • Package
  • Class

Packages

  • Klarna
    • Checkout
  • Payment
    • Klarna
      • HTTP
      • Interfaces
      • Unit
        • Tests

Classes

  • Klarna_Checkout_HTTP_CURLFactory
  • Klarna_Checkout_HTTP_Transport
  1 <?php
  2 /**
  3  * Copyright 2015 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 Klarna_Checkout_BasicConnector class
 18  *
 19  * PHP version 5.3
 20  *
 21  * @category  Payment
 22  * @package   Klarna_Checkout
 23  * @author    Klarna <support@klarna.com>
 24  * @copyright 2015 Klarna AB
 25  * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
 26  * @link      http://developers.klarna.com/
 27  */
 28 
 29 /**
 30  * Basic implementation of the connector interface
 31  *
 32  * @category  Payment
 33  * @package   Klarna_Checkout
 34  * @author    Rickard D. <rickard.dybeck@klarna.com>
 35  * @author    Christer G. <christer.gustavsson@klarna.com>
 36  * @author    David K. <david.keijser@klarna.com>
 37  * @copyright 2015 Klarna AB
 38  * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache license v2.0
 39  * @link      http://developers.klarna.com/
 40  */
 41 class Klarna_Checkout_BasicConnector implements Klarna_Checkout_ConnectorInterface
 42 {
 43 
 44     /**
 45      * Klarna_Checkout_HTTP_TransportInterface Implementation
 46      *
 47      * @var Klarna_Checkout_HTTP_TransportInterface
 48      */
 49     protected $http;
 50 
 51     /**
 52      * Digester class
 53      *
 54      * @var Klarna_Checkout_Digest
 55      */
 56     protected $digester;
 57 
 58     /**
 59      * The domain for the request
 60      *
 61      * @var string
 62      */
 63     protected $domain;
 64 
 65     /**
 66      * Shared Secret used to sign requests
 67      *
 68      * @var string
 69      */
 70     private $_secret;
 71 
 72     /**
 73      * Create a new Checkout Connector
 74      *
 75      * @param Klarna_Checkout_HTTP_TransportInterface $http     Transport
 76      * @param Klarna_Checkout_Digest                  $digester Digest Generator
 77      * @param string                                  $secret   Shared secret
 78      * @param string                                  $domain   Domain of the request
 79      */
 80     public function __construct(
 81         Klarna_Checkout_HTTP_TransportInterface $http,
 82         Klarna_Checkout_Digest $digester,
 83         $secret,
 84         $domain = Klarna_Checkout_Connector::BASE_URL
 85     ) {
 86         $this->http = $http;
 87         $this->digester = $digester;
 88         $this->_secret = $secret;
 89         $this->domain = $domain;
 90     }
 91 
 92     /**
 93      * Create the user agent identifier to use
 94      *
 95      * @return Klarna_Checkout_UserAgent
 96      */
 97     protected function userAgent()
 98     {
 99         return new Klarna_Checkout_UserAgent();
100     }
101 
102     /**
103      * Applying the method on the specific resource
104      *
105      * @param string                            $method   Http methods
106      * @param Klarna_Checkout_ResourceInterface $resource resource
107      * @param array                             $options  Options
108      *
109      * @return mixed
110      */
111     public function apply(
112         $method,
113         Klarna_Checkout_ResourceInterface $resource,
114         array $options = null
115     ) {
116         switch ($method) {
117         case 'GET':
118         case 'POST':
119             return $this->handle($method, $resource, $options, array());
120         default:
121             throw new InvalidArgumentException(
122                 "{$method} is not a valid HTTP method"
123             );
124         }
125     }
126 
127     /**
128      * Gets the underlying transport object
129      *
130      * @return Klarna_Checkout_HTTP_TransportInterface Transport object
131      */
132     public function getTransport()
133     {
134         return $this->http;
135     }
136 
137     /**
138      * Set content (headers, payload) on a request
139      *
140      * @param Klarna_Checkout_ResourceInterface $resource Klarna Checkout Resource
141      * @param string                            $method   HTTP Method
142      * @param string                            $payload  Payload to send with the
143      *                                                    request
144      * @param string                            $url      URL for request
145      *
146      * @return Klarna_Checkout_HTTP_Request
147      */
148     protected function createRequest(
149         Klarna_Checkout_ResourceInterface $resource,
150         $method,
151         $payload,
152         $url
153     ) {
154         // Generate the digest string
155         $digest = $this->digester->create($payload . $this->_secret);
156 
157         $request = $this->http->createRequest($url);
158 
159         $request->setMethod($method);
160 
161         // Set HTTP Headers
162         $accept = $resource->getAccept();
163         $contentType = $resource->getContentType();
164         $request->setHeader('User-Agent', (string)$this->userAgent());
165         $request->setHeader('Authorization', "Klarna {$digest}");
166         $request->setHeader('Accept', $accept ? $accept : $contentType);
167         if (strlen($payload) > 0) {
168             $request->setHeader('Content-Type', $contentType);
169             $request->setData($payload);
170         }
171 
172         return $request;
173     }
174 
175     /**
176      * Get the current domain
177      *
178      * @return string
179      */
180     public function getDomain()
181     {
182         return $this->domain;
183     }
184 
185     /**
186      * Get the url to use
187      *
188      * @param Klarna_Checkout_ResourceInterface $resource resource
189      * @param array                             $options  Options
190      *
191      * @return string Url to use for HTTP requests
192      */
193     protected function getUrl(
194         Klarna_Checkout_ResourceInterface $resource, array $options
195     ) {
196         if (array_key_exists('url', $options)) {
197             return $options['url'];
198         }
199 
200         return $resource->getLocation();
201     }
202 
203     /**
204      * Get the data to use
205      *
206      * @param Klarna_Checkout_ResourceInterface $resource resource
207      * @param array                             $options  Options
208      *
209      * @return array data to use for HTTP requests
210      */
211     protected function getData(
212         Klarna_Checkout_ResourceInterface $resource, array $options
213     ) {
214         if (array_key_exists('data', $options)) {
215             return $options['data'];
216         }
217 
218         return $resource->marshal();
219     }
220 
221     /**
222      * Throw an exception if the server responds with an error code.
223      *
224      * @param Klarna_Checkout_HTTP_Response $result HTTP Response object
225      *
226      * @throws Klarna_Checkout_ApiErrorException
227      * @return void
228      */
229     protected function verifyResponse(Klarna_Checkout_HTTP_Response $result)
230     {
231         // Error Status Code recieved. Throw an exception.
232         if ($result->getStatus() >= 400 && $result->getStatus() <= 599) {
233 
234             $json = json_decode($result->getData(), true);
235             $payload = ($json && is_array($json)) ? $json : array();
236 
237             throw new Klarna_Checkout_ApiErrorException(
238                 "API Error", $result->getStatus(), $payload
239             );
240         }
241     }
242 
243     /**
244      * Act upon the status of a response
245      *
246      * @param Klarna_Checkout_HTTP_Response     $result   response from server
247      * @param Klarna_Checkout_ResourceInterface $resource associated resource
248      * @param array                             $visited  list of visited locations
249      *
250      * @return Klarna_Checkout_HTTP_Response
251      * @throws Klarna_Checkout_ConnectorException
252      */
253     protected function handleResponse(
254         Klarna_Checkout_HTTP_Response $result,
255         Klarna_Checkout_ResourceInterface $resource,
256         array $visited = array()
257     ) {
258         // Check if we got an Error status code back
259         $this->verifyResponse($result);
260 
261         $url = $result->getHeader('Location');
262         switch ($result->getStatus()) {
263         case 301:
264             // Update location and fallthrough
265             $resource->setLocation($url);
266         case 302:
267             // Don't fallthrough for other than GET
268             if ($result->getRequest()->getMethod() !== 'GET') {
269                 break;
270             }
271         case 303:
272             // Detect eternal loops
273             if (in_array($url, $visited)) {
274                 throw new Klarna_Checkout_ConnectorException(
275                     'Infinite redirect loop detected.',
276                     -1
277                 );
278             }
279             $visited[] = $url;
280             // Follow redirect
281             return $this->handle(
282                 'GET',
283                 $resource,
284                 array('url' => $url),
285                 $visited
286             );
287         case 201:
288             // Update Location
289             $resource->setLocation($url);
290             break;
291         case 200:
292             // Update Data on resource
293             $json = json_decode($result->getData(), true);
294             if ($json === null) {
295                 throw new Klarna_Checkout_ConnectorException(
296                     'Bad format on response content.',
297                     -2
298                 );
299             }
300             $resource->parse($json);
301         }
302 
303         return $result;
304     }
305 
306     /**
307      * Perform a HTTP Call on the supplied resource using the wanted method.
308      *
309      * @param string                            $method   HTTP Method
310      * @param Klarna_Checkout_ResourceInterface $resource Klarna Order
311      * @param array                             $options  Options
312      * @param array                             $visited  list of visited locations
313      *
314      * @throws Klarna_Checkout_Exception        if 4xx or 5xx response code.
315      *
316      * @return Klarna_Checkout_HTTP_Response    Result object containing status code
317      *                                          and payload
318      */
319     protected function handle(
320         $method,
321         Klarna_Checkout_ResourceInterface $resource,
322         array $options = null,
323         array $visited = array()
324     ) {
325         if ($options === null) {
326             $options = array();
327         }
328 
329         // Define the target URL
330         $url = $this->getUrl($resource, $options);
331 
332         // Set a payload if it is a POST call.
333         $payload = '';
334         if ($method === 'POST') {
335             $payload = json_encode($this->getData($resource, $options));
336         }
337 
338         // Create a HTTP Request object
339         $request = $this->createRequest($resource, $method, $payload, $url);
340 
341         // Execute the HTTP Request
342         $result = $this->http->send($request);
343 
344         // Handle statuses appropriately.
345         return $this->handleResponse($result, $resource, $visited);
346     }
347 }
348 
API documentation generated by ApiGen