Avenla_KlarnaCheckout - Version 1.2.0

Version Notes

- Added support for Rest API (supporting now also UK and US)
- Fixed method to get shipping tax rate
- Updated all Klarna libraries
- General optimization
- Added option for separate shipping address
- Improved logging

Download this release

Release Info

Developer Avenla Oy
Extension Avenla_KlarnaCheckout
Version 1.2.0
Comparing to
See all releases


Code changes from version 1.1.6 to 1.2.0

Files changed (194) hide show
  1. app/code/community/Avenla/KlarnaCheckout/Block/Adminhtml/System/Config/Field/Pclass.php +48 -40
  2. app/code/community/Avenla/KlarnaCheckout/Block/Adminhtml/System/Config/Fieldset/Info.php +46 -47
  3. app/code/community/Avenla/KlarnaCheckout/Block/Catalog/Product/Price.php +79 -102
  4. app/code/community/Avenla/KlarnaCheckout/Block/KCO.php +11 -5
  5. app/code/community/Avenla/KlarnaCheckout/Block/KCO/Confirmation.php +140 -201
  6. app/code/community/Avenla/KlarnaCheckout/Block/KCO/Info.php +26 -20
  7. app/code/community/Avenla/KlarnaCheckout/Block/KCO/Newsletter.php +21 -22
  8. app/code/community/Avenla/KlarnaCheckout/Block/Widgets/Logo.php +5 -8
  9. app/code/community/Avenla/KlarnaCheckout/Block/Widgets/Methods.php +2 -5
  10. app/code/community/Avenla/KlarnaCheckout/Helper/Api.php +0 -100
  11. app/code/community/Avenla/KlarnaCheckout/Helper/Data.php +325 -194
  12. app/code/community/Avenla/KlarnaCheckout/Model/Api.php +415 -478
  13. app/code/community/Avenla/KlarnaCheckout/Model/Config.php +365 -316
  14. app/code/community/Avenla/KlarnaCheckout/Model/KCO.php +0 -239
  15. app/code/community/Avenla/KlarnaCheckout/Model/Newsletter.php +42 -43
  16. app/code/community/Avenla/KlarnaCheckout/Model/Observer.php +138 -156
  17. app/code/community/Avenla/KlarnaCheckout/Model/Order.php +0 -326
  18. app/code/community/Avenla/KlarnaCheckout/Model/Order/Abstract.php +311 -0
  19. app/code/community/Avenla/KlarnaCheckout/Model/Order/Kcov2.php +370 -0
  20. app/code/community/Avenla/KlarnaCheckout/Model/Order/Kcov3.php +413 -0
  21. app/code/community/Avenla/KlarnaCheckout/Model/Payment/Abstract.php +143 -0
  22. app/code/community/Avenla/KlarnaCheckout/Model/Payment/KCO.php +346 -0
  23. app/code/community/Avenla/KlarnaCheckout/Model/Payment/KCOv3.php +408 -0
  24. app/code/community/Avenla/KlarnaCheckout/Model/Source/AnalyticsType.php +18 -19
  25. app/code/community/Avenla/KlarnaCheckout/Model/Source/Api.php +43 -0
  26. app/code/community/Avenla/KlarnaCheckout/Model/Source/Countries.php +0 -50
  27. app/code/community/Avenla/KlarnaCheckout/Model/Source/Kcolayout.php +9 -9
  28. app/code/community/Avenla/KlarnaCheckout/Model/Source/Orderlocale.php +0 -49
  29. app/code/community/Avenla/KlarnaCheckout/Model/Source/Pplayout.php +17 -19
  30. app/code/community/Avenla/KlarnaCheckout/Model/Source/Ppwidget.php +26 -27
  31. app/code/community/Avenla/KlarnaCheckout/Model/Source/Servermode.php +17 -17
  32. app/code/community/Avenla/KlarnaCheckout/Model/Source/Shippingmethods.php +26 -26
  33. app/code/community/Avenla/KlarnaCheckout/Model/Source/Taxclass.php +11 -11
  34. app/code/community/Avenla/KlarnaCheckout/Model/Validator.php +87 -65
  35. app/code/community/Avenla/KlarnaCheckout/controllers/Adminhtml/KCOController.php +0 -32
  36. app/code/community/Avenla/KlarnaCheckout/controllers/Adminhtml/KlarnaCheckout/KCOController.php +61 -0
  37. app/code/community/Avenla/KlarnaCheckout/controllers/CartController.php +31 -33
  38. app/code/community/Avenla/KlarnaCheckout/controllers/KCOController.php +212 -354
  39. app/code/community/Avenla/KlarnaCheckout/etc/config.xml +36 -14
  40. app/code/community/Avenla/KlarnaCheckout/etc/system.xml +115 -94
  41. app/code/community/Avenla/KlarnaCheckout/etc/widget.xml +87 -90
  42. app/design/adminhtml/default/default/template/KCO/info.phtml +92 -38
  43. app/design/adminhtml/default/default/template/KCO/system/config/field/pclass.phtml +12 -8
  44. app/design/adminhtml/default/default/template/KCO/system/config/fieldset/info.phtml +6 -6
  45. app/design/frontend/base/default/template/KCO/KCO.phtml +3 -16
  46. app/design/frontend/base/default/template/KCO/catalog/product/price.phtml +13 -14
  47. app/design/frontend/base/default/template/KCO/info.phtml +5 -5
  48. app/design/frontend/base/default/template/KCO/link.phtml +6 -7
  49. app/locale/fi_FI/Avenla_KlarnaCheckout.csv +13 -2
  50. lib/Klarna/Exceptions.php +0 -735
  51. lib/Klarna/checkout/checkouthtml.intf.php +0 -97
  52. lib/Klarna/checkout/threatmetrix.class.php +0 -136
  53. lib/Klarna/examples/activate.php +0 -66
  54. lib/Klarna/examples/activateInvoice.php +0 -53
  55. lib/Klarna/examples/activatePart.php +0 -67
  56. lib/Klarna/examples/activateReservation.php +0 -240
  57. lib/Klarna/examples/addTransaction.php +0 -159
  58. lib/Klarna/examples/calc_monthly_cost.php +0 -59
  59. lib/Klarna/examples/cancelReservation.php +0 -55
  60. lib/Klarna/examples/changeReservation.php +0 -60
  61. lib/Klarna/examples/checkOrderStatus.php +0 -64
  62. lib/Klarna/examples/creditInvoice.php +0 -59
  63. lib/Klarna/examples/creditPart.php +0 -80
  64. lib/Klarna/examples/deleteInvoice.php +0 -49
  65. lib/Klarna/examples/emailInvoice.php +0 -56
  66. lib/Klarna/examples/fetchPClasses.php +0 -54
  67. lib/Klarna/examples/getAddresses.php +0 -86
  68. lib/Klarna/examples/getPClasses.php +0 -63
  69. lib/Klarna/examples/invoiceAddress.php +0 -80
  70. lib/Klarna/examples/invoiceAmount.php +0 -56
  71. lib/Klarna/examples/invoicePartAmount.php +0 -70
  72. lib/Klarna/examples/reserveAmount.php +0 -170
  73. lib/Klarna/examples/reserveOCR.php +0 -59
  74. lib/Klarna/examples/returnAmount.php +0 -63
  75. lib/Klarna/examples/sendInvoice.php +0 -58
  76. lib/Klarna/examples/splitReservation.php +0 -66
  77. lib/Klarna/examples/update.php +0 -129
  78. lib/Klarna/examples/updateChargeAmount.php +0 -60
  79. lib/Klarna/examples/updateGoodsQty.php +0 -61
  80. lib/Klarna/examples/updateOrderNo.php +0 -59
  81. lib/KlarnaCheckout/autoload.php +7 -0
  82. lib/KlarnaCheckout/composer/ClassLoader.php +413 -0
  83. lib/KlarnaCheckout/composer/LICENSE +21 -0
  84. lib/KlarnaCheckout/composer/autoload_classmap.php +14 -0
  85. lib/KlarnaCheckout/composer/autoload_files.php +10 -0
  86. lib/KlarnaCheckout/composer/autoload_namespaces.php +11 -0
  87. lib/KlarnaCheckout/composer/autoload_psr4.php +14 -0
  88. lib/KlarnaCheckout/composer/autoload_real.php +55 -0
  89. lib/KlarnaCheckout/composer/installed.json +386 -0
  90. lib/KlarnaCheckout/guzzlehttp/guzzle/.editorconfig +11 -0
  91. lib/KlarnaCheckout/guzzlehttp/guzzle/.gitignore +11 -0
  92. lib/KlarnaCheckout/guzzlehttp/guzzle/.travis.yml +41 -0
  93. lib/KlarnaCheckout/guzzlehttp/guzzle/CHANGELOG.md +1053 -0
  94. lib/KlarnaCheckout/guzzlehttp/guzzle/LICENSE +19 -0
  95. lib/KlarnaCheckout/guzzlehttp/guzzle/Makefile +50 -0
  96. lib/KlarnaCheckout/guzzlehttp/guzzle/README.md +70 -0
  97. lib/KlarnaCheckout/guzzlehttp/guzzle/UPGRADING.md +1050 -0
  98. lib/KlarnaCheckout/guzzlehttp/guzzle/build/packager.php +21 -0
  99. lib/KlarnaCheckout/guzzlehttp/guzzle/composer.json +39 -0
  100. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/Makefile +153 -0
  101. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/_static/guzzle-icon.png +0 -0
  102. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/_static/logo.png +0 -0
  103. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/_templates/nav_links.html +3 -0
  104. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/clients.rst +1326 -0
  105. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/conf.py +28 -0
  106. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/events.rst +516 -0
  107. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/faq.rst +199 -0
  108. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/handlers.rst +43 -0
  109. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/http-messages.rst +483 -0
  110. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/index.rst +98 -0
  111. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/overview.rst +150 -0
  112. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/quickstart.rst +448 -0
  113. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/requirements.txt +2 -0
  114. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/streams.rst +213 -0
  115. lib/KlarnaCheckout/guzzlehttp/guzzle/docs/testing.rst +232 -0
  116. lib/KlarnaCheckout/guzzlehttp/guzzle/phpunit.xml.dist +17 -0
  117. lib/KlarnaCheckout/guzzlehttp/guzzle/src/BatchResults.php +148 -0
  118. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Client.php +352 -0
  119. lib/KlarnaCheckout/guzzlehttp/guzzle/src/ClientInterface.php +150 -0
  120. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Collection.php +236 -0
  121. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/CookieJar.php +248 -0
  122. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php +75 -0
  123. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php +86 -0
  124. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php +66 -0
  125. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/SetCookie.php +373 -0
  126. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractEvent.php +20 -0
  127. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php +61 -0
  128. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php +40 -0
  129. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php +63 -0
  130. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/BeforeEvent.php +26 -0
  131. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/CompleteEvent.php +14 -0
  132. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/Emitter.php +146 -0
  133. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/EmitterInterface.php +96 -0
  134. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/EndEvent.php +28 -0
  135. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/ErrorEvent.php +27 -0
  136. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/EventInterface.php +23 -0
  137. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/HasEmitterInterface.php +15 -0
  138. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/HasEmitterTrait.php +20 -0
  139. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php +88 -0
  140. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/ProgressEvent.php +51 -0
  141. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/RequestEvents.php +56 -0
  142. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/SubscriberInterface.php +34 -0
  143. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/BadResponseException.php +7 -0
  144. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ClientException.php +7 -0
  145. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ConnectException.php +4 -0
  146. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php +4 -0
  147. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ParseException.php +31 -0
  148. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/RequestException.php +121 -0
  149. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ServerException.php +7 -0
  150. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/StateException.php +4 -0
  151. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php +4 -0
  152. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/TransferException.php +4 -0
  153. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/XmlParseException.php +34 -0
  154. lib/KlarnaCheckout/guzzlehttp/guzzle/src/HasDataTrait.php +75 -0
  155. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/AbstractMessage.php +253 -0
  156. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/AppliesHeadersInterface.php +24 -0
  157. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/FutureResponse.php +158 -0
  158. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageFactory.php +364 -0
  159. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php +71 -0
  160. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageInterface.php +136 -0
  161. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageParser.php +171 -0
  162. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/Request.php +195 -0
  163. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/RequestInterface.php +136 -0
  164. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/Response.php +208 -0
  165. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/ResponseInterface.php +111 -0
  166. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Mimetypes.php +963 -0
  167. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Pool.php +333 -0
  168. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/MultipartBody.php +109 -0
  169. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostBody.php +287 -0
  170. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostBodyInterface.php +109 -0
  171. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostFile.php +135 -0
  172. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostFileInterface.php +41 -0
  173. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Query.php +204 -0
  174. lib/KlarnaCheckout/guzzlehttp/guzzle/src/QueryParser.php +163 -0
  175. lib/KlarnaCheckout/guzzlehttp/guzzle/src/RequestFsm.php +153 -0
  176. lib/KlarnaCheckout/guzzlehttp/guzzle/src/RingBridge.php +165 -0
  177. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Cookie.php +58 -0
  178. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/History.php +172 -0
  179. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/HttpError.php +36 -0
  180. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Mock.php +147 -0
  181. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Prepare.php +130 -0
  182. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Redirect.php +176 -0
  183. lib/KlarnaCheckout/guzzlehttp/guzzle/src/ToArrayInterface.php +15 -0
  184. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Transaction.php +103 -0
  185. lib/KlarnaCheckout/guzzlehttp/guzzle/src/UriTemplate.php +241 -0
  186. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Url.php +595 -0
  187. lib/KlarnaCheckout/guzzlehttp/guzzle/src/Utils.php +211 -0
  188. lib/KlarnaCheckout/guzzlehttp/guzzle/tests/BatchResultsTest.php +58 -0
  189. lib/KlarnaCheckout/guzzlehttp/guzzle/tests/ClientTest.php +647 -0
  190. lib/KlarnaCheckout/guzzlehttp/guzzle/tests/CollectionTest.php +416 -0
  191. lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/CookieJarTest.php +339 -0
  192. lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/FileCookieJarTest.php +71 -0
  193. lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/SessionCookieJarTest.php +76 -0
  194. lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/SetCookieTest.php +304 -0
app/code/community/Avenla/KlarnaCheckout/Block/Adminhtml/System/Config/Field/Pclass.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,44 +20,52 @@
20
  */
21
  class Avenla_KlarnaCheckout_Block_Adminhtml_System_Config_Field_Pclass extends Mage_Adminhtml_Block_System_Config_Form_Field
22
  {
23
- /**
24
- * Set template
25
- */
26
- public function __construct()
27
- {
28
- parent::__construct();
29
- $this->setTemplate('KCO/system/config/field/pclass.phtml');
30
- }
31
 
32
- public function getButtonHtml()
33
- {
34
- $html = $this->getLayout()->createBlock('adminhtml/widget_button')
35
- ->setType('button')
36
- ->setLabel(Mage::helper('klarnaCheckout')->__('Update PClasses'))
37
- ->setOnClick("javascript:updatePClasses(); return false;")
38
- ->toHtml();
39
 
40
- return $html;
 
 
 
 
 
 
 
 
 
41
  }
42
 
43
- /**
44
- * Return element html
45
- *
46
- * @param Varien_Data_Form_Element_Abstract $element
47
- * @return string
48
- */
49
- protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
50
- {
51
- return $this->_toHtml();
52
- }
 
 
 
 
53
 
54
- /**
55
- * Get url for update action
56
- *
57
- * @return string
58
- */
59
- public function getAjaxUpdateUrl()
60
- {
61
- return Mage::getUrl('klarnaCheckout/adminhtml_KCO/updatePClasses/');
62
- }
63
- }
 
 
 
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  class Avenla_KlarnaCheckout_Block_Adminhtml_System_Config_Field_Pclass extends Mage_Adminhtml_Block_System_Config_Form_Field
22
  {
23
+ protected function _prepareLayout()
24
+ {
25
+ parent::_prepareLayout();
26
+ if (!$this->getTemplate())
27
+ $this->setTemplate('KCO/system/config/field/pclass.phtml');
 
 
 
28
 
29
+ return $this;
30
+ }
 
 
 
 
 
31
 
32
+ /**
33
+ * Unset some non-related element parameters
34
+ *
35
+ * @param Varien_Data_Form_Element_Abstract $element
36
+ * @return string
37
+ */
38
+ public function render(Varien_Data_Form_Element_Abstract $element)
39
+ {
40
+ $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
41
+ return parent::render($element);
42
  }
43
 
44
+ /**
45
+ * Return element html
46
+ *
47
+ * @param Varien_Data_Form_Element_Abstract $element
48
+ * @return string
49
+ */
50
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
51
+ {
52
+ $oData = $element->getOriginalData();
53
+ $buttonData = array(
54
+ 'button_label' => Mage::helper('klarnaCheckout')->__($oData['button_label']),
55
+ 'html_id' => $element->getHtmlId()
56
+ );
57
+ $this->addData($buttonData);
58
 
59
+ return $this->_toHtml();
60
+ }
61
+
62
+ /**
63
+ * Get url for update action
64
+ *
65
+ * @return string
66
+ */
67
+ public function getAjaxUpdateUrl()
68
+ {
69
+ return Mage::getUrl('adminhtml/klarnaCheckout_KCO/updatePClasses/');
70
+ }
71
+ }
app/code/community/Avenla/KlarnaCheckout/Block/Adminhtml/System/Config/Fieldset/Info.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -19,48 +19,47 @@
19
  * @package Avenla_KlarnaCheckout
20
  */
21
  class Avenla_KlarnaCheckout_Block_Adminhtml_System_Config_Fieldset_Info extends Mage_Adminhtml_Block_Abstract
22
- implements Varien_Data_Form_Element_Renderer_Interface
23
  {
24
- protected $_template = 'KCO/system/config/fieldset/info.phtml';
25
- private $helper;
26
-
27
- /**
28
- * Render fieldset html
29
- *
30
- * @param Varien_Data_Form_Element_Abstract Element
31
- * @return string
32
- */
33
- public function render(Varien_Data_Form_Element_Abstract $element)
34
- {
35
- $this->helper = Mage::helper("klarnaCheckout");
36
- $this->assign('logoSrc', $this->helper->getLogoSrc());
37
- $this->assign('apiLink', Mage::helper('klarnaCheckout/api')->getApiDocumentationUrl());
38
- $this->assign('documentationUrl', $this->helper->getDocumentationUrl());
39
-
40
- return $this->toHtml();
41
- }
42
-
43
- /**
44
- * Check store configuration
45
- *
46
- * @return array
47
- */
48
- public function getAlerts()
49
- {
50
- $alerts = array();
51
-
52
- if(!$this->helper->getConnectionStatus())
53
- $alerts[] = "Connection to Klarna failed, please check your eid/shared secret and store settings.";
54
-
55
- if(Mage::getStoreConfig('tax/calculation/discount_tax') != 1)
56
- $alerts[] = "Discount is applied before taxes, this may cause different price on Klarna Checkout. Please check store tax configation.";
57
-
58
- if(Mage::getStoreConfig('tax/calculation/price_includes_tax') != 1)
59
- $alerts[] = "Catalog prices are set excluding tax, this may result in different prices in Checkout.";
 
 
60
 
61
- if(!Mage::getModel('klarnaCheckout/config')->getLicenseAgreement())
62
- $alerts[] = "By accepting the license agreement and filling in your contact information you can use Klarna Checkout module for free.";
63
-
64
- return $alerts;
65
- }
66
- }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
19
  * @package Avenla_KlarnaCheckout
20
  */
21
  class Avenla_KlarnaCheckout_Block_Adminhtml_System_Config_Fieldset_Info extends Mage_Adminhtml_Block_Abstract
22
+ implements Varien_Data_Form_Element_Renderer_Interface
23
  {
24
+ protected $_template = 'KCO/system/config/fieldset/info.phtml';
25
+
26
+ /**
27
+ * Render fieldset html
28
+ *
29
+ * @param Varien_Data_Form_Element_Abstract Element
30
+ * @return string
31
+ */
32
+ public function render(Varien_Data_Form_Element_Abstract $element)
33
+ {
34
+ $this->assign('logoSrc', Mage::helper("klarnaCheckout")->getLogoSrc());
35
+ $this->assign('apiLink', Avenla_KlarnaCheckout_Model_Config::KLARNA_DOC_URL);
36
+ $this->assign('documentationUrl', Avenla_KlarnaCheckout_Model_Config::DOCUMENTATION_URL);
37
+
38
+ return $this->toHtml();
39
+ }
40
+
41
+ /**
42
+ * Check store configuration
43
+ *
44
+ * @return array
45
+ */
46
+ public function getAlerts()
47
+ {
48
+ $alerts = array();
49
+ $kco = Mage::helper('klarnaCheckout')->getKco();
50
+
51
+ if(!Mage::helper("klarnaCheckout")->getConnectionStatus($kco))
52
+ $alerts[] = "Connection to Klarna failed, please check your eid/shared secret and store settings.";
53
+
54
+ if(Mage::getStoreConfig('tax/calculation/discount_tax') != 1)
55
+ $alerts[] = "Discount is applied before taxes, this may cause different price on Klarna Checkout. Please check store tax configation.";
56
+
57
+ if(Mage::getStoreConfig('tax/calculation/price_includes_tax') != 1)
58
+ $alerts[] = "Catalog prices are set excluding tax, this may result in different prices in Checkout.";
59
+
60
+ if(!Mage::getModel('klarnaCheckout/config')->getLicenseAgreement())
61
+ $alerts[] = "By accepting the license agreement and filling in your contact information you can use Klarna Checkout module for free.";
62
 
63
+ return $alerts;
64
+ }
65
+ }
 
 
 
app/code/community/Avenla/KlarnaCheckout/Block/Catalog/Product/Price.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -18,113 +18,90 @@
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
-
22
  class Avenla_KlarnaCheckout_Block_Catalog_Product_Price extends Mage_Bundle_Block_Catalog_Product_Price
23
- {
24
- private $config;
25
-
26
- public function __construct()
27
- {
28
- $this->config = Mage::getSingleton('klarnaCheckout/KCO')->getConfig();
29
- return parent::_construct();
30
- }
31
-
32
- protected function _toHtml()
33
- {
34
- $html = parent::_toHtml();
35
- if($this->getLayout()->getBlock('klarnaCheckout_price') && $this->getRequest()->getControllerName() == 'product')
36
- return $html;
37
-
38
- if($type = $this->getWidgetType()){
39
- if($this->getRequest()->getControllerName()=='category' && $this->config->getPpWidgetSelection() != "product_list")
40
- return $html;
41
-
42
- $html .= $this->getLayout()->createBlock('core/template', 'klarnaCheckout_price')
43
- ->setWidgetType($this->getWidgetType())
44
- ->setWidgetData($this->getWidgetData())
45
- ->setTemplate('KCO/catalog/product/price.phtml')->toHtml();
46
  }
47
 
48
  return $html;
49
  }
50
 
51
- /**
52
- * Get widget type
53
- *
54
- * @return string | false
55
- */
56
- public function getWidgetType()
57
- {
58
- $selection = $this->config->getPpWidgetSelection();
59
- if($selection == 'product' || $selection == 'product_list'){
60
- return "product";
61
- }
62
- else if($selection == 'klarna'){
63
- return $selection;
64
- }
65
-
66
- return false;
67
- }
68
 
69
- /**
70
- * Get widget data
71
- *
72
- * @return mixed | false
73
- */
74
- public function getWidgetData()
75
- {
76
- $price = $this->_getPrice();
77
-
78
- if($price < 0.1)
79
- return false;
80
-
81
- if($this->getWidgetType() == "product"){
82
- if($widgetText = Mage::getModel('klarnaCheckout/api')->getMonthlyPrice($price)){
83
- return $this->__("From %s/mo.", $widgetText);
84
- }
85
- }
86
- else if($this->getWidgetType() == "klarna"){
87
- return array(
88
- 'width' => 210,
89
- 'height' => 70,
90
- 'eid' => $this->config->getKlarnaEid(),
91
- 'locale' => Mage::app()->getLocale()->getLocaleCode(),
92
- 'price' => $price,
93
- 'layout' => $this->config->getPpWidgetLayout()
94
- );
95
- }
96
 
97
- return false;
98
- }
99
 
100
- /**
101
- * Get product price
102
- *
103
- * @return float
104
- */
105
- private function _getPrice()
106
- {
107
- if($this->getDisplayMinimalPrice()){
108
- $price = $this->getProduct()->getMinimalPrice();
109
- }
110
- else{
111
- $price = $this->getProduct()->getFinalPrice();
112
- }
113
 
114
- $c = Mage::app()->getStore()->getCurrentCurrencyCode();
115
- $bc = Mage::app()->getStore()->getBaseCurrencyCode();
116
- $rate = 1;
117
-
118
- if ($bc != $c) {
119
- $currency = Mage::getModel('directory/currency');
120
- $currency->load($bc);
121
- $rate = $currency->getRate($c);
122
- }
123
 
124
- return $this->helper('tax')->getPrice(
125
- $this->getProduct(),
126
- $price,
127
- true
128
- ) * $rate;
129
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
 
21
  class Avenla_KlarnaCheckout_Block_Catalog_Product_Price extends Mage_Bundle_Block_Catalog_Product_Price
22
+ {
23
+ private $config;
24
+
25
+ protected function _toHtml()
26
+ {
27
+ $html = parent::_toHtml();
28
+ if($kco = Mage::helper('klarnaCheckout')->getKco()){
29
+ $this->config = $kco->getConfig();
30
+
31
+ if(!$this->config->getPpWidgetSelection() || $this->config->getPpWidgetSelection() == "no")
32
+ return $html;
33
+
34
+ if(($this->getRequest()->getControllerName() == 'product' && $this->getLayout()->getBlock('klarnaCheckout_price')) ||
35
+ ($this->getRequest()->getControllerName() == "category" && $this->config->getPpWidgetSelection() != Avenla_KlarnaCheckout_Model_Config::WIDGET_TYPE_LIST))
36
+ return $html;
37
+
38
+ $data = $this->getWidgetData($this->config->getPpWidgetSelection() != Avenla_KlarnaCheckout_Model_Config::WIDGET_TYPE_KLARNA);
39
+
40
+ $html .= $this->getLayout()->createBlock('core/template', 'klarnaCheckout_price')
41
+ ->setWidgetData($data)
42
+ ->setTemplate('KCO/catalog/product/price.phtml')->toHtml();
 
 
43
  }
44
 
45
  return $html;
46
  }
47
 
48
+ /**
49
+ * Get widget data
50
+ *
51
+ * @return Varien_Object|false
52
+ */
53
+ public function getWidgetData($custom = false)
54
+ {
55
+ $price = $this->_getPrice();
 
 
 
 
 
 
 
 
 
56
 
57
+ if($price < 0.1)
58
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ $data = new Varien_Object();
 
61
 
62
+ if($custom){
63
+ $data->setMonthlyPrice(Mage::getModel('klarnaCheckout/api')->getMonthlyPrice($price));
64
+ }
65
+ else{
66
+ $data->setWidth(210);
67
+ $data->setHeight(70);
68
+ $data->setEid($this->config->getKlarnaEid());
69
+ $data->setLocale(Mage::app()->getLocale()->getLocaleCode());
70
+ $data->setPrice($price);
71
+ $data->setLayout($this->config->getPpWidgetLayout());
72
+ }
 
 
73
 
74
+ return $data;
75
+ }
 
 
 
 
 
 
 
76
 
77
+ /**
78
+ * Get product price
79
+ *
80
+ * @return float
81
+ */
82
+ private function _getPrice()
83
+ {
84
+ if($this->getDisplayMinimalPrice()){
85
+ $price = $this->getProduct()->getMinimalPrice();
86
+ }
87
+ else{
88
+ $price = $this->getProduct()->getFinalPrice();
89
+ }
90
+
91
+ $c = Mage::app()->getStore()->getCurrentCurrencyCode();
92
+ $bc = Mage::app()->getStore()->getBaseCurrencyCode();
93
+ $rate = 1;
94
+
95
+ if ($bc != $c) {
96
+ $currency = Mage::getModel('directory/currency');
97
+ $currency->load($bc);
98
+ $rate = $currency->getRate($c);
99
+ }
100
+
101
+ return $this->helper('tax')->getPrice(
102
+ $this->getProduct(),
103
+ $price,
104
+ true
105
+ ) * $rate;
106
+ }
107
  }
app/code/community/Avenla/KlarnaCheckout/Block/KCO.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -21,5 +21,11 @@
21
 
22
  class Avenla_KlarnaCheckout_Block_KCO extends Mage_Core_Block_Template
23
  {
24
-
 
 
 
 
 
 
25
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
21
 
22
  class Avenla_KlarnaCheckout_Block_KCO extends Mage_Core_Block_Template
23
  {
24
+ public function getLoadUrl()
25
+ {
26
+ return $this->getUrl(
27
+ "klarnaCheckout/KCO/loadKcoFrame/",
28
+ array("_forced_secure" => Mage::app()->getStore()->isCurrentlySecure())
29
+ );
30
+ }
31
  }
app/code/community/Avenla/KlarnaCheckout/Block/KCO/Confirmation.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,210 +20,149 @@
20
  */
21
  class Avenla_KlarnaCheckout_Block_KCO_Confirmation extends Mage_Core_Block_Template
22
  {
23
-
24
  protected function _toHtml()
25
- {
26
- return $this->getKcoFrame();
27
- }
28
-
29
  /**
30
- * Return Klarna Checkout confirmation page
31
- *
32
- * @return string
33
- */
34
  private function getKcoFrame()
35
  {
36
- $order = Mage::getModel("klarnaCheckout/order")->getOrder(null, $this->getCheckoutID());
37
- $order->fetch();
38
- $result = "";
39
-
40
- if(Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() !== false && isset($_SESSION['klarna_checkout'])){
41
- $result .= $this->getAnalyticsCode($order);
42
- }
43
-
44
- $result .= $order['gui']['snippet'];
45
-
46
- $link_to_store = '<div class="buttons-set"><button type="button" class="button"
47
- title="'. $this->__('Continue Shopping') .'" onclick="window.location=\''. $this->getUrl() .'\'">
48
- <span><span>'. $this->__('Continue Shopping') .'</span></span></button></div>';
49
-
50
- $result .= $link_to_store;
51
-
52
- unset($_SESSION['klarna_checkout']);
53
-
54
- return $result;
55
  }
56
-
57
- /**
58
- * Get Google Analytics Ecommerce tracking code
59
- *
60
- * @param Klarna_Checkout_Order $ko
61
- * @return string
62
- */
63
- private function getAnalyticsCode($ko)
64
- {
65
- $type = Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsType();
66
- $orderId = false;
67
-
68
- if(strlen($ko['merchant_reference']['orderid2']) > 0){
69
- $mo = Mage::getModel('sales/order')->load($ko['merchant_reference']['orderid1'], 'increment_id');
70
- if($mo->getId()){
71
- $orderId = $ko['merchant_reference']['orderid1'];
72
- }
73
- }
74
-
75
- if(!$orderId){
76
- $quote = Mage::getModel('sales/quote')->load($ko['merchant_reference']['orderid1']);
77
- $quote->reserveOrderId();
78
- $quote->save();
79
- $orderId = $quote->getReservedOrderId();
80
- }
81
-
82
- if(count($ko['cart']['items']) < 1)
83
- return;
84
-
85
- foreach($ko['cart']['items'] as $p){
86
- $shipping_fee = "";
87
- if($p['type'] == 'shipping_fee')
88
- $shipping_fee = $p['total_price_including_tax'];
89
- }
90
-
91
- if($type == Avenla_KlarnaCheckout_Model_Config::ANALYTICS_UNIVERSAL){
92
- return $this->getUniversalAnalyticsCode($ko, $shipping_fee, $orderId);
93
- }
94
- else{
95
- return $this->getClassicAnalyticsCode($ko, $shipping_fee, $orderId);
96
- }
97
- }
98
 
99
  /**
100
- * Get classic Google Analytics Ecommerce tracking code
101
- *
102
- * @param Klarna_Checkout_Order $ko
103
- * @param string $shipping_fee
104
- * @param string $orderId
105
- * @return string
106
- */
107
- private function getClassicAnalyticsCode($ko, $shipping_fee, $orderId)
108
  {
 
 
 
109
 
110
- $gc = '<script type="text/javascript">';
111
- $gc .= "//<![CDATA[\n";
112
- $gc .= 'var _gaq = _gaq || [];';
113
- $gc .= '_gaq.push(["_setAccount", "' . Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() . '"]);';
114
-
115
- $gc .= sprintf("_gaq.push(['_addTrans', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']);",
116
- $orderId,
117
- Mage::app()->getStore()->getName(),
118
- $ko['cart']['total_price_including_tax'] / 100,
119
- $ko['cart']['total_tax_amount'] / 100,
120
- $shipping_fee / 100,
121
- $ko['billing_address']['city'],
122
- null,
123
- $ko['billing_address']['country']
124
- );
125
-
126
- foreach ($ko['cart']['items'] as $p){
127
-
128
- if($p['type'] == 'shipping_fee')
129
- continue;
130
-
131
-
132
- $product = Mage::getModel('catalog/product')->loadByAttribute('sku', $p['reference']);
133
- if($product){
134
- $categoryIds = Mage::getModel('catalog/product')
135
- ->loadByAttribute('sku', $p['reference'])
136
- ->getCategoryIds();
137
-
138
- if(!empty($categoryIds))
139
- $cat = Mage::getModel('catalog/category')->load(end($categoryIds))->getName();
140
- }
141
-
142
- $gc .= sprintf("_gaq.push(['_addItem', '%s', '%s', '%s', '%s', '%s', '%s']);",
143
- $orderId,
144
- $p['reference'],
145
- $p['name'],
146
- null,
147
- $p['unit_price'] / 100,
148
- $p['quantity']
149
- );
150
- }
151
-
152
- $gc .= '_gaq.push(["_set", "currencyCode", "'. $ko['purchase_currency'].'"]); ';
153
- $gc .= '_gaq.push(["_trackTrans"]);';
154
- $gc .= '(function() { ';
155
- $gc .= 'var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true; ';
156
- $gc .= 'ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";';
157
- $gc .= 'var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);';
158
- $gc .= ' })();';
159
- $gc .= '//]]>' . "\n";
160
- $gc .= '</script>';
161
-
162
- return $gc;
163
- }
164
-
165
- /**
166
- * Get Universal Google Analytics Ecommerce tracking code
167
- *
168
- * @param Klarna_Checkout_Order $ko
169
- * @param string $shipping_fee
170
- * @param string $orderId
171
- * @return string
172
- */
173
- public function getUniversalAnalyticsCode($ko, $shipping_fee, $orderId)
174
- {
175
- $gc = '<script type="text/javascript">';
176
- $gc .= "//<![CDATA[\n";
177
- $gc .= "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){";
178
- $gc .= "(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),";
179
- $gc .= "m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)";
180
- $gc .= "})(window,document,'script','//www.google-analytics.com/analytics.js','ga');";
181
-
182
- $gc .= "ga('create', '" . Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() . "', 'auto');";
183
-
184
- $gc .= "ga('require', 'ecommerce');";
185
- $gc .= sprintf("ga('ecommerce:addTransaction', {
186
- 'id': '%s',
187
- 'affiliation': '%s',
188
- 'revenue': '%s',
189
- 'tax': '%s',
190
- 'shipping': '%s',
191
- 'currency': '%s'
192
- });",
193
- $orderId,
194
- Mage::app()->getStore()->getName(),
195
- $ko['cart']['total_price_including_tax'] / 100,
196
- $ko['cart']['total_tax_amount'] / 100,
197
- $shipping_fee / 100,
198
- $ko['purchase_currency']
199
- );
200
-
201
- foreach ($ko['cart']['items'] as $p){
202
-
203
- if($p['type'] == 'shipping_fee')
204
- continue;
205
-
206
- $gc .= sprintf("ga('ecommerce:addItem', {
207
- 'id': '%s',
208
- 'sku': '%s',
209
- 'name': '%s',
210
- 'category': '%s',
211
- 'price': '%s',
212
- 'quantity': '%s'
213
- });",
214
- $orderId,
215
- $p['reference'],
216
- $p['name'],
217
- null,
218
- $p['unit_price'] / 100,
219
- $p['quantity']
220
- );
221
- }
222
- $gc .= "ga('ecommerce:send');";
223
-
224
- $gc .= '//]]>' . "\n";
225
- $gc .= '</script>';
226
-
227
- return $gc;
228
- }
229
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  class Avenla_KlarnaCheckout_Block_KCO_Confirmation extends Mage_Core_Block_Template
22
  {
 
23
  protected function _toHtml()
24
+ {
25
+ return $this->getKcoFrame();
26
+ }
27
+
28
  /**
29
+ * Return Klarna Checkout confirmation page
30
+ *
31
+ * @return string
32
+ */
33
  private function getKcoFrame()
34
  {
35
+ $result = "";
36
+ if($analyticsData = $this->getAnalyticsData())
37
+ $result .= $this->getAnalyticsCode($analyticsData);
38
+
39
+ $result .= $this->getKlarnaSnippet();
40
+ $linkToStore = '<div class="buttons-set"><button type="button" class="button"
41
+ title="'. $this->__('Continue Shopping') .'" onclick="window.location=\''. $this->getUrl() .'\'">
42
+ <span><span>'. $this->__('Continue Shopping') .'</span></span></button></div>';
43
+
44
+ $result .= $linkToStore;
45
+
46
+ return $result;
 
 
 
 
 
 
 
47
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  /**
50
+ * Get Google Analytics Ecommerce tracking code
51
+ *
52
+ * @param Klarna_Checkout_Order $ko
53
+ * @return string
54
+ */
55
+ private function getAnalyticsCode($data)
 
 
56
  {
57
+ $type = Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsType();
58
+ if($type == Avenla_KlarnaCheckout_Model_Config::ANALYTICS_UNIVERSAL)
59
+ return $this->getUniversalAnalyticsCode($data);
60
 
61
+ return $this->getClassicAnalyticsCode($data);
62
+ }
63
+
64
+ /**
65
+ * Get classic Google Analytics Ecommerce tracking code
66
+ *
67
+ * @param Varien_Object $data
68
+ * @return string
69
+ */
70
+ private function getClassicAnalyticsCode($data)
71
+ {
72
+ $gc = '<script type="text/javascript">';
73
+ $gc .= "//<![CDATA[\n";
74
+ $gc .= 'var _gaq = _gaq || [];';
75
+ $gc .= '_gaq.push(["_setAccount", "' . Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() . '"]);';
76
+
77
+ $gc .= sprintf("_gaq.push(['_addTrans', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']);",
78
+ $data->getOrderId(),
79
+ Mage::app()->getStore()->getName(),
80
+ $data->getTotalInclTax(),
81
+ $data->getTotalTaxAmount(),
82
+ $data->getShippingFee(),
83
+ $data->getBillingCity(),
84
+ null,
85
+ $data->getBillingCountry()
86
+ );
87
+
88
+ foreach ($data->getItems() as $p){
89
+ $gc .= sprintf("_gaq.push(['_addItem', '%s', '%s', '%s', '%s', '%s', '%s']);",
90
+ $data->getOrderId(),
91
+ $p->getReference(),
92
+ $p->getName(),
93
+ null,
94
+ $p->getUnitPrice(),
95
+ $p->getQty
96
+ );
97
+ }
98
+
99
+ $gc .= '_gaq.push(["_set", "currencyCode", "'. $data->getCurrency() .'"]); ';
100
+ $gc .= '_gaq.push(["_trackTrans"]);';
101
+ $gc .= '(function() { ';
102
+ $gc .= 'var ga = document.createElement("script"); ga.type = "text/javascript"; ga.async = true; ';
103
+ $gc .= 'ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";';
104
+ $gc .= 'var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ga, s);';
105
+ $gc .= ' })();';
106
+ $gc .= '//]]>' . "\n";
107
+ $gc .= '</script>';
108
+
109
+ return $gc;
110
+ }
111
+
112
+ /**
113
+ * Get Universal Google Analytics Ecommerce tracking code
114
+ *
115
+ * @param Varien_Object $data
116
+ * @return string
117
+ */
118
+ public function getUniversalAnalyticsCode($data)
119
+ {
120
+ $gc = '<script type="text/javascript">';
121
+ $gc .= "//<![CDATA[\n";
122
+ $gc .= "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){";
123
+ $gc .= "(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),";
124
+ $gc .= "m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)";
125
+ $gc .= "})(window,document,'script','//www.google-analytics.com/analytics.js','ga');";
126
+ $gc .= "ga('create', '" . Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() . "', 'auto');";
127
+ $gc .= "ga('require', 'ecommerce');";
128
+ $gc .= sprintf("ga('ecommerce:addTransaction', {
129
+ 'id': '%s',
130
+ 'affiliation': '%s',
131
+ 'revenue': '%s',
132
+ 'tax': '%s',
133
+ 'shipping': '%s',
134
+ 'currency': '%s'
135
+ });",
136
+ $data->getOrderId(),
137
+ Mage::app()->getStore()->getName(),
138
+ $data->getTotalInclTax(),
139
+ $data->getTotalTaxAmount(),
140
+ $data->getShippingFee(),
141
+ $data->getCurrency()
142
+ );
143
+
144
+ foreach ($data->getItems() as $p){
145
+ $gc .= sprintf("ga('ecommerce:addItem', {
146
+ 'id': '%s',
147
+ 'sku': '%s',
148
+ 'name': '%s',
149
+ 'category': '%s',
150
+ 'price': '%s',
151
+ 'quantity': '%s'
152
+ });",
153
+ $data->getOrderId(),
154
+ $p->getReference(),
155
+ $p->getName(),
156
+ null,
157
+ $p->getPrice(),
158
+ $p->getQty()
159
+ );
160
+ }
161
+ $gc .= "ga('ecommerce:send');";
162
+
163
+ $gc .= '//]]>' . "\n";
164
+ $gc .= '</script>';
165
+
166
+ return $gc;
167
+ }
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
app/code/community/Avenla/KlarnaCheckout/Block/KCO/Info.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,24 +20,30 @@
20
  */
21
  class Avenla_KlarnaCheckout_Block_KCO_Info extends Mage_Payment_Block_Info
22
  {
23
- protected function _toHtml()
24
- {
25
- $this->setTemplate('KCO/info.phtml');
26
  $helper = Mage::helper("klarnaCheckout");
 
27
  $payment = $this->getMethod();
 
 
 
28
 
29
- $this->assign('info', $this->getInfo());
30
- $this->assign('imgSrc', $helper->getLogoSrc());
31
- $this->assign('guiUrl', $helper->getKlarnaMerchantsUrl());
32
-
33
- if (count($this->getInfo()->getAdditionalInformation("klarna_order_invoice")) > 0){
34
- $server = $this->getInfo()->getAdditionalInformation("klarna_server");
35
- $this->assign('pdfUrl', $server . "/packslips/");
 
 
 
 
 
36
  }
37
-
38
- if (strlen($this->getInfo()->getAdditionalInformation("klarna_message")) > 0)
39
- $this->assign('message', $this->getInfo()->getAdditionalInformation("klarna_message"));
40
-
41
  return parent::_toHtml();
42
- }
43
- }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  class Avenla_KlarnaCheckout_Block_KCO_Info extends Mage_Payment_Block_Info
22
  {
23
+ protected function _toHtml()
24
+ {
25
+ $this->setTemplate('KCO/info.phtml');
26
  $helper = Mage::helper("klarnaCheckout");
27
+
28
  $payment = $this->getMethod();
29
+ $order = $this->getInfo()->getOrder();
30
+ $orderStore = $order->getStore()->getId();
31
+ $klarnaOrderId = $this->getInfo()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
32
 
33
+ $this->assign('orderStore', $orderStore);
34
+ $this->assign('orderState', $order->getState());
35
+
36
+ $kco = $payment->getOrderModel();
37
+ $kco->useConfigForStore($orderStore);
38
+ if($klarnaOrderId){
39
+ try{
40
+ $this->assign('klarnaInfo', $kco->getOrderInformation($klarnaOrderId, $this->getInfo()));
41
+ }
42
+ catch(Exception $e){
43
+ Mage::helper('klarnaCheckout')->logException($e);
44
+ }
45
  }
46
+
 
 
 
47
  return parent::_toHtml();
48
+ }
49
+ }
app/code/community/Avenla/KlarnaCheckout/Block/KCO/Newsletter.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,24 +20,23 @@
20
  */
21
  class Avenla_KlarnaCheckout_Block_KCO_Newsletter extends Mage_Core_Block_Template
22
  {
23
-
24
  protected function _toHtml()
25
- {
26
- $this->setTemplate('KCO/newsletter.phtml');
27
- return parent::_toHtml();
28
- }
29
-
30
- /**
31
- * Check for previous selection
32
- *
33
- * @return bool
34
- */
35
- public function isChecked()
36
- {
37
- $quote = Mage::getSingleton('checkout/session')->getQuote();
38
- if($quote->getPayment()->getAdditionalInformation("klarna_newsletter"))
39
- return true;
40
 
41
- return false;
42
- }
43
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  class Avenla_KlarnaCheckout_Block_KCO_Newsletter extends Mage_Core_Block_Template
22
  {
 
23
  protected function _toHtml()
24
+ {
25
+ $this->setTemplate('KCO/newsletter.phtml');
26
+ return parent::_toHtml();
27
+ }
28
+
29
+ /**
30
+ * Check for previous selection
31
+ *
32
+ * @return bool
33
+ */
34
+ public function isChecked()
35
+ {
36
+ $quote = Mage::getSingleton('checkout/session')->getQuote();
37
+ if($quote->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_NEWSLETTER))
38
+ return true;
39
 
40
+ return false;
41
+ }
42
  }
app/code/community/Avenla/KlarnaCheckout/Block/Widgets/Logo.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -28,10 +28,7 @@ class Avenla_KlarnaCheckout_Block_Widgets_Logo extends Mage_Core_Block_Abstract
28
  if($width < 1)
29
  $width = 350;
30
 
31
- $country = Mage::helper('klarnaCheckout')->getLocale(Mage::getStoreConfig('general/country/default', Mage::app()->getStore()));
32
- $country = str_replace('-', '_', $country);
33
- $imgSrc = 'https://cdn.klarna.com/1.0/shared/image/generic/logo/'.$country.'/basic/'.$this->getData('background').'.png?width='.$width.'&eid='. Mage::getModel('klarnaCheckout/config')->getKlarnaEid();
34
-
35
  return '<img src='.$imgSrc.' />';
36
  }
37
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
28
  if($width < 1)
29
  $width = 350;
30
 
31
+ $imgSrc = Mage::helper('klarnaCheckout')->getLogoSrc($width, $this->getData('background'));
 
 
 
32
  return '<img src='.$imgSrc.' />';
33
  }
34
  }
app/code/community/Avenla/KlarnaCheckout/Block/Widgets/Methods.php CHANGED
@@ -24,7 +24,7 @@ class Avenla_KlarnaCheckout_Block_Widgets_Methods extends Mage_Core_Block_Templa
24
  protected function _toHtml()
25
  {
26
  $beforeBodyEnd = $this->getLayout()->getBlock('before_body_end');
27
- $script = $this->getLayout()->createBlock('core/text')->setText('<script async src="https://cdn.klarna.com/1.0/code/client/all.js"></script>');
28
  $beforeBodyEnd->append($script);
29
 
30
  $this->setTemplate('KCO/widget/methods.phtml');
@@ -34,11 +34,8 @@ class Avenla_KlarnaCheckout_Block_Widgets_Methods extends Mage_Core_Block_Templa
34
  $width = 350;
35
 
36
  $this->setWidth($width);
37
- $locale = strtolower(Mage::app()->getLocale()->getLocaleCode());
38
- $this->setLocale($locale);
39
 
40
  return parent::_toHtml();
41
  }
42
-
43
-
44
  }
24
  protected function _toHtml()
25
  {
26
  $beforeBodyEnd = $this->getLayout()->getBlock('before_body_end');
27
+ $script = $this->getLayout()->createBlock('core/text')->setText('<script async src="' . Avenla_KlarnaCheckout_Model_Config::KLARNA_WIDGET_SCRIPT . '"></script>');
28
  $beforeBodyEnd->append($script);
29
 
30
  $this->setTemplate('KCO/widget/methods.phtml');
34
  $width = 350;
35
 
36
  $this->setWidth($width);
37
+ $this->setLocale(strtolower(Mage::app()->getLocale()->getLocaleCode()));
 
38
 
39
  return parent::_toHtml();
40
  }
 
 
41
  }
app/code/community/Avenla/KlarnaCheckout/Helper/Api.php DELETED
@@ -1,100 +0,0 @@
1
- <?php
2
- /**
3
- * This file is released under a custom license by Avenla Oy.
4
- * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
- * For questions and support - klarna-support@avenla.com
8
- *
9
- * @category Avenla
10
- * @package Avenla_KlarnaCheckout
11
- * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
- */
14
-
15
- /**
16
- * Avenla KlarnaCheckout
17
- *
18
- * @category Avenla
19
- * @package Avenla_KlarnaCheckout
20
- */
21
- class Avenla_KlarnaCheckout_Helper_Api extends Mage_Core_Helper_Abstract
22
- {
23
-
24
- /**
25
- * Get default country from store config
26
- *
27
- * @return string
28
- */
29
- public function getCountry()
30
- {
31
- return Mage::getStoreConfig('general/country/default');
32
- }
33
-
34
- /**
35
- * Get Klarna reservation number from order
36
- *
37
- * @param Mage_Sales_Model_Order $mo
38
- * @return mixed
39
- */
40
- public function getReservationNumber($mo)
41
- {
42
- if($rno = $mo->getPayment()->getAdditionalInformation("klarna_order_reservation"))
43
- return $rno;
44
-
45
- return false;
46
- }
47
-
48
- /**
49
- * Get Klarna invoice numbers from order
50
- *
51
- * @param Mage_Sales_Model_Order $mo
52
- * @return array
53
- */
54
- public function getKlarnaInvoices($mo)
55
- {
56
- if($result = $mo->getPayment()->getAdditionalInformation("klarna_order_invoice"))
57
- return $result;
58
-
59
- return array();
60
- }
61
-
62
- /**
63
- * Save Klarna invoice numbers to order
64
- *
65
- * @param Mage_Sales_Model_Order $mo
66
- * @param array $klarnainvoices
67
- * @return Mage_Sales_Model_Order
68
- */
69
- public function saveKlarnaInvoices($mo, $klarnainvoices)
70
- {
71
- $mo->getPayment()->setAdditionalInformation("klarna_order_invoice", $klarnainvoices);
72
- return $mo;
73
- }
74
-
75
- /**
76
- * Handle failed activation
77
- *
78
- * @param Mage_Sales_Model_Order $mo
79
- * @param string $rno
80
- * @param Exception $e
81
- */
82
- public function failedActivation($mo, $rno, $e)
83
- {
84
- $mo->addStatusHistoryComment(
85
- $this->__('Failed to activate reservation %s', $rno) ."(" . $e->getMessage() . ")"
86
- );
87
- $mo->save();
88
- Mage::unregister('kco_save');
89
- Mage::logException($e);
90
- }
91
-
92
- /**
93
- * Get Klarna API documentation URL
94
- *
95
- */
96
- public function getApiDocumentationUrl()
97
- {
98
- return Avenla_KlarnaCheckout_Model_Config::KLARNA_DOC_URL;
99
- }
100
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Avenla/KlarnaCheckout/Helper/Data.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,197 +20,328 @@
20
  */
21
  class Avenla_KlarnaCheckout_Helper_Data extends Mage_Core_Helper_Data
22
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- /**
25
- * Write in KCO log if debugging is enabled
26
- *
27
- * @param mixed $message
28
- * @param integer $level
29
- */
30
- public function log($message, $level = 7)
31
- {
32
-
33
- if(!Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->debuglog())
34
- return;
35
-
36
- $file = 'KCO.log';
37
- Mage::log($message, $level, $file);
38
- }
39
-
40
- /**
41
- * Get confirmation url
42
- *
43
- * @return string
44
- */
45
- public function getConfirmationUri()
46
- {
47
- return rtrim(Mage::getUrl('klarnaCheckout/KCO/confirmation?klarna_order={checkout.order.uri}'), "/");
48
- }
49
-
50
- /**
51
- * Get push url
52
- *
53
- * @return string
54
- */
55
- public function getPushUri()
56
- {
57
  $storeId = Mage::app()->getStore()->getStoreId();
58
- return rtrim(Mage::getUrl('klarnaCheckout/KCO/push?storeid='.$storeId.'&klarna_order={checkout.order.uri}'), "/");
59
- }
60
-
61
- /**
62
- * Get validation url
63
- *
64
- * @return string | false
65
- */
66
- public function getValidationUri()
67
- {
68
- $uri = rtrim(Mage::getUrl('klarnaCheckout/KCO/validation?sid='.Mage::getSingleton('core/session')
69
- ->getSessionId(), array('_forced_secure' => true)), "/");
70
-
71
- if(parse_url($uri, PHP_URL_SCHEME) == "https")
72
- return $uri;
73
-
74
- return false;
75
- }
76
-
77
- /**
78
- * Get url of checkout page
79
- *
80
- * @return string
81
- */
82
- public function getCheckoutUri()
83
- {
84
- return rtrim(Mage::helper('checkout/url')->getCheckoutUrl(), "/");
85
- }
86
-
87
- /**
88
- * Get url of cart page
89
- *
90
- * @return string
91
- */
92
- public function getCartUri()
93
- {
94
- return Mage::getUrl('checkout/cart');
95
- }
96
-
97
- /**
98
- * Get Klarna logo url
99
- *
100
- * @param int $width
101
- * @return string
102
- */
103
- public function getLogoSrc($width = 88)
104
- {
105
- $eid = Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->getKlarnaEid();
106
- return "https://cdn.klarna.com/1.0/shared/image/generic/logo/sv_se/basic/blue-black.png?width=". $width . "&eid=" . $eid;
107
- }
108
-
109
- /**
110
- * Get link text
111
- *
112
- * @return string
113
- */
114
- public function getLinkText()
115
- {
116
- return Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->getLinkText();
117
- }
118
-
119
- /**
120
- * Get url to Klarna online GUI
121
- *
122
- * @return string
123
- */
124
- public function getKlarnaMerchantsUrl()
125
- {
126
- return Avenla_KlarnaCheckout_Model_Config::ONLINE_GUI_URL;
127
- }
128
-
129
- /**
130
- * Send test query to Klarna to verify given merchant credentials
131
- *
132
- * @return bool
133
- */
134
- public function getConnectionStatus($quote = null)
135
- {
136
- try{
137
- $ko = Mage::getModel("klarnaCheckout/order")->dummyOrder($quote);
138
-
139
- if($ko == null)
140
- return false;
141
-
142
- $ko->fetch();
143
- return true;
144
  }
145
- catch (Exception $e) {
146
- return false;
147
- }
148
- }
149
-
150
- /**
151
- * Check if Klarna order was made in current store
152
- *
153
- * @param Klarna_Checkout_Order $ko
154
- * @return bool
155
- */
156
- public function isOrderFromCurrentStore($ko)
157
- {
158
- $uri = $ko['merchant']['push_uri'];
159
- preg_match('/storeid=(.*?)&klarna_order/', $uri, $res);
160
-
161
- if($res[1] == Mage::app()->getStore()->getStoreId())
162
- return true;
163
-
164
- return false;
165
- }
166
-
167
- /**
168
- * Get order shipping tax rate
169
- *
170
- * @return float $taxRate
171
- */
172
- public function getShippingVatRate()
173
- {
174
- $taxRate = 0;
175
- $taxHelper = Mage::helper('tax/data');
176
- $taxClass = $taxHelper->getShippingTaxClass(Mage::app()->getStore());
177
- $taxClasses = Mage::helper("core")->jsonDecode(Mage::helper("tax")->getAllRatesByProductClass());
178
- if(isset($taxClasses["value_".$taxClass]))
179
- $taxRate = $taxClasses["value_".$taxClass];
180
-
181
- return $taxRate;
182
- }
183
-
184
- /**
185
- * Get locale code for purchase country
186
- *
187
- * @param string $country
188
- * @return string
189
- */
190
- public function getLocale($country)
191
- {
192
- switch($country){
193
- case 'SE':
194
- return 'sv-se';
195
- case 'NO':
196
- return 'nb-no';
197
- case 'DE':
198
- return 'de-de';
199
- case 'AT':
200
- return 'de-at';
201
- case 'FI':
202
- default:
203
- return 'fi-fi';
204
- }
205
- }
206
-
207
- /**
208
- * Get url for module documentation
209
- *
210
- * @return string
211
- */
212
- public function getDocumentationUrl()
213
- {
214
- return Avenla_KlarnaCheckout_Model_Config::DOCUMENTATION_URL;
215
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  class Avenla_KlarnaCheckout_Helper_Data extends Mage_Core_Helper_Data
22
  {
23
+ /**
24
+ * Write in KCO log if debugging is enabled
25
+ *
26
+ * @param mixed $message
27
+ * @param int $level
28
+ */
29
+ public function log($message, $level = 7)
30
+ {
31
+ if(!Mage::getSingleton('klarnaCheckout/payment_KCO')->getConfig()->debuglog())
32
+ return;
33
+
34
+ $file = 'KCO.log';
35
+ Mage::log($message, $level, $file);
36
+ }
37
+
38
+ /**
39
+ * Write exception to log
40
+ *
41
+ * @param Exception $e
42
+ */
43
+ public function logException(Exception $e)
44
+ {
45
+ $this->log("\n" . $e->__toString(), Zend_Log::ERR);
46
+ if($e instanceof Klarna_Checkout_ApiErrorException){
47
+ $this->log($e->getMessage());
48
+ $this->log($e->getPayload());
49
+ }
50
+
51
+ Mage::logException($e);
52
+ }
53
+
54
+ /**
55
+ * Get KCO payment model
56
+ *
57
+ * @return mixed
58
+ */
59
+ public function getKco()
60
+ {
61
+ $version = Mage::getSingleton('klarnaCheckout/config')->getApiVersion();
62
+ if($version == Avenla_KlarnaCheckout_Model_Config::API_TYPE_KCOV2){
63
+ return Mage::getModel('klarnaCheckout/payment_KCO');
64
+ }
65
+ elseif($version == Avenla_KlarnaCheckout_Model_Config::API_TYPE_KCOV3_UK || $version == Avenla_KlarnaCheckout_Model_Config::API_TYPE_KCOV3_US){
66
+ return Mage::getModel('klarnaCheckout/payment_KCOv3');
67
+ }
68
+
69
+ return false;
70
+ }
71
+
72
+ /**
73
+ * Get confirmation url
74
+ *
75
+ * @return string
76
+ */
77
+ public function getConfirmationUri()
78
+ {
79
+ return rtrim(Mage::getUrl('klarnaCheckout/KCO/confirmation?' . Avenla_KlarnaCheckout_Model_Payment_Abstract::REQUEST_KLARNA_ORDER . '={checkout.order.id}'), "/");
80
+ }
81
 
82
+ /**
83
+ * Get push url
84
+ *
85
+ * @return string
86
+ */
87
+ public function getPushUri()
88
+ {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  $storeId = Mage::app()->getStore()->getStoreId();
90
+ return rtrim(Mage::getUrl('klarnaCheckout/KCO/push?storeid='.$storeId.'&' . Avenla_KlarnaCheckout_Model_Payment_Abstract::REQUEST_KLARNA_ORDER . '={checkout.order.id}'), "/");
91
+ }
92
+
93
+ /**
94
+ * Get validation url
95
+ *
96
+ * @return string|false
97
+ */
98
+ public function getValidationUri()
99
+ {
100
+ $uri = rtrim(Mage::getUrl('klarnaCheckout/KCO/validation?sid='.Mage::getSingleton('core/session')
101
+ ->getSessionId(), array('_forced_secure' => true)), "/");
102
+
103
+ if(parse_url($uri, PHP_URL_SCHEME) == "https")
104
+ return $uri;
105
+
106
+ return false;
107
+ }
108
+
109
+ /**
110
+ * Get url of checkout page
111
+ *
112
+ * @return string
113
+ */
114
+ public function getCheckoutUri()
115
+ {
116
+ return rtrim(Mage::helper('checkout/url')->getCheckoutUrl(), "/");
117
+ }
118
+
119
+ /**
120
+ * Get url of cart page
121
+ *
122
+ * @return string
123
+ */
124
+ public function getCartUri()
125
+ {
126
+ return Mage::getUrl('checkout/cart');
127
+ }
128
+
129
+ /**
130
+ * Get Klarna logo url
131
+ *
132
+ * @param int $width|88
133
+ * @param string $background|blue-black
134
+ * @return string
135
+ */
136
+ public function getLogoSrc($width = 88, $background = "blue-black")
137
+ {
138
+ $country = $this->getLocale(Mage::getStoreConfig('general/country/default', Mage::app()->getStore()));
139
+ $country = str_replace('-', '_', $country);
140
+ $eid = Mage::getSingleton('klarnaCheckout/payment_KCO')->getConfig()->getKlarnaEid();
141
+
142
+ return 'https://cdn.klarna.com/1.0/shared/image/generic/logo/'.$country.'/basic/'.$background.'.png?width='.$width.'&eid='. Mage::getModel('klarnaCheckout/config')->getKlarnaEid();
143
+ }
144
+
145
+ /**
146
+ * Send test query to Klarna to verify given merchant credentials
147
+ *
148
+ * @return bool
149
+ */
150
+ public function getConnectionStatus($kco, $quote = null)
151
+ {
152
+ try{
153
+ $ko = $kco->getOrderModel()->dummyOrder($quote);
154
+
155
+ if($ko == null)
156
+ return false;
157
+
158
+ $ko->fetch();
159
+ return true;
160
+ }
161
+ catch (Exception $e) {
162
+ $this->logException($e);
163
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
165
+ }
166
+
167
+ /**
168
+ * Check if Klarna order was made in current store
169
+ *
170
+ * @param Klarna_Checkout_Order $ko
171
+ * @return bool
172
+ */
173
+ public function isOrderFromCurrentStore($ko)
174
+ {
175
+ $uri = $ko['merchant']['push_uri'];
176
+ preg_match('/storeid=(.*?)&' . Avenla_KlarnaCheckout_Model_Payment_Abstract::REQUEST_KLARNA_ORDER . '/', $uri, $res);
177
+
178
+ if($res[1] == Mage::app()->getStore()->getStoreId())
179
+ return true;
180
+
181
+ return false;
182
+ }
183
+
184
+ /**
185
+ * Get order shipping tax rate
186
+ *
187
+ * @param Mage_Sales_Model_Quote
188
+ * @return float $taxRate
189
+ */
190
+ public function getShippingVatRate($quote)
191
+ {
192
+ $taxCalculationModel = Mage::getSingleton('tax/calculation');
193
+
194
+ $request = $taxCalculationModel->getRateRequest(
195
+ $quote->getShippingAddress(),
196
+ $quote->getBillingAddress(),
197
+ $quote->getCustomerTaxClassId(),
198
+ $quote->getStore()
199
+ );
200
+
201
+ $shippingTaxClass = Mage::getStoreConfig(Mage_Tax_Model_Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS, $quote->getStore());
202
+ $rate = $taxCalculationModel->getRate($request->setProductClassId($shippingTaxClass));
203
+
204
+ return $rate;
205
+ }
206
+
207
+ /**
208
+ * Get locale code for purchase country
209
+ *
210
+ * @param string $country
211
+ * @return string
212
+ */
213
+ public function getLocale($country)
214
+ {
215
+ switch($country){
216
+ case 'SE':
217
+ return 'sv-se';
218
+ case 'NO':
219
+ return 'nb-no';
220
+ case 'DE':
221
+ return 'de-de';
222
+ case 'AT':
223
+ return 'de-at';
224
+ case 'GB':
225
+ return 'en-gb';
226
+ case 'US':
227
+ return 'en-us';
228
+ case 'FI':
229
+ default:
230
+ return 'fi-fi';
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Format Klarna price for Magento
236
+ *
237
+ * @param int $price
238
+ * @param int store|null
239
+ * @return mixed
240
+ */
241
+ public function formatKlarnaPriceForMagento($price, $store = null)
242
+ {
243
+ $price = $price / 100;
244
+ return Mage::helper('core')->currencyByStore($price, $store, true, false);
245
+ }
246
+
247
+ /**
248
+ * Format Magento price for Klarna
249
+ *
250
+ * @param float $price
251
+ * @return int $price
252
+ */
253
+ public function formatPriceForKlarna($price)
254
+ {
255
+ return round($price, 2) * 100;
256
+ }
257
+
258
+ /**
259
+ * Check if order is made with KCO
260
+ *
261
+ * @param Mage_Sales_Model_Order $mo
262
+ * @return bool
263
+ */
264
+ public function isKcoOrder($order)
265
+ {
266
+ $kcoCodes = array(
267
+ Mage::getModel('klarnaCheckout/payment_KCO')->getCode(),
268
+ Mage::getModel('klarnaCheckout/payment_KCOv3')->getCode()
269
+ );
270
+
271
+ $paymentCode = $order->getPayment()->getMethodInstance()->getCode();
272
+ if(in_array($paymentCode, $kcoCodes))
273
+ return true;
274
+
275
+ return false;
276
+ }
277
+
278
+ /**
279
+ * Check for key in registry
280
+ *
281
+ * @return bool
282
+ */
283
+ public function isKcoSave()
284
+ {
285
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_KCO_SAVE))
286
+ return true;
287
+
288
+ return false;
289
+ }
290
+
291
+ /**
292
+ * Add key to registry
293
+ */
294
+ public function prepareKcoSave()
295
+ {
296
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_KCO_SAVE, true);
297
+ }
298
+
299
+ /**
300
+ * Remove key from registry
301
+ */
302
+ public function finishKcoSave()
303
+ {
304
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_KCO_SAVE);
305
+ }
306
+
307
+ /**
308
+ * Get Klarna reservation number from order
309
+ *
310
+ * @param Mage_Sales_Model_Order $mo
311
+ * @return string|false
312
+ */
313
+ public function getReservationNumber($mo)
314
+ {
315
+ if($rno = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_RESERVATION))
316
+ return $rno;
317
+
318
+ return false;
319
+ }
320
+
321
+ /**
322
+ * Get Klarna invoice numbers from order
323
+ *
324
+ * @param Mage_Sales_Model_Order $mo
325
+ * @return array
326
+ */
327
+ public function getKlarnaInvoices($mo)
328
+ {
329
+ if($result = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_INVOICE))
330
+ return $result;
331
+
332
+ return array();
333
+ }
334
+
335
+ /**
336
+ * Save Klarna invoice numbers to order
337
+ *
338
+ * @param Mage_Sales_Model_Order $mo
339
+ * @param array $klarnainvoices
340
+ * @return Mage_Sales_Model_Order
341
+ */
342
+ public function saveKlarnaInvoices($mo, $klarnainvoices)
343
+ {
344
+ $mo->getPayment()->setAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_INVOICE, $klarnainvoices);
345
+ return $mo;
346
+ }
347
  }
app/code/community/Avenla/KlarnaCheckout/Model/Api.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -19,492 +19,429 @@
19
  * @package Avenla_KlarnaCheckout
20
  */
21
 
22
- require_once(Mage::getBaseDir('lib') . '/Klarna/Klarna.php');
23
- require_once(Mage::getBaseDir('lib') . '/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc');
24
- require_once(Mage::getBaseDir('lib') . '/Klarna/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc');
25
 
26
  class Avenla_KlarnaCheckout_Model_Api extends Mage_Core_Model_Abstract
27
  {
28
- protected $klarna;
29
- private $helper;
30
-
31
- public function __construct()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  {
33
- $this->helper = Mage::helper('klarnaCheckout/api');
34
- $this->klarna = new Klarna();
35
-
36
- $locale = $this->klarna->getLocale($this->helper->getCountry());
37
- $config = Mage::getSingleton('klarnaCheckout/KCO')->getConfig();
38
-
39
- try{
40
- $this->klarna->config(
41
- $config->getKlarnaEid(),
42
- $config->getKlarnaSharedSecret(),
43
- $locale['country'],
44
- $locale['language'],
45
- $locale['currency'],
46
- $config->isLive() ? Klarna::LIVE : Klarna::BETA,
47
- 'json',
48
- Mage::getBaseDir('lib').'/Klarna/pclasses/'.$config->getKlarnaEid().'_pclass_'.$locale['country'].'.json',
49
- true,
50
- true
51
- );
52
- }
53
- catch (Exception $e) {
54
- Mage::logException($e);
55
- }
 
 
 
 
 
 
 
 
 
 
56
  }
57
-
58
  /**
59
- * Activate Klarna reservation
60
- *
61
- * @param Magento_Sales_Order
62
- * @param string $invoiceId|null
63
- * @return bool
64
- */
65
- public function activateReservation($mo, $invoiceId = null)
66
- {
67
- Mage::register('kco_save', true);
68
-
69
- if($invoiceId != null){
70
- $result = $this->activateFromInvoice($mo, Mage::getModel('sales/order_invoice')->load($invoiceId));
71
- }
72
- else if(false !== $qtys = $this->checkIfPartial($mo)){
73
- $result = $this->activatePartialReservation($mo, $qtys);
74
- }
75
- else{
76
- $result = $this->activateFullReservation($mo);
77
- }
78
- Mage::unregister('kco_save');
79
-
80
- return $result;
81
- }
82
-
83
- /**
84
- * Check if activation is partial or full
85
- *
86
- * @param Magento_Sales_Order $mo
87
- * @return array | false
88
- */
89
- private function checkIfPartial($mo)
90
- {
91
- $qtys = array();
92
- $partial = false;
93
-
94
- foreach($mo->getAllVisibleItems() as $item){
95
-
96
- if($item->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE){
97
- if($item->isChildrenCalculated()){
98
- foreach($item->getChildrenItems() as $child){
99
- $qtys[$child->getId()] = $child->getQtyShipped() - $child->getQtyInvoiced();
100
-
101
- if($child->getQtyOrdered() != $child->getQtyShipped())
102
- $partial = true;
103
- }
104
- }
105
- else{
106
- if($item->isDummy()){
107
- $bundleQtys = array();
108
- foreach($item->getChildrenItems() as $child){
109
- $parentCount = 0;
110
- $bundleCount = $child->getQtyOrdered() / $item->getQtyOrdered();
111
- $qtyInvoiced = $bundleCount * $item->getQtyInvoiced();
112
- $diff = $child->getQtyShipped() - $qtyInvoiced;
113
-
114
- if($diff >= $bundleCount)
115
- $parentCount = floor($bundleCount / $diff);
116
-
117
- $bundleQtys[] = $parentCount;
118
-
119
- if($child->getQtyOrdered() != $child->getQtyShipped())
120
- $partial = true;
121
- }
122
-
123
- $qtys[$item->getId()] = min($bundleQtys);
124
- }
125
- else{
126
- $qtys[$item->getId()] = $item->getQtyShipped() - $item->getQtyInvoiced();
127
-
128
- if($item->getQtyShipped() != $item->getQtyOrdered())
129
- $partial = true;
130
- }
131
- }
132
- }
133
- else{
134
- $qtys[$item->getId()] = $item->getQtyShipped() - $item->getQtyInvoiced();
135
-
136
- if($item->getQtyShipped() != $item->getQtyOrdered())
137
- $partial = true;
138
- }
139
- }
140
-
141
- if($partial)
142
- return $qtys;
143
-
144
- return false;
145
- }
146
-
147
- /**
148
- * Do partial activation
149
- *
150
- * @param Magento_Sales_Order $mo
151
- * @param array $qtys
152
- * @return bool
153
- */
154
- public function activatePartialReservation($mo, $qtys)
155
- {
156
- if(!Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->activatePartial())
157
- return false;
158
-
159
- foreach($qtys as $key => $qty){
160
- $sku = Mage::getModel('sales/order_item')->load($key)->getSku();
161
- $sku = iconv('UTF-8', 'ISO-8859-1', $sku);
162
- $this->klarna->addArtNo($qty, $sku);
163
- }
164
-
165
- $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
166
- if(empty($klarnainvoices)){
167
- $this->klarna->addArtNo(1, 'shipping_fee');
168
- }
169
-
170
- try{
171
- $rno = $this->helper->getReservationNumber($mo);
172
- $result = $this->klarna->activate($rno);
173
-
174
- $mo = $this->createMageInvoice($mo, $result, $qtys);
175
- $mo = $this->checkExpiration($mo);
176
- $mo->save();
177
-
178
- return true;
179
- }
180
- catch(Exception $e) {
181
- $this->helper->failedActivation($mo, $rno, $e);
182
- return false;
183
- }
184
- }
185
-
186
- /**
187
- * Do full activation
188
- *
189
- * @param Magento_Sales_Order $mo
190
- * @return bool
191
- */
192
- public function activateFullReservation($mo)
193
- {
194
- if($rno = $this->helper->getReservationNumber($mo)){
195
- try{
196
- $result = $this->klarna->activate($rno);
197
- $mo = $this->createMageInvoice($mo, $result);
198
- $mo = $this->checkExpiration($mo);
199
- $mo->save();
200
-
201
- return true;
202
- }
203
- catch(Exception $e) {
204
- $this->helper->failedActivation($mo, $rno, $e);
205
- return false;
206
- }
207
- }
208
- return false;
209
- }
210
-
211
- /**
212
- * Create invoice for Magento order
213
- *
214
- * @param Magento_Sales_Order $mo
215
- * @param array $result
216
- * @param array $qtys
217
- * @return Magento_Sales_Order
218
- */
219
- private function createMageInvoice($mo, $result, $qtys = null)
220
- {
221
- $invoice = Mage::getModel('sales/service_order', $mo)->prepareInvoice($qtys);
222
-
223
- if (!$invoice->getTotalQty())
224
- Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products'));
225
-
226
- if(Mage::registry('kco_transaction') != null)
227
- Mage::unregister('kco_transaction');
228
-
229
- Mage::register('kco_transaction', $result[1]);
230
- $amount = $invoice->getGrandTotal();
231
- $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
232
- $invoice->register();
233
-
234
- $mo->getPayment()->setTransactionId($result[1]);
235
-
236
- Mage::getModel('core/resource_transaction')
237
- ->addObject($invoice)
238
- ->addObject($invoice->getOrder())
239
- ->save();
240
-
241
- $invoice->save();
242
- $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
243
- $klarnainvoices[$invoice->getId()] = array(
244
- 'invoice' => $result[1],
245
- 'risk' => $result[0]
246
- );
247
-
248
- $mo->addStatusHistoryComment($this->helper->__('Created Klarna invoice %s', $result[1]));
249
- $mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
250
-
251
- return $mo;
252
- }
253
-
254
- /**
255
- * Check reservation expiration
256
- *
257
- * @param Magento_Sales_Order $mo
258
- * @return Magento_Sales_Order
259
- */
260
- private function checkExpiration($mo)
261
- {
262
- $expr = $mo->getPayment()->getAdditionalInformation("klarna_order_reservation_expiration");
263
- $expiration = new Zend_Date($expr);
264
-
265
- if($expiration < new Zend_Date()){
266
- $formattedExpiration = Mage::helper('core')->formatDate(
267
- $expr,'medium', false);
268
-
269
- $mo->getPayment()->setAdditionalInformation(
270
- 'klarna_message',
271
  'Reservation was activated after expiration (expired '.$formattedExpiration.')'
272
  );
273
- }
274
- return $mo;
275
- }
276
-
277
- /**
278
- * Activate reservation from Magento invoice
279
- *
280
- * @param Magento_Sales_Order $mo
281
- * @param Magento_Sales_Order_Invoice $invoice
282
- * @return bool
283
- */
284
- public function activateFromInvoice($mo, $invoice)
285
- {
286
- if($rno = $this->helper->getReservationNumber($mo)){
287
-
288
- if (abs($mo->getTotalDue() - $invoice->getGrandTotal()) > .0001){
289
- foreach($invoice->getAllItems() as $item){
290
- if(!$item->getOrderItem()->isDummy()){
291
- $this->klarna->addArtNo($item->getQty(), $item->getSku());
292
- }
293
- }
294
- if($invoice->getShippingAmount() > 0){
295
- $this->klarna->addArtNo(1, 'shipping_fee');
296
- }
297
- }
298
-
299
- try{
300
- $result = $this->klarna->activate($rno);
301
-
302
- if(Mage::registry('kco_invoicekey') != null)
303
- Mage::unregister('kco_invoicekey');
304
-
305
- Mage::register('kco_invoicekey', $result[1]);
306
-
307
- $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
308
- $klarnainvoices[$result[1]] = array(
309
- 'invoice' => $result[1],
310
- 'risk' => $result[0]
311
- );
312
-
313
- if(Mage::registry('kco_transaction') != null)
314
- Mage::unregister('kco_transaction');
315
-
316
- Mage::register('kco_transaction', $result[1]);
317
-
318
- $mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
319
- $mo = $this->checkExpiration($mo);
320
-
321
- $mo->save();
322
-
323
- return true;
324
- }
325
- catch(Exception $e) {
326
- $this->helper->failedActivation($mo, $rno, $e);
327
- return false;
328
- }
329
- }
330
- }
331
-
332
-
333
- /**
334
- * Credit Klarna invoice
335
- *
336
- * @param string $invoiceNo
337
- * @return bool
338
- */
339
- public function creditInvoice($invoiceNo)
340
- {
341
- try {
342
- $result = $this->klarna->creditInvoice($invoiceNo);
343
- return $this->emailInvoice($result);
344
- }
345
- catch(Exception $e) {
346
- Mage::logException($e);
347
- return false;
348
- }
349
- }
350
-
351
  /**
352
- * Credit Klarna invoice partially
353
- *
354
- * @param string $invoiceNo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  * @param array $products
356
- * @param float $adjustment |null
357
- * @param float $adjustmentTaxRate | null
358
- * @return bool
359
- */
360
- public function creditPart($invoiceNo, $products, $adjustment = null, $adjustmentTaxRate = null)
361
- {
362
- if($adjustment){
363
- $this->klarna->addArticle(
364
- 1,
365
- 'Adjustment',
366
- $this->helper->__('Adjustment fee'),
367
- $adjustment,
368
- $adjustmentTaxRate,
369
- 0,
370
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
371
- );
372
- }
373
-
374
- foreach($products as $key => $p){
375
- $this->klarna->addArtNo($p, $key);
376
- }
377
-
378
- try {
379
- $result = $this->klarna->creditPart($invoiceNo);
380
- return $this->emailInvoice($result);
381
- }
382
- catch(Exception $e) {
383
- Mage::logException($e);
384
- return false;
385
- }
386
- }
387
-
388
- /**
389
- * Return amount from Klarna invoice
390
- *
391
- * @param string $invoiceNo
392
- * @param float $amount
393
  * @param float $vat|0
394
- * @return bool
395
- */
396
- public function returnAmount($invoiceNo, $amount, $vat = 0)
397
- {
398
- try {
399
- $result = $this->klarna->returnAmount(
400
- $invoiceNo,
401
- $amount,
402
- $vat,
403
- KlarnaFlags::INC_VAT
404
- );
405
- return $this->emailInvoice($result);
406
- }
407
- catch(Exception $e) {
408
- Mage::logException($e);
409
- return false;
410
- }
411
- }
412
-
413
- /**
414
- * Cancel Klarna reservation
415
- *
416
- * @param string $rno
417
  * @param Mage_Sales_Model_Order $mo|null
418
- * @return bool
419
- */
420
- public function cancelReservation($rno, $mo = null)
421
- {
422
- try {
423
- $result = $this->klarna->cancelReservation($rno);
424
-
425
- if($mo){
426
- $mo->addStatusHistoryComment(
427
- $this->helper->__('Klarna reservation <b>%s</b> was canceled.', $rno)
428
- );
429
- }
430
- return true;
431
- }
432
- catch(Exception $e) {
433
- if($mo){
434
- $mo->addStatusHistoryComment(
435
- $this->helper->__('Failed to cancel Klarna reservation <b>%s</b>.(%s - %s)',
436
- $rno,
437
- $e->getMessage(),
438
- $e->getCode())
439
- );
440
- }
441
- Mage::logException($e);
442
- return false;
443
- }
444
- }
 
 
445
 
446
  /**
447
- * Send invoice e-mail
448
- *
449
- * @param string $invoiceNo
450
- * @return bool
451
- */
452
- public function emailInvoice($invoiceNo)
453
- {
454
- try {
455
- $result = $this->klarna->emailInvoice($invoiceNo);
456
- return true;
457
- } catch(Exception $e) {
458
- Mage::logException($e);
459
- return false;
460
- }
461
- }
462
-
463
- /**
464
- * Get cheapest monthly price
465
- *
466
- * @param float $price
467
- * @return string | bool
468
- */
469
- public function getMonthlyPrice($price)
470
- {
471
- if($pclass = $this->klarna->getCheapestPClass($price, KlarnaFlags::PRODUCT_PAGE)){
472
- $value = KlarnaCalc::calc_monthly_cost(
473
- $price,
474
- $pclass,
475
- KlarnaFlags::PRODUCT_PAGE
476
- );
477
-
478
- $country = $pclass->getCountry();
479
- $currency = KlarnaCurrency::getCode(KlarnaCountry::getCurrency($pclass->getCountry()));
480
-
481
- try{
482
- $currency = Mage::app()->getLocale()->currency(strtoupper($currency))->getSymbol();
483
- }
484
- catch(Exception $e){
485
- Mage::logException($e);
486
- }
487
-
488
- return $value . $currency;
489
- }
490
-
491
- return false;
492
- }
493
-
494
- /**
495
- * Update Klarna PClasses
496
- *
497
- * @return string
498
- */
499
- public function updatePClasses()
500
- {
501
- try {
502
- $this->klarna->fetchPClasses();
503
- return $this->helper->__('PClasses updated successfully');
504
- }
505
- catch(Exception $e) {
506
- Mage::logException($e);
507
- return $e->getMessage();
508
- }
509
- }
510
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
19
  * @package Avenla_KlarnaCheckout
20
  */
21
 
22
+ require_once(Mage::getBaseDir('lib') . '/KlarnaCheckout/autoload.php');
 
 
23
 
24
  class Avenla_KlarnaCheckout_Model_Api extends Mage_Core_Model_Abstract
25
  {
26
+ protected $klarna;
27
+ private $config;
28
+ private $helper;
29
+
30
+ public function __construct($payment = null)
31
+ {
32
+ $this->klarna = new Klarna();
33
+ $this->helper = Mage::helper('klarnaCheckout');
34
+
35
+ if($payment){
36
+ $this->config = $payment->getConfig();
37
+ }
38
+ else{
39
+ $this->config = Mage::getModel('klarnaCheckout/config');
40
+ }
41
+
42
+ $defaultCountry = $this->config->getDefaultCountry();
43
+ $locale = $this->klarna->getLocale($defaultCountry);
44
+
45
+ try{
46
+ $this->klarna->config(
47
+ $this->config->getKlarnaEid(),
48
+ $this->config->getKlarnaSharedSecret(),
49
+ $locale['country'],
50
+ $locale['language'],
51
+ $locale['currency'],
52
+ $this->config->isLive() ? Klarna::LIVE : Klarna::BETA,
53
+ 'json',
54
+ Mage::getBaseDir('lib').'/KlarnaCheckout/pclasses/'.$this->config->getKlarnaEid().'_pclass_'.$locale['country'].'.json',
55
+ true,
56
+ true
57
+ );
58
+ }
59
+ catch (Exception $e) {
60
+ $this->helper->logException($e);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Do partial activation
66
+ *
67
+ * @param Magento_Sales_Order $mo
68
+ * @param array $qtys
69
+ * @return bool
70
+ */
71
+ public function activatePartialReservation($mo, $qtys)
72
+ {
73
+ if(!$this->config->activatePartial())
74
+ return false;
75
+
76
+ foreach($qtys as $key => $qty){
77
+ $sku = Mage::getModel('sales/order_item')->load($key)->getSku();
78
+ $sku = iconv('UTF-8', 'ISO-8859-1', $sku);
79
+ $this->klarna->addArtNo($qty, $sku);
80
+ }
81
+
82
+ $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
83
+ if(empty($klarnainvoices) && $mo->getShippingAmount() > 0)
84
+ $this->klarna->addArtNo(1, 'shipping_fee');
85
+
86
+ try{
87
+ $rno = $this->helper->getReservationNumber($mo);
88
+ $result = $this->klarna->activate($rno);
89
+
90
+ $mo = $this->createMageInvoice($mo, $result, $qtys);
91
+ $mo = $this->checkExpiration($mo);
92
+ $mo->save();
93
+
94
+ return true;
95
+ }
96
+ catch(Exception $e) {
97
+ $this->helper->logException($e);
98
+ $mo->addStatusHistoryComment(
99
+ $this->helper->__('Failed to activate reservation %s', $rno) ."(" . $e->getMessage() . ")"
100
+ );
101
+ $mo->save();
102
+
103
+ return false;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Do full activation
109
+ *
110
+ * @param Magento_Sales_Order $mo
111
+ * @return bool
112
+ */
113
+ public function activateFullReservation($mo)
114
+ {
115
+ if($rno = $this->helper->getReservationNumber($mo)){
116
+ try{
117
+ $result = $this->klarna->activate($rno);
118
+ $mo = $this->createMageInvoice($mo, $result);
119
+ $mo = $this->checkExpiration($mo);
120
+ $mo->save();
121
+
122
+ return true;
123
+ }
124
+ catch(Exception $e) {
125
+ $this->helper->logException($e);
126
+ $mo->addStatusHistoryComment(
127
+ $this->helper->__('Failed to activate reservation %s', $rno) ."(" . $e->getMessage() . ")"
128
+ );
129
+ $mo->save();
130
+
131
+ return false;
132
+ }
133
+ }
134
+ return false;
135
+ }
136
+
137
+ /**
138
+ * Create invoice for Magento order
139
+ *
140
+ * @param Magento_Sales_Order $mo
141
+ * @param array $result
142
+ * @param array $qtys|null
143
+ * @return Magento_Sales_Order
144
+ */
145
+ private function createMageInvoice($mo, $result, $qtys = null)
146
  {
147
+ $invoice = Mage::getModel('sales/service_order', $mo)->prepareInvoice($qtys);
148
+
149
+ if (!$invoice->getTotalQty())
150
+ Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products'));
151
+
152
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION) != null)
153
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION);
154
+
155
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION, $result[1]);
156
+ $amount = $invoice->getBaseGrandTotal();
157
+ $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
158
+ $invoice->register();
159
+
160
+ $mo->getPayment()->setTransactionId($result[1]);
161
+
162
+ Mage::getModel('core/resource_transaction')
163
+ ->addObject($invoice)
164
+ ->addObject($invoice->getOrder())
165
+ ->save();
166
+
167
+ $invoice->save();
168
+
169
+ $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
170
+ $klarnainvoices[$invoice->getId()] = array(
171
+ 'invoice' => $result[1],
172
+ 'risk' => $result[0]
173
+ );
174
+
175
+
176
+ $mo->addStatusHistoryComment($this->helper->__('Created Klarna invoice %s', $result[1]));
177
+ $mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
178
+
179
+ return $mo;
180
  }
181
+
182
  /**
183
+ * Check reservation expiration
184
+ *
185
+ * @param Magento_Sales_Order $mo
186
+ * @return Magento_Sales_Order
187
+ */
188
+ private function checkExpiration($mo)
189
+ {
190
+ if(!$this->helper->isKcoOrder($mo))
191
+ return $mo;
192
+
193
+ $klarnaOrderId = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
194
+
195
+ $kco = $mo->getPayment()->getMethodInstance()->getOrderModel();
196
+ $kco->useConfigForStore($mo->getStore()->getId());
197
+ $info = $kco->getOrderInformation($klarnaOrderId);
198
+ $expr = $info->getExpiration();
199
+
200
+ if(new Zend_Date($expr) < new Zend_Date()){
201
+ $formattedExpiration = Mage::helper('core')->formatDate($expr,'medium', false);
202
+
203
+ $mo->getPayment()->setAdditionalInformation(
204
+ Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_MESSAGE,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  'Reservation was activated after expiration (expired '.$formattedExpiration.')'
206
  );
207
+ }
208
+ return $mo;
209
+ }
210
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  /**
212
+ * Activate reservation from Magento invoice
213
+ *
214
+ * @param Magento_Sales_Order $mo
215
+ * @param Magento_Sales_Order_Invoice $invoice
216
+ * @return bool
217
+ */
218
+ public function activateFromInvoice($mo, $invoice)
219
+ {
220
+ if($rno = $this->helper->getReservationNumber($mo)){
221
+ if (abs($mo->getTotalDue() - $invoice->getGrandTotal()) > .0001){
222
+ foreach($invoice->getAllItems() as $item){
223
+ if(!$item->getOrderItem()->isDummy())
224
+ $this->klarna->addArtNo($item->getQty(), $item->getSku());
225
+ }
226
+ if($invoice->getShippingAmount() > 0)
227
+ $this->klarna->addArtNo(1, 'shipping_fee');
228
+ }
229
+
230
+ try{
231
+ $result = $this->klarna->activate($rno);
232
+
233
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_INVOICE) != null)
234
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_INVOICE);
235
+
236
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_INVOICE, $result[1]);
237
+
238
+ $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
239
+ $klarnainvoices[$result[1]] = array(
240
+ 'invoice' => $result[1],
241
+ 'risk' => $result[0]
242
+ );
243
+
244
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION) != null)
245
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION);
246
+
247
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION, $result[1]);
248
+
249
+ $mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
250
+ $mo = $this->checkExpiration($mo);
251
+
252
+ $mo->save();
253
+
254
+ return true;
255
+ }
256
+ catch(Exception $e) {
257
+ $this->helper->logException($e);
258
+ $mo->addStatusHistoryComment(
259
+ $this->helper->__('Failed to activate reservation %s', $rno) ."(" . $e->getMessage() . ")"
260
+ );
261
+ $mo->save();
262
+
263
+ return false;
264
+ }
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Credit Klarna invoice
270
+ *
271
+ * @param string $invoiceNo
272
+ * @return bool
273
+ */
274
+ public function creditInvoice($invoiceNo)
275
+ {
276
+ try {
277
+ $result = $this->klarna->creditInvoice($invoiceNo);
278
+ return $this->emailInvoice($result);
279
+ }
280
+ catch(Exception $e) {
281
+ $this->helper->logException($e);
282
+ return false;
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Credit Klarna invoice partially
288
+ *
289
+ * @param string $invoiceNo
290
  * @param array $products
291
+ * @param float $adjustment |null
292
+ * @param float $adjustmentTaxRate | null
293
+ * @return bool
294
+ */
295
+ public function creditPart($invoiceNo, $products, $adjustment = null, $adjustmentTaxRate = null)
296
+ {
297
+ if($adjustment){
298
+ $this->klarna->addArticle(
299
+ 1,
300
+ 'Adjustment',
301
+ $this->helper->__('Adjustment fee'),
302
+ $adjustment,
303
+ $adjustmentTaxRate,
304
+ 0,
305
+ KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
306
+ );
307
+ }
308
+
309
+ foreach($products as $key => $p){
310
+ $this->klarna->addArtNo($p, $key);
311
+ }
312
+
313
+ try {
314
+ $result = $this->klarna->creditPart($invoiceNo);
315
+ return $this->emailInvoice($result);
316
+ }
317
+ catch(Exception $e) {
318
+ $this->logException($e);
319
+ return false;
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Return amount from Klarna invoice
325
+ *
326
+ * @param string $invoiceNo
327
+ * @param float $amount
328
  * @param float $vat|0
329
+ * @return bool
330
+ */
331
+ public function returnAmount($invoiceNo, $amount, $vat = 0)
332
+ {
333
+ try {
334
+ $result = $this->klarna->returnAmount(
335
+ $invoiceNo,
336
+ $amount,
337
+ $vat,
338
+ KlarnaFlags::INC_VAT
339
+ );
340
+ return $this->emailInvoice($result);
341
+ }
342
+ catch(Exception $e) {
343
+ $this->helper->logException($e);
344
+ return false;
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Cancel Klarna reservation
350
+ *
351
+ * @param string $rno
352
  * @param Mage_Sales_Model_Order $mo|null
353
+ * @return bool
354
+ */
355
+ public function cancelReservation($rno, $mo = null)
356
+ {
357
+ try {
358
+ $result = $this->klarna->cancelReservation($rno);
359
+
360
+ if($mo){
361
+ $mo->addStatusHistoryComment(
362
+ $this->helper->__('Klarna reservation <b>%s</b> was canceled.', $rno)
363
+ );
364
+ }
365
+ return true;
366
+ }
367
+ catch(Exception $e){
368
+ $this->helper->logException($e);
369
+ if($mo){
370
+ $mo->addStatusHistoryComment(
371
+ $this->helper->__('Failed to cancel Klarna reservation <b>%s</b>.(%s - %s)',
372
+ $rno,
373
+ $e->getMessage(),
374
+ $e->getCode()
375
+ )
376
+ );
377
+ }
378
+
379
+ return false;
380
+ }
381
+ }
382
 
383
  /**
384
+ * Send invoice e-mail
385
+ *
386
+ * @param string $invoiceNo
387
+ * @return bool
388
+ */
389
+ public function emailInvoice($invoiceNo)
390
+ {
391
+ try {
392
+ $result = $this->klarna->emailInvoice($invoiceNo);
393
+ return true;
394
+ } catch(Exception $e) {
395
+ $this->helper->logException($e);
396
+ return false;
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Get cheapest monthly price
402
+ *
403
+ * @param float $price
404
+ * @return string | bool
405
+ */
406
+ public function getMonthlyPrice($price)
407
+ {
408
+ if($pclass = $this->klarna->getCheapestPClass($price, KlarnaFlags::PRODUCT_PAGE)){
409
+ $value = KlarnaCalc::calc_monthly_cost(
410
+ $price,
411
+ $pclass,
412
+ KlarnaFlags::PRODUCT_PAGE
413
+ );
414
+
415
+ $country = $pclass->getCountry();
416
+ $currency = KlarnaCurrency::getCode(KlarnaCountry::getCurrency($pclass->getCountry()));
417
+
418
+ try{
419
+ $currency = Mage::app()->getLocale()->currency(strtoupper($currency))->getSymbol();
420
+ }
421
+ catch(Exception $e){
422
+ $this->helper->logException($e);
423
+ }
424
+
425
+ return $value . $currency;
426
+ }
427
+
428
+ return false;
429
+ }
430
+
431
+ /**
432
+ * Update Klarna PClasses
433
+ *
434
+ * @return string
435
+ */
436
+ public function updatePClasses()
437
+ {
438
+ try {
439
+ $this->klarna->fetchPClasses();
440
+ return $this->helper->__('PClasses updated successfully');
441
+ }
442
+ catch(Exception $e) {
443
+ $this->helper->logException($e);
444
+ return $e->getMessage();
445
+ }
446
+ }
447
  }
app/code/community/Avenla/KlarnaCheckout/Model/Config.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,330 +20,379 @@
20
  */
21
  class Avenla_KlarnaCheckout_Model_Config extends Varien_Object
22
  {
23
- const KCO_LIVE_URL = 'https://checkout.klarna.com';
24
- const KCO_DEMO_URL = 'https://checkout.testdrive.klarna.com';
25
- const KCO_LIVE_S_URL = 'https://online.klarna.com';
26
- const KCO_DEMO_S_URL = 'https://testdrive.klarna.com';
27
  const KLARNA_DOC_URL = 'http://developers.klarna.com/';
28
  const ONLINE_GUI_URL = 'https://merchants.klarna.com';
29
- const LICENSE_URL = 'http://productdownloads.avenla.com/magento-modules/klarna-checkout/license';
30
- const ANALYTICS_UNIVERSAL = 'universal';
31
- const ANALYTICS_CLASSIC = 'analytics';
32
- const DOCUMENTATION_URL = 'http://productdownloads.avenla.com/magento-modules/klarna-checkout#documentation';
33
-
34
- /**
35
- * Return config var
36
- *
37
- * @param string $key
38
- * @param string $default value for non-existing key
39
- * @return mixed
40
- */
41
- public function getConfigData($key, $default=false)
42
- {
43
- $store = Mage::app()->getStore();
44
-
45
- if(Mage::app()->getStore()->getId() == 0)
46
- $store = Mage::app()->getRequest()->getParam('store', 0);
47
-
48
- if (!$this->hasData($key)) {
49
- $value = Mage::getStoreConfig('payment/klarnaCheckout_payment/'.$key, $store);
50
- if (is_null($value) || false===$value) {
51
- $value = $default;
52
- }
53
- $this->setData($key, $value);
54
- }
55
- return $this->getData($key);
56
- }
57
-
58
- /**
59
- * Get Klarna merchant eid
60
- *
61
- * @return string
62
- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  public function getKlarnaEid()
64
  {
65
- return $this->getConfigData('merchantid');
66
  }
67
-
68
- /**
69
- * Get Klarna merchant shared secret
70
- *
71
- * @return string
72
- */
73
  public function getKlarnaSharedSecret()
74
  {
75
- return Mage::helper('core')->decrypt($this->getConfigData('sharedsecret'));
76
  }
77
-
78
  /**
79
- * Get terms url
80
- *
81
- * @return string
82
- */
83
  public function getTermsUri()
84
  {
85
- return Mage::getUrl($this->getConfigData('terms_url'));
86
- }
87
-
88
- /**
89
- * Get Klarna Checkout mode (LIVE OR BETA)
90
- *
91
- * @return bool
92
- */
93
- public function isLive()
94
- {
95
- if($this->getConfigData('server') == "LIVE")
96
- return true;
97
-
98
- return false;
99
- }
100
-
101
- /**
102
- * Get module status
103
- *
104
- * @return bool
105
- */
106
- public function isActive()
107
- {
108
- return $this->getConfigData('active');
109
- }
110
-
111
- /**
112
- * Get partial shipment activation mode
113
- *
114
- * @return bool
115
- */
116
- public function activatePartial()
117
- {
118
- return $this->getConfigData('activate_partial');
119
- }
120
-
121
- /**
122
- * Get Google Analytics number or false if not found
123
- *
124
- * @return mixed
125
- */
126
- public function getGoogleAnalyticsNo()
127
- {
128
- $ga = $this->getConfigData('google_analytics');
129
- if(strlen($ga) < 1)
130
- return false;
131
-
132
- return $this->getConfigData('google_analytics');
133
- }
134
-
135
- /**
136
- * Get Google Analytics account type
137
- *
138
- * @return string
139
- */
140
- public function getGoogleAnalyticsType()
141
- {
142
- return $this->getConfigData('google_analytics_type');
143
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
 
 
145
  /**
146
- * Get method title
147
- *
148
- * @return string
149
- */
150
- public function getTitle()
151
- {
152
- if(strlen($this->getConfigData('title')) > 0)
153
- return $this->getConfigData('title');
154
-
155
- return "Klarna Checkout";
156
- }
157
-
158
- /**
159
- * Get link text
160
- *
161
- * @return string
162
- */
163
- public function getLinkText()
164
- {
165
- if(strlen($this->getConfigData('linktext')) > 0)
166
- return $this->getConfigData('linktext');
167
-
168
- return "Go to Klarna Checkout";
169
- }
170
  /**
171
- * Get tax rate for credit memo adjustment
172
- *
173
- * @return float
174
- */
175
- public function getReturnTaxRate()
176
- {
177
- $taxClass = $this->getConfigData('return_tax');
178
-
179
- $taxClasses = Mage::helper("core")->jsonDecode(Mage::helper("tax")->getAllRatesByProductClass());
180
- if(isset($taxClasses["value_".$taxClass]))
181
- return $taxClasses["value_".$taxClass];
182
-
183
- return 0;
184
- }
185
-
186
- /**
187
- * Get license agreement status
188
- *
189
- * @return bool
190
- */
191
- public function getLicenseAgreement()
192
- {
193
- return $this->getConfigData('license');
194
- }
195
-
196
- /**
197
- * Get allowed shipping methods
198
- *
199
- * @return array
200
- */
201
- public function getDisallowedShippingMethods()
202
- {
203
- $methods = array();
204
- if($this->getConfigData('disabled_shipping_methods'))
205
- $methods = explode(",", $this->getConfigData('disabled_shipping_methods'));
206
-
207
- return $methods;
208
- }
209
-
210
- /**
211
- * Check if Part payment is enabled
212
- *
213
- * @return bool
214
- */
215
- public function getPpWidgetSelection()
216
- {
217
- return $this->getConfigData('pp_widget');
218
- }
219
-
220
- /**
221
- * Get part payment widget layout
222
- *
223
- * @return string
224
- */
225
- public function getPpWidgetLayout()
226
- {
227
- return $this->getConfigData('pp_layout');
228
- }
229
-
230
- /**
231
- * Get config for default Checkout
232
- *
233
- * @return bool
234
- */
235
- public function hideDefaultCheckout()
236
- {
237
- return $this->getConfigData('default_checkout');
238
- }
239
-
240
- /**
241
- * Get layout selection for KCO cart
242
- *
243
- * @return string
244
- */
245
- public function getKcoLayout()
246
- {
247
- return $this->getConfigData('kco_layout');
248
- }
249
-
250
- /**
251
- * Show sign for newsletter checkbox
252
- *
253
- * @return bool
254
- */
255
- public function showNewsletter()
256
- {
257
- return $this->getConfigData('show_newsletter');
258
- }
259
-
260
- /**
261
- * Show gift message form on cart page
262
- *
263
- * @return bool
264
- */
265
- public function showGiftMessage()
266
- {
267
- return $this->getConfigData('show_giftmessage');
268
- }
269
-
270
- /**
271
- * Debug logging
272
- *
273
- * @return bool
274
- */
275
- public function debuglog()
276
- {
277
- return $this->getConfigData('debug_log');
278
- }
279
-
280
- /**
281
- * Use custom colors in KCO
282
- *
283
- * @return bool
284
- */
285
- public function useCustomColors()
286
- {
287
- return $this->getConfigData('custom_colors');
288
- }
289
-
290
- /**
291
- * Get button color
292
- *
293
- * @return string
294
- */
295
- public function getButtonColor()
296
- {
297
- return $this->getConfigData('color_button');
298
- }
299
-
300
- /**
301
- * Get button text color
302
- *
303
- * @return string
304
- */
305
- public function getButtonTextColor()
306
- {
307
- return $this->getConfigData('color_button_text');
308
- }
309
-
310
- /**
311
- * Get checkbox color
312
- *
313
- * @return string
314
- */
315
- public function getCheckboxColor()
316
- {
317
- return $this->getConfigData('color_checkbox');
318
- }
319
-
320
- /**
321
- * Get checkbox checkmark color
322
- *
323
- * @return string
324
- */
325
- public function getCheckboxCheckmarkColor()
326
- {
327
- return $this->getConfigData('color_checkbox_checkmark');
328
- }
329
-
330
- /**
331
- * Get header color
332
- *
333
- * @return string
334
- */
335
- public function getHeaderColor()
336
- {
337
- return $this->getConfigData('color_header');
338
- }
339
-
340
- /**
341
- * Get link color
342
- *
343
- * @return string
344
- */
345
- public function getLinkColor()
346
- {
347
- return $this->getConfigData('color_link');
348
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  class Avenla_KlarnaCheckout_Model_Config extends Varien_Object
22
  {
 
 
 
 
23
  const KLARNA_DOC_URL = 'http://developers.klarna.com/';
24
  const ONLINE_GUI_URL = 'https://merchants.klarna.com';
25
+
26
+ const ANALYTICS_UNIVERSAL = 'universal';
27
+ const ANALYTICS_CLASSIC = 'analytics';
28
+ const LICENSE_URL = 'http://productdownloads.avenla.com/magento-modules/klarna-checkout/license';
29
+ const DOCUMENTATION_URL = 'http://productdownloads.avenla.com/magento-modules/klarna-checkout#documentation';
30
+
31
+ const API_TYPE_KCOV2 = 2;
32
+ const API_TYPE_KCOV3_UK = 3;
33
+ const API_TYPE_KCOV3_US = 4;
34
+
35
+ const KLARNA_WIDGET_SCRIPT = "https://cdn.klarna.com/1.0/code/client/all.js";
36
+ const WIDGET_TYPE_KLARNA = 'klarna';
37
+ const WIDGET_TYPE_PRODUCT = 'product';
38
+ const WIDGET_TYPE_LIST = 'product_list';
39
+
40
+ private $store = null;
41
+
42
+ public function setStore($storeId)
43
+ {
44
+ $this->store = $storeId;
45
+ }
46
+
47
+ public function getStore()
48
+ {
49
+ if($this->store != null)
50
+ return $this->store;
51
+
52
+ if(Mage::app()->getStore()->getId() == 0)
53
+ return Mage::app()->getRequest()->getParam('store', 0);
54
+
55
+ return $this->store;
56
+ }
57
+
58
+ /**
59
+ * Return config var
60
+ *
61
+ * @param string $key
62
+ * @param string $default value for non-existing key
63
+ * @return mixed
64
+ */
65
+ public function getConfigData($key, $default = false)
66
+ {
67
+ if (!$this->hasData($key) || $this->store != null){
68
+ $value = Mage::getStoreConfig('payment/klarnaCheckout_payment/'.$key, $this->getStore());
69
+ if (is_null($value) || false === $value) {
70
+ $value = $default;
71
+ }
72
+ $this->setData($key, $value);
73
+ }
74
+ return $this->getData($key);
75
+ }
76
+
77
+ /**
78
+ * Get Klarna merchant eid
79
+ *
80
+ * @return string
81
+ */
82
  public function getKlarnaEid()
83
  {
84
+ return $this->getConfigData('merchantid');
85
  }
86
+
87
+ /**
88
+ * Get Klarna merchant shared secret
89
+ *
90
+ * @return string
91
+ */
92
  public function getKlarnaSharedSecret()
93
  {
94
+ return Mage::helper('core')->decrypt($this->getConfigData('sharedsecret'));
95
  }
96
+
97
  /**
98
+ * Get terms url
99
+ *
100
+ * @return string
101
+ */
102
  public function getTermsUri()
103
  {
104
+ return Mage::getUrl($this->getConfigData('terms_url'));
105
+ }
106
+
107
+ /**
108
+ * Get Klarna Checkout mode (LIVE OR BETA)
109
+ *
110
+ * @return bool
111
+ */
112
+ public function isLive()
113
+ {
114
+ if($this->getConfigData('server') == "LIVE")
115
+ return true;
116
+
117
+ return false;
118
+ }
119
+
120
+ /**
121
+ * Get module status
122
+ *
123
+ * @return bool
124
+ */
125
+ public function isActive()
126
+ {
127
+ return $this->getConfigData('active');
128
+ }
129
+
130
+ /**
131
+ * Get partial shipment activation mode
132
+ *
133
+ * @return bool
134
+ */
135
+ public function activatePartial()
136
+ {
137
+ return $this->getConfigData('activate_partial');
138
+ }
139
+
140
+ /**
141
+ * Get Google Analytics number or false if not found
142
+ *
143
+ * @return mixed
144
+ */
145
+ public function getGoogleAnalyticsNo()
146
+ {
147
+ $ga = $this->getConfigData('google_analytics');
148
+ if(strlen($ga) < 1)
149
+ return false;
150
+
151
+ return $this->getConfigData('google_analytics');
152
+ }
153
+
154
+ /**
155
+ * Get Google Analytics account type
156
+ *
157
+ * @return string
158
+ */
159
+ public function getGoogleAnalyticsType()
160
+ {
161
+ return $this->getConfigData('google_analytics_type');
162
+ }
163
+
164
+ /**
165
+ * Get method title
166
+ *
167
+ * @return string
168
+ */
169
+ public function getTitle()
170
+ {
171
+ if(strlen($this->getConfigData('title')) > 0)
172
+ return $this->getConfigData('title');
173
+
174
+ return "Klarna Checkout";
175
+ }
176
+
177
+ /**
178
+ * Get link text
179
+ *
180
+ * @return string
181
+ */
182
+ public function getLinkText()
183
+ {
184
+ if(strlen($this->getConfigData('linktext')) > 0)
185
+ return $this->getConfigData('linktext');
186
 
187
+ return "Go to Klarna Checkout";
188
+ }
189
  /**
190
+ * Get tax rate for credit memo adjustment
191
+ *
192
+ * @return float
193
+ */
194
+ public function getReturnTaxRate()
195
+ {
196
+ $taxClass = $this->getConfigData('return_tax');
197
+
198
+ $taxClasses = Mage::helper("core")->jsonDecode(Mage::helper("tax")->getAllRatesByProductClass());
199
+ if(isset($taxClasses["value_".$taxClass]))
200
+ return $taxClasses["value_".$taxClass];
201
+
202
+ return 0;
203
+ }
204
+
 
 
 
 
 
 
 
 
 
205
  /**
206
+ * Get license agreement status
207
+ *
208
+ * @return bool
209
+ */
210
+ public function getLicenseAgreement()
211
+ {
212
+ return $this->getConfigData('license');
213
+ }
214
+
215
+ /**
216
+ * Get allowed shipping methods
217
+ *
218
+ * @return array
219
+ */
220
+ public function getDisallowedShippingMethods()
221
+ {
222
+ $methods = array();
223
+ if($this->getConfigData('disabled_shipping_methods'))
224
+ $methods = explode(",", $this->getConfigData('disabled_shipping_methods'));
225
+
226
+ return $methods;
227
+ }
228
+
229
+ /**
230
+ * Check if Part payment is enabled
231
+ *
232
+ * @return bool
233
+ */
234
+ public function getPpWidgetSelection()
235
+ {
236
+ return $this->getConfigData('pp_widget');
237
+ }
238
+
239
+ /**
240
+ * Get part payment widget layout
241
+ *
242
+ * @return string
243
+ */
244
+ public function getPpWidgetLayout()
245
+ {
246
+ return $this->getConfigData('pp_layout');
247
+ }
248
+
249
+ /**
250
+ * Get config for default Checkout
251
+ *
252
+ * @return bool
253
+ */
254
+ public function hideDefaultCheckout()
255
+ {
256
+ return $this->getConfigData('default_checkout');
257
+ }
258
+
259
+ /**
260
+ * Get layout selection for KCO cart
261
+ *
262
+ * @return string
263
+ */
264
+ public function getKcoLayout()
265
+ {
266
+ return $this->getConfigData('kco_layout');
267
+ }
268
+
269
+ /**
270
+ * Show sign for newsletter checkbox
271
+ *
272
+ * @return bool
273
+ */
274
+ public function showNewsletter()
275
+ {
276
+ return $this->getConfigData('show_newsletter');
277
+ }
278
+
279
+ /**
280
+ * Show gift message form on cart page
281
+ *
282
+ * @return bool
283
+ */
284
+ public function showGiftMessage()
285
+ {
286
+ return $this->getConfigData('show_giftmessage');
287
+ }
288
+
289
+ /**
290
+ * Debug logging
291
+ *
292
+ * @return bool
293
+ */
294
+ public function debuglog()
295
+ {
296
+ return $this->getConfigData('debug_log');
297
+ }
298
+
299
+ /**
300
+ * Use custom colors in KCO
301
+ *
302
+ * @return bool
303
+ */
304
+ public function useCustomColors()
305
+ {
306
+ return $this->getConfigData('custom_colors');
307
+ }
308
+
309
+ /**
310
+ * Get button color
311
+ *
312
+ * @return string
313
+ */
314
+ public function getButtonColor()
315
+ {
316
+ return $this->getConfigData('color_button');
317
+ }
318
+
319
+ /**
320
+ * Get button text color
321
+ *
322
+ * @return string
323
+ */
324
+ public function getButtonTextColor()
325
+ {
326
+ return $this->getConfigData('color_button_text');
327
+ }
328
+
329
+ /**
330
+ * Get checkbox color
331
+ *
332
+ * @return string
333
+ */
334
+ public function getCheckboxColor()
335
+ {
336
+ return $this->getConfigData('color_checkbox');
337
+ }
338
+
339
+ /**
340
+ * Get checkbox checkmark color
341
+ *
342
+ * @return string
343
+ */
344
+ public function getCheckboxCheckmarkColor()
345
+ {
346
+ return $this->getConfigData('color_checkbox_checkmark');
347
+ }
348
+
349
+ /**
350
+ * Get header color
351
+ *
352
+ * @return string
353
+ */
354
+ public function getHeaderColor()
355
+ {
356
+ return $this->getConfigData('color_header');
357
+ }
358
+
359
+ /**
360
+ * Get link color
361
+ *
362
+ * @return string
363
+ */
364
+ public function getLinkColor()
365
+ {
366
+ return $this->getConfigData('color_link');
367
+ }
368
+
369
+ /**
370
+ * Get API version
371
+ *
372
+ * @return int
373
+ */
374
+ public function getApiVersion()
375
+ {
376
+ return $this->getConfigData('api');
377
+ }
378
+
379
+ /**
380
+ * Allow separate shipping address
381
+ *
382
+ * @return bool
383
+ */
384
+ public function allowSeparateShippingAddress()
385
+ {
386
+ return (bool)$this->getConfigData('allow_separate_shipping');
387
+ }
388
+
389
+ /**
390
+ * Get default country from store config
391
+ *
392
+ * @return string
393
+ */
394
+ public function getDefaultCountry()
395
+ {
396
+ return Mage::getStoreConfig('general/country/default', $this->getStore());
397
+ }
398
  }
app/code/community/Avenla/KlarnaCheckout/Model/KCO.php DELETED
@@ -1,239 +0,0 @@
1
- <?php
2
- /**
3
- * This file is released under a custom license by Avenla Oy.
4
- * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
- * For questions and support - klarna-support@avenla.com
8
- *
9
- * @category Avenla
10
- * @package Avenla_KlarnaCheckout
11
- * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
- */
14
-
15
- /**
16
- * Avenla KlarnaCheckout
17
- *
18
- * @category Avenla
19
- * @package Avenla_KlarnaCheckout
20
- */
21
-
22
- class Avenla_KlarnaCheckout_Model_KCO extends Mage_Payment_Model_Method_Abstract
23
- {
24
- protected $_code = 'klarnaCheckout_payment';
25
- protected $_formBlockType = 'klarnaCheckout/KCO_form';
26
- protected $_infoBlockType = 'klarnaCheckout/KCO_info';
27
-
28
- protected $_isGateway = true;
29
- protected $_canAuthorize = true;
30
- protected $_canCapture = true;
31
- protected $_canCapturePartial = true;
32
- protected $_canRefund = true;
33
- protected $_canRefundInvoicePartial = true;
34
- protected $_canVoid = false;
35
- protected $_canUseInternal = false;
36
- protected $_canUseCheckout = false;
37
- protected $_canUseForMultishipping = false;
38
- protected $_order = null;
39
-
40
- /**
41
- * Get Config model
42
- *
43
- * @return object Avenla_KlarnaCheckout_Model_Config
44
- */
45
- public function getConfig()
46
- {
47
- return Mage::getSingleton('klarnaCheckout/config');
48
- }
49
-
50
- /**
51
- * Check if Klarna Checkout is available
52
- *
53
- * @param Mage_Sales_Model_Quote|null $quote
54
- * @return bool
55
- */
56
- public function isAvailable($quote = null)
57
- {
58
- if($quote == null)
59
- $quote = Mage::getSingleton('checkout/session')->getQuote();
60
-
61
- if(in_array($quote->getShippingAddress()->getShippingMethod(), $this->getConfig()->getDisallowedShippingMethods()))
62
- return false;
63
-
64
- $result = parent::isAvailable($quote) &&
65
- (Mage::getSingleton('customer/session')->isLoggedIn() || Mage::helper('checkout')->isAllowedGuestCheckout($quote)) &&
66
- count($quote->getAllVisibleItems()) >= 1 && $this->getConfig()->getLicenseAgreement();
67
-
68
- if($result)
69
- $result = Mage::helper('klarnaCheckout')->getConnectionStatus($quote);
70
-
71
- return $result;
72
- }
73
-
74
- /**
75
- * Capture payment
76
- *
77
- * @param Varien_Object $payment
78
- * @param float $amount
79
- * @return Avenla_KlarnaCheckout_Model_KCO
80
- */
81
- public function capture(Varien_Object $payment, $amount)
82
- {
83
- $order = $payment->getOrder();
84
- $currentId = Mage::app()->getStore()->getStoreId();
85
- Mage::app()->setCurrentStore($order->getStore()->getStoreId());
86
-
87
- if(Mage::registry('kco_transaction') == null){
88
- foreach ($order->getInvoiceCollection() as $invoice) {
89
- if($invoice->getId() == null){
90
- $inv = $invoice;
91
- }
92
- }
93
- if(isset($inv))
94
- Mage::getModel('klarnaCheckout/api')->activateFromInvoice($order, $inv);
95
- }
96
-
97
- if($id = Mage::registry('kco_transaction')){
98
- $payment->setTransactionId($id);
99
- $payment->setIsTransactionClosed(1);
100
- Mage::unregister('kco_transaction');
101
- }
102
-
103
- Mage::app()->setCurrentStore($currentId);
104
- return $this;
105
- }
106
-
107
- /**
108
- * Register KCO save before redund
109
- *
110
- * @param $invoice
111
- * @param Varien_Object $payment
112
- * @return Avenla_KlarnaCheckout_Model_KCO
113
- */
114
- public function processBeforeRefund($invoice, $payment)
115
- {
116
- Mage::register('kco_save', true);
117
- return $this;
118
- }
119
-
120
- /**
121
- * Unregister KCO save after redund
122
- *
123
- * @param $creditmemo
124
- * @param Varien_Object $payment
125
- * @return Avenla_KlarnaCheckout_Model_KCO
126
- */
127
- public function processCreditmemo($creditmemo, $payment)
128
- {
129
- Mage::unregister('kco_save');
130
- return $this;
131
- }
132
-
133
- /**
134
- * Refund specified amount from invoice
135
- *
136
- * @param Varien_Object $payment
137
- * @param float $amount
138
- * @return Avenla_KlarnaCheckout_Model_KCO
139
- */
140
- public function refund(Varien_Object $payment, $amount)
141
- {
142
- $order = $payment->getOrder();
143
-
144
- $currentId = Mage::app()->getStore()->getStoreId();
145
- Mage::app()->setCurrentStore($order->getStore()->getStoreId());
146
- $api = Mage::getModel('klarnaCheckout/api');
147
- $rno = Mage::helper('klarnaCheckout/api')->getReservationNumber($order);
148
-
149
- if($rno === false)
150
- return $this;
151
-
152
- $creditmemo = $payment->getCreditmemo();
153
- $invoice = $creditmemo->getInvoice();
154
- $klarna_invoice = $invoice->getTransactionId();
155
-
156
- $products = array();
157
- $result = array();
158
- $total_refund = false;
159
-
160
- if (abs($invoice->getGrandTotal() - $creditmemo->getGrandTotal()) < .0001)
161
- $total_refund = true;
162
-
163
- foreach ($creditmemo->getAllItems() as $item)
164
- {
165
- $invoiceItem = Mage::getResourceModel('sales/order_invoice_item_collection')
166
- ->addAttributeToSelect('*')
167
- ->setInvoiceFilter($invoice->getId())
168
- ->addFieldToFilter('order_item_id', $item->getOrderItemId())
169
- ->getFirstItem();
170
-
171
- $diff = $item->getQty() - $invoiceItem->getQty();
172
-
173
- if($diff > 0)
174
- $total_refund = false;
175
-
176
- if($item->getQty() > 0 && !$item->getOrderItem()->isDummy())
177
- $products[$item->getSku()] = $item->getQty();
178
- }
179
-
180
- if($total_refund){
181
- $result[] = $api->creditInvoice($klarna_invoice)
182
- ? "Refunded Klarna invoice " . $klarna_invoice
183
- : "Failed to refund Klarna invoice " . $klarna_invoice;
184
- }
185
- else{
186
- $fee = null;
187
- if($creditmemo->getAdjustment() < 0)
188
- $fee = abs($creditmemo->getAdjustment());
189
-
190
- if(!empty($products) || $creditmemo->getShippingAmount() > 0){
191
- if (abs($invoice->getShippingAmount() - $creditmemo->getShippingAmount()) < .0001)
192
- $products['shipping_fee'] = 1;
193
-
194
- if($fee != null){
195
- $response = $api->creditPart($klarna_invoice, $products, $fee, $this->getConfig()->getReturnTaxRate());
196
- }
197
- else{
198
- $response = $api->creditPart($klarna_invoice, $products);
199
- }
200
-
201
- if($response){
202
- $t = "Credited products: ";
203
- foreach($products as $key => $p){
204
- $t .= $key."(".$p.") ";
205
- }
206
- $result[] = $t;
207
- }
208
- else{
209
- $result[] = "Failed to do partial refund";
210
- }
211
-
212
- if($creditmemo->getShippingAmount() > 0 && !array_key_exists('shipping_fee', $products)){
213
- $result[] = $api->returnAmount($klarna_invoice, $creditmemo->getShippingAmount(), Mage::helper('klarnaCheckout')->getShippingVatRate())
214
- ? "Refunded amount of " . $creditmemo->getShippingAmount() . " from shipment on Klarna invoice " . $klarna_invoice
215
- : "Failed to refund amount of " . $creditmemo->getShippingAmount() . " from shipment on Klarna invoice " . $klarna_invoice;
216
-
217
- }
218
- }
219
-
220
- if($creditmemo->getAdjustment() > 0){
221
- $result[] = $api->returnAmount($klarna_invoice, $creditmemo->getAdjustment(), $this->getConfig()->getReturnTaxRate())
222
- ? "Refunded amount of " . $creditmemo->getAdjustment() . " on Klarna invoice " . $klarna_invoice
223
- : "Failed to refund amount of " . $creditmemo->getAdjustment() . " on Klarna invoice " . $klarna_invoice;
224
- }
225
- }
226
-
227
- if(!empty($result)) {
228
- foreach($result as $msg)
229
- {
230
- $order->addStatusHistoryComment($msg);
231
- }
232
- $order->save();
233
- }
234
-
235
- Mage::app()->setCurrentStore($currentId);
236
-
237
- return $this;
238
- }
239
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Avenla/KlarnaCheckout/Model/Newsletter.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,46 +20,45 @@
20
  */
21
 
22
  class Avenla_KlarnaCheckout_Model_Newsletter extends Mage_Core_Model_Abstract
23
- {
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- /**
26
- * Save newsletter selection to additional data
27
- *
28
- * @param bool $status
29
- */
30
- public function addNewsletterStatus($status)
31
- {
32
- $customerSession = Mage::getSingleton('customer/session');
33
- $quote = Mage::getSingleton('checkout/session')->getQuote();
34
- $quote->getPayment()->setAdditionalInformation("klarna_newsletter", $status);
35
- $quote->save();
36
- }
37
 
38
- /**
39
- * Subscribe order e-mail for newsletter
40
- *
41
- * @param Mage_Sales_Model_Order $mo
42
- * @param int $websiteId
43
- */
44
- public function signForNewsLetter($mo, $websiteId)
45
- {
46
- $email = $mo->getCustomerEmail();
47
- $subscriberId = Mage::getModel('newsletter/subscriber')->loadByEmail($email)->getId();
48
 
49
- if($subscriberId)
50
- return false;
51
-
52
- try{
53
- if($mo->getCustomerId() != NULL){
54
- $customer = Mage::getModel('customer/customer')->load($mo->getCustomerId());
55
- Mage::getModel('newsletter/subscriber')->subscribeCustomer($customer);
56
- }
57
- else{
58
- Mage::getModel('newsletter/subscriber')->subscribe($email);
59
- }
60
- }
61
- catch (Exception $e) {
62
- Mage::logException($e);
63
- }
64
- }
65
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
 
22
  class Avenla_KlarnaCheckout_Model_Newsletter extends Mage_Core_Model_Abstract
23
+ {
24
+
25
+ /**
26
+ * Save newsletter selection to additional data
27
+ *
28
+ * @param bool $status
29
+ */
30
+ public function addNewsletterStatus($status)
31
+ {
32
+ $quote = Mage::getSingleton('checkout/session')->getQuote();
33
+ $quote->getPayment()->setAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_NEWSLETTER, $status);
34
+ $quote->save();
35
+ }
36
 
37
+ /**
38
+ * Subscribe order e-mail for newsletter
39
+ *
40
+ * @param Mage_Sales_Model_Order $mo
41
+ * @param int $websiteId
42
+ */
43
+ public function signForNewsLetter($mo, $websiteId)
44
+ {
45
+ $email = $mo->getCustomerEmail();
46
+ $subscriberId = Mage::getModel('newsletter/subscriber')->loadByEmail($email)->getId();
 
 
47
 
48
+ if($subscriberId)
49
+ return false;
 
 
 
 
 
 
 
 
50
 
51
+ try{
52
+ if($mo->getCustomerId() != NULL){
53
+ $customer = Mage::getModel('customer/customer')->load($mo->getCustomerId());
54
+ Mage::getModel('newsletter/subscriber')->subscribeCustomer($customer);
55
+ }
56
+ else{
57
+ Mage::getModel('newsletter/subscriber')->subscribe($email);
58
+ }
59
+ }
60
+ catch (Exception $e) {
61
+ Mage::helper('KlarnaCheckout')->logException($e);
62
+ }
63
+ }
 
 
 
64
  }
app/code/community/Avenla/KlarnaCheckout/Model/Observer.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -21,162 +21,144 @@
21
 
22
  class Avenla_KlarnaCheckout_Model_Observer
23
  {
24
- private $api;
25
- private $helper;
26
- private $apiHelper;
27
-
28
- public function __construct()
29
- {
30
- $this->helper = Mage::helper('klarnaCheckout');
31
- $this->apiHelper = Mage::helper('klarnaCheckout/api');
32
- }
33
-
34
- /**
35
- * Process order after status change
36
- *
37
- * @param Varien_Event_Observer $observer
38
- */
39
- public function orderStatusChanged($observer)
40
  {
41
- if(Mage::registry('kco_save'))
42
- return $this;
43
-
44
- $order = $observer->getEvent()->getOrder();
45
- $rno = $this->apiHelper->getReservationNumber($order);
46
-
47
- if($rno === false)
48
- return $this;
49
-
50
- Mage::app()->setCurrentStore($order->getStore()->getStoreId());
51
- $this->api = Mage::getModel('klarnaCheckout/api');
52
-
53
- switch ($order->getState()) {
54
- case Mage_Sales_Model_Order::STATE_COMPLETE:
55
- if($order->canInvoice()){
56
- $this->api->activateReservation($order);
57
- }
58
- else{
59
- $this->api->cancelReservation($rno, $order);
60
- }
61
-
62
- break;
63
-
64
- case Mage_Sales_Model_Order::STATE_CANCELED:
65
- $this->api->cancelReservation($rno, $order);
66
-
67
- break;
68
-
69
- default:
70
- $mixed = false;
71
- foreach($order->getAllItems() as $item){
72
- if($item->getQtyShipped() > $item->getQtyInvoiced())
73
- $mixed = true;
74
- }
75
-
76
- if($mixed)
77
- $this->api->activateReservation($order);
78
- }
79
  }
80
 
81
  /**
82
- * Process invoice after save
83
- *
84
- * @param Varien_Event_Observer $observer
85
- */
86
- public function invoiceSaved($observer)
87
- {
88
- if(Mage::registry('kco_save'))
89
- return $this;
90
-
91
- if($kco_invoicekey = Mage::registry('kco_invoicekey')){
92
- $invoice = $observer->getEvent()->getInvoice();
93
- $order = $invoice->getOrder();
94
- $rno = $this->apiHelper->getReservationNumber($order);
95
-
96
- if($rno !== false){
97
- if(false !== $klarnainvoices = $this->apiHelper->getKlarnaInvoices($order)){
98
- if (!array_key_exists($invoice->getId(), $klarnainvoices)){
99
- $klarnainvoices[$invoice->getId()] = $klarnainvoices[$kco_invoicekey];
100
- unset($klarnainvoices[$kco_invoicekey]);
101
-
102
- $order = $this->apiHelper->saveKlarnaInvoices($order, $klarnainvoices);
103
- Mage::register('kco_save', true);
104
- $order->save();
105
- Mage::unregister('kco_save');
106
- }
107
- }
108
- }
109
- }
110
- }
111
-
112
  /**
113
- * Add Klarna link in default Checkout
114
- *
115
- * @param Varien_Event_Observer $observer
116
- */
117
- public function insertKlarnaLink($observer)
118
- {
119
- $block = $observer->getBlock();
120
- $isLogged = Mage::helper('customer')->isLoggedIn();
121
-
122
- if(!Mage::getModel('klarnaCheckout/config')->isActive())
123
- return $this;
124
-
125
- if (
126
- $block->getType() == 'checkout/onepage_login' ||
127
- ($isLogged && $block->getType() == 'checkout/onepage_billing') ||
128
- ($block->getType() == 'checkout/onepage_payment_methods' && $block->getBlockAlias() != 'methods') &&
129
- Mage::getSingleton('klarnaCheckout/KCO')->isAvailable()
130
- )
131
- {
132
- $child = clone $block;
133
- $child->setType('klarnaCheckout/KCO_Link');
134
- $block->setChild('original', $child);
135
- $block->setTemplate('KCO/link.phtml');
136
- }
137
- }
138
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  /**
140
- * Add activate reservation button to admin order view
141
- *
142
- * @param Varien_Event_Observer $observer
143
- */
144
- public function addActivate($observer)
145
- {
146
- $block = $observer->getEvent()->getBlock();
147
-
148
- if(get_class($block) =='Mage_Adminhtml_Block_Sales_Order_View'
149
- && $block->getRequest()->getControllerName() == 'sales_order')
150
- {
151
- $order = $block->getOrder();
152
-
153
- if($order->getPayment()->getAdditionalInformation("klarna_order_reference")){
154
- $block->addButton('activate_klarna_reservation', array(
155
- 'label' => Mage::helper('klarnaCheckout')->__('Activate Klarna reservation'),
156
- 'onclick' => 'setLocation(\'' . $block->getUrl('klarnaCheckout/KCO/activateReservation', array('order_id' => $order->getId())) . '\')',
157
- 'class' => 'save'
158
- ));
159
- }
160
- }
161
- }
162
-
163
- /**
164
- * Add new layout handle if needed
165
- *
166
- * @param Varien_Event_Observer $observer
167
- */
168
- public function layoutLoadBefore($observer)
169
- {
170
- if (Mage::getModel('klarnaCheckout/config')->hideDefaultCheckout()){
171
- $observer->getEvent()->getLayout()->getUpdate()
172
- ->addHandle('kco_only');
173
- }
174
-
175
- $kco_layout = Mage::getModel('klarnaCheckout/config')->getKcoLayout();
176
-
177
- if($observer->getAction()->getFullActionName() == "checkout_cart_index" && ($kco_layout && $kco_layout != "default")){
178
- $observer->getEvent()->getLayout()->getUpdate()
179
- ->addHandle($kco_layout);
180
- }
181
- }
182
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
21
 
22
  class Avenla_KlarnaCheckout_Model_Observer
23
  {
24
+ /**
25
+ * Process order after status change
26
+ *
27
+ * @param Varien_Event_Observer $observer
28
+ */
29
+ public function orderStatusChanged($observer)
 
 
 
 
 
 
 
 
 
 
30
  {
31
+ if(Mage::helper('klarnaCheckout')->isKcoSave())
32
+ return $this;
33
+
34
+ $order = $observer->getEvent()->getOrder();
35
+ $isKcoOrder = Mage::helper('klarnaCheckout')->isKcoOrder($order);
36
+
37
+ if(!$isKcoOrder)
38
+ return $this;
39
+
40
+ $kco = $order->getPayment()->getMethodInstance()->setStore($order->getStore());
41
+ switch ($order->getState()){
42
+ case Mage_Sales_Model_Order::STATE_COMPLETE:
43
+ if($order->canInvoice()){
44
+ $kco->activateReservation($order);
45
+ }
46
+ else{
47
+ $kco->cancelReservation($order);
48
+ }
49
+
50
+ break;
51
+ case Mage_Sales_Model_Order::STATE_CANCELED:
52
+ $kco->cancelReservation($order);
53
+ break;
54
+ default:
55
+ $mixed = false;
56
+ foreach($order->getAllItems() as $item){
57
+ if($item->getQtyShipped() > $item->getQtyInvoiced())
58
+ $mixed = true;
59
+ }
60
+
61
+ if($mixed)
62
+ $kco->activateReservation($order);
63
+ }
 
 
 
 
 
64
  }
65
 
66
  /**
67
+ * Process invoice after save
68
+ *
69
+ * @param Varien_Event_Observer $observer
70
+ */
71
+ public function invoiceSaved($observer)
72
+ {
73
+ if(Mage::helper('klarnaCheckout')->isKcoSave())
74
+ return $this;
75
+
76
+ if($kcoInvoiceKey = Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_INVOICE)){
77
+ $invoice = $observer->getEvent()->getInvoice();
78
+ $order = $invoice->getOrder();
79
+
80
+ if(Mage::helper('klarnaCheckout')->isKcoOrder($order)){
81
+ if(false !== $klarnainvoices = Mage::helper('klarnaCheckout')->getKlarnaInvoices($order)){
82
+ if (!array_key_exists($invoice->getId(), $klarnainvoices)){
83
+ $klarnainvoices[$invoice->getId()] = $klarnainvoices[$kcoInvoiceKey];
84
+ unset($klarnainvoices[$kcoInvoiceKey]);
85
+ $order = Mage::helper('klarnaCheckout')->saveKlarnaInvoices($order, $klarnainvoices);
86
+ Mage::helper('klarnaCheckout')->prepareKcoSave();
87
+ $order->save();
88
+ Mage::helper('klarnaCheckout')->finishKcoSave();
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ return $this;
95
+ }
96
+
97
  /**
98
+ * Add Klarna link in default Checkout
99
+ *
100
+ * @param Varien_Event_Observer $observer
101
+ */
102
+ public function insertKlarnaLink($observer)
103
+ {
104
+ $block = $observer->getBlock();
105
+ $isLogged = Mage::helper('customer')->isLoggedIn();
106
+
107
+ $kco = Mage::helper('klarnaCheckout')->getKco();
108
+
109
+ if(!$kco->getConfig()->isActive())
110
+ return $this;
111
+
112
+ if (
113
+ $block->getType() == 'checkout/onepage_login' ||
114
+ ($isLogged && $block->getType() == 'checkout/onepage_billing') ||
115
+ ($block->getType() == 'checkout/onepage_payment_methods' && $block->getBlockAlias() != 'methods') &&
116
+ $kco->isAvailable()
117
+ )
118
+ {
119
+ $child = clone $block;
120
+ $child->setType('klarnaCheckout/KCO_Link');
121
+ $block->setChild('original', $child);
122
+ $block->setTemplate('KCO/link.phtml');
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Add activate reservation button to admin order view
128
+ *
129
+ * @param Varien_Event_Observer $observer
130
+ */
131
+ public function addActivate($observer)
132
+ {
133
+ $block = $observer->getEvent()->getBlock();
134
+
135
+ if(get_class($block) =='Mage_Adminhtml_Block_Sales_Order_View'
136
+ && $block->getRequest()->getControllerName() == 'sales_order')
137
+ {
138
+ $order = $block->getOrder();
139
+ if(!Mage::helper('klarnaCheckout')->isKcoOrder($order))
140
+ return $this;
141
+
142
+ $block->addButton('activate_klarna_reservation', array(
143
+ 'label' => Mage::helper('klarnaCheckout')->__('Activate Klarna reservation'),
144
+ 'onclick' => 'setLocation(\'' . $block->getUrl('adminhtml/klarnaCheckout_KCO/activateReservation', array('order_id' => $order->getId())) . '\')',
145
+ 'class' => 'save'
146
+ ));
147
+ }
148
+ }
149
+
150
  /**
151
+ * Add new layout handle if needed
152
+ *
153
+ * @param Varien_Event_Observer $observer
154
+ */
155
+ public function layoutLoadBefore($observer)
156
+ {
157
+ if (Mage::getModel('klarnaCheckout/config')->hideDefaultCheckout())
158
+ $observer->getEvent()->getLayout()->getUpdate()->addHandle('kco_only');
159
+
160
+ $kcoLayout = Mage::getModel('klarnaCheckout/config')->getKcoLayout();
161
+ if($observer->getAction()->getFullActionName() == "checkout_cart_index" && ($kcoLayout && $kcoLayout != "default"))
162
+ $observer->getEvent()->getLayout()->getUpdate()->addHandle($kcoLayout);
163
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
app/code/community/Avenla/KlarnaCheckout/Model/Order.php DELETED
@@ -1,326 +0,0 @@
1
- <?php
2
- /**
3
- * This file is released under a custom license by Avenla Oy.
4
- * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
- * For questions and support - klarna-support@avenla.com
8
- *
9
- * @category Avenla
10
- * @package Avenla_KlarnaCheckout
11
- * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
- */
14
-
15
- /**
16
- * Avenla KlarnaCheckout
17
- *
18
- * @category Avenla
19
- * @package Avenla_KlarnaCheckout
20
- */
21
-
22
- require_once(Mage::getBaseDir('lib') . '/KlarnaCheckout/Checkout.php');
23
-
24
- class Avenla_KlarnaCheckout_Model_Order extends Klarna_Checkout_Order
25
- {
26
- private $helper;
27
- private $quote;
28
- private $config;
29
- private $cart;
30
- private $dummy = false;
31
- public $connector;
32
- public $order;
33
- private $mobile;
34
- private $discounted = 0;
35
-
36
- public function __construct()
37
- {
38
- $this->helper = Mage::helper("klarnaCheckout");
39
- $this->config = Mage::getSingleton('klarnaCheckout/KCO')->getConfig();
40
- $url = $this->config->isLive()
41
- ? Avenla_KlarnaCheckout_Model_Config::KCO_LIVE_URL
42
- : Avenla_KlarnaCheckout_Model_Config::KCO_DEMO_URL;
43
-
44
- parent::$baseUri = $url . '/checkout/orders';
45
- parent::$contentType = "application/vnd.klarna.checkout.aggregated-order-v2+json";
46
-
47
- $this->connector = Klarna_Checkout_Connector::create($this->config->getKlarnaSharedSecret());
48
- }
49
-
50
- /**
51
- * Get Klarna Checkout order
52
- *
53
- * @param Mage_Sales_Model_Quote $quote
54
- * @param string $checkoutId
55
- * @return Klarna_Checkout_Order
56
- */
57
- public function getOrder($quote = null, $checkoutId = null, $mobile = false)
58
- {
59
- $this->order = new Klarna_Checkout_Order($this->connector, $checkoutId);
60
- $this->mobile = $mobile;
61
- if(!$quote)
62
- return $this->order;
63
-
64
- $this->quote = $quote;
65
- $this->addProductsToCart();
66
- $this->getShippingCosts();
67
- $this->processDiscount();
68
-
69
- $checkoutId ? $this->updateOrder() : $this->createOrder();
70
-
71
- return $this->order;
72
- }
73
-
74
- /**
75
- * Create new Klarna Checkout order
76
- *
77
- */
78
- private function createOrder()
79
- {
80
- try{
81
- $create['purchase_country'] = $this->getPurchaseCountry();
82
- $create['purchase_currency'] = Mage::app()->getStore()->getBaseCurrencyCode();
83
- $create['locale'] = $this->helper->getLocale($this->getPurchaseCountry());
84
- $create['merchant']['id'] = $this->config->getKlarnaEid();
85
- $create['merchant']['terms_uri'] = $this->config->getTermsUri();
86
- $create['merchant']['checkout_uri'] = $this->helper->getCheckoutUri();
87
- $create['merchant']['confirmation_uri'] = $this->helper->getConfirmationUri();
88
- $create['merchant']['push_uri'] = $this->helper->getPushUri();
89
-
90
- if($this->helper->getValidationUri())
91
- $create['merchant']['validation_uri'] = $this->helper->getValidationUri();
92
-
93
- $create['merchant_reference']['orderid1'] = $this->quote ? $this->quote->getId() : '12345';
94
- $create['gui']['options'] = array('disable_autofocus');
95
- $create['gui']['layout'] = $this->mobile ? 'mobile' : 'desktop';
96
-
97
- if($this->config->useCustomColors()){
98
- $create['options']['color_button'] = '#'.$this->config->getButtonColor();
99
- $create['options']['color_button_text'] = '#'.$this->config->getButtonTextColor();
100
- $create['options']['color_checkbox'] = '#'.$this->config->getCheckboxColor();
101
- $create['options']['color_checkbox_checkmark'] = '#'.$this->config->getCheckboxCheckmarkColor();
102
- $create['options']['color_header'] = '#'.$this->config->getHeaderColor();
103
- $create['options']['color_link'] = '#'.$this->config->getLinkColor();
104
- }
105
-
106
- $info = $this->getCustomerInfo();
107
-
108
- if(!empty($info))
109
- $create['shipping_address'] = $info;
110
-
111
- foreach ($this->cart as $item){
112
- $create['cart']['items'][] = $item;
113
- }
114
-
115
- $this->order->create($create);
116
- if(!$this->dummy)
117
- $this->order->fetch();
118
- }
119
- catch (Exception $e) {
120
- Mage::logException($e);
121
- $this->order = null;
122
- }
123
- }
124
-
125
- /**
126
- * Update existing Klarna Checkout order
127
- *
128
- */
129
- public function updateOrder()
130
- {
131
- try {
132
- $this->order->fetch();
133
- if(!$this->helper->isOrderFromCurrentStore($this->order) ||
134
- strtoupper($this->order['purchase_country']) != $this->getPurchaseCountry()){
135
- $this->createOrder();
136
- return;
137
- }
138
-
139
- $update['cart']['items'] = array();
140
- $update['merchant_reference']['orderid1'] = $this->quote->getId();
141
-
142
- $info = $this->getCustomerInfo();
143
- if(!empty($info))
144
- $update['shipping_address'] = $info;
145
-
146
- foreach ($this->cart as $item){
147
- $update['cart']['items'][] = $item;
148
- }
149
-
150
- $this->order->update($update);
151
- }
152
- catch (Exception $e) {
153
- Mage::logException($e);
154
- $this->order = null;
155
- unset($_SESSION['klarna_checkout']);
156
- }
157
- }
158
-
159
- /**
160
- * Get purchase country
161
- *
162
- * @return string
163
- */
164
- private function getPurchaseCountry()
165
- {
166
- if($this->quote && $this->quote->getShippingAddress()->getCountry()){
167
- return $this->quote->getShippingAddress()->getCountry();
168
- }
169
- else{
170
- return Mage::getStoreConfig('general/country/default', Mage::app()->getStore());
171
- }
172
- }
173
-
174
- /**
175
- * Get customer info for Klarna Checkout
176
- *
177
- * @return array
178
- */
179
- private function getCustomerInfo()
180
- {
181
- $info = array();
182
-
183
- if($this->quote){
184
- $sa = $this->quote->getShippingAddress();
185
- $sa->getPostcode() != null ? $info['postal_code'] = $sa->getPostcode() : '';
186
- $sa->getEmail() != null ? $info['email'] = $sa->getEmail() : '';
187
- }
188
-
189
- return $info;
190
- }
191
-
192
- /**
193
- * Process items from quote to Klarna Checkout order cart
194
- *
195
- */
196
- private function addProductsToCart()
197
- {
198
- $this->cart = array();
199
- $mCart = $this->quote->getAllVisibleItems();
200
-
201
- if(count($mCart) > 0){
202
- foreach ($mCart as $i){
203
- if($i->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE && $i->isChildrenCalculated()){
204
- foreach($i->getChildren() as $c){
205
- $this->addProduct($c);
206
- }
207
- }
208
- else{
209
- $this->addProduct($i);
210
- }
211
- }
212
- }
213
- }
214
-
215
- /**
216
- * Add quote item to cart array
217
- *
218
- * @param Mage_Sales_Model_Quote_Item
219
- */
220
- private function addProduct($item)
221
- {
222
- $discount_rate = 0;
223
- if($item->getBaseDiscountAmount()){
224
- $discount_rate = $item->getBaseDiscountAmount() / ($item->getBaseRowTotalInclTax() / 100);
225
- $this->discounted += $item->getBaseDiscountAmount();
226
- }
227
-
228
- $this->cart[] = array(
229
- 'type' => 'physical',
230
- 'reference' => $item->getSku(),
231
- 'name' => $item->getName(),
232
- 'uri' => $item->getUrlPath(),
233
- 'quantity' => (int)$item->getTotalQty(),
234
- 'unit_price' => round($item->getBasePriceInclTax(), 2) * 100,
235
- 'discount_rate' => round($discount_rate, 2) * 100,
236
- 'tax_rate' => round($item->getTaxPercent(), 2) * 100
237
- );
238
- }
239
-
240
- /**
241
- * Process discount from quote to Klarna Checkout order
242
- *
243
- */
244
- private function processDiscount()
245
- {
246
- $totals = $this->quote->getTotals();
247
- $baseDiscount = $this->quote->getShippingAddress()->getBaseDiscountAmount();
248
-
249
- if(abs($baseDiscount) - $this->discounted > 0.001){
250
- $discount = $totals['discount'];
251
- $diff = abs($baseDiscount) - $this->discounted;
252
-
253
- $this->cart[] = array(
254
- 'type' => 'discount',
255
- 'reference' => $discount->getcode(),
256
- 'name' => $discount->getTitle(),
257
- 'quantity' => 1,
258
- 'unit_price' => round($diff, 2) * 100,
259
- 'tax_rate' => 0
260
- );
261
- }
262
- }
263
-
264
- /**
265
- * Process shipping costs from quote to Klarna Checkout order
266
- *
267
- */
268
- private function getShippingCosts()
269
- {
270
- if($this->quote->getShippingAddress()->getShippingMethod() != null){
271
-
272
- $taxRate = 0;
273
- $taxHelper = Mage::helper('tax/data');
274
- $taxClass = $taxHelper->getShippingTaxClass(Mage::app()->getStore());
275
- $taxClasses = Mage::helper("core")->jsonDecode(Mage::helper("tax")->getAllRatesByProductClass());
276
- if(isset($taxClasses["value_".$taxClass]))
277
- $taxRate = $taxClasses["value_".$taxClass];
278
-
279
- $shippingAddress = $this->quote->getShippingAddress();
280
- $discount_rate = 0;
281
-
282
- if($shippingAddress->getBaseShippingDiscountAmount()){
283
- $discount_rate = $shippingAddress->getBaseShippingDiscountAmount() / ($shippingAddress->getBaseShippingInclTax() / 100);
284
- $this->discounted += $shippingAddress->getBaseShippingDiscountAmount();
285
- }
286
-
287
- $shippingCosts = array(
288
- 'type' => 'shipping_fee',
289
- 'reference' => 'shipping_fee',
290
- 'name' => $shippingAddress->getShippingDescription(),
291
- 'quantity' => 1,
292
- 'unit_price' => round($shippingAddress->getBaseShippingInclTax(), 2) * 100,
293
- 'discount_rate' => round($discount_rate, 2) * 100,
294
- 'tax_rate' => (int)($taxRate * 100)
295
- );
296
-
297
- $this->cart[] = $shippingCosts;
298
- }
299
- }
300
-
301
- /**
302
- * Create dummy order with test product
303
- *
304
- * @return Klarna_Checkout_Order
305
- */
306
- public function dummyOrder($quote = null)
307
- {
308
- $this->dummy = true;
309
- if($quote)
310
- $this->quote = $quote;
311
-
312
- $this->order = new Klarna_Checkout_Order($this->connector, null);
313
-
314
- $this->cart = array(
315
- array(
316
- 'reference' => '123456789',
317
- 'name' => 'Test product',
318
- 'quantity' => 1,
319
- 'unit_price' => 4490,
320
- 'tax_rate' => 0
321
- ));
322
- $this->createOrder();
323
-
324
- return $this->order;
325
- }
326
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Avenla/KlarnaCheckout/Model/Order/Abstract.php ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+
22
+ class Avenla_KlarnaCheckout_Model_Order_Abstract extends Mage_Core_Model_Abstract
23
+ {
24
+ public $order;
25
+ protected $helper;
26
+ protected $config;
27
+ protected $connector;
28
+ protected $cart;
29
+ protected $quote;
30
+ protected $discounted = 0;
31
+ protected $dummyAmount = 4490;
32
+ protected $dummy = false;
33
+
34
+ public function __construct()
35
+ {
36
+ $this->helper = Mage::helper("klarnaCheckout");
37
+ $this->config = $this->getPaymentModel()->getConfig();
38
+ $this->getConnector();
39
+ }
40
+
41
+ /**
42
+ * Get related Klarna order object
43
+ *
44
+ * @param Mage_Sales_Model_Quote $quote
45
+ * @param string $checkoutId
46
+ * @return mixed
47
+ */
48
+ public function getOrder($quote = null, $checkoutId = null)
49
+ {
50
+ if(!$checkoutId && Mage::getSingleton('core/session')->getKCOid())
51
+ $checkoudId = Mage::getSingleton('core/session')->getKCOid();
52
+
53
+ if(!$this->order)
54
+ $this->initOrder($checkoutId);
55
+
56
+ if(!$quote){
57
+ $this->order->fetch();
58
+ return $this->order;
59
+ }
60
+
61
+ $this->quote = $quote;
62
+ $this->addProductsToCart();
63
+ $this->getShippingCosts();
64
+ $this->processDiscount();
65
+
66
+ $checkoutId ? $this->updateOrder() : $this->createOrder();
67
+
68
+ Mage::getSingleton('core/session')->setKCOid($this->getKlarnaOrderId());
69
+
70
+ return $this->order;
71
+ }
72
+
73
+ /**
74
+ * Use configuration for given store and reload connector
75
+ *
76
+ * @param int store
77
+ */
78
+ public function useConfigForStore($store)
79
+ {
80
+ $this->config->setStore($store);
81
+ $this->getConnector();
82
+ }
83
+
84
+ /**
85
+ * Get purchase country
86
+ *
87
+ * @return string
88
+ */
89
+ protected function getPurchaseCountry()
90
+ {
91
+ if($this->quote && $this->quote->getShippingAddress()->getCountry())
92
+ return $this->quote->getShippingAddress()->getCountry();
93
+
94
+ return $this->config->getDefaultCountry();
95
+ }
96
+
97
+ /**
98
+ * Get customer info for Klarna Checkout
99
+ *
100
+ * @return array
101
+ */
102
+ protected function getCustomerInfo()
103
+ {
104
+ $info = array();
105
+
106
+ if($this->quote){
107
+ $sa = $this->quote->getShippingAddress();
108
+ $sa->getPostcode() != null ? $info['postal_code'] = $sa->getPostcode() : '';
109
+ $this->quote->getCustomerEmail() != null ? $info['email'] = $this->quote->getCustomerEmail() : '';
110
+ }
111
+
112
+ return $info;
113
+ }
114
+
115
+ /**
116
+ * Create new Klarna Checkout order
117
+ */
118
+ protected function createOrder()
119
+ {
120
+ $request = new Varien_Object();
121
+ $info = $this->getCustomerInfo();
122
+
123
+ if(!empty($info))
124
+ $request->setShippingAddress($info);
125
+
126
+ $request->setPurchaseCountry($this->getPurchaseCountry());
127
+ $request->setPurchaseCurrency(Mage::app()->getStore()->getBaseCurrencyCode());
128
+ $request->setLocale($this->helper->getLocale($this->getPurchaseCountry()));
129
+
130
+ $options = new Varien_Object();
131
+ $options->setAllowSeparateShippingAddress($this->config->allowSeparateShippingAddress());
132
+
133
+ if($this->config->useCustomColors()){
134
+ $options->setColorButton('#'.$this->config->getButtonColor());
135
+ $options->setColorButtonText('#'.$this->config->getButtonTextColor());
136
+ $options->setColorCheckbox('#'.$this->config->getCheckboxColor());
137
+ $options->setColorCheckboxCheckmark('#'.$this->config->getCheckboxCheckmarkColor());
138
+ $options->setColorHeader('#'.$this->config->getHeaderColor());
139
+ $options->setColorLink('#'.$this->config->getLinkColor());
140
+ }
141
+
142
+ $request->setGui(array('options' => array('disable_autofocus')));
143
+ $request->addData(array('options' => $options->getData()));
144
+ $request->addData($this->getOrderData());
145
+
146
+ try{
147
+ $this->helper->log($request->getData());
148
+ $this->order->create($request->getData());
149
+
150
+ if(!$this->dummy)
151
+ $this->order->fetch();
152
+ }
153
+ catch (Exception $e){
154
+ $this->helper->logException($e);
155
+ $this->order = null;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Update existing Klarna Checkout order
161
+ */
162
+ protected function updateOrder()
163
+ {
164
+ try {
165
+ $this->order->fetch();
166
+ if(!$this->helper->isOrderFromCurrentStore($this->order) ||
167
+ strtoupper($this->order['purchase_country']) != $this->getPurchaseCountry()){
168
+ $this->createOrder();
169
+ return;
170
+ }
171
+
172
+ $request = new Varien_Object();
173
+ $info = $this->getCustomerInfo();
174
+ if(!empty($info))
175
+ $request->setShippingAddress($info);
176
+
177
+ $request->addData($this->getOrderData(true));
178
+ $this->order->update($request->getData());
179
+ }
180
+ catch (Exception $e){
181
+ $this->helper->logException($e);
182
+ $this->order = null;
183
+ Mage::getSingleton('core/session')->unsKCOid();
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Process items from quote to KCO order cart
189
+ */
190
+ protected function addProductsToCart()
191
+ {
192
+ $this->cart = array();
193
+ $mCart = $this->quote->getAllVisibleItems();
194
+
195
+ if(count($mCart) > 0){
196
+ foreach ($mCart as $i){
197
+ if($i->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE && $i->isChildrenCalculated()){
198
+ foreach($i->getChildren() as $c){
199
+ $this->addProduct($c);
200
+ }
201
+ }
202
+ else{
203
+ $this->addProduct($i);
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Create Magento order from Klarna order
211
+ *
212
+ * @return Mage_Sales_Model_Order
213
+ */
214
+ public function createMagentoOrder()
215
+ {
216
+ $quoteId = $this->getMerchantReference();
217
+ $quote = Mage::getModel("sales/quote")->load($quoteId);
218
+ $ko = $this->order;
219
+
220
+ if($quote->getCustomerIsGuest())
221
+ $quote->setCustomerEmail($ko['billing_address']['email'])->save();
222
+
223
+ $quote->getBillingAddress()->addData($this->convertAddress($ko['billing_address']));
224
+ $quote->getShippingAddress()->addData($this->convertAddress($ko['shipping_address']));
225
+ $quote->getPayment()->setMethod($this->getPaymentModel()->getCode());
226
+ $quote->getPayment()->setAdditionalInformation($this->getAdditionalOrderInformation());
227
+ $quote->collectTotals()->save();
228
+
229
+ $service = Mage::getModel('sales/service_quote', $quote);
230
+ $service->submitAll();
231
+ $quote->setIsActive(false)->save();
232
+
233
+ return $service->getOrder();
234
+ }
235
+
236
+ /**
237
+ * Convert Klarna address to Magento address
238
+ *
239
+ * @param array $address
240
+ * @param string $region
241
+ * @param string $region_code
242
+ * @return array
243
+ */
244
+ private function convertAddress($address, $region = '', $region_code = '')
245
+ {
246
+ $country_id = strtoupper($address['country']);
247
+
248
+ if($region_code == '')
249
+ $region_code = 1;
250
+
251
+ $street = isset($address['street_address'])
252
+ ? $address['street_address']
253
+ : $address['street_name'] . " " . $address['street_number'];
254
+
255
+ $phone = strlen($address['phone'] > 0) ? $address['phone'] : '1';
256
+
257
+ $magentoAddress = array(
258
+ 'firstname' => $address['given_name'],
259
+ 'lastname' => $address['family_name'],
260
+ 'email' => $address['email'],
261
+ 'street' => $street,
262
+ 'city' => $address['city'],
263
+ 'region_id' => $region_code,
264
+ 'region' => $region,
265
+ 'postcode' => $address['postal_code'],
266
+ 'country_id' => strtoupper($address['country']),
267
+ 'telephone' => $phone
268
+ );
269
+
270
+ return $magentoAddress;
271
+ }
272
+
273
+ /**
274
+ * Cancel Magento order
275
+ *
276
+ * @param Mage_Sales_Model_Order $mo
277
+ * @param string $msg
278
+ */
279
+ protected function cancelMagentoOrder($mo, $msg)
280
+ {
281
+ $mo->cancel();
282
+ $mo->setStatus($msg);
283
+ $mo->save();
284
+ }
285
+
286
+ /**
287
+ * Confirm order
288
+ *
289
+ * @param Mage_Sales_Model_Order $mo
290
+ */
291
+ public function confirmOrder($mo, $checkoutId)
292
+ {
293
+ $mo->getSendConfirmation(null);
294
+ $mo->sendNewOrderEmail();
295
+ if($mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_NEWSLETTER))
296
+ Mage::getModel('klarnaCheckout/newsletter')->signForNewsletter($mo, Mage::app()->getStore()->getWebsiteId());
297
+ }
298
+
299
+ /**
300
+ * Check if the Klarna order is complete
301
+ *
302
+ * @return bool
303
+ */
304
+ public function isOrderComplete()
305
+ {
306
+ if($this->order['status'] == "checkout_complete")
307
+ return true;
308
+
309
+ return false;
310
+ }
311
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Order/Kcov2.php ADDED
@@ -0,0 +1,370 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+
22
+ require_once(Mage::getBaseDir('lib') . '/KlarnaCheckout/autoload.php');
23
+
24
+ class Avenla_KlarnaCheckout_Model_Order_Kcov2 extends Avenla_KlarnaCheckout_Model_Order_Abstract
25
+ {
26
+ /**
27
+ * Get related payment model
28
+ *
29
+ * @return Avenla_KlarnaCheckout_Model_Payment_KCOv2
30
+ */
31
+ protected function getPaymentModel()
32
+ {
33
+ return Mage::getModel('klarnaCheckout/payment_KCO');
34
+ }
35
+
36
+ /**
37
+ * Get Klarna connector
38
+ */
39
+ protected function getConnector()
40
+ {
41
+ $this->connector = Klarna_Checkout_Connector::create(
42
+ $this->config->getKlarnaSharedSecret(),
43
+ $this->getServiceUrl()
44
+ );
45
+ }
46
+
47
+ /**
48
+ * Get Klarna service URL
49
+ *
50
+ * @return string
51
+ */
52
+ protected function getServiceUrl()
53
+ {
54
+ $url = $this->config->isLive()
55
+ ? Klarna_Checkout_Connector::BASE_URL
56
+ : Klarna_Checkout_Connector::BASE_TEST_URL;
57
+
58
+ return $url;
59
+ }
60
+
61
+ /**
62
+ * Initialize Klarna order object
63
+ *
64
+ * @param string $checkoutId|null
65
+ * @return Klarna_Checkout_Order
66
+ */
67
+ protected function initOrder($checkoutId = null)
68
+ {
69
+ $this->order = new Klarna_Checkout_Order($this->connector, $checkoutId);
70
+ return $this->order;
71
+ }
72
+
73
+ /**
74
+ * Get Klarna order id
75
+ *
76
+ * @return string
77
+ */
78
+ protected function getKlarnaOrderId()
79
+ {
80
+ if(isset($this->order['id']))
81
+ return $this->order['id'];
82
+
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * Get order data for create or update request
88
+ *
89
+ * @return array
90
+ */
91
+ protected function getOrderData($isUpdate = false)
92
+ {
93
+ $data = array();
94
+ if(!$isUpdate){
95
+ $data['merchant']['id'] = $this->config->getKlarnaEid();
96
+ $data['merchant']['terms_uri'] = $this->config->getTermsUri();
97
+ $data['merchant']['checkout_uri'] = $this->helper->getCheckoutUri();
98
+ $data['merchant']['confirmation_uri'] = $this->helper->getConfirmationUri();
99
+ $data['merchant']['push_uri'] = $this->helper->getPushUri();
100
+
101
+ if($this->helper->getValidationUri())
102
+ $data['merchant']['validation_uri'] = $this->helper->getValidationUri();
103
+ }
104
+
105
+ $data['merchant_reference']['orderid1'] = $this->quote ? $this->quote->getId() : '12345';
106
+ $data['cart']['items'] = $this->cart;
107
+
108
+ return $data;
109
+ }
110
+
111
+ /**
112
+ * Add quote item to cart array
113
+ *
114
+ * @param Mage_Sales_Model_Quote_Item
115
+ */
116
+ protected function addProduct($item)
117
+ {
118
+ $discountRate = 0;
119
+ if($item->getBaseDiscountAmount()){
120
+ $discountRate = $item->getBaseDiscountAmount() / ($item->getBaseRowTotalInclTax() / 100);
121
+ $this->discounted += $item->getBaseDiscountAmount();
122
+ }
123
+
124
+ $this->cart[] = array(
125
+ 'type' => 'physical',
126
+ 'reference' => $item->getSku(),
127
+ 'name' => $item->getName(),
128
+ 'uri' => $item->getUrlPath(),
129
+ 'quantity' => (int)$item->getTotalQty(),
130
+ 'unit_price' => $this->helper->formatPriceForKlarna($item->getBasePriceInclTax()),
131
+ 'discount_rate' => $this->helper->formatPriceForKlarna($discountRate),
132
+ 'tax_rate' => $this->helper->formatPriceForKlarna($item->getTaxPercent())
133
+ );
134
+ }
135
+
136
+ /**
137
+ * Process discount from quote to Klarna Checkout order
138
+ */
139
+ protected function processDiscount()
140
+ {
141
+ $totals = $this->quote->getTotals();
142
+ $baseDiscount = $this->quote->getShippingAddress()->getBaseDiscountAmount();
143
+
144
+ if(abs($baseDiscount) - $this->discounted > 0.001){
145
+ $discount = $totals['discount'];
146
+ $diff = abs($baseDiscount) - $this->discounted;
147
+
148
+ $this->cart[] = array(
149
+ 'type' => 'discount',
150
+ 'reference' => $discount->getcode(),
151
+ 'name' => $discount->getTitle(),
152
+ 'quantity' => 1,
153
+ 'unit_price' => $this->helper->formatPriceForKlarna($diff),
154
+ 'tax_rate' => 0
155
+ );
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Process shipping costs from quote to Klarna Checkout order
161
+ */
162
+ protected function getShippingCosts()
163
+ {
164
+ if($this->quote->getShippingAddress()->getShippingMethod() != null){
165
+
166
+ $taxRate = $this->helper->getShippingVatRate($this->quote);
167
+ $shippingAddress = $this->quote->getShippingAddress();
168
+ $discountRate = 0;
169
+
170
+ if($shippingAddress->getBaseShippingDiscountAmount()){
171
+ $discountRate = $shippingAddress->getBaseShippingInclTax() == 0
172
+ ? 100
173
+ : $shippingAddress->getBaseShippingDiscountAmount() / ($shippingAddress->getBaseShippingInclTax() / 100);
174
+ $this->discounted += $shippingAddress->getBaseShippingDiscountAmount();
175
+ }
176
+
177
+ $shippingCosts = array(
178
+ 'type' => 'shipping_fee',
179
+ 'reference' => 'shipping_fee',
180
+ 'name' => $shippingAddress->getShippingDescription(),
181
+ 'quantity' => 1,
182
+ 'unit_price' => $this->helper->formatPriceForKlarna($shippingAddress->getBaseShippingInclTax()),
183
+ 'discount_rate' => $this->helper->formatPriceForKlarna($discountRate),
184
+ 'tax_rate' => $this->helper->formatPriceForKlarna($taxRate)
185
+ );
186
+
187
+ $this->cart[] = $shippingCosts;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Get Klarna HTML-snippet
193
+ *
194
+ * @return string
195
+ */
196
+ public function getHtmlSnippet()
197
+ {
198
+ return $this->order['gui']['snippet'];
199
+ }
200
+
201
+ /**
202
+ * Get merchant reference
203
+ *
204
+ * @param int $no|1
205
+ * @return string
206
+ */
207
+ public function getMerchantReference($no = 1)
208
+ {
209
+ if($this->order['merchant_reference']['orderid'.$no])
210
+ return $this->order['merchant_reference']['orderid'.$no];
211
+
212
+ return false;
213
+ }
214
+
215
+ /**
216
+ * Cancel Klarna reservation
217
+ */
218
+ public function cancelReservation()
219
+ {
220
+ Mage::getModel('klarnaCheckout/api')->cancelReservation($this->order['reservation']);
221
+ }
222
+
223
+ /**
224
+ * Confirm Klarna order
225
+ *
226
+ * @param Mage_Sales_Model_Order $mo
227
+ * @param string $quoteId
228
+ */
229
+ public function confirmOrder($mo, $checkoutId)
230
+ {
231
+ $quoteId = $this->order['merchant_reference']['orderid1'];
232
+ $data['merchant_reference']['orderid1'] = $mo->getIncrementId();
233
+ $data['merchant_reference']['orderid2'] = $quoteId;
234
+ $data['status'] = 'created';
235
+ $this->order->update($data);
236
+
237
+ if($this->order['status'] != "created"){
238
+ $this->cancelMagentoOrder($mo, $this->__('Order canceled: Failed to create order in Klarna.'));
239
+ }
240
+ else{
241
+ parent::confirmOrder($mo, $quoteId);
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Get Klarna order information
247
+ *
248
+ * @param array $paymentInfo|null
249
+ * @return Varien_Object
250
+ */
251
+ public function getOrderInformation($checkoutId, $paymentInfo = null)
252
+ {
253
+ $this->getOrder(null, $checkoutId);
254
+
255
+ $info = new Varien_Object();
256
+ $info->setLogoSrc($this->helper->getLogoSrc());
257
+ $info->setGuiUrl(Avenla_KlarnaCheckout_Model_Config::ONLINE_GUI_URL);
258
+ $info->setExpiration($this->order['expires_at']);
259
+
260
+ if($paymentInfo){
261
+ $info->setReservation($paymentInfo->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_RESERVATION));
262
+ if (count($paymentInfo->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_INVOICE)) > 0){
263
+ $info->setOrderInvoices($paymentInfo->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_INVOICE));
264
+ $info->setPdfUrl($this->getServiceUrl() . "/packslips/");
265
+ }
266
+ if (strlen($paymentInfo->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_MESSAGE)) > 0)
267
+ $info->setMessage($paymentInfo->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_MESSAGE));
268
+ }
269
+
270
+ return $info;
271
+ }
272
+
273
+ /**
274
+ * Get additional information to be saved in Magento order
275
+ *
276
+ * @return array
277
+ */
278
+ protected function getAdditionalOrderInformation()
279
+ {
280
+ $data = array();
281
+ $data[Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID] = $this->getKlarnaOrderId();
282
+ $data[Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_RESERVATION] = $this->order['reservation'];
283
+
284
+ return $data;
285
+ }
286
+
287
+ /**
288
+ * Create dummy order with test product
289
+ *
290
+ * @return Klarna_Checkout_Order
291
+ */
292
+ public function dummyOrder($quote = null)
293
+ {
294
+ try{
295
+ $this->dummy = true;
296
+ if($quote)
297
+ $this->quote = $quote;
298
+
299
+ $this->initOrder();
300
+ $this->cart = array(
301
+ array(
302
+ 'reference' => '123456789',
303
+ 'name' => 'Test product',
304
+ 'quantity' => 1,
305
+ 'unit_price' => 4490,
306
+ 'tax_rate' => 0
307
+ ));
308
+ $this->createOrder();
309
+
310
+ return $this->order;
311
+ }
312
+ catch(Exception $e){
313
+ $this->helper->logException($e);
314
+ return false;
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Get order analytics data
320
+ *
321
+ * @return Varien_Object
322
+ */
323
+ public function getAnalyticsData()
324
+ {
325
+ $ko = $this->order;
326
+
327
+ if(count($ko['cart']['items']) < 1)
328
+ return false;
329
+
330
+ $orderId = false;
331
+ if(isset($ko['merchant_reference']['orderid2']) && strlen($ko['merchant_reference']['orderid2']) > 0){
332
+ $mo = Mage::getModel('sales/order')->load($ko['merchant_reference']['orderid1'], 'increment_id');
333
+ if($mo->getId())
334
+ $orderId = $ko['merchant_reference']['orderid1'];
335
+ }
336
+
337
+ if(!$orderId){
338
+ $quote = Mage::getModel('sales/quote')->load($ko['merchant_reference']['orderid1']);
339
+ $quote->reserveOrderId();
340
+ $quote->save();
341
+ $orderId = $quote->getReservedOrderId();
342
+ }
343
+
344
+ $result = new Varien_Object();
345
+ $result->setOrderId($orderId);
346
+ $result->setTotalInclTax($ko['cart']['total_price_including_tax'] / 100);
347
+ $result->setTotalTaxAmount($ko['cart']['total_tax_amount'] / 100);
348
+ $result->setBillingCity($ko['billing_address']['city']);
349
+ $result->setBillingCountry($ko['billing_address']['country']);
350
+ $result->setCurrency(strtoupper($ko['purchase_currency']));
351
+ $result->setShippingFee(0);
352
+ $items = array();
353
+ foreach($ko['cart']['items'] as $p){
354
+ if($p['type'] == 'shipping_fee'){
355
+ $result->setShippingFee($p['total_price_including_tax'] / 100);
356
+ }
357
+ else{
358
+ $line = new Varien_Object();
359
+ $line->setReference($p['reference']);
360
+ $line->setName($p['name']);
361
+ $line->setPrice($p['unit_price'] / 100);
362
+ $line->setQty($p['quantity']);
363
+ $items[] = $line;
364
+ }
365
+ }
366
+ $result->setItems($items);
367
+
368
+ return $result;
369
+ }
370
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Order/Kcov3.php ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+
22
+ require_once(Mage::getBaseDir('lib') . '/KlarnaCheckout/autoload.php');
23
+
24
+ class Avenla_KlarnaCheckout_Model_Order_Kcov3 extends Avenla_KlarnaCheckout_Model_Order_Abstract
25
+ {
26
+ const ORDER_STATUS_AUTHORIZED = 'AUTHORIZED';
27
+ const ORDER_STATUS_PARTCAPTURED = 'PART_CAPTURED';
28
+ const ORDER_STATUS_CAPTURED = 'CAPTURED';
29
+ const ORDER_STATUS_CANCELLED = 'CANCELLED';
30
+ const ORDER_STATUS_EXPIRED = 'EXPIRED';
31
+ const ORDER_STATUS_CLOSED = 'CLOSED';
32
+
33
+ private $orderManagement = null;
34
+
35
+ /**
36
+ * Get related payment model
37
+ *
38
+ * @return Avenla_KlarnaCheckout_Model_Payment_KCOv3
39
+ */
40
+ protected function getPaymentModel()
41
+ {
42
+ return Mage::getModel('klarnaCheckout/payment_KCOv3');
43
+ }
44
+
45
+ /**
46
+ * Get Klarna connector
47
+ */
48
+ protected function getConnector()
49
+ {
50
+ $connector = Klarna\Rest\Transport\Connector::create(
51
+ $this->config->getKlarnaEid(),
52
+ $this->config->getKlarnaSharedSecret(),
53
+ $this->getServiceUrl()
54
+ );
55
+
56
+ $this->connector = $connector;
57
+ }
58
+
59
+ /**
60
+ * Get Klarna service URL
61
+ *
62
+ * @return string
63
+ */
64
+ protected function getServiceUrl()
65
+ {
66
+ $url = null;
67
+
68
+ if($this->config->getApiVersion() == Avenla_KlarnaCheckout_Model_Config::API_TYPE_KCOV3_US){
69
+ $url = $this->config->isLive()
70
+ ? Klarna\Rest\Transport\ConnectorInterface::NA_BASE_URL
71
+ : Klarna\Rest\Transport\ConnectorInterface::NA_TEST_BASE_URL;
72
+ }
73
+ else{
74
+ $url = $this->config->isLive()
75
+ ? Klarna\Rest\Transport\ConnectorInterface::EU_BASE_URL
76
+ : Klarna\Rest\Transport\ConnectorInterface::EU_TEST_BASE_URL;
77
+ }
78
+
79
+ return $url;
80
+ }
81
+
82
+ /**
83
+ * Initialize Klarna order object
84
+ *
85
+ * @param string $checkoutId|null
86
+ * @return Klarna\Rest\Checkout\Order
87
+ */
88
+ protected function initOrder($checkoutId = null)
89
+ {
90
+ $this->order = new Klarna\Rest\Checkout\Order($this->connector, $checkoutId);
91
+ return $this->order;
92
+ }
93
+
94
+ /**
95
+ * Get Klarna order id
96
+ *
97
+ * @return string
98
+ */
99
+ protected function getKlarnaOrderId()
100
+ {
101
+ if($this->order['order_id'])
102
+ return $this->order['order_id'];
103
+
104
+ return null;
105
+ }
106
+
107
+ /**
108
+ * Get order data for create or update request
109
+ *
110
+ * @return array
111
+ */
112
+ protected function getOrderData($isUpdate = false)
113
+ {
114
+ $data = array();
115
+ $data['merchant_reference1'] = $this->quote ? $this->quote->getId() : '12345';
116
+ if(!$isUpdate){
117
+ $data['merchant_urls']['terms'] = $this->config->getTermsUri();
118
+ $data['merchant_urls']['checkout'] = $this->helper->getCheckoutUri();
119
+ $data['merchant_urls']['confirmation'] = $this->helper->getConfirmationUri($this->type);
120
+ $data['merchant_urls']['push'] = $this->helper->getPushUri($this->type);
121
+
122
+ if($this->helper->getValidationUri($this->type))
123
+ $data['merchant_urls']['validation'] = $this->helper->getValidationUri($this->type);
124
+ }
125
+
126
+ $data["order_amount"] = $this->dummy ? $this->dummyAmount : $this->helper->formatPriceForKlarna($this->quote->getBaseGrandTotal());
127
+ $data["order_tax_amount"] = $this->dummy ? 0 : $this->helper->formatPriceForKlarna($this->quote->getShippingAddress()->getBaseTaxAmount());
128
+ $data['order_lines'] = $this->cart;
129
+
130
+ return $data;
131
+ }
132
+
133
+ /**
134
+ * Add quote item to cart array
135
+ *
136
+ * @param Mage_Sales_Model_Quote_Item
137
+ */
138
+ protected function addProduct($item)
139
+ {
140
+ if($item->getBaseDiscountAmount())
141
+ $this->discounted += $item->getBaseDiscountAmount();
142
+
143
+ $discountedTotal = $item->getBaseRowTotalInclTax() - $item->getBaseDiscountAmount();
144
+
145
+ $this->cart[] = array(
146
+ 'type' => 'physical',
147
+ 'reference' => $item->getSku(),
148
+ 'name' => $item->getName(),
149
+ 'quantity' => (int)$item->getTotalQty(),
150
+ 'unit_price' => $this->helper->formatPriceForKlarna($item->getBasePriceInclTax()),
151
+ 'tax_rate' => $this->helper->formatPriceForKlarna($item->getTaxPercent()),
152
+ 'total_amount' => $this->helper->formatPriceForKlarna($discountedTotal),
153
+ 'total_tax_amount' => $this->helper->formatPriceForKlarna($item->getBaseTaxAmount()),
154
+ 'total_discount_amount' => $this->helper->formatPriceForKlarna($item->getBaseDiscountAmount())
155
+ );
156
+ }
157
+
158
+ /**
159
+ * Process discount from quote to Klarna Checkout order
160
+ */
161
+ protected function processDiscount()
162
+ {
163
+ $totals = $this->quote->getTotals();
164
+ $baseDiscount = $this->quote->getShippingAddress()->getBaseDiscountAmount();
165
+
166
+ if(abs($baseDiscount) - $this->discounted > 0.001){
167
+ $discount = $totals['discount'];
168
+ $diff = abs($baseDiscount) - $this->discounted;
169
+
170
+ $this->cart[] = array(
171
+ 'type' => 'discount',
172
+ 'reference' => $discount->getcode(),
173
+ 'name' => $discount->getTitle(),
174
+ 'quantity' => 1,
175
+ 'unit_price' => $this->helper->formatPriceForKlarna($diff),
176
+ 'tax_rate' => 0,
177
+ 'total_amount' => $this->helper->formatPriceForKlarna($diff),
178
+ 'total_tax_amount' => 0
179
+ );
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Process shipping costs from quote to Klarna Checkout order
185
+ */
186
+ protected function getShippingCosts()
187
+ {
188
+ if($this->quote->getShippingAddress()->getShippingMethod() != null){
189
+
190
+ $taxRate = Mage::helper('klarnaCheckout')->getShippingVatRate($this->quote);
191
+ $shippingAddress = $this->quote->getShippingAddress();
192
+
193
+ if($shippingAddress->getBaseShippingDiscountAmount())
194
+ $this->discounted += $shippingAddress->getBaseShippingDiscountAmount();
195
+
196
+ $this->cart[] = array(
197
+ 'type' => 'shipping_fee',
198
+ 'reference' => 'shipping_fee',
199
+ 'name' => $shippingAddress->getShippingDescription(),
200
+ 'quantity' => 1,
201
+ 'unit_price' => $this->helper->formatPriceForKlarna($shippingAddress->getBaseShippingInclTax()),
202
+ 'tax_rate' => (int)($taxRate * 100),
203
+ 'total_tax_amount' => $this->helper->formatPriceForKlarna($shippingAddress->getBaseShippingTaxAmount()),
204
+ 'total_discount_amount' => $this->helper->formatPriceForKlarna($shippingAddress->getBaseShippingDiscountAmount()),
205
+ 'total_amount' => $this->helper->formatPriceForKlarna($shippingAddress->getBaseShippingInclTax())
206
+ );
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Get Klarna HTML-snippet
212
+ *
213
+ * @return string
214
+ */
215
+ public function getHtmlSnippet()
216
+ {
217
+ return $this->order['html_snippet'];
218
+ }
219
+
220
+ /**
221
+ * Get merchant reference
222
+ *
223
+ * @param int $no|1
224
+ * @return string
225
+ */
226
+ public function getMerchantReference($no = 1)
227
+ {
228
+ return $this->order['merchant_reference'.$no];
229
+ }
230
+
231
+ /**
232
+ * Cancel Klarna reservation
233
+ *
234
+ */
235
+ public function cancelReservation()
236
+ {
237
+ $this->order->cancel();
238
+ }
239
+
240
+ /**
241
+ * Get Klarna order management object
242
+ *
243
+ * @param string $orderId
244
+ * @return \Klarna\Rest\OrderManagement\Order
245
+ */
246
+ public function getManagement($orderId)
247
+ {
248
+ if(!$this->orderManagement){
249
+ $om = new \Klarna\Rest\OrderManagement\Order(
250
+ $this->connector,
251
+ $orderId
252
+ );
253
+
254
+ $om->fetch();
255
+ $this->orderManagement = $om;
256
+ }
257
+
258
+ return $this->orderManagement;
259
+ }
260
+
261
+ /**
262
+ * Confirm Klarna order
263
+ *
264
+ * @param Magento_Sales_Model_Order $mo
265
+ * @param string $checkoutId
266
+ */
267
+ public function confirmOrder($mo, $checkoutId)
268
+ {
269
+ $quoteId = $this->order['merchant_reference1'];
270
+ $om = $this->getManagement($checkoutId);
271
+ $om->updateMerchantReferences([
272
+ "merchant_reference1" => $mo->getIncrementId(),
273
+ "merchant_reference2" => $quoteId
274
+ ]);
275
+
276
+ $om->acknowledge();
277
+ parent::confirmOrder($mo, $checkoutId);
278
+ }
279
+
280
+ /**
281
+ * Get Klarna order information
282
+ *
283
+ * @param array $paymentInfo|null
284
+ * @return Varien_Object
285
+ */
286
+ public function getOrderInformation($checkoutId, $paymentInfo = null)
287
+ {
288
+ $info = new Varien_Object();
289
+
290
+ $klarnainfo = $this->getManagement($checkoutId);
291
+ $info->setLogoSrc($this->helper->getLogoSrc());
292
+ $info->setExpiration($klarnainfo['expires_at']);
293
+ $info->setKlarnaReference($klarnainfo['klarna_reference']);
294
+ $info->setCaptures($klarnainfo['captures']);
295
+ $info->setRefunds($klarnainfo['refunds']);
296
+ $info->setRemainingAmount($klarnainfo['remaining_authorized_amount']);
297
+
298
+ switch ($klarnainfo['status']) {
299
+ case self::ORDER_STATUS_EXPIRED:
300
+ $info->setStatusMessage("Order authorization time has expired");
301
+ break;
302
+ case self::ORDER_STATUS_CLOSED:
303
+ $info->setStatusMessage("Order has been closed");
304
+ break;
305
+ case self::ORDER_STATUS_CANCELLED:
306
+ $info->setStatusMessage("Order has been canceled");
307
+ break;
308
+ }
309
+
310
+ return $info;
311
+ }
312
+
313
+ /**
314
+ * Get additional information to be saved in Magento order
315
+ *
316
+ * @return array
317
+ */
318
+ protected function getAdditionalOrderInformation()
319
+ {
320
+ $data = array();
321
+ $data[Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID] = $this->getKlarnaOrderId();
322
+
323
+ return $data;
324
+ }
325
+
326
+ /**
327
+ * Create dummy order with test product
328
+ *
329
+ * @return Klarna\Rest\Checkout\Order
330
+ */
331
+ public function dummyOrder($quote = null)
332
+ {
333
+ try{
334
+ $this->dummy = true;
335
+ if($quote)
336
+ $this->quote = $quote;
337
+
338
+ $this->initOrder();
339
+ $this->cart = array(
340
+ array(
341
+ 'type' => 'physical',
342
+ 'reference' => '123456789',
343
+ 'name' => 'Test product',
344
+ 'quantity' => 1,
345
+ 'unit_price' => $this->dummyAmount,
346
+ 'tax_rate' => 0,
347
+ 'total_amount' => $this->dummyAmount,
348
+ 'total_tax_amount' => 0,
349
+ 'total_discount_amount' => 0
350
+ ));
351
+
352
+ $this->createOrder();
353
+ return $this->order;
354
+ }
355
+ catch(Exception $e){
356
+ $this->helper->logException($e);
357
+ return false;
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Get order analytics data
363
+ *
364
+ * @return Varien_Object
365
+ */
366
+ public function getAnalyticsData()
367
+ {
368
+ $ko = $this->order;
369
+
370
+ if(count($ko['order_lines']) < 1)
371
+ return false;
372
+
373
+ $orderId = false;
374
+ if(isset($ko['merchant_reference2']) && strlen($ko['merchant_reference2']) > 0){
375
+ $mo = Mage::getModel('sales/order')->load($ko['merchant_reference1'], 'increment_id');
376
+ if($mo->getId())
377
+ $orderId = $ko['merchant_reference1'];
378
+ }
379
+
380
+ if(!$orderId){
381
+ $quote = Mage::getModel('sales/quote')->load($ko['merchant_reference1']);
382
+ $quote->reserveOrderId();
383
+ $quote->save();
384
+ $orderId = $quote->getReservedOrderId();
385
+ }
386
+
387
+ $result = new Varien_Object();
388
+ $result->setOrderId($orderId);
389
+ $result->setTotalInclTax($ko['order_amount'] / 100);
390
+ $result->setTotalTaxAmount($ko['order_tax_amount'] / 100);
391
+ $result->setBillingCity($ko['billing_address']['city']);
392
+ $result->setBillingCountry($ko['billing_address']['country']);
393
+ $result->setCurrency(strtoupper($ko['purchase_currency']));
394
+ $result->setShippingFee(0);
395
+ $items = array();
396
+ foreach($ko['order_lines'] as $p){
397
+ if($p['type'] == 'shipping_fee'){
398
+ $result->setShippingFee($p['total_amount'] / 100);
399
+ }
400
+ else{
401
+ $line = new Varien_Object();
402
+ $line->setReference($p['reference']);
403
+ $line->setName($p['name']);
404
+ $line->setPrice($p['unit_price'] / 100);
405
+ $line->setQty($p['quantity']);
406
+ $items[] = $line;
407
+ }
408
+ }
409
+ $result->setItems($items);
410
+
411
+ return $result;
412
+ }
413
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Payment/Abstract.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+
22
+ class Avenla_KlarnaCheckout_Model_Payment_Abstract extends Mage_Payment_Model_Method_Abstract
23
+ {
24
+ const ADDITIONAL_FIELD_KLARNA_RESERVATION = "klarna_order_reservation";
25
+ const ADDITIONAL_FIELD_KLARNA_ORDER_ID = "klarna_order_id";
26
+ const ADDITIONAL_FIELD_NEWSLETTER = "klarna_newsletter";
27
+ const ADDITIONAL_FIELD_VALIDATION_MSG = "kco_validation_message";
28
+ const ADDITIONAL_FIELD_KLARNA_MESSAGE = "klarna_message";
29
+ const ADDITIONAL_FIELD_KLARNA_INVOICE = "klarna_order_invoice";
30
+
31
+ const REGISTRY_KEY_INVOICE = "kco_invoicekey";
32
+ const REGISTRY_KEY_TRANSACTION = "kco_transaction";
33
+ const REGISTRY_KEY_KCO_SAVE = "kco_save";
34
+ const REQUEST_KLARNA_ORDER = 'klarna_order';
35
+
36
+ protected $_isGateway = true;
37
+ protected $_canAuthorize = true;
38
+ protected $_canCapture = true;
39
+ protected $_canCapturePartial = true;
40
+ protected $_canRefund = true;
41
+ protected $_canRefundInvoicePartial = true;
42
+ protected $_canVoid = false;
43
+ protected $_canUseInternal = false;
44
+ protected $_canUseForMultishipping = false;
45
+ protected $_order = null;
46
+
47
+ protected $helper;
48
+
49
+ public function __construct()
50
+ {
51
+ $this->helper = Mage::helper('klarnaCheckout');
52
+ parent::__construct();
53
+ }
54
+
55
+ /**
56
+ * Activate Klarna reservation
57
+ *
58
+ * @param Magento_Sales_Order $mo
59
+ * @param string $invoiceId|null
60
+ * @return bool
61
+ */
62
+ public function activateReservation($mo, $invoiceId = null)
63
+ {
64
+ $this->helper->prepareKcoSave();
65
+
66
+ if($invoiceId != null){
67
+ $result = $this->activateFromInvoice($mo, Mage::getModel('sales/order_invoice')->load($invoiceId));
68
+ }
69
+ else if(false !== $qtys = $this->checkIfPartial($mo)){
70
+ $result = $this->activatePartialReservation($mo, $qtys);
71
+ }
72
+ else{
73
+ $result = $this->activateFullReservation($mo);
74
+ }
75
+
76
+ $this->helper->finishKcoSave();
77
+
78
+ return $result;
79
+ }
80
+
81
+ /**
82
+ * Check if activation is partial or full
83
+ *
84
+ * @param Magento_Sales_Order $mo
85
+ * @return array $qtys|false
86
+ */
87
+ protected function checkIfPartial($mo)
88
+ {
89
+ $qtys = array();
90
+ $partial = false;
91
+
92
+ foreach($mo->getAllVisibleItems() as $item){
93
+ if($item->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE){
94
+ if($item->isChildrenCalculated()){
95
+ foreach($item->getChildrenItems() as $child){
96
+ $qtys[$child->getId()] = $child->getQtyShipped() - $child->getQtyInvoiced();
97
+
98
+ if($child->getQtyOrdered() != $child->getQtyShipped())
99
+ $partial = true;
100
+ }
101
+ }
102
+ else{
103
+ if($item->isDummy()){
104
+ $bundleQtys = array();
105
+ foreach($item->getChildrenItems() as $child){
106
+ $parentCount = 0;
107
+ $bundleCount = $child->getQtyOrdered() / $item->getQtyOrdered();
108
+ $qtyInvoiced = $bundleCount * $item->getQtyInvoiced();
109
+ $diff = $child->getQtyShipped() - $qtyInvoiced;
110
+
111
+ if($diff >= $bundleCount)
112
+ $parentCount = floor($bundleCount / $diff);
113
+
114
+ $bundleQtys[] = $parentCount;
115
+
116
+ if($child->getQtyOrdered() != $child->getQtyShipped())
117
+ $partial = true;
118
+ }
119
+
120
+ $qtys[$item->getId()] = min($bundleQtys);
121
+ }
122
+ else{
123
+ $qtys[$item->getId()] = $item->getQtyShipped() - $item->getQtyInvoiced();
124
+
125
+ if($item->getQtyShipped() != $item->getQtyOrdered())
126
+ $partial = true;
127
+ }
128
+ }
129
+ }
130
+ else{
131
+ $qtys[$item->getId()] = $item->getQtyShipped() - $item->getQtyInvoiced();
132
+
133
+ if($item->getQtyShipped() != $item->getQtyOrdered())
134
+ $partial = true;
135
+ }
136
+ }
137
+
138
+ if($partial)
139
+ return $qtys;
140
+
141
+ return false;
142
+ }
143
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Payment/KCO.php ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+
22
+ class Avenla_KlarnaCheckout_Model_Payment_KCO extends Avenla_KlarnaCheckout_Model_Payment_Abstract
23
+ {
24
+ protected $_code = 'klarnaCheckout_payment';
25
+ protected $_formBlockType = 'klarnaCheckout/KCO_form';
26
+ protected $_infoBlockType = 'klarnaCheckout/KCO_info';
27
+ protected $_canUseCheckout = false;
28
+
29
+ /**
30
+ * Get Config model
31
+ *
32
+ * @return Avenla_KlarnaCheckout_Model_Config
33
+ */
34
+ public function getConfig()
35
+ {
36
+ $config = Mage::getSingleton('klarnaCheckout/config');
37
+ $config->setStore($this->getStore());
38
+ return $config;
39
+ }
40
+
41
+ /**
42
+ * Check if Klarna Checkout is available
43
+ *
44
+ * @param Mage_Sales_Model_Quote|null $quote
45
+ * @return bool
46
+ */
47
+ public function isAvailable($quote = null)
48
+ {
49
+ if($quote == null)
50
+ $quote = Mage::getSingleton('checkout/session')->getQuote();
51
+
52
+ $result = (parent::isAvailable($quote) && $this->getConfig()->getLicenseAgreement() && count($quote->getAllVisibleItems()) >= 1);
53
+ if(!$result){
54
+ Mage::getSingleton('core/session')->setKCOMessage("Klarna Checkout is not available");
55
+ return false;
56
+ }
57
+
58
+ if(in_array($quote->getShippingAddress()->getShippingMethod(), $this->getConfig()->getDisallowedShippingMethods())){
59
+ Mage::getSingleton('core/session')->setKCOMessage("Klarna Checkout is not available with selected shipping method");
60
+ return false;
61
+ }
62
+
63
+ if(!Mage::getSingleton('customer/session')->isLoggedIn() && !Mage::helper('checkout')->isAllowedGuestCheckout($quote)){
64
+ Mage::getSingleton('core/session')->setKCOMessage("Please login to use Klarna Checkout");
65
+ Mage::getSingleton('core/session')->setKCORequireLogin(true);
66
+ return false;
67
+ }
68
+
69
+ if (!$quote->validateMinimumAmount()){
70
+ $minimumAmount = Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())
71
+ ->toCurrency(Mage::getStoreConfig('sales/minimum_order/amount'));
72
+
73
+ $msg = Mage::getStoreConfig('sales/minimum_order/description')
74
+ ? Mage::getStoreConfig('sales/minimum_order/description')
75
+ : Mage::helper('checkout')->__('Minimum order amount is %s', $minimumAmount);
76
+
77
+ Mage::getSingleton('core/session')->setKCOMessage($msg);
78
+ return false;
79
+ }
80
+
81
+ if(!$this->helper->getConnectionStatus($this, $quote)){
82
+ Mage::getSingleton('core/session')->setKCOMessage("Klarna Checkout is not available");
83
+ return false;
84
+ }
85
+
86
+ return true;
87
+ }
88
+
89
+ /**
90
+ * Get order model
91
+ *
92
+ * @return Avenla_KlarnaCheckout_Model_Order_Kcov2
93
+ */
94
+ public function getOrderModel()
95
+ {
96
+ $ko = Mage::getModel('klarnaCheckout/order_Kcov2');
97
+ $ko->useConfigForStore($this->getStore());
98
+ return $ko;
99
+ }
100
+
101
+ /**
102
+ * Cancel reservation
103
+ *
104
+ * @param Magento_Sales_Model_Order $mo
105
+ * @return bool
106
+ */
107
+ public function cancelReservation($mo)
108
+ {
109
+ $rno = $this->helper->getReservationNumber($mo);
110
+ return Mage::getModel('klarnaCheckout/api', $this)
111
+ ->cancelReservation($rno, $mo);
112
+ }
113
+
114
+ /**
115
+ * Activate reservation from invoice
116
+ *
117
+ * @param Magento_Sales_Model_Order $mo
118
+ * @param Magento_Sales_Model_Order_Invoice $invoice
119
+ * @return bool
120
+ */
121
+ protected function activateFromInvoice($mo, $invoice)
122
+ {
123
+ return Mage::getModel('klarnaCheckout/api', $this)
124
+ ->activateFromInvoice($mo, $invoice);
125
+ }
126
+
127
+ /**
128
+ * Activate partial reservation
129
+ *
130
+ * @param Magento_Sales_Model_Order $mo
131
+ * @param array $qtys
132
+ * @return bool
133
+ */
134
+ protected function activatePartialReservation($mo, $qtys)
135
+ {
136
+ return Mage::getModel('klarnaCheckout/api', $this)
137
+ ->activatePartialReservation($mo, $qtys);
138
+ }
139
+
140
+ /**
141
+ * Activate full reservation
142
+ *
143
+ * @param Magento_Sales_Model_Order $mo
144
+ * @return bool
145
+ */
146
+ public function activateFullReservation($mo)
147
+ {
148
+ return Mage::getModel('klarnaCheckout/api', $this)
149
+ ->activateFullReservation($mo);
150
+ }
151
+
152
+ /**
153
+ * Credit invoice
154
+ *
155
+ * @param string $invoiceNo
156
+ * @return bool
157
+ */
158
+ protected function creditInvoice($invoiceNo)
159
+ {
160
+ return Mage::getModel('klarnaCheckout/api', $this)
161
+ ->creditInvoice($invoiceNo);
162
+ }
163
+
164
+ /**
165
+ * Credit Klarna invoice partially
166
+ *
167
+ * @param string $invoiceNo
168
+ * @param array $products
169
+ * @param float $adjustment |null
170
+ * @param float $adjustmentTaxRate | null
171
+ * @return bool
172
+ */
173
+ protected function creditPart($invoiceNo, $products, $adjustment = null, $adjustmentTaxRate = null)
174
+ {
175
+ return Mage::getModel('klarnaCheckout/api', $this)
176
+ ->creditPart($invoiceNo, $products, $adjustment, $adjustmentTaxRate);
177
+ }
178
+
179
+ /**
180
+ * Return amount from Klarna invoice
181
+ *
182
+ * @param string $invoiceNo
183
+ * @param float $amount
184
+ * @param float $vat|0
185
+ * @return bool
186
+ */
187
+ protected function returnAmount($invoiceNo, $amount, $vat = 0)
188
+ {
189
+ return Mage::getModel('klarnaCheckout/api', $this)
190
+ ->returnAmount($invoiceNo, $amount, $vat);
191
+ }
192
+
193
+ /**
194
+ * Capture payment
195
+ *
196
+ * @param Varien_Object $payment
197
+ * @param float $amount
198
+ * @return Avenla_KlarnaCheckout_Model_KCO
199
+ */
200
+ public function capture(Varien_Object $payment, $amount)
201
+ {
202
+ $order = $payment->getOrder();
203
+ $this->setStore($order->getStore()->getStoreId());
204
+
205
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION) == null){
206
+ foreach ($order->getInvoiceCollection() as $invoice) {
207
+ if($invoice->getId() == null)
208
+ $inv = $invoice;
209
+ }
210
+
211
+ if(isset($inv))
212
+ $this->activateFromInvoice($order, $inv);
213
+ }
214
+
215
+ if($id = Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION)){
216
+ $payment->setTransactionId($id);
217
+ $payment->setIsTransactionClosed(1);
218
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION);
219
+ }
220
+
221
+ return $this;
222
+ }
223
+
224
+ /**
225
+ * Register KCO save before redund
226
+ *
227
+ * @param $invoice
228
+ * @param Varien_Object $payment
229
+ * @return Avenla_KlarnaCheckout_Model_KCO
230
+ */
231
+ public function processBeforeRefund($invoice, $payment)
232
+ {
233
+ $this->helper->prepareKcoSave();
234
+ return $this;
235
+ }
236
+
237
+ /**
238
+ * Unregister KCO save after redund
239
+ *
240
+ * @param $creditmemo
241
+ * @param Varien_Object $payment
242
+ * @return Avenla_KlarnaCheckout_Model_KCO
243
+ */
244
+ public function processCreditmemo($creditmemo, $payment)
245
+ {
246
+ $this->helper->finishKcoSave();
247
+ return $this;
248
+ }
249
+
250
+ /**
251
+ * Refund specified amount from invoice
252
+ *
253
+ * @param Varien_Object $payment
254
+ * @param float $amount
255
+ * @return Avenla_KlarnaCheckout_Model_KCO
256
+ */
257
+ public function refund(Varien_Object $payment, $amount)
258
+ {
259
+ $order = $payment->getOrder();
260
+ $this->setStore($order->getStore()->getStoreId());
261
+
262
+ if(!$this->helper->isKcoOrder($order))
263
+ return $this;
264
+
265
+ $creditmemo = $payment->getCreditmemo();
266
+ $invoice = $creditmemo->getInvoice();
267
+ $klarnaInvoice = $invoice->getTransactionId();
268
+
269
+ $products = array();
270
+ $result = array();
271
+ $totalRefund = false;
272
+
273
+ if (abs($invoice->getGrandTotal() - $creditmemo->getGrandTotal()) < .0001)
274
+ $totalRefund = true;
275
+
276
+ foreach ($creditmemo->getAllItems() as $item){
277
+ $invoiceItem = Mage::getResourceModel('sales/order_invoice_item_collection')
278
+ ->addAttributeToSelect('*')
279
+ ->setInvoiceFilter($invoice->getId())
280
+ ->addFieldToFilter('order_item_id', $item->getOrderItemId())
281
+ ->getFirstItem();
282
+
283
+ $diff = $item->getQty() - $invoiceItem->getQty();
284
+
285
+ if($diff > 0)
286
+ $totalRefund = false;
287
+
288
+ if($item->getQty() > 0 && !$item->getOrderItem()->isDummy())
289
+ $products[$item->getSku()] = $item->getQty();
290
+ }
291
+
292
+ if($totalRefund){
293
+ $result[] = $this->creditInvoice($klarnaInvoice)
294
+ ? "Refunded Klarna invoice " . $klarnaInvoice
295
+ : "Failed to refund Klarna invoice " . $klarnaInvoice;
296
+ }
297
+ else{
298
+ $fee = null;
299
+ if($creditmemo->getAdjustment() < 0)
300
+ $fee = abs($creditmemo->getAdjustment());
301
+
302
+ if(!empty($products) || $creditmemo->getShippingAmount() > 0){
303
+ if (abs($invoice->getShippingAmount() - $creditmemo->getShippingAmount()) < .0001)
304
+ $products['shipping_fee'] = 1;
305
+
306
+ if($fee != null){
307
+ $response = $this->creditPart($klarnaInvoice, $products, $fee, $this->getConfig()->getReturnTaxRate());
308
+ }
309
+ else{
310
+ $response = $this->creditPart($klarnaInvoice, $products);
311
+ }
312
+
313
+ if($response){
314
+ $t = "Credited products: ";
315
+ foreach($products as $key => $p){
316
+ $t .= $key."(".$p.") ";
317
+ }
318
+ $result[] = $t;
319
+ }
320
+ else{
321
+ $result[] = "Failed to do partial refund";
322
+ }
323
+
324
+ if($creditmemo->getShippingAmount() > 0 && !array_key_exists('shipping_fee', $products)){
325
+ $result[] = $this->returnAmount($klarnaInvoice, $creditmemo->getShippingAmount(), Mage::helper('klarnaCheckout')->getShippingVatRate())
326
+ ? "Refunded amount of " . $creditmemo->getShippingAmount() . " from shipment on Klarna invoice " . $klarnaInvoice
327
+ : "Failed to refund amount of " . $creditmemo->getShippingAmount() . " from shipment on Klarna invoice " . $klarnaInvoice;
328
+ }
329
+ }
330
+ if($creditmemo->getAdjustment() > 0){
331
+ $result[] = $this->returnAmount($klarnaInvoice, $creditmemo->getAdjustment(), $this->getConfig()->getReturnTaxRate())
332
+ ? "Refunded amount of " . $creditmemo->getAdjustment() . " on Klarna invoice " . $klarnaInvoice
333
+ : "Failed to refund amount of " . $creditmemo->getAdjustment() . " on Klarna invoice " . $klarnaInvoice;
334
+ }
335
+ }
336
+
337
+ if(!empty($result)) {
338
+ foreach($result as $msg){
339
+ $order->addStatusHistoryComment($msg);
340
+ }
341
+ $order->save();
342
+ }
343
+
344
+ return $this;
345
+ }
346
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Payment/KCOv3.php ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+
22
+ class Avenla_KlarnaCheckout_Model_Payment_KCOv3 extends Avenla_KlarnaCheckout_Model_Payment_KCO
23
+ {
24
+ protected $_code = 'klarnaCheckout_payment_v3';
25
+
26
+ /**
27
+ * Get order model
28
+ *
29
+ * @return Avenla_KlarnaCheckout_Model_Order_Kcov3
30
+ */
31
+ public function getOrderModel()
32
+ {
33
+ $ko = Mage::getModel('klarnaCheckout/order_Kcov3');
34
+ $ko->useConfigForStore($this->getStore());
35
+ return $ko;
36
+ }
37
+
38
+ /**
39
+ * Cancel Klarna reservation
40
+ *
41
+ * @param Mage_Sales_Model_Order $mo
42
+ * @return bool
43
+ */
44
+ public function cancelReservation($mo)
45
+ {
46
+ $klarnaOrderId = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
47
+ $ko = $this->getOrderModel();
48
+ $order = $ko->getManagement($klarnaOrderId);
49
+ $rno = $order['klarna_reference'];
50
+ $this->helper->prepareKcoSave();
51
+
52
+ if(!$order['remaining_authorized_amount'])
53
+ return false;
54
+
55
+ try {
56
+ if(!empty($order['captures'])){
57
+ $response = $order->releaseRemainingAuthorization();
58
+ }
59
+ else{
60
+ $response = $order->cancel();
61
+ }
62
+
63
+ $mo->addStatusHistoryComment(
64
+ $this->helper->__('Klarna reservation <b>%s</b> was canceled.', $rno)
65
+ );
66
+ $mo->save();
67
+ $this->helper->finishKcoSave();
68
+ return true;
69
+ }
70
+ catch(Exception $e) {
71
+ $this->helper->logException($e);
72
+ $mo->addStatusHistoryComment(
73
+ $this->helper->__('Failed to cancel Klarna reservation <b>%s</b>.(%s - %s)',
74
+ $rno,
75
+ $e->getMessage(),
76
+ $e->getCode()
77
+ )
78
+ );
79
+ $mo->save();
80
+ $this->helper->finishKcoSave();
81
+
82
+ return false;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Activate reservation from Magento invoice
88
+ *
89
+ * @param Magento_Sales_Order $mo
90
+ * @param Magento_Sales_Order_Invoice $invoice
91
+ * @return bool
92
+ */
93
+ protected function activateFromInvoice($mo, $invoice)
94
+ {
95
+ if(!$this->helper->isKcoOrder($mo))
96
+ return $this;
97
+
98
+ $klarnaOrderId = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
99
+ $ko = $this->getOrderModel();
100
+ $order = $ko->getManagement($klarnaOrderId);
101
+ $request = new Varien_Object();
102
+
103
+ if(!$order['remaining_authorized_amount'])
104
+ return false;
105
+
106
+ if (abs($mo->getTotalDue() - $invoice->getGrandTotal()) > .0001){
107
+ $capturedAmount = $this->helper->formatPriceForKlarna($invoice->getBaseGrandTotal());
108
+ $request->setCapturedAmount($capturedAmount);
109
+ $request->setDescription($this->helper->__("Partial capture from invoice %s", $invoice->getIncrementId()));
110
+ }
111
+ else{
112
+ $request->setCapturedAmount($order['remaining_authorized_amount']);
113
+ $request->setDescription($this->helper->__('Order complete after invoice'));
114
+ $request->setOrderLines($order['order_lines']);
115
+ }
116
+
117
+ try{
118
+ $response = $order->createCapture($request->getData());
119
+ $location = $response->getLocation();
120
+ $captureId = end(explode("/", $location));
121
+ $capture = $order->fetchCapture($captureId);
122
+
123
+ if(!$capture->getId())
124
+ Mage::throwException("Capture not found");
125
+
126
+ $amount = $capture["captured_amount"];
127
+ $result = array('', $captureId);
128
+
129
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_INVOICE) != null)
130
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_INVOICE);
131
+
132
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_INVOICE, $result[1]);
133
+
134
+ $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
135
+ $klarnainvoices[$result[1]] = array(
136
+ 'invoice' => $result[1],
137
+ 'risk' => $result[0]
138
+ );
139
+
140
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION) != null)
141
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION);
142
+
143
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION, $result[1]);
144
+
145
+ $mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
146
+ $mo = $this->checkExpiration($mo);
147
+
148
+ $mo->save();
149
+
150
+ return true;
151
+ }
152
+ catch(Exception $e){
153
+ $this->helper->logException($e);
154
+ $mo->addStatusHistoryComment(
155
+ $this->helper->__('Failed to activate reservation (' . $e->getMessage() . ')')
156
+ );
157
+ $mo->save();
158
+
159
+ return false;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Do partial activation
165
+ *
166
+ * @param Magento_Sales_Order $mo
167
+ * @param array $qtys
168
+ * @return bool
169
+ */
170
+ protected function activatePartialReservation($mo, $qtys)
171
+ {
172
+ if(!$this->getConfig()->activatePartial())
173
+ return false;
174
+
175
+ $klarnaOrderId = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
176
+ $ko = $this->getOrderModel();
177
+ $order = $ko->getManagement($klarnaOrderId);
178
+
179
+ if(!$order['remaining_authorized_amount'])
180
+ return false;
181
+
182
+ $invoice = Mage::getModel('sales/service_order', $mo)->prepareInvoice($qtys);
183
+ if (!$invoice->getTotalQty())
184
+ Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products'));
185
+
186
+ $capturedAmount = $this->helper->formatPriceForKlarna($invoice->getBaseGrandTotal());
187
+
188
+ $request = new Varien_Object();
189
+ $request->setCapturedAmount($capturedAmount);
190
+ $request->setDescription($this->helper->__("Partial capture"));
191
+
192
+ try{
193
+ $response = $order->createCapture($request->getData());
194
+ $location = $response->getLocation();
195
+ $captureId = end(explode("/", $location));
196
+ $capture = $order->fetchCapture($captureId);
197
+
198
+ if(!$capture->getId())
199
+ Mage::throwException("Capture not found");
200
+
201
+ $amount = $capture["captured_amount"];
202
+ $result = array('', $captureId);
203
+
204
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION) != null)
205
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION);
206
+
207
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION, $result[1]);
208
+
209
+ $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
210
+ $invoice->register();
211
+ $mo->getPayment()->setTransactionId($result[1]);
212
+
213
+ Mage::getModel('core/resource_transaction')
214
+ ->addObject($invoice)
215
+ ->addObject($invoice->getOrder())
216
+ ->save();
217
+
218
+ $invoice->save();
219
+
220
+ $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
221
+ $klarnainvoices[$invoice->getId()] = array(
222
+ 'invoice' => $result[1]
223
+ );
224
+
225
+ $mo->addStatusHistoryComment($this->helper->__('Created Klarna invoice %s', $result[1]));
226
+ $mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
227
+
228
+ $mo->save();
229
+
230
+ return true;
231
+ }
232
+ catch(Exception $e) {
233
+ $this->helper->logException($e);
234
+ return false;
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Do full activation
240
+ *
241
+ * @param Magento_Sales_Order $mo
242
+ * @return bool
243
+ */
244
+ public function activateFullReservation($mo)
245
+ {
246
+ $klarnaOrderId = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
247
+ $ko = $this->getOrderModel();
248
+ $order = $ko->getManagement($klarnaOrderId);
249
+
250
+ if(!$order['remaining_authorized_amount'])
251
+ return false;
252
+
253
+ $request = new Varien_Object();
254
+ $request->setCapturedAmount($order['remaining_authorized_amount']);
255
+ $request->setDescription($this->helper->__('Order complete'));
256
+ $request->setOrderLines($order['order_lines']);
257
+
258
+ try{
259
+ $response = $order->createCapture($request->getData());
260
+ $location = $response->getLocation();
261
+ $captureId = end(explode("/", $location));
262
+ $capture = $order->fetchCapture($captureId);
263
+
264
+ if(!$capture->getId())
265
+ Mage::throwException("Capture not found");
266
+
267
+ $amount = $capture["captured_amount"];
268
+ $result = array('', $captureId);
269
+ $mo = $this->createMageInvoice($mo, $result);
270
+ $mo->save();
271
+
272
+ return true;
273
+ }
274
+ catch(Exception $e) {
275
+ $this->helper->logException($e);
276
+ return false;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Refund specified amount from invoice
282
+ *
283
+ * @param Varien_Object $payment
284
+ * @param float $amount
285
+ * @return Avenla_KlarnaCheckout_Model_KCOv3
286
+ */
287
+ public function refund(Varien_Object $payment, $amount)
288
+ {
289
+ $mo = $payment->getOrder();
290
+ $this->setStore($mo->getStore()->getStoreId());
291
+
292
+ if(!$this->helper->isKcoOrder($mo))
293
+ return $this;
294
+
295
+ $creditmemo = $payment->getCreditmemo();
296
+ $invoice = $creditmemo->getInvoice();
297
+ $captureId = $invoice->getTransactionId();
298
+ $klarnaOrderId = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
299
+ $ko = $this->getOrderModel();
300
+ $order = $ko->getManagement($klarnaOrderId);
301
+ $capture = $order->fetchCapture($captureId);
302
+ $products = array();
303
+
304
+ foreach ($creditmemo->getAllItems() as $item){
305
+ $products[] = $item->getSku();
306
+ }
307
+
308
+ $orderLines = array();
309
+ foreach($capture['order_lines'] as $oLine){
310
+ if(in_array($oLine['reference'], $products))
311
+ $orderLines[] = $oLine;
312
+ }
313
+
314
+ $description = $this->helper->__("Refunded capture %s", $capture['klarna_reference']);
315
+ $refundedAmount = $this->helper->formatPriceForKlarna($creditmemo->getBaseGrandTotal());
316
+ $request = new Varien_Object();
317
+ $request->setRefundedAmount($refundedAmount);
318
+ $request->setDescription($description);
319
+ if(!empty($orderLines))
320
+ $request->setOrderLines($orderLines);
321
+
322
+ try{
323
+ $response = $order->refund($request->getData());
324
+ $mo->addStatusHistoryComment($description);
325
+ $mo->save();
326
+
327
+ return $this;
328
+ }
329
+ catch(Exception $e) {
330
+ $this->helper->logException($e);
331
+ return false;
332
+ }
333
+
334
+ return $this;
335
+ }
336
+
337
+ /**
338
+ * Create invoice for Magento order
339
+ *
340
+ * @param Magento_Sales_Order $mo
341
+ * @param array $result
342
+ * @param array $qtys|null
343
+ * @return Magento_Sales_Order
344
+ */
345
+ private function createMageInvoice($mo, $result, $qtys = null)
346
+ {
347
+ $invoice = Mage::getModel('sales/service_order', $mo)->prepareInvoice($qtys);
348
+
349
+ if (!$invoice->getTotalQty())
350
+ Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products'));
351
+
352
+ if(Mage::registry(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION) != null)
353
+ Mage::unregister(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION);
354
+
355
+ Mage::register(Avenla_KlarnaCheckout_Model_Payment_Abstract::REGISTRY_KEY_TRANSACTION, $result[1]);
356
+ $amount = $invoice->getBaseGrandTotal();
357
+ $invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
358
+ $invoice->register();
359
+
360
+ $mo->getPayment()->setTransactionId($result[1]);
361
+
362
+ Mage::getModel('core/resource_transaction')
363
+ ->addObject($invoice)
364
+ ->addObject($invoice->getOrder())
365
+ ->save();
366
+
367
+ $invoice->save();
368
+
369
+ $klarnainvoices = $this->helper->getKlarnaInvoices($mo);
370
+ $klarnainvoices[$invoice->getId()] = array(
371
+ 'invoice' => $result[1]
372
+ );
373
+
374
+ $mo->addStatusHistoryComment($this->helper->__('Created Klarna invoice %s', $result[1]));
375
+ $mo = $this->helper->saveKlarnaInvoices($mo, $klarnainvoices);
376
+
377
+ return $mo;
378
+ }
379
+
380
+ /**
381
+ * Check reservation expiration
382
+ *
383
+ * @param Magento_Sales_Order $mo
384
+ * @return Magento_Sales_Order
385
+ */
386
+ private function checkExpiration($mo)
387
+ {
388
+ if(!$this->helper->isKcoOrder($mo))
389
+ return $mo;
390
+
391
+ $klarnaOrderId = $mo->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_ORDER_ID);
392
+ $kco = $mo->getPayment()->getMethodInstance()->getOrderModel();
393
+ $kco->useConfigForStore($mo->getStore()->getId());
394
+ $info = $kco->getOrderInformation($klarnaOrderId);
395
+ $expr = $info->getExpiration();
396
+
397
+ if(new Zend_Date($expr) < new Zend_Date()){
398
+ $formattedExpiration = Mage::helper('core')->formatDate($expr,'medium', false);
399
+
400
+ $mo->getPayment()->setAdditionalInformation(
401
+ Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_KLARNA_MESSAGE,
402
+ 'Reservation was activated after expiration (expired '.$formattedExpiration.')'
403
+ );
404
+ }
405
+
406
+ return $mo;
407
+ }
408
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Source/AnalyticsType.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -18,21 +18,20 @@
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
-
22
  class Avenla_KlarnaCheckout_Model_Source_AnalyticsType
23
  {
24
- public function toOptionArray()
25
- {
26
- return array(
27
- array(
28
- 'value' => Avenla_KlarnaCheckout_Model_Config::ANALYTICS_UNIVERSAL,
29
- 'label' => Mage::helper('klarnaCheckout')->__('Universal Analytics')
30
- ),
31
- array(
32
- 'value' => Avenla_KlarnaCheckout_Model_Config::ANALYTICS_CLASSIC,
33
- 'label' => Mage::helper('klarnaCheckout')->__('Google Analytics')
34
- )
35
- );
36
- }
37
-
38
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
+
22
  class Avenla_KlarnaCheckout_Model_Source_AnalyticsType
23
  {
24
+ public function toOptionArray()
25
+ {
26
+ return array(
27
+ array(
28
+ 'value' => Avenla_KlarnaCheckout_Model_Config::ANALYTICS_UNIVERSAL,
29
+ 'label' => Mage::helper('klarnaCheckout')->__('Universal Analytics')
30
+ ),
31
+ array(
32
+ 'value' => Avenla_KlarnaCheckout_Model_Config::ANALYTICS_CLASSIC,
33
+ 'label' => Mage::helper('klarnaCheckout')->__('Google Analytics')
34
+ )
35
+ );
36
+ }
 
37
  }
app/code/community/Avenla/KlarnaCheckout/Model/Source/Api.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+
22
+ class Avenla_KlarnaCheckout_Model_Source_Api
23
+ {
24
+ public function toOptionArray()
25
+ {
26
+ $kco2Countries = "FI, SE, NO, DE, AT";
27
+
28
+ return array(
29
+ array(
30
+ 'label' => 'KCO v2 ('. $kco2Countries .')',
31
+ 'value' => Avenla_KlarnaCheckout_Model_Config::API_TYPE_KCOV2
32
+ ),
33
+ array(
34
+ 'label' => 'KCO v3 (UK)',
35
+ 'value' => Avenla_KlarnaCheckout_Model_Config::API_TYPE_KCOV3_UK,
36
+ ),
37
+ array(
38
+ 'label' => 'KCO v3 (US)',
39
+ 'value' => Avenla_KlarnaCheckout_Model_Config::API_TYPE_KCOV3_US,
40
+ )
41
+ );
42
+ }
43
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Source/Countries.php DELETED
@@ -1,50 +0,0 @@
1
- <?php
2
- /**
3
- * This file is released under a custom license by Avenla Oy.
4
- * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
- * For questions and support - klarna-support@avenla.com
8
- *
9
- * @category Avenla
10
- * @package Avenla_KlarnaCheckout
11
- * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
- */
14
-
15
- /**
16
- * Avenla KlarnaCheckout
17
- *
18
- * @category Avenla
19
- * @package Avenla_KlarnaCheckout
20
- */
21
-
22
- class Avenla_KlarnaCheckout_Model_Source_Countries
23
- {
24
- public function toOptionArray()
25
- {
26
- return array(
27
- array(
28
- 'label' => Mage::helper('core')->__('Norway'),
29
- 'value' => 'NO'
30
- ),
31
- array(
32
- 'label' => Mage::helper('core')->__('Sweden'),
33
- 'value' => 'SE'
34
- ),
35
- array(
36
- 'label' => Mage::helper('core')->__('Finland'),
37
- 'value' => 'FI'
38
- ),
39
- array(
40
- 'label' => Mage::helper('core')->__('Germany'),
41
- 'value' => 'DE'
42
- ),
43
- array(
44
- 'label' => Mage::helper('core')->__('Austria'),
45
- 'value' => 'AT'
46
- )
47
- );
48
- }
49
-
50
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Avenla/KlarnaCheckout/Model/Source/Kcolayout.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -18,12 +18,12 @@
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
-
22
  class Avenla_KlarnaCheckout_Model_Source_Kcolayout
23
  {
24
- public function toOptionArray()
25
- {
26
- $options = array(
27
  array(
28
  'label' => Mage::helper('klarnaCheckout')->__('Default'),
29
  'value' => 'default'
@@ -35,5 +35,5 @@ class Avenla_KlarnaCheckout_Model_Source_Kcolayout
35
  );
36
 
37
  return $options;
38
- }
39
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
+
22
  class Avenla_KlarnaCheckout_Model_Source_Kcolayout
23
  {
24
+ public function toOptionArray()
25
+ {
26
+ $options = array(
27
  array(
28
  'label' => Mage::helper('klarnaCheckout')->__('Default'),
29
  'value' => 'default'
35
  );
36
 
37
  return $options;
38
+ }
39
  }
app/code/community/Avenla/KlarnaCheckout/Model/Source/Orderlocale.php DELETED
@@ -1,49 +0,0 @@
1
- <?php
2
- /**
3
- * This file is released under a custom license by Avenla Oy.
4
- * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
- * For questions and support - klarna-support@avenla.com
8
- *
9
- * @category Avenla
10
- * @package Avenla_KlarnaCheckout
11
- * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
- */
14
-
15
- /**
16
- * Avenla KlarnaCheckout
17
- *
18
- * @category Avenla
19
- * @package Avenla_KlarnaCheckout
20
- */
21
-
22
- class Avenla_KlarnaCheckout_Model_Source_Orderlocale
23
- {
24
- public function toOptionArray()
25
- {
26
- return array(
27
- array(
28
- 'label' => Mage::app()->getLocale()->getCountryTranslation('FI'),
29
- 'value' => 'fi-fi'
30
- ),
31
- array(
32
- 'label' => Mage::app()->getLocale()->getCountryTranslation('SE'),
33
- 'value' => 'sv-se'
34
- ),
35
- array(
36
- 'label' => Mage::app()->getLocale()->getCountryTranslation('NO'),
37
- 'value' => 'nb-no'
38
- ),
39
- array(
40
- 'label' => Mage::app()->getLocale()->getCountryTranslation('DE'),
41
- 'value' => 'de-de'
42
- ),
43
- array(
44
- 'label' => Mage::app()->getLocale()->getCountryTranslation('AT'),
45
- 'value' => 'de-at'
46
- )
47
- );
48
- }
49
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Avenla/KlarnaCheckout/Model/Source/Pplayout.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -18,19 +18,18 @@
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
-
22
  class Avenla_KlarnaCheckout_Model_Source_Pplayout
23
  {
24
- public function toOptionArray()
25
- {
26
- $options = array();
27
-
28
- $layouts = array(
29
- 'Pale',
30
- 'Dark',
31
- 'Deep',
32
- 'Deep-extra'
33
- );
34
 
35
  foreach($layouts as $layout){
36
  $options[] = array(
@@ -38,8 +37,7 @@ class Avenla_KlarnaCheckout_Model_Source_Pplayout
38
  'value' => strtolower($layout)
39
  );
40
  }
41
-
42
- return $options;
43
- }
44
 
45
- }
 
 
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
+
22
  class Avenla_KlarnaCheckout_Model_Source_Pplayout
23
  {
24
+ public function toOptionArray()
25
+ {
26
+ $options = array();
27
+ $layouts = array(
28
+ 'Pale',
29
+ 'Dark',
30
+ 'Deep',
31
+ 'Deep-extra'
32
+ );
 
33
 
34
  foreach($layouts as $layout){
35
  $options[] = array(
37
  'value' => strtolower($layout)
38
  );
39
  }
 
 
 
40
 
41
+ return $options;
42
+ }
43
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Source/Ppwidget.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -18,29 +18,28 @@
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
-
22
  class Avenla_KlarnaCheckout_Model_Source_Ppwidget
23
  {
24
- public function toOptionArray()
25
- {
26
- return array(
27
- array(
28
- 'label' => "No",
29
- 'value' => 'no'
30
- ),
31
- array(
32
- 'label' => Mage::helper('klarnaCheckout')->__("Klarna widget"),
33
- 'value' => 'klarna'
34
- ),
35
- array(
36
- 'label' => Mage::helper('klarnaCheckout')->__("Custom widget on product page"),
37
- 'value' => 'product'
38
- ),
39
- array(
40
- 'label' => Mage::helper('klarnaCheckout')->__("Custom widget on product page and product listing"),
41
- 'value' => 'product_list'
42
- )
43
- );
44
- }
45
-
46
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
+
22
  class Avenla_KlarnaCheckout_Model_Source_Ppwidget
23
  {
24
+ public function toOptionArray()
25
+ {
26
+ return array(
27
+ array(
28
+ 'label' => "No",
29
+ 'value' => false
30
+ ),
31
+ array(
32
+ 'label' => Mage::helper('klarnaCheckout')->__("Klarna widget"),
33
+ 'value' => Avenla_KlarnaCheckout_Model_Config::WIDGET_TYPE_KLARNA
34
+ ),
35
+ array(
36
+ 'label' => Mage::helper('klarnaCheckout')->__("Custom widget on product page"),
37
+ 'value' => Avenla_KlarnaCheckout_Model_Config::WIDGET_TYPE_PRODUCT
38
+ ),
39
+ array(
40
+ 'label' => Mage::helper('klarnaCheckout')->__("Custom widget on product page and product listing"),
41
+ 'value' => Avenla_KlarnaCheckout_Model_Config::WIDGET_TYPE_LIST
42
+ )
43
+ );
44
+ }
 
45
  }
app/code/community/Avenla/KlarnaCheckout/Model/Source/Servermode.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -21,17 +21,17 @@
21
 
22
  class Avenla_KlarnaCheckout_Model_Source_Servermode
23
  {
24
- public function toOptionArray()
25
- {
26
- return array(
27
- array(
28
- 'label' => 'Live',
29
- 'value' => 'LIVE'
30
- ),
31
- array(
32
- 'label' => 'Testdrive',
33
- 'value' => 'DEMO',
34
- )
35
- );
36
- }
37
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
21
 
22
  class Avenla_KlarnaCheckout_Model_Source_Servermode
23
  {
24
+ public function toOptionArray()
25
+ {
26
+ return array(
27
+ array(
28
+ 'label' => 'Live',
29
+ 'value' => 'LIVE'
30
+ ),
31
+ array(
32
+ 'label' => 'Testdrive',
33
+ 'value' => 'DEMO',
34
+ )
35
+ );
36
+ }
37
  }
app/code/community/Avenla/KlarnaCheckout/Model/Source/Shippingmethods.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,29 +20,29 @@
20
  */
21
 
22
  class Avenla_KlarnaCheckout_Model_Source_Shippingmethods
23
- {
24
- public function toOptionArray()
25
- {
26
- $methods = Mage::getSingleton('shipping/config')->getActiveCarriers();
27
- $options = array();
28
 
29
- foreach($methods as $_code => $_method){
30
- if ($methods = $_method->getAllowedMethods()){
31
- foreach ($methods as $_mcode => $_mname){
32
- $code = $_code . '_' . $_mcode;
33
- $title = $_mname;
34
 
35
- if(!$title = Mage::getStoreConfig("carriers/$_code/title"))
36
- $title = $_code;
37
 
38
- $options[] = array(
39
- 'value' => $code,
40
- 'label' => $title
41
- );
42
- }
43
- }
44
- }
45
 
46
- return $options;
47
- }
48
- }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
 
22
  class Avenla_KlarnaCheckout_Model_Source_Shippingmethods
23
+ {
24
+ public function toOptionArray()
25
+ {
26
+ $methods = Mage::getSingleton('shipping/config')->getActiveCarriers();
27
+ $options = array();
28
 
29
+ foreach($methods as $_code => $_method){
30
+ if ($methods = $_method->getAllowedMethods()){
31
+ foreach ($methods as $_mcode => $_mname){
32
+ $code = $_code . '_' . $_mcode;
33
+ $title = $_mname;
34
 
35
+ if(!$title = Mage::getStoreConfig("carriers/$_code/title"))
36
+ $title = $_code;
37
 
38
+ $options[] = array(
39
+ 'value' => $code,
40
+ 'label' => $title
41
+ );
42
+ }
43
+ }
44
+ }
45
 
46
+ return $options;
47
+ }
48
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Source/Taxclass.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -18,12 +18,12 @@
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
-
22
  class Avenla_KlarnaCheckout_Model_Source_Taxclass
23
  {
24
- public function toOptionArray()
25
- {
26
- $options = Mage::getModel('tax/class_source_product')->toOptionArray();
27
- return $options;
28
- }
29
- }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
18
  * @category Avenla
19
  * @package Avenla_KlarnaCheckout
20
  */
21
+
22
  class Avenla_KlarnaCheckout_Model_Source_Taxclass
23
  {
24
+ public function toOptionArray()
25
+ {
26
+ $options = Mage::getModel('tax/class_source_product')->toOptionArray();
27
+ return $options;
28
+ }
29
+ }
app/code/community/Avenla/KlarnaCheckout/Model/Validator.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,72 +20,94 @@
20
  */
21
 
22
  class Avenla_KlarnaCheckout_Model_Validator extends Mage_Core_Model_Abstract
23
- {
24
 
25
- /**
26
- * Parse Klarna order for validation
27
- *
28
- * @return object
29
- */
30
  public function parseValidationPost()
31
- {
32
- $rawrequestBody = file_get_contents('php://input');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- if (mb_detect_encoding($rawrequestBody, 'UTF-8', true)){
35
- $order = json_decode($rawrequestBody);
36
- }
37
- else {
38
- $rawrequestBody = iconv("ISO-8859-1", "UTF-8", $rawrequestBody);
39
- $order = json_decode($rawrequestBody);
40
- }
41
 
42
- return $order;
43
- }
 
 
 
44
 
45
- /**
46
- * Validate quote
47
- *
48
- * @param Mage_Sales_Model_Quote
49
- * @return bool
50
- */
51
- public function validateQuote($quote, $ko)
52
- {
53
- if(!isset($ko->shipping_address->phone) || !isset($ko->billing_address->phone)){
54
- $msg = Mage::helper('klarnaCheckout')->__('Please fill in your phone number.');
55
- $this->setErrorMessage($quote, $msg);
56
- return false;
57
- }
58
-
59
- if (!$quote->isVirtual()){
60
- $address = $quote->getShippingAddress();
61
- $method= $address->getShippingMethod();
62
- $rate = $address->getShippingRateByCode($method);
63
-
64
- if (!$quote->isVirtual() && (!$method || !$rate)){
65
- $msg = Mage::helper('sales')->__('Please specify a shipping method.');
66
- $this->setErrorMessage($quote, $msg);
67
- return false;
68
- }
69
 
70
- if($quote->getShippingAddress()->getPostcode() != $ko->shipping_address->postal_code){
71
- $msg = Mage::helper('klarnaCheckout')->__('Please use the same post code for your quote and Klarna.');
72
- $this->setErrorMessage($quote, $msg);
73
- return false;
74
- }
75
- }
76
-
77
- return true;
78
- }
79
 
80
- /**
81
- * Set error message to quote payment data
82
- *
83
- * @param Mage_Sales_Model_Quote
84
- * @param string
85
- */
86
- private function setErrorMessage($quote, $message)
87
- {
88
- $quote->getPayment()->setAdditionalInformation("kco_validation_message", $message);
89
- $quote->getPayment()->save();
90
- }
 
 
 
 
 
 
91
  }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
 
22
  class Avenla_KlarnaCheckout_Model_Validator extends Mage_Core_Model_Abstract
23
+ {
24
 
25
+ /**
26
+ * Parse Klarna order for validation
27
+ *
28
+ * @return object
29
+ */
30
  public function parseValidationPost()
31
+ {
32
+ $rawrequestBody = file_get_contents('php://input');
33
+
34
+ if (mb_detect_encoding($rawrequestBody, 'UTF-8', true)){
35
+ $order = json_decode($rawrequestBody);
36
+ }
37
+ else {
38
+ $rawrequestBody = iconv("ISO-8859-1", "UTF-8", $rawrequestBody);
39
+ $order = json_decode($rawrequestBody);
40
+ }
41
+
42
+ return $order;
43
+ }
44
+
45
+ /**
46
+ * Validate quote
47
+ *
48
+ * @param Mage_Sales_Model_Quote $quote
49
+ * @param object $ko|null
50
+ * @return bool
51
+ */
52
+ public function validateQuote($quote, $ko = null)
53
+ {
54
+ $result = true;
55
+ if($ko){
56
+ if(!isset($ko->shipping_address->phone) || !isset($ko->billing_address->phone)){
57
+ $msg = Mage::helper('klarnaCheckout')->__('Please fill in your phone number.');
58
+ $this->setErrorMessage($quote, $msg);
59
+ $result = false;
60
+ }
61
+ }
62
+
63
+ if(!$quote->isVirtual()){
64
+
65
+ $address = $quote->getShippingAddress();
66
+ $method = $address->getShippingMethod();
67
+ $rate = $address->getShippingRateByCode($method);
68
+
69
+ if($address->getPostcode() == null){
70
+ $msg = Mage::helper('klarnaCheckout')->__("Please fill in your post code");
71
+ $result = false;
72
+ }
73
+
74
+ if($ko && $address->getPostcode() != $ko->shipping_address->postal_code){
75
+ $msg = Mage::helper('klarnaCheckout')->__('Please use the same post code for your quote and Klarna.');
76
+ return false;
77
+ }
78
 
79
+ if($address->getCountry() == null){
80
+ $msg = Mage::helper('klarnaCheckout')->__("Please select country");
81
+ $result = false;
82
+ }
 
 
 
83
 
84
+ if (!$method || !$rate){
85
+ $msg = Mage::helper('klarnaCheckout')->__("Please select shipping method to use Klarna Checkout");
86
+ $result = false;
87
+ }
88
+ }
89
 
90
+ if(isset($msg))
91
+ $this->setErrorMessage($quote, $msg, $ko != null);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
+ return $result;
94
+ }
 
 
 
 
 
 
 
95
 
96
+ /**
97
+ * Set error message to quote or customer session
98
+ *
99
+ * @param Mage_Sales_Model_Quote
100
+ * @param string $message
101
+ * @param bool $toQuote|null
102
+ */
103
+ private function setErrorMessage($quote, $message, $toQuote = false)
104
+ {
105
+ if($toQuote){
106
+ $quote->getPayment()->setAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_VALIDATION_MSG, $message);
107
+ $quote->getPayment()->save();
108
+ }
109
+ else{
110
+ Mage::getSingleton('core/session')->setKCOMessage($message);
111
+ }
112
+ }
113
  }
app/code/community/Avenla/KlarnaCheckout/controllers/Adminhtml/KCOController.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
- /**
3
- * This file is released under a custom license by Avenla Oy.
4
- * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
- * For questions and support - klarna-support@avenla.com
8
- *
9
- * @category Avenla
10
- * @package Avenla_KlarnaCheckout
11
- * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
- */
14
-
15
- /**
16
- * Avenla KlarnaCheckout
17
- *
18
- * @category Avenla
19
- * @package Avenla_KlarnaCheckout
20
- */
21
- class Avenla_KlarnaCheckout_Adminhtml_KCOController extends Mage_Adminhtml_Controller_Action
22
- {
23
- /**
24
- * Update Klarna PClasses
25
- *
26
- */
27
- public function updatePClassesAction()
28
- {
29
- $result = Mage::getModel('klarnaCheckout/api')->updatePClasses();
30
- Mage::app()->getResponse()->setBody($result);
31
- }
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Avenla/KlarnaCheckout/controllers/Adminhtml/KlarnaCheckout/KCOController.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This file is released under a custom license by Avenla Oy.
4
+ * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
+ * For questions and support - klarna-support@avenla.com
8
+ *
9
+ * @category Avenla
10
+ * @package Avenla_KlarnaCheckout
11
+ * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
+ */
14
+
15
+ /**
16
+ * Avenla KlarnaCheckout
17
+ *
18
+ * @category Avenla
19
+ * @package Avenla_KlarnaCheckout
20
+ */
21
+ class Avenla_KlarnaCheckout_Adminhtml_KlarnaCheckout_KCOController extends Mage_Adminhtml_Controller_Action
22
+ {
23
+ /**
24
+ * Update Klarna PClasses
25
+ *
26
+ */
27
+ public function updatePClassesAction()
28
+ {
29
+ $result = Mage::getModel('klarnaCheckout/api')->updatePClasses();
30
+ Mage::app()->getResponse()->setBody($result);
31
+ }
32
+
33
+ /**
34
+ * Activate Klarna reservation
35
+ *
36
+ */
37
+ public function activateReservationAction()
38
+ {
39
+ try {
40
+ if($orderId = $this->getRequest()->getParam('order_id')){
41
+ $order = Mage::getModel('sales/order')->load($orderId);
42
+ if(Mage::helper('klarnaCheckout')->isKcoOrder($order)){
43
+ $method = $order->getPayment()->getMethodInstance()->setStore($order->getStore());
44
+ $method->activateFullReservation($order);
45
+ }
46
+ else{
47
+ $this->_getSession()->addError($this->__('Order was not placed with Klarna Checkout'));
48
+ }
49
+ }
50
+ else{
51
+ $this->_getSession()->addError($this->__('No order found'));
52
+ }
53
+ }
54
+ catch(Exception $e) {
55
+ Mage::helper('klarnaCheckout')->logException($e);
56
+ $this->_getSession()->addError($this->__($e->getMessage()));
57
+ }
58
+
59
+ $this->_redirectReferer();
60
+ }
61
+ }
app/code/community/Avenla/KlarnaCheckout/controllers/CartController.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -27,47 +27,45 @@ class Avenla_KlarnaCheckout_CartController extends Mage_Checkout_CartController
27
  */
28
  public function estimateAjaxPostAction()
29
  {
30
- $country = (string) $this->getRequest()->getParam('country_id');
31
- $postcode = (string) $this->getRequest()->getParam('estimate_postcode');
32
- $city = (string) $this->getRequest()->getParam('estimate_city');
33
- $regionId = (string) $this->getRequest()->getParam('region_id');
34
- $region = (string) $this->getRequest()->getParam('region');
35
 
36
  $this->_getQuote()->getShippingAddress()
37
- ->setCountryId($country)
38
- ->setCity($city)
39
- ->setPostcode($postcode)
40
- ->setRegionId($regionId)
41
- ->setRegion($region)
42
- ->setCollectShippingRates(true);
43
-
44
  $this->_getQuote()->save();
45
  $this->_getCart()->save();
46
-
47
  $this->getResponse()->setBody($this->getEncodedResponse());
48
  }
49
 
50
-
51
  /**
52
- * Estimate update action
53
- */
54
  public function estimateUpdateAjaxPostAction()
55
  {
56
  $code = (string) $this->getRequest()->getParam('estimate_method');
57
 
58
- if (!empty($code)) {
59
- $this->_getQuote()->getShippingAddress()->setShippingMethod($code)->save();
60
- }
61
-
62
- $cart = $this->_getCart();
63
- $cart->save();
64
 
65
  $this->getResponse()->setBody($this->getEncodedResponse());
66
  }
67
 
68
  /**
69
  * Get response array
70
- *
71
  * @return array
72
  */
73
  private function getEncodedResponse()
@@ -80,25 +78,25 @@ class Avenla_KlarnaCheckout_CartController extends Mage_Checkout_CartController
80
 
81
  return Mage::helper('core')->jsonEncode($resp);
82
  }
83
-
84
  /**
85
  * Get shipping html
86
- *
87
  * @return string
88
  */
89
  private function getShippingHtml()
90
  {
91
  $layout = $this->getLayout();
92
  $layout->getMessagesBlock()->setMessages(Mage::getSingleton('checkout/session')
93
- ->getMessages(true),Mage::getSingleton('catalog/session')->getMessages(true));
94
  $block = $this->getLayout()->createBlock('checkout/cart_shipping')->setTemplate('KCO/cart/shipping.phtml');
95
 
96
  return $block->toHtml();
97
  }
98
-
99
  /**
100
  * Get review html
101
- *
102
  * @return string
103
  */
104
  private function getTotalsHtml()
@@ -110,4 +108,4 @@ class Avenla_KlarnaCheckout_CartController extends Mage_Checkout_CartController
110
 
111
  return $block->toHtml();
112
  }
113
- }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
27
  */
28
  public function estimateAjaxPostAction()
29
  {
30
+ $country = (string) $this->getRequest()->getParam('country_id');
31
+ $postcode = (string) $this->getRequest()->getParam('estimate_postcode');
32
+ $city = (string) $this->getRequest()->getParam('estimate_city');
33
+ $regionId = (string) $this->getRequest()->getParam('region_id');
34
+ $region = (string) $this->getRequest()->getParam('region');
35
 
36
  $this->_getQuote()->getShippingAddress()
37
+ ->setCountryId($country)
38
+ ->setCity($city)
39
+ ->setPostcode($postcode)
40
+ ->setRegionId($regionId)
41
+ ->setRegion($region)
42
+ ->setCollectShippingRates(true);
43
+
44
  $this->_getQuote()->save();
45
  $this->_getCart()->save();
46
+
47
  $this->getResponse()->setBody($this->getEncodedResponse());
48
  }
49
 
 
50
  /**
51
+ * Estimate update action
52
+ */
53
  public function estimateUpdateAjaxPostAction()
54
  {
55
  $code = (string) $this->getRequest()->getParam('estimate_method');
56
 
57
+ if (!empty($code))
58
+ $this->_getQuote()->getShippingAddress()->setShippingMethod($code)->save();
59
+
60
+ $cart = $this->_getCart();
61
+ $cart->save();
 
62
 
63
  $this->getResponse()->setBody($this->getEncodedResponse());
64
  }
65
 
66
  /**
67
  * Get response array
68
+ *
69
  * @return array
70
  */
71
  private function getEncodedResponse()
78
 
79
  return Mage::helper('core')->jsonEncode($resp);
80
  }
81
+
82
  /**
83
  * Get shipping html
84
+ *
85
  * @return string
86
  */
87
  private function getShippingHtml()
88
  {
89
  $layout = $this->getLayout();
90
  $layout->getMessagesBlock()->setMessages(Mage::getSingleton('checkout/session')
91
+ ->getMessages(true),Mage::getSingleton('catalog/session')->getMessages(true));
92
  $block = $this->getLayout()->createBlock('checkout/cart_shipping')->setTemplate('KCO/cart/shipping.phtml');
93
 
94
  return $block->toHtml();
95
  }
96
+
97
  /**
98
  * Get review html
99
+ *
100
  * @return string
101
  */
102
  private function getTotalsHtml()
108
 
109
  return $block->toHtml();
110
  }
111
+ }
app/code/community/Avenla/KlarnaCheckout/controllers/KCOController.php CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,355 +20,213 @@
20
  */
21
  class Avenla_KlarnaCheckout_KCOController extends Mage_Core_Controller_Front_Action
22
  {
23
- /**
24
- * Load Klarna Checkout iframe
25
- *
26
- */
27
- public function loadKcoFrameAction()
28
- {
29
- $mobile = false;
30
-
31
- if($this->getRequest()->getParam('mobile') == true)
32
- $mobile = true;
33
-
34
- $result = array();
35
-
36
- $quote = Mage::getSingleton('checkout/session')->getQuote();
37
- $kco = Mage::getModel('klarnaCheckout/KCO');
38
-
39
- $validationMessage = $quote->getPayment()->getAdditionalInformation("kco_validation_message");
40
- $quote->getPayment()->setAdditionalInformation("kco_validation_message", null);
41
-
42
- if (!$quote->validateMinimumAmount()){
43
- $minimumAmount = Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())
44
- ->toCurrency(Mage::getStoreConfig('sales/minimum_order/amount'));
45
-
46
- $warning = Mage::getStoreConfig('sales/minimum_order/description')
47
- ? Mage::getStoreConfig('sales/minimum_order/description')
48
- : Mage::helper('checkout')->__('Minimum order amount is %s', $minimumAmount);
49
-
50
- $result['msg'] = $warning;
51
- }
52
-
53
- if(!$kco->isAvailable($quote)){
54
- if(!(Mage::getSingleton('customer/session')->isLoggedIn() || Mage::helper('checkout')->isAllowedGuestCheckout($quote))){
55
- $result['msg'] = $this->__("Please login to use Klarna Checkout");
56
- $this->loadLayout();
57
- Mage::getSingleton('customer/session')->setBeforeAuthUrl(Mage::getUrl('checkout/cart'));
58
- $result['klarnaframe'] = $this->getLayout()->createBlock('customer/form_login')->setTemplate('customer/form/mini.login.phtml')->toHtml();
59
- $result['kcologin'] = true;
60
- }
61
- else{
62
- $result['msg'] = $this->__("Klarna Checkout is not available");
63
- }
64
- }
65
- else{
66
- $ko = null;
67
- $kcoOrder = Mage::getModel("klarnaCheckout/order");
68
-
69
- if (array_key_exists('klarna_checkout', $_SESSION))
70
- $ko = $kcoOrder->getOrder($quote, $_SESSION['klarna_checkout'], $mobile);
71
-
72
- if ($ko == null)
73
- $ko = $kcoOrder->getOrder($quote, null, $mobile);
74
-
75
- if($ko != null){
76
- $_SESSION['klarna_checkout'] = $sessionId = $ko->getLocation();
77
- if(!$quote->isVirtual()){
78
- if($quote->getShippingAddress()->getPostcode() == null)
79
- $result['msg'] = $this->__("Please fill in your post code");
80
-
81
- if($quote->getShippingAddress()->getCountry() == null)
82
- $result['msg'] = $this->__("Please select country");
83
-
84
- if ($quote->getShippingAddress()->getShippingMethod() == null)
85
- $result['msg'] = $this->__("Please select shipping method to use Klarna Checkout");
86
- }
87
-
88
- if($validationMessage)
89
- $result['validationMsg'] = $validationMessage;
90
-
91
- $result['klarnaframe'] = $ko['gui']['snippet'];
92
- }
93
- }
94
-
95
- $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
96
- }
97
-
98
- /**
99
- * Confirmation action for Klarna Checkout
100
- *
101
- */
102
- public function confirmationAction()
103
- {
104
- $redirect = false;
105
- @$checkoutId = $_GET['klarna_order'];
106
- $ko = Mage::getModel("klarnaCheckout/order")->getOrder(null, $checkoutId);
107
-
108
- try{
109
- $ko->fetch();
110
- if ($ko['status'] == "checkout_complete" || $ko['status'] == "created"){
111
- $this->emptyCart();
112
- $this->loadLayout();
113
- $this->getLayout()->getBlock('klarnaCheckout.confirmation')->setCheckoutID($checkoutId);
114
- $this->renderLayout();
115
- }
116
- else{
117
- $redirect = true;
118
- }
119
- }
120
- catch(Exception $e) {
121
- Mage::logException($e);
122
- $redirect = true;
123
- }
124
-
125
- if($redirect){
126
- header('Location: ' . Mage::helper('checkout/url')->getCartUrl());
127
- exit();
128
- }
129
- }
130
-
131
- /**
132
- * Validation action for Klarna Checkout
133
- *
134
- */
135
- public function validationAction()
136
- {
137
- $validator = Mage::getModel('klarnaCheckout/validator');
138
- $ko = $validator->parseValidationPost();
139
- $quote = Mage::getModel("sales/quote")->load($ko->merchant_reference->orderid1);
140
-
141
- if(!$validator->validateQuote($quote, $ko)){
142
- $this->getResponse()
143
- ->setHttpResponseCode(303)
144
- ->setHeader('Location', Mage::getUrl('checkout/cart'));
145
- }
146
- }
147
-
148
- /**
149
- * Action for saving gift message form
150
- *
151
- */
152
- public function saveGiftMessageAction()
153
- {
154
- Mage::dispatchEvent(
155
- 'kco_save_giftmessage',
156
- array(
157
- 'request' => $this->getRequest(),
158
- 'quote' => Mage::getSingleton('checkout/session')->getQuote()
159
- )
160
- );
161
-
162
- $result = array();
163
-
164
- $result['msg'] = $this->__('Gift message saved successfully');
165
- $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
166
- }
167
-
168
-
169
- /**
170
- * Convert Klarna address to Magento address
171
- *
172
- * @param array $address
173
- * @param string $region
174
- * @param string $region_code
175
- */
176
- private function convertAddress($address, $region = '', $region_code = '')
177
- {
178
- $country_id = strtoupper($address['country']);
179
-
180
- if($region_code == '')
181
- $region_code = 1;
182
-
183
- $street = isset($address['street_address'])
184
- ? $address['street_address']
185
- : $address['street_name'] . " " . $address['street_number'];
186
-
187
- $phone = strlen($address['phone'] > 0) ? $address['phone'] : '1';
188
-
189
- $magentoAddress = array(
190
- 'firstname' => $address['given_name'],
191
- 'lastname' => $address['family_name'],
192
- 'email' => $address['email'],
193
- 'street' => $street,
194
- 'city' => $address['city'],
195
- 'region_id' => $region_code,
196
- 'region' => $region,
197
- 'postcode' => $address['postal_code'],
198
- 'country_id' => strtoupper($address['country']),
199
- 'telephone' => $phone
200
- );
201
-
202
- return $magentoAddress;
203
- }
204
-
205
- /**
206
- * Activate Klarna reservation (manually from order view)
207
- *
208
- */
209
- public function activateReservationAction()
210
- {
211
- try {
212
- if($orderId = $this->getRequest()->getParam('order_id')){
213
- $order = Mage::getModel('sales/order')->load($orderId);
214
-
215
- if(Mage::helper('klarnaCheckout/api')->getReservationNumber($order) !== false){
216
- Mage::register('kco_save', true);
217
- $currentId = Mage::app()->getStore()->getStoreId();
218
- Mage::app()->setCurrentStore($order->getStore()->getStoreId());
219
- Mage::getModel("klarnaCheckout/api")->activateFullReservation($order);
220
- Mage::app()->setCurrentStore($currentId);
221
- Mage::unregister('kco_save');
222
- }
223
- else{
224
- $this->_getSession()->addError($this->__('No Klarna reservation number found in order'));
225
- $this->_redirectReferer();
226
-
227
- return;
228
- }
229
- }
230
- }
231
- catch(Exception $e) {
232
- $this->_getSession()->addError($this->__($e->getMessage()));
233
- $this->_redirectReferer();
234
- }
235
- $this->_redirectReferer();
236
- }
237
-
238
- /**
239
- * Push action for Klarna Checkout
240
- *
241
- */
242
- public function pushAction()
243
- {
244
- @$checkoutId = $_GET['klarna_order'];
245
- Mage::app()->setCurrentStore($_GET['storeid']);
246
- $ko = Mage::getModel("klarnaCheckout/order")->getOrder(null, $checkoutId);
247
- $ko->fetch();
248
- $quoteID = $ko['merchant_reference']['orderid1'];
249
-
250
- if ($ko['status'] == "checkout_complete" && $quoteID){
251
- $quote = Mage::getModel("sales/quote")->load($quoteID);
252
-
253
- Mage::helper('klarnaCheckout')->log('QUOTE ID: ' . $quoteID);
254
- Mage::helper('klarnaCheckout')->log($ko['cart']);
255
-
256
- if(count($quote->getAllItems()) < 1){
257
- Mage::log("No valid quote found for Klarna order, reservation canceled.");
258
- Mage::getModel('klarnaCheckout/api')->cancelReservation($ko['reservation']);
259
- return;
260
- }
261
-
262
- $mo = $this->quoteToOrder($quote, $ko);
263
-
264
- $url = Mage::getSingleton('klarnaCheckout/KCO')->getConfig()->isLive()
265
- ? Avenla_KlarnaCheckout_Model_Config::KCO_LIVE_S_URL
266
- : Avenla_KlarnaCheckout_Model_Config::KCO_DEMO_S_URL;
267
-
268
- $mo->getPayment()->setAdditionalInformation("klarna_server", $url);
269
- $mo->getPayment()->setAdditionalInformation("klarna_order_id", $ko['id']);
270
- $mo->getPayment()->setAdditionalInformation("klarna_order_reference", $ko['reference']);
271
- $mo->getPayment()->setAdditionalInformation("klarna_order_reservation", $ko['reservation']);
272
- $mo->getPayment()->setAdditionalInformation("klarna_order_reservation_expiration", $ko['expires_at']);
273
- $mo->getPayment()->save();
274
-
275
- $update['merchant_reference']['orderid1'] = $mo->getIncrementId();
276
- $update['merchant_reference']['orderid2'] = $quoteID;
277
- $update['status'] = 'created';
278
- $ko->update($update);
279
-
280
- if($ko['status'] != "created"){
281
- $this->cancelOrder($mo, $this->__('Order canceled: Failed to create order in Klarna.'));
282
- }
283
  else{
284
- $mo->getSendConfirmation(null);
285
- $mo->sendNewOrderEmail();
286
-
287
- if($mo->getPayment()->getAdditionalInformation("klarna_newsletter"))
288
- Mage::getModel('klarnaCheckout/newsletter')->signForNewsletter($mo, Mage::app()->getStore()->getWebsiteId());
289
- }
290
- }
291
- else{
292
- if($ko['status'] != "checkout_complete")
293
- Mage::log("Klarna reservation " . $ko['reservation'] ." got to pushAction with status: " . $ko['status']);
294
-
295
- if(!$quoteID){
296
- Mage::getModel('klarnaCheckout/api')->cancelReservation($ko['reservation']);
297
- Mage::log("Couldn't find quote id for Klarna reservation " . $ko['reservation']);
298
- }
299
- }
300
- }
301
-
302
- /**
303
- * Convert Magento quote to order
304
- *
305
- * @param Mage_Sales_Model_Quote
306
- * @param Klarna_Checkout_Order
307
- * @return Mage_Sales_Model_Order
308
- */
309
- private function quoteToOrder($quote, $ko)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  {
311
- $quote->setCustomerEmail($ko['billing_address']['email'])->save();
312
- $quote->getBillingAddress()->addData($this->convertAddress($ko['billing_address']));
313
- $quote->getShippingAddress()->addData($this->convertAddress($ko['shipping_address']));
314
- $quote->getPayment()->setMethod(Mage::getModel("klarnaCheckout/KCO")->getCode());
315
- $quote->collectTotals()->save();
316
- $service = Mage::getModel('sales/service_quote', $quote);
317
- $service->submitAll();
318
- $quote->setIsActive(false)->save();
319
-
320
- return $service->getOrder();
321
- }
322
-
323
- /**
324
- * Cancel Magento order
325
- *
326
- * @param Mage_Sales_Model_Order
327
- * @param string msg
328
- */
329
- private function cancelOrder($mo, $msg)
330
- {
331
- $mo->cancel();
332
- $mo->setStatus($msg);
333
- $mo->save();
334
- }
335
-
336
- /**
337
- * Clear the checkout session after successful checkout
338
- *
339
- */
340
- private function emptyCart()
341
- {
342
- $quote = Mage::getSingleton('checkout/session')->getQuote();
343
- $quote->setIsActive(false)->save();
344
- Mage::getSingleton('checkout/session')->clear();
345
- }
346
-
347
- /**
348
- * Subscribe to newsletter
349
- *
350
- */
351
- public function newsletterAction()
352
- {
353
- $result = array();
354
- $status = false;
355
- $customerSession = Mage::getSingleton('customer/session');
356
-
357
- if($this->getRequest()->getParam('status') == true)
358
- $status = true;
359
-
360
- if ($status && Mage::getStoreConfig(Mage_Newsletter_Model_Subscriber::XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG) != 1 &&
361
- !$customerSession->isLoggedIn()) {
362
- $result['letter_msg'] = $this->__(
363
- 'Sorry, but administrator denied subscription for guests. Please <a href="%s">register</a>.',
364
- Mage::helper('customer')->getRegisterUrl()
365
- );
366
- $status = false;
367
- }
368
-
369
- $result['msg'] = ' ';
370
-
371
- Mage::getModel('klarnaCheckout/newsletter')->addNewsletterStatus($status);
372
- $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
373
- }
374
- }
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  class Avenla_KlarnaCheckout_KCOController extends Mage_Core_Controller_Front_Action
22
  {
23
+ /**
24
+ * Load Klarna Checkout iframe
25
+ */
26
+ public function loadKcoFrameAction()
27
+ {
28
+ $result = new Varien_Object();
29
+ $kco = Mage::helper('klarnaCheckout')->getKco();
30
+ $quote = Mage::getSingleton('checkout/session')->getQuote();
31
+
32
+ if (!$quote->getCustomerIsGuest() && !Mage::getSingleton('customer/session')->isLoggedIn() && Mage::helper('checkout')->isAllowedGuestCheckout($quote))
33
+ $quote->setCustomerIsGuest(true)->save();
34
+
35
+ if($validationMessage = $quote->getPayment()->getAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_VALIDATION_MSG)){
36
+ $quote->getPayment()->setAdditionalInformation(Avenla_KlarnaCheckout_Model_Payment_Abstract::ADDITIONAL_FIELD_VALIDATION_MSG, null);
37
+ $result->setValidationMsg($validationMessage);
38
+ }
39
+
40
+ if(!$kco->isAvailable($quote)){
41
+ $result->setMsg(Mage::getSingleton('core/session')->getKCOMessage());
42
+
43
+ if(Mage::getSingleton('core/session')->getKCORequireLogin()){
44
+ $this->loadLayout();
45
+ Mage::getSingleton('customer/session')->setBeforeAuthUrl(Mage::getUrl('checkout/cart'));
46
+ $result->setKlarnaframe($this->getLayout()->createBlock('customer/form_login')->setTemplate('customer/form/mini.login.phtml')->toHtml());
47
+ $result->setKcologin(true);
48
+ }
49
+ }
50
+ else{
51
+ $kcoOrder = $kco->getOrderModel();
52
+ if($kcoOrder->getOrder($quote)){
53
+ if(!Mage::getModel('klarnaCheckout/validator')->validateQuote($quote))
54
+ $result->setMsg(Mage::getSingleton('core/session')->getKCOMessage());
55
+
56
+ $result->setKlarnaframe($kcoOrder->getHtmlSnippet());
57
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  else{
59
+ $result->setMsg("Klarna Checkout is not available");
60
+ }
61
+ }
62
+
63
+ Mage::getSingleton('core/session')->unsKCOMessage();
64
+ Mage::getSingleton('core/session')->unsKCORequireLogin();
65
+
66
+ $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result->getData()));
67
+ }
68
+
69
+ /**
70
+ * Confirmation action for Klarna Checkout
71
+ */
72
+ public function confirmationAction()
73
+ {
74
+ $redirect = false;
75
+ $checkoutId = Mage::app()->getRequest()->getParam(Avenla_KlarnaCheckout_Model_Payment_Abstract::REQUEST_KLARNA_ORDER);
76
+ $kco = Mage::helper('klarnaCheckout')->getKco()->getOrderModel();
77
+ $ko = $kco->getOrder(null, $checkoutId);
78
+
79
+ try{
80
+ $ko->fetch();
81
+ if (($ko['status'] == "checkout_complete" || $ko['status'] == "created") && Mage::getSingleton('core/session')->getKCOid()){
82
+ $this->emptyCart();
83
+ $this->loadLayout();
84
+
85
+ $confirmation = $this->getLayout()->getBlock('klarnaCheckout.confirmation');
86
+ $confirmation->setCheckoutID($checkoutId);
87
+ $confirmation->setKlarnaSnippet($kco->getHtmlSnippet());
88
+
89
+ if(Mage::getModel('klarnaCheckout/config')->getGoogleAnalyticsNo() !== false)
90
+ $confirmation->setAnalyticsData($kco->getAnalyticsData());
91
+
92
+ $this->renderLayout();
93
+ Mage::getSingleton('core/session')->unsKCOid();
94
+ }
95
+ else{
96
+ $redirect = true;
97
+ }
98
+ }
99
+ catch(Exception $e) {
100
+ Mage::helper('klarnaCheckout')->logException($e);
101
+ $redirect = true;
102
+ }
103
+
104
+ if($redirect){
105
+ header('Location: ' . Mage::helper('checkout/url')->getCartUrl());
106
+ exit();
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Validation action for Klarna Checkout
112
+ */
113
+ public function validationAction()
114
+ {
115
+ $validator = Mage::getModel('klarnaCheckout/validator');
116
+ $ko = $validator->parseValidationPost();
117
+ $quoteId = false;
118
+ if(isset($ko->merchant_reference->orderid1)){
119
+ $quoteId = $ko->merchant_reference->orderid1;
120
+ }
121
+ elseif(isset($ko->merchant_reference1)){
122
+ $quoteId = $ko->merchant_reference1;
123
+ }
124
+
125
+ if($quoteId){
126
+ $quote = Mage::getModel("sales/quote")->load($quoteId);
127
+
128
+ if(!$validator->validateQuote($quote, $ko)){
129
+ $this->getResponse()
130
+ ->setHttpResponseCode(303)
131
+ ->setHeader('Location', Mage::getUrl('checkout/cart'));
132
+ }
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Save gift message form
138
+ *
139
+ */
140
+ public function saveGiftMessageAction()
141
+ {
142
+ Mage::dispatchEvent(
143
+ 'kco_save_giftmessage',
144
+ array(
145
+ 'request' => $this->getRequest(),
146
+ 'quote' => Mage::getSingleton('checkout/session')->getQuote()
147
+ )
148
+ );
149
+
150
+ $result = array();
151
+ $result['msg'] = $this->__('Gift message saved successfully');
152
+ $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
153
+ }
154
+
155
+ /**
156
+ * Push action for Klarna Checkout
157
+ */
158
+ public function pushAction()
159
+ {
160
+ $checkoutId = $this->getRequest()->getParam(Avenla_KlarnaCheckout_Model_Payment_Abstract::REQUEST_KLARNA_ORDER);
161
+ $storeid = $this->getRequest()->getParam('storeid');
162
+ Mage::app()->setCurrentStore($storeid);
163
+
164
+ $kco = Mage::helper('klarnaCheckout')->getKco()->getOrderModel();
165
+ $ko = $kco->getOrder(null, $checkoutId);
166
+
167
+ $quoteId = $kco->getMerchantReference();
168
+
169
+ if (!$kco->isOrderComplete()){
170
+ Mage::helper('klarnaCheckout')->log("Klarna order " . $checkoutId . " not complete in push. Status: " . $ko['status']);
171
+ return false;
172
+ }
173
+
174
+ if(!$quoteId){
175
+ $kco->cancelReservation();
176
+ Mage::helper('klarnaCheckout')->log("No quote found for Klarna order " . $checkoutId);
177
+ return false;
178
+ }
179
+
180
+ $quote = Mage::getModel("sales/quote")->load($quoteId);
181
+
182
+ if(count($quote->getAllItems()) < 1){
183
+ Mage::helper('klarnaCheckout')->log("Quote has no items, reservation canceled.");
184
+ $kco->cancelReservation();
185
+ return false;
186
+ }
187
+ try{
188
+ $mo = $kco->createMagentoOrder();
189
+ $kco->confirmOrder($mo, $checkoutId);
190
+ }
191
+ catch(Exception $e){
192
+ Mage::helper('klarnaCheckout')->logException($e);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Clear the checkout session after successful checkout
198
+ */
199
+ private function emptyCart()
200
+ {
201
+ $quote = Mage::getSingleton('checkout/session')->getQuote();
202
+ $quote->setIsActive(false)->save();
203
+ Mage::getSingleton('checkout/session')->clear();
204
+ }
205
+
206
+ /**
207
+ * Save newsletter subscribtion status
208
+ */
209
+ public function newsletterAction()
210
  {
211
+ $result = array();
212
+ $status = false;
213
+ $customerSession = Mage::getSingleton('customer/session');
214
+
215
+ if($this->getRequest()->getParam('status') == true)
216
+ $status = true;
217
+
218
+ if ($status && Mage::getStoreConfig(Mage_Newsletter_Model_Subscriber::XML_PATH_ALLOW_GUEST_SUBSCRIBE_FLAG) != 1
219
+ && !$customerSession->isLoggedIn()) {
220
+ $result['letter_msg'] = $this->__(
221
+ 'Sorry, but administrator denied subscription for guests. Please <a href="%s">register</a>.',
222
+ Mage::helper('customer')->getRegisterUrl()
223
+ );
224
+ $status = false;
225
+ }
226
+
227
+ $result['msg'] = ' ';
228
+
229
+ Mage::getModel('klarnaCheckout/newsletter')->addNewsletterStatus($status);
230
+ $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
231
+ }
232
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Avenla/KlarnaCheckout/etc/config.xml CHANGED
@@ -3,14 +3,14 @@
3
 
4
  This file is released under a custom license by Avenla Oy.
5
  All rights reserved
6
-
7
- License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
8
  For questions and support - klarna-support@avenla.com
9
-
10
  @category Avenla
11
  @package Avenla_KlarnaCheckout
12
  @copyright Copyright (c) Avenla Oy
13
- @link http://www.avenla.fi
14
 
15
 
16
 
@@ -23,7 +23,7 @@
23
  <config>
24
  <modules>
25
  <Avenla_KlarnaCheckout>
26
- <version>1.1.6</version>
27
  </Avenla_KlarnaCheckout>
28
  </modules>
29
  <global>
@@ -58,14 +58,6 @@
58
  </groups>
59
  </payment>
60
  <events>
61
- <core_block_abstract_to_html_before>
62
- <observers>
63
- <Avenla_KlarnaCheckout_core_block_abstract_to_html_before>
64
- <class>klarnaCheckout/observer</class>
65
- <method>addActivate</method>
66
- </Avenla_KlarnaCheckout_core_block_abstract_to_html_before>
67
- </observers>
68
- </core_block_abstract_to_html_before>
69
  <sales_order_save_commit_after>
70
  <observers>
71
  <avenla_klarnacheckout_sales_order_save_commit_after>
@@ -98,8 +90,9 @@
98
  <default>
99
  <payment>
100
  <klarnaCheckout_payment>
101
- <model>klarnaCheckout/KCO</model>
102
  <group>klarnaCheckout</group>
 
103
  <payment_action>authorize</payment_action>
104
  <active>1</active>
105
  <title>Klarna Checkout</title>
@@ -111,7 +104,14 @@
111
  <color_checkbox_checkmark>FFFFFF</color_checkbox_checkmark>
112
  <color_header>434343</color_header>
113
  <color_link>0089CF</color_link>
 
114
  </klarnaCheckout_payment>
 
 
 
 
 
 
115
  </payment>
116
  </default>
117
  <frontend>
@@ -167,7 +167,18 @@
167
  </controller_action_layout_load_before>
168
  </events>
169
  </frontend>
 
170
  <adminhtml>
 
 
 
 
 
 
 
 
 
 
171
  <layout>
172
  <updates>
173
  <klarnaCheckout>
@@ -207,4 +218,15 @@
207
  </resources>
208
  </acl>
209
  </adminhtml>
 
 
 
 
 
 
 
 
 
 
 
210
  </config>
3
 
4
  This file is released under a custom license by Avenla Oy.
5
  All rights reserved
6
+
7
+ License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
8
  For questions and support - klarna-support@avenla.com
9
+
10
  @category Avenla
11
  @package Avenla_KlarnaCheckout
12
  @copyright Copyright (c) Avenla Oy
13
+ @link http://www.avenla.fi
14
 
15
 
16
 
23
  <config>
24
  <modules>
25
  <Avenla_KlarnaCheckout>
26
+ <version>1.2.0</version>
27
  </Avenla_KlarnaCheckout>
28
  </modules>
29
  <global>
58
  </groups>
59
  </payment>
60
  <events>
 
 
 
 
 
 
 
 
61
  <sales_order_save_commit_after>
62
  <observers>
63
  <avenla_klarnacheckout_sales_order_save_commit_after>
90
  <default>
91
  <payment>
92
  <klarnaCheckout_payment>
93
+ <model>klarnaCheckout/payment_KCO</model>
94
  <group>klarnaCheckout</group>
95
+ <api>2</api>
96
  <payment_action>authorize</payment_action>
97
  <active>1</active>
98
  <title>Klarna Checkout</title>
104
  <color_checkbox_checkmark>FFFFFF</color_checkbox_checkmark>
105
  <color_header>434343</color_header>
106
  <color_link>0089CF</color_link>
107
+ <allow_separate_shipping>0</allow_separate_shipping>
108
  </klarnaCheckout_payment>
109
+ <klarnaCheckout_payment_v3>
110
+ <active>1</active>
111
+ <payment_action>authorize</payment_action>
112
+ <title>Klarna Checkout</title>
113
+ <model>klarnaCheckout/payment_KCOv3</model>
114
+ </klarnaCheckout_payment_v3>
115
  </payment>
116
  </default>
117
  <frontend>
167
  </controller_action_layout_load_before>
168
  </events>
169
  </frontend>
170
+
171
  <adminhtml>
172
+ <events>
173
+ <core_block_abstract_to_html_before>
174
+ <observers>
175
+ <Avenla_KlarnaCheckout_core_block_abstract_to_html_before>
176
+ <class>klarnaCheckout/observer</class>
177
+ <method>addActivate</method>
178
+ </Avenla_KlarnaCheckout_core_block_abstract_to_html_before>
179
+ </observers>
180
+ </core_block_abstract_to_html_before>
181
+ </events>
182
  <layout>
183
  <updates>
184
  <klarnaCheckout>
218
  </resources>
219
  </acl>
220
  </adminhtml>
221
+ <admin>
222
+ <routers>
223
+ <adminhtml>
224
+ <args>
225
+ <modules>
226
+ <klarnaCheckout before="Mage_Adminhtml">Avenla_KlarnaCheckout_Adminhtml</klarnaCheckout>
227
+ </modules>
228
+ </args>
229
+ </adminhtml>
230
+ </routers>
231
+ </admin>
232
  </config>
app/code/community/Avenla/KlarnaCheckout/etc/system.xml CHANGED
@@ -2,14 +2,14 @@
2
  <!--
3
  This file is released under a custom license by Avenla Oy.
4
  All rights reserved
5
-
6
- License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  For questions and support - klarna-support@avenla.com
8
-
9
  @category Avenla
10
  @package Avenla_KlarnaCheckout
11
  @copyright Copyright (c) Avenla Oy
12
- @link http://www.avenla.fi
13
 
14
 
15
  Avenla KlarnaCheckout
@@ -53,12 +53,21 @@
53
  <show_in_default>1</show_in_default>
54
  <show_in_website>1</show_in_website>
55
  <show_in_store>1</show_in_store>
56
- </active>
 
 
 
 
 
 
 
 
 
57
  <server translate="label">
58
  <label>Server</label>
59
  <frontend_type>select</frontend_type>
60
  <source_model>klarnaCheckout/source_servermode</source_model>
61
- <sort_order>4</sort_order>
62
  <show_in_default>1</show_in_default>
63
  <show_in_website>1</show_in_website>
64
  <show_in_store>1</show_in_store>
@@ -66,7 +75,7 @@
66
  <merchantid translate="label">
67
  <label>Merchant ID</label>
68
  <frontend_type>text</frontend_type>
69
- <sort_order>5</sort_order>
70
  <show_in_default>1</show_in_default>
71
  <show_in_website>1</show_in_website>
72
  <show_in_store>1</show_in_store>
@@ -75,7 +84,7 @@
75
  <label>Shared secret</label>
76
  <frontend_type>obscure</frontend_type>
77
  <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
78
- <sort_order>6</sort_order>
79
  <show_in_default>1</show_in_default>
80
  <show_in_website>1</show_in_website>
81
  <show_in_store>1</show_in_store>
@@ -84,7 +93,7 @@
84
  <label>Debug log</label>
85
  <frontend_type>select</frontend_type>
86
  <source_model>adminhtml/system_config_source_yesno</source_model>
87
- <sort_order>7</sort_order>
88
  <show_in_default>1</show_in_default>
89
  <show_in_website>1</show_in_website>
90
  <show_in_store>1</show_in_store>
@@ -94,16 +103,26 @@
94
  <comment><![CDATA[When selected, partial shipments will be automatically activated in Klarna]]></comment>
95
  <frontend_type>select</frontend_type>
96
  <source_model>adminhtml/system_config_source_yesno</source_model>
97
- <sort_order>8</sort_order>
98
  <show_in_default>1</show_in_default>
99
  <show_in_website>1</show_in_website>
100
  <show_in_store>1</show_in_store>
101
  </activate_partial>
 
 
 
 
 
 
 
 
 
 
102
  <return_tax translate="label">
103
  <label>Tax class for all amount returns / adjustment fee</label>
104
  <frontend_type>select</frontend_type>
105
  <source_model>klarnaCheckout/source_taxclass</source_model>
106
- <sort_order>9</sort_order>
107
  <show_in_default>1</show_in_default>
108
  <show_in_website>1</show_in_website>
109
  <show_in_store>1</show_in_store>
@@ -111,7 +130,7 @@
111
  <title translate="label">
112
  <label>Title</label>
113
  <frontend_type>text</frontend_type>
114
- <sort_order>10</sort_order>
115
  <show_in_default>1</show_in_default>
116
  <show_in_website>1</show_in_website>
117
  <show_in_store>1</show_in_store>
@@ -120,7 +139,7 @@
120
  <label>Link text</label>
121
  <comment><![CDATA[Text shown in Klarna link at Magento Checkout]]></comment>
122
  <frontend_type>text</frontend_type>
123
- <sort_order>11</sort_order>
124
  <show_in_default>1</show_in_default>
125
  <show_in_website>1</show_in_website>
126
  <show_in_store>1</show_in_store>
@@ -129,7 +148,7 @@
129
  <label>Terms URL</label>
130
  <comment><![CDATA[Relative to Website Base URL]]></comment>
131
  <frontend_type>text</frontend_type>
132
- <sort_order>12</sort_order>
133
  <show_in_default>1</show_in_default>
134
  <show_in_website>1</show_in_website>
135
  <show_in_store>1</show_in_store>
@@ -138,7 +157,7 @@
138
  <label>Google Analytics account no</label>
139
  <comment><![CDATA[Enter account number to use Google Ecommerce tracking]]></comment>
140
  <frontend_type>text</frontend_type>
141
- <sort_order>13</sort_order>
142
  <show_in_default>1</show_in_default>
143
  <show_in_website>1</show_in_website>
144
  <show_in_store>1</show_in_store>
@@ -147,7 +166,7 @@
147
  <label>Google Analytics account Type</label>
148
  <frontend_type>select</frontend_type>
149
  <source_model>klarnaCheckout/source_analyticsType</source_model>
150
- <sort_order>14</sort_order>
151
  <show_in_default>1</show_in_default>
152
  <show_in_website>1</show_in_website>
153
  <show_in_store>1</show_in_store>
@@ -156,7 +175,7 @@
156
  <label>Hide links to default Checkout</label>
157
  <frontend_type>select</frontend_type>
158
  <source_model>adminhtml/system_config_source_yesno</source_model>
159
- <sort_order>15</sort_order>
160
  <show_in_default>1</show_in_default>
161
  <show_in_website>1</show_in_website>
162
  <show_in_store>1</show_in_store>
@@ -165,7 +184,7 @@
165
  <label>Cart page layout</label>
166
  <frontend_type>select</frontend_type>
167
  <source_model>klarnaCheckout/source_kcolayout</source_model>
168
- <sort_order>16</sort_order>
169
  <show_in_default>1</show_in_default>
170
  <show_in_website>1</show_in_website>
171
  <show_in_store>1</show_in_store>
@@ -174,17 +193,18 @@
174
  <label>Disabled shipping methods</label>
175
  <frontend_type>multiselect</frontend_type>
176
  <source_model>klarnaCheckout/source_shippingmethods</source_model>
177
- <sort_order>17</sort_order>
178
  <show_in_default>1</show_in_default>
179
  <show_in_website>1</show_in_website>
180
  <show_in_store>1</show_in_store>
181
  <can_be_empty>1</can_be_empty>
182
  </disabled_shipping_methods>
183
  <pp_widget translate="label">
 
184
  <label>Show part payment widget on product page</label>
185
  <frontend_type>select</frontend_type>
186
  <source_model>klarnaCheckout/source_ppwidget</source_model>
187
- <sort_order>18</sort_order>
188
  <show_in_default>1</show_in_default>
189
  <show_in_website>1</show_in_website>
190
  <show_in_store>1</show_in_store>
@@ -194,16 +214,26 @@
194
  <label>Part payment widget layout</label>
195
  <frontend_type>select</frontend_type>
196
  <source_model>klarnaCheckout/source_pplayout</source_model>
197
- <sort_order>19</sort_order>
198
  <show_in_default>1</show_in_default>
199
  <show_in_website>1</show_in_website>
200
  <show_in_store>1</show_in_store>
201
  </pp_layout>
 
 
 
 
 
 
 
 
 
 
202
  <show_newsletter translate="label">
203
  <label>Show newsletter subscription checkbox</label>
204
  <frontend_type>select</frontend_type>
205
  <source_model>adminhtml/system_config_source_yesno</source_model>
206
- <sort_order>20</sort_order>
207
  <show_in_default>1</show_in_default>
208
  <show_in_website>1</show_in_website>
209
  <show_in_store>1</show_in_store>
@@ -213,89 +243,80 @@
213
  <comment><![CDATA[Only if you have gift messages are enabled.]]></comment>
214
  <frontend_type>select</frontend_type>
215
  <source_model>adminhtml/system_config_source_yesno</source_model>
216
- <sort_order>21</sort_order>
217
  <show_in_default>1</show_in_default>
218
  <show_in_website>1</show_in_website>
219
  <show_in_store>1</show_in_store>
220
  </show_giftmessage>
221
- <update_pclass translate="label">
222
- <label>Update PClasses</label>
223
- <frontend_type>button</frontend_type>
224
- <frontend_model>klarnaCheckout/adminhtml_system_config_field_pclass</frontend_model>
225
- <sort_order>22</sort_order>
226
- <show_in_default>1</show_in_default>
227
- <show_in_website>1</show_in_website>
228
- <show_in_store>1</show_in_store>
229
- </update_pclass>
230
- <custom_colors translate="label">
231
  <label>Use custom colors</label>
232
  <frontend_type>select</frontend_type>
233
  <source_model>adminhtml/system_config_source_yesno</source_model>
234
- <sort_order>23</sort_order>
235
  <show_in_default>1</show_in_default>
236
  <show_in_website>1</show_in_website>
237
  <show_in_store>1</show_in_store>
238
  </custom_colors>
239
- <color_button translate="label">
240
- <label>Button color</label>
241
- <frontend_type>text</frontend_type>
242
- <validate>color</validate>
243
- <sort_order>24</sort_order>
244
- <show_in_default>1</show_in_default>
245
- <show_in_website>1</show_in_website>
246
- <show_in_store>1</show_in_store>
247
- <depends><custom_colors>1</custom_colors></depends>
248
- </color_button>
249
- <color_button_text translate="label">
250
- <label>Button text color</label>
251
- <frontend_type>text</frontend_type>
252
- <validate>color</validate>
253
- <sort_order>25</sort_order>
254
- <show_in_default>1</show_in_default>
255
- <show_in_website>1</show_in_website>
256
- <show_in_store>1</show_in_store>
257
- <depends><custom_colors>1</custom_colors></depends>
258
- </color_button_text>
259
- <color_checkbox translate="label">
260
- <label>Checkbox color</label>
261
- <frontend_type>text</frontend_type>
262
- <validate>color</validate>
263
- <sort_order>26</sort_order>
264
- <show_in_default>1</show_in_default>
265
- <show_in_website>1</show_in_website>
266
- <show_in_store>1</show_in_store>
267
- <depends><custom_colors>1</custom_colors></depends>
268
- </color_checkbox>
269
- <color_checkbox_checkmark translate="label">
270
- <label>Checkbox checkmark color</label>
271
- <frontend_type>text</frontend_type>
272
- <validate>color</validate>
273
- <sort_order>27</sort_order>
274
- <show_in_default>1</show_in_default>
275
- <show_in_website>1</show_in_website>
276
- <show_in_store>1</show_in_store>
277
- <depends><custom_colors>1</custom_colors></depends>
278
- </color_checkbox_checkmark>
279
- <color_header translate="label">
280
- <label>Header color</label>
281
- <frontend_type>text</frontend_type>
282
- <validate>color</validate>
283
- <sort_order>28</sort_order>
284
- <show_in_default>1</show_in_default>
285
- <show_in_website>1</show_in_website>
286
- <show_in_store>1</show_in_store>
287
- <depends><custom_colors>1</custom_colors></depends>
288
- </color_header>
289
- <color_link translate="label">
290
- <label>Link color</label>
291
- <frontend_type>text</frontend_type>
292
- <validate>color</validate>
293
- <sort_order>29</sort_order>
294
- <show_in_default>1</show_in_default>
295
- <show_in_website>1</show_in_website>
296
- <show_in_store>1</show_in_store>
297
- <depends><custom_colors>1</custom_colors></depends>
298
- </color_link>
299
  </fields>
300
  </klarnaCheckout_payment>
301
  </groups>
2
  <!--
3
  This file is released under a custom license by Avenla Oy.
4
  All rights reserved
5
+
6
+ License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  For questions and support - klarna-support@avenla.com
8
+
9
  @category Avenla
10
  @package Avenla_KlarnaCheckout
11
  @copyright Copyright (c) Avenla Oy
12
+ @link http://www.avenla.fi
13
 
14
 
15
  Avenla KlarnaCheckout
53
  <show_in_default>1</show_in_default>
54
  <show_in_website>1</show_in_website>
55
  <show_in_store>1</show_in_store>
56
+ </active>
57
+ <api translate="label">
58
+ <label>API</label>
59
+ <frontend_type>select</frontend_type>
60
+ <source_model>klarnaCheckout/source_api</source_model>
61
+ <sort_order>4</sort_order>
62
+ <show_in_default>1</show_in_default>
63
+ <show_in_website>1</show_in_website>
64
+ <show_in_store>1</show_in_store>
65
+ </api>
66
  <server translate="label">
67
  <label>Server</label>
68
  <frontend_type>select</frontend_type>
69
  <source_model>klarnaCheckout/source_servermode</source_model>
70
+ <sort_order>5</sort_order>
71
  <show_in_default>1</show_in_default>
72
  <show_in_website>1</show_in_website>
73
  <show_in_store>1</show_in_store>
75
  <merchantid translate="label">
76
  <label>Merchant ID</label>
77
  <frontend_type>text</frontend_type>
78
+ <sort_order>6</sort_order>
79
  <show_in_default>1</show_in_default>
80
  <show_in_website>1</show_in_website>
81
  <show_in_store>1</show_in_store>
84
  <label>Shared secret</label>
85
  <frontend_type>obscure</frontend_type>
86
  <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
87
+ <sort_order>7</sort_order>
88
  <show_in_default>1</show_in_default>
89
  <show_in_website>1</show_in_website>
90
  <show_in_store>1</show_in_store>
93
  <label>Debug log</label>
94
  <frontend_type>select</frontend_type>
95
  <source_model>adminhtml/system_config_source_yesno</source_model>
96
+ <sort_order>8</sort_order>
97
  <show_in_default>1</show_in_default>
98
  <show_in_website>1</show_in_website>
99
  <show_in_store>1</show_in_store>
103
  <comment><![CDATA[When selected, partial shipments will be automatically activated in Klarna]]></comment>
104
  <frontend_type>select</frontend_type>
105
  <source_model>adminhtml/system_config_source_yesno</source_model>
106
+ <sort_order>9</sort_order>
107
  <show_in_default>1</show_in_default>
108
  <show_in_website>1</show_in_website>
109
  <show_in_store>1</show_in_store>
110
  </activate_partial>
111
+ <allow_separate_shipping translate="label">
112
+ <label>Allow separate shipping address</label>
113
+ <comment><![CDATA[Please confirm that your contract with Klarna allows the use of a separate shipping address.]]></comment>
114
+ <frontend_type>select</frontend_type>
115
+ <source_model>adminhtml/system_config_source_yesno</source_model>
116
+ <sort_order>10</sort_order>
117
+ <show_in_default>1</show_in_default>
118
+ <show_in_website>1</show_in_website>
119
+ <show_in_store>1</show_in_store>
120
+ </allow_separate_shipping>
121
  <return_tax translate="label">
122
  <label>Tax class for all amount returns / adjustment fee</label>
123
  <frontend_type>select</frontend_type>
124
  <source_model>klarnaCheckout/source_taxclass</source_model>
125
+ <sort_order>11</sort_order>
126
  <show_in_default>1</show_in_default>
127
  <show_in_website>1</show_in_website>
128
  <show_in_store>1</show_in_store>
130
  <title translate="label">
131
  <label>Title</label>
132
  <frontend_type>text</frontend_type>
133
+ <sort_order>12</sort_order>
134
  <show_in_default>1</show_in_default>
135
  <show_in_website>1</show_in_website>
136
  <show_in_store>1</show_in_store>
139
  <label>Link text</label>
140
  <comment><![CDATA[Text shown in Klarna link at Magento Checkout]]></comment>
141
  <frontend_type>text</frontend_type>
142
+ <sort_order>13</sort_order>
143
  <show_in_default>1</show_in_default>
144
  <show_in_website>1</show_in_website>
145
  <show_in_store>1</show_in_store>
148
  <label>Terms URL</label>
149
  <comment><![CDATA[Relative to Website Base URL]]></comment>
150
  <frontend_type>text</frontend_type>
151
+ <sort_order>14</sort_order>
152
  <show_in_default>1</show_in_default>
153
  <show_in_website>1</show_in_website>
154
  <show_in_store>1</show_in_store>
157
  <label>Google Analytics account no</label>
158
  <comment><![CDATA[Enter account number to use Google Ecommerce tracking]]></comment>
159
  <frontend_type>text</frontend_type>
160
+ <sort_order>15</sort_order>
161
  <show_in_default>1</show_in_default>
162
  <show_in_website>1</show_in_website>
163
  <show_in_store>1</show_in_store>
166
  <label>Google Analytics account Type</label>
167
  <frontend_type>select</frontend_type>
168
  <source_model>klarnaCheckout/source_analyticsType</source_model>
169
+ <sort_order>16</sort_order>
170
  <show_in_default>1</show_in_default>
171
  <show_in_website>1</show_in_website>
172
  <show_in_store>1</show_in_store>
175
  <label>Hide links to default Checkout</label>
176
  <frontend_type>select</frontend_type>
177
  <source_model>adminhtml/system_config_source_yesno</source_model>
178
+ <sort_order>17</sort_order>
179
  <show_in_default>1</show_in_default>
180
  <show_in_website>1</show_in_website>
181
  <show_in_store>1</show_in_store>
184
  <label>Cart page layout</label>
185
  <frontend_type>select</frontend_type>
186
  <source_model>klarnaCheckout/source_kcolayout</source_model>
187
+ <sort_order>18</sort_order>
188
  <show_in_default>1</show_in_default>
189
  <show_in_website>1</show_in_website>
190
  <show_in_store>1</show_in_store>
193
  <label>Disabled shipping methods</label>
194
  <frontend_type>multiselect</frontend_type>
195
  <source_model>klarnaCheckout/source_shippingmethods</source_model>
196
+ <sort_order>19</sort_order>
197
  <show_in_default>1</show_in_default>
198
  <show_in_website>1</show_in_website>
199
  <show_in_store>1</show_in_store>
200
  <can_be_empty>1</can_be_empty>
201
  </disabled_shipping_methods>
202
  <pp_widget translate="label">
203
+ <depends><api>2</api></depends>
204
  <label>Show part payment widget on product page</label>
205
  <frontend_type>select</frontend_type>
206
  <source_model>klarnaCheckout/source_ppwidget</source_model>
207
+ <sort_order>20</sort_order>
208
  <show_in_default>1</show_in_default>
209
  <show_in_website>1</show_in_website>
210
  <show_in_store>1</show_in_store>
214
  <label>Part payment widget layout</label>
215
  <frontend_type>select</frontend_type>
216
  <source_model>klarnaCheckout/source_pplayout</source_model>
217
+ <sort_order>21</sort_order>
218
  <show_in_default>1</show_in_default>
219
  <show_in_website>1</show_in_website>
220
  <show_in_store>1</show_in_store>
221
  </pp_layout>
222
+ <update_pclass translate="button_label">
223
+ <depends><api>2</api></depends>
224
+ <label></label>
225
+ <button_label>Update Pclasses</button_label>
226
+ <frontend_model>klarnaCheckout/adminhtml_system_config_field_pclass</frontend_model>
227
+ <sort_order>22</sort_order>
228
+ <show_in_default>1</show_in_default>
229
+ <show_in_website>1</show_in_website>
230
+ <show_in_store>1</show_in_store>
231
+ </update_pclass>
232
  <show_newsletter translate="label">
233
  <label>Show newsletter subscription checkbox</label>
234
  <frontend_type>select</frontend_type>
235
  <source_model>adminhtml/system_config_source_yesno</source_model>
236
+ <sort_order>23</sort_order>
237
  <show_in_default>1</show_in_default>
238
  <show_in_website>1</show_in_website>
239
  <show_in_store>1</show_in_store>
243
  <comment><![CDATA[Only if you have gift messages are enabled.]]></comment>
244
  <frontend_type>select</frontend_type>
245
  <source_model>adminhtml/system_config_source_yesno</source_model>
246
+ <sort_order>24</sort_order>
247
  <show_in_default>1</show_in_default>
248
  <show_in_website>1</show_in_website>
249
  <show_in_store>1</show_in_store>
250
  </show_giftmessage>
251
+ <custom_colors translate="label">
 
 
 
 
 
 
 
 
 
252
  <label>Use custom colors</label>
253
  <frontend_type>select</frontend_type>
254
  <source_model>adminhtml/system_config_source_yesno</source_model>
255
+ <sort_order>25</sort_order>
256
  <show_in_default>1</show_in_default>
257
  <show_in_website>1</show_in_website>
258
  <show_in_store>1</show_in_store>
259
  </custom_colors>
260
+ <color_button translate="label">
261
+ <label>Button color</label>
262
+ <frontend_type>text</frontend_type>
263
+ <validate>color</validate>
264
+ <sort_order>26</sort_order>
265
+ <show_in_default>1</show_in_default>
266
+ <show_in_website>1</show_in_website>
267
+ <show_in_store>1</show_in_store>
268
+ <depends><custom_colors>1</custom_colors></depends>
269
+ </color_button>
270
+ <color_button_text translate="label">
271
+ <label>Button text color</label>
272
+ <frontend_type>text</frontend_type>
273
+ <validate>color</validate>
274
+ <sort_order>27</sort_order>
275
+ <show_in_default>1</show_in_default>
276
+ <show_in_website>1</show_in_website>
277
+ <show_in_store>1</show_in_store>
278
+ <depends><custom_colors>1</custom_colors></depends>
279
+ </color_button_text>
280
+ <color_checkbox translate="label">
281
+ <label>Checkbox color</label>
282
+ <frontend_type>text</frontend_type>
283
+ <validate>color</validate>
284
+ <sort_order>28</sort_order>
285
+ <show_in_default>1</show_in_default>
286
+ <show_in_website>1</show_in_website>
287
+ <show_in_store>1</show_in_store>
288
+ <depends><custom_colors>1</custom_colors></depends>
289
+ </color_checkbox>
290
+ <color_checkbox_checkmark translate="label">
291
+ <label>Checkbox checkmark color</label>
292
+ <frontend_type>text</frontend_type>
293
+ <validate>color</validate>
294
+ <sort_order>29</sort_order>
295
+ <show_in_default>1</show_in_default>
296
+ <show_in_website>1</show_in_website>
297
+ <show_in_store>1</show_in_store>
298
+ <depends><custom_colors>1</custom_colors></depends>
299
+ </color_checkbox_checkmark>
300
+ <color_header translate="label">
301
+ <label>Header color</label>
302
+ <frontend_type>text</frontend_type>
303
+ <validate>color</validate>
304
+ <sort_order>30</sort_order>
305
+ <show_in_default>1</show_in_default>
306
+ <show_in_website>1</show_in_website>
307
+ <show_in_store>1</show_in_store>
308
+ <depends><custom_colors>1</custom_colors></depends>
309
+ </color_header>
310
+ <color_link translate="label">
311
+ <label>Link color</label>
312
+ <frontend_type>text</frontend_type>
313
+ <validate>color</validate>
314
+ <sort_order>31</sort_order>
315
+ <show_in_default>1</show_in_default>
316
+ <show_in_website>1</show_in_website>
317
+ <show_in_store>1</show_in_store>
318
+ <depends><custom_colors>1</custom_colors></depends>
319
+ </color_link>
320
  </fields>
321
  </klarnaCheckout_payment>
322
  </groups>
app/code/community/Avenla/KlarnaCheckout/etc/widget.xml CHANGED
@@ -3,16 +3,14 @@
3
 
4
  This file is released under a custom license by Avenla Oy.
5
  All rights reserved
6
-
7
- License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
8
  For questions and support - klarna-support@avenla.com
9
-
10
  @category Avenla
11
  @package Avenla_KlarnaCheckout
12
  @copyright Copyright (c) Avenla Oy
13
- @link http://www.avenla.fi
14
-
15
-
16
 
17
  Avenla KlarnaCheckout
18
 
@@ -21,93 +19,92 @@
21
 
22
  -->
23
  <widgets>
24
- <klarnaCheckout_methods type="klarnaCheckout/widgets_methods">
25
  <name>Klarna Checkout payment methods</name>
26
- <description type="desc">View your Klarna Checkout payment methods with Klarna tooltip</description>
27
- <parameters>
28
- <methodslayout>
29
- <required>1</required>
30
- <visible>1</visible>
31
- <label>Layout</label>
32
- <type>select</type>
33
- <values>
34
- <sinle_row translate="label">
35
- <value>long</value>
36
- <label>One row</label>
37
- </sinle_row>
38
- <two_rows translate="label">
39
- <value>short</value>
40
- <label>Two rows</label>
41
- </two_rows>
42
- </values>
43
- </methodslayout>
44
- <color>
45
- <required>1</required>
46
- <visible>1</visible>
47
- <label>Color</label>
48
- <type>select</type>
49
- <values>
50
- <blue translate="label">
51
- <value>blue</value>
52
- <label>Blue</label>
53
- </blue>
54
- <white translate="label">
55
- <value>white</value>
56
- <label>White</label>
57
- </white>
58
- </values>
59
- </color>
60
- <tooltiplayout>
61
- <required>1</required>
62
- <visible>1</visible>
63
- <label>Tooltip layout</label>
64
- <type>select</type>
65
- <values>
66
- <blue translate="label">
67
- <value>blue</value>
68
- <label>Blue</label>
69
- </blue>
70
- <white translate="label">
71
- <value>white</value>
72
- <label>White</label>
73
- </white>
74
- </values>
75
- </tooltiplayout>
76
- <width>
77
- <required>1</required>
78
- <visible>1</visible>
79
- <label>Width</label>
80
- <type>text</type>
81
- </width>
82
- </parameters>
83
-
84
  </klarnaCheckout_methods>
85
  <klarnaCheckout_logo type="klarnaCheckout/widgets_logo">
86
  <name>Klarna logo</name>
87
- <description type="desc">View Klarna logo</description>
88
- <parameters>
89
- <background>
90
- <required>1</required>
91
- <visible>1</visible>
92
- <label>Background</label>
93
- <type>select</type>
94
- <values>
95
- <light translate="label">
96
- <value>blue-black</value>
97
- <label>Light</label>
98
- </light>
99
- <dark translate="label">
100
- <value>white</value>
101
- <label>Dark</label>
102
- </dark>
103
- </values>
104
- </background>
105
- <width>
106
- <required>1</required>
107
- <visible>1</visible>
108
- <label>Width</label>
109
- <type>text</type>
110
- </width>
111
- </parameters>
112
  </klarnaCheckout_logo>
113
  </widgets>
3
 
4
  This file is released under a custom license by Avenla Oy.
5
  All rights reserved
6
+
7
+ License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
8
  For questions and support - klarna-support@avenla.com
9
+
10
  @category Avenla
11
  @package Avenla_KlarnaCheckout
12
  @copyright Copyright (c) Avenla Oy
13
+ @link http://www.avenla.fi
 
 
14
 
15
  Avenla KlarnaCheckout
16
 
19
 
20
  -->
21
  <widgets>
22
+ <klarnaCheckout_methods type="klarnaCheckout/widgets_methods">
23
  <name>Klarna Checkout payment methods</name>
24
+ <description type="desc">View your Klarna Checkout payment methods with Klarna tooltip</description>
25
+ <parameters>
26
+ <methodslayout>
27
+ <required>1</required>
28
+ <visible>1</visible>
29
+ <label>Layout</label>
30
+ <type>select</type>
31
+ <values>
32
+ <sinle_row translate="label">
33
+ <value>long</value>
34
+ <label>One row</label>
35
+ </sinle_row>
36
+ <two_rows translate="label">
37
+ <value>short</value>
38
+ <label>Two rows</label>
39
+ </two_rows>
40
+ </values>
41
+ </methodslayout>
42
+ <color>
43
+ <required>1</required>
44
+ <visible>1</visible>
45
+ <label>Color</label>
46
+ <type>select</type>
47
+ <values>
48
+ <blue translate="label">
49
+ <value>blue</value>
50
+ <label>Blue</label>
51
+ </blue>
52
+ <white translate="label">
53
+ <value>white</value>
54
+ <label>White</label>
55
+ </white>
56
+ </values>
57
+ </color>
58
+ <tooltiplayout>
59
+ <required>1</required>
60
+ <visible>1</visible>
61
+ <label>Tooltip layout</label>
62
+ <type>select</type>
63
+ <values>
64
+ <blue translate="label">
65
+ <value>blue</value>
66
+ <label>Blue</label>
67
+ </blue>
68
+ <white translate="label">
69
+ <value>white</value>
70
+ <label>White</label>
71
+ </white>
72
+ </values>
73
+ </tooltiplayout>
74
+ <width>
75
+ <required>1</required>
76
+ <visible>1</visible>
77
+ <label>Width</label>
78
+ <type>text</type>
79
+ </width>
80
+ </parameters>
 
81
  </klarnaCheckout_methods>
82
  <klarnaCheckout_logo type="klarnaCheckout/widgets_logo">
83
  <name>Klarna logo</name>
84
+ <description type="desc">View Klarna logo</description>
85
+ <parameters>
86
+ <background>
87
+ <required>1</required>
88
+ <visible>1</visible>
89
+ <label>Background</label>
90
+ <type>select</type>
91
+ <values>
92
+ <light translate="label">
93
+ <value>blue-black</value>
94
+ <label>Light</label>
95
+ </light>
96
+ <dark translate="label">
97
+ <value>white</value>
98
+ <label>Dark</label>
99
+ </dark>
100
+ </values>
101
+ </background>
102
+ <width>
103
+ <required>1</required>
104
+ <visible>1</visible>
105
+ <label>Width</label>
106
+ <type>text</type>
107
+ </width>
108
+ </parameters>
109
  </klarnaCheckout_logo>
110
  </widgets>
app/design/adminhtml/default/default/template/KCO/info.phtml CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,49 +20,103 @@
20
  */
21
  ?>
22
  <?php if ($this->getRequest()->getActionName() == "view"): ?>
23
-
24
- <img src="<?php echo $imgSrc; ?>" alt="Klarna Checkout" />
25
- <a href="<?php echo $guiUrl; ?>" target="_blank" style="float:right"><?php echo $this->__('Klarna online GUI'); ?></a>
26
 
27
- <?php if (count($info->getAdditionalInformation("klarna_order_invoice")) > 0): ?>
28
-
29
- <?php foreach($info->getAdditionalInformation("klarna_order_invoice") as $inv): ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  <p>
31
  <b><?php echo $this->__('Klarna Invoice number: %s', $inv["invoice"]); ?></b>
32
- <?php if(isset($pdfUrl)): ?>
33
- <a href="<?php echo $pdfUrl . $inv['invoice'] . ".pdf" ?>" target="_blank"><?php echo $this->__('Packing slip'); ?></a>
34
  <?php endif; ?>
35
  </p>
36
  <?php endforeach; ?>
37
-
38
- <?php endif; ?>
39
-
40
- <?php if($this->getInfo()->getOrder()->getState() != Mage_Sales_Model_Order::STATE_COMPLETE): ?>
41
- <p><b>
42
- <?php echo $this->__('Klarna reservation number: %s', $info->getAdditionalInformation("klarna_order_reservation"));?>
43
-
44
- <?php if (strlen($info->getAdditionalInformation("klarna_order_reservation_expiration")) > 0): ?>
45
- <p>
46
- <?php echo $this->__('Klarna reservation expires: %s',
47
- Mage::helper('core')->formatDate($info->getAdditionalInformation("klarna_order_reservation_expiration"), 'medium', false)); ?>
48
- </p>
49
-
50
- <?php
51
- $temp_time = strtotime($info->getAdditionalInformation("klarna_order_reservation_expiration"));
52
- $expiration = new Zend_Date($info->getAdditionalInformation("klarna_order_reservation_expiration"));
53
- $now = new Zend_Date();
54
- ?>
55
- <?php if(strtotime($info->getAdditionalInformation("klarna_order_reservation_expiration")) < $now->get()): ?>
56
- <p class="klarnaAlert" style="font-weight:bold; color:red;"><?php echo $this->__('Klarna reservation has expired.'); ?></p>
57
- <?php endif; ?>
58
- <?php endif; ?>
59
- </b></p>
60
  <?php endif; ?>
61
 
62
- <?php if(isset($message)): ?>
63
- <p><b><?php echo $message; ?></b></p>
64
  <?php endif; ?>
65
-
66
  <?php else: ?>
67
  <p>Klarna Checkout</p>
68
  <?php endif; ?>
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  ?>
22
  <?php if ($this->getRequest()->getActionName() == "view"): ?>
 
 
 
23
 
24
+ <?php // Logo and GUI link ?>
25
+ <img src="<?php echo $klarnaInfo->getLogoSrc(); ?>" alt="Klarna Checkout" />
26
+ <?php if($klarnaInfo->getGuiUrl()): ?>
27
+ <a href="<?php echo $klarnaInfo->getGuiUrl(); ?>" target="_blank" style="float:right"><?php echo $this->__('Klarna online GUI'); ?></a>
28
+ <?php endif; ?>
29
+
30
+ <?php // Klarna reservation ?>
31
+ <?php if($klarnaInfo->getReservation() && $orderState != Mage_Sales_Model_Order::STATE_COMPLETE): ?>
32
+ <p><b><?php echo $this->__('Klarna reservation : %s', $klarnaInfo->getReservation());?></b><p>
33
+ <?php endif; ?>
34
+
35
+ <?php // Klarna reference ?>
36
+ <?php if($klarnaInfo->getKlarnaReference()): ?>
37
+ <p><b><?php echo $this->__('Klarna reference number: %s', $klarnaInfo->getKlarnaReference());?></b><p>
38
+ <?php endif; ?>
39
+
40
+ <?php // Order status ?>
41
+ <?php if($klarnaInfo->getStatusMessage()): ?>
42
+ <p><?php echo $this->__($klarnaInfo->getStatusMessage());?><p>
43
+ <?php endif; ?>
44
+
45
+ <?php // Remaining amount on reservation ?>
46
+ <?php if($klarnaInfo->getRemainingAmount()): ?>
47
+ <p><?php echo $this->__('Remaining amount: %s', Mage::helper('klarnaCheckout')->formatKlarnaPriceForMagento($klarnaInfo->getRemainingAmount(), $orderStore));?><p>
48
+ <?php endif; ?>
49
+
50
+ <?php // Reservation expiration ?>
51
+ <?php if($klarnaInfo->getExpiration() && $orderState != Mage_Sales_Model_Order::STATE_COMPLETE): ?>
52
+ <p><?php echo $this->__('Klarna reservation expires: %s', Mage::helper('core')->formatDate($klarnaInfo->getExpiration(), 'medium', false)); ?></p>
53
+ <?php $now = new Zend_Date();?>
54
+ <?php if(strtotime($klarnaInfo->getExpiration()) < $now->get()): ?>
55
+ <p class="klarnaAlert" style="font-weight:bold; color:red;"><?php echo $this->__('Klarna reservation has expired.'); ?></p>
56
+ <?php endif; ?>
57
+ <?php endif; ?>
58
+
59
+ <?php // Invoices ?>
60
+ <?php if($klarnaInfo->getCaptures()):?>
61
+ <div style="border:1px solid #CCC;padding:5px;">
62
+ <p><?php echo $this->__('Captures:'); ?></p>
63
+ <table class="actions">
64
+ <tr>
65
+ <th><?php echo $this->__('Reference'); ?></th>
66
+ <th><?php echo $this->__('Captured amount'); ?></th>
67
+ <th><?php echo $this->__('Captured at'); ?></th>
68
+ <th><?php echo $this->__('Refunded amount'); ?></th>
69
+ </tr>
70
+
71
+ <?php foreach($klarnaInfo->getCaptures() as $capture): ?>
72
+ <tr>
73
+ <td><?php echo $capture['klarna_reference']; ?></td>
74
+ <td><?php echo Mage::helper('klarnaCheckout')->formatKlarnaPriceForMagento($capture['captured_amount'], $orderStore); ?></td>
75
+ <td><?php echo Mage::helper('core')->formatDate($capture['captured_at'], 'medium', false); ?></td>
76
+ <td><?php echo Mage::helper('klarnaCheckout')->formatKlarnaPriceForMagento($capture['refunded_amount'], $orderStore); ?></td>
77
+ </tr>
78
+ <?php endforeach; ?>
79
+ </table>
80
+ </div>
81
+ <?php endif; ?>
82
+
83
+ <?php // Refunds ?>
84
+ <?php if($klarnaInfo->getRefunds()):?>
85
+ <div style="border:1px solid #CCC;padding:5px;">
86
+ <p><?php echo $this->__('Refunds:'); ?></p>
87
+ <table class="actions">
88
+ <tr>
89
+ <th><?php echo $this->__('Refunded amount'); ?></th>
90
+ <th><?php echo $this->__('Refunded at'); ?></th>
91
+ <th><?php echo $this->__('Description'); ?></th>
92
+ </tr>
93
+
94
+ <?php foreach($klarnaInfo->getRefunds() as $refund): ?>
95
+ <tr>
96
+ <td><?php echo Mage::helper('klarnaCheckout')->formatKlarnaPriceForMagento($refund['refunded_amount'], $orderStore); ?></td>
97
+ <td><?php echo Mage::helper('core')->formatDate($refund['refunded_at'], 'medium', false); ?></td>
98
+ <td><?php echo $refund['description']; ?></td>
99
+ </tr>
100
+ <?php endforeach; ?>
101
+ </table>
102
+ </div>
103
+ <?php endif; ?>
104
+
105
+ <?php // Klarna invoices ?>
106
+ <?php if ($klarnaInfo->getOrderInvoices()): ?>
107
+ <?php foreach($klarnaInfo->getOrderInvoices() as $inv): ?>
108
  <p>
109
  <b><?php echo $this->__('Klarna Invoice number: %s', $inv["invoice"]); ?></b>
110
+ <?php if($klarnaInfo->getPdfUrl()): ?>
111
+ <a href="<?php echo $klarnaInfo->getPdfUrl() . $inv['invoice'] . ".pdf" ?>" target="_blank"><?php echo $this->__('Packing slip'); ?></a>
112
  <?php endif; ?>
113
  </p>
114
  <?php endforeach; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  <?php endif; ?>
116
 
117
+ <?php if($klarnaInfo->getMessage()): ?>
118
+ <p><b><?php echo $klarnaInfo->getMessage(); ?></b></p>
119
  <?php endif; ?>
 
120
  <?php else: ?>
121
  <p>Klarna Checkout</p>
122
  <?php endif; ?>
app/design/adminhtml/default/default/template/KCO/system/config/field/pclass.phtml CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -22,9 +22,8 @@
22
  <script type="text/javascript">
23
  //<![CDATA[
24
  function updatePClasses() {
25
-
26
  new Ajax.Request('<?php echo $this->getAjaxUpdateUrl() ?>', {
27
- onSuccess: function(response){
28
  if (response.responseText){
29
  $('pclassResponse').update(response.responseText);
30
  }
@@ -33,5 +32,10 @@
33
  }
34
  //]]>
35
  </script>
36
- <?php echo $this->getButtonHtml() ?>
37
- <p id="pclassResponse"></p>
 
 
 
 
 
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
22
  <script type="text/javascript">
23
  //<![CDATA[
24
  function updatePClasses() {
 
25
  new Ajax.Request('<?php echo $this->getAjaxUpdateUrl() ?>', {
26
+ onSuccess: function(response){
27
  if (response.responseText){
28
  $('pclassResponse').update(response.responseText);
29
  }
32
  }
33
  //]]>
34
  </script>
35
+
36
+ <div class="pp-buttons-container">
37
+ <button onclick="javascript:updatePClasses(); return false;" class="scalable" type="button" id="<?php echo $this->getHtmlId() ?>">
38
+ <span><span><span><?php echo $this->escapeHtml($this->getButtonLabel()); ?></span></span></span>
39
+ </button>
40
+ </div>
41
+ <p id="pclassResponse" style="clear:both;"></p>
app/design/adminhtml/default/default/template/KCO/system/config/fieldset/info.phtml CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -27,7 +27,7 @@
27
  <a href="<?php echo $documentationUrl; ?>" target="_blank" style="float: right;clear: both;margin-top: 10px;">
28
  <?php echo $this->__('Avenla Klarna Checkout module documentation'); ?>
29
  </a>
30
-
31
  <div class="infoContent">
32
  <?php
33
  $alerts = $this->getAlerts();
@@ -35,7 +35,7 @@
35
  ?>
36
  <ul>
37
  <?php foreach($alerts as $alert): ?>
38
- <li class="klarna_alert" style="color:red;}">
39
  <?php echo '<b>' . $this->__('Warning!') .'</b> '. $this->__($alert); ?></li>
40
  <?php endforeach; ?>
41
  </ul>
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
27
  <a href="<?php echo $documentationUrl; ?>" target="_blank" style="float: right;clear: both;margin-top: 10px;">
28
  <?php echo $this->__('Avenla Klarna Checkout module documentation'); ?>
29
  </a>
30
+
31
  <div class="infoContent">
32
  <?php
33
  $alerts = $this->getAlerts();
35
  ?>
36
  <ul>
37
  <?php foreach($alerts as $alert): ?>
38
+ <li class="klarna_alert" style="color:red;">
39
  <?php echo '<b>' . $this->__('Warning!') .'</b> '. $this->__($alert); ?></li>
40
  <?php endforeach; ?>
41
  </ul>
app/design/frontend/base/default/template/KCO/KCO.phtml CHANGED
@@ -19,14 +19,7 @@
19
  * @package Avenla_KlarnaCheckout
20
  */
21
  ?>
22
- <?php
23
- if (Mage::app()->getStore()->isCurrentlySecure()){
24
- $kcoloadurl = $this->getUrl("klarnaCheckout/KCO/loadKcoFrame/", array("_forced_secure" => true));
25
- }
26
- else{
27
- $kcoloadurl = $this->getUrl("klarnaCheckout/KCO/loadKcoFrame/");
28
- }
29
- ?>
30
  <div id="klarnaMsg" style="display:none"><h2></h2></div>
31
 
32
  <div id="klarnaWrapper" name="klarnaWrapper">
@@ -37,13 +30,8 @@
37
  <script>
38
  function loadFrame()
39
  {
40
- var kcoloadurl = '<?php echo $kcoloadurl; ?>';
41
 
42
- if($$('div.payments')[0]){
43
- if($$('div.payments')[0].getWidth() < 600)
44
- kcoloadurl = kcoloadurl + 'mobile/1';
45
- }
46
-
47
  new Ajax.Request(kcoloadurl, {
48
  method:'POST',
49
  onSuccess: function(k) {
@@ -90,8 +78,7 @@
90
  },250);
91
  }
92
  }
93
-
94
-
95
  document.observe('dom:loaded', function(){
96
  loadFrame();
97
  });
19
  * @package Avenla_KlarnaCheckout
20
  */
21
  ?>
22
+
 
 
 
 
 
 
 
23
  <div id="klarnaMsg" style="display:none"><h2></h2></div>
24
 
25
  <div id="klarnaWrapper" name="klarnaWrapper">
30
  <script>
31
  function loadFrame()
32
  {
33
+ var kcoloadurl = '<?php echo $this->getLoadUrl(); ?>';
34
 
 
 
 
 
 
35
  new Ajax.Request(kcoloadurl, {
36
  method:'POST',
37
  onSuccess: function(k) {
78
  },250);
79
  }
80
  }
81
+
 
82
  document.observe('dom:loaded', function(){
83
  loadFrame();
84
  });
app/design/frontend/base/default/template/KCO/catalog/product/price.phtml CHANGED
@@ -19,20 +19,19 @@
19
  * @package Avenla_KlarnaCheckout
20
  */
21
  ?>
22
- <?php if($this->getWidgetType() == "klarna"): ?>
23
- <?php $params = $this->getWidgetData(); ?>
24
- <?php if($params['price']): ?>
25
- <div style="width:<?php echo $params['width']; ?>px; height:<?php echo $params['height']; ?>px"
 
 
 
 
26
  class="klarna-widget klarna-part-payment"
27
- data-eid="<?php echo $params['eid']; ?>"
28
- data-locale="<?php echo $params['locale']; ?>"
29
- data-price="<?php echo $params['price']; ?>"
30
- data-layout="<?php echo $params['layout']; ?>">
31
  </div>
32
- <?php endif; ?>
33
- <?php elseif($this->getWidgetType() == "product" && $this->getWidgetData()): ?>
34
- <div class="kco-ppayment">
35
- <p><?php echo $this->getWidgetData(); ?></p>
36
- <img src="<?php echo Mage::helper('klarnaCheckout')->getLogoSrc(50); ?>" />
37
- </div>
38
  <?php endif; ?>
19
  * @package Avenla_KlarnaCheckout
20
  */
21
  ?>
22
+ <?php if($data = $this->getWidgetData()): ?>
23
+ <?php if($monthly = $data->getMonthlyPrice()): ?>
24
+ <div class="kco-ppayment">
25
+ <p><?php echo Mage::helper('klarnaCheckout')->__("From %s/mo.", $monthly); ?></p>
26
+ <img src="<?php echo Mage::helper('klarnaCheckout')->getLogoSrc(50); ?>" />
27
+ </div>
28
+ <?php elseif($data->getPrice()): ?>
29
+ <div style="width:<?php echo $data->getWidth(); ?>px; height:<?php echo $data->getHeight(); ?>px"
30
  class="klarna-widget klarna-part-payment"
31
+ data-eid="<?php echo $data->getEid(); ?>"
32
+ data-locale="<?php echo $data->getLocale(); ?>"
33
+ data-price="<?php echo $data->getPrice(); ?>"
34
+ data-layout="<?php echo $data->getLayout(); ?>">
35
  </div>
36
+ <?php endif; ?>
 
 
 
 
 
37
  <?php endif; ?>
app/design/frontend/base/default/template/KCO/info.phtml CHANGED
@@ -2,14 +2,14 @@
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,5 +20,5 @@
20
  */
21
  ?>
22
 
23
- <img src="<?php echo $imgSrc; ?>" alt="Klarna Checkout" />
24
  <p><?php echo $this->__('Klarna Checkout'); ?></p>
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  ?>
22
 
23
+ <img src="<?php echo Mage::helper('klarnaCheckout')->getLogoSrc(); ?>" alt="Klarna Checkout" />
24
  <p><?php echo $this->__('Klarna Checkout'); ?></p>
app/design/frontend/base/default/template/KCO/link.phtml CHANGED
@@ -1,15 +1,15 @@
1
- <?php
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
- *
6
- * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
- *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
- * @link http://www.avenla.fi
13
  */
14
 
15
  /**
@@ -20,10 +20,9 @@
20
  */
21
  ?>
22
  <?php $helper = Mage::helper("klarnaCheckout"); ?>
23
-
24
  <a href="<?php echo $helper->getCartUri();?>" class="klarnaLink">
25
  <img src="<?php echo $helper->getLogoSrc(); ?>" alt="Klarna Checkout" />
26
- <p class="klarnaLinkText"><?php echo $this->__($helper->getLinkText());?></p>
27
  </a>
28
 
29
  <?php echo $this->getChildHtml('original'); ?>
1
+ <?php
2
  /**
3
  * This file is released under a custom license by Avenla Oy.
4
  * All rights reserved
5
+ *
6
+ * License and more information can be found at http://productdownloads.avenla.com/magento-modules/klarna-checkout/
7
  * For questions and support - klarna-support@avenla.com
8
+ *
9
  * @category Avenla
10
  * @package Avenla_KlarnaCheckout
11
  * @copyright Copyright (c) Avenla Oy
12
+ * @link http://www.avenla.fi
13
  */
14
 
15
  /**
20
  */
21
  ?>
22
  <?php $helper = Mage::helper("klarnaCheckout"); ?>
 
23
  <a href="<?php echo $helper->getCartUri();?>" class="klarnaLink">
24
  <img src="<?php echo $helper->getLogoSrc(); ?>" alt="Klarna Checkout" />
25
+ <p class="klarnaLinkText"><?php echo $helper->__(Mage::getModel('klarnaCheckout/config')->getLinkText());?></p>
26
  </a>
27
 
28
  <?php echo $this->getChildHtml('original'); ?>
app/locale/fi_FI/Avenla_KlarnaCheckout.csv CHANGED
@@ -1,7 +1,6 @@
1
  "Klarna online GUI", "Klarna hallinta"
2
  "Klarna Invoice number: %s", "Klarna laskunumero: %s"
3
  "Packing slip", "Lasku"
4
- "Klarna reservation number: %s", "Klarna varausnumero: %s"
5
  "Klarna reservation expires: %s", "Klarna varaus erääntyy: %s"
6
  "Klarna reservation has expired.", "Klarna varaus on erääntynyt."
7
  "Klarna API Documentation", "Klarna API dokumentaatio"
@@ -88,4 +87,16 @@
88
  "Checkbox color", "Valintaruudun väri"
89
  "Checkbox checkmark color", "Valintaruudun valinnan väri"
90
  "Header color", "Otsikoiden väri"
91
- "Link color", "Linkkien väri"
 
 
 
 
 
 
 
 
 
 
 
 
1
  "Klarna online GUI", "Klarna hallinta"
2
  "Klarna Invoice number: %s", "Klarna laskunumero: %s"
3
  "Packing slip", "Lasku"
 
4
  "Klarna reservation expires: %s", "Klarna varaus erääntyy: %s"
5
  "Klarna reservation has expired.", "Klarna varaus on erääntynyt."
6
  "Klarna API Documentation", "Klarna API dokumentaatio"
87
  "Checkbox color", "Valintaruudun väri"
88
  "Checkbox checkmark color", "Valintaruudun valinnan väri"
89
  "Header color", "Otsikoiden väri"
90
+ "Link color", "Linkkien väri"
91
+ "Please confirm that your contract with Klarna allows the use of a separate shipping address.", "Varmistahan Klarnalta että sopimuksenne sallii erillisten toimitusosoitteiden käytön"
92
+ "API", "Rajapinta"
93
+ "Allow separate shipping address", "Salli erillinen toimitusosoite"
94
+ "Klarna reservation : %s", "Klarna varaus : %s"
95
+ "Klarna reference number: %s", "Klarna viite: %s"
96
+ "Remaining amount: %s", "Jäljellä oleva summa: %s"
97
+ "Reference", "Viite"
98
+ "Captured amount", "Suoritettu summa"
99
+ "Captured at", "Suoritettu"
100
+ "Refunded amount", "Hyvitetty summa"
101
+ "Refunded at", "Hyvitetty"
102
+ "Description", "Kuvaus"
lib/Klarna/Exceptions.php DELETED
@@ -1,735 +0,0 @@
1
- <?php
2
- /**
3
- * Klarna Exceptions
4
- *
5
- * PHP Version 5.3
6
- *
7
- * @category Payment
8
- * @package KlarnaAPI
9
- * @author MS Dev <ms.modules@klarna.com>
10
- * @copyright 2012 Klarna AB (http://klarna.com)
11
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
12
- * @link http://integration.klarna.com/
13
- */
14
-
15
- require_once 'Country.php';
16
-
17
- /**
18
- * KlarnaException class, only used so it says "KlarnaException" instead of
19
- * Exception.
20
- *
21
- * @category Payment
22
- * @package KlarnaAPI
23
- * @author MS Dev <ms.modules@klarna.com>
24
- * @copyright 2012 Klarna AB (http://klarna.com)
25
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
26
- * @link http://integration.klarna.com/
27
- */
28
- class KlarnaException extends Exception
29
- {
30
- /**
31
- * Returns an error message readable by end customers.
32
- *
33
- * @return string
34
- */
35
- public function __toString()
36
- {
37
- return $this->getMessage() . " (#".$this->code.")";
38
- }
39
- }
40
-
41
- /**
42
- * Exception for invalid Configuration object
43
- *
44
- * @category Payment
45
- * @package KlarnaAPI
46
- * @author MS Dev <ms.modules@klarna.com>
47
- * @copyright 2012 Klarna AB (http://klarna.com)
48
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
49
- * @link http://integration.klarna.com/
50
- */
51
- class Klarna_InvalidConfigurationException extends KlarnaException
52
- {
53
- /**
54
- * Constructor
55
- */
56
- public function __construct()
57
- {
58
- parent::__construct(
59
- "Supplied config is not a KlarnaConfig/ArrayAccess object!",
60
- 50001
61
- );
62
- }
63
- }
64
- /**
65
- * Exception for incomplete Configuration object
66
- *
67
- * @category Payment
68
- * @package KlarnaAPI
69
- * @author MS Dev <ms.modules@klarna.com>
70
- * @copyright 2012 Klarna AB (http://klarna.com)
71
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
72
- * @link http://integration.klarna.com/
73
- */
74
- class Klarna_IncompleteConfigurationException extends KlarnaException
75
- {
76
- /**
77
- * Constructor
78
- */
79
- public function __construct()
80
- {
81
- parent::__construct('Klarna instance not fully configured!', 50002);
82
- }
83
- }
84
-
85
- /**
86
- * Exception for invalid KlarnaAddr object
87
- *
88
- * @category Payment
89
- * @package KlarnaAPI
90
- * @author MS Dev <ms.modules@klarna.com>
91
- * @copyright 2012 Klarna AB (http://klarna.com)
92
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
93
- * @link http://integration.klarna.com/
94
- */
95
- class Klarna_InvalidKlarnaAddrException extends KlarnaException
96
- {
97
- /**
98
- * Constructor
99
- */
100
- public function __construct()
101
- {
102
- parent::__construct(
103
- "Supplied address is not a KlarnaAddr object!",
104
- 50011
105
- );
106
- }
107
- }
108
-
109
- /**
110
- * Exception for no KlarnaAddr set
111
- *
112
- * @category Payment
113
- * @package KlarnaAPI
114
- * @author MS Dev <ms.modules@klarna.com>
115
- * @copyright 2012 Klarna AB (http://klarna.com)
116
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
117
- * @link http://integration.klarna.com/
118
- */
119
- class Klarna_MissingAddressException extends KlarnaException
120
- {
121
- /**
122
- * Constructor
123
- */
124
- public function __construct()
125
- {
126
- parent::__construct("No address set!", 50035);
127
- }
128
- }
129
-
130
- /**
131
- * Exception for missing Configuration field
132
- *
133
- * @category Payment
134
- * @package KlarnaAPI
135
- * @author MS Dev <ms.modules@klarna.com>
136
- * @copyright 2012 Klarna AB (http://klarna.com)
137
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
138
- * @link http://integration.klarna.com/
139
- */
140
- class Klarna_ConfigFieldMissingException extends KlarnaException
141
- {
142
- /**
143
- * Constructor
144
- *
145
- * @param string $field config field
146
- */
147
- public function __construct($field)
148
- {
149
- parent::__construct("Config field '{$field}' is not valid!", 50003);
150
-
151
- }
152
- }
153
-
154
- /**
155
- * Exception for Unknown Encoding
156
- *
157
- * @category Payment
158
- * @package KlarnaAPI
159
- * @author MS Dev <ms.modules@klarna.com>
160
- * @copyright 2012 Klarna AB (http://klarna.com)
161
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
162
- * @link http://integration.klarna.com/
163
- */
164
- class Klarna_UnknownEncodingException extends KlarnaException
165
- {
166
- /**
167
- * Constructor
168
- *
169
- * @param int $encoding encoding
170
- */
171
- public function __construct($encoding)
172
- {
173
- parent::__construct(
174
- "Unknown PNO/SSN encoding constant! ({$encoding})", 50091
175
- );
176
- }
177
- }
178
-
179
- /**
180
- * Exception for Unknown Address Type
181
- *
182
- * @category Payment
183
- * @package KlarnaAPI
184
- * @author MS Dev <ms.modules@klarna.com>
185
- * @copyright 2012 Klarna AB (http://klarna.com)
186
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
187
- * @link http://integration.klarna.com/
188
- */
189
- class Klarna_UnknownAddressTypeException extends KlarnaException
190
- {
191
- /**
192
- * Constructor
193
- *
194
- * @param int $type type
195
- */
196
- public function __construct($type)
197
- {
198
- parent::__construct("Unknown address type: {$type}", 50012);
199
- }
200
- }
201
-
202
- /**
203
- * Exception for Missing Country
204
- *
205
- * @category Payment
206
- * @package KlarnaAPI
207
- * @author MS Dev <ms.modules@klarna.com>
208
- * @copyright 2012 Klarna AB (http://klarna.com)
209
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
210
- * @link http://integration.klarna.com/
211
- */
212
- class Klarna_MissingCountryException extends KlarnaException
213
- {
214
- /**
215
- * Constructor
216
- */
217
- public function __construct()
218
- {
219
- parent::__construct('You must set country first!', 50046);
220
- }
221
- }
222
-
223
- /**
224
- * Exception for Unknown Country
225
- *
226
- * @category Payment
227
- * @package KlarnaAPI
228
- * @author MS Dev <ms.modules@klarna.com>
229
- * @copyright 2012 Klarna AB (http://klarna.com)
230
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
231
- * @link http://integration.klarna.com/
232
- */
233
- class Klarna_UnknownCountryException extends KlarnaException
234
- {
235
- /**
236
- * Constructor
237
- *
238
- * @param mixed $country country
239
- */
240
- public function __construct($country)
241
- {
242
- parent::__construct("Unknown country! ({$country})", 50006);
243
- }
244
- }
245
-
246
- /**
247
- * Exception for Unknown Language
248
- *
249
- * @category Payment
250
- * @package KlarnaAPI
251
- * @author MS Dev <ms.modules@klarna.com>
252
- * @copyright 2012 Klarna AB (http://klarna.com)
253
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
254
- * @link http://integration.klarna.com/
255
- */
256
- class Klarna_UnknownLanguageException extends KlarnaException
257
- {
258
- /**
259
- * Constructor
260
- *
261
- * @param mixed $language language
262
- */
263
- public function __construct($language)
264
- {
265
- parent::__construct("Unknown language! ({$language})", 50007);
266
- }
267
- }
268
-
269
- /**
270
- * Exception for Unknown Currency
271
- *
272
- * @category Payment
273
- * @package KlarnaAPI
274
- * @author MS Dev <ms.modules@klarna.com>
275
- * @copyright 2012 Klarna AB (http://klarna.com)
276
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
277
- * @link http://integration.klarna.com/
278
- */
279
- class Klarna_UnknownCurrencyException extends KlarnaException
280
- {
281
- /**
282
- * Constructor
283
- *
284
- * @param mixed $currency currency
285
- */
286
- public function __construct($currency)
287
- {
288
- parent::__construct("Unknown currency! ({$currency})", 50008);
289
- }
290
- }
291
-
292
- /**
293
- * Exception for Missing Arguments
294
- *
295
- * @category Payment
296
- * @package KlarnaAPI
297
- * @author MS Dev <ms.modules@klarna.com>
298
- * @copyright 2012 Klarna AB (http://klarna.com)
299
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
300
- * @link http://integration.klarna.com/
301
- */
302
- class Klarna_ArgumentNotSetException extends KlarnaException
303
- {
304
- /**
305
- * Constructor
306
- *
307
- * @param string $argument argument
308
- */
309
- public function __construct($argument)
310
- {
311
- parent::__construct("Argument '{$argument}' not set!", 50005);
312
- }
313
- }
314
-
315
- /**
316
- * Exception for Country and Currency mismatch
317
- *
318
- * @category Payment
319
- * @package KlarnaAPI
320
- * @author MS Dev <ms.modules@klarna.com>
321
- * @copyright 2012 Klarna AB (http://klarna.com)
322
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
323
- * @link http://integration.klarna.com/
324
- */
325
- class Klarna_CountryCurrencyMismatchException extends KlarnaException
326
- {
327
- /**
328
- * Constructor
329
- *
330
- * @param mixed $country country
331
- * @param mixed $currency currency
332
- */
333
- public function __construct($country, $currency)
334
- {
335
- $countryCode = KlarnaCountry::getCode($country);
336
- parent::__construct(
337
- "Mismatching country/currency for '{$countryCode}'! ".
338
- "[country: $country currency: $currency]",
339
- 50011
340
- );
341
- }
342
- }
343
-
344
- /**
345
- * Exception for Country and Currency mismatch
346
- *
347
- * @category Payment
348
- * @package KlarnaAPI
349
- * @author MS Dev <ms.modules@klarna.com>
350
- * @copyright 2012 Klarna AB (http://klarna.com)
351
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
352
- * @link http://integration.klarna.com/
353
- */
354
- class Klarna_CountryLanguageMismatchException extends KlarnaException
355
- {
356
- /**
357
- * Constructor
358
- *
359
- * @param mixed $country country
360
- * @param mixed $language language
361
- */
362
- public function __construct($country, $language)
363
- {
364
- $countryCode = KlarnaCountry::getCode($country);
365
- parent::__construct(
366
- "Mismatching country/language for '{$countryCode}'! ".
367
- "[country: $country language: $language]",
368
- 50024
369
- );
370
- }
371
- }
372
-
373
- /**
374
- * Exception for Shipping country being different from set country
375
- *
376
- * @category Payment
377
- * @package KlarnaAPI
378
- * @author MS Dev <ms.modules@klarna.com>
379
- * @copyright 2012 Klarna AB (http://klarna.com)
380
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
381
- * @link http://integration.klarna.com/
382
- */
383
- class Klarna_ShippingCountryException extends KlarnaException
384
- {
385
- /**
386
- * Constructor
387
- */
388
- public function __construct()
389
- {
390
- parent::__construct(
391
- 'Shipping address country must match the country set!', 50041
392
- );
393
- }
394
- }
395
-
396
- /**
397
- * Exception for Missing Goodslist
398
- *
399
- * @category Payment
400
- * @package KlarnaAPI
401
- * @author MS Dev <ms.modules@klarna.com>
402
- * @copyright 2012 Klarna AB (http://klarna.com)
403
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
404
- * @link http://integration.klarna.com/
405
- */
406
- class Klarna_MissingGoodslistException extends KlarnaException
407
- {
408
- /**
409
- * Constructor
410
- */
411
- public function __construct()
412
- {
413
- parent::__construct("No articles in goodslist!", 50034);
414
- }
415
- }
416
-
417
- /**
418
- * Exception for invalid price
419
- *
420
- * @category Payment
421
- * @package KlarnaAPI
422
- * @author MS Dev <ms.modules@klarna.com>
423
- * @copyright 2012 Klarna AB (http://klarna.com)
424
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
425
- * @link http://integration.klarna.com/
426
- */
427
- class Klarna_InvalidPriceException extends KlarnaException
428
- {
429
- /**
430
- * Constructor
431
- *
432
- * @param mixed $price price
433
- */
434
- public function __construct($price)
435
- {
436
- parent::__construct(
437
- "price/amount must be an integer and greater than 0! ($price)",
438
- 50039
439
- );
440
- }
441
- }
442
-
443
-
444
- /**
445
- * Exception for invalid pcstorage class
446
- *
447
- * @category Payment
448
- * @package KlarnaAPI
449
- * @author MS Dev <ms.modules@klarna.com>
450
- * @copyright 2012 Klarna AB (http://klarna.com)
451
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
452
- * @link http://integration.klarna.com/
453
- */
454
- class Klarna_PCStorageInvalidException extends KlarnaException
455
- {
456
- /**
457
- * Constructor
458
- *
459
- * @param string $className classname
460
- * @param string $pclassStorage pcstorage class file
461
- */
462
- public function __construct($className, $pclassStorage)
463
- {
464
- parent::__construct(
465
- "$className located in $pclassStorage is not a PCStorage instance.",
466
- 50052
467
- );
468
- }
469
- }
470
-
471
- /**
472
- * Exception for invalid type
473
- *
474
- * @category Payment
475
- * @package KlarnaAPI
476
- * @author MS Dev <ms.modules@klarna.com>
477
- * @copyright 2012 Klarna AB (http://klarna.com)
478
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
479
- * @link http://integration.klarna.com/
480
- */
481
- class Klarna_InvalidTypeException extends KlarnaException
482
- {
483
- /**
484
- * Constructor
485
- *
486
- * @param string $param parameter
487
- * @param string $type type
488
- */
489
- public function __construct($param, $type)
490
- {
491
- parent::__construct(
492
- "$param is not of the expected type. Expected: $type.",
493
- 50062
494
- );
495
- }
496
- }
497
-
498
- /**
499
- * Exception for invalid PNO
500
- *
501
- * @category Payment
502
- * @package KlarnaAPI
503
- * @author MS Dev <ms.modules@klarna.com>
504
- * @copyright 2012 Klarna AB (http://klarna.com)
505
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
506
- * @link http://integration.klarna.com/
507
- */
508
- class Klarna_InvalidPNOException extends KlarnaException
509
- {
510
- /**
511
- * Constructor
512
- */
513
- public function __construct()
514
- {
515
- parent::__construct("PNO/SSN is not valid!", 50078);
516
- }
517
- }
518
-
519
-
520
- /**
521
- * Exception for invalid Email
522
- *
523
- * @category Payment
524
- * @package KlarnaAPI
525
- * @author MS Dev <ms.modules@klarna.com>
526
- * @copyright 2012 Klarna AB (http://klarna.com)
527
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
528
- * @link http://integration.klarna.com/
529
- */
530
- class Klarna_InvalidEmailException extends KlarnaException
531
- {
532
- /**
533
- * Constructor
534
- */
535
- public function __construct()
536
- {
537
- parent::__construct("Email is not valid!", 50017);
538
- }
539
- }
540
-
541
- /**
542
- * Exception for invalid Email
543
- *
544
- * @category Payment
545
- * @package KlarnaAPI
546
- * @author MS Dev <ms.modules@klarna.com>
547
- * @copyright 2012 Klarna AB (http://klarna.com)
548
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
549
- * @link http://integration.klarna.com/
550
- */
551
- class Klarna_UnsupportedMarketException extends KlarnaException
552
- {
553
- /**
554
- * Constructor
555
- *
556
- * @param string|array $countries allowed countries
557
- */
558
- public function __construct($countries)
559
- {
560
- if (is_array($countries)) {
561
- $countries = implode(", ", $countries);
562
- }
563
- parent::__construct(
564
- "This method is only available for customers from: {$countries}",
565
- 50025
566
- );
567
- }
568
- }
569
- /**
570
- * Exception for invalid Locale
571
- *
572
- * @category Payment
573
- * @package KlarnaAPI
574
- * @author MS Dev <ms.modules@klarna.com>
575
- * @copyright 2012 Klarna AB (http://klarna.com)
576
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
577
- * @link http://integration.klarna.com/
578
- */
579
- class Klarna_InvalidLocaleException extends KlarnaException
580
- {
581
- /**
582
- * Constructor
583
- */
584
- public function __construct()
585
- {
586
- parent::__construct(
587
- "You must set country, language and currency!",
588
- 50023
589
- );
590
- }
591
- }
592
-
593
- /**
594
- * Exception for Missing Address Fields
595
- *
596
- * @category Payment
597
- * @package KlarnaAPI
598
- * @author MS Dev <ms.modules@klarna.com>
599
- * @copyright 2012 Klarna AB (http://klarna.com)
600
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
601
- * @link http://integration.klarna.com/
602
- */
603
- class Klarna_AddressFieldMissingException extends KlarnaException
604
- {
605
- /**
606
- * Constructor
607
- *
608
- * @param string $argument argument
609
- */
610
- public function __construct($argument)
611
- {
612
- parent::__construct("'{$argument}' not set!", 50015);
613
- }
614
- }
615
-
616
- /**
617
- * Exception for File Not Writable
618
- *
619
- * @category Payment
620
- * @package KlarnaAPI
621
- * @author MS Dev <ms.modules@klarna.com>
622
- * @copyright 2012 Klarna AB (http://klarna.com)
623
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
624
- * @link http://integration.klarna.com/
625
- */
626
- class Klarna_FileNotWritableException extends KlarnaException
627
- {
628
- /**
629
- * Constructor
630
- *
631
- * @param string $file filename
632
- */
633
- public function __construct($file)
634
- {
635
- parent::__construct("Unable to write to {$file}!");
636
- }
637
- }
638
-
639
- /**
640
- * Exception for File Not Readable
641
- *
642
- * @category Payment
643
- * @package KlarnaAPI
644
- * @author MS Dev <ms.modules@klarna.com>
645
- * @copyright 2012 Klarna AB (http://klarna.com)
646
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
647
- * @link http://integration.klarna.com/
648
- */
649
- class Klarna_FileNotReadableException extends KlarnaException
650
- {
651
- /**
652
- * Constructor
653
- *
654
- * @param string $file filename
655
- */
656
- public function __construct($file)
657
- {
658
- parent::__construct("Unable to read from {$file}!");
659
- }
660
- }
661
-
662
- /**
663
- * Exception for File Not Readable
664
- *
665
- * @category Payment
666
- * @package KlarnaAPI
667
- * @author MS Dev <ms.modules@klarna.com>
668
- * @copyright 2012 Klarna AB (http://klarna.com)
669
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
670
- * @link http://integration.klarna.com/
671
- */
672
- class Klarna_FileNotFoundException extends KlarnaException
673
- {
674
- /**
675
- * Constructor
676
- *
677
- * @param string $file filename
678
- */
679
- public function __construct($file)
680
- {
681
- parent::__construct("Unable to find file: {$file}!");
682
- }
683
- }
684
-
685
- /**
686
- * Exception for Database Errors
687
- *
688
- * @category Payment
689
- * @package KlarnaAPI
690
- * @author MS Dev <ms.modules@klarna.com>
691
- * @copyright 2012 Klarna AB (http://klarna.com)
692
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
693
- * @link http://integration.klarna.com/
694
- */
695
-
696
- class Klarna_DatabaseException extends KlarnaException
697
- {
698
- }
699
-
700
- /**
701
- * Exception for PClass Errors
702
- *
703
- * @category Payment
704
- * @package KlarnaAPI
705
- * @author MS Dev <ms.modules@klarna.com>
706
- * @copyright 2012 Klarna AB (http://klarna.com)
707
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
708
- * @link http://integration.klarna.com/
709
- */
710
- class Klarna_PClassException extends KlarnaException
711
- {
712
- }
713
-
714
- /**
715
- * Exception for XML Parse errors
716
- *
717
- * @category Payment
718
- * @package KlarnaAPI
719
- * @author MS Dev <ms.modules@klarna.com>
720
- * @copyright 2012 Klarna AB (http://klarna.com)
721
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
722
- * @link http://integration.klarna.com/
723
- */
724
- class Klarna_XMLParseException extends KlarnaException
725
- {
726
- /**
727
- * Constructor
728
- *
729
- * @param string $file filename
730
- */
731
- public function __construct($file)
732
- {
733
- parent::__construct("Unable to parse XML file: {$file}!");
734
- }
735
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/checkout/checkouthtml.intf.php DELETED
@@ -1,97 +0,0 @@
1
- <?php
2
- /**
3
- * CheckoutHTML interface for threatmetrix
4
- *
5
- * PHP Version 5.3
6
- *
7
- * @category Payment
8
- * @package KlarnaAPI
9
- * @author MS Dev <ms.modules@klarna.com>
10
- * @copyright 2012 Klarna AB (http://klarna.com)
11
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
12
- * @link http://integration.klarna.com/
13
- */
14
-
15
- /**
16
- * This interface provides methods to supply checkout page specific HTML.<br>
17
- * Can be used to insert device identification, fraud prevention,<br>
18
- * client side validation code into the checkout page.
19
- *
20
- * @category Payment
21
- * @package KlarnaAPI
22
- * @author MS Dev <ms.modules@klarna.com>
23
- * @copyright 2012 Klarna AB (http://klarna.com)
24
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
25
- * @link http://integration.klarna.com/
26
- */
27
- abstract class CheckoutHTML
28
- {
29
-
30
- /**
31
- * Creates a session ID used for e.g. client identification and fraud
32
- * prevention.
33
- *
34
- * This method creates a 40 character long integer.
35
- * The first 30 numbers is microtime + random numbers.
36
- * The last 10 numbers is the eid zero-padded.
37
- *
38
- * All random functions are automatically seeded as of PHP 4.2.0.
39
- *
40
- * E.g. for eid 1004 output could be:
41
- * 1624100001298454658880354228080000001004
42
- *
43
- * @param int $eid merchant id
44
- *
45
- * @return string A integer with a string length of 40.
46
- */
47
- public static function getSessionID($eid)
48
- {
49
- $eid = strval($eid);
50
- while (strlen($eid) < 10) {
51
- $eid = "0" . $eid; //Zero-pad the eid.
52
- }
53
-
54
- $sid = str_replace(array(' ', ',', '.'), '', microtime());
55
- $sid[0] = rand(1, 9); //Make sure we always have a non-zero first.
56
-
57
- //microtime + rand = 30 numbers in length
58
- while (strlen($sid) < 30) {
59
- //rand is automatically seeded as of PHP 4.2.0
60
- $sid .= rand(0, 9999);
61
- }
62
- $sid = substr($sid, 0, 30);
63
- $sid .= $eid;
64
-
65
- return $sid;
66
- }
67
-
68
- /**
69
- * Initializes this object, this method is always called
70
- * before {@link CheckoutHTML::toHTML()}.
71
- * This method is used in {@link Klarna::addTransaction()},
72
- * {@link Klarna::reserveAmount()} and in {@link Klarna::checkoutHTML()}
73
- *
74
- * @param Klarna $klarna The API instance
75
- * @param int $eid merchant id
76
- *
77
- * @return void
78
- */
79
- abstract public function init($klarna, $eid);
80
-
81
- /**
82
- * This returns the HTML code for this object,
83
- * which will be used in the checkout page.
84
- *
85
- * @return string HTML
86
- */
87
- abstract public function toHTML();
88
-
89
- /**
90
- * This function is used to clear any stored values
91
- * (in SESSION, COOKIE or similar)
92
- * which are required to be unique between purchases.
93
- *
94
- * @return void
95
- */
96
- abstract public function clear();
97
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/checkout/threatmetrix.class.php DELETED
@@ -1,136 +0,0 @@
1
- <?php
2
- /**
3
- * threatmetrix implementation of checckouthtml
4
- *
5
- * PHP Version 5.3
6
- *
7
- * @category Payment
8
- * @package KlarnaAPI
9
- * @author MS Dev <ms.modules@klarna.com>
10
- * @copyright 2012 Klarna AB (http://klarna.com)
11
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
12
- * @link http://integration.klarna.com/
13
- */
14
-
15
- /**
16
- * ThreatMetrix is a fraud prevention and device identification software.
17
- *
18
- * @category Payment
19
- * @package KlarnaAPI
20
- * @author MS Dev <ms.modules@klarna.com>
21
- * @copyright 2012 Klarna AB (http://klarna.com)
22
- * @license http://opensource.org/licenses/BSD-2-Clause BSD-2
23
- * @link http://integration.klarna.com/
24
- */
25
- class ThreatMetrix extends CheckoutHTML
26
- {
27
-
28
- /**
29
- * The ID used in conjunction with the Klarna API.
30
- *
31
- * @var int
32
- */
33
- const ID = 'dev_id_1';
34
-
35
- /**
36
- * ThreatMetrix organizational ID.
37
- *
38
- * @var string
39
- */
40
- protected $orgID = 'qicrzsu4';
41
-
42
- /**
43
- * Session ID for the client.
44
- *
45
- * @var string
46
- */
47
- protected $sessionID;
48
-
49
- /**
50
- * Hostname used to access ThreatMetrix.
51
- *
52
- * @var string
53
- */
54
- protected $host = 'h.online-metrix.net';
55
-
56
- /**
57
- * Protocol used to access ThreatMetrix.
58
- *
59
- * @var string
60
- */
61
- protected $proto = 'https';
62
-
63
- /**
64
- * Initializes this object, this method is always called
65
- * before {@link CheckoutHTML::toHTML()}.
66
- * This method is used in {@link Klarna::addTransaction()},
67
- * {@link Klarna::reserveAmount()} and in {@link Klarna::checkoutHTML()}
68
- *
69
- * @param Klarna $klarna The API instance
70
- * @param int $eid Merchant ID
71
- *
72
- * @return void
73
- */
74
- public function init($klarna, $eid)
75
- {
76
- if (!is_int($eid)) {
77
- throw new Klarna_ConfigFieldMissingException('eid');
78
- }
79
- if (isset($_SESSION)) {
80
- if (!isset($_SESSION[self::ID])
81
- || (strlen($_SESSION[self::ID]) < 40)
82
- ) {
83
- $_SESSION[self::ID] = parent::getSessionID($eid);
84
- $this->sessionID = $_SESSION[self::ID];
85
- } else {
86
- $this->sessionID = $_SESSION[self::ID];
87
- }
88
- } else {
89
- $this->sessionID = parent::getSessionID($eid);
90
- }
91
-
92
- $klarna->setSessionID(self::ID, $this->sessionID);
93
- }
94
-
95
- /**
96
- * This function is used to clear any stored values
97
- * (in SESSION, COOKIE or similar)
98
- * which are required to be unique between purchases.
99
- *
100
- * @return void
101
- */
102
- public function clear()
103
- {
104
- if (isset($_SESSION) && isset($_SESSION[self::ID])) {
105
- $_SESSION[self::ID] = null;
106
- unset($_SESSION[self::ID]);
107
- }
108
- }
109
-
110
- /**
111
- * This returns the HTML code for this object,
112
- * which will be used in the checkout page.
113
- *
114
- * @return string
115
- */
116
- public function toHTML()
117
- {
118
- $html
119
- = "<p style='display: none; ".
120
- "background:url($this->proto://$this->host/fp/clear.png?org_id=".
121
- "$this->orgID&session_id=$this->sessionID&m=1)'></p>".
122
- "<script src='$this->proto://$this->host/fp/check.js?org_id=".
123
- "$this->orgID&session_id=$this->sessionID' ".
124
- "type='text/javascript'></script>".
125
- "<img src='$this->proto://$this->host/fp/clear.png?org_id=".
126
- "$this->orgID&session_id=$this->sessionID&m=2' alt='' >".
127
- "<object type='application/x-shockwave-flash' style='display: none' ".
128
- "data='$this->proto://$this->host/fp/fp.swf?org_id=$this->orgID&".
129
- "session_id=$this->sessionID' width='1' height='1' id='obj_id'>".
130
- "<param name='movie' value='$this->proto://$this->host/fp/fp.swf?".
131
- "org_id=$this->orgID&session_id=$this->sessionID' />".
132
- "<div></div>".
133
- "</object>";
134
- return $html;
135
- }
136
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/activate.php DELETED
@@ -1,66 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- /**
31
- * 2. Activate the reservation
32
- */
33
- $rno = '123456';
34
-
35
- // Optional fields should be set using
36
- // [[setActivateInfo]]
37
- $k->setActivateInfo('key', 'value');
38
- // [[setActivateInfo]]
39
-
40
- // [[setActivateInfo:response]]
41
- null;
42
- // [[setActivateInfo:response]]
43
-
44
- try {
45
- // [[activate]]
46
- $result = $k->activate($rno);
47
- // [[activate]]
48
-
49
- // [[activate:response]]
50
- array(
51
- "ok",
52
- "1234567890"
53
- );
54
- // [[activate:response]]
55
-
56
-
57
- $risk = $result[0]; // ok or no_risk
58
- $invno = $result[1];
59
-
60
-
61
- echo "risk: {$risk}\ninvno: {$invno}\n";
62
- // Reservation is activated, proceed accordingly.
63
- } catch(Exception $e) {
64
- // Something went wrong, print the message:
65
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
66
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/activateInvoice.php DELETED
@@ -1,53 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
-
34
- /**
35
- * 2. Activate the invoice
36
- */
37
-
38
- // Here you enter the invoice number you got from addTransaction():
39
- $invNo = '123456';
40
-
41
- try {
42
- // You can specify a new pclass ID if the customer wanted to change it
43
- // before you activate.
44
- $url = $k->activateInvoice($invNo, $pclass = KlarnaPClass::INVOICE);
45
-
46
- echo "{$url}\n";
47
-
48
- // The url points to a PDF file for the invoice.
49
- // Invoice activated, proceed accordingly.
50
- } catch(Exception $e) {
51
- // Something went wrong or the invoice doesn't exist.
52
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
53
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/activatePart.php DELETED
@@ -1,67 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Partially activate the invoice
35
- */
36
-
37
- // Here you specify the quantity of an article you wish to partially activate.
38
- // artNo must be the same as the one you used in addArticle() when you made the
39
- // addTransaction() call.
40
- $k->addArtNo(
41
- 1, // Quantity
42
- 'MG200MMS' // Article number
43
- );
44
-
45
- // Here you enter the invoice number you got from addTransaction():
46
- $invNo = '123456';
47
-
48
- try {
49
- $result = $k->activatePart(
50
- $invNo, // Invoice number
51
- KlarnaPClass::INVOICE // Or the PClass ID used to make the order.
52
- );
53
- $url = $result['url'];
54
- echo "url: ${url}\n";
55
- if (isset($result['invno'])) {
56
- $invno = $result['invno'];
57
- echo "invno: ${invno}\n";
58
- }
59
- // The url points to a PDF file for the invoice.
60
- // The invno field is only present if the invoice was not entirely activated,
61
- // and in that case it contains the new invoice number.
62
-
63
- // Invoice activated, proceed accordingly.
64
- } catch(Exception $e) {
65
- // Something went wrong or the invoice doesn't exist.
66
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
67
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/activateReservation.php DELETED
@@ -1,240 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
- // [[init]]
15
- $k = new Klarna();
16
- // [[init]]
17
-
18
- // [[init:response]]
19
- new Klarna();
20
- // [[init:response]]
21
-
22
- // [[config]]
23
- $k->config(
24
- 123456, // Merchant ID
25
- 'sharedSecret', // Shared Secret
26
- KlarnaCountry::SE, // Country
27
- KlarnaLanguage::SV, // Language
28
- KlarnaCurrency::SEK, // Currency
29
- Klarna::BETA, // Server
30
- 'json', // PClass Storage
31
- '/srv/pclasses.json', // PClass Storage URI path
32
- true, // SSL
33
- true // Remote logging of response times of xmlrpc calls
34
- );
35
- // [[config]]
36
-
37
- // [[config:response]]
38
- null;
39
- // [[config:response]]
40
-
41
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
42
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
43
-
44
- /**
45
- * 2. Add the article(s), shipping and/or handling fee.
46
- */
47
-
48
- // Here we add a normal product to our goods list.
49
- $k->addArticle(
50
- 4, // Quantity
51
- "MG200MMS", // Article number
52
- "Matrox G200 MMS", // Article name/title
53
- 299.99, // Price
54
- 25, // 25% VAT
55
- 0, // Discount
56
- KlarnaFlags::INC_VAT // Price is including VAT.
57
- );
58
-
59
- // Next we might want to add a shipment fee for the product
60
- // [[addArticle]]
61
- $k->addArticle(
62
- 1,
63
- "",
64
- "Shipping fee",
65
- 14.5,
66
- 25,
67
- 0,
68
- // Price is including VAT and is shipment fee
69
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
70
- );
71
- // [[addArticle]]
72
-
73
- // [[addArticle:response]]
74
- null;
75
- // [[addArticle:response]]
76
-
77
- // Lastly, we want to use an invoice/handling fee as well
78
- $k->addArticle(
79
- 1,
80
- "",
81
- "Handling fee",
82
- 11.5,
83
- 25,
84
- 0,
85
- // Price is including VAT and is handling/invoice fee
86
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
87
- );
88
-
89
-
90
- /**
91
- * 3. Create and set the address(es).
92
- */
93
-
94
- // Create the address object and specify the values.
95
- // [[setAddress]]
96
- $addr = new KlarnaAddr(
97
- 'always_approved@klarna.com', // email
98
- '', // Telno, only one phone number is needed.
99
- '0762560000', // Cellno
100
- 'Testperson-se', // Firstname
101
- 'Approved', // Lastname
102
- '', // No care of, C/O.
103
- 'Stårgatan 1', // Street
104
- '12345', // Zip Code
105
- 'Ankeborg', // City
106
- KlarnaCountry::SE, // Country
107
- null, // HouseNo for German and Dutch customers.
108
- null // House Extension. Dutch customers only.
109
- );
110
-
111
- $k->setAddress(KlarnaFlags::IS_BILLING, $addr);
112
- // [[setAddress]]
113
-
114
- // [[setAddress:response]]
115
- null;
116
- // [[setAddress:response]]
117
-
118
- $k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
119
-
120
- /**
121
- * 4. Specify relevant information from your store. (OPTIONAL)
122
- */
123
-
124
- // Set store specific information so you can e.g. search and associate invoices
125
- // with order numbers.
126
- // [[setEstoreInfo]]
127
- $k->setEstoreInfo(
128
- 'order id #1',
129
- 'order id #2'
130
- );
131
- // [[setEstoreInfo]]
132
-
133
- // [[setEstoreInfo:response]]
134
- null;
135
- // [[setEstoreInfo:response]]
136
-
137
- // If you don't have the order id available at this stage, you can later use the
138
- // method updateOrderNo().
139
-
140
- /**
141
- * 5. Set additional information. (OPTIONAL)
142
- */
143
-
144
- /** Comment **/
145
-
146
- // [[setComment]]
147
- $k->setComment('A text string stored in the invoice commentary area.');
148
- // [[setComment]]
149
-
150
- // [[setComment:response]]
151
- null;
152
- // [[setComment:response]]
153
-
154
- /** Extra info **/
155
-
156
- // Normal shipment is defaulted, delays the start of invoice
157
- // expiration/due-date.
158
-
159
- // [[setShipmentInfo]]
160
- $k->setShipmentInfo('key', 'value');
161
- // [[setShipmentInfo]]
162
-
163
- // [[setShipmentInfo:response]]
164
- null;
165
- // [[setShipmentInfo:response]]
166
-
167
- // [[setTravelInfo]]
168
- $k->setTravelInfo('key', 'value');
169
- // [[setTravelInfo]]
170
-
171
- // [[setTravelInfo:response]]
172
- null;
173
- // [[setTravelInfo:response]]
174
-
175
- // [[setBankInfo]]
176
- $k->setBankInfo('key', 'value');
177
- // [[setBankInfo]]
178
-
179
- // [[setBankInfo:response]]
180
- null;
181
- // [[setBankInfo:response]]
182
-
183
- // [[setIncomeInfo]]
184
- $k->setIncomeInfo('key', 'value');
185
- // [[setIncomeInfo]]
186
-
187
- // [[setIncomeInfo:response]]
188
- null;
189
- // [[setIncomeInfo:response]]
190
-
191
- // [[setExtraInfo]]
192
- $k->setExtraInfo('key', 'value');
193
- // [[setExtraInfo]]
194
-
195
- // [[setExtraInfo:response]]
196
- null;
197
- // [[setExtraInfo:response]]
198
-
199
- /**
200
- * 6. Invoke activateReservation and transmit the data.
201
- */
202
-
203
- /* Make sure the order status is ACCEPTED, before activation.
204
- You can do this by using checkOrderStatus(). */
205
-
206
- // Here you enter the reservation number you got from reserveAmount():
207
- $rno = '123456';
208
-
209
- try {
210
- // Transmit all the specified data, from the steps above, to Klarna.
211
- // [[activateReservation]]
212
- $result = $k->activateReservation(
213
- '4103219202', // PNO (Date of birth for DE and NL).
214
- $rno, // Reservation to activate
215
- null, // Gender.
216
- '', // OCR number to use if you have reserved one.
217
- KlarnaFlags::NO_FLAG, // Flags to affect behavior.
218
- // -1, notes that this is an invoice purchase, for part payment purchase
219
- // you will have a pclass object which you use getId() from.
220
- KlarnaPClass::INVOICE
221
- );
222
- // [[activateReservation]]
223
-
224
- // [[activateReservation:response]]
225
- array(
226
- "ok",
227
- "1234567890"
228
- );
229
- // [[activateReservation:response]]
230
-
231
- $risk = $result[0]; // ok or no_risk
232
- $invno = $result[1];
233
-
234
-
235
- echo "risk: {$risk}\ninvno: {$invno}\n";
236
- // Reservation is activated, proceed accordingly.
237
- } catch(Exception $e) {
238
- // Something went wrong, print the message:
239
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
240
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/addTransaction.php DELETED
@@ -1,159 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Add the article(s), shipping and/or handling fee.
35
- */
36
-
37
- // Here we add a normal product to our goods list.
38
- $k->addArticle(
39
- 4, // Quantity
40
- "MG200MMS", // Article number
41
- "Matrox G200 MMS", // Article name/title
42
- 299.99, // Price
43
- 25, // 25% VAT
44
- 0, // Discount
45
- KlarnaFlags::INC_VAT // Price is including VAT.
46
- );
47
-
48
- // Next we might want to add a shipment fee for the product
49
- $k->addArticle(
50
- 1,
51
- "",
52
- "Shipping fee",
53
- 14.5,
54
- 25,
55
- 0,
56
- // Price is including VAT and is shipment fee
57
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
58
- );
59
-
60
- // Lastly, we want to use an invoice/handling fee as well
61
- $k->addArticle(
62
- 1,
63
- "",
64
- "Handling fee",
65
- 11.5,
66
- 25,
67
- 0,
68
- // Price is including VAT and is handling/invoice fee
69
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
70
- );
71
-
72
- /**
73
- * 3. Create and set the address(es).
74
- */
75
-
76
- // Create the address object and specify the values.
77
- $addr = new KlarnaAddr(
78
- 'always_approved@klarna.com', // email
79
- '', // Telno, only one phone number is needed.
80
- '0762560000', // Cellno
81
- 'Testperson-se', // Firstname
82
- 'Approved', // Lastname
83
- '', // No care of, C/O.
84
- 'St�rgatan 1', // Street
85
- '12345', // Zip Code
86
- 'Ankeborg', // City
87
- KlarnaCountry::SE, // Country
88
- null, // HouseNo for German and Dutch customers.
89
- null // House Extension. Dutch customers only.
90
- );
91
-
92
- // Next we tell the Klarna instance to use the address in the next order.
93
- $k->setAddress(KlarnaFlags::IS_BILLING, $addr); // Billing / invoice address
94
- $k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
95
-
96
- /**
97
- * 4. Specify relevant information from your store. (OPTIONAL)
98
- */
99
-
100
- // Set store specific information so you can e.g. search and associate invoices
101
- // with order numbers.
102
- $k->setEstoreInfo(
103
- '175012', // Order ID 1
104
- '1999110234', // Order ID 2
105
- '' // Optional username, email or identifier
106
- );
107
-
108
- // If you don't have the order id available at this stage, you can later use the
109
- // method updateOrderNo().
110
-
111
- /**
112
- * 5. Set additional information. (OPTIONAL)
113
- */
114
-
115
- /** Comment **/
116
-
117
- $k->setComment('A text string stored in the invoice commentary area.');
118
-
119
- /** Shipment type **/
120
-
121
- // Normal shipment is defaulted, delays the start of invoice expiration/due-date.
122
- $k->setShipmentInfo('delay_adjust', KlarnaFlags::EXPRESS_SHIPMENT);
123
-
124
-
125
- /**
126
- * 6. Invoke addTransaction and transmit the data.
127
- */
128
-
129
- try {
130
- // Transmit all the specified data, from the steps above, to Klarna.
131
- $result = $k->addTransaction(
132
- '4103219202', // PNO (Date of birth for DE and NL).
133
- null, // Gender.
134
- KlarnaFlags::NO_FLAG, // Flags to affect behavior.
135
- // -1, notes that this is an invoice purchase, for part payment purchase
136
- // you will have a pclass object on which you use getId().
137
- KlarnaPClass::INVOICE
138
- );
139
-
140
- // Check the order status
141
- if ($result[1] == KlarnaFlags::PENDING) {
142
- /* The order is under manual review and will be accepted or denied at a
143
- later stage. Use cronjob with checkOrderStatus() or visit Klarna
144
- Online to check to see if the status has changed. You should still
145
- show it to the customer as it was accepted, to avoid further attempts
146
- to fraud.
147
- */
148
- }
149
-
150
- // Here we get the invoice number
151
- $invno = $result[0];
152
-
153
- // Order is complete, store it in a database.
154
- echo "Status: {$result[1]}\nInvno: {$result[0]}\n";
155
- } catch(Exception $e) {
156
- // The purchase was denied or something went wrong, print the message:
157
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
158
- echo $e->getTraceAsString();
159
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/calc_monthly_cost.php DELETED
@@ -1,59 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Calculate the monthly cost for the product page.
35
- */
36
-
37
- $pclass = $k->getCheapestPClass($sum, $flag);
38
-
39
- // Did we get a PClass? (it is false if we didn't)
40
- if ($pclass) {
41
- // Here we reuse the same values as above:
42
- // [[calc_monthly_cost]]
43
- $value = KlarnaCalc::calc_monthly_cost(
44
- 149.99,
45
- $pclass,
46
- KlarnaFlags::PRODUCT_PAGE // or KlarnaFlags::CHECKOUT_PAGE
47
- );
48
- // [[calc_monthly_cost]]
49
-
50
- // [[calc_monthly_cost_response]]
51
- 45.50;
52
- // [[calc_monthly_cost_response]]
53
-
54
- echo "Value: {$value}\n";
55
- /*
56
- $value is now a rounded monthly cost amount to be displayed to the
57
- customer.
58
- */
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/cancelReservation.php DELETED
@@ -1,55 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Cancelling a reservation
35
- */
36
-
37
- // Here you enter the reservation number you got from reserveAmount():
38
- $rno = '123456';
39
-
40
- try {
41
- // [[cancelReservation]]
42
- $result = $k->cancelReservation($rno);
43
- // [[cancelReservation]]
44
-
45
-
46
- // [[response]]
47
- true;
48
- // [[response]]
49
-
50
- echo "Result: {$result}\n";
51
- // Reservation cancelled, proceed accordingly.
52
- } catch(Exception $e) {
53
- // Something went wrong or the reservation doesn't exist.
54
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
55
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/changeReservation.php DELETED
@@ -1,60 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Change the reservation.
35
- */
36
-
37
- // Here you enter the reservation number you got from reserveAmount():
38
- $rno = '123456';
39
-
40
- try {
41
- // [[changeReservation]]
42
- $result = $k->changeReservation(
43
- $rno, // Reservation number
44
- 49.99, // Amount
45
- KlarnaFlags::NEW_AMOUNT // Flag deciding if the amount is the new amount
46
- // to reserve, or if it is to be added to the
47
- // existing amount. (KlarnaFlags::ADD_AMOUNT)
48
- );
49
- // [[changeReservation]]
50
-
51
- // [[changeReservation:response]]
52
- true;
53
- // [[changeReservation:response]]
54
-
55
- // Reservation changed, proceed accordingly.
56
- echo "Result: {$result}\n";
57
- } catch (Exception $e) {
58
- // Something went wrong or the reservation doesn't exist.
59
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
60
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/checkOrderStatus.php DELETED
@@ -1,64 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Check the status on your order (invoice or reservation)
35
- */
36
-
37
- $id = '123456'; // Your reservation or invoice number.
38
-
39
- try {
40
- // [[checkOrderStatus]]
41
- $result = $k->checkOrderStatus(
42
- $id, // Reservation, invoice number or order id.
43
- 0 // Flag specifying number type. 0 = rno or invno. 1 = order id.
44
- );
45
- // [[checkOrderStatus]]
46
-
47
- // [[checkOrderStatus:response]]
48
- "1";
49
- // [[checkOrderStatus:response]]
50
-
51
- if ($result == KlarnaFlags::ACCEPTED) {
52
- // Status changed, you can now activate your invoice/reservation.
53
- echo "Accepted\n";
54
- } else if ($result == KlarnaFlags::DENIED) {
55
- echo "Denied\n";
56
- // Status changed, it is now denied, proceed accordingly.
57
- } else {
58
- echo "Pending\n";
59
- //Order is still pending, try again later.
60
- }
61
- } catch (Exception $e) {
62
- //Something went wrong, print the message:
63
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
64
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/creditInvoice.php DELETED
@@ -1,59 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Completely refund a invoice.
35
- */
36
-
37
- // Here you enter the invoice number:
38
- $invNo = '123456';
39
-
40
- try {
41
- // [[creditInvoice]]
42
- $result = $k->creditInvoice(
43
- $invNo, // Invoice Number
44
- '' // Credit number. (Optional).
45
- );
46
- // [[creditInvoice]]
47
-
48
- // [[creditInvoice:response]]
49
- "123456";
50
- // [[creditInvoice:response]]
51
-
52
- echo "Result: {$result}\n";
53
-
54
- /* Invoice fully refunded, proceed accordingly.
55
- $result contains the invoice number of the refunded invoice. */
56
- } catch(Exception $e) {
57
- // Something went wrong, print the message:
58
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/creditPart.php DELETED
@@ -1,80 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Partially refund a invoice.
35
- */
36
-
37
- // Here you enter the invoice number:
38
- $invNo = '123456';
39
-
40
- // Specify for which article(s) you want to refund.
41
- $k->addArtNo(
42
- 1, // Quantity
43
- 'MG200MMS' // Article Number. Must be the same as the one you used
44
- ); // in addArticle() when you made the addTransaction() call.
45
-
46
- // Adding a return fee is possible. If you are interested in this
47
- // functionality, make sure to always be in contact with Klarna before
48
- // integrating return fees.
49
-
50
- // $k->addArticle(
51
- // 1,
52
- // "",
53
- // "Restocking fee",
54
- // 11.5,
55
- // 25,
56
- // 0,
57
- // KlarnaFlags::NO_FLAG
58
- // );
59
-
60
- try {
61
- // [[creditPart]]
62
- $result = $k->creditPart(
63
- $invNo, // Invoice Number
64
- '' // Credit Number. (Optional).
65
- );
66
- // [[creditPart]]
67
-
68
- // [[creditPart:response]]
69
- "123456";
70
- // [[creditPart:response]]
71
-
72
- echo "Result: {$result}\n";
73
-
74
- /* Invoice partially refunded, proceed accordingly.
75
- $result contains the invoice number of the refunded invoice.
76
- */
77
- } catch(Exception $e) {
78
- // Something went wrong, print the message:
79
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
80
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/deleteInvoice.php DELETED
@@ -1,49 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Remove the invoice
35
- */
36
-
37
- //Here you enter the invoice number you got from addTransaction():
38
- $invNo = '123456';
39
-
40
- try {
41
- $result = $k->deleteInvoice($invNo);
42
-
43
- echo "Result: {$result}\n";
44
-
45
- //Invoice removed, proceed accordingly.
46
- } catch(Exception $e) {
47
- //Something went wrong or the invoice doesn't exist.
48
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
49
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/emailInvoice.php DELETED
@@ -1,56 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Send an (activated) invoice to the customer via email.
35
- */
36
-
37
- // Here you enter the invoice number:
38
- $invNo = '123456';
39
-
40
- try {
41
- // [[emailInvoice]]
42
- $result = $k->emailInvoice($invNo);
43
- // [[emailInvoice]]
44
-
45
- // [[emailInvoice:response]]
46
- "123456";
47
- // [[emailInvoice:response]]
48
-
49
- echo "Result: {$result}\n";
50
- /* Invoice sent to customer via email, proceed accordingly.
51
- $result contains the invoice number of the emailed invoice.
52
- */
53
- } catch(Exception $e) {
54
- // Something went wrong, print the message:
55
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
56
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/fetchPClasses.php DELETED
@@ -1,54 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Retrieve the PClasses from Klarna.
35
- */
36
-
37
- try {
38
- // [[fetchPClasses]]
39
- $k->fetchPClasses();
40
- // [[fetchPClasses]]
41
-
42
- // [[fetchPClassesResult]]
43
- null;
44
- // [[fetchPClassesResult]]
45
-
46
- /* PClasses successfully fetched, now you can use getPClasses() to load them
47
- locally or getPClass to load a specific PClass locally.
48
- */
49
- echo "Fetched " . count($k->getAllPClasses()) . " pclasses.\n";
50
-
51
- } catch(Exception $e) {
52
- // Something went wrong, print the message:
53
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
54
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/getAddresses.php DELETED
@@ -1,86 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Get the address(es) from Klarna. (Sweden only!)
35
- */
36
- $k->setCountry('se');
37
- try {
38
- //Attempt to get the address(es) associated with the SSN/PNO.
39
- // [[getAddresses]]
40
- $addrs = $k->getAddresses('410321-9202');
41
- // [[getAddresses]]
42
-
43
- // [[getAddresses:response]]
44
- array(
45
- new KlarnaAddr(
46
- '',
47
- '',
48
- '',
49
- 'Testperson-se',
50
- 'Approved',
51
- '',
52
- 'Stårgatan 1',
53
- '12345',
54
- 'Ankeborg',
55
- KlarnaCountry::SE,
56
- null,
57
- null
58
- )
59
- );
60
- // [[getAddresses:response]]
61
- /* If there exists several addresses you would want to output a list in
62
- which the customer could choose the address which suits him/her.
63
- */
64
-
65
- // Print them if available:
66
- foreach ($addrs as $key => $addr) {
67
- echo "<table>\n";
68
-
69
- // This only works if the right getAddresses type is used.
70
- if ($addr->isCompany) {
71
- echo "\t<tr><td>Company</td><td>{$addr->getCompanyName()}</td></tr>\n";
72
- } else {
73
- echo "\t<tr><td>First name</td><td>{$addr->getFirstName()}</td></tr>\n";
74
- echo "\t<tr><td>Last name</td><td>{$addr->getLastName()}</td></tr>\n";
75
- }
76
-
77
- echo "\t<tr><td>Street</td><td>{$addr->getStreet()}</td></tr>\n";
78
- echo "\t<tr><td>Zip code</td><td>{$addr->getZipCode()}</td></tr>\n";
79
- echo "\t<tr><td>City</td><td>{$addr->getCity()}</td></tr>\n";
80
- echo "\t<tr><td>Country</td><td>{$addr->getCountryCode()}</td></tr>\n";
81
- echo "</table>\n";
82
- }
83
- } catch(Exception $e) {
84
- //Something went wrong
85
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
86
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/getPClasses.php DELETED
@@ -1,63 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Load the PClasses from the local file or MySQL table.
35
- */
36
-
37
- /*
38
- PClasses are loaded from the local storage, as defined by "pcStorage"
39
- and "pcURI".
40
- */
41
-
42
- // Load all PClasses available.
43
- $pclasses = $k->getPClasses();
44
- // Here we can define a specific type of PClass we want to load
45
- // (KlarnaPClass::CAMPAIGN, for example), or leave it empty to get all that
46
- // are usable.
47
-
48
- // Next we might want to display the description in a drop down menu:
49
- echo "<select name='pclass'>\n";
50
- foreach ($pclasses as $pclass) {
51
- echo "\t<option value='{$pclass->getId()}'>{$pclass->getDescription()}</option>\n";
52
- }
53
- echo "</select>\n";
54
-
55
- // When the customer has confirmed the purchase and chosen a pclass, you can
56
- // easily grab just that one by doing:
57
- $pclassId = $pclasses[0]->getId(); // Let's say the customer picked the first one
58
- $pclass = $k->getPClass($pclassId);
59
-
60
- var_dump($pclass);
61
-
62
- // Next we can use $pclassId in the addTransaction call or in the reserveAmount
63
- // call.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/invoiceAddress.php DELETED
@@ -1,80 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Get the address associated with the purchase/invoice.
35
- */
36
-
37
- // Here you enter the invoice number:
38
- $invNo = '123456';
39
-
40
- try {
41
- // Attempt to get the address
42
- // [[invoiceAddress]]
43
- $addr = $k->invoiceAddress($invNo);
44
- // [[invoiceAddress]]
45
-
46
- // [[invoiceAddress:response]]
47
- new KlarnaAddr(
48
- '',
49
- '',
50
- '',
51
- 'Testperson-se',
52
- 'Approved',
53
- '',
54
- 'Stårgatan 1',
55
- '12345',
56
- 'Ankeborg',
57
- KlarnaCountry::SE,
58
- null,
59
- null
60
- );
61
- // [[invoiceAddress:response]]
62
-
63
- // Display the retrieved address:
64
- echo "<table>\n";
65
- if ($addr->isCompany) {
66
- echo "\t<tr><td>Company</td><td>{$addr->getCompanyName()}</td></tr>\n";
67
- } else {
68
- echo "\t<tr><td>First name</td><td>{$addr->getFirstName()}</td></tr>\n";
69
- echo "\t<tr><td>Last name</td><td>{$addr->getLastName()}</td></tr>\n";
70
- }
71
-
72
- echo "\t<tr><td>Street</td><td>{$addr->getStreet()}</td></tr>\n";
73
- echo "\t<tr><td>Zip code</td><td>{$addr->getZipCode()}</td></tr>\n";
74
- echo "\t<tr><td>City</td><td>{$addr->getCity()}</td></tr>\n";
75
- echo "\t<tr><td>Country</td><td>{$addr->getCountryCode()}</td></tr>\n";
76
- echo "</table>\n";
77
- } catch(Exception $e) {
78
- //Something went wrong
79
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
80
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/invoiceAmount.php DELETED
@@ -1,56 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Retrieve the total amount of a invoice.
35
- */
36
-
37
- // Here you enter the invoice number:
38
- $invNo = '123456';
39
-
40
- try {
41
- // [[InvoiceAmount]]
42
- $result = $k->invoiceAmount($invNo);
43
- // [[InvoiceAmount]]
44
-
45
- // [[InvoiceAmount:response]]
46
- 123.45;
47
- // [[InvoiceAmount:response]]
48
-
49
- echo "Result: {$result}\n";
50
- /* Invoice amount successfully retrieved, proceed accordingly.
51
- $result contains the total sum of the invoice.
52
- */
53
- } catch(Exception $e) {
54
- //Something went wrong, print the message:
55
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
56
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/invoicePartAmount.php DELETED
@@ -1,70 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Retrieve the amount for specific article(s) from an invoice.
35
- */
36
-
37
- // Here you enter the invoice number:
38
- $invNo = '123456';
39
-
40
- // Specify for which article(s) you want the amount.
41
- // artNo must be the same as the one you used in addArticle() when you made the
42
- // addTransaction() call.
43
- // [[addArtNo]]
44
- $k->addArtNo(
45
- 1, // Quantity
46
- 'MG200MMS' // Article number
47
- );
48
- // [[addArtNo]]
49
-
50
- // [[addArtNo:response]]
51
- null;
52
- // [[addArtNo:response]]
53
-
54
- try {
55
- // [[invoicePartAmount]]
56
- $result = $k->invoicePartAmount($invNo);
57
- // [[invoicePartAmount]]
58
-
59
- // [[invoicePartAmount:response]]
60
- 45.50;
61
- // [[invoicePartAmount:response]]
62
-
63
- echo "Result: {$result}\n";
64
- /* Partial invoice amount successfully retrieved, proceed accordingly.
65
- $result contains the sum of specified article(s).
66
- */
67
- } catch(Exception $e) {
68
- // Something went wrong, print the message:
69
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
70
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/reserveAmount.php DELETED
@@ -1,170 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Add the article(s), shipping and/or handling fee.
35
- */
36
-
37
- // Here we add a normal product to our goods list.
38
- $k->addArticle(
39
- 4, // Quantity
40
- "MG200MMS", // Article number
41
- "Matrox G200 MMS", // Article name/title
42
- 299.99, // Price
43
- 25, // 25% VAT
44
- 0, // Discount
45
- KlarnaFlags::INC_VAT // Price is including VAT.
46
- );
47
-
48
- // Next we might want to add a shipment fee for the product
49
- $k->addArticle(
50
- 1,
51
- "",
52
- "Shipping fee",
53
- 14.5,
54
- 25,
55
- 0,
56
- // Price is including VAT and is shipment fee
57
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
58
- );
59
-
60
- // Lastly, we want to use an invoice/handling fee as well
61
- $k->addArticle(
62
- 1,
63
- "",
64
- "Handling fee",
65
- 11.5,
66
- 25,
67
- 0,
68
- // Price is including VAT and is handling/invoice fee
69
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
70
- );
71
-
72
- /**
73
- * 3. Create and set the address(es).
74
- */
75
-
76
- // Create the address object and specify the values.
77
- $addr = new KlarnaAddr(
78
- 'always_approved@klarna.com', // email
79
- '', // Telno, only one phone number is needed.
80
- '0762560000', // Cellno
81
- 'Testperson-se', // Firstname
82
- 'Approved', // Lastname
83
- '', // No care of, C/O.
84
- 'St?rgatan 1', // Street
85
- '12345', // Zip Code
86
- 'Ankeborg', // City
87
- KlarnaCountry::SE, // Country
88
- null, // HouseNo for German and Dutch customers.
89
- null // House Extension. Dutch customers only.
90
- );
91
-
92
- // Next we tell the Klarna instance to use the address in the next order.
93
- $k->setAddress(KlarnaFlags::IS_BILLING, $addr); // Billing / invoice address
94
- $k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
95
-
96
- /**
97
- * 4. Specify relevant information from your store. (OPTIONAL)
98
- */
99
-
100
- // Set store specific information so you can e.g. search and associate invoices
101
- // with order numbers.
102
- $k->setEstoreInfo(
103
- '175012', // Order ID 1
104
- '1999110234', // Order ID 2
105
- '' // Optional username, email or identifier
106
- );
107
-
108
- // If you don't have the order id available at this stage, you can later use the
109
- // method updateOrderNo().
110
-
111
- /**
112
- * 5. Set additional information. (OPTIONAL)
113
- */
114
-
115
- /** Comment **/
116
-
117
- $k->setComment('A text string stored in the invoice commentary area.');
118
-
119
- /** Shipment type **/
120
-
121
- // Normal shipment is defaulted, delays the start of invoice expiration/due-date.
122
- $k->setShipmentInfo('delay_adjust', KlarnaFlags::EXPRESS_SHIPMENT);
123
-
124
- /**
125
- * 6. Invoke reserveAmount and transmit the data.
126
- */
127
-
128
- try {
129
- // Transmit all the specified data, from the steps above, to Klarna.
130
- // [[reserveAmount]]
131
- $result = $k->reserveAmount(
132
- '4103219202', // PNO (Date of birth for DE and NL).
133
- null, // Gender.
134
- // Amount. -1 specifies that calculation should calculate the amount
135
- // using the goods list
136
- -1,
137
- KlarnaFlags::NO_FLAG, // Flags to affect behavior.
138
- // -1 notes that this is an invoice purchase, for part payment purchase
139
- // you will have a pclass object on which you use getId().
140
- KlarnaPClass::INVOICE
141
- );
142
- // [[reserveAmount]]
143
-
144
- // [[reserveAmount:response]]
145
- array(
146
- "123456",
147
- 1
148
- );
149
- // [[reserveAmount:response]]
150
-
151
-
152
- //Check the order status
153
- if ($result[1] == KlarnaFlags::PENDING) {
154
- /* The order is under manual review and will be accepted or denied at a
155
- later stage. Use cronjob with checkOrderStatus() or visit Klarna
156
- Online to check to see if the status has changed. You should still
157
- show it to the customer as it was accepted, to avoid further attempts
158
- to fraud.
159
- */
160
- }
161
-
162
- // Here we get the reservation number
163
- $rno = $result[0];
164
-
165
- echo "status: {$result[1]}\nrno: {$result[0]}\n";
166
- // Order is complete, store it in a database.
167
- } catch(Exception $e) {
168
- // The purchase was denied or something went wrong, print the message:
169
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
170
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/reserveOCR.php DELETED
@@ -1,59 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Reserve the OCR numbers.
35
- */
36
-
37
- try {
38
- // Reserve the OCR number(s):
39
- // [[reserveOCR]]
40
- $result = $k->reserveOCR(
41
- 1 // Number of OCR numbers you wish to reserve.
42
- );
43
- // [[reserveOCR]]
44
-
45
- // [[reserveOCR:response]]
46
- array(
47
- "41789461815156"
48
- );
49
- // [[reserveOCR:response]]
50
-
51
- echo "Result: \n";
52
- foreach ($result as $r) {
53
- echo "{$r}\n";
54
- }
55
- /* $result now contains an array of OCR numbers, proceed accordingly. */
56
- } catch(Exception $e) {
57
- // Something went wrong, print the message:
58
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/returnAmount.php DELETED
@@ -1,63 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Give a discount on the invoice.
35
- */
36
-
37
- // Here you enter the invoice number:
38
- $invNo = '123456';
39
-
40
- try {
41
- // [[returnAmount]]
42
- $result = $k->returnAmount(
43
- $invNo, // Invoice number
44
- 19.99, // Amount given as a discount.
45
- 25, // 25% VAT
46
- KlarnaFlags::INC_VAT, // Amount including VAT.
47
- "Family discount" // Description
48
- );
49
- // [[returnAmount]]
50
-
51
- // [[returnAmountResult]]
52
- "123456";
53
- // [[returnAmountResult]]
54
-
55
- echo "Result: {$result}\n";
56
-
57
- /* Discount given, proceed accordingly.
58
- $result contains the invoice number of the discounted invoice.
59
- */
60
- } catch(Exception $e) {
61
- // Something went wrong, print the message:
62
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
63
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/sendInvoice.php DELETED
@@ -1,58 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Send an (activated) invoice to the customer.
35
- * (Postal service / normal mail)
36
- */
37
-
38
- // Here you enter the invoice number:
39
- $invNo = '123456';
40
-
41
- try {
42
- // [[sendInvoice]]
43
- $result = $k->sendInvoice("123456");
44
- // [[sendInvoice]]
45
-
46
- // [[sendInvoice:response]]
47
- "123456";
48
- // [[sendInvoice:response]]
49
-
50
- echo "Result: {$result}\n";
51
-
52
- /* Invoice sent to customer, proceed accordingly.
53
- $result contains the invoice number of the sent invoice.
54
- */
55
- } catch(Exception $e) {
56
- // Something went wrong, print the message:
57
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
58
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/splitReservation.php DELETED
@@ -1,66 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Split the reservation.
35
- */
36
-
37
- // Here you enter the reservation number you got from reserveAmount():
38
- $rno = '123456';
39
-
40
- try {
41
- // Transmit all the specified data, from the steps above, to Klarna.
42
- // [[splitReservation]]
43
- $result = $k->splitReservation(
44
- $rno, // Reservation number
45
- 99.5, // Amount to be subtracted from the reservation.
46
- KlarnaFlags::NO_FLAG // No specific behaviour.
47
- );
48
- // [[splitReservation]]
49
-
50
- // [[splitReservation:response]]
51
- array(
52
- '12345',
53
- 1
54
- );
55
- // [[splitReservation:response]]
56
-
57
-
58
- // Split successful, proceed accordingly.
59
- $newRno = $result[0]; // New reservation number
60
- $status = $result[1]; // Status of the new reservation (1 or 2)
61
-
62
- echo "New RNO: {$result[0]}\nStatus: {$result[1]}\n";
63
- } catch(Exception $e) {
64
- // Something went wrong, print the message:
65
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
66
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/update.php DELETED
@@ -1,129 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Add the article(s), shipping and/or handling fee. (OPTIONAL)
35
- */
36
-
37
- // Here we add a normal product to our goods list.
38
- $k->addArticle(
39
- 4, // Quantity
40
- "MG200MMS", // Article number
41
- "Matrox G200 MMS", // Article name/title
42
- 299.99, // Price
43
- 25, // 25% VAT
44
- 0, // Discount
45
- KlarnaFlags::INC_VAT // Price is including VAT.
46
- );
47
-
48
- // Next we might want to add a shipment fee for the product
49
- $k->addArticle(
50
- 1,
51
- "",
52
- "Shipping fee",
53
- 14.5,
54
- 25,
55
- 0,
56
- // Price is including VAT and is shipment fee
57
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_SHIPMENT
58
- );
59
-
60
- // Lastly, we want to use an invoice/handling fee as well
61
- $k->addArticle(
62
- 1,
63
- "",
64
- "Handling fee",
65
- 11.5,
66
- 25,
67
- 0,
68
- // Price is including VAT and is handling/invoice fee
69
- KlarnaFlags::INC_VAT | KlarnaFlags::IS_HANDLING
70
- );
71
-
72
- /**
73
- * 3. Create and set the address(es). (OPTIONAL)
74
- */
75
-
76
- // Create the address object and specify the values.
77
- $addr = new KlarnaAddr(
78
- 'always_approved@klarna.com', // email
79
- '', // Telno, only one phone number is needed.
80
- '0762560000', // Cellno
81
- 'Testperson-se', // Firstname
82
- 'Approved', // Lastname
83
- '', // No care of, C/O.
84
- 'St�rgatan 1', // Street
85
- '12345', // Zip Code
86
- 'Ankeborg', // City
87
- KlarnaCountry::SE, // Country
88
- null, // HouseNo for German and Dutch customers.
89
- null // House Extension. Dutch customers only.
90
- );
91
-
92
- // Next we tell the Klarna instance to use the address in the next order.
93
- $k->setAddress(KlarnaFlags::IS_BILLING, $addr); // Billing / invoice address
94
- $k->setAddress(KlarnaFlags::IS_SHIPPING, $addr); // Shipping / delivery address
95
-
96
- /**
97
- * 4. Specify relevant information from your store. (OPTIONAL)
98
- */
99
-
100
- // Set store specific information so you can e.g. search and associate invoices
101
- // with order numbers.
102
- $k->setEstoreInfo(
103
- '175012', // Order ID 1
104
- '1999110234', // Order ID 2
105
- '' // Optional username, email or identifier
106
- );
107
-
108
- /**
109
- * 5. Make the call to Klarna
110
- */
111
-
112
- // Reservation number
113
- $rno = '123456';
114
-
115
- try {
116
- // [[update]]
117
- $result = $k->update($rno);
118
- // [[update]]
119
-
120
- // [[update:response]]
121
- true;
122
- // [[update:response]]
123
-
124
- if ($result) {
125
- echo "Update successful\n";
126
- }
127
- } catch(KlarnaException $e) {
128
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
129
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/updateChargeAmount.php DELETED
@@ -1,60 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Update charge amount (shipping fee or handling fee).
35
- */
36
-
37
- // Here you enter the invoice number you got from addTransaction():
38
- $invNo = '123456';
39
-
40
- try {
41
- // [[updateChargeAmount]]
42
- $result = $k->updateChargeAmount(
43
- $invNo, // Invoice number
44
- KlarnaFlags::IS_SHIPMENT, // IS_SHIPMENT or IS_HANDLING
45
- 16.7 // Set the shipping fee to 16.7
46
- );
47
- // [[updateChargeAmount]]
48
-
49
- // [[updateChargeAmount:response]]
50
- "123456";
51
- // [[updateChargeAmount:response]]
52
-
53
- echo "Result: {$result}\n";
54
- /* Charge type updated successfully, proceed accordingly.
55
- $result contains the same invoice number.
56
- */
57
- } catch(Exception $e) {
58
- // Something went wrong, print the message:
59
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
60
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/updateGoodsQty.php DELETED
@@ -1,61 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Update goods quantity.
35
- */
36
-
37
- // Here you enter the invoice number you got from addTransaction():
38
- $invNo = '123456';
39
-
40
- try {
41
- // [[updateGoodsQty]]
42
- $result = $k->updateGoodsQty(
43
- $invNo, // Invoice number
44
- 'MG200MMS', // ArtNo must be the same as the one you used in
45
- // addArticle() when you made the addTransaction() call.
46
- 2 // New Quantity
47
- );
48
- // [[updateGoodsQty]]
49
-
50
- // [[updateGoodsQty:response]]
51
- "123456";
52
- // [[updateGoodsQty:response]]
53
-
54
- echo "Result: {$result}\n";
55
- /* Article quantity updated successfully, proceed accordingly.
56
- $result contains the same invoice number.
57
- */
58
- } catch(Exception $e) {
59
- // Something went wrong, print the message:
60
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
61
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/Klarna/examples/updateOrderNo.php DELETED
@@ -1,59 +0,0 @@
1
- <?php
2
-
3
- require_once dirname(__DIR__) . '/Klarna.php';
4
-
5
- // Dependencies from http://phpxmlrpc.sourceforge.net/
6
- require_once dirname(dirname(__FILE__)) .
7
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc.inc';
8
- require_once dirname(dirname(__FILE__)) .
9
- '/transport/xmlrpc-3.0.0.beta/lib/xmlrpc_wrappers.inc';
10
-
11
- /**
12
- * 1. Initialize and setup the Klarna instance.
13
- */
14
-
15
- $k = new Klarna();
16
-
17
- $k->config(
18
- 123456, // Merchant ID
19
- 'sharedSecret', // Shared Secret
20
- KlarnaCountry::SE, // Country
21
- KlarnaLanguage::SV, // Language
22
- KlarnaCurrency::SEK, // Currency
23
- Klarna::BETA, // Server
24
- 'json', // PClass Storage
25
- '/srv/pclasses.json', // PClass Storage URI path
26
- true, // SSL
27
- true // Remote logging of response times of xmlrpc calls
28
- );
29
-
30
- // OR you can set the config to loads from a file, for example /srv/klarna.json:
31
- // $k->setConfig(new KlarnaConfig('/srv/klarna.json'));
32
-
33
- /**
34
- * 2. Update order number / id.
35
- */
36
-
37
- // Here you enter the invoice number you got from addTransaction():
38
- $invNo = '123456';
39
-
40
- try {
41
- // [[updateOrderNo]]
42
- $result = $k->updateOrderNo(
43
- $invNo, // Invoice Number
44
- '1234' // The order id/number you wish to associated.
45
- );
46
- // [[updateOrderNo]]
47
-
48
- // [[updateOrderNo:response]]
49
- "123456";
50
- // [[updateOrderNo:response]]
51
-
52
- echo "Result: {$result}\n";
53
- /* Order id is now assicated with the invoice, proceed accordingly.
54
- $result contains the same invoice number.
55
- */
56
- } catch(Exception $e) {
57
- // Something went wrong, print the message:
58
- echo "{$e->getMessage()} (#{$e->getCode()})\n";
59
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lib/KlarnaCheckout/autoload.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ require_once __DIR__ . '/composer' . '/autoload_real.php';
6
+
7
+ return ComposerAutoloaderInitb90caf33581ed2bbffe93cf19e493840::getLoader();
lib/KlarnaCheckout/composer/ClassLoader.php ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0 class loader
17
+ *
18
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
19
+ *
20
+ * $loader = new \Composer\Autoload\ClassLoader();
21
+ *
22
+ * // register classes with namespaces
23
+ * $loader->add('Symfony\Component', __DIR__.'/component');
24
+ * $loader->add('Symfony', __DIR__.'/framework');
25
+ *
26
+ * // activate the autoloader
27
+ * $loader->register();
28
+ *
29
+ * // to enable searching the include path (eg. for PEAR packages)
30
+ * $loader->setUseIncludePath(true);
31
+ *
32
+ * In this example, if you try to use a class in the Symfony\Component
33
+ * namespace or one of its children (Symfony\Component\Console for instance),
34
+ * the autoloader will first look for the class under the component/
35
+ * directory, and it will then fallback to the framework/ directory if not
36
+ * found before giving up.
37
+ *
38
+ * This class is loosely based on the Symfony UniversalClassLoader.
39
+ *
40
+ * @author Fabien Potencier <fabien@symfony.com>
41
+ * @author Jordi Boggiano <j.boggiano@seld.be>
42
+ */
43
+ class ClassLoader
44
+ {
45
+ // PSR-4
46
+ private $prefixLengthsPsr4 = array();
47
+ private $prefixDirsPsr4 = array();
48
+ private $fallbackDirsPsr4 = array();
49
+
50
+ // PSR-0
51
+ private $prefixesPsr0 = array();
52
+ private $fallbackDirsPsr0 = array();
53
+
54
+ private $useIncludePath = false;
55
+ private $classMap = array();
56
+
57
+ private $classMapAuthoritative = false;
58
+
59
+ public function getPrefixes()
60
+ {
61
+ if (!empty($this->prefixesPsr0)) {
62
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
63
+ }
64
+
65
+ return array();
66
+ }
67
+
68
+ public function getPrefixesPsr4()
69
+ {
70
+ return $this->prefixDirsPsr4;
71
+ }
72
+
73
+ public function getFallbackDirs()
74
+ {
75
+ return $this->fallbackDirsPsr0;
76
+ }
77
+
78
+ public function getFallbackDirsPsr4()
79
+ {
80
+ return $this->fallbackDirsPsr4;
81
+ }
82
+
83
+ public function getClassMap()
84
+ {
85
+ return $this->classMap;
86
+ }
87
+
88
+ /**
89
+ * @param array $classMap Class to filename map
90
+ */
91
+ public function addClassMap(array $classMap)
92
+ {
93
+ if ($this->classMap) {
94
+ $this->classMap = array_merge($this->classMap, $classMap);
95
+ } else {
96
+ $this->classMap = $classMap;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Registers a set of PSR-0 directories for a given prefix, either
102
+ * appending or prepending to the ones previously set for this prefix.
103
+ *
104
+ * @param string $prefix The prefix
105
+ * @param array|string $paths The PSR-0 root directories
106
+ * @param bool $prepend Whether to prepend the directories
107
+ */
108
+ public function add($prefix, $paths, $prepend = false)
109
+ {
110
+ if (!$prefix) {
111
+ if ($prepend) {
112
+ $this->fallbackDirsPsr0 = array_merge(
113
+ (array) $paths,
114
+ $this->fallbackDirsPsr0
115
+ );
116
+ } else {
117
+ $this->fallbackDirsPsr0 = array_merge(
118
+ $this->fallbackDirsPsr0,
119
+ (array) $paths
120
+ );
121
+ }
122
+
123
+ return;
124
+ }
125
+
126
+ $first = $prefix[0];
127
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
128
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
129
+
130
+ return;
131
+ }
132
+ if ($prepend) {
133
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
134
+ (array) $paths,
135
+ $this->prefixesPsr0[$first][$prefix]
136
+ );
137
+ } else {
138
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
139
+ $this->prefixesPsr0[$first][$prefix],
140
+ (array) $paths
141
+ );
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Registers a set of PSR-4 directories for a given namespace, either
147
+ * appending or prepending to the ones previously set for this namespace.
148
+ *
149
+ * @param string $prefix The prefix/namespace, with trailing '\\'
150
+ * @param array|string $paths The PSR-0 base directories
151
+ * @param bool $prepend Whether to prepend the directories
152
+ *
153
+ * @throws \InvalidArgumentException
154
+ */
155
+ public function addPsr4($prefix, $paths, $prepend = false)
156
+ {
157
+ if (!$prefix) {
158
+ // Register directories for the root namespace.
159
+ if ($prepend) {
160
+ $this->fallbackDirsPsr4 = array_merge(
161
+ (array) $paths,
162
+ $this->fallbackDirsPsr4
163
+ );
164
+ } else {
165
+ $this->fallbackDirsPsr4 = array_merge(
166
+ $this->fallbackDirsPsr4,
167
+ (array) $paths
168
+ );
169
+ }
170
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
171
+ // Register directories for a new namespace.
172
+ $length = strlen($prefix);
173
+ if ('\\' !== $prefix[$length - 1]) {
174
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
175
+ }
176
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
177
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
178
+ } elseif ($prepend) {
179
+ // Prepend directories for an already registered namespace.
180
+ $this->prefixDirsPsr4[$prefix] = array_merge(
181
+ (array) $paths,
182
+ $this->prefixDirsPsr4[$prefix]
183
+ );
184
+ } else {
185
+ // Append directories for an already registered namespace.
186
+ $this->prefixDirsPsr4[$prefix] = array_merge(
187
+ $this->prefixDirsPsr4[$prefix],
188
+ (array) $paths
189
+ );
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Registers a set of PSR-0 directories for a given prefix,
195
+ * replacing any others previously set for this prefix.
196
+ *
197
+ * @param string $prefix The prefix
198
+ * @param array|string $paths The PSR-0 base directories
199
+ */
200
+ public function set($prefix, $paths)
201
+ {
202
+ if (!$prefix) {
203
+ $this->fallbackDirsPsr0 = (array) $paths;
204
+ } else {
205
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Registers a set of PSR-4 directories for a given namespace,
211
+ * replacing any others previously set for this namespace.
212
+ *
213
+ * @param string $prefix The prefix/namespace, with trailing '\\'
214
+ * @param array|string $paths The PSR-4 base directories
215
+ *
216
+ * @throws \InvalidArgumentException
217
+ */
218
+ public function setPsr4($prefix, $paths)
219
+ {
220
+ if (!$prefix) {
221
+ $this->fallbackDirsPsr4 = (array) $paths;
222
+ } else {
223
+ $length = strlen($prefix);
224
+ if ('\\' !== $prefix[$length - 1]) {
225
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
226
+ }
227
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
228
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Turns on searching the include path for class files.
234
+ *
235
+ * @param bool $useIncludePath
236
+ */
237
+ public function setUseIncludePath($useIncludePath)
238
+ {
239
+ $this->useIncludePath = $useIncludePath;
240
+ }
241
+
242
+ /**
243
+ * Can be used to check if the autoloader uses the include path to check
244
+ * for classes.
245
+ *
246
+ * @return bool
247
+ */
248
+ public function getUseIncludePath()
249
+ {
250
+ return $this->useIncludePath;
251
+ }
252
+
253
+ /**
254
+ * Turns off searching the prefix and fallback directories for classes
255
+ * that have not been registered with the class map.
256
+ *
257
+ * @param bool $classMapAuthoritative
258
+ */
259
+ public function setClassMapAuthoritative($classMapAuthoritative)
260
+ {
261
+ $this->classMapAuthoritative = $classMapAuthoritative;
262
+ }
263
+
264
+ /**
265
+ * Should class lookup fail if not found in the current class map?
266
+ *
267
+ * @return bool
268
+ */
269
+ public function isClassMapAuthoritative()
270
+ {
271
+ return $this->classMapAuthoritative;
272
+ }
273
+
274
+ /**
275
+ * Registers this instance as an autoloader.
276
+ *
277
+ * @param bool $prepend Whether to prepend the autoloader or not
278
+ */
279
+ public function register($prepend = false)
280
+ {
281
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
282
+ }
283
+
284
+ /**
285
+ * Unregisters this instance as an autoloader.
286
+ */
287
+ public function unregister()
288
+ {
289
+ spl_autoload_unregister(array($this, 'loadClass'));
290
+ }
291
+
292
+ /**
293
+ * Loads the given class or interface.
294
+ *
295
+ * @param string $class The name of the class
296
+ * @return bool|null True if loaded, null otherwise
297
+ */
298
+ public function loadClass($class)
299
+ {
300
+ if ($file = $this->findFile($class)) {
301
+ includeFile($file);
302
+
303
+ return true;
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Finds the path to the file where the class is defined.
309
+ *
310
+ * @param string $class The name of the class
311
+ *
312
+ * @return string|false The path if found, false otherwise
313
+ */
314
+ public function findFile($class)
315
+ {
316
+ // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317
+ if ('\\' == $class[0]) {
318
+ $class = substr($class, 1);
319
+ }
320
+
321
+ // class map lookup
322
+ if (isset($this->classMap[$class])) {
323
+ return $this->classMap[$class];
324
+ }
325
+ if ($this->classMapAuthoritative) {
326
+ return false;
327
+ }
328
+
329
+ $file = $this->findFileWithExtension($class, '.php');
330
+
331
+ // Search for Hack files if we are running on HHVM
332
+ if ($file === null && defined('HHVM_VERSION')) {
333
+ $file = $this->findFileWithExtension($class, '.hh');
334
+ }
335
+
336
+ if ($file === null) {
337
+ // Remember that this class does not exist.
338
+ return $this->classMap[$class] = false;
339
+ }
340
+
341
+ return $file;
342
+ }
343
+
344
+ private function findFileWithExtension($class, $ext)
345
+ {
346
+ // PSR-4 lookup
347
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
348
+
349
+ $first = $class[0];
350
+ if (isset($this->prefixLengthsPsr4[$first])) {
351
+ foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
352
+ if (0 === strpos($class, $prefix)) {
353
+ foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
354
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
355
+ return $file;
356
+ }
357
+ }
358
+ }
359
+ }
360
+ }
361
+
362
+ // PSR-4 fallback dirs
363
+ foreach ($this->fallbackDirsPsr4 as $dir) {
364
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
365
+ return $file;
366
+ }
367
+ }
368
+
369
+ // PSR-0 lookup
370
+ if (false !== $pos = strrpos($class, '\\')) {
371
+ // namespaced class name
372
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
373
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
374
+ } else {
375
+ // PEAR-like class name
376
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
377
+ }
378
+
379
+ if (isset($this->prefixesPsr0[$first])) {
380
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
381
+ if (0 === strpos($class, $prefix)) {
382
+ foreach ($dirs as $dir) {
383
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
384
+ return $file;
385
+ }
386
+ }
387
+ }
388
+ }
389
+ }
390
+
391
+ // PSR-0 fallback dirs
392
+ foreach ($this->fallbackDirsPsr0 as $dir) {
393
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
394
+ return $file;
395
+ }
396
+ }
397
+
398
+ // PSR-0 include paths.
399
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
400
+ return $file;
401
+ }
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Scope isolated include.
407
+ *
408
+ * Prevents access to $this/self from included files.
409
+ */
410
+ function includeFile($file)
411
+ {
412
+ include $file;
413
+ }
lib/KlarnaCheckout/composer/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Copyright (c) 2015 Nils Adermann, Jordi Boggiano
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished
9
+ to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
lib/KlarnaCheckout/composer/autoload_classmap.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'xmlrpc_client' => $vendorDir . '/phpxmlrpc/phpxmlrpc/lib/xmlrpc.inc',
10
+ 'xmlrpc_server' => $vendorDir . '/phpxmlrpc/phpxmlrpc/lib/xmlrpcs.inc',
11
+ 'xmlrpcmsg' => $vendorDir . '/phpxmlrpc/phpxmlrpc/lib/xmlrpc.inc',
12
+ 'xmlrpcresp' => $vendorDir . '/phpxmlrpc/phpxmlrpc/lib/xmlrpc.inc',
13
+ 'xmlrpcval' => $vendorDir . '/phpxmlrpc/phpxmlrpc/lib/xmlrpc.inc',
14
+ );
lib/KlarnaCheckout/composer/autoload_files.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_files.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ $vendorDir . '/react/promise/src/functions_include.php',
10
+ );
lib/KlarnaCheckout/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'Klarna' => array($vendorDir . '/klarna/checkout/src'),
10
+ '' => array($vendorDir . '/klarna/php-xmlrpc/src'),
11
+ );
lib/KlarnaCheckout/composer/autoload_psr4.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'React\\Promise\\' => array($vendorDir . '/react/promise/src'),
10
+ 'GuzzleHttp\\Stream\\' => array($vendorDir . '/guzzlehttp/streams/src'),
11
+ 'GuzzleHttp\\Ring\\' => array($vendorDir . '/guzzlehttp/ringphp/src'),
12
+ 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
13
+ '' => array($vendorDir . '/klarna/kco_rest/src'),
14
+ );
lib/KlarnaCheckout/composer/autoload_real.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInitb90caf33581ed2bbffe93cf19e493840
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ public static function getLoader()
17
+ {
18
+ if (null !== self::$loader) {
19
+ return self::$loader;
20
+ }
21
+
22
+ spl_autoload_register(array('ComposerAutoloaderInitb90caf33581ed2bbffe93cf19e493840', 'loadClassLoader'), true, true);
23
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInitb90caf33581ed2bbffe93cf19e493840', 'loadClassLoader'));
25
+
26
+ $map = require __DIR__ . '/autoload_namespaces.php';
27
+ foreach ($map as $namespace => $path) {
28
+ $loader->set($namespace, $path);
29
+ }
30
+
31
+ $map = require __DIR__ . '/autoload_psr4.php';
32
+ foreach ($map as $namespace => $path) {
33
+ $loader->setPsr4($namespace, $path);
34
+ }
35
+
36
+ $classMap = require __DIR__ . '/autoload_classmap.php';
37
+ if ($classMap) {
38
+ $loader->addClassMap($classMap);
39
+ }
40
+
41
+ $loader->register(true);
42
+
43
+ $includeFiles = require __DIR__ . '/autoload_files.php';
44
+ foreach ($includeFiles as $file) {
45
+ composerRequireb90caf33581ed2bbffe93cf19e493840($file);
46
+ }
47
+
48
+ return $loader;
49
+ }
50
+ }
51
+
52
+ function composerRequireb90caf33581ed2bbffe93cf19e493840($file)
53
+ {
54
+ require $file;
55
+ }
lib/KlarnaCheckout/composer/installed.json ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "phpxmlrpc/phpxmlrpc",
4
+ "version": "3.0.1",
5
+ "version_normalized": "3.0.1.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/gggeek/phpxmlrpc.git",
9
+ "reference": "490862c33009397151ac39c811b6ee8e24689692"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/gggeek/phpxmlrpc/zipball/490862c33009397151ac39c811b6ee8e24689692",
14
+ "reference": "490862c33009397151ac39c811b6ee8e24689692",
15
+ "shasum": ""
16
+ },
17
+ "require": {
18
+ "php": ">=5.1.0"
19
+ },
20
+ "time": "2015-04-19 00:17:47",
21
+ "type": "library",
22
+ "installation-source": "dist",
23
+ "autoload": {
24
+ "classmap": [
25
+ "lib/xmlrpc.inc",
26
+ "lib/xmlrpcs.inc"
27
+ ]
28
+ },
29
+ "notification-url": "https://packagist.org/downloads/",
30
+ "license": [
31
+ "BSD-3-Clause"
32
+ ],
33
+ "description": "A php library for building xmlrpc clients and servers",
34
+ "homepage": "http://gggeek.github.io/phpxmlrpc/",
35
+ "keywords": [
36
+ "webservices",
37
+ "xmlrpc"
38
+ ]
39
+ },
40
+ {
41
+ "name": "klarna/php-xmlrpc",
42
+ "version": "v4.0.0",
43
+ "version_normalized": "4.0.0.0",
44
+ "source": {
45
+ "type": "git",
46
+ "url": "https://github.com/klarna/php-xmlrpc.git",
47
+ "reference": "7fe154c30b390e544a0f4f885805ef563efbe147"
48
+ },
49
+ "dist": {
50
+ "type": "zip",
51
+ "url": "https://api.github.com/repos/klarna/php-xmlrpc/zipball/7fe154c30b390e544a0f4f885805ef563efbe147",
52
+ "reference": "7fe154c30b390e544a0f4f885805ef563efbe147",
53
+ "shasum": ""
54
+ },
55
+ "require": {
56
+ "ext-curl": "*",
57
+ "php": ">=5.2.16",
58
+ "phpxmlrpc/phpxmlrpc": "~3.0"
59
+ },
60
+ "require-dev": {
61
+ "apigen/apigen": "4.0.*",
62
+ "klarna/apigen-theme": "~1.0"
63
+ },
64
+ "time": "2015-06-02 13:11:21",
65
+ "type": "library",
66
+ "installation-source": "dist",
67
+ "autoload": {
68
+ "psr-0": {
69
+ "": "src/"
70
+ }
71
+ },
72
+ "notification-url": "https://packagist.org/downloads/",
73
+ "license": [
74
+ "Apache-2.0"
75
+ ],
76
+ "authors": [
77
+ {
78
+ "name": "Klarna AB",
79
+ "email": "integration@klarna.com"
80
+ }
81
+ ],
82
+ "description": "PHP SDK for Klarna's XMLRPC API",
83
+ "homepage": "http://developers.klarna.com"
84
+ },
85
+ {
86
+ "name": "klarna/checkout",
87
+ "version": "v4.0.0",
88
+ "version_normalized": "4.0.0.0",
89
+ "source": {
90
+ "type": "git",
91
+ "url": "https://github.com/klarna/kco_php.git",
92
+ "reference": "00f1deed2155e525bb36d87a93c1471ba3333baf"
93
+ },
94
+ "dist": {
95
+ "type": "zip",
96
+ "url": "https://api.github.com/repos/klarna/kco_php/zipball/00f1deed2155e525bb36d87a93c1471ba3333baf",
97
+ "reference": "00f1deed2155e525bb36d87a93c1471ba3333baf",
98
+ "shasum": ""
99
+ },
100
+ "require": {
101
+ "ext-curl": "*",
102
+ "php": ">=5.3.0"
103
+ },
104
+ "require-dev": {
105
+ "phpmd/phpmd": "~2.2",
106
+ "phpunit/phpunit": "~4.6",
107
+ "satooshi/php-coveralls": "~0.6",
108
+ "squizlabs/php_codesniffer": "~2.3"
109
+ },
110
+ "time": "2015-06-11 12:26:37",
111
+ "type": "library",
112
+ "installation-source": "dist",
113
+ "autoload": {
114
+ "psr-0": {
115
+ "Klarna": "src"
116
+ }
117
+ },
118
+ "notification-url": "https://packagist.org/downloads/",
119
+ "license": [
120
+ "Apache-2.0"
121
+ ],
122
+ "description": "Wrapper for the Klarna Checkout API",
123
+ "homepage": "http://developers.klarna.com"
124
+ },
125
+ {
126
+ "name": "react/promise",
127
+ "version": "v2.2.1",
128
+ "version_normalized": "2.2.1.0",
129
+ "source": {
130
+ "type": "git",
131
+ "url": "https://github.com/reactphp/promise.git",
132
+ "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627"
133
+ },
134
+ "dist": {
135
+ "type": "zip",
136
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/3b6fca09c7d56321057fa8867c8dbe1abf648627",
137
+ "reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627",
138
+ "shasum": ""
139
+ },
140
+ "require": {
141
+ "php": ">=5.4.0"
142
+ },
143
+ "time": "2015-07-03 13:48:55",
144
+ "type": "library",
145
+ "extra": {
146
+ "branch-alias": {
147
+ "dev-master": "2.0-dev"
148
+ }
149
+ },
150
+ "installation-source": "dist",
151
+ "autoload": {
152
+ "psr-4": {
153
+ "React\\Promise\\": "src/"
154
+ },
155
+ "files": [
156
+ "src/functions_include.php"
157
+ ]
158
+ },
159
+ "notification-url": "https://packagist.org/downloads/",
160
+ "license": [
161
+ "MIT"
162
+ ],
163
+ "authors": [
164
+ {
165
+ "name": "Jan Sorgalla",
166
+ "email": "jsorgalla@gmail.com"
167
+ }
168
+ ],
169
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP"
170
+ },
171
+ {
172
+ "name": "guzzlehttp/streams",
173
+ "version": "3.0.0",
174
+ "version_normalized": "3.0.0.0",
175
+ "source": {
176
+ "type": "git",
177
+ "url": "https://github.com/guzzle/streams.git",
178
+ "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
179
+ },
180
+ "dist": {
181
+ "type": "zip",
182
+ "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
183
+ "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
184
+ "shasum": ""
185
+ },
186
+ "require": {
187
+ "php": ">=5.4.0"
188
+ },
189
+ "require-dev": {
190
+ "phpunit/phpunit": "~4.0"
191
+ },
192
+ "time": "2014-10-12 19:18:40",
193
+ "type": "library",
194
+ "extra": {
195
+ "branch-alias": {
196
+ "dev-master": "3.0-dev"
197
+ }
198
+ },
199
+ "installation-source": "dist",
200
+ "autoload": {
201
+ "psr-4": {
202
+ "GuzzleHttp\\Stream\\": "src/"
203
+ }
204
+ },
205
+ "notification-url": "https://packagist.org/downloads/",
206
+ "license": [
207
+ "MIT"
208
+ ],
209
+ "authors": [
210
+ {
211
+ "name": "Michael Dowling",
212
+ "email": "mtdowling@gmail.com",
213
+ "homepage": "https://github.com/mtdowling"
214
+ }
215
+ ],
216
+ "description": "Provides a simple abstraction over streams of data",
217
+ "homepage": "http://guzzlephp.org/",
218
+ "keywords": [
219
+ "Guzzle",
220
+ "stream"
221
+ ]
222
+ },
223
+ {
224
+ "name": "guzzlehttp/ringphp",
225
+ "version": "1.1.0",
226
+ "version_normalized": "1.1.0.0",
227
+ "source": {
228
+ "type": "git",
229
+ "url": "https://github.com/guzzle/RingPHP.git",
230
+ "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b"
231
+ },
232
+ "dist": {
233
+ "type": "zip",
234
+ "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
235
+ "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
236
+ "shasum": ""
237
+ },
238
+ "require": {
239
+ "guzzlehttp/streams": "~3.0",
240
+ "php": ">=5.4.0",
241
+ "react/promise": "~2.0"
242
+ },
243
+ "require-dev": {
244
+ "ext-curl": "*",
245
+ "phpunit/phpunit": "~4.0"
246
+ },
247
+ "suggest": {
248
+ "ext-curl": "Guzzle will use specific adapters if cURL is present"
249
+ },
250
+ "time": "2015-05-20 03:37:09",
251
+ "type": "library",
252
+ "extra": {
253
+ "branch-alias": {
254
+ "dev-master": "1.1-dev"
255
+ }
256
+ },
257
+ "installation-source": "dist",
258
+ "autoload": {
259
+ "psr-4": {
260
+ "GuzzleHttp\\Ring\\": "src/"
261
+ }
262
+ },
263
+ "notification-url": "https://packagist.org/downloads/",
264
+ "license": [
265
+ "MIT"
266
+ ],
267
+ "authors": [
268
+ {
269
+ "name": "Michael Dowling",
270
+ "email": "mtdowling@gmail.com",
271
+ "homepage": "https://github.com/mtdowling"
272
+ }
273
+ ],
274
+ "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function."
275
+ },
276
+ {
277
+ "name": "guzzlehttp/guzzle",
278
+ "version": "5.3.0",
279
+ "version_normalized": "5.3.0.0",
280
+ "source": {
281
+ "type": "git",
282
+ "url": "https://github.com/guzzle/guzzle.git",
283
+ "reference": "f3c8c22471cb55475105c14769644a49c3262b93"
284
+ },
285
+ "dist": {
286
+ "type": "zip",
287
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f3c8c22471cb55475105c14769644a49c3262b93",
288
+ "reference": "f3c8c22471cb55475105c14769644a49c3262b93",
289
+ "shasum": ""
290
+ },
291
+ "require": {
292
+ "guzzlehttp/ringphp": "^1.1",
293
+ "php": ">=5.4.0"
294
+ },
295
+ "require-dev": {
296
+ "ext-curl": "*",
297
+ "phpunit/phpunit": "^4.0",
298
+ "psr/log": "^1.0"
299
+ },
300
+ "time": "2015-05-20 03:47:55",
301
+ "type": "library",
302
+ "extra": {
303
+ "branch-alias": {
304
+ "dev-master": "5.0-dev"
305
+ }
306
+ },
307
+ "installation-source": "dist",
308
+ "autoload": {
309
+ "psr-4": {
310
+ "GuzzleHttp\\": "src/"
311
+ }
312
+ },
313
+ "notification-url": "https://packagist.org/downloads/",
314
+ "license": [
315
+ "MIT"
316
+ ],
317
+ "authors": [
318
+ {
319
+ "name": "Michael Dowling",
320
+ "email": "mtdowling@gmail.com",
321
+ "homepage": "https://github.com/mtdowling"
322
+ }
323
+ ],
324
+ "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
325
+ "homepage": "http://guzzlephp.org/",
326
+ "keywords": [
327
+ "client",
328
+ "curl",
329
+ "framework",
330
+ "http",
331
+ "http client",
332
+ "rest",
333
+ "web service"
334
+ ]
335
+ },
336
+ {
337
+ "name": "klarna/kco_rest",
338
+ "version": "v2.2.0",
339
+ "version_normalized": "2.2.0.0",
340
+ "source": {
341
+ "type": "git",
342
+ "url": "https://github.com/klarna/kco_rest_php.git",
343
+ "reference": "8a2142a2ebb087bb61901d51d1bb9698790e78c5"
344
+ },
345
+ "dist": {
346
+ "type": "zip",
347
+ "url": "https://api.github.com/repos/klarna/kco_rest_php/zipball/8a2142a2ebb087bb61901d51d1bb9698790e78c5",
348
+ "reference": "8a2142a2ebb087bb61901d51d1bb9698790e78c5",
349
+ "shasum": ""
350
+ },
351
+ "require": {
352
+ "guzzlehttp/guzzle": ">=4.2,<6.0",
353
+ "php": ">=5.4.0"
354
+ },
355
+ "require-dev": {
356
+ "apigen/apigen": "4.0.*",
357
+ "klarna/apigen-theme": "~1.0",
358
+ "phploc/phploc": "2.0.*",
359
+ "phpmd/phpmd": "2.1.*",
360
+ "phpunit/phpunit": "4.2.*",
361
+ "satooshi/php-coveralls": "0.6.*",
362
+ "sebastian/phpcpd": "2.0.*",
363
+ "squizlabs/php_codesniffer": "1.5.*"
364
+ },
365
+ "time": "2015-12-07 09:51:35",
366
+ "type": "library",
367
+ "installation-source": "dist",
368
+ "autoload": {
369
+ "psr-4": {
370
+ "": "src/"
371
+ }
372
+ },
373
+ "notification-url": "https://packagist.org/downloads/",
374
+ "license": [
375
+ "Apache-2.0"
376
+ ],
377
+ "authors": [
378
+ {
379
+ "name": "Klarna AB",
380
+ "email": "integration@klarna.com"
381
+ }
382
+ ],
383
+ "description": "Klarna Checkout PHP SDK",
384
+ "homepage": "http://developers.klarna.com"
385
+ }
386
+ ]
lib/KlarnaCheckout/guzzlehttp/guzzle/.editorconfig ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # EditorConfig is awesome: http://EditorConfig.org
2
+
3
+ # top-most EditorConfig file
4
+ root = true
5
+
6
+ # Unix-style newlines with a newline ending for every file
7
+ # Indent with 4 spaces
8
+ [php]
9
+ end_of_line = lf
10
+ indent_style = space
11
+ indent_size = 4
lib/KlarnaCheckout/guzzlehttp/guzzle/.gitignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ phpunit.xml
2
+ composer.phar
3
+ composer.lock
4
+ composer-test.lock
5
+ vendor/
6
+ build/artifacts/
7
+ artifacts/
8
+ docs/_build
9
+ docs/*.pyc
10
+ .idea
11
+ .DS_STORE
lib/KlarnaCheckout/guzzlehttp/guzzle/.travis.yml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.4
5
+ - 5.5
6
+ - 5.6
7
+ - 7.0
8
+ - hhvm
9
+
10
+ before_script:
11
+ - curl --version
12
+ - pear config-set php_ini ~/.phpenv/versions/`php -r 'echo phpversion();'`/etc/php.ini || echo 'Error modifying PEAR'
13
+ - pecl install uri_template || echo 'Error installing uri_template'
14
+ - composer self-update
15
+ - composer install --no-interaction --prefer-source --dev
16
+ - ~/.nvm/nvm.sh install v0.6.14
17
+ - ~/.nvm/nvm.sh run v0.6.14
18
+
19
+ script: make test
20
+
21
+ matrix:
22
+ allow_failures:
23
+ - php: hhvm
24
+ - php: 7.0
25
+ fast_finish: true
26
+
27
+ before_deploy:
28
+ - make package
29
+
30
+ deploy:
31
+ provider: releases
32
+ api_key:
33
+ secure: UpypqlYgsU68QT/x40YzhHXvzWjFwCNo9d+G8KAdm7U9+blFfcWhV1aMdzugvPMl6woXgvJj7qHq5tAL4v6oswCORhpSBfLgOQVFaica5LiHsvWlAedOhxGmnJqMTwuepjBCxXhs3+I8Kof1n4oUL9gKytXjOVCX/f7XU1HiinU=
34
+ file:
35
+ - build/artifacts/guzzle.phar
36
+ - build/artifacts/guzzle.zip
37
+ on:
38
+ repo: guzzle/guzzle
39
+ tags: true
40
+ all_branches: true
41
+ php: 5.4
lib/KlarnaCheckout/guzzlehttp/guzzle/CHANGELOG.md ADDED
@@ -0,0 +1,1053 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CHANGELOG
2
+
3
+ ## 5.3.0 - 2015-05-19
4
+
5
+ * Mock now supports `save_to`
6
+ * Marked `AbstractRequestEvent::getTransaction()` as public.
7
+ * Fixed a bug in which multiple headers using different casing would overwrite
8
+ previous headers in the associative array.
9
+ * Added `Utils::getDefaultHandler()`
10
+ * Marked `GuzzleHttp\Client::getDefaultUserAgent` as deprecated.
11
+ * URL scheme is now always lowercased.
12
+
13
+ ## 5.2.0 - 2015-01-27
14
+
15
+ * Added `AppliesHeadersInterface` to make applying headers to a request based
16
+ on the body more generic and not specific to `PostBodyInterface`.
17
+ * Reduced the number of stack frames needed to send requests.
18
+ * Nested futures are now resolved in the client rather than the RequestFsm
19
+ * Finishing state transitions is now handled in the RequestFsm rather than the
20
+ RingBridge.
21
+ * Added a guard in the Pool class to not use recursion for request retries.
22
+
23
+ ## 5.1.0 - 2014-12-19
24
+
25
+ * Pool class no longer uses recursion when a request is intercepted.
26
+ * The size of a Pool can now be dynamically adjusted using a callback.
27
+ See https://github.com/guzzle/guzzle/pull/943.
28
+ * Setting a request option to `null` when creating a request with a client will
29
+ ensure that the option is not set. This allows you to overwrite default
30
+ request options on a per-request basis.
31
+ See https://github.com/guzzle/guzzle/pull/937.
32
+ * Added the ability to limit which protocols are allowed for redirects by
33
+ specifying a `protocols` array in the `allow_redirects` request option.
34
+ * Nested futures due to retries are now resolved when waiting for synchronous
35
+ responses. See https://github.com/guzzle/guzzle/pull/947.
36
+ * `"0"` is now an allowed URI path. See
37
+ https://github.com/guzzle/guzzle/pull/935.
38
+ * `Query` no longer typehints on the `$query` argument in the constructor,
39
+ allowing for strings and arrays.
40
+ * Exceptions thrown in the `end` event are now correctly wrapped with Guzzle
41
+ specific exceptions if necessary.
42
+
43
+ ## 5.0.3 - 2014-11-03
44
+
45
+ This change updates query strings so that they are treated as un-encoded values
46
+ by default where the value represents an un-encoded value to send over the
47
+ wire. A Query object then encodes the value before sending over the wire. This
48
+ means that even value query string values (e.g., ":") are url encoded. This
49
+ makes the Query class match PHP's http_build_query function. However, if you
50
+ want to send requests over the wire using valid query string characters that do
51
+ not need to be encoded, then you can provide a string to Url::setQuery() and
52
+ pass true as the second argument to specify that the query string is a raw
53
+ string that should not be parsed or encoded (unless a call to getQuery() is
54
+ subsequently made, forcing the query-string to be converted into a Query
55
+ object).
56
+
57
+ ## 5.0.2 - 2014-10-30
58
+
59
+ * Added a trailing `\r\n` to multipart/form-data payloads. See
60
+ https://github.com/guzzle/guzzle/pull/871
61
+ * Added a `GuzzleHttp\Pool::send()` convenience method to match the docs.
62
+ * Status codes are now returned as integers. See
63
+ https://github.com/guzzle/guzzle/issues/881
64
+ * No longer overwriting an existing `application/x-www-form-urlencoded` header
65
+ when sending POST requests, allowing for customized headers. See
66
+ https://github.com/guzzle/guzzle/issues/877
67
+ * Improved path URL serialization.
68
+
69
+ * No longer double percent-encoding characters in the path or query string if
70
+ they are already encoded.
71
+ * Now properly encoding the supplied path to a URL object, instead of only
72
+ encoding ' ' and '?'.
73
+ * Note: This has been changed in 5.0.3 to now encode query string values by
74
+ default unless the `rawString` argument is provided when setting the query
75
+ string on a URL: Now allowing many more characters to be present in the
76
+ query string without being percent encoded. See http://tools.ietf.org/html/rfc3986#appendix-A
77
+
78
+ ## 5.0.1 - 2014-10-16
79
+
80
+ Bugfix release.
81
+
82
+ * Fixed an issue where connection errors still returned response object in
83
+ error and end events event though the response is unusable. This has been
84
+ corrected so that a response is not returned in the `getResponse` method of
85
+ these events if the response did not complete. https://github.com/guzzle/guzzle/issues/867
86
+ * Fixed an issue where transfer statistics were not being populated in the
87
+ RingBridge. https://github.com/guzzle/guzzle/issues/866
88
+
89
+ ## 5.0.0 - 2014-10-12
90
+
91
+ Adding support for non-blocking responses and some minor API cleanup.
92
+
93
+ ### New Features
94
+
95
+ * Added support for non-blocking responses based on `guzzlehttp/guzzle-ring`.
96
+ * Added a public API for creating a default HTTP adapter.
97
+ * Updated the redirect plugin to be non-blocking so that redirects are sent
98
+ concurrently. Other plugins like this can now be updated to be non-blocking.
99
+ * Added a "progress" event so that you can get upload and download progress
100
+ events.
101
+ * Added `GuzzleHttp\Pool` which implements FutureInterface and transfers
102
+ requests concurrently using a capped pool size as efficiently as possible.
103
+ * Added `hasListeners()` to EmitterInterface.
104
+ * Removed `GuzzleHttp\ClientInterface::sendAll` and marked
105
+ `GuzzleHttp\Client::sendAll` as deprecated (it's still there, just not the
106
+ recommended way).
107
+
108
+ ### Breaking changes
109
+
110
+ The breaking changes in this release are relatively minor. The biggest thing to
111
+ look out for is that request and response objects no longer implement fluent
112
+ interfaces.
113
+
114
+ * Removed the fluent interfaces (i.e., `return $this`) from requests,
115
+ responses, `GuzzleHttp\Collection`, `GuzzleHttp\Url`,
116
+ `GuzzleHttp\Query`, `GuzzleHttp\Post\PostBody`, and
117
+ `GuzzleHttp\Cookie\SetCookie`. This blog post provides a good outline of
118
+ why I did this: http://ocramius.github.io/blog/fluent-interfaces-are-evil/.
119
+ This also makes the Guzzle message interfaces compatible with the current
120
+ PSR-7 message proposal.
121
+ * Removed "functions.php", so that Guzzle is truly PSR-4 compliant. Except
122
+ for the HTTP request functions from function.php, these functions are now
123
+ implemented in `GuzzleHttp\Utils` using camelCase. `GuzzleHttp\json_decode`
124
+ moved to `GuzzleHttp\Utils::jsonDecode`. `GuzzleHttp\get_path` moved to
125
+ `GuzzleHttp\Utils::getPath`. `GuzzleHttp\set_path` moved to
126
+ `GuzzleHttp\Utils::setPath`. `GuzzleHttp\batch` should now be
127
+ `GuzzleHttp\Pool::batch`, which returns an `objectStorage`. Using functions.php
128
+ caused problems for many users: they aren't PSR-4 compliant, require an
129
+ explicit include, and needed an if-guard to ensure that the functions are not
130
+ declared multiple times.
131
+ * Rewrote adapter layer.
132
+ * Removing all classes from `GuzzleHttp\Adapter`, these are now
133
+ implemented as callables that are stored in `GuzzleHttp\Ring\Client`.
134
+ * Removed the concept of "parallel adapters". Sending requests serially or
135
+ concurrently is now handled using a single adapter.
136
+ * Moved `GuzzleHttp\Adapter\Transaction` to `GuzzleHttp\Transaction`. The
137
+ Transaction object now exposes the request, response, and client as public
138
+ properties. The getters and setters have been removed.
139
+ * Removed the "headers" event. This event was only useful for changing the
140
+ body a response once the headers of the response were known. You can implement
141
+ a similar behavior in a number of ways. One example might be to use a
142
+ FnStream that has access to the transaction being sent. For example, when the
143
+ first byte is written, you could check if the response headers match your
144
+ expectations, and if so, change the actual stream body that is being
145
+ written to.
146
+ * Removed the `asArray` parameter from
147
+ `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
148
+ value as an array, then use the newly added `getHeaderAsArray()` method of
149
+ `MessageInterface`. This change makes the Guzzle interfaces compatible with
150
+ the PSR-7 interfaces.
151
+ * `GuzzleHttp\Message\MessageFactory` no longer allows subclasses to add
152
+ custom request options using double-dispatch (this was an implementation
153
+ detail). Instead, you should now provide an associative array to the
154
+ constructor which is a mapping of the request option name mapping to a
155
+ function that applies the option value to a request.
156
+ * Removed the concept of "throwImmediately" from exceptions and error events.
157
+ This control mechanism was used to stop a transfer of concurrent requests
158
+ from completing. This can now be handled by throwing the exception or by
159
+ cancelling a pool of requests or each outstanding future request individually.
160
+ * Updated to "GuzzleHttp\Streams" 3.0.
161
+ * `GuzzleHttp\Stream\StreamInterface::getContents()` no longer accepts a
162
+ `maxLen` parameter. This update makes the Guzzle streams project
163
+ compatible with the current PSR-7 proposal.
164
+ * `GuzzleHttp\Stream\Stream::__construct`,
165
+ `GuzzleHttp\Stream\Stream::factory`, and
166
+ `GuzzleHttp\Stream\Utils::create` no longer accept a size in the second
167
+ argument. They now accept an associative array of options, including the
168
+ "size" key and "metadata" key which can be used to provide custom metadata.
169
+
170
+ ## 4.2.2 - 2014-09-08
171
+
172
+ * Fixed a memory leak in the CurlAdapter when reusing cURL handles.
173
+ * No longer using `request_fulluri` in stream adapter proxies.
174
+ * Relative redirects are now based on the last response, not the first response.
175
+
176
+ ## 4.2.1 - 2014-08-19
177
+
178
+ * Ensuring that the StreamAdapter does not always add a Content-Type header
179
+ * Adding automated github releases with a phar and zip
180
+
181
+ ## 4.2.0 - 2014-08-17
182
+
183
+ * Now merging in default options using a case-insensitive comparison.
184
+ Closes https://github.com/guzzle/guzzle/issues/767
185
+ * Added the ability to automatically decode `Content-Encoding` response bodies
186
+ using the `decode_content` request option. This is set to `true` by default
187
+ to decode the response body if it comes over the wire with a
188
+ `Content-Encoding`. Set this value to `false` to disable decoding the
189
+ response content, and pass a string to provide a request `Accept-Encoding`
190
+ header and turn on automatic response decoding. This feature now allows you
191
+ to pass an `Accept-Encoding` header in the headers of a request but still
192
+ disable automatic response decoding.
193
+ Closes https://github.com/guzzle/guzzle/issues/764
194
+ * Added the ability to throw an exception immediately when transferring
195
+ requests in parallel. Closes https://github.com/guzzle/guzzle/issues/760
196
+ * Updating guzzlehttp/streams dependency to ~2.1
197
+ * No longer utilizing the now deprecated namespaced methods from the stream
198
+ package.
199
+
200
+ ## 4.1.8 - 2014-08-14
201
+
202
+ * Fixed an issue in the CurlFactory that caused setting the `stream=false`
203
+ request option to throw an exception.
204
+ See: https://github.com/guzzle/guzzle/issues/769
205
+ * TransactionIterator now calls rewind on the inner iterator.
206
+ See: https://github.com/guzzle/guzzle/pull/765
207
+ * You can now set the `Content-Type` header to `multipart/form-data`
208
+ when creating POST requests to force multipart bodies.
209
+ See https://github.com/guzzle/guzzle/issues/768
210
+
211
+ ## 4.1.7 - 2014-08-07
212
+
213
+ * Fixed an error in the HistoryPlugin that caused the same request and response
214
+ to be logged multiple times when an HTTP protocol error occurs.
215
+ * Ensuring that cURL does not add a default Content-Type when no Content-Type
216
+ has been supplied by the user. This prevents the adapter layer from modifying
217
+ the request that is sent over the wire after any listeners may have already
218
+ put the request in a desired state (e.g., signed the request).
219
+ * Throwing an exception when you attempt to send requests that have the
220
+ "stream" set to true in parallel using the MultiAdapter.
221
+ * Only calling curl_multi_select when there are active cURL handles. This was
222
+ previously changed and caused performance problems on some systems due to PHP
223
+ always selecting until the maximum select timeout.
224
+ * Fixed a bug where multipart/form-data POST fields were not correctly
225
+ aggregated (e.g., values with "&").
226
+
227
+ ## 4.1.6 - 2014-08-03
228
+
229
+ * Added helper methods to make it easier to represent messages as strings,
230
+ including getting the start line and getting headers as a string.
231
+
232
+ ## 4.1.5 - 2014-08-02
233
+
234
+ * Automatically retrying cURL "Connection died, retrying a fresh connect"
235
+ errors when possible.
236
+ * cURL implementation cleanup
237
+ * Allowing multiple event subscriber listeners to be registered per event by
238
+ passing an array of arrays of listener configuration.
239
+
240
+ ## 4.1.4 - 2014-07-22
241
+
242
+ * Fixed a bug that caused multi-part POST requests with more than one field to
243
+ serialize incorrectly.
244
+ * Paths can now be set to "0"
245
+ * `ResponseInterface::xml` now accepts a `libxml_options` option and added a
246
+ missing default argument that was required when parsing XML response bodies.
247
+ * A `save_to` stream is now created lazily, which means that files are not
248
+ created on disk unless a request succeeds.
249
+
250
+ ## 4.1.3 - 2014-07-15
251
+
252
+ * Various fixes to multipart/form-data POST uploads
253
+ * Wrapping function.php in an if-statement to ensure Guzzle can be used
254
+ globally and in a Composer install
255
+ * Fixed an issue with generating and merging in events to an event array
256
+ * POST headers are only applied before sending a request to allow you to change
257
+ the query aggregator used before uploading
258
+ * Added much more robust query string parsing
259
+ * Fixed various parsing and normalization issues with URLs
260
+ * Fixing an issue where multi-valued headers were not being utilized correctly
261
+ in the StreamAdapter
262
+
263
+ ## 4.1.2 - 2014-06-18
264
+
265
+ * Added support for sending payloads with GET requests
266
+
267
+ ## 4.1.1 - 2014-06-08
268
+
269
+ * Fixed an issue related to using custom message factory options in subclasses
270
+ * Fixed an issue with nested form fields in a multi-part POST
271
+ * Fixed an issue with using the `json` request option for POST requests
272
+ * Added `ToArrayInterface` to `GuzzleHttp\Cookie\CookieJar`
273
+
274
+ ## 4.1.0 - 2014-05-27
275
+
276
+ * Added a `json` request option to easily serialize JSON payloads.
277
+ * Added a `GuzzleHttp\json_decode()` wrapper to safely parse JSON.
278
+ * Added `setPort()` and `getPort()` to `GuzzleHttp\Message\RequestInterface`.
279
+ * Added the ability to provide an emitter to a client in the client constructor.
280
+ * Added the ability to persist a cookie session using $_SESSION.
281
+ * Added a trait that can be used to add event listeners to an iterator.
282
+ * Removed request method constants from RequestInterface.
283
+ * Fixed warning when invalid request start-lines are received.
284
+ * Updated MessageFactory to work with custom request option methods.
285
+ * Updated cacert bundle to latest build.
286
+
287
+ 4.0.2 (2014-04-16)
288
+ ------------------
289
+
290
+ * Proxy requests using the StreamAdapter now properly use request_fulluri (#632)
291
+ * Added the ability to set scalars as POST fields (#628)
292
+
293
+ ## 4.0.1 - 2014-04-04
294
+
295
+ * The HTTP status code of a response is now set as the exception code of
296
+ RequestException objects.
297
+ * 303 redirects will now correctly switch from POST to GET requests.
298
+ * The default parallel adapter of a client now correctly uses the MultiAdapter.
299
+ * HasDataTrait now initializes the internal data array as an empty array so
300
+ that the toArray() method always returns an array.
301
+
302
+ ## 4.0.0 - 2014-03-29
303
+
304
+ * For more information on the 4.0 transition, see:
305
+ http://mtdowling.com/blog/2014/03/15/guzzle-4-rc/
306
+ * For information on changes and upgrading, see:
307
+ https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
308
+ * Added `GuzzleHttp\batch()` as a convenience function for sending requests in
309
+ parallel without needing to write asynchronous code.
310
+ * Restructured how events are added to `GuzzleHttp\ClientInterface::sendAll()`.
311
+ You can now pass a callable or an array of associative arrays where each
312
+ associative array contains the "fn", "priority", and "once" keys.
313
+
314
+ ## 4.0.0.rc-2 - 2014-03-25
315
+
316
+ * Removed `getConfig()` and `setConfig()` from clients to avoid confusion
317
+ around whether things like base_url, message_factory, etc. should be able to
318
+ be retrieved or modified.
319
+ * Added `getDefaultOption()` and `setDefaultOption()` to ClientInterface
320
+ * functions.php functions were renamed using snake_case to match PHP idioms
321
+ * Added support for `HTTP_PROXY`, `HTTPS_PROXY`, and
322
+ `GUZZLE_CURL_SELECT_TIMEOUT` environment variables
323
+ * Added the ability to specify custom `sendAll()` event priorities
324
+ * Added the ability to specify custom stream context options to the stream
325
+ adapter.
326
+ * Added a functions.php function for `get_path()` and `set_path()`
327
+ * CurlAdapter and MultiAdapter now use a callable to generate curl resources
328
+ * MockAdapter now properly reads a body and emits a `headers` event
329
+ * Updated Url class to check if a scheme and host are set before adding ":"
330
+ and "//". This allows empty Url (e.g., "") to be serialized as "".
331
+ * Parsing invalid XML no longer emits warnings
332
+ * Curl classes now properly throw AdapterExceptions
333
+ * Various performance optimizations
334
+ * Streams are created with the faster `Stream\create()` function
335
+ * Marked deprecation_proxy() as internal
336
+ * Test server is now a collection of static methods on a class
337
+
338
+ ## 4.0.0-rc.1 - 2014-03-15
339
+
340
+ * See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
341
+
342
+ ## 3.8.1 - 2014-01-28
343
+
344
+ * Bug: Always using GET requests when redirecting from a 303 response
345
+ * Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in
346
+ `Guzzle\Http\ClientInterface::setSslVerification()`
347
+ * Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL
348
+ * Bug: The body of a request can now be set to `"0"`
349
+ * Sending PHP stream requests no longer forces `HTTP/1.0`
350
+ * Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of
351
+ each sub-exception
352
+ * Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than
353
+ clobbering everything).
354
+ * Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators)
355
+ * Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`.
356
+ For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`.
357
+ * Now properly escaping the regular expression delimiter when matching Cookie domains.
358
+ * Network access is now disabled when loading XML documents
359
+
360
+ ## 3.8.0 - 2013-12-05
361
+
362
+ * Added the ability to define a POST name for a file
363
+ * JSON response parsing now properly walks additionalProperties
364
+ * cURL error code 18 is now retried automatically in the BackoffPlugin
365
+ * Fixed a cURL error when URLs contain fragments
366
+ * Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were
367
+ CurlExceptions
368
+ * CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e)
369
+ * Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS`
370
+ * Fixed a bug that was encountered when parsing empty header parameters
371
+ * UriTemplate now has a `setRegex()` method to match the docs
372
+ * The `debug` request parameter now checks if it is truthy rather than if it exists
373
+ * Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin
374
+ * Added the ability to combine URLs using strict RFC 3986 compliance
375
+ * Command objects can now return the validation errors encountered by the command
376
+ * Various fixes to cache revalidation (#437 and 29797e5)
377
+ * Various fixes to the AsyncPlugin
378
+ * Cleaned up build scripts
379
+
380
+ ## 3.7.4 - 2013-10-02
381
+
382
+ * Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430)
383
+ * Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp
384
+ (see https://github.com/aws/aws-sdk-php/issues/147)
385
+ * Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots
386
+ * Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420)
387
+ * Updated the bundled cacert.pem (#419)
388
+ * OauthPlugin now supports adding authentication to headers or query string (#425)
389
+
390
+ ## 3.7.3 - 2013-09-08
391
+
392
+ * Added the ability to get the exception associated with a request/command when using `MultiTransferException` and
393
+ `CommandTransferException`.
394
+ * Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description
395
+ * Schemas are only injected into response models when explicitly configured.
396
+ * No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of
397
+ an EntityBody.
398
+ * Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator.
399
+ * Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`.
400
+ * Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody()
401
+ * Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin
402
+ * Bug fix: Visiting XML attributes first before visiting XML children when serializing requests
403
+ * Bug fix: Properly parsing headers that contain commas contained in quotes
404
+ * Bug fix: mimetype guessing based on a filename is now case-insensitive
405
+
406
+ ## 3.7.2 - 2013-08-02
407
+
408
+ * Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander
409
+ See https://github.com/guzzle/guzzle/issues/371
410
+ * Bug fix: Cookie domains are now matched correctly according to RFC 6265
411
+ See https://github.com/guzzle/guzzle/issues/377
412
+ * Bug fix: GET parameters are now used when calculating an OAuth signature
413
+ * Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted
414
+ * `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched
415
+ * `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input.
416
+ See https://github.com/guzzle/guzzle/issues/379
417
+ * Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See
418
+ https://github.com/guzzle/guzzle/pull/380
419
+ * cURL multi cleanup and optimizations
420
+
421
+ ## 3.7.1 - 2013-07-05
422
+
423
+ * Bug fix: Setting default options on a client now works
424
+ * Bug fix: Setting options on HEAD requests now works. See #352
425
+ * Bug fix: Moving stream factory before send event to before building the stream. See #353
426
+ * Bug fix: Cookies no longer match on IP addresses per RFC 6265
427
+ * Bug fix: Correctly parsing header parameters that are in `<>` and quotes
428
+ * Added `cert` and `ssl_key` as request options
429
+ * `Host` header can now diverge from the host part of a URL if the header is set manually
430
+ * `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter
431
+ * OAuth parameters are only added via the plugin if they aren't already set
432
+ * Exceptions are now thrown when a URL cannot be parsed
433
+ * Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails
434
+ * Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin
435
+
436
+ ## 3.7.0 - 2013-06-10
437
+
438
+ * See UPGRADING.md for more information on how to upgrade.
439
+ * Requests now support the ability to specify an array of $options when creating a request to more easily modify a
440
+ request. You can pass a 'request.options' configuration setting to a client to apply default request options to
441
+ every request created by a client (e.g. default query string variables, headers, curl options, etc.).
442
+ * Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`.
443
+ See `Guzzle\Http\StaticClient::mount`.
444
+ * Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests
445
+ created by a command (e.g. custom headers, query string variables, timeout settings, etc.).
446
+ * Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the
447
+ headers of a response
448
+ * Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key
449
+ (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`)
450
+ * ServiceBuilders now support storing and retrieving arbitrary data
451
+ * CachePlugin can now purge all resources for a given URI
452
+ * CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource
453
+ * CachePlugin now uses the Vary header to determine if a resource is a cache hit
454
+ * `Guzzle\Http\Message\Response` now implements `\Serializable`
455
+ * Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters
456
+ * `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable
457
+ * Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()`
458
+ * Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size
459
+ * `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message
460
+ * Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older
461
+ Symfony users can still use the old version of Monolog.
462
+ * Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`.
463
+ Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`.
464
+ * Several performance improvements to `Guzzle\Common\Collection`
465
+ * Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
466
+ createRequest, head, delete, put, patch, post, options, prepareRequest
467
+ * Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
468
+ * Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
469
+ * Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
470
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
471
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
472
+ * Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
473
+ default `array()`
474
+ * Added `Guzzle\Stream\StreamInterface::isRepeatable`
475
+ * Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
476
+ $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
477
+ $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`.
478
+ * Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`.
479
+ * Removed `Guzzle\Http\ClientInterface::expandTemplate()`
480
+ * Removed `Guzzle\Http\ClientInterface::setRequestFactory()`
481
+ * Removed `Guzzle\Http\ClientInterface::getCurlMulti()`
482
+ * Removed `Guzzle\Http\Message\RequestInterface::canCache`
483
+ * Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`
484
+ * Removed `Guzzle\Http\Message\RequestInterface::isRedirect`
485
+ * Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
486
+ * You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting
487
+ `Guzzle\Common\Version::$emitWarnings` to true.
488
+ * Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use
489
+ `$request->getResponseBody()->isRepeatable()` instead.
490
+ * Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
491
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
492
+ * Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
493
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
494
+ * Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
495
+ * Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
496
+ * Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
497
+ * Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand.
498
+ These will work through Guzzle 4.0
499
+ * Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params].
500
+ * Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
501
+ * Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`.
502
+ * Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`.
503
+ * Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
504
+ * Marked `Guzzle\Common\Collection::inject()` as deprecated.
505
+ * Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');`
506
+ * CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
507
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
508
+ * Always setting X-cache headers on cached responses
509
+ * Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
510
+ * `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
511
+ $request, Response $response);`
512
+ * `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
513
+ * `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
514
+ * Added `CacheStorageInterface::purge($url)`
515
+ * `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
516
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
517
+ CanCacheStrategyInterface $canCache = null)`
518
+ * Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
519
+
520
+ ## 3.6.0 - 2013-05-29
521
+
522
+ * ServiceDescription now implements ToArrayInterface
523
+ * Added command.hidden_params to blacklist certain headers from being treated as additionalParameters
524
+ * Guzzle can now correctly parse incomplete URLs
525
+ * Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
526
+ * Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
527
+ * Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
528
+ * Specific header implementations can be created for complex headers. When a message creates a header, it uses a
529
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
530
+ CacheControl header implementation.
531
+ * Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
532
+ * Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
533
+ * Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
534
+ Guzzle\Http\Curl\RequestMediator
535
+ * Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
536
+ * Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
537
+ * Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
538
+ * Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
539
+ * Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
540
+ * All response header helper functions return a string rather than mixing Header objects and strings inconsistently
541
+ * Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
542
+ directly via interfaces
543
+ * Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
544
+ but are a no-op until removed.
545
+ * Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a
546
+ `Guzzle\Service\Command\ArrayCommandInterface`.
547
+ * Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
548
+ on a request while the request is still being transferred
549
+ * The ability to case-insensitively search for header values
550
+ * Guzzle\Http\Message\Header::hasExactHeader
551
+ * Guzzle\Http\Message\Header::raw. Use getAll()
552
+ * Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
553
+ instead.
554
+ * `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
555
+ * Added the ability to cast Model objects to a string to view debug information.
556
+
557
+ ## 3.5.0 - 2013-05-13
558
+
559
+ * Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times
560
+ * Bug: Better cleanup of one-time events across the board (when an event is meant to fire once, it will now remove
561
+ itself from the EventDispatcher)
562
+ * Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values
563
+ * Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too
564
+ * Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a
565
+ non-existent key
566
+ * Bug: All __call() method arguments are now required (helps with mocking frameworks)
567
+ * Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference
568
+ to help with refcount based garbage collection of resources created by sending a request
569
+ * Deprecating ZF1 cache and log adapters. These will be removed in the next major version.
570
+ * Deprecating `Response::getPreviousResponse()` (method signature still exists, but it'sdeprecated). Use the
571
+ HistoryPlugin for a history.
572
+ * Added a `responseBody` alias for the `response_body` location
573
+ * Refactored internals to no longer rely on Response::getRequest()
574
+ * HistoryPlugin can now be cast to a string
575
+ * HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests
576
+ and responses that are sent over the wire
577
+ * Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects
578
+
579
+ ## 3.4.3 - 2013-04-30
580
+
581
+ * Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response
582
+ * Added a check to re-extract the temp cacert bundle from the phar before sending each request
583
+
584
+ ## 3.4.2 - 2013-04-29
585
+
586
+ * Bug fix: Stream objects now work correctly with "a" and "a+" modes
587
+ * Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present
588
+ * Bug fix: AsyncPlugin no longer forces HEAD requests
589
+ * Bug fix: DateTime timezones are now properly handled when using the service description schema formatter
590
+ * Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails
591
+ * Setting a response on a request will write to the custom request body from the response body if one is specified
592
+ * LogPlugin now writes to php://output when STDERR is undefined
593
+ * Added the ability to set multiple POST files for the same key in a single call
594
+ * application/x-www-form-urlencoded POSTs now use the utf-8 charset by default
595
+ * Added the ability to queue CurlExceptions to the MockPlugin
596
+ * Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send)
597
+ * Configuration loading now allows remote files
598
+
599
+ ## 3.4.1 - 2013-04-16
600
+
601
+ * Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti
602
+ handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost.
603
+ * Exceptions are now properly grouped when sending requests in parallel
604
+ * Redirects are now properly aggregated when a multi transaction fails
605
+ * Redirects now set the response on the original object even in the event of a failure
606
+ * Bug fix: Model names are now properly set even when using $refs
607
+ * Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax
608
+ * Added support for oauth_callback in OAuth signatures
609
+ * Added support for oauth_verifier in OAuth signatures
610
+ * Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection
611
+
612
+ ## 3.4.0 - 2013-04-11
613
+
614
+ * Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289
615
+ * Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289
616
+ * Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263
617
+ * Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.
618
+ * Bug fix: Added `number` type to service descriptions.
619
+ * Bug fix: empty parameters are removed from an OAuth signature
620
+ * Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header
621
+ * Bug fix: Fixed "array to string" error when validating a union of types in a service description
622
+ * Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream
623
+ * Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin.
624
+ * Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs.
625
+ * The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections.
626
+ * Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if
627
+ the Content-Type can be determined based on the entity body or the path of the request.
628
+ * Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder.
629
+ * Added support for a PSR-3 LogAdapter.
630
+ * Added a `command.after_prepare` event
631
+ * Added `oauth_callback` parameter to the OauthPlugin
632
+ * Added the ability to create a custom stream class when using a stream factory
633
+ * Added a CachingEntityBody decorator
634
+ * Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized.
635
+ * The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar.
636
+ * You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies
637
+ * POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This
638
+ means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use
639
+ POST fields or files (the latter is only used when emulating a form POST in the browser).
640
+ * Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest
641
+
642
+ ## 3.3.1 - 2013-03-10
643
+
644
+ * Added the ability to create PHP streaming responses from HTTP requests
645
+ * Bug fix: Running any filters when parsing response headers with service descriptions
646
+ * Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing
647
+ * Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across
648
+ response location visitors.
649
+ * Bug fix: Removed the possibility of creating configuration files with circular dependencies
650
+ * RequestFactory::create() now uses the key of a POST file when setting the POST file name
651
+ * Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set
652
+
653
+ ## 3.3.0 - 2013-03-03
654
+
655
+ * A large number of performance optimizations have been made
656
+ * Bug fix: Added 'wb' as a valid write mode for streams
657
+ * Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned
658
+ * Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()`
659
+ * BC: Removed `Guzzle\Http\Utils` class
660
+ * BC: Setting a service description on a client will no longer modify the client's command factories.
661
+ * BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using
662
+ the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
663
+ * BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to
664
+ lowercase
665
+ * Operation parameter objects are now lazy loaded internally
666
+ * Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses
667
+ * Added support for instantiating responseType=class responseClass classes. Classes must implement
668
+ `Guzzle\Service\Command\ResponseClassInterface`
669
+ * Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These
670
+ additional properties also support locations and can be used to parse JSON responses where the outermost part of the
671
+ JSON is an array
672
+ * Added support for nested renaming of JSON models (rename sentAs to name)
673
+ * CachePlugin
674
+ * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error
675
+ * Debug headers can now added to cached response in the CachePlugin
676
+
677
+ ## 3.2.0 - 2013-02-14
678
+
679
+ * CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients.
680
+ * URLs with no path no longer contain a "/" by default
681
+ * Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url.
682
+ * BadResponseException no longer includes the full request and response message
683
+ * Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface
684
+ * Adding getResponseBody() to Guzzle\Http\Message\RequestInterface
685
+ * Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription
686
+ * Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list
687
+ * xmlEncoding can now be customized for the XML declaration of a XML service description operation
688
+ * Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value
689
+ aggregation and no longer uses callbacks
690
+ * The URL encoding implementation of Guzzle\Http\QueryString can now be customized
691
+ * Bug fix: Filters were not always invoked for array service description parameters
692
+ * Bug fix: Redirects now use a target response body rather than a temporary response body
693
+ * Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded
694
+ * Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives
695
+
696
+ ## 3.1.2 - 2013-01-27
697
+
698
+ * Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the
699
+ response body. For example, the XmlVisitor now parses the XML response into an array in the before() method.
700
+ * Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent
701
+ * CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444)
702
+ * Fixed a bug where redirect responses were not chained correctly using getPreviousResponse()
703
+ * Setting default headers on a client after setting the user-agent will not erase the user-agent setting
704
+
705
+ ## 3.1.1 - 2013-01-20
706
+
707
+ * Adding wildcard support to Guzzle\Common\Collection::getPath()
708
+ * Adding alias support to ServiceBuilder configs
709
+ * Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface
710
+
711
+ ## 3.1.0 - 2013-01-12
712
+
713
+ * BC: CurlException now extends from RequestException rather than BadResponseException
714
+ * BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse()
715
+ * Added getData to ServiceDescriptionInterface
716
+ * Added context array to RequestInterface::setState()
717
+ * Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http
718
+ * Bug: Adding required content-type when JSON request visitor adds JSON to a command
719
+ * Bug: Fixing the serialization of a service description with custom data
720
+ * Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing
721
+ an array of successful and failed responses
722
+ * Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection
723
+ * Added Guzzle\Http\IoEmittingEntityBody
724
+ * Moved command filtration from validators to location visitors
725
+ * Added `extends` attributes to service description parameters
726
+ * Added getModels to ServiceDescriptionInterface
727
+
728
+ ## 3.0.7 - 2012-12-19
729
+
730
+ * Fixing phar detection when forcing a cacert to system if null or true
731
+ * Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()`
732
+ * Cleaning up `Guzzle\Common\Collection::inject` method
733
+ * Adding a response_body location to service descriptions
734
+
735
+ ## 3.0.6 - 2012-12-09
736
+
737
+ * CurlMulti performance improvements
738
+ * Adding setErrorResponses() to Operation
739
+ * composer.json tweaks
740
+
741
+ ## 3.0.5 - 2012-11-18
742
+
743
+ * Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin
744
+ * Bug: Response body can now be a string containing "0"
745
+ * Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert
746
+ * Bug: QueryString::fromString now properly parses query string parameters that contain equal signs
747
+ * Added support for XML attributes in service description responses
748
+ * DefaultRequestSerializer now supports array URI parameter values for URI template expansion
749
+ * Added better mimetype guessing to requests and post files
750
+
751
+ ## 3.0.4 - 2012-11-11
752
+
753
+ * Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value
754
+ * Bug: Cookies can now be added that have a name, domain, or value set to "0"
755
+ * Bug: Using the system cacert bundle when using the Phar
756
+ * Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures
757
+ * Enhanced cookie jar de-duplication
758
+ * Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added
759
+ * Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies
760
+ * Added the ability to create any sort of hash for a stream rather than just an MD5 hash
761
+
762
+ ## 3.0.3 - 2012-11-04
763
+
764
+ * Implementing redirects in PHP rather than cURL
765
+ * Added PECL URI template extension and using as default parser if available
766
+ * Bug: Fixed Content-Length parsing of Response factory
767
+ * Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams.
768
+ * Adding ToArrayInterface throughout library
769
+ * Fixing OauthPlugin to create unique nonce values per request
770
+
771
+ ## 3.0.2 - 2012-10-25
772
+
773
+ * Magic methods are enabled by default on clients
774
+ * Magic methods return the result of a command
775
+ * Service clients no longer require a base_url option in the factory
776
+ * Bug: Fixed an issue with URI templates where null template variables were being expanded
777
+
778
+ ## 3.0.1 - 2012-10-22
779
+
780
+ * Models can now be used like regular collection objects by calling filter, map, etc.
781
+ * Models no longer require a Parameter structure or initial data in the constructor
782
+ * Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator`
783
+
784
+ ## 3.0.0 - 2012-10-15
785
+
786
+ * Rewrote service description format to be based on Swagger
787
+ * Now based on JSON schema
788
+ * Added nested input structures and nested response models
789
+ * Support for JSON and XML input and output models
790
+ * Renamed `commands` to `operations`
791
+ * Removed dot class notation
792
+ * Removed custom types
793
+ * Broke the project into smaller top-level namespaces to be more component friendly
794
+ * Removed support for XML configs and descriptions. Use arrays or JSON files.
795
+ * Removed the Validation component and Inspector
796
+ * Moved all cookie code to Guzzle\Plugin\Cookie
797
+ * Magic methods on a Guzzle\Service\Client now return the command un-executed.
798
+ * Calling getResult() or getResponse() on a command will lazily execute the command if needed.
799
+ * Now shipping with cURL's CA certs and using it by default
800
+ * Added previousResponse() method to response objects
801
+ * No longer sending Accept and Accept-Encoding headers on every request
802
+ * Only sending an Expect header by default when a payload is greater than 1MB
803
+ * Added/moved client options:
804
+ * curl.blacklist to curl.option.blacklist
805
+ * Added ssl.certificate_authority
806
+ * Added a Guzzle\Iterator component
807
+ * Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin
808
+ * Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin)
809
+ * Added a more robust caching plugin
810
+ * Added setBody to response objects
811
+ * Updating LogPlugin to use a more flexible MessageFormatter
812
+ * Added a completely revamped build process
813
+ * Cleaning up Collection class and removing default values from the get method
814
+ * Fixed ZF2 cache adapters
815
+
816
+ ## 2.8.8 - 2012-10-15
817
+
818
+ * Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did
819
+
820
+ ## 2.8.7 - 2012-09-30
821
+
822
+ * Bug: Fixed config file aliases for JSON includes
823
+ * Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests
824
+ * Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload
825
+ * Bug: Hardening request and response parsing to account for missing parts
826
+ * Bug: Fixed PEAR packaging
827
+ * Bug: Fixed Request::getInfo
828
+ * Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail
829
+ * Adding the ability for the namespace Iterator factory to look in multiple directories
830
+ * Added more getters/setters/removers from service descriptions
831
+ * Added the ability to remove POST fields from OAuth signatures
832
+ * OAuth plugin now supports 2-legged OAuth
833
+
834
+ ## 2.8.6 - 2012-09-05
835
+
836
+ * Added the ability to modify and build service descriptions
837
+ * Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command
838
+ * Added a `json` parameter location
839
+ * Now allowing dot notation for classes in the CacheAdapterFactory
840
+ * Using the union of two arrays rather than an array_merge when extending service builder services and service params
841
+ * Ensuring that a service is a string before doing strpos() checks on it when substituting services for references
842
+ in service builder config files.
843
+ * Services defined in two different config files that include one another will by default replace the previously
844
+ defined service, but you can now create services that extend themselves and merge their settings over the previous
845
+ * The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like
846
+ '_default' with a default JSON configuration file.
847
+
848
+ ## 2.8.5 - 2012-08-29
849
+
850
+ * Bug: Suppressed empty arrays from URI templates
851
+ * Bug: Added the missing $options argument from ServiceDescription::factory to enable caching
852
+ * Added support for HTTP responses that do not contain a reason phrase in the start-line
853
+ * AbstractCommand commands are now invokable
854
+ * Added a way to get the data used when signing an Oauth request before a request is sent
855
+
856
+ ## 2.8.4 - 2012-08-15
857
+
858
+ * Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin
859
+ * Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable.
860
+ * Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream
861
+ * Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream
862
+ * Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5())
863
+ * Added additional response status codes
864
+ * Removed SSL information from the default User-Agent header
865
+ * DELETE requests can now send an entity body
866
+ * Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries
867
+ * Added the ability of the MockPlugin to consume mocked request bodies
868
+ * LogPlugin now exposes request and response objects in the extras array
869
+
870
+ ## 2.8.3 - 2012-07-30
871
+
872
+ * Bug: Fixed a case where empty POST requests were sent as GET requests
873
+ * Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body
874
+ * Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new
875
+ * Added multiple inheritance to service description commands
876
+ * Added an ApiCommandInterface and added `getParamNames()` and `hasParam()`
877
+ * Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything
878
+ * Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles
879
+
880
+ ## 2.8.2 - 2012-07-24
881
+
882
+ * Bug: Query string values set to 0 are no longer dropped from the query string
883
+ * Bug: A Collection object is no longer created each time a call is made to `Guzzle\Service\Command\AbstractCommand::getRequestHeaders()`
884
+ * Bug: `+` is now treated as an encoded space when parsing query strings
885
+ * QueryString and Collection performance improvements
886
+ * Allowing dot notation for class paths in filters attribute of a service descriptions
887
+
888
+ ## 2.8.1 - 2012-07-16
889
+
890
+ * Loosening Event Dispatcher dependency
891
+ * POST redirects can now be customized using CURLOPT_POSTREDIR
892
+
893
+ ## 2.8.0 - 2012-07-15
894
+
895
+ * BC: Guzzle\Http\Query
896
+ * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl)
897
+ * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding()
898
+ * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool)
899
+ * Changed the aggregation functions of QueryString to be static methods
900
+ * Can now use fromString() with querystrings that have a leading ?
901
+ * cURL configuration values can be specified in service descriptions using `curl.` prefixed parameters
902
+ * Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body
903
+ * Cookies are no longer URL decoded by default
904
+ * Bug: URI template variables set to null are no longer expanded
905
+
906
+ ## 2.7.2 - 2012-07-02
907
+
908
+ * BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser.
909
+ * BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty()
910
+ * CachePlugin now allows for a custom request parameter function to check if a request can be cached
911
+ * Bug fix: CachePlugin now only caches GET and HEAD requests by default
912
+ * Bug fix: Using header glue when transferring headers over the wire
913
+ * Allowing deeply nested arrays for composite variables in URI templates
914
+ * Batch divisors can now return iterators or arrays
915
+
916
+ ## 2.7.1 - 2012-06-26
917
+
918
+ * Minor patch to update version number in UA string
919
+ * Updating build process
920
+
921
+ ## 2.7.0 - 2012-06-25
922
+
923
+ * BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes.
924
+ * BC: Removed magic setX methods from commands
925
+ * BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method
926
+ * Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable.
927
+ * Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity)
928
+ * Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace
929
+ * Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin
930
+ * Added the ability to set POST fields and files in a service description
931
+ * Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method
932
+ * Adding a command.before_prepare event to clients
933
+ * Added BatchClosureTransfer and BatchClosureDivisor
934
+ * BatchTransferException now includes references to the batch divisor and transfer strategies
935
+ * Fixed some tests so that they pass more reliably
936
+ * Added Guzzle\Common\Log\ArrayLogAdapter
937
+
938
+ ## 2.6.6 - 2012-06-10
939
+
940
+ * BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin
941
+ * BC: Removing Guzzle\Service\Command\CommandSet
942
+ * Adding generic batching system (replaces the batch queue plugin and command set)
943
+ * Updating ZF cache and log adapters and now using ZF's composer repository
944
+ * Bug: Setting the name of each ApiParam when creating through an ApiCommand
945
+ * Adding result_type, result_doc, deprecated, and doc_url to service descriptions
946
+ * Bug: Changed the default cookie header casing back to 'Cookie'
947
+
948
+ ## 2.6.5 - 2012-06-03
949
+
950
+ * BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource()
951
+ * BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from
952
+ * BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data
953
+ * BC: Renaming methods in the CookieJarInterface
954
+ * Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations
955
+ * Making the default glue for HTTP headers ';' instead of ','
956
+ * Adding a removeValue to Guzzle\Http\Message\Header
957
+ * Adding getCookies() to request interface.
958
+ * Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber()
959
+
960
+ ## 2.6.4 - 2012-05-30
961
+
962
+ * BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class.
963
+ * BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand
964
+ * Bug: Fixing magic method command calls on clients
965
+ * Bug: Email constraint only validates strings
966
+ * Bug: Aggregate POST fields when POST files are present in curl handle
967
+ * Bug: Fixing default User-Agent header
968
+ * Bug: Only appending or prepending parameters in commands if they are specified
969
+ * Bug: Not requiring response reason phrases or status codes to match a predefined list of codes
970
+ * Allowing the use of dot notation for class namespaces when using instance_of constraint
971
+ * Added any_match validation constraint
972
+ * Added an AsyncPlugin
973
+ * Passing request object to the calculateWait method of the ExponentialBackoffPlugin
974
+ * Allowing the result of a command object to be changed
975
+ * Parsing location and type sub values when instantiating a service description rather than over and over at runtime
976
+
977
+ ## 2.6.3 - 2012-05-23
978
+
979
+ * [BC] Guzzle\Common\FromConfigInterface no longer requires any config options.
980
+ * [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields.
981
+ * You can now use an array of data when creating PUT request bodies in the request factory.
982
+ * Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable.
983
+ * [Http] Adding support for Content-Type in multipart POST uploads per upload
984
+ * [Http] Added support for uploading multiple files using the same name (foo[0], foo[1])
985
+ * Adding more POST data operations for easier manipulation of POST data.
986
+ * You can now set empty POST fields.
987
+ * The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files.
988
+ * Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate.
989
+ * CS updates
990
+
991
+ ## 2.6.2 - 2012-05-19
992
+
993
+ * [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method.
994
+
995
+ ## 2.6.1 - 2012-05-19
996
+
997
+ * [BC] Removing 'path' support in service descriptions. Use 'uri'.
998
+ * [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache.
999
+ * [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it.
1000
+ * [BC] Removing Guzzle\Common\XmlElement.
1001
+ * All commands, both dynamic and concrete, have ApiCommand objects.
1002
+ * Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits.
1003
+ * Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored.
1004
+ * Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible.
1005
+
1006
+ ## 2.6.0 - 2012-05-15
1007
+
1008
+ * [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder
1009
+ * [BC] Executing a Command returns the result of the command rather than the command
1010
+ * [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed.
1011
+ * [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args.
1012
+ * [BC] Moving ResourceIterator* to Guzzle\Service\Resource
1013
+ * [BC] Completely refactored ResourceIterators to iterate over a cloned command object
1014
+ * [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate
1015
+ * [BC] Guzzle\Guzzle is now deprecated
1016
+ * Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject
1017
+ * Adding Guzzle\Version class to give version information about Guzzle
1018
+ * Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate()
1019
+ * Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data
1020
+ * ServiceDescription and ServiceBuilder are now cacheable using similar configs
1021
+ * Changing the format of XML and JSON service builder configs. Backwards compatible.
1022
+ * Cleaned up Cookie parsing
1023
+ * Trimming the default Guzzle User-Agent header
1024
+ * Adding a setOnComplete() method to Commands that is called when a command completes
1025
+ * Keeping track of requests that were mocked in the MockPlugin
1026
+ * Fixed a caching bug in the CacheAdapterFactory
1027
+ * Inspector objects can be injected into a Command object
1028
+ * Refactoring a lot of code and tests to be case insensitive when dealing with headers
1029
+ * Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL
1030
+ * Adding the ability to set global option overrides to service builder configs
1031
+ * Adding the ability to include other service builder config files from within XML and JSON files
1032
+ * Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method.
1033
+
1034
+ ## 2.5.0 - 2012-05-08
1035
+
1036
+ * Major performance improvements
1037
+ * [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated.
1038
+ * [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component.
1039
+ * [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}"
1040
+ * Added the ability to passed parameters to all requests created by a client
1041
+ * Added callback functionality to the ExponentialBackoffPlugin
1042
+ * Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies.
1043
+ * Rewinding request stream bodies when retrying requests
1044
+ * Exception is thrown when JSON response body cannot be decoded
1045
+ * Added configurable magic method calls to clients and commands. This is off by default.
1046
+ * Fixed a defect that added a hash to every parsed URL part
1047
+ * Fixed duplicate none generation for OauthPlugin.
1048
+ * Emitting an event each time a client is generated by a ServiceBuilder
1049
+ * Using an ApiParams object instead of a Collection for parameters of an ApiCommand
1050
+ * cache.* request parameters should be renamed to params.cache.*
1051
+ * Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc.). See CurlHandle.
1052
+ * Added the ability to disable type validation of service descriptions
1053
+ * ServiceDescriptions and ServiceBuilders are now Serializable
lib/KlarnaCheckout/guzzlehttp/guzzle/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
lib/KlarnaCheckout/guzzlehttp/guzzle/Makefile ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ all: clean coverage docs
2
+
3
+ start-server:
4
+ cd vendor/guzzlehttp/ringphp && make start-server
5
+
6
+ stop-server:
7
+ cd vendor/guzzlehttp/ringphp && make stop-server
8
+
9
+ test: start-server
10
+ vendor/bin/phpunit
11
+ $(MAKE) stop-server
12
+
13
+ coverage: start-server
14
+ vendor/bin/phpunit --coverage-html=artifacts/coverage
15
+ $(MAKE) stop-server
16
+
17
+ view-coverage:
18
+ open artifacts/coverage/index.html
19
+
20
+ clean:
21
+ rm -rf artifacts/*
22
+
23
+ docs:
24
+ cd docs && make html && cd ..
25
+
26
+ view-docs:
27
+ open docs/_build/html/index.html
28
+
29
+ tag:
30
+ $(if $(TAG),,$(error TAG is not defined. Pass via "make tag TAG=4.2.1"))
31
+ @echo Tagging $(TAG)
32
+ chag update $(TAG)
33
+ sed -i '' -e "s/VERSION = '.*'/VERSION = '$(TAG)'/" src/ClientInterface.php
34
+ php -l src/ClientInterface.php
35
+ git add -A
36
+ git commit -m '$(TAG) release'
37
+ chag tag
38
+
39
+ perf: start-server
40
+ php tests/perf.php
41
+ $(MAKE) stop-server
42
+
43
+ package: burgomaster
44
+ php build/packager.php
45
+
46
+ burgomaster:
47
+ mkdir -p build/artifacts
48
+ curl -s https://raw.githubusercontent.com/mtdowling/Burgomaster/0.0.2/src/Burgomaster.php > build/artifacts/Burgomaster.php
49
+
50
+ .PHONY: docs burgomaster
lib/KlarnaCheckout/guzzlehttp/guzzle/README.md ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Guzzle, PHP HTTP client and webservice framework
2
+ ================================================
3
+
4
+ [![Build Status](https://secure.travis-ci.org/guzzle/guzzle.svg?branch=master)](http://travis-ci.org/guzzle/guzzle)
5
+
6
+ Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
7
+ trivial to integrate with web services.
8
+
9
+ - Manages things like persistent connections, represents query strings as
10
+ collections, simplifies sending streaming POST requests with fields and
11
+ files, and abstracts away the underlying HTTP transport layer.
12
+ - Can send both synchronous and asynchronous requests using the same interface
13
+ without requiring a dependency on a specific event loop.
14
+ - Pluggable HTTP adapters allows Guzzle to integrate with any method you choose
15
+ for sending HTTP requests over the wire (e.g., cURL, sockets, PHP's stream
16
+ wrapper, non-blocking event loops like ReactPHP.
17
+ - Guzzle makes it so that you no longer need to fool around with cURL options,
18
+ stream contexts, or sockets.
19
+
20
+ ```php
21
+ $client = new GuzzleHttp\Client();
22
+ $response = $client->get('http://guzzlephp.org');
23
+ $res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]);
24
+ echo $res->getStatusCode();
25
+ // "200"
26
+ echo $res->getHeader('content-type');
27
+ // 'application/json; charset=utf8'
28
+ echo $res->getBody();
29
+ // {"type":"User"...'
30
+ var_export($res->json());
31
+ // Outputs the JSON decoded data
32
+
33
+ // Send an asynchronous request.
34
+ $req = $client->createRequest('GET', 'http://httpbin.org', ['future' => true]);
35
+ $client->send($req)->then(function ($response) {
36
+ echo 'I completed! ' . $response;
37
+ });
38
+ ```
39
+
40
+ Get more information and answers with the
41
+ [Documentation](http://guzzlephp.org/),
42
+ [Forums](https://groups.google.com/forum/?hl=en#!forum/guzzle),
43
+ and [Gitter](https://gitter.im/guzzle/guzzle).
44
+
45
+ ### Installing via Composer
46
+
47
+ The recommended way to install Guzzle is through
48
+ [Composer](http://getcomposer.org).
49
+
50
+ ```bash
51
+ # Install Composer
52
+ curl -sS https://getcomposer.org/installer | php
53
+ ```
54
+
55
+ Next, run the Composer command to install the latest stable version of Guzzle:
56
+
57
+ ```bash
58
+ composer.phar require guzzlehttp/guzzle
59
+ ```
60
+
61
+ After installing, you need to require Composer's autoloader:
62
+
63
+ ```php
64
+ require 'vendor/autoload.php';
65
+ ```
66
+
67
+ ### Documentation
68
+
69
+ More information can be found in the online documentation at
70
+ http://guzzlephp.org/.
lib/KlarnaCheckout/guzzlehttp/guzzle/UPGRADING.md ADDED
@@ -0,0 +1,1050 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Guzzle Upgrade Guide
2
+ ====================
3
+
4
+ 4.x to 5.0
5
+ ----------
6
+
7
+ ## Rewritten Adapter Layer
8
+
9
+ Guzzle now uses [RingPHP](http://ringphp.readthedocs.org/en/latest) to send
10
+ HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor
11
+ is still supported, but it has now been renamed to `handler`. Instead of
12
+ passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP
13
+ `callable` that follows the RingPHP specification.
14
+
15
+ ## Removed Fluent Interfaces
16
+
17
+ [Fluent interfaces were removed](http://ocramius.github.io/blog/fluent-interfaces-are-evil)
18
+ from the following classes:
19
+
20
+ - `GuzzleHttp\Collection`
21
+ - `GuzzleHttp\Url`
22
+ - `GuzzleHttp\Query`
23
+ - `GuzzleHttp\Post\PostBody`
24
+ - `GuzzleHttp\Cookie\SetCookie`
25
+
26
+ ## Removed functions.php
27
+
28
+ Removed "functions.php", so that Guzzle is truly PSR-4 compliant. The following
29
+ functions can be used as replacements.
30
+
31
+ - `GuzzleHttp\json_decode` -> `GuzzleHttp\Utils::jsonDecode`
32
+ - `GuzzleHttp\get_path` -> `GuzzleHttp\Utils::getPath`
33
+ - `GuzzleHttp\Utils::setPath` -> `GuzzleHttp\set_path`
34
+ - `GuzzleHttp\Pool::batch` -> `GuzzleHttp\batch`. This function is, however,
35
+ deprecated in favor of using `GuzzleHttp\Pool::batch()`.
36
+
37
+ The "procedural" global client has been removed with no replacement (e.g.,
38
+ `GuzzleHttp\get()`, `GuzzleHttp\post()`, etc.). Use a `GuzzleHttp\Client`
39
+ object as a replacement.
40
+
41
+ ## `throwImmediately` has been removed
42
+
43
+ The concept of "throwImmediately" has been removed from exceptions and error
44
+ events. This control mechanism was used to stop a transfer of concurrent
45
+ requests from completing. This can now be handled by throwing the exception or
46
+ by cancelling a pool of requests or each outstanding future request
47
+ individually.
48
+
49
+ ## headers event has been removed
50
+
51
+ Removed the "headers" event. This event was only useful for changing the
52
+ body a response once the headers of the response were known. You can implement
53
+ a similar behavior in a number of ways. One example might be to use a
54
+ FnStream that has access to the transaction being sent. For example, when the
55
+ first byte is written, you could check if the response headers match your
56
+ expectations, and if so, change the actual stream body that is being
57
+ written to.
58
+
59
+ ## Updates to HTTP Messages
60
+
61
+ Removed the `asArray` parameter from
62
+ `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
63
+ value as an array, then use the newly added `getHeaderAsArray()` method of
64
+ `MessageInterface`. This change makes the Guzzle interfaces compatible with
65
+ the PSR-7 interfaces.
66
+
67
+ 3.x to 4.0
68
+ ----------
69
+
70
+ ## Overarching changes:
71
+
72
+ - Now requires PHP 5.4 or greater.
73
+ - No longer requires cURL to send requests.
74
+ - Guzzle no longer wraps every exception it throws. Only exceptions that are
75
+ recoverable are now wrapped by Guzzle.
76
+ - Various namespaces have been removed or renamed.
77
+ - No longer requiring the Symfony EventDispatcher. A custom event dispatcher
78
+ based on the Symfony EventDispatcher is
79
+ now utilized in `GuzzleHttp\Event\EmitterInterface` (resulting in significant
80
+ speed and functionality improvements).
81
+
82
+ Changes per Guzzle 3.x namespace are described below.
83
+
84
+ ## Batch
85
+
86
+ The `Guzzle\Batch` namespace has been removed. This is best left to
87
+ third-parties to implement on top of Guzzle's core HTTP library.
88
+
89
+ ## Cache
90
+
91
+ The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement
92
+ has been implemented yet, but hoping to utilize a PSR cache interface).
93
+
94
+ ## Common
95
+
96
+ - Removed all of the wrapped exceptions. It's better to use the standard PHP
97
+ library for unrecoverable exceptions.
98
+ - `FromConfigInterface` has been removed.
99
+ - `Guzzle\Common\Version` has been removed. The VERSION constant can be found
100
+ at `GuzzleHttp\ClientInterface::VERSION`.
101
+
102
+ ### Collection
103
+
104
+ - `getAll` has been removed. Use `toArray` to convert a collection to an array.
105
+ - `inject` has been removed.
106
+ - `keySearch` has been removed.
107
+ - `getPath` no longer supports wildcard expressions. Use something better like
108
+ JMESPath for this.
109
+ - `setPath` now supports appending to an existing array via the `[]` notation.
110
+
111
+ ### Events
112
+
113
+ Guzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses
114
+ `GuzzleHttp\Event\Emitter`.
115
+
116
+ - `Symfony\Component\EventDispatcher\EventDispatcherInterface` is replaced by
117
+ `GuzzleHttp\Event\EmitterInterface`.
118
+ - `Symfony\Component\EventDispatcher\EventDispatcher` is replaced by
119
+ `GuzzleHttp\Event\Emitter`.
120
+ - `Symfony\Component\EventDispatcher\Event` is replaced by
121
+ `GuzzleHttp\Event\Event`, and Guzzle now has an EventInterface in
122
+ `GuzzleHttp\Event\EventInterface`.
123
+ - `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and
124
+ `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the
125
+ event emitter of a request, client, etc. now uses the `getEmitter` method
126
+ rather than the `getDispatcher` method.
127
+
128
+ #### Emitter
129
+
130
+ - Use the `once()` method to add a listener that automatically removes itself
131
+ the first time it is invoked.
132
+ - Use the `listeners()` method to retrieve a list of event listeners rather than
133
+ the `getListeners()` method.
134
+ - Use `emit()` instead of `dispatch()` to emit an event from an emitter.
135
+ - Use `attach()` instead of `addSubscriber()` and `detach()` instead of
136
+ `removeSubscriber()`.
137
+
138
+ ```php
139
+ $mock = new Mock();
140
+ // 3.x
141
+ $request->getEventDispatcher()->addSubscriber($mock);
142
+ $request->getEventDispatcher()->removeSubscriber($mock);
143
+ // 4.x
144
+ $request->getEmitter()->attach($mock);
145
+ $request->getEmitter()->detach($mock);
146
+ ```
147
+
148
+ Use the `on()` method to add a listener rather than the `addListener()` method.
149
+
150
+ ```php
151
+ // 3.x
152
+ $request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } );
153
+ // 4.x
154
+ $request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } );
155
+ ```
156
+
157
+ ## Http
158
+
159
+ ### General changes
160
+
161
+ - The cacert.pem certificate has been moved to `src/cacert.pem`.
162
+ - Added the concept of adapters that are used to transfer requests over the
163
+ wire.
164
+ - Simplified the event system.
165
+ - Sending requests in parallel is still possible, but batching is no longer a
166
+ concept of the HTTP layer. Instead, you must use the `complete` and `error`
167
+ events to asynchronously manage parallel request transfers.
168
+ - `Guzzle\Http\Url` has moved to `GuzzleHttp\Url`.
169
+ - `Guzzle\Http\QueryString` has moved to `GuzzleHttp\Query`.
170
+ - QueryAggregators have been rewritten so that they are simply callable
171
+ functions.
172
+ - `GuzzleHttp\StaticClient` has been removed. Use the functions provided in
173
+ `functions.php` for an easy to use static client instance.
174
+ - Exceptions in `GuzzleHttp\Exception` have been updated to all extend from
175
+ `GuzzleHttp\Exception\TransferException`.
176
+
177
+ ### Client
178
+
179
+ Calling methods like `get()`, `post()`, `head()`, etc. no longer create and
180
+ return a request, but rather creates a request, sends the request, and returns
181
+ the response.
182
+
183
+ ```php
184
+ // 3.0
185
+ $request = $client->get('/');
186
+ $response = $request->send();
187
+
188
+ // 4.0
189
+ $response = $client->get('/');
190
+
191
+ // or, to mirror the previous behavior
192
+ $request = $client->createRequest('GET', '/');
193
+ $response = $client->send($request);
194
+ ```
195
+
196
+ `GuzzleHttp\ClientInterface` has changed.
197
+
198
+ - The `send` method no longer accepts more than one request. Use `sendAll` to
199
+ send multiple requests in parallel.
200
+ - `setUserAgent()` has been removed. Use a default request option instead. You
201
+ could, for example, do something like:
202
+ `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`.
203
+ - `setSslVerification()` has been removed. Use default request options instead,
204
+ like `$client->setConfig('defaults/verify', true)`.
205
+
206
+ `GuzzleHttp\Client` has changed.
207
+
208
+ - The constructor now accepts only an associative array. You can include a
209
+ `base_url` string or array to use a URI template as the base URL of a client.
210
+ You can also specify a `defaults` key that is an associative array of default
211
+ request options. You can pass an `adapter` to use a custom adapter,
212
+ `batch_adapter` to use a custom adapter for sending requests in parallel, or
213
+ a `message_factory` to change the factory used to create HTTP requests and
214
+ responses.
215
+ - The client no longer emits a `client.create_request` event.
216
+ - Creating requests with a client no longer automatically utilize a URI
217
+ template. You must pass an array into a creational method (e.g.,
218
+ `createRequest`, `get`, `put`, etc.) in order to expand a URI template.
219
+
220
+ ### Messages
221
+
222
+ Messages no longer have references to their counterparts (i.e., a request no
223
+ longer has a reference to it's response, and a response no loger has a
224
+ reference to its request). This association is now managed through a
225
+ `GuzzleHttp\Adapter\TransactionInterface` object. You can get references to
226
+ these transaction objects using request events that are emitted over the
227
+ lifecycle of a request.
228
+
229
+ #### Requests with a body
230
+
231
+ - `GuzzleHttp\Message\EntityEnclosingRequest` and
232
+ `GuzzleHttp\Message\EntityEnclosingRequestInterface` have been removed. The
233
+ separation between requests that contain a body and requests that do not
234
+ contain a body has been removed, and now `GuzzleHttp\Message\RequestInterface`
235
+ handles both use cases.
236
+ - Any method that previously accepts a `GuzzleHttp\Response` object now accept a
237
+ `GuzzleHttp\Message\ResponseInterface`.
238
+ - `GuzzleHttp\Message\RequestFactoryInterface` has been renamed to
239
+ `GuzzleHttp\Message\MessageFactoryInterface`. This interface is used to create
240
+ both requests and responses and is implemented in
241
+ `GuzzleHttp\Message\MessageFactory`.
242
+ - POST field and file methods have been removed from the request object. You
243
+ must now use the methods made available to `GuzzleHttp\Post\PostBodyInterface`
244
+ to control the format of a POST body. Requests that are created using a
245
+ standard `GuzzleHttp\Message\MessageFactoryInterface` will automatically use
246
+ a `GuzzleHttp\Post\PostBody` body if the body was passed as an array or if
247
+ the method is POST and no body is provided.
248
+
249
+ ```php
250
+ $request = $client->createRequest('POST', '/');
251
+ $request->getBody()->setField('foo', 'bar');
252
+ $request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r')));
253
+ ```
254
+
255
+ #### Headers
256
+
257
+ - `GuzzleHttp\Message\Header` has been removed. Header values are now simply
258
+ represented by an array of values or as a string. Header values are returned
259
+ as a string by default when retrieving a header value from a message. You can
260
+ pass an optional argument of `true` to retrieve a header value as an array
261
+ of strings instead of a single concatenated string.
262
+ - `GuzzleHttp\PostFile` and `GuzzleHttp\PostFileInterface` have been moved to
263
+ `GuzzleHttp\Post`. This interface has been simplified and now allows the
264
+ addition of arbitrary headers.
265
+ - Custom headers like `GuzzleHttp\Message\Header\Link` have been removed. Most
266
+ of the custom headers are now handled separately in specific
267
+ subscribers/plugins, and `GuzzleHttp\Message\HeaderValues::parseParams()` has
268
+ been updated to properly handle headers that contain parameters (like the
269
+ `Link` header).
270
+
271
+ #### Responses
272
+
273
+ - `GuzzleHttp\Message\Response::getInfo()` and
274
+ `GuzzleHttp\Message\Response::setInfo()` have been removed. Use the event
275
+ system to retrieve this type of information.
276
+ - `GuzzleHttp\Message\Response::getRawHeaders()` has been removed.
277
+ - `GuzzleHttp\Message\Response::getMessage()` has been removed.
278
+ - `GuzzleHttp\Message\Response::calculateAge()` and other cache specific
279
+ methods have moved to the CacheSubscriber.
280
+ - Header specific helper functions like `getContentMd5()` have been removed.
281
+ Just use `getHeader('Content-MD5')` instead.
282
+ - `GuzzleHttp\Message\Response::setRequest()` and
283
+ `GuzzleHttp\Message\Response::getRequest()` have been removed. Use the event
284
+ system to work with request and response objects as a transaction.
285
+ - `GuzzleHttp\Message\Response::getRedirectCount()` has been removed. Use the
286
+ Redirect subscriber instead.
287
+ - `GuzzleHttp\Message\Response::isSuccessful()` and other related methods have
288
+ been removed. Use `getStatusCode()` instead.
289
+
290
+ #### Streaming responses
291
+
292
+ Streaming requests can now be created by a client directly, returning a
293
+ `GuzzleHttp\Message\ResponseInterface` object that contains a body stream
294
+ referencing an open PHP HTTP stream.
295
+
296
+ ```php
297
+ // 3.0
298
+ use Guzzle\Stream\PhpStreamRequestFactory;
299
+ $request = $client->get('/');
300
+ $factory = new PhpStreamRequestFactory();
301
+ $stream = $factory->fromRequest($request);
302
+ $data = $stream->read(1024);
303
+
304
+ // 4.0
305
+ $response = $client->get('/', ['stream' => true]);
306
+ // Read some data off of the stream in the response body
307
+ $data = $response->getBody()->read(1024);
308
+ ```
309
+
310
+ #### Redirects
311
+
312
+ The `configureRedirects()` method has been removed in favor of a
313
+ `allow_redirects` request option.
314
+
315
+ ```php
316
+ // Standard redirects with a default of a max of 5 redirects
317
+ $request = $client->createRequest('GET', '/', ['allow_redirects' => true]);
318
+
319
+ // Strict redirects with a custom number of redirects
320
+ $request = $client->createRequest('GET', '/', [
321
+ 'allow_redirects' => ['max' => 5, 'strict' => true]
322
+ ]);
323
+ ```
324
+
325
+ #### EntityBody
326
+
327
+ EntityBody interfaces and classes have been removed or moved to
328
+ `GuzzleHttp\Stream`. All classes and interfaces that once required
329
+ `GuzzleHttp\EntityBodyInterface` now require
330
+ `GuzzleHttp\Stream\StreamInterface`. Creating a new body for a request no
331
+ longer uses `GuzzleHttp\EntityBody::factory` but now uses
332
+ `GuzzleHttp\Stream\Stream::factory` or even better:
333
+ `GuzzleHttp\Stream\create()`.
334
+
335
+ - `Guzzle\Http\EntityBodyInterface` is now `GuzzleHttp\Stream\StreamInterface`
336
+ - `Guzzle\Http\EntityBody` is now `GuzzleHttp\Stream\Stream`
337
+ - `Guzzle\Http\CachingEntityBody` is now `GuzzleHttp\Stream\CachingStream`
338
+ - `Guzzle\Http\ReadLimitEntityBody` is now `GuzzleHttp\Stream\LimitStream`
339
+ - `Guzzle\Http\IoEmittyinEntityBody` has been removed.
340
+
341
+ #### Request lifecycle events
342
+
343
+ Requests previously submitted a large number of requests. The number of events
344
+ emitted over the lifecycle of a request has been significantly reduced to make
345
+ it easier to understand how to extend the behavior of a request. All events
346
+ emitted during the lifecycle of a request now emit a custom
347
+ `GuzzleHttp\Event\EventInterface` object that contains context providing
348
+ methods and a way in which to modify the transaction at that specific point in
349
+ time (e.g., intercept the request and set a response on the transaction).
350
+
351
+ - `request.before_send` has been renamed to `before` and now emits a
352
+ `GuzzleHttp\Event\BeforeEvent`
353
+ - `request.complete` has been renamed to `complete` and now emits a
354
+ `GuzzleHttp\Event\CompleteEvent`.
355
+ - `request.sent` has been removed. Use `complete`.
356
+ - `request.success` has been removed. Use `complete`.
357
+ - `error` is now an event that emits a `GuzzleHttp\Event\ErrorEvent`.
358
+ - `request.exception` has been removed. Use `error`.
359
+ - `request.receive.status_line` has been removed.
360
+ - `curl.callback.progress` has been removed. Use a custom `StreamInterface` to
361
+ maintain a status update.
362
+ - `curl.callback.write` has been removed. Use a custom `StreamInterface` to
363
+ intercept writes.
364
+ - `curl.callback.read` has been removed. Use a custom `StreamInterface` to
365
+ intercept reads.
366
+
367
+ `headers` is a new event that is emitted after the response headers of a
368
+ request have been received before the body of the response is downloaded. This
369
+ event emits a `GuzzleHttp\Event\HeadersEvent`.
370
+
371
+ You can intercept a request and inject a response using the `intercept()` event
372
+ of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and
373
+ `GuzzleHttp\Event\ErrorEvent` event.
374
+
375
+ See: http://docs.guzzlephp.org/en/latest/events.html
376
+
377
+ ## Inflection
378
+
379
+ The `Guzzle\Inflection` namespace has been removed. This is not a core concern
380
+ of Guzzle.
381
+
382
+ ## Iterator
383
+
384
+ The `Guzzle\Iterator` namespace has been removed.
385
+
386
+ - `Guzzle\Iterator\AppendIterator`, `Guzzle\Iterator\ChunkedIterator`, and
387
+ `Guzzle\Iterator\MethodProxyIterator` are nice, but not a core requirement of
388
+ Guzzle itself.
389
+ - `Guzzle\Iterator\FilterIterator` is no longer needed because an equivalent
390
+ class is shipped with PHP 5.4.
391
+ - `Guzzle\Iterator\MapIterator` is not really needed when using PHP 5.5 because
392
+ it's easier to just wrap an iterator in a generator that maps values.
393
+
394
+ For a replacement of these iterators, see https://github.com/nikic/iter
395
+
396
+ ## Log
397
+
398
+ The LogPlugin has moved to https://github.com/guzzle/log-subscriber. The
399
+ `Guzzle\Log` namespace has been removed. Guzzle now relies on
400
+ `Psr\Log\LoggerInterface` for all logging. The MessageFormatter class has been
401
+ moved to `GuzzleHttp\Subscriber\Log\Formatter`.
402
+
403
+ ## Parser
404
+
405
+ The `Guzzle\Parser` namespace has been removed. This was previously used to
406
+ make it possible to plug in custom parsers for cookies, messages, URI
407
+ templates, and URLs; however, this level of complexity is not needed in Guzzle
408
+ so it has been removed.
409
+
410
+ - Cookie: Cookie parsing logic has been moved to
411
+ `GuzzleHttp\Cookie\SetCookie::fromString`.
412
+ - Message: Message parsing logic for both requests and responses has been moved
413
+ to `GuzzleHttp\Message\MessageFactory::fromMessage`. Message parsing is only
414
+ used in debugging or deserializing messages, so it doesn't make sense for
415
+ Guzzle as a library to add this level of complexity to parsing messages.
416
+ - UriTemplate: URI template parsing has been moved to
417
+ `GuzzleHttp\UriTemplate`. The Guzzle library will automatically use the PECL
418
+ URI template library if it is installed.
419
+ - Url: URL parsing is now performed in `GuzzleHttp\Url::fromString` (previously
420
+ it was `Guzzle\Http\Url::factory()`). If custom URL parsing is necessary,
421
+ then developers are free to subclass `GuzzleHttp\Url`.
422
+
423
+ ## Plugin
424
+
425
+ The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`.
426
+ Several plugins are shipping with the core Guzzle library under this namespace.
427
+
428
+ - `GuzzleHttp\Subscriber\Cookie`: Replaces the old CookiePlugin. Cookie jar
429
+ code has moved to `GuzzleHttp\Cookie`.
430
+ - `GuzzleHttp\Subscriber\History`: Replaces the old HistoryPlugin.
431
+ - `GuzzleHttp\Subscriber\HttpError`: Throws errors when a bad HTTP response is
432
+ received.
433
+ - `GuzzleHttp\Subscriber\Mock`: Replaces the old MockPlugin.
434
+ - `GuzzleHttp\Subscriber\Prepare`: Prepares the body of a request just before
435
+ sending. This subscriber is attached to all requests by default.
436
+ - `GuzzleHttp\Subscriber\Redirect`: Replaces the RedirectPlugin.
437
+
438
+ The following plugins have been removed (third-parties are free to re-implement
439
+ these if needed):
440
+
441
+ - `GuzzleHttp\Plugin\Async` has been removed.
442
+ - `GuzzleHttp\Plugin\CurlAuth` has been removed.
443
+ - `GuzzleHttp\Plugin\ErrorResponse\ErrorResponsePlugin` has been removed. This
444
+ functionality should instead be implemented with event listeners that occur
445
+ after normal response parsing occurs in the guzzle/command package.
446
+
447
+ The following plugins are not part of the core Guzzle package, but are provided
448
+ in separate repositories:
449
+
450
+ - `Guzzle\Http\Plugin\BackoffPlugin` has been rewritten to be muchs simpler
451
+ to build custom retry policies using simple functions rather than various
452
+ chained classes. See: https://github.com/guzzle/retry-subscriber
453
+ - `Guzzle\Http\Plugin\Cache\CachePlugin` has moved to
454
+ https://github.com/guzzle/cache-subscriber
455
+ - `Guzzle\Http\Plugin\Log\LogPlugin` has moved to
456
+ https://github.com/guzzle/log-subscriber
457
+ - `Guzzle\Http\Plugin\Md5\Md5Plugin` has moved to
458
+ https://github.com/guzzle/message-integrity-subscriber
459
+ - `Guzzle\Http\Plugin\Mock\MockPlugin` has moved to
460
+ `GuzzleHttp\Subscriber\MockSubscriber`.
461
+ - `Guzzle\Http\Plugin\Oauth\OauthPlugin` has moved to
462
+ https://github.com/guzzle/oauth-subscriber
463
+
464
+ ## Service
465
+
466
+ The service description layer of Guzzle has moved into two separate packages:
467
+
468
+ - http://github.com/guzzle/command Provides a high level abstraction over web
469
+ services by representing web service operations using commands.
470
+ - http://github.com/guzzle/guzzle-services Provides an implementation of
471
+ guzzle/command that provides request serialization and response parsing using
472
+ Guzzle service descriptions.
473
+
474
+ ## Stream
475
+
476
+ Stream have moved to a separate package available at
477
+ https://github.com/guzzle/streams.
478
+
479
+ `Guzzle\Stream\StreamInterface` has been given a large update to cleanly take
480
+ on the responsibilities of `Guzzle\Http\EntityBody` and
481
+ `Guzzle\Http\EntityBodyInterface` now that they have been removed. The number
482
+ of methods implemented by the `StreamInterface` has been drastically reduced to
483
+ allow developers to more easily extend and decorate stream behavior.
484
+
485
+ ## Removed methods from StreamInterface
486
+
487
+ - `getStream` and `setStream` have been removed to better encapsulate streams.
488
+ - `getMetadata` and `setMetadata` have been removed in favor of
489
+ `GuzzleHttp\Stream\MetadataStreamInterface`.
490
+ - `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been
491
+ removed. This data is accessible when
492
+ using streams that implement `GuzzleHttp\Stream\MetadataStreamInterface`.
493
+ - `rewind` has been removed. Use `seek(0)` for a similar behavior.
494
+
495
+ ## Renamed methods
496
+
497
+ - `detachStream` has been renamed to `detach`.
498
+ - `feof` has been renamed to `eof`.
499
+ - `ftell` has been renamed to `tell`.
500
+ - `readLine` has moved from an instance method to a static class method of
501
+ `GuzzleHttp\Stream\Stream`.
502
+
503
+ ## Metadata streams
504
+
505
+ `GuzzleHttp\Stream\MetadataStreamInterface` has been added to denote streams
506
+ that contain additional metadata accessible via `getMetadata()`.
507
+ `GuzzleHttp\Stream\StreamInterface::getMetadata` and
508
+ `GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed.
509
+
510
+ ## StreamRequestFactory
511
+
512
+ The entire concept of the StreamRequestFactory has been removed. The way this
513
+ was used in Guzzle 3 broke the actual interface of sending streaming requests
514
+ (instead of getting back a Response, you got a StreamInterface). Streeaming
515
+ PHP requests are now implemented throught the `GuzzleHttp\Adapter\StreamAdapter`.
516
+
517
+ 3.6 to 3.7
518
+ ----------
519
+
520
+ ### Deprecations
521
+
522
+ - You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.:
523
+
524
+ ```php
525
+ \Guzzle\Common\Version::$emitWarnings = true;
526
+ ```
527
+
528
+ The following APIs and options have been marked as deprecated:
529
+
530
+ - Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead.
531
+ - Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
532
+ - Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
533
+ - Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
534
+ - Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
535
+ - Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
536
+ - Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
537
+ - Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
538
+ - Marked `Guzzle\Common\Collection::inject()` as deprecated.
539
+ - Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use
540
+ `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or
541
+ `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));`
542
+
543
+ 3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational
544
+ request methods. When paired with a client's configuration settings, these options allow you to specify default settings
545
+ for various aspects of a request. Because these options make other previous configuration options redundant, several
546
+ configuration options and methods of a client and AbstractCommand have been deprecated.
547
+
548
+ - Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`.
549
+ - Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`.
550
+ - Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')`
551
+ - Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0
552
+
553
+ $command = $client->getCommand('foo', array(
554
+ 'command.headers' => array('Test' => '123'),
555
+ 'command.response_body' => '/path/to/file'
556
+ ));
557
+
558
+ // Should be changed to:
559
+
560
+ $command = $client->getCommand('foo', array(
561
+ 'command.request_options' => array(
562
+ 'headers' => array('Test' => '123'),
563
+ 'save_as' => '/path/to/file'
564
+ )
565
+ ));
566
+
567
+ ### Interface changes
568
+
569
+ Additions and changes (you will need to update any implementations or subclasses you may have created):
570
+
571
+ - Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
572
+ createRequest, head, delete, put, patch, post, options, prepareRequest
573
+ - Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
574
+ - Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
575
+ - Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
576
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
577
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
578
+ - Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
579
+ default `array()`
580
+ - Added `Guzzle\Stream\StreamInterface::isRepeatable`
581
+ - Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
582
+
583
+ The following methods were removed from interfaces. All of these methods are still available in the concrete classes
584
+ that implement them, but you should update your code to use alternative methods:
585
+
586
+ - Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
587
+ `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
588
+ `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or
589
+ `$client->setDefaultOption('headers/{header_name}', 'value')`. or
590
+ `$client->setDefaultOption('headers', array('header_name' => 'value'))`.
591
+ - Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`.
592
+ - Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail.
593
+ - Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail.
594
+ - Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail.
595
+ - Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin.
596
+ - Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin.
597
+ - Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin.
598
+
599
+ ### Cache plugin breaking changes
600
+
601
+ - CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
602
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
603
+ - Always setting X-cache headers on cached responses
604
+ - Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
605
+ - `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
606
+ $request, Response $response);`
607
+ - `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
608
+ - `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
609
+ - Added `CacheStorageInterface::purge($url)`
610
+ - `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
611
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
612
+ CanCacheStrategyInterface $canCache = null)`
613
+ - Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
614
+
615
+ 3.5 to 3.6
616
+ ----------
617
+
618
+ * Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
619
+ * Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
620
+ * Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
621
+ For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader().
622
+ Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request.
623
+ * Specific header implementations can be created for complex headers. When a message creates a header, it uses a
624
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
625
+ CacheControl header implementation.
626
+ * Moved getLinks() from Response to just be used on a Link header object.
627
+
628
+ If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the
629
+ HeaderInterface (e.g. toArray(), getAll(), etc.).
630
+
631
+ ### Interface changes
632
+
633
+ * Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
634
+ * Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
635
+ * Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
636
+ Guzzle\Http\Curl\RequestMediator
637
+ * Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
638
+ * Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
639
+ * Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
640
+
641
+ ### Removed deprecated functions
642
+
643
+ * Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
644
+ * Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
645
+
646
+ ### Deprecations
647
+
648
+ * The ability to case-insensitively search for header values
649
+ * Guzzle\Http\Message\Header::hasExactHeader
650
+ * Guzzle\Http\Message\Header::raw. Use getAll()
651
+ * Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
652
+ instead.
653
+
654
+ ### Other changes
655
+
656
+ * All response header helper functions return a string rather than mixing Header objects and strings inconsistently
657
+ * Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
658
+ directly via interfaces
659
+ * Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
660
+ but are a no-op until removed.
661
+ * Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a
662
+ `Guzzle\Service\Command\ArrayCommandInterface`.
663
+ * Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
664
+ on a request while the request is still being transferred
665
+ * `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
666
+
667
+ 3.3 to 3.4
668
+ ----------
669
+
670
+ Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
671
+
672
+ 3.2 to 3.3
673
+ ----------
674
+
675
+ ### Response::getEtag() quote stripping removed
676
+
677
+ `Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header
678
+
679
+ ### Removed `Guzzle\Http\Utils`
680
+
681
+ The `Guzzle\Http\Utils` class was removed. This class was only used for testing.
682
+
683
+ ### Stream wrapper and type
684
+
685
+ `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getStreamType()` are no longer converted to lowercase.
686
+
687
+ ### curl.emit_io became emit_io
688
+
689
+ Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the
690
+ 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
691
+
692
+ 3.1 to 3.2
693
+ ----------
694
+
695
+ ### CurlMulti is no longer reused globally
696
+
697
+ Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added
698
+ to a single client can pollute requests dispatched from other clients.
699
+
700
+ If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the
701
+ ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is
702
+ created.
703
+
704
+ ```php
705
+ $multi = new Guzzle\Http\Curl\CurlMulti();
706
+ $builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json');
707
+ $builder->addListener('service_builder.create_client', function ($event) use ($multi) {
708
+ $event['client']->setCurlMulti($multi);
709
+ }
710
+ });
711
+ ```
712
+
713
+ ### No default path
714
+
715
+ URLs no longer have a default path value of '/' if no path was specified.
716
+
717
+ Before:
718
+
719
+ ```php
720
+ $request = $client->get('http://www.foo.com');
721
+ echo $request->getUrl();
722
+ // >> http://www.foo.com/
723
+ ```
724
+
725
+ After:
726
+
727
+ ```php
728
+ $request = $client->get('http://www.foo.com');
729
+ echo $request->getUrl();
730
+ // >> http://www.foo.com
731
+ ```
732
+
733
+ ### Less verbose BadResponseException
734
+
735
+ The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and
736
+ response information. You can, however, get access to the request and response object by calling `getRequest()` or
737
+ `getResponse()` on the exception object.
738
+
739
+ ### Query parameter aggregation
740
+
741
+ Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a
742
+ setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is
743
+ responsible for handling the aggregation of multi-valued query string variables into a flattened hash.
744
+
745
+ 2.8 to 3.x
746
+ ----------
747
+
748
+ ### Guzzle\Service\Inspector
749
+
750
+ Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig`
751
+
752
+ **Before**
753
+
754
+ ```php
755
+ use Guzzle\Service\Inspector;
756
+
757
+ class YourClient extends \Guzzle\Service\Client
758
+ {
759
+ public static function factory($config = array())
760
+ {
761
+ $default = array();
762
+ $required = array('base_url', 'username', 'api_key');
763
+ $config = Inspector::fromConfig($config, $default, $required);
764
+
765
+ $client = new self(
766
+ $config->get('base_url'),
767
+ $config->get('username'),
768
+ $config->get('api_key')
769
+ );
770
+ $client->setConfig($config);
771
+
772
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
773
+
774
+ return $client;
775
+ }
776
+ ```
777
+
778
+ **After**
779
+
780
+ ```php
781
+ use Guzzle\Common\Collection;
782
+
783
+ class YourClient extends \Guzzle\Service\Client
784
+ {
785
+ public static function factory($config = array())
786
+ {
787
+ $default = array();
788
+ $required = array('base_url', 'username', 'api_key');
789
+ $config = Collection::fromConfig($config, $default, $required);
790
+
791
+ $client = new self(
792
+ $config->get('base_url'),
793
+ $config->get('username'),
794
+ $config->get('api_key')
795
+ );
796
+ $client->setConfig($config);
797
+
798
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
799
+
800
+ return $client;
801
+ }
802
+ ```
803
+
804
+ ### Convert XML Service Descriptions to JSON
805
+
806
+ **Before**
807
+
808
+ ```xml
809
+ <?xml version="1.0" encoding="UTF-8"?>
810
+ <client>
811
+ <commands>
812
+ <!-- Groups -->
813
+ <command name="list_groups" method="GET" uri="groups.json">
814
+ <doc>Get a list of groups</doc>
815
+ </command>
816
+ <command name="search_groups" method="GET" uri='search.json?query="{{query}} type:group"'>
817
+ <doc>Uses a search query to get a list of groups</doc>
818
+ <param name="query" type="string" required="true" />
819
+ </command>
820
+ <command name="create_group" method="POST" uri="groups.json">
821
+ <doc>Create a group</doc>
822
+ <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
823
+ <param name="Content-Type" location="header" static="application/json"/>
824
+ </command>
825
+ <command name="delete_group" method="DELETE" uri="groups/{{id}}.json">
826
+ <doc>Delete a group by ID</doc>
827
+ <param name="id" type="integer" required="true"/>
828
+ </command>
829
+ <command name="get_group" method="GET" uri="groups/{{id}}.json">
830
+ <param name="id" type="integer" required="true"/>
831
+ </command>
832
+ <command name="update_group" method="PUT" uri="groups/{{id}}.json">
833
+ <doc>Update a group</doc>
834
+ <param name="id" type="integer" required="true"/>
835
+ <param name="data" type="array" location="body" filters="json_encode" doc="Group JSON"/>
836
+ <param name="Content-Type" location="header" static="application/json"/>
837
+ </command>
838
+ </commands>
839
+ </client>
840
+ ```
841
+
842
+ **After**
843
+
844
+ ```json
845
+ {
846
+ "name": "Zendesk REST API v2",
847
+ "apiVersion": "2012-12-31",
848
+ "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users",
849
+ "operations": {
850
+ "list_groups": {
851
+ "httpMethod":"GET",
852
+ "uri": "groups.json",
853
+ "summary": "Get a list of groups"
854
+ },
855
+ "search_groups":{
856
+ "httpMethod":"GET",
857
+ "uri": "search.json?query=\"{query} type:group\"",
858
+ "summary": "Uses a search query to get a list of groups",
859
+ "parameters":{
860
+ "query":{
861
+ "location": "uri",
862
+ "description":"Zendesk Search Query",
863
+ "type": "string",
864
+ "required": true
865
+ }
866
+ }
867
+ },
868
+ "create_group": {
869
+ "httpMethod":"POST",
870
+ "uri": "groups.json",
871
+ "summary": "Create a group",
872
+ "parameters":{
873
+ "data": {
874
+ "type": "array",
875
+ "location": "body",
876
+ "description":"Group JSON",
877
+ "filters": "json_encode",
878
+ "required": true
879
+ },
880
+ "Content-Type":{
881
+ "type": "string",
882
+ "location":"header",
883
+ "static": "application/json"
884
+ }
885
+ }
886
+ },
887
+ "delete_group": {
888
+ "httpMethod":"DELETE",
889
+ "uri": "groups/{id}.json",
890
+ "summary": "Delete a group",
891
+ "parameters":{
892
+ "id":{
893
+ "location": "uri",
894
+ "description":"Group to delete by ID",
895
+ "type": "integer",
896
+ "required": true
897
+ }
898
+ }
899
+ },
900
+ "get_group": {
901
+ "httpMethod":"GET",
902
+ "uri": "groups/{id}.json",
903
+ "summary": "Get a ticket",
904
+ "parameters":{
905
+ "id":{
906
+ "location": "uri",
907
+ "description":"Group to get by ID",
908
+ "type": "integer",
909
+ "required": true
910
+ }
911
+ }
912
+ },
913
+ "update_group": {
914
+ "httpMethod":"PUT",
915
+ "uri": "groups/{id}.json",
916
+ "summary": "Update a group",
917
+ "parameters":{
918
+ "id": {
919
+ "location": "uri",
920
+ "description":"Group to update by ID",
921
+ "type": "integer",
922
+ "required": true
923
+ },
924
+ "data": {
925
+ "type": "array",
926
+ "location": "body",
927
+ "description":"Group JSON",
928
+ "filters": "json_encode",
929
+ "required": true
930
+ },
931
+ "Content-Type":{
932
+ "type": "string",
933
+ "location":"header",
934
+ "static": "application/json"
935
+ }
936
+ }
937
+ }
938
+ }
939
+ ```
940
+
941
+ ### Guzzle\Service\Description\ServiceDescription
942
+
943
+ Commands are now called Operations
944
+
945
+ **Before**
946
+
947
+ ```php
948
+ use Guzzle\Service\Description\ServiceDescription;
949
+
950
+ $sd = new ServiceDescription();
951
+ $sd->getCommands(); // @returns ApiCommandInterface[]
952
+ $sd->hasCommand($name);
953
+ $sd->getCommand($name); // @returns ApiCommandInterface|null
954
+ $sd->addCommand($command); // @param ApiCommandInterface $command
955
+ ```
956
+
957
+ **After**
958
+
959
+ ```php
960
+ use Guzzle\Service\Description\ServiceDescription;
961
+
962
+ $sd = new ServiceDescription();
963
+ $sd->getOperations(); // @returns OperationInterface[]
964
+ $sd->hasOperation($name);
965
+ $sd->getOperation($name); // @returns OperationInterface|null
966
+ $sd->addOperation($operation); // @param OperationInterface $operation
967
+ ```
968
+
969
+ ### Guzzle\Common\Inflection\Inflector
970
+
971
+ Namespace is now `Guzzle\Inflection\Inflector`
972
+
973
+ ### Guzzle\Http\Plugin
974
+
975
+ Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.
976
+
977
+ ### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log
978
+
979
+ Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively.
980
+
981
+ **Before**
982
+
983
+ ```php
984
+ use Guzzle\Common\Log\ClosureLogAdapter;
985
+ use Guzzle\Http\Plugin\LogPlugin;
986
+
987
+ /** @var \Guzzle\Http\Client */
988
+ $client;
989
+
990
+ // $verbosity is an integer indicating desired message verbosity level
991
+ $client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);
992
+ ```
993
+
994
+ **After**
995
+
996
+ ```php
997
+ use Guzzle\Log\ClosureLogAdapter;
998
+ use Guzzle\Log\MessageFormatter;
999
+ use Guzzle\Plugin\Log\LogPlugin;
1000
+
1001
+ /** @var \Guzzle\Http\Client */
1002
+ $client;
1003
+
1004
+ // $format is a string indicating desired message format -- @see MessageFormatter
1005
+ $client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);
1006
+ ```
1007
+
1008
+ ### Guzzle\Http\Plugin\CurlAuthPlugin
1009
+
1010
+ Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`.
1011
+
1012
+ ### Guzzle\Http\Plugin\ExponentialBackoffPlugin
1013
+
1014
+ Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes.
1015
+
1016
+ **Before**
1017
+
1018
+ ```php
1019
+ use Guzzle\Http\Plugin\ExponentialBackoffPlugin;
1020
+
1021
+ $backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(
1022
+ ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)
1023
+ ));
1024
+
1025
+ $client->addSubscriber($backoffPlugin);
1026
+ ```
1027
+
1028
+ **After**
1029
+
1030
+ ```php
1031
+ use Guzzle\Plugin\Backoff\BackoffPlugin;
1032
+ use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
1033
+
1034
+ // Use convenient factory method instead -- see implementation for ideas of what
1035
+ // you can do with chaining backoff strategies
1036
+ $backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(
1037
+ HttpBackoffStrategy::getDefaultFailureCodes(), array(429)
1038
+ ));
1039
+ $client->addSubscriber($backoffPlugin);
1040
+ ```
1041
+
1042
+ ### Known Issues
1043
+
1044
+ #### [BUG] Accept-Encoding header behavior changed unintentionally.
1045
+
1046
+ (See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)
1047
+
1048
+ In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to
1049
+ properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.
1050
+ See issue #217 for a workaround, or use a version containing the fix.
lib/KlarnaCheckout/guzzlehttp/guzzle/build/packager.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require __DIR__ . '/artifacts/Burgomaster.php';
3
+
4
+ $stageDirectory = __DIR__ . '/artifacts/staging';
5
+ $projectRoot = __DIR__ . '/../';
6
+ $packager = new \Burgomaster($stageDirectory, $projectRoot);
7
+
8
+ // Copy basic files to the stage directory. Note that we have chdir'd onto
9
+ // the $projectRoot directory, so use relative paths.
10
+ foreach (['README.md', 'LICENSE'] as $file) {
11
+ $packager->deepCopy($file, $file);
12
+ }
13
+
14
+ // Copy each dependency to the staging directory. Copy *.php and *.pem files.
15
+ $packager->recursiveCopy('src', 'GuzzleHttp', ['php']);
16
+ $packager->recursiveCopy('vendor/react/promise/src', 'React/Promise');
17
+ $packager->recursiveCopy('vendor/guzzlehttp/ringphp/src', 'GuzzleHttp/Ring');
18
+ $packager->recursiveCopy('vendor/guzzlehttp/streams/src', 'GuzzleHttp/Stream');
19
+ $packager->createAutoloader(['React/Promise/functions.php']);
20
+ $packager->createPhar(__DIR__ . '/artifacts/guzzle.phar');
21
+ $packager->createZip(__DIR__ . '/artifacts/guzzle.zip');
lib/KlarnaCheckout/guzzlehttp/guzzle/composer.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "guzzlehttp/guzzle",
3
+ "type": "library",
4
+ "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
5
+ "keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"],
6
+ "homepage": "http://guzzlephp.org/",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "Michael Dowling",
11
+ "email": "mtdowling@gmail.com",
12
+ "homepage": "https://github.com/mtdowling"
13
+ }
14
+ ],
15
+ "require": {
16
+ "php": ">=5.4.0",
17
+ "guzzlehttp/ringphp": "^1.1"
18
+ },
19
+ "require-dev": {
20
+ "ext-curl": "*",
21
+ "psr/log": "^1.0",
22
+ "phpunit/phpunit": "^4.0"
23
+ },
24
+ "autoload": {
25
+ "psr-4": {
26
+ "GuzzleHttp\\": "src/"
27
+ }
28
+ },
29
+ "autoload-dev": {
30
+ "psr-4": {
31
+ "GuzzleHttp\\Tests\\": "tests/"
32
+ }
33
+ },
34
+ "extra": {
35
+ "branch-alias": {
36
+ "dev-master": "5.0-dev"
37
+ }
38
+ }
39
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/Makefile ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line.
5
+ SPHINXOPTS =
6
+ SPHINXBUILD = sphinx-build
7
+ PAPER =
8
+ BUILDDIR = _build
9
+
10
+ # Internal variables.
11
+ PAPEROPT_a4 = -D latex_paper_size=a4
12
+ PAPEROPT_letter = -D latex_paper_size=letter
13
+ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14
+ # the i18n builder cannot share the environment and doctrees with the others
15
+ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16
+
17
+ .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18
+
19
+ help:
20
+ @echo "Please use \`make <target>' where <target> is one of"
21
+ @echo " html to make standalone HTML files"
22
+ @echo " dirhtml to make HTML files named index.html in directories"
23
+ @echo " singlehtml to make a single large HTML file"
24
+ @echo " pickle to make pickle files"
25
+ @echo " json to make JSON files"
26
+ @echo " htmlhelp to make HTML files and a HTML help project"
27
+ @echo " qthelp to make HTML files and a qthelp project"
28
+ @echo " devhelp to make HTML files and a Devhelp project"
29
+ @echo " epub to make an epub"
30
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
32
+ @echo " text to make text files"
33
+ @echo " man to make manual pages"
34
+ @echo " texinfo to make Texinfo files"
35
+ @echo " info to make Texinfo files and run them through makeinfo"
36
+ @echo " gettext to make PO message catalogs"
37
+ @echo " changes to make an overview of all changed/added/deprecated items"
38
+ @echo " linkcheck to check all external links for integrity"
39
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40
+
41
+ clean:
42
+ -rm -rf $(BUILDDIR)/*
43
+
44
+ html:
45
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46
+ @echo
47
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48
+
49
+ dirhtml:
50
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51
+ @echo
52
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53
+
54
+ singlehtml:
55
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56
+ @echo
57
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58
+
59
+ pickle:
60
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61
+ @echo
62
+ @echo "Build finished; now you can process the pickle files."
63
+
64
+ json:
65
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66
+ @echo
67
+ @echo "Build finished; now you can process the JSON files."
68
+
69
+ htmlhelp:
70
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71
+ @echo
72
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
73
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
74
+
75
+ qthelp:
76
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77
+ @echo
78
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Guzzle.qhcp"
81
+ @echo "To view the help file:"
82
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Guzzle.qhc"
83
+
84
+ devhelp:
85
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86
+ @echo
87
+ @echo "Build finished."
88
+ @echo "To view the help file:"
89
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/Guzzle"
90
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Guzzle"
91
+ @echo "# devhelp"
92
+
93
+ epub:
94
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95
+ @echo
96
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97
+
98
+ latex:
99
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100
+ @echo
101
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
103
+ "(use \`make latexpdf' here to do that automatically)."
104
+
105
+ latexpdf:
106
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107
+ @echo "Running LaTeX files through pdflatex..."
108
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
109
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110
+
111
+ text:
112
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113
+ @echo
114
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
115
+
116
+ man:
117
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118
+ @echo
119
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120
+
121
+ texinfo:
122
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123
+ @echo
124
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125
+ @echo "Run \`make' in that directory to run these through makeinfo" \
126
+ "(use \`make info' here to do that automatically)."
127
+
128
+ info:
129
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130
+ @echo "Running Texinfo files through makeinfo..."
131
+ make -C $(BUILDDIR)/texinfo info
132
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133
+
134
+ gettext:
135
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136
+ @echo
137
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138
+
139
+ changes:
140
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141
+ @echo
142
+ @echo "The overview file is in $(BUILDDIR)/changes."
143
+
144
+ linkcheck:
145
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146
+ @echo
147
+ @echo "Link check complete; look for any errors in the above output " \
148
+ "or in $(BUILDDIR)/linkcheck/output.txt."
149
+
150
+ doctest:
151
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152
+ @echo "Testing of doctests in the sources finished, look at the " \
153
+ "results in $(BUILDDIR)/doctest/output.txt."
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/_static/guzzle-icon.png ADDED
Binary file
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/_static/logo.png ADDED
Binary file
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/_templates/nav_links.html ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <li><a href="https://github.com/guzzle/guzzle">GitHub</a></li>
2
+ <li><a href="https://groups.google.com/forum/?hl=en#!forum/guzzle">Forum</a></li>
3
+ <li><a href="irc:irc.freenode.com/#guzzlephp">IRC</a></li>
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/clients.rst ADDED
@@ -0,0 +1,1326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ Clients
3
+ =======
4
+
5
+ Clients are used to create requests, create transactions, send requests
6
+ through an HTTP handler, and return a response. You can add default request
7
+ options to a client that are applied to every request (e.g., default headers,
8
+ default query string parameters, etc.), and you can add event listeners and
9
+ subscribers to every request created by a client.
10
+
11
+ Creating a client
12
+ =================
13
+
14
+ The constructor of a client accepts an associative array of configuration
15
+ options.
16
+
17
+ base_url
18
+ Configures a base URL for the client so that requests created
19
+ using a relative URL are combined with the ``base_url`` of the client
20
+ according to section `5.2 of RFC 3986 <http://tools.ietf.org/html/rfc3986#section-5.2>`_.
21
+
22
+ .. code-block:: php
23
+
24
+ // Create a client with a base URL
25
+ $client = new GuzzleHttp\Client(['base_url' => 'https://github.com']);
26
+ // Send a request to https://github.com/notifications
27
+ $response = $client->get('/notifications');
28
+
29
+ Don't feel like reading RFC 3986? Here are some quick examples on how a
30
+ ``base_url`` is resolved with another URI.
31
+
32
+ ======================= ================== ===============================
33
+ base_url URI Result
34
+ ======================= ================== ===============================
35
+ ``http://foo.com`` ``/bar`` ``http://foo.com/bar``
36
+ ``http://foo.com/foo`` ``/bar`` ``http://foo.com/bar``
37
+ ``http://foo.com/foo`` ``bar`` ``http://foo.com/bar``
38
+ ``http://foo.com/foo/`` ``bar`` ``http://foo.com/foo/bar``
39
+ ``http://foo.com`` ``http://baz.com`` ``http://baz.com``
40
+ ``http://foo.com/?bar`` ``bar`` ``http://foo.com/bar``
41
+ ======================= ================== ===============================
42
+
43
+ handler
44
+ Configures the `RingPHP handler <http://ringphp.readthedocs.org>`_
45
+ used to transfer the HTTP requests of a client. Guzzle will, by default,
46
+ utilize a stacked handlers that chooses the best handler to use based on the
47
+ provided request options and based on the extensions available in the
48
+ environment.
49
+
50
+ message_factory
51
+ Specifies the factory used to create HTTP requests and responses
52
+ (``GuzzleHttp\Message\MessageFactoryInterface``).
53
+
54
+ defaults
55
+ Associative array of :ref:`request-options` that are applied to every
56
+ request created by the client. This allows you to specify things like
57
+ default headers (e.g., User-Agent), default query string parameters, SSL
58
+ configurations, and any other supported request options.
59
+
60
+ emitter
61
+ Specifies an event emitter (``GuzzleHttp\Event\EmitterInterface``) instance
62
+ to be used by the client to emit request events. This option is useful if
63
+ you need to inject an emitter with listeners/subscribers already attached.
64
+
65
+ Here's an example of creating a client with various options.
66
+
67
+ .. code-block:: php
68
+
69
+ use GuzzleHttp\Client;
70
+
71
+ $client = new Client([
72
+ 'base_url' => ['https://api.twitter.com/{version}/', ['version' => 'v1.1']],
73
+ 'defaults' => [
74
+ 'headers' => ['Foo' => 'Bar'],
75
+ 'query' => ['testing' => '123'],
76
+ 'auth' => ['username', 'password'],
77
+ 'proxy' => 'tcp://localhost:80'
78
+ ]
79
+ ]);
80
+
81
+ Sending Requests
82
+ ================
83
+
84
+ Requests can be created using various methods of a client. You can create
85
+ **and** send requests using one of the following methods:
86
+
87
+ - ``GuzzleHttp\Client::get``: Sends a GET request.
88
+ - ``GuzzleHttp\Client::head``: Sends a HEAD request
89
+ - ``GuzzleHttp\Client::post``: Sends a POST request
90
+ - ``GuzzleHttp\Client::put``: Sends a PUT request
91
+ - ``GuzzleHttp\Client::delete``: Sends a DELETE request
92
+ - ``GuzzleHttp\Client::options``: Sends an OPTIONS request
93
+
94
+ Each of the above methods accepts a URL as the first argument and an optional
95
+ associative array of :ref:`request-options` as the second argument.
96
+
97
+ Synchronous Requests
98
+ --------------------
99
+
100
+ Guzzle sends synchronous (blocking) requests when the ``future`` request option
101
+ is not specified. This means that the request will complete immediately, and if
102
+ an error is encountered, a ``GuzzleHttp\Exception\RequestException`` will be
103
+ thrown.
104
+
105
+ .. code-block:: php
106
+
107
+ $client = new GuzzleHttp\Client();
108
+
109
+ $client->put('http://httpbin.org', [
110
+ 'headers' => ['X-Foo' => 'Bar'],
111
+ 'body' => 'this is the body!',
112
+ 'save_to' => '/path/to/local/file',
113
+ 'allow_redirects' => false,
114
+ 'timeout' => 5
115
+ ]);
116
+
117
+ Synchronous Error Handling
118
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
119
+
120
+ When a recoverable error is encountered while calling the ``send()`` method of
121
+ a client, a ``GuzzleHttp\Exception\RequestException`` is thrown.
122
+
123
+ .. code-block:: php
124
+
125
+ use GuzzleHttp\Client;
126
+ use GuzzleHttp\Exception\RequestException;
127
+
128
+ $client = new Client();
129
+
130
+ try {
131
+ $client->get('http://httpbin.org');
132
+ } catch (RequestException $e) {
133
+ echo $e->getRequest() . "\n";
134
+ if ($e->hasResponse()) {
135
+ echo $e->getResponse() . "\n";
136
+ }
137
+ }
138
+
139
+ ``GuzzleHttp\Exception\RequestException`` always contains a
140
+ ``GuzzleHttp\Message\RequestInterface`` object that can be accessed using the
141
+ exception's ``getRequest()`` method.
142
+
143
+ A response might be present in the exception. In the event of a networking
144
+ error, no response will be received. You can check if a ``RequestException``
145
+ has a response using the ``hasResponse()`` method. If the exception has a
146
+ response, then you can access the associated
147
+ ``GuzzleHttp\Message\ResponseInterface`` using the ``getResponse()`` method of
148
+ the exception.
149
+
150
+ Asynchronous Requests
151
+ ---------------------
152
+
153
+ You can send asynchronous requests by setting the ``future`` request option
154
+ to ``true`` (or a string that your handler understands). This creates a
155
+ ``GuzzleHttp\Message\FutureResponse`` object that has not yet completed. Once
156
+ you have a future response, you can use a promise object obtained by calling
157
+ the ``then`` method of the response to take an action when the response has
158
+ completed or encounters an error.
159
+
160
+ .. code-block:: php
161
+
162
+ $response = $client->put('http://httpbin.org/get', ['future' => true]);
163
+
164
+ // Call the function when the response completes
165
+ $response->then(function ($response) {
166
+ echo $response->getStatusCode();
167
+ });
168
+
169
+ You can call the ``wait()`` method of a future response to block until it has
170
+ completed. You also use a future response object just like a normal response
171
+ object by accessing the methods of the response. Using a future response like a
172
+ normal response object, also known as *dereferencing*, will block until the
173
+ response has completed.
174
+
175
+ .. code-block:: php
176
+
177
+ $response = $client->put('http://httpbin.org/get', ['future' => true]);
178
+
179
+ // Block until the response has completed
180
+ echo $response->getStatusCode();
181
+
182
+ .. important::
183
+
184
+ If an exception occurred while transferring the future response, then the
185
+ exception encountered will be thrown when dereferencing.
186
+
187
+ .. note::
188
+
189
+ It depends on the RingPHP handler used by a client, but you typically need
190
+ to use the same RingPHP handler in order to utilize asynchronous requests
191
+ across multiple clients.
192
+
193
+ Asynchronous Error Handling
194
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
195
+
196
+ Handling errors with future response object promises is a bit different. When
197
+ using a promise, exceptions are forwarded to the ``$onError`` function provided
198
+ to the second argument of the ``then()`` function.
199
+
200
+ .. code-block:: php
201
+
202
+ $response = $client->put('http://httpbin.org/get', ['future' => true]);
203
+
204
+ $response
205
+ ->then(
206
+ function ($response) {
207
+ // This is called when the request succeeded
208
+ echo 'Success: ' . $response->getStatusCode();
209
+ // Returning a value will forward the value to the next promise
210
+ // in the chain.
211
+ return $response;
212
+ },
213
+ function ($error) {
214
+ // This is called when the exception failed.
215
+ echo 'Exception: ' . $error->getMessage();
216
+ // Throwing will "forward" the exception to the next promise
217
+ // in the chain.
218
+ throw $error;
219
+ }
220
+ )
221
+ ->then(
222
+ function($response) {
223
+ // This is called after the first promise in the chain. It
224
+ // receives the value returned from the first promise.
225
+ echo $response->getReasonPhrase();
226
+ },
227
+ function ($error) {
228
+ // This is called if the first promise error handler in the
229
+ // chain rethrows the exception.
230
+ echo 'Error: ' . $error->getMessage();
231
+ }
232
+ );
233
+
234
+ Please see the `React/Promises project documentation <https://github.com/reactphp/promise>`_
235
+ for more information on how promise resolution and rejection forwarding works.
236
+
237
+ HTTP Errors
238
+ -----------
239
+
240
+ If the ``exceptions`` request option is not set to ``false``, then exceptions
241
+ are thrown for HTTP protocol errors as well:
242
+ ``GuzzleHttp\Exception\ClientErrorResponseException`` for 4xx level HTTP
243
+ responses and ``GuzzleHttp\Exception\ServerException`` for 5xx level responses,
244
+ both of which extend from ``GuzzleHttp\Exception\BadResponseException``.
245
+
246
+ Creating Requests
247
+ -----------------
248
+
249
+ You can create a request without sending it. This is useful for building up
250
+ requests over time or sending requests in concurrently.
251
+
252
+ .. code-block:: php
253
+
254
+ $request = $client->createRequest('GET', 'http://httpbin.org', [
255
+ 'headers' => ['X-Foo' => 'Bar']
256
+ ]);
257
+
258
+ // Modify the request as needed
259
+ $request->setHeader('Baz', 'bar');
260
+
261
+ After creating a request, you can send it with the client's ``send()`` method.
262
+
263
+ .. code-block:: php
264
+
265
+ $response = $client->send($request);
266
+
267
+ Sending Requests With a Pool
268
+ ============================
269
+
270
+ You can send requests concurrently using a fixed size pool via the
271
+ ``GuzzleHttp\Pool`` class. The Pool class is an implementation of
272
+ ``GuzzleHttp\Ring\Future\FutureInterface``, meaning it can be dereferenced at a
273
+ later time or cancelled before sending. The Pool constructor accepts a client
274
+ object, iterator or array that yields ``GuzzleHttp\Message\RequestInterface``
275
+ objects, and an optional associative array of options that can be used to
276
+ affect the transfer.
277
+
278
+ .. code-block:: php
279
+
280
+ use GuzzleHttp\Pool;
281
+
282
+ $requests = [
283
+ $client->createRequest('GET', 'http://httpbin.org'),
284
+ $client->createRequest('DELETE', 'http://httpbin.org/delete'),
285
+ $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'test'])
286
+ ];
287
+
288
+ $options = [];
289
+
290
+ // Create a pool. Note: the options array is optional.
291
+ $pool = new Pool($client, $requests, $options);
292
+
293
+ // Send the requests
294
+ $pool->wait();
295
+
296
+ The Pool constructor accepts the following associative array of options:
297
+
298
+ - **pool_size**: Integer representing the maximum number of requests that are
299
+ allowed to be sent concurrently.
300
+ - **before**: Callable or array representing the event listeners to add to
301
+ each request's :ref:`before_event` event.
302
+ - **complete**: Callable or array representing the event listeners to add to
303
+ each request's :ref:`complete_event` event.
304
+ - **error**: Callable or array representing the event listeners to add to
305
+ each request's :ref:`error_event` event.
306
+ - **end**: Callable or array representing the event listeners to add to
307
+ each request's :ref:`end_event` event.
308
+
309
+ The "before", "complete", "error", and "end" event options accept a callable or
310
+ an array of associative arrays where each associative array contains a "fn" key
311
+ with a callable value, an optional "priority" key representing the event
312
+ priority (with a default value of 0), and an optional "once" key that can be
313
+ set to true so that the event listener will be removed from the request after
314
+ it is first triggered.
315
+
316
+ .. code-block:: php
317
+
318
+ use GuzzleHttp\Pool;
319
+ use GuzzleHttp\Event\CompleteEvent;
320
+
321
+ // Add a single event listener using a callable.
322
+ Pool::send($client, $requests, [
323
+ 'complete' => function (CompleteEvent $event) {
324
+ echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n";
325
+ echo 'Response: ' . $event->getResponse()->getBody() . "\n\n";
326
+ }
327
+ ]);
328
+
329
+ // The above is equivalent to the following, but the following structure
330
+ // allows you to add multiple event listeners to the same event name.
331
+ Pool::send($client, $requests, [
332
+ 'complete' => [
333
+ [
334
+ 'fn' => function (CompleteEvent $event) { /* ... */ },
335
+ 'priority' => 0, // Optional
336
+ 'once' => false // Optional
337
+ ]
338
+ ]
339
+ ]);
340
+
341
+ Asynchronous Response Handling
342
+ ------------------------------
343
+
344
+ When sending requests concurrently using a pool, the request/response/error
345
+ lifecycle must be handled asynchronously. This means that you give the Pool
346
+ multiple requests and handle the response or errors that is associated with the
347
+ request using event callbacks.
348
+
349
+ .. code-block:: php
350
+
351
+ use GuzzleHttp\Pool;
352
+ use GuzzleHttp\Event\ErrorEvent;
353
+
354
+ Pool::send($client, $requests, [
355
+ 'complete' => function (CompleteEvent $event) {
356
+ echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n";
357
+ echo 'Response: ' . $event->getResponse()->getBody() . "\n\n";
358
+ // Do something with the completion of the request...
359
+ },
360
+ 'error' => function (ErrorEvent $event) {
361
+ echo 'Request failed: ' . $event->getRequest()->getUrl() . "\n";
362
+ echo $event->getException();
363
+ // Do something to handle the error...
364
+ }
365
+ ]);
366
+
367
+ The ``GuzzleHttp\Event\ErrorEvent`` event object is emitted when an error
368
+ occurs during a transfer. With this event, you have access to the request that
369
+ was sent, the response that was received (if one was received), access to
370
+ transfer statistics, and the ability to intercept the exception with a
371
+ different ``GuzzleHttp\Message\ResponseInterface`` object. See :doc:`events`
372
+ for more information.
373
+
374
+ Handling Errors After Transferring
375
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
376
+
377
+ It sometimes might be easier to handle all of the errors that occurred during a
378
+ transfer after all of the requests have been sent. Here we are adding each
379
+ failed request to an array that we can use to process errors later.
380
+
381
+ .. code-block:: php
382
+
383
+ use GuzzleHttp\Pool;
384
+ use GuzzleHttp\Event\ErrorEvent;
385
+
386
+ $errors = [];
387
+ Pool::send($client, $requests, [
388
+ 'error' => function (ErrorEvent $event) use (&$errors) {
389
+ $errors[] = $event;
390
+ }
391
+ ]);
392
+
393
+ foreach ($errors as $error) {
394
+ // Handle the error...
395
+ }
396
+
397
+ .. _batch-requests:
398
+
399
+ Batching Requests
400
+ -----------------
401
+
402
+ Sometimes you just want to send a few requests concurrently and then process
403
+ the results all at once after they've been sent. Guzzle provides a convenience
404
+ function ``GuzzleHttp\Pool::batch()`` that makes this very simple:
405
+
406
+ .. code-block:: php
407
+
408
+ use GuzzleHttp\Pool;
409
+ use GuzzleHttp\Client;
410
+
411
+ $client = new Client();
412
+
413
+ $requests = [
414
+ $client->createRequest('GET', 'http://httpbin.org/get'),
415
+ $client->createRequest('HEAD', 'http://httpbin.org/get'),
416
+ $client->createRequest('PUT', 'http://httpbin.org/put'),
417
+ ];
418
+
419
+ // Results is a GuzzleHttp\BatchResults object.
420
+ $results = Pool::batch($client, $requests);
421
+
422
+ // Can be accessed by index.
423
+ echo $results[0]->getStatusCode();
424
+
425
+ // Can be accessed by request.
426
+ echo $results->getResult($requests[0])->getStatusCode();
427
+
428
+ // Retrieve all successful responses
429
+ foreach ($results->getSuccessful() as $response) {
430
+ echo $response->getStatusCode() . "\n";
431
+ }
432
+
433
+ // Retrieve all failures.
434
+ foreach ($results->getFailures() as $requestException) {
435
+ echo $requestException->getMessage() . "\n";
436
+ }
437
+
438
+ ``GuzzleHttp\Pool::batch()`` accepts an optional associative array of options
439
+ in the third argument that allows you to specify the 'before', 'complete',
440
+ 'error', and 'end' events as well as specify the maximum number of requests to
441
+ send concurrently using the 'pool_size' option key.
442
+
443
+ .. _request-options:
444
+
445
+ Request Options
446
+ ===============
447
+
448
+ You can customize requests created by a client using **request options**.
449
+ Request options control various aspects of a request including, headers,
450
+ query string parameters, timeout settings, the body of a request, and much
451
+ more.
452
+
453
+ All of the following examples use the following client:
454
+
455
+ .. code-block:: php
456
+
457
+ $client = new GuzzleHttp\Client(['base_url' => 'http://httpbin.org']);
458
+
459
+ headers
460
+ -------
461
+
462
+ :Summary: Associative array of headers to add to the request. Each key is the
463
+ name of a header, and each value is a string or array of strings
464
+ representing the header field values.
465
+ :Types: array
466
+ :Defaults: None
467
+
468
+ .. code-block:: php
469
+
470
+ // Set various headers on a request
471
+ $client->get('/get', [
472
+ 'headers' => [
473
+ 'User-Agent' => 'testing/1.0',
474
+ 'Accept' => 'application/json',
475
+ 'X-Foo' => ['Bar', 'Baz']
476
+ ]
477
+ ]);
478
+
479
+ body
480
+ ----
481
+
482
+ :Summary: The ``body`` option is used to control the body of an entity
483
+ enclosing request (e.g., PUT, POST, PATCH).
484
+ :Types:
485
+ - string
486
+ - ``fopen()`` resource
487
+ - ``GuzzleHttp\Stream\StreamInterface``
488
+ - ``GuzzleHttp\Post\PostBodyInterface``
489
+ :Default: None
490
+
491
+ This setting can be set to any of the following types:
492
+
493
+ - string
494
+
495
+ .. code-block:: php
496
+
497
+ // You can send requests that use a string as the message body.
498
+ $client->put('/put', ['body' => 'foo']);
499
+
500
+ - resource returned from ``fopen()``
501
+
502
+ .. code-block:: php
503
+
504
+ // You can send requests that use a stream resource as the body.
505
+ $resource = fopen('http://httpbin.org', 'r');
506
+ $client->put('/put', ['body' => $resource]);
507
+
508
+ - Array
509
+
510
+ Use an array to send POST style requests that use a
511
+ ``GuzzleHttp\Post\PostBodyInterface`` object as the body.
512
+
513
+ .. code-block:: php
514
+
515
+ // You can send requests that use a POST body containing fields & files.
516
+ $client->post('/post', [
517
+ 'body' => [
518
+ 'field' => 'abc',
519
+ 'other_field' => '123',
520
+ 'file_name' => fopen('/path/to/file', 'r')
521
+ ]
522
+ ]);
523
+
524
+ - ``GuzzleHttp\Stream\StreamInterface``
525
+
526
+ .. code-block:: php
527
+
528
+ // You can send requests that use a Guzzle stream object as the body
529
+ $stream = GuzzleHttp\Stream\Stream::factory('contents...');
530
+ $client->post('/post', ['body' => $stream]);
531
+
532
+ json
533
+ ----
534
+
535
+ :Summary: The ``json`` option is used to easily upload JSON encoded data as the
536
+ body of a request. A Content-Type header of ``application/json`` will be
537
+ added if no Content-Type header is already present on the message.
538
+ :Types:
539
+ Any PHP type that can be operated on by PHP's ``json_encode()`` function.
540
+ :Default: None
541
+
542
+ .. code-block:: php
543
+
544
+ $request = $client->createRequest('PUT', '/put', ['json' => ['foo' => 'bar']]);
545
+ echo $request->getHeader('Content-Type');
546
+ // application/json
547
+ echo $request->getBody();
548
+ // {"foo":"bar"}
549
+
550
+ .. note::
551
+
552
+ This request option does not support customizing the Content-Type header
553
+ or any of the options from PHP's `json_encode() <http://www.php.net/manual/en/function.json-encode.php>`_
554
+ function. If you need to customize these settings, then you must pass the
555
+ JSON encoded data into the request yourself using the ``body`` request
556
+ option and you must specify the correct Content-Type header using the
557
+ ``headers`` request option.
558
+
559
+ query
560
+ -----
561
+
562
+ :Summary: Associative array of query string values to add to the request.
563
+ :Types:
564
+ - array
565
+ - ``GuzzleHttp\Query``
566
+ :Default: None
567
+
568
+ .. code-block:: php
569
+
570
+ // Send a GET request to /get?foo=bar
571
+ $client->get('/get', ['query' => ['foo' => 'bar']]);
572
+
573
+ Query strings specified in the ``query`` option are combined with any query
574
+ string values that are parsed from the URL.
575
+
576
+ .. code-block:: php
577
+
578
+ // Send a GET request to /get?abc=123&foo=bar
579
+ $client->get('/get?abc=123', ['query' => ['foo' => 'bar']]);
580
+
581
+ auth
582
+ ----
583
+
584
+ :Summary: Pass an array of HTTP authentication parameters to use with the
585
+ request. The array must contain the username in index [0], the password in
586
+ index [1], and you can optionally provide a built-in authentication type in
587
+ index [2]. Pass ``null`` to disable authentication for a request.
588
+ :Types:
589
+ - array
590
+ - string
591
+ - null
592
+ :Default: None
593
+
594
+ The built-in authentication types are as follows:
595
+
596
+ basic
597
+ Use `basic HTTP authentication <http://www.ietf.org/rfc/rfc2069.txt>`_ in
598
+ the ``Authorization`` header (the default setting used if none is
599
+ specified).
600
+
601
+ .. code-block:: php
602
+
603
+ $client->get('/get', ['auth' => ['username', 'password']]);
604
+
605
+ digest
606
+ Use `digest authentication <http://www.ietf.org/rfc/rfc2069.txt>`_ (must be
607
+ supported by the HTTP handler).
608
+
609
+ .. code-block:: php
610
+
611
+ $client->get('/get', ['auth' => ['username', 'password', 'digest']]);
612
+
613
+ *This is currently only supported when using the cURL handler, but creating
614
+ a replacement that can be used with any HTTP handler is planned.*
615
+
616
+ .. important::
617
+
618
+ The authentication type (whether it's provided as a string or as the third
619
+ option in an array) is always converted to a lowercase string. Take this
620
+ into account when implementing custom authentication types and when
621
+ implementing custom message factories.
622
+
623
+ Custom Authentication Schemes
624
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
625
+
626
+ You can also provide a string representing a custom authentication type name.
627
+ When using a custom authentication type string, you will need to implement
628
+ the authentication method in an event listener that checks the ``auth`` request
629
+ option of a request before it is sent. Authentication listeners that require
630
+ a request is not modified after they are signed should have a very low priority
631
+ to ensure that they are fired last or near last in the event chain.
632
+
633
+ .. code-block:: php
634
+
635
+ use GuzzleHttp\Event\BeforeEvent;
636
+ use GuzzleHttp\Event\RequestEvents;
637
+
638
+ /**
639
+ * Custom authentication listener that handles the "foo" auth type.
640
+ *
641
+ * Listens to the "before" event of a request and only modifies the request
642
+ * when the "auth" config setting of the request is "foo".
643
+ */
644
+ class FooAuth implements GuzzleHttp\Event\SubscriberInterface
645
+ {
646
+ private $password;
647
+
648
+ public function __construct($password)
649
+ {
650
+ $this->password = $password;
651
+ }
652
+
653
+ public function getEvents()
654
+ {
655
+ return ['before' => ['sign', RequestEvents::SIGN_REQUEST]];
656
+ }
657
+
658
+ public function sign(BeforeEvent $e)
659
+ {
660
+ if ($e->getRequest()->getConfig()['auth'] == 'foo') {
661
+ $e->getRequest()->setHeader('X-Foo', 'Foo ' . $this->password);
662
+ }
663
+ }
664
+ }
665
+
666
+ $client->getEmitter()->attach(new FooAuth('password'));
667
+ $client->get('/', ['auth' => 'foo']);
668
+
669
+ Adapter Specific Authentication Schemes
670
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
671
+
672
+ If you need to use authentication methods provided by cURL (e.g., NTLM, GSS,
673
+ etc.), then you need to specify a curl handler option in the ``options``
674
+ request option array. See :ref:`config-option` for more information.
675
+
676
+ .. _cookies-option:
677
+
678
+ cookies
679
+ -------
680
+
681
+ :Summary: Specifies whether or not cookies are used in a request or what cookie
682
+ jar to use or what cookies to send.
683
+ :Types:
684
+ - bool
685
+ - array
686
+ - ``GuzzleHttp\Cookie\CookieJarInterface``
687
+ :Default: None
688
+
689
+ Set to ``true`` to use a shared cookie session associated with the client.
690
+
691
+ .. code-block:: php
692
+
693
+ // Enable cookies using the shared cookie jar of the client.
694
+ $client->get('/get', ['cookies' => true]);
695
+
696
+ Pass an associative array containing cookies to send in the request and start a
697
+ new cookie session.
698
+
699
+ .. code-block:: php
700
+
701
+ // Enable cookies and send specific cookies
702
+ $client->get('/get', ['cookies' => ['foo' => 'bar']]);
703
+
704
+ Set to a ``GuzzleHttp\Cookie\CookieJarInterface`` object to use an existing
705
+ cookie jar.
706
+
707
+ .. code-block:: php
708
+
709
+ $jar = new GuzzleHttp\Cookie\CookieJar();
710
+ $client->get('/get', ['cookies' => $jar]);
711
+
712
+ .. _allow_redirects-option:
713
+
714
+ allow_redirects
715
+ ---------------
716
+
717
+ :Summary: Describes the redirect behavior of a request
718
+ :Types:
719
+ - bool
720
+ - array
721
+ :Default:
722
+ ::
723
+
724
+ [
725
+ 'max' => 5,
726
+ 'strict' => false,
727
+ 'referer' => true,
728
+ 'protocols' => ['http', 'https']
729
+ ]
730
+
731
+ Set to ``false`` to disable redirects.
732
+
733
+ .. code-block:: php
734
+
735
+ $res = $client->get('/redirect/3', ['allow_redirects' => false]);
736
+ echo $res->getStatusCode();
737
+ // 302
738
+
739
+ Set to ``true`` (the default setting) to enable normal redirects with a maximum
740
+ number of 5 redirects.
741
+
742
+ .. code-block:: php
743
+
744
+ $res = $client->get('/redirect/3');
745
+ echo $res->getStatusCode();
746
+ // 200
747
+
748
+ Pass an associative array containing the 'max' key to specify the maximum
749
+ number of redirects, provide a 'strict' key value to specify whether or not to
750
+ use strict RFC compliant redirects (meaning redirect POST requests with POST
751
+ requests vs. doing what most browsers do which is redirect POST requests with
752
+ GET requests), provide a 'referer' key to specify whether or not the "Referer"
753
+ header should be added when redirecting, and provide a 'protocols' array that
754
+ specifies which protocols are supported for redirects (defaults to
755
+ ``['http', 'https']``).
756
+
757
+ .. code-block:: php
758
+
759
+ $res = $client->get('/redirect/3', [
760
+ 'allow_redirects' => [
761
+ 'max' => 10, // allow at most 10 redirects.
762
+ 'strict' => true, // use "strict" RFC compliant redirects.
763
+ 'referer' => true, // add a Referer header
764
+ 'protocols' => ['https'] // only allow https URLs
765
+ ]
766
+ ]);
767
+ echo $res->getStatusCode();
768
+ // 200
769
+
770
+ decode_content
771
+ --------------
772
+
773
+ :Summary: Specify whether or not ``Content-Encoding`` responses (gzip,
774
+ deflate, etc.) are automatically decoded.
775
+ :Types:
776
+ - string
777
+ - bool
778
+ :Default: ``true``
779
+
780
+ This option can be used to control how content-encoded response bodies are
781
+ handled. By default, ``decode_content`` is set to true, meaning any gzipped
782
+ or deflated response will be decoded by Guzzle.
783
+
784
+ When set to ``false``, the body of a response is never decoded, meaning the
785
+ bytes pass through the handler unchanged.
786
+
787
+ .. code-block:: php
788
+
789
+ // Request gzipped data, but do not decode it while downloading
790
+ $client->get('/foo.js', [
791
+ 'headers' => ['Accept-Encoding' => 'gzip'],
792
+ 'decode_content' => false
793
+ ]);
794
+
795
+ When set to a string, the bytes of a response are decoded and the string value
796
+ provided to the ``decode_content`` option is passed as the ``Accept-Encoding``
797
+ header of the request.
798
+
799
+ .. code-block:: php
800
+
801
+ // Pass "gzip" as the Accept-Encoding header.
802
+ $client->get('/foo.js', ['decode_content' => 'gzip']);
803
+
804
+ .. _save_to-option:
805
+
806
+ save_to
807
+ -------
808
+
809
+ :Summary: Specify where the body of a response will be saved.
810
+ :Types:
811
+ - string
812
+ - ``fopen()`` resource
813
+ - ``GuzzleHttp\Stream\StreamInterface``
814
+ :Default: PHP temp stream
815
+
816
+ Pass a string to specify the path to a file that will store the contents of the
817
+ response body:
818
+
819
+ .. code-block:: php
820
+
821
+ $client->get('/stream/20', ['save_to' => '/path/to/file']);
822
+
823
+ Pass a resource returned from ``fopen()`` to write the response to a PHP stream:
824
+
825
+ .. code-block:: php
826
+
827
+ $resource = fopen('/path/to/file', 'w');
828
+ $client->get('/stream/20', ['save_to' => $resource]);
829
+
830
+ Pass a ``GuzzleHttp\Stream\StreamInterface`` object to stream the response body
831
+ to an open Guzzle stream:
832
+
833
+ .. code-block:: php
834
+
835
+ $resource = fopen('/path/to/file', 'w');
836
+ $stream = GuzzleHttp\Stream\Stream::factory($resource);
837
+ $client->get('/stream/20', ['save_to' => $stream]);
838
+
839
+ .. _events-option:
840
+
841
+ events
842
+ ------
843
+
844
+ :Summary: An associative array mapping event names to a callable. Or an
845
+ associative array containing the 'fn' key that maps to a callable, an
846
+ optional 'priority' key used to specify the event priority, and an optional
847
+ 'once' key used to specify if the event should remove itself the first time
848
+ it is triggered.
849
+ :Types: array
850
+ :Default: None
851
+
852
+ .. code-block:: php
853
+
854
+ use GuzzleHttp\Event\BeforeEvent;
855
+ use GuzzleHttp\Event\HeadersEvent;
856
+ use GuzzleHttp\Event\CompleteEvent;
857
+ use GuzzleHttp\Event\ErrorEvent;
858
+
859
+ $client->get('/', [
860
+ 'events' => [
861
+ 'before' => function (BeforeEvent $e) { echo 'Before'; },
862
+ 'complete' => function (CompleteEvent $e) { echo 'Complete'; },
863
+ 'error' => function (ErrorEvent $e) { echo 'Error'; },
864
+ ]
865
+ ]);
866
+
867
+ Here's an example of using the associative array format for control over the
868
+ priority and whether or not an event should be triggered more than once.
869
+
870
+ .. code-block:: php
871
+
872
+ $client->get('/', [
873
+ 'events' => [
874
+ 'before' => [
875
+ 'fn' => function (BeforeEvent $e) { echo 'Before'; },
876
+ 'priority' => 100,
877
+ 'once' => true
878
+ ]
879
+ ]
880
+ ]);
881
+
882
+ .. _subscribers-option:
883
+
884
+ subscribers
885
+ -----------
886
+
887
+ :Summary: Array of event subscribers to add to the request. Each value in the
888
+ array must be an instance of ``GuzzleHttp\Event\SubscriberInterface``.
889
+ :Types: array
890
+ :Default: None
891
+
892
+ .. code-block:: php
893
+
894
+ use GuzzleHttp\Subscriber\History;
895
+ use GuzzleHttp\Subscriber\Mock;
896
+ use GuzzleHttp\Message\Response;
897
+
898
+ $history = new History();
899
+ $mock = new Mock([new Response(200)]);
900
+ $client->get('/', ['subscribers' => [$history, $mock]]);
901
+
902
+ echo $history;
903
+ // Outputs the request and response history
904
+
905
+ .. _exceptions-option:
906
+
907
+ exceptions
908
+ ----------
909
+
910
+ :Summary: Set to ``false`` to disable throwing exceptions on an HTTP protocol
911
+ errors (i.e., 4xx and 5xx responses). Exceptions are thrown by default when
912
+ HTTP protocol errors are encountered.
913
+ :Types: bool
914
+ :Default: ``true``
915
+
916
+ .. code-block:: php
917
+
918
+ $client->get('/status/500');
919
+ // Throws a GuzzleHttp\Exception\ServerException
920
+
921
+ $res = $client->get('/status/500', ['exceptions' => false]);
922
+ echo $res->getStatusCode();
923
+ // 500
924
+
925
+ .. _timeout-option:
926
+
927
+ timeout
928
+ -------
929
+
930
+ :Summary: Float describing the timeout of the request in seconds. Use ``0``
931
+ to wait indefinitely (the default behavior).
932
+ :Types: float
933
+ :Default: ``0``
934
+
935
+ .. code-block:: php
936
+
937
+ // Timeout if a server does not return a response in 3.14 seconds.
938
+ $client->get('/delay/5', ['timeout' => 3.14]);
939
+ // PHP Fatal error: Uncaught exception 'GuzzleHttp\Exception\RequestException'
940
+
941
+ .. _connect_timeout-option:
942
+
943
+ connect_timeout
944
+ ---------------
945
+
946
+ :Summary: Float describing the number of seconds to wait while trying to connect
947
+ to a server. Use ``0`` to wait indefinitely (the default behavior).
948
+ :Types: float
949
+ :Default: ``0``
950
+
951
+ .. code-block:: php
952
+
953
+ // Timeout if the client fails to connect to the server in 3.14 seconds.
954
+ $client->get('/delay/5', ['connect_timeout' => 3.14]);
955
+
956
+ .. note::
957
+
958
+ This setting must be supported by the HTTP handler used to send a request.
959
+ ``connect_timeout`` is currently only supported by the built-in cURL
960
+ handler.
961
+
962
+ .. _verify-option:
963
+
964
+ verify
965
+ ------
966
+
967
+ :Summary: Describes the SSL certificate verification behavior of a request.
968
+
969
+ - Set to ``true`` to enable SSL certificate verification and use the default
970
+ CA bundle provided by operating system.
971
+ - Set to ``false`` to disable certificate verification (this is insecure!).
972
+ - Set to a string to provide the path to a CA bundle to enable verification
973
+ using a custom certificate.
974
+ :Types:
975
+ - bool
976
+ - string
977
+ :Default: ``true``
978
+
979
+ .. code-block:: php
980
+
981
+ // Use the system's CA bundle (this is the default setting)
982
+ $client->get('/', ['verify' => true]);
983
+
984
+ // Use a custom SSL certificate on disk.
985
+ $client->get('/', ['verify' => '/path/to/cert.pem']);
986
+
987
+ // Disable validation entirely (don't do this!).
988
+ $client->get('/', ['verify' => false]);
989
+
990
+ Not all system's have a known CA bundle on disk. For example, Windows and
991
+ OS X do not have a single common location for CA bundles. When setting
992
+ "verify" to ``true``, Guzzle will do its best to find the most appropriate
993
+ CA bundle on your system. When using cURL or the PHP stream wrapper on PHP
994
+ versions >= 5.6, this happens by default. When using the PHP stream
995
+ wrapper on versions < 5.6, Guzzle tries to find your CA bundle in the
996
+ following order:
997
+
998
+ 1. Check if ``openssl.cafile`` is set in your php.ini file.
999
+ 2. Check if ``curl.cainfo`` is set in your php.ini file.
1000
+ 3. Check if ``/etc/pki/tls/certs/ca-bundle.crt`` exists (Red Hat, CentOS,
1001
+ Fedora; provided by the ca-certificates package)
1002
+ 4. Check if ``/etc/ssl/certs/ca-certificates.crt`` exists (Ubuntu, Debian;
1003
+ provided by the ca-certificates package)
1004
+ 5. Check if ``/usr/local/share/certs/ca-root-nss.crt`` exists (FreeBSD;
1005
+ provided by the ca_root_nss package)
1006
+ 6. Check if ``/usr/local/etc/openssl/cert.pem`` (OS X; provided by homebrew)
1007
+ 7. Check if ``C:\windows\system32\curl-ca-bundle.crt`` exists (Windows)
1008
+ 8. Check if ``C:\windows\curl-ca-bundle.crt`` exists (Windows)
1009
+
1010
+ The result of this lookup is cached in memory so that subsequent calls
1011
+ in the same process will return very quickly. However, when sending only
1012
+ a single request per-process in something like Apache, you should consider
1013
+ setting the ``openssl.cafile`` environment variable to the path on disk
1014
+ to the file so that this entire process is skipped.
1015
+
1016
+ If you do not need a specific certificate bundle, then Mozilla provides a
1017
+ commonly used CA bundle which can be downloaded
1018
+ `here <https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt>`_
1019
+ (provided by the maintainer of cURL). Once you have a CA bundle available on
1020
+ disk, you can set the "openssl.cafile" PHP ini setting to point to the path to
1021
+ the file, allowing you to omit the "verify" request option. Much more detail on
1022
+ SSL certificates can be found on the
1023
+ `cURL website <http://curl.haxx.se/docs/sslcerts.html>`_.
1024
+
1025
+ .. _cert-option:
1026
+
1027
+ cert
1028
+ ----
1029
+
1030
+ :Summary: Set to a string to specify the path to a file containing a PEM
1031
+ formatted client side certificate. If a password is required, then set to
1032
+ an array containing the path to the PEM file in the first array element
1033
+ followed by the password required for the certificate in the second array
1034
+ element.
1035
+ :Types:
1036
+ - string
1037
+ - array
1038
+ :Default: None
1039
+
1040
+ .. code-block:: php
1041
+
1042
+ $client->get('/', ['cert' => ['/path/server.pem', 'password']]);
1043
+
1044
+ .. _ssl_key-option:
1045
+
1046
+ ssl_key
1047
+ -------
1048
+
1049
+ :Summary: Specify the path to a file containing a private SSL key in PEM
1050
+ format. If a password is required, then set to an array containing the path
1051
+ to the SSL key in the first array element followed by the password required
1052
+ for the certificate in the second element.
1053
+ :Types:
1054
+ - string
1055
+ - array
1056
+ :Default: None
1057
+
1058
+ .. note::
1059
+
1060
+ ``ssl_key`` is implemented by HTTP handlers. This is currently only
1061
+ supported by the cURL handler, but might be supported by other third-part
1062
+ handlers.
1063
+
1064
+ .. _proxy-option:
1065
+
1066
+ proxy
1067
+ -----
1068
+
1069
+ :Summary: Pass a string to specify an HTTP proxy, or an array to specify
1070
+ different proxies for different protocols.
1071
+ :Types:
1072
+ - string
1073
+ - array
1074
+ :Default: None
1075
+
1076
+ Pass a string to specify a proxy for all protocols.
1077
+
1078
+ .. code-block:: php
1079
+
1080
+ $client->get('/', ['proxy' => 'tcp://localhost:8125']);
1081
+
1082
+ Pass an associative array to specify HTTP proxies for specific URI schemes
1083
+ (i.e., "http", "https").
1084
+
1085
+ .. code-block:: php
1086
+
1087
+ $client->get('/', [
1088
+ 'proxy' => [
1089
+ 'http' => 'tcp://localhost:8125', // Use this proxy with "http"
1090
+ 'https' => 'tcp://localhost:9124' // Use this proxy with "https"
1091
+ ]
1092
+ ]);
1093
+
1094
+ .. note::
1095
+
1096
+ You can provide proxy URLs that contain a scheme, username, and password.
1097
+ For example, ``"http://username:password@192.168.16.1:10"``.
1098
+
1099
+ .. _debug-option:
1100
+
1101
+ debug
1102
+ -----
1103
+
1104
+ :Summary: Set to ``true`` or set to a PHP stream returned by ``fopen()`` to
1105
+ enable debug output with the handler used to send a request. For example,
1106
+ when using cURL to transfer requests, cURL's verbose of ``CURLOPT_VERBOSE``
1107
+ will be emitted. When using the PHP stream wrapper, stream wrapper
1108
+ notifications will be emitted. If set to true, the output is written to
1109
+ PHP's STDOUT. If a PHP stream is provided, output is written to the stream.
1110
+ :Types:
1111
+ - bool
1112
+ - ``fopen()`` resource
1113
+ :Default: None
1114
+
1115
+ .. code-block:: php
1116
+
1117
+ $client->get('/get', ['debug' => true]);
1118
+
1119
+ Running the above example would output something like the following:
1120
+
1121
+ ::
1122
+
1123
+ * About to connect() to httpbin.org port 80 (#0)
1124
+ * Trying 107.21.213.98... * Connected to httpbin.org (107.21.213.98) port 80 (#0)
1125
+ > GET /get HTTP/1.1
1126
+ Host: httpbin.org
1127
+ User-Agent: Guzzle/4.0 curl/7.21.4 PHP/5.5.7
1128
+
1129
+ < HTTP/1.1 200 OK
1130
+ < Access-Control-Allow-Origin: *
1131
+ < Content-Type: application/json
1132
+ < Date: Sun, 16 Feb 2014 06:50:09 GMT
1133
+ < Server: gunicorn/0.17.4
1134
+ < Content-Length: 335
1135
+ < Connection: keep-alive
1136
+ <
1137
+ * Connection #0 to host httpbin.org left intact
1138
+
1139
+ .. _stream-option:
1140
+
1141
+ stream
1142
+ ------
1143
+
1144
+ :Summary: Set to ``true`` to stream a response rather than download it all
1145
+ up-front.
1146
+ :Types: bool
1147
+ :Default: ``false``
1148
+
1149
+ .. code-block:: php
1150
+
1151
+ $response = $client->get('/stream/20', ['stream' => true]);
1152
+ // Read bytes off of the stream until the end of the stream is reached
1153
+ $body = $response->getBody();
1154
+ while (!$body->eof()) {
1155
+ echo $body->read(1024);
1156
+ }
1157
+
1158
+ .. note::
1159
+
1160
+ Streaming response support must be implemented by the HTTP handler used by
1161
+ a client. This option might not be supported by every HTTP handler, but the
1162
+ interface of the response object remains the same regardless of whether or
1163
+ not it is supported by the handler.
1164
+
1165
+ .. _expect-option:
1166
+
1167
+ expect
1168
+ ------
1169
+
1170
+ :Summary: Controls the behavior of the "Expect: 100-Continue" header.
1171
+ :Types:
1172
+ - bool
1173
+ - integer
1174
+ :Default: ``1048576``
1175
+
1176
+ Set to ``true`` to enable the "Expect: 100-Continue" header for all requests
1177
+ that sends a body. Set to ``false`` to disable the "Expect: 100-Continue"
1178
+ header for all requests. Set to a number so that the size of the payload must
1179
+ be greater than the number in order to send the Expect header. Setting to a
1180
+ number will send the Expect header for all requests in which the size of the
1181
+ payload cannot be determined or where the body is not rewindable.
1182
+
1183
+ By default, Guzzle will add the "Expect: 100-Continue" header when the size of
1184
+ the body of a request is greater than 1 MB and a request is using HTTP/1.1.
1185
+
1186
+ .. note::
1187
+
1188
+ This option only takes effect when using HTTP/1.1. The HTTP/1.0 and
1189
+ HTTP/2.0 protocols do not support the "Expect: 100-Continue" header.
1190
+ Support for handling the "Expect: 100-Continue" workflow must be
1191
+ implemented by Guzzle HTTP handlers used by a client.
1192
+
1193
+ .. _version-option:
1194
+
1195
+ version
1196
+ -------
1197
+
1198
+ :Summary: Protocol version to use with the request.
1199
+ :Types: string, float
1200
+ :Default: ``1.1``
1201
+
1202
+ .. code-block:: php
1203
+
1204
+ // Force HTTP/1.0
1205
+ $request = $client->createRequest('GET', '/get', ['version' => 1.0]);
1206
+ echo $request->getProtocolVersion();
1207
+ // 1.0
1208
+
1209
+ .. _config-option:
1210
+
1211
+ config
1212
+ ------
1213
+
1214
+ :Summary: Associative array of config options that are forwarded to a request's
1215
+ configuration collection. These values are used as configuration options
1216
+ that can be consumed by plugins and handlers.
1217
+ :Types: array
1218
+ :Default: None
1219
+
1220
+ .. code-block:: php
1221
+
1222
+ $request = $client->createRequest('GET', '/get', ['config' => ['foo' => 'bar']]);
1223
+ echo $request->getConfig('foo');
1224
+ // 'bar'
1225
+
1226
+ Some HTTP handlers allow you to specify custom handler-specific settings. For
1227
+ example, you can pass custom cURL options to requests by passing an associative
1228
+ array in the ``config`` request option under the ``curl`` key.
1229
+
1230
+ .. code-block:: php
1231
+
1232
+ // Use custom cURL options with the request. This example uses NTLM auth
1233
+ // to authenticate with a server.
1234
+ $client->get('/', [
1235
+ 'config' => [
1236
+ 'curl' => [
1237
+ CURLOPT_HTTPAUTH => CURLAUTH_NTLM,
1238
+ CURLOPT_USERPWD => 'username:password'
1239
+ ]
1240
+ ]
1241
+ ]);
1242
+
1243
+ future
1244
+ ------
1245
+
1246
+ :Summary: Specifies whether or not a response SHOULD be an instance of a
1247
+ ``GuzzleHttp\Message\FutureResponse`` object.
1248
+ :Types:
1249
+ - bool
1250
+ - string
1251
+ :Default: ``false``
1252
+
1253
+ By default, Guzzle requests should be synchronous. You can create asynchronous
1254
+ future responses by passing the ``future`` request option as ``true``. The
1255
+ response will only be executed when it is used like a normal response, the
1256
+ ``wait()`` method of the response is called, or the corresponding handler that
1257
+ created the response is destructing and there are futures that have not been
1258
+ resolved.
1259
+
1260
+ .. important::
1261
+
1262
+ This option only has an effect if your handler can create and return future
1263
+ responses. However, even if a response is completed synchronously, Guzzle
1264
+ will ensure that a FutureResponse object is returned for API consistency.
1265
+
1266
+ .. code-block:: php
1267
+
1268
+ $response = $client->get('/foo', ['future' => true])
1269
+ ->then(function ($response) {
1270
+ echo 'I got a response! ' . $response;
1271
+ });
1272
+
1273
+ Event Subscribers
1274
+ =================
1275
+
1276
+ Requests emit lifecycle events when they are transferred. A client object has a
1277
+ ``GuzzleHttp\Common\EventEmitter`` object that can be used to add event
1278
+ *listeners* and event *subscribers* to all requests created by the client.
1279
+
1280
+ .. important::
1281
+
1282
+ **Every** event listener or subscriber added to a client will be added to
1283
+ every request created by the client.
1284
+
1285
+ .. code-block:: php
1286
+
1287
+ use GuzzleHttp\Client;
1288
+ use GuzzleHttp\Event\BeforeEvent;
1289
+
1290
+ $client = new Client();
1291
+
1292
+ // Add a listener that will echo out requests before they are sent
1293
+ $client->getEmitter()->on('before', function (BeforeEvent $e) {
1294
+ echo 'About to send request: ' . $e->getRequest();
1295
+ });
1296
+
1297
+ $client->get('http://httpbin.org/get');
1298
+ // Outputs the request as a string because of the event
1299
+
1300
+ See :doc:`events` for more information on the event system used in Guzzle.
1301
+
1302
+ Environment Variables
1303
+ =====================
1304
+
1305
+ Guzzle exposes a few environment variables that can be used to customize the
1306
+ behavior of the library.
1307
+
1308
+ ``GUZZLE_CURL_SELECT_TIMEOUT``
1309
+ Controls the duration in seconds that a curl_multi_* handler will use when
1310
+ selecting on curl handles using ``curl_multi_select()``. Some systems
1311
+ have issues with PHP's implementation of ``curl_multi_select()`` where
1312
+ calling this function always results in waiting for the maximum duration of
1313
+ the timeout.
1314
+ ``HTTP_PROXY``
1315
+ Defines the proxy to use when sending requests using the "http" protocol.
1316
+ ``HTTPS_PROXY``
1317
+ Defines the proxy to use when sending requests using the "https" protocol.
1318
+
1319
+ Relevant ini Settings
1320
+ ---------------------
1321
+
1322
+ Guzzle can utilize PHP ini settings when configuring clients.
1323
+
1324
+ ``openssl.cafile``
1325
+ Specifies the path on disk to a CA file in PEM format to use when sending
1326
+ requests over "https". See: https://wiki.php.net/rfc/tls-peer-verification#phpini_defaults
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/conf.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys, os
2
+ from sphinx.highlighting import lexers
3
+ from pygments.lexers.web import PhpLexer
4
+
5
+
6
+ lexers['php'] = PhpLexer(startinline=True, linenos=1)
7
+ lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1)
8
+ primary_domain = 'php'
9
+
10
+ extensions = []
11
+ templates_path = ['_templates']
12
+ source_suffix = '.rst'
13
+ master_doc = 'index'
14
+ project = u'Guzzle'
15
+ copyright = u'2014, Michael Dowling'
16
+ version = '5.0.0'
17
+ html_title = "Guzzle Documentation"
18
+ html_short_title = "Guzzle"
19
+
20
+ exclude_patterns = ['_build']
21
+ html_static_path = ['_static']
22
+
23
+ on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
24
+
25
+ if not on_rtd: # only import and set the theme if we're building docs locally
26
+ import sphinx_rtd_theme
27
+ html_theme = 'sphinx_rtd_theme'
28
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/events.rst ADDED
@@ -0,0 +1,516 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ============
2
+ Event System
3
+ ============
4
+
5
+ Guzzle uses an event emitter to allow you to easily extend the behavior of a
6
+ request, change the response associated with a request, and implement custom
7
+ error handling. All events in Guzzle are managed and emitted by an
8
+ **event emitter**.
9
+
10
+ Event Emitters
11
+ ==============
12
+
13
+ Clients, requests, and any other class that implements the
14
+ ``GuzzleHttp\Event\HasEmitterInterface`` interface have a
15
+ ``GuzzleHttp\Event\Emitter`` object. You can add event *listeners* and
16
+ event *subscribers* to an event *emitter*.
17
+
18
+ emitter
19
+ An object that implements ``GuzzleHttp\Event\EmitterInterface``. This
20
+ object emits named events to event listeners. You may register event
21
+ listeners on subscribers on an emitter.
22
+
23
+ event listeners
24
+ Callable functions that are registered on an event emitter for specific
25
+ events. Event listeners are registered on an emitter with a *priority*
26
+ setting. If no priority is provided, ``0`` is used by default.
27
+
28
+ event subscribers
29
+ Classes that tell an event emitter what methods to listen to and what
30
+ functions on the class to invoke when the event is triggered. Event
31
+ subscribers subscribe event listeners to an event emitter. They should be
32
+ used when creating more complex event based logic in applications (i.e.,
33
+ cookie handling is implemented using an event subscriber because it's
34
+ easier to share a subscriber than an anonymous function and because
35
+ handling cookies is a complex process).
36
+
37
+ priority
38
+ Describes the order in which event listeners are invoked when an event is
39
+ emitted. The higher a priority value, the earlier the event listener will
40
+ be invoked (a higher priority means the listener is more important). If
41
+ no priority is provided, the priority is assumed to be ``0``.
42
+
43
+ When specifying an event priority, you can pass ``"first"`` or ``"last"`` to
44
+ dynamically specify the priority based on the current event priorities
45
+ associated with the given event name in the emitter. Use ``"first"`` to set
46
+ the priority to the current highest priority plus one. Use ``"last"`` to
47
+ set the priority to the current lowest event priority minus one. It is
48
+ important to remember that these dynamic priorities are calculated only at
49
+ the point of insertion into the emitter and they are not rearranged after
50
+ subsequent listeners are added to an emitter.
51
+
52
+ propagation
53
+ Describes whether or not other event listeners are triggered. Event
54
+ emitters will trigger every event listener registered to a specific event
55
+ in priority order until all of the listeners have been triggered **or**
56
+ until the propagation of an event is stopped.
57
+
58
+ Getting an EventEmitter
59
+ -----------------------
60
+
61
+ You can get the event emitter of ``GuzzleHttp\Event\HasEmitterInterface``
62
+ object using the the ``getEmitter()`` method. Here's an example of getting a
63
+ client object's event emitter.
64
+
65
+ .. code-block:: php
66
+
67
+ $client = new GuzzleHttp\Client();
68
+ $emitter = $client->getEmitter();
69
+
70
+ .. note::
71
+
72
+ You'll notice that the event emitter used in Guzzle is very similar to the
73
+ `Symfony2 EventDispatcher component <https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher>`_.
74
+ This is because the Guzzle event system is based on the Symfony2 event
75
+ system with several changes. Guzzle uses its own event emitter to improve
76
+ performance, isolate Guzzle from changes to the Symfony, and provide a few
77
+ improvements that make it easier to use for an HTTP client (e.g., the
78
+ addition of the ``once()`` method).
79
+
80
+ Adding Event Listeners
81
+ ----------------------
82
+
83
+ After you have the emitter, you can register event listeners that listen to
84
+ specific events using the ``on()`` method. When registering an event listener,
85
+ you must tell the emitter what event to listen to (e.g., "before", "after",
86
+ "progress", "complete", "error", etc.), what callable to invoke when the
87
+ event is triggered, and optionally provide a priority.
88
+
89
+ .. code-block:: php
90
+
91
+ use GuzzleHttp\Event\BeforeEvent;
92
+
93
+ $emitter->on('before', function (BeforeEvent $event) {
94
+ echo $event->getRequest();
95
+ });
96
+
97
+ When a listener is triggered, it is passed an event that implements the
98
+ ``GuzzleHttp\Event\EventInterface`` interface, the name of the event, and the
99
+ event emitter itself. The above example could more verbosely be written as
100
+ follows:
101
+
102
+ .. code-block:: php
103
+
104
+ use GuzzleHttp\Event\BeforeEvent;
105
+
106
+ $emitter->on('before', function (BeforeEvent $event, $name) {
107
+ echo $event->getRequest();
108
+ });
109
+
110
+ You can add an event listener that automatically removes itself after it is
111
+ triggered using the ``once()`` method of an event emitter.
112
+
113
+ .. code-block:: php
114
+
115
+ $client = new GuzzleHttp\Client();
116
+ $client->getEmitter()->once('before', function () {
117
+ echo 'This will only happen once... per request!';
118
+ });
119
+
120
+ Event Propagation
121
+ -----------------
122
+
123
+ Event listeners can prevent other event listeners from being triggered by
124
+ stopping an event's propagation.
125
+
126
+ Stopping event propagation can be useful, for example, if an event listener has
127
+ changed the state of the subject to such an extent that allowing subsequent
128
+ event listeners to be triggered could place the subject in an inconsistent
129
+ state. This technique is used in Guzzle extensively when intercepting error
130
+ events with responses.
131
+
132
+ You can stop the propagation of an event using the ``stopPropagation()`` method
133
+ of a ``GuzzleHttp\Event\EventInterface`` object:
134
+
135
+ .. code-block:: php
136
+
137
+ use GuzzleHttp\Event\ErrorEvent;
138
+
139
+ $emitter->on('error', function (ErrorEvent $event) {
140
+ $event->stopPropagation();
141
+ });
142
+
143
+ After stopping the propagation of an event, any subsequent event listeners that
144
+ have not yet been triggered will not be triggered. You can check to see if the
145
+ propagation of an event was stopped using the ``isPropagationStopped()`` method
146
+ of the event.
147
+
148
+ .. code-block:: php
149
+
150
+ $client = new GuzzleHttp\Client();
151
+ $emitter = $client->getEmitter();
152
+ // Note: assume that the $errorEvent was created
153
+ if ($emitter->emit('error', $errorEvent)->isPropagationStopped()) {
154
+ echo 'It was stopped!';
155
+ }
156
+
157
+ .. hint::
158
+
159
+ When emitting events, the event that was emitted is returned from the
160
+ emitter. This allows you to easily chain calls as shown in the above
161
+ example.
162
+
163
+ Event Subscribers
164
+ -----------------
165
+
166
+ Event subscribers are classes that implement the
167
+ ``GuzzleHttp\Event\SubscriberInterface`` object. They are used to register
168
+ one or more event listeners to methods of the class. Event subscribers tell
169
+ event emitters exactly which events to listen to and what method to invoke on
170
+ the class when the event is triggered by called the ``getEvents()`` method of
171
+ a subscriber.
172
+
173
+ The following example registers event listeners to the ``before`` and
174
+ ``complete`` event of a request. When the ``before`` event is emitted, the
175
+ ``onBefore`` instance method of the subscriber is invoked. When the
176
+ ``complete`` event is emitted, the ``onComplete`` event of the subscriber is
177
+ invoked. Each array value in the ``getEvents()`` return value MUST
178
+ contain the name of the method to invoke and can optionally contain the
179
+ priority of the listener (as shown in the ``before`` listener in the example).
180
+
181
+ .. code-block:: php
182
+
183
+ use GuzzleHttp\Event\EmitterInterface;
184
+ use GuzzleHttp\Event\SubscriberInterface;
185
+ use GuzzleHttp\Event\BeforeEvent;
186
+ use GuzzleHttp\Event\CompleteEvent;
187
+
188
+ class SimpleSubscriber implements SubscriberInterface
189
+ {
190
+ public function getEvents()
191
+ {
192
+ return [
193
+ // Provide name and optional priority
194
+ 'before' => ['onBefore', 100],
195
+ 'complete' => ['onComplete'],
196
+ // You can pass a list of listeners with different priorities
197
+ 'error' => [['beforeError', 'first'], ['afterError', 'last']]
198
+ ];
199
+ }
200
+
201
+ public function onBefore(BeforeEvent $event, $name)
202
+ {
203
+ echo 'Before!';
204
+ }
205
+
206
+ public function onComplete(CompleteEvent $event, $name)
207
+ {
208
+ echo 'Complete!';
209
+ }
210
+ }
211
+
212
+ To register the listeners the subscriber needs to be attached to the emitter:
213
+
214
+ .. code-block:: php
215
+
216
+ $client = new GuzzleHttp\Client();
217
+ $emitter = $client->getEmitter();
218
+ $subscriber = new SimpleSubscriber();
219
+ $emitter->attach($subscriber);
220
+
221
+ //to remove the listeners
222
+ $emitter->detach($subscriber);
223
+
224
+ .. note::
225
+
226
+ You can specify event priorities using integers or ``"first"`` and
227
+ ``"last"`` to dynamically determine the priority.
228
+
229
+ Event Priorities
230
+ ================
231
+
232
+ When adding event listeners or subscribers, you can provide an optional event
233
+ priority. This priority is used to determine how early or late a listener is
234
+ triggered. Specifying the correct priority is an important aspect of ensuring
235
+ a listener behaves as expected. For example, if you wanted to ensure that
236
+ cookies associated with a redirect were added to a cookie jar, you'd need to
237
+ make sure that the listener that collects the cookies is triggered before the
238
+ listener that performs the redirect.
239
+
240
+ In order to help make the process of determining the correct event priority of
241
+ a listener easier, Guzzle provides several pre-determined named event
242
+ priorities. These priorities are exposed as constants on the
243
+ ``GuzzleHttp\Event\RequestEvents`` object.
244
+
245
+ last
246
+ Use ``"last"`` as an event priority to set the priority to the current
247
+ lowest event priority minus one.
248
+
249
+ first
250
+ Use ``"first"`` as an event priority to set the priority to the current
251
+ highest priority plus one.
252
+
253
+ ``GuzzleHttp\Event\RequestEvents::EARLY``
254
+ Used when you want a listener to be triggered as early as possible in the
255
+ event chain.
256
+
257
+ ``GuzzleHttp\Event\RequestEvents::LATE``
258
+ Used when you want a listener to be to be triggered as late as possible in
259
+ the event chain.
260
+
261
+ ``GuzzleHttp\Event\RequestEvents::PREPARE_REQUEST``
262
+ Used when you want a listener to be trigger while a request is being
263
+ prepared during the ``before`` event. This event priority is used by the
264
+ ``GuzzleHttp\Subscriber\Prepare`` event subscriber which is responsible for
265
+ guessing a Content-Type, Content-Length, and Expect header of a request.
266
+ You should subscribe after this event is triggered if you want to ensure
267
+ that this subscriber has already been triggered.
268
+
269
+ ``GuzzleHttp\Event\RequestEvents::SIGN_REQUEST``
270
+ Used when you want a listener to be triggered when a request is about to be
271
+ signed. Any listener triggered at this point should expect that the request
272
+ object will no longer be mutated. If you are implementing a custom
273
+ signature subscriber, then you should use this event priority to sign
274
+ requests.
275
+
276
+ ``GuzzleHttp\Event\RequestEvents::VERIFY_RESPONSE``
277
+ Used when you want a listener to be triggered when a response is being
278
+ validated during the ``complete`` event. The
279
+ ``GuzzleHttp\Subscriber\HttpError`` event subscriber uses this event
280
+ priority to check if an exception should be thrown due to a 4xx or 5xx
281
+ level response status code. If you are doing any kind of verification of a
282
+ response during the complete event, it should happen at this priority.
283
+
284
+ ``GuzzleHttp\Event\RequestEvents::REDIRECT_RESPONSE``
285
+ Used when you want a listener to be triggered when a response is being
286
+ redirected during the ``complete`` event. The
287
+ ``GuzzleHttp\Subscriber\Redirect`` event subscriber uses this event
288
+ priority when performing redirects.
289
+
290
+ You can use the above event priorities as a guideline for determining the
291
+ priority of you event listeners. You can use these constants and add to or
292
+ subtract from them to ensure that a listener happens before or after the named
293
+ priority.
294
+
295
+ .. note::
296
+
297
+ "first" and "last" priorities are not adjusted after they added to an
298
+ emitter. For example, if you add a listener with a priority of "first",
299
+ you can still add subsequent listeners with a higher priority which would
300
+ be triggered before the listener added with a priority of "first".
301
+
302
+ Working With Request Events
303
+ ===========================
304
+
305
+ Requests emit lifecycle events when they are transferred.
306
+
307
+ .. important::
308
+
309
+ Excluding the ``end`` event, request lifecycle events may be triggered
310
+ multiple times due to redirects, retries, or reusing a request multiple
311
+ times. Use the ``once()`` method want the event to be triggered once. You
312
+ can also remove an event listener from an emitter by using the emitter which
313
+ is provided to the listener.
314
+
315
+ .. _before_event:
316
+
317
+ before
318
+ ------
319
+
320
+ The ``before`` event is emitted before a request is sent. The event emitted is
321
+ a ``GuzzleHttp\Event\BeforeEvent``.
322
+
323
+ .. code-block:: php
324
+
325
+ use GuzzleHttp\Client;
326
+ use GuzzleHttp\Event\EmitterInterface;
327
+ use GuzzleHttp\Event\BeforeEvent;
328
+
329
+ $client = new Client(['base_url' => 'http://httpbin.org']);
330
+ $request = $client->createRequest('GET', '/');
331
+ $request->getEmitter()->on(
332
+ 'before',
333
+ function (BeforeEvent $e, $name) {
334
+ echo $name . "\n";
335
+ // "before"
336
+ echo $e->getRequest()->getMethod() . "\n";
337
+ // "GET" / "POST" / "PUT" / etc.
338
+ echo get_class($e->getClient());
339
+ // "GuzzleHttp\Client"
340
+ }
341
+ );
342
+
343
+ You can intercept a request with a response before the request is sent over the
344
+ wire. The ``intercept()`` method of the ``BeforeEvent`` accepts a
345
+ ``GuzzleHttp\Message\ResponseInterface``. Intercepting the event will prevent
346
+ the request from being sent over the wire and stops the propagation of the
347
+ ``before`` event, preventing subsequent event listeners from being invoked.
348
+
349
+ .. code-block:: php
350
+
351
+ use GuzzleHttp\Client;
352
+ use GuzzleHttp\Event\BeforeEvent;
353
+ use GuzzleHttp\Message\Response;
354
+
355
+ $client = new Client(['base_url' => 'http://httpbin.org']);
356
+ $request = $client->createRequest('GET', '/status/500');
357
+ $request->getEmitter()->on('before', function (BeforeEvent $e) {
358
+ $response = new Response(200);
359
+ $e->intercept($response);
360
+ });
361
+
362
+ $response = $client->send($request);
363
+ echo $response->getStatusCode();
364
+ // 200
365
+
366
+ .. attention::
367
+
368
+ Any exception encountered while executing the ``before`` event will trigger
369
+ the ``error`` event of a request.
370
+
371
+ .. _complete_event:
372
+
373
+ complete
374
+ --------
375
+
376
+ The ``complete`` event is emitted after a transaction completes and an entire
377
+ response has been received. The event is a ``GuzzleHttp\Event\CompleteEvent``.
378
+
379
+ You can intercept the ``complete`` event with a different response if needed
380
+ using the ``intercept()`` method of the event. This can be useful, for example,
381
+ for changing the response for caching.
382
+
383
+ .. code-block:: php
384
+
385
+ use GuzzleHttp\Client;
386
+ use GuzzleHttp\Event\CompleteEvent;
387
+ use GuzzleHttp\Message\Response;
388
+
389
+ $client = new Client(['base_url' => 'http://httpbin.org']);
390
+ $request = $client->createRequest('GET', '/status/302');
391
+ $cachedResponse = new Response(200);
392
+
393
+ $request->getEmitter()->on(
394
+ 'complete',
395
+ function (CompleteEvent $e) use ($cachedResponse) {
396
+ if ($e->getResponse()->getStatusCode() == 302) {
397
+ // Intercept the original transaction with the new response
398
+ $e->intercept($cachedResponse);
399
+ }
400
+ }
401
+ );
402
+
403
+ $response = $client->send($request);
404
+ echo $response->getStatusCode();
405
+ // 200
406
+
407
+ .. attention::
408
+
409
+ Any ``GuzzleHttp\Exception\RequestException`` encountered while executing
410
+ the ``complete`` event will trigger the ``error`` event of a request.
411
+
412
+ .. _error_event:
413
+
414
+ error
415
+ -----
416
+
417
+ The ``error`` event is emitted when a request fails (whether it's from a
418
+ networking error or an HTTP protocol error). The event emitted is a
419
+ ``GuzzleHttp\Event\ErrorEvent``.
420
+
421
+ This event is useful for retrying failed requests. Here's an example of
422
+ retrying failed basic auth requests by re-sending the original request with
423
+ a username and password.
424
+
425
+ .. code-block:: php
426
+
427
+ use GuzzleHttp\Client;
428
+ use GuzzleHttp\Event\ErrorEvent;
429
+
430
+ $client = new Client(['base_url' => 'http://httpbin.org']);
431
+ $request = $client->createRequest('GET', '/basic-auth/foo/bar');
432
+ $request->getEmitter()->on('error', function (ErrorEvent $e) {
433
+ if ($e->getResponse()->getStatusCode() == 401) {
434
+ // Add authentication stuff as needed and retry the request
435
+ $e->getRequest()->setHeader('Authorization', 'Basic ' . base64_encode('foo:bar'));
436
+ // Get the client of the event and retry the request
437
+ $newResponse = $e->getClient()->send($e->getRequest());
438
+ // Intercept the original transaction with the new response
439
+ $e->intercept($newResponse);
440
+ }
441
+ });
442
+
443
+ .. attention::
444
+
445
+ If an ``error`` event is intercepted with a response, then the ``complete``
446
+ event of a request is triggered. If the ``complete`` event fails, then the
447
+ ``error`` event is triggered once again.
448
+
449
+ .. _progress_event:
450
+
451
+ progress
452
+ --------
453
+
454
+ The ``progress`` event is emitted when data is uploaded or downloaded. The
455
+ event emitted is a ``GuzzleHttp\Event\ProgressEvent``.
456
+
457
+ You can access the emitted progress values using the corresponding public
458
+ properties of the event object:
459
+
460
+ - ``$downloadSize``: The number of bytes that will be downloaded (if known)
461
+ - ``$downloaded``: The number of bytes that have been downloaded
462
+ - ``$uploadSize``: The number of bytes that will be uploaded (if known)
463
+ - ``$uploaded``: The number of bytes that have been uploaded
464
+
465
+ This event cannot be intercepted.
466
+
467
+ .. code-block:: php
468
+
469
+ use GuzzleHttp\Client;
470
+ use GuzzleHttp\Event\ProgressEvent;
471
+
472
+ $client = new Client(['base_url' => 'http://httpbin.org']);
473
+ $request = $client->createRequest('PUT', '/put', [
474
+ 'body' => str_repeat('.', 100000)
475
+ ]);
476
+
477
+ $request->getEmitter()->on('progress', function (ProgressEvent $e) {
478
+ echo 'Downloaded ' . $e->downloaded . ' of ' . $e->downloadSize . ' '
479
+ . 'Uploaded ' . $e->uploaded . ' of ' . $e->uploadSize . "\r";
480
+ });
481
+
482
+ $client->send($request);
483
+ echo "\n";
484
+
485
+ .. _end_event:
486
+
487
+ end
488
+ ---
489
+
490
+ The ``end`` event is a terminal event, emitted once per request, that provides
491
+ access to the response that was received or the exception that was encountered.
492
+ The event emitted is a ``GuzzleHttp\Event\EndEvent``.
493
+
494
+ This event can be intercepted, but keep in mind that the ``complete`` event
495
+ will not fire after intercepting this event.
496
+
497
+ .. code-block:: php
498
+
499
+ use GuzzleHttp\Client;
500
+ use GuzzleHttp\Event\EndEvent;
501
+
502
+ $client = new Client(['base_url' => 'http://httpbin.org']);
503
+ $request = $client->createRequest('PUT', '/put', [
504
+ 'body' => str_repeat('.', 100000)
505
+ ]);
506
+
507
+ $request->getEmitter()->on('end', function (EndEvent $e) {
508
+ if ($e->getException()) {
509
+ echo 'Error: ' . $e->getException()->getMessage();
510
+ } else {
511
+ echo 'Response: ' . $e->getResponse();
512
+ }
513
+ });
514
+
515
+ $client->send($request);
516
+ echo "\n";
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/faq.rst ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ===
2
+ FAQ
3
+ ===
4
+
5
+ Why should I use Guzzle?
6
+ ========================
7
+
8
+ Guzzle makes it easy to send HTTP requests and super simple to integrate with
9
+ web services. Guzzle manages things like persistent connections, represents
10
+ query strings as collections, makes it simple to send streaming POST requests
11
+ with fields and files, and abstracts away the underlying HTTP transport layer.
12
+ By providing an object oriented interface for HTTP clients, requests, responses,
13
+ headers, and message bodies, Guzzle makes it so that you no longer need to fool
14
+ around with cURL options, stream contexts, or sockets.
15
+
16
+ **Asynchronous and Synchronous Requests**
17
+
18
+ Guzzle allows you to send both asynchronous and synchronous requests using the
19
+ same interface and no direct dependency on an event loop. This flexibility
20
+ allows Guzzle to send an HTTP request using the most appropriate HTTP handler
21
+ based on the request being sent. For example, when sending synchronous
22
+ requests, Guzzle will by default send requests using cURL easy handles to
23
+ ensure you're using the fastest possible method for serially transferring HTTP
24
+ requests. When sending asynchronous requests, Guzzle might use cURL's multi
25
+ interface or any other asynchronous handler you configure. When you request
26
+ streaming data, Guzzle will by default use PHP's stream wrapper.
27
+
28
+ **Streams**
29
+
30
+ Request and response message bodies use :doc:`Guzzle Streams <streams>`,
31
+ allowing you to stream data without needing to load it all into memory.
32
+ Guzzle's stream layer provides a large suite of functionality:
33
+
34
+ - You can modify streams at runtime using custom or a number of
35
+ pre-made decorators.
36
+ - You can emit progress events as data is read from a stream.
37
+ - You can validate the integrity of a stream using a rolling hash as data is
38
+ read from a stream.
39
+
40
+ **Event System and Plugins**
41
+
42
+ Guzzle's event system allows you to completely modify the behavior of a client
43
+ or request at runtime to cater them for any API. You can send a request with a
44
+ client, and the client can do things like automatically retry your request if
45
+ it fails, automatically redirect, log HTTP messages that are sent over the
46
+ wire, emit progress events as data is uploaded and downloaded, sign requests
47
+ using OAuth 1.0, verify the integrity of messages before and after they are
48
+ sent over the wire, and anything else you might need.
49
+
50
+ **Testable**
51
+
52
+ Another important aspect of Guzzle is that it's really
53
+ :doc:`easy to test clients <testing>`. You can mock HTTP responses and when
54
+ testing an handler implementation, Guzzle provides a mock node.js web server.
55
+
56
+ **Ecosystem**
57
+
58
+ Guzzle has a large `ecosystem of plugins <http://guzzle.readthedocs.org/en/latest/index.html#http-components>`_,
59
+ including `service descriptions <https://github.com/guzzle/guzzle-services>`_
60
+ which allows you to abstract web services using service descriptions. These
61
+ service descriptions define how to serialize an HTTP request and how to parse
62
+ an HTTP response into a more meaningful model object.
63
+
64
+ - `Guzzle Command <https://github.com/guzzle/command>`_: Provides the building
65
+ blocks for service description abstraction.
66
+ - `Guzzle Services <https://github.com/guzzle/guzzle-services>`_: Provides an
67
+ implementation of "Guzzle Command" that utilizes Guzzle's service description
68
+ format.
69
+
70
+ Does Guzzle require cURL?
71
+ =========================
72
+
73
+ No. Guzzle can use any HTTP handler to send requests. This means that Guzzle
74
+ can be used with cURL, PHP's stream wrapper, sockets, and non-blocking libraries
75
+ like `React <http://reactphp.org/>`_. You just need to configure a
76
+ `RingPHP <http://guzzle-ring.readthedocs.org/en/latest/>`_ handler to use a
77
+ different method of sending requests.
78
+
79
+ .. note::
80
+
81
+ Guzzle has historically only utilized cURL to send HTTP requests. cURL is
82
+ an amazing HTTP client (arguably the best), and Guzzle will continue to use
83
+ it by default when it is available. It is rare, but some developers don't
84
+ have cURL installed on their systems or run into version specific issues.
85
+ By allowing swappable HTTP handlers, Guzzle is now much more customizable
86
+ and able to adapt to fit the needs of more developers.
87
+
88
+ Can Guzzle send asynchronous requests?
89
+ ======================================
90
+
91
+ Yes. Pass the ``future`` true request option to a request to send it
92
+ asynchronously. Guzzle will then return a ``GuzzleHttp\Message\FutureResponse``
93
+ object that can be used synchronously by accessing the response object like a
94
+ normal response, and it can be used asynchronously using a promise that is
95
+ notified when the response is resolved with a real response or rejected with an
96
+ exception.
97
+
98
+ .. code-block:: php
99
+
100
+ $request = $client->createRequest('GET', ['future' => true]);
101
+ $client->send($request)->then(function ($response) {
102
+ echo 'Got a response! ' . $response;
103
+ });
104
+
105
+ You can force an asynchronous response to complete using the ``wait()`` method
106
+ of a response.
107
+
108
+ .. code-block:: php
109
+
110
+ $request = $client->createRequest('GET', ['future' => true]);
111
+ $futureResponse = $client->send($request);
112
+ $futureResponse->wait();
113
+
114
+ How can I add custom cURL options?
115
+ ==================================
116
+
117
+ cURL offer a huge number of `customizable options <http://us1.php.net/curl_setopt>`_.
118
+ While Guzzle normalizes many of these options across different handlers, there
119
+ are times when you need to set custom cURL options. This can be accomplished
120
+ by passing an associative array of cURL settings in the **curl** key of the
121
+ **config** request option.
122
+
123
+ For example, let's say you need to customize the outgoing network interface
124
+ used with a client.
125
+
126
+ .. code-block:: php
127
+
128
+ $client->get('/', [
129
+ 'config' => [
130
+ 'curl' => [
131
+ CURLOPT_INTERFACE => 'xxx.xxx.xxx.xxx'
132
+ ]
133
+ ]
134
+ ]);
135
+
136
+ How can I add custom stream context options?
137
+ ============================================
138
+
139
+ You can pass custom `stream context options <http://www.php.net/manual/en/context.php>`_
140
+ using the **stream_context** key of the **config** request option. The
141
+ **stream_context** array is an associative array where each key is a PHP
142
+ transport, and each value is an associative array of transport options.
143
+
144
+ For example, let's say you need to customize the outgoing network interface
145
+ used with a client and allow self-signed certificates.
146
+
147
+ .. code-block:: php
148
+
149
+ $client->get('/', [
150
+ 'stream' => true,
151
+ 'config' => [
152
+ 'stream_context' => [
153
+ 'ssl' => [
154
+ 'allow_self_signed' => true
155
+ ],
156
+ 'socket' => [
157
+ 'bindto' => 'xxx.xxx.xxx.xxx'
158
+ ]
159
+ ]
160
+ ]
161
+ ]);
162
+
163
+ Why am I getting an SSL verification error?
164
+ ===========================================
165
+
166
+ You need to specify the path on disk to the CA bundle used by Guzzle for
167
+ verifying the peer certificate. See :ref:`verify-option`.
168
+
169
+ What is this Maximum function nesting error?
170
+ ============================================
171
+
172
+ Maximum function nesting level of '100' reached, aborting
173
+
174
+ You could run into this error if you have the XDebug extension installed and
175
+ you execute a lot of requests in callbacks. This error message comes
176
+ specifically from the XDebug extension. PHP itself does not have a function
177
+ nesting limit. Change this setting in your php.ini to increase the limit::
178
+
179
+ xdebug.max_nesting_level = 1000
180
+
181
+ Why am I getting a 417 error response?
182
+ ======================================
183
+
184
+ This can occur for a number of reasons, but if you are sending PUT, POST, or
185
+ PATCH requests with an ``Expect: 100-Continue`` header, a server that does not
186
+ support this header will return a 417 response. You can work around this by
187
+ setting the ``expect`` request option to ``false``:
188
+
189
+ .. code-block:: php
190
+
191
+ $client = new GuzzleHttp\Client();
192
+
193
+ // Disable the expect header on a single request
194
+ $response = $client->put('/', [], 'the body', [
195
+ 'expect' => false
196
+ ]);
197
+
198
+ // Disable the expect header on all client requests
199
+ $client->setDefaultOption('expect', false)
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/handlers.rst ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ================
2
+ RingPHP Handlers
3
+ ================
4
+
5
+ Guzzle uses RingPHP handlers to send HTTP requests over the wire.
6
+ RingPHP provides a low-level library that can be used to "glue" Guzzle with
7
+ any transport method you choose. By default, Guzzle utilizes cURL and PHP's
8
+ stream wrappers to send HTTP requests.
9
+
10
+ RingPHP handlers makes it extremely simple to integrate Guzzle with any
11
+ HTTP transport. For example, you could quite easily bridge Guzzle and React
12
+ to use Guzzle in React's event loop.
13
+
14
+ Using a handler
15
+ ---------------
16
+
17
+ You can change the handler used by a client using the ``handler`` option in the
18
+ ``GuzzleHttp\Client`` constructor.
19
+
20
+ .. code-block:: php
21
+
22
+ use GuzzleHttp\Client;
23
+ use GuzzleHttp\Ring\Client\MockHandler;
24
+
25
+ // Create a mock handler that always returns a 200 response.
26
+ $handler = new MockHandler(['status' => 200]);
27
+
28
+ // Configure to client to use the mock handler.
29
+ $client = new Client(['handler' => $handler]);
30
+
31
+ At its core, handlers are simply PHP callables that accept a request array
32
+ and return a ``GuzzleHttp\Ring\Future\FutureArrayInterface``. This future array
33
+ can be used just like a normal PHP array, causing it to block, or you can use
34
+ the promise interface using the ``then()`` method of the future. Guzzle hooks
35
+ up to the RingPHP project using a very simple bridge class
36
+ (``GuzzleHttp\RingBridge``).
37
+
38
+ Creating a handler
39
+ ------------------
40
+
41
+ See the `RingPHP <http://ringphp.readthedocs.org>`_ project
42
+ documentation for more information on creating custom handlers that can be
43
+ used with Guzzle clients.
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/http-messages.rst ADDED
@@ -0,0 +1,483 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =============================
2
+ Request and Response Messages
3
+ =============================
4
+
5
+ Guzzle is an HTTP client that sends HTTP requests to a server and receives HTTP
6
+ responses. Both requests and responses are referred to as messages.
7
+
8
+ Headers
9
+ =======
10
+
11
+ Both request and response messages contain HTTP headers.
12
+
13
+ Complex Headers
14
+ ---------------
15
+
16
+ Some headers contain additional key value pair information. For example, Link
17
+ headers contain a link and several key value pairs:
18
+
19
+ ::
20
+
21
+ <http://foo.com>; rel="thing"; type="image/jpeg"
22
+
23
+ Guzzle provides a convenience feature that can be used to parse these types of
24
+ headers:
25
+
26
+ .. code-block:: php
27
+
28
+ use GuzzleHttp\Message\Request;
29
+
30
+ $request = new Request('GET', '/', [
31
+ 'Link' => '<http:/.../front.jpeg>; rel="front"; type="image/jpeg"'
32
+ ]);
33
+
34
+ $parsed = Request::parseHeader($request, 'Link');
35
+ var_export($parsed);
36
+
37
+ Will output:
38
+
39
+ .. code-block:: php
40
+
41
+ array (
42
+ 0 =>
43
+ array (
44
+ 0 => '<http:/.../front.jpeg>',
45
+ 'rel' => 'front',
46
+ 'type' => 'image/jpeg',
47
+ ),
48
+ )
49
+
50
+ The result contains a hash of key value pairs. Header values that have no key
51
+ (i.e., the link) are indexed numerically while headers parts that form a key
52
+ value pair are added as a key value pair.
53
+
54
+ See :ref:`headers` for information on how the headers of a request and response
55
+ can be accessed and modified.
56
+
57
+ Body
58
+ ====
59
+
60
+ Both request and response messages can contain a body.
61
+
62
+ You can check to see if a request or response has a body using the
63
+ ``getBody()`` method:
64
+
65
+ .. code-block:: php
66
+
67
+ $response = GuzzleHttp\get('http://httpbin.org/get');
68
+ if ($response->getBody()) {
69
+ echo $response->getBody();
70
+ // JSON string: { ... }
71
+ }
72
+
73
+ The body used in request and response objects is a
74
+ ``GuzzleHttp\Stream\StreamInterface``. This stream is used for both uploading
75
+ data and downloading data. Guzzle will, by default, store the body of a message
76
+ in a stream that uses PHP temp streams. When the size of the body exceeds
77
+ 2 MB, the stream will automatically switch to storing data on disk rather than
78
+ in memory (protecting your application from memory exhaustion).
79
+
80
+ You can change the body used in a request or response using the ``setBody()``
81
+ method:
82
+
83
+ .. code-block:: php
84
+
85
+ use GuzzleHttp\Stream\Stream;
86
+ $request = $client->createRequest('PUT', 'http://httpbin.org/put');
87
+ $request->setBody(Stream::factory('foo'));
88
+
89
+ The easiest way to create a body for a request is using the static
90
+ ``GuzzleHttp\Stream\Stream::factory()`` method. This method accepts various
91
+ inputs like strings, resources returned from ``fopen()``, and other
92
+ ``GuzzleHttp\Stream\StreamInterface`` objects.
93
+
94
+ The body of a request or response can be cast to a string or you can read and
95
+ write bytes off of the stream as needed.
96
+
97
+ .. code-block:: php
98
+
99
+ use GuzzleHttp\Stream\Stream;
100
+ $request = $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'testing...']);
101
+
102
+ echo $request->getBody()->read(4);
103
+ // test
104
+ echo $request->getBody()->read(4);
105
+ // ing.
106
+ echo $request->getBody()->read(1024);
107
+ // ..
108
+ var_export($request->eof());
109
+ // true
110
+
111
+ You can find out more about Guzzle stream objects in :doc:`streams`.
112
+
113
+ Requests
114
+ ========
115
+
116
+ Requests are sent from a client to a server. Requests include the method to
117
+ be applied to a resource, the identifier of the resource, and the protocol
118
+ version to use.
119
+
120
+ Clients are used to create request messages. More precisely, clients use
121
+ a ``GuzzleHttp\Message\MessageFactoryInterface`` to create request messages.
122
+ You create requests with a client using the ``createRequest()`` method.
123
+
124
+ .. code-block:: php
125
+
126
+ // Create a request but don't send it immediately
127
+ $request = $client->createRequest('GET', 'http://httpbin.org/get');
128
+
129
+ Request Methods
130
+ ---------------
131
+
132
+ When creating a request, you are expected to provide the HTTP method you wish
133
+ to perform. You can specify any method you'd like, including a custom method
134
+ that might not be part of RFC 7231 (like "MOVE").
135
+
136
+ .. code-block:: php
137
+
138
+ // Create a request using a completely custom HTTP method
139
+ $request = $client->createRequest('MOVE', 'http://httpbin.org/move', ['exceptions' => false]);
140
+
141
+ echo $request->getMethod();
142
+ // MOVE
143
+
144
+ $response = $client->send($request);
145
+ echo $response->getStatusCode();
146
+ // 405
147
+
148
+ You can create and send a request using methods on a client that map to the
149
+ HTTP method you wish to use.
150
+
151
+ :GET: ``$client->get('http://httpbin.org/get', [/** options **/])``
152
+ :POST: ``$client->post('http://httpbin.org/post', [/** options **/])``
153
+ :HEAD: ``$client->head('http://httpbin.org/get', [/** options **/])``
154
+ :PUT: ``$client->put('http://httpbin.org/put', [/** options **/])``
155
+ :DELETE: ``$client->delete('http://httpbin.org/delete', [/** options **/])``
156
+ :OPTIONS: ``$client->options('http://httpbin.org/get', [/** options **/])``
157
+ :PATCH: ``$client->patch('http://httpbin.org/put', [/** options **/])``
158
+
159
+ .. code-block:: php
160
+
161
+ $response = $client->patch('http://httpbin.org/patch', ['body' => 'content']);
162
+
163
+ Request URI
164
+ -----------
165
+
166
+ The resource you are requesting with an HTTP request is identified by the
167
+ path of the request, the query string, and the "Host" header of the request.
168
+
169
+ When creating a request, you can provide the entire resource URI as a URL.
170
+
171
+ .. code-block:: php
172
+
173
+ $response = $client->get('http://httbin.org/get?q=foo');
174
+
175
+ Using the above code, you will send a request that uses ``httpbin.org`` as
176
+ the Host header, sends the request over port 80, uses ``/get`` as the path,
177
+ and sends ``?q=foo`` as the query string. All of this is parsed automatically
178
+ from the provided URI.
179
+
180
+ Sometimes you don't know what the entire request will be when it is created.
181
+ In these cases, you can modify the request as needed before sending it using
182
+ the ``createRequest()`` method of the client and methods on the request that
183
+ allow you to change it.
184
+
185
+ .. code-block:: php
186
+
187
+ $request = $client->createRequest('GET', 'http://httbin.org');
188
+
189
+ You can change the path of the request using ``setPath()``:
190
+
191
+ .. code-block:: php
192
+
193
+ $request->setPath('/get');
194
+ echo $request->getPath();
195
+ // /get
196
+ echo $request->getUrl();
197
+ // http://httpbin.com/get
198
+
199
+ Scheme
200
+ ~~~~~~
201
+
202
+ The `scheme <http://tools.ietf.org/html/rfc3986#section-3.1>`_ of a request
203
+ specifies the protocol to use when sending the request. When using Guzzle, the
204
+ scheme can be set to "http" or "https".
205
+
206
+ You can change the scheme of the request using the ``setScheme()`` method:
207
+
208
+ .. code-block:: php
209
+
210
+ $request = $client->createRequest('GET', 'http://httbin.org');
211
+ $request->setScheme('https');
212
+ echo $request->getScheme();
213
+ // https
214
+ echo $request->getUrl();
215
+ // https://httpbin.com/get
216
+
217
+ Port
218
+ ~~~~
219
+
220
+ No port is necessary when using the "http" or "https" schemes, but you can
221
+ override the port using ``setPort()``. If you need to modify the port used with
222
+ the specified scheme from the default setting, then you must use the
223
+ ``setPort()`` method.
224
+
225
+ .. code-block:: php
226
+
227
+ $request = $client->createRequest('GET', 'http://httbin.org');
228
+ $request->setPort(8080);
229
+ echo $request->getPort();
230
+ // 8080
231
+ echo $request->getUrl();
232
+ // https://httpbin.com:8080/get
233
+
234
+ // Set the port back to the default value for the scheme
235
+ $request->setPort(443);
236
+ echo $request->getUrl();
237
+ // https://httpbin.com/get
238
+
239
+ Query string
240
+ ~~~~~~~~~~~~
241
+
242
+ You can get the query string of the request using the ``getQuery()`` method.
243
+ This method returns a ``GuzzleHttp\Query`` object. A Query object can be
244
+ accessed like a PHP array, iterated in a foreach statement like a PHP array,
245
+ and cast to a string.
246
+
247
+ .. code-block:: php
248
+
249
+ $request = $client->createRequest('GET', 'http://httbin.org');
250
+ $query = $request->getQuery();
251
+ $query['foo'] = 'bar';
252
+ $query['baz'] = 'bam';
253
+ $query['bam'] = ['test' => 'abc'];
254
+
255
+ echo $request->getQuery();
256
+ // foo=bar&baz=bam&bam%5Btest%5D=abc
257
+
258
+ echo $request->getQuery()['foo'];
259
+ // bar
260
+ echo $request->getQuery()->get('foo');
261
+ // bar
262
+ echo $request->getQuery()->get('foo');
263
+ // bar
264
+
265
+ var_export($request->getQuery()['bam']);
266
+ // array('test' => 'abc')
267
+
268
+ foreach ($query as $key => $value) {
269
+ var_export($value);
270
+ }
271
+
272
+ echo $request->getUrl();
273
+ // https://httpbin.com/get?foo=bar&baz=bam&bam%5Btest%5D=abc
274
+
275
+ Query Aggregators
276
+ ^^^^^^^^^^^^^^^^^
277
+
278
+ Query objects can store scalar values or arrays of values. When an array of
279
+ values is added to a query object, the query object uses a query aggregator to
280
+ convert the complex structure into a string. Query objects will use
281
+ `PHP style query strings <http://www.php.net/http_build_query>`_ when complex
282
+ query string parameters are converted to a string. You can customize how
283
+ complex query string parameters are aggregated using the ``setAggregator()``
284
+ method of a query string object.
285
+
286
+ .. code-block:: php
287
+
288
+ $query->setAggregator($query::duplicateAggregator());
289
+
290
+ In the above example, we've changed the query object to use the
291
+ "duplicateAggregator". This aggregator will allow duplicate entries to appear
292
+ in a query string rather than appending "[n]" to each value. So if you had a
293
+ query string with ``['a' => ['b', 'c']]``, the duplicate aggregator would
294
+ convert this to "a=b&a=c" while the default aggregator would convert this to
295
+ "a[0]=b&a[1]=c" (with urlencoded brackets).
296
+
297
+ The ``setAggregator()`` method accepts a ``callable`` which is used to convert
298
+ a deeply nested array of query string variables into a flattened array of key
299
+ value pairs. The callable accepts an array of query data and returns a
300
+ flattened array of key value pairs where each value is an array of strings.
301
+ You can use the ``GuzzleHttp\Query::walkQuery()`` static function to easily
302
+ create custom query aggregators.
303
+
304
+ Host
305
+ ~~~~
306
+
307
+ You can change the host header of the request in a predictable way using the
308
+ ``setHost()`` method of a request:
309
+
310
+ .. code-block:: php
311
+
312
+ $request->setHost('www.google.com');
313
+ echo $request->getHost();
314
+ // www.google.com
315
+ echo $request->getUrl();
316
+ // https://www.google.com/get?foo=bar&baz=bam
317
+
318
+ .. note::
319
+
320
+ The Host header can also be changed by modifying the Host header of a
321
+ request directly, but modifying the Host header directly could result in
322
+ sending a request to a different Host than what is specified in the Host
323
+ header (sometimes this is actually the desired behavior).
324
+
325
+ Resource
326
+ ~~~~~~~~
327
+
328
+ You can use the ``getResource()`` method of a request to return the path and
329
+ query string of a request in a single string.
330
+
331
+ .. code-block:: php
332
+
333
+ $request = $client->createRequest('GET', 'http://httpbin.org/get?baz=bar');
334
+ echo $request->getResource();
335
+ // /get?baz=bar
336
+
337
+ Request Config
338
+ --------------
339
+
340
+ Request messages contain a configuration collection that can be used by
341
+ event listeners and HTTP handlers to modify how a request behaves or is
342
+ transferred over the wire. For example, many of the request options that are
343
+ specified when creating a request are actually set as config options that are
344
+ only acted upon by handlers and listeners when the request is sent.
345
+
346
+ You can get access to the request's config object using the ``getConfig()``
347
+ method of a request.
348
+
349
+ .. code-block:: php
350
+
351
+ $request = $client->createRequest('GET', '/');
352
+ $config = $request->getConfig();
353
+
354
+ The config object is a ``GuzzleHttp\Collection`` object that acts like
355
+ an associative array. You can grab values from the collection using array like
356
+ access. You can also modify and remove values using array like access.
357
+
358
+ .. code-block:: php
359
+
360
+ $config['foo'] = 'bar';
361
+ echo $config['foo'];
362
+ // bar
363
+
364
+ var_export(isset($config['foo']));
365
+ // true
366
+
367
+ unset($config['foo']);
368
+ var_export(isset($config['foo']));
369
+ // false
370
+
371
+ var_export($config['foo']);
372
+ // NULL
373
+
374
+ HTTP handlers and event listeners can expose additional customization options
375
+ through request config settings. For example, in order to specify custom cURL
376
+ options to the cURL handler, you need to specify an associative array in the
377
+ ``curl`` ``config`` request option.
378
+
379
+ .. code-block:: php
380
+
381
+ $client->get('/', [
382
+ 'config' => [
383
+ 'curl' => [
384
+ CURLOPT_HTTPAUTH => CURLAUTH_NTLM,
385
+ CURLOPT_USERPWD => 'username:password'
386
+ ]
387
+ ]
388
+ ]);
389
+
390
+ Consult the HTTP handlers and event listeners you are using to see if they
391
+ allow customization through request configuration options.
392
+
393
+ Event Emitter
394
+ -------------
395
+
396
+ Request objects implement ``GuzzleHttp\Event\HasEmitterInterface``, so they
397
+ have a method called ``getEmitter()`` that can be used to get an event emitter
398
+ used by the request. Any listener or subscriber attached to a request will only
399
+ be triggered for the lifecycle events of a specific request. Conversely, adding
400
+ an event listener or subscriber to a client will listen to all lifecycle events
401
+ of all requests created by the client.
402
+
403
+ See :doc:`events` for more information.
404
+
405
+ Responses
406
+ =========
407
+
408
+ Responses are the HTTP messages a client receives from a server after sending
409
+ an HTTP request message.
410
+
411
+ Start-Line
412
+ ----------
413
+
414
+ The start-line of a response contains the protocol and protocol version,
415
+ status code, and reason phrase.
416
+
417
+ .. code-block:: php
418
+
419
+ $response = GuzzleHttp\get('http://httpbin.org/get');
420
+ echo $response->getStatusCode();
421
+ // 200
422
+ echo $response->getReasonPhrase();
423
+ // OK
424
+ echo $response->getProtocolVersion();
425
+ // 1.1
426
+
427
+ Body
428
+ ----
429
+
430
+ As described earlier, you can get the body of a response using the
431
+ ``getBody()`` method.
432
+
433
+ .. code-block:: php
434
+
435
+ if ($body = $response->getBody()) {
436
+ echo $body;
437
+ // Cast to a string: { ... }
438
+ $body->seek(0);
439
+ // Rewind the body
440
+ $body->read(1024);
441
+ // Read bytes of the body
442
+ }
443
+
444
+ When working with JSON responses, you can use the ``json()`` method of a
445
+ response:
446
+
447
+ .. code-block:: php
448
+
449
+ $json = $response->json();
450
+
451
+ .. note::
452
+
453
+ Guzzle uses the ``json_decode()`` method of PHP and uses arrays rather than
454
+ ``stdClass`` objects for objects.
455
+
456
+ You can use the ``xml()`` method when working with XML data.
457
+
458
+ .. code-block:: php
459
+
460
+ $xml = $response->xml();
461
+
462
+ .. note::
463
+
464
+ Guzzle uses the ``SimpleXMLElement`` objects when converting response
465
+ bodies to XML.
466
+
467
+ Effective URL
468
+ -------------
469
+
470
+ The URL that was ultimately accessed that returned a response can be accessed
471
+ using the ``getEffectiveUrl()`` method of a response. This method will return
472
+ the URL of a request or the URL of the last redirected URL if any redirects
473
+ occurred while transferring a request.
474
+
475
+ .. code-block:: php
476
+
477
+ $response = GuzzleHttp\get('http://httpbin.org/get');
478
+ echo $response->getEffectiveUrl();
479
+ // http://httpbin.org/get
480
+
481
+ $response = GuzzleHttp\get('http://httpbin.org/redirect-to?url=http://www.google.com');
482
+ echo $response->getEffectiveUrl();
483
+ // http://www.google.com
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/index.rst ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services
2
+
3
+ ======
4
+ Guzzle
5
+ ======
6
+
7
+ Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
8
+ trivial to integrate with web services.
9
+
10
+ - Manages things like persistent connections, represents query strings as
11
+ collections, simplifies sending streaming POST requests with fields and
12
+ files, and abstracts away the underlying HTTP transport layer.
13
+ - Can send both synchronous and asynchronous requests using the same interface
14
+ without requiring a dependency on a specific event loop.
15
+ - Pluggable HTTP handlers allows Guzzle to integrate with any method you choose
16
+ for sending HTTP requests over the wire (e.g., cURL, sockets, PHP's stream
17
+ wrapper, non-blocking event loops like `React <http://reactphp.org/>`_, etc.).
18
+ - Guzzle makes it so that you no longer need to fool around with cURL options,
19
+ stream contexts, or sockets.
20
+
21
+ .. code-block:: php
22
+
23
+ $client = new GuzzleHttp\Client();
24
+ $response = $client->get('http://guzzlephp.org');
25
+ $res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]);
26
+ echo $res->getStatusCode();
27
+ // "200"
28
+ echo $res->getHeader('content-type');
29
+ // 'application/json; charset=utf8'
30
+ echo $res->getBody();
31
+ // {"type":"User"...'
32
+ var_export($res->json());
33
+ // Outputs the JSON decoded data
34
+
35
+ // Send an asynchronous request.
36
+ $req = $client->createRequest('GET', 'http://httpbin.org', ['future' => true]);
37
+ $client->send($req)->then(function ($response) {
38
+ echo 'I completed! ' . $response;
39
+ });
40
+
41
+ User guide
42
+ ----------
43
+
44
+ .. toctree::
45
+ :maxdepth: 2
46
+
47
+ overview
48
+ quickstart
49
+ clients
50
+ http-messages
51
+ events
52
+ streams
53
+ handlers
54
+ testing
55
+ faq
56
+
57
+ HTTP Components
58
+ ---------------
59
+
60
+ There are a number of optional libraries you can use along with Guzzle's HTTP
61
+ layer to add capabilities to the client.
62
+
63
+ `Log Subscriber <https://github.com/guzzle/log-subscriber>`_
64
+ Logs HTTP requests and responses sent over the wire using customizable
65
+ log message templates.
66
+
67
+ `OAuth Subscriber <https://github.com/guzzle/oauth-subscriber>`_
68
+ Signs requests using OAuth 1.0.
69
+
70
+ `Cache Subscriber <https://github.com/guzzle/cache-subscriber>`_
71
+ Implements a private transparent proxy cache that caches HTTP responses.
72
+
73
+ `Retry Subscriber <https://github.com/guzzle/retry-subscriber>`_
74
+ Retries failed requests using customizable retry strategies (e.g., retry
75
+ based on response status code, cURL error codes, etc.)
76
+
77
+ `Message Integrity Subscriber <https://github.com/guzzle/message-integrity-subscriber>`_
78
+ Verifies the message integrity of HTTP responses using customizable
79
+ validators. This plugin can be used, for example, to verify the Content-MD5
80
+ headers of responses.
81
+
82
+ Service Description Commands
83
+ ----------------------------
84
+
85
+ You can use the **Guzzle Command** library to encapsulate interaction with a
86
+ web service using command objects. Building on top of Guzzle's command
87
+ abstraction allows you to easily implement things like service description that
88
+ can be used to serialize requests and parse responses using a meta-description
89
+ of a web service.
90
+
91
+ `Guzzle Command <https://github.com/guzzle/command>`_
92
+ Provides the foundational elements used to build high-level, command based,
93
+ web service clients with Guzzle.
94
+
95
+ `Guzzle Services <https://github.com/guzzle/guzzle-services>`_
96
+ Provides an implementation of the *Guzzle Command* library that uses
97
+ Guzzle service descriptions to describe web services, serialize requests,
98
+ and parse responses into easy to use model structures.
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/overview.rst ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ========
2
+ Overview
3
+ ========
4
+
5
+ Requirements
6
+ ============
7
+
8
+ #. PHP 5.4.0
9
+ #. To use the PHP stream handler, ``allow_url_fopen`` must be enabled in your
10
+ system's php.ini.
11
+ #. To use the cURL handler, you must have a recent version of cURL >= 7.16.2
12
+ compiled with OpenSSL and zlib.
13
+
14
+ .. note::
15
+
16
+ Guzzle no longer requires cURL in order to send HTTP requests. Guzzle will
17
+ use the PHP stream wrapper to send HTTP requests if cURL is not installed.
18
+ Alternatively, you can provide your own HTTP handler used to send requests.
19
+
20
+ .. _installation:
21
+
22
+ Installation
23
+ ============
24
+
25
+ The recommended way to install Guzzle is with `Composer <http://getcomposer.org>`_. Composer is a dependency
26
+ management tool for PHP that allows you to declare the dependencies your project needs and installs them into your
27
+ project.
28
+
29
+ .. code-block:: bash
30
+
31
+ # Install Composer
32
+ curl -sS https://getcomposer.org/installer | php
33
+
34
+ You can add Guzzle as a dependency using the composer.phar CLI:
35
+
36
+ .. code-block:: bash
37
+
38
+ php composer.phar require guzzlehttp/guzzle:~5.0
39
+
40
+ Alternatively, you can specify Guzzle as a dependency in your project's
41
+ existing composer.json file:
42
+
43
+ .. code-block:: js
44
+
45
+ {
46
+ "require": {
47
+ "guzzlehttp/guzzle": "~5.0"
48
+ }
49
+ }
50
+
51
+ After installing, you need to require Composer's autoloader:
52
+
53
+ .. code-block:: php
54
+
55
+ require 'vendor/autoload.php';
56
+
57
+ You can find out more on how to install Composer, configure autoloading, and
58
+ other best-practices for defining dependencies at `getcomposer.org <http://getcomposer.org>`_.
59
+
60
+ Bleeding edge
61
+ -------------
62
+
63
+ During your development, you can keep up with the latest changes on the master
64
+ branch by setting the version requirement for Guzzle to ``~5.0@dev``.
65
+
66
+ .. code-block:: js
67
+
68
+ {
69
+ "require": {
70
+ "guzzlehttp/guzzle": "~5.0@dev"
71
+ }
72
+ }
73
+
74
+ License
75
+ =======
76
+
77
+ Licensed using the `MIT license <http://opensource.org/licenses/MIT>`_.
78
+
79
+ Copyright (c) 2014 Michael Dowling <https://github.com/mtdowling>
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining a copy
82
+ of this software and associated documentation files (the "Software"), to deal
83
+ in the Software without restriction, including without limitation the rights
84
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
85
+ copies of the Software, and to permit persons to whom the Software is
86
+ furnished to do so, subject to the following conditions:
87
+
88
+ The above copyright notice and this permission notice shall be included in
89
+ all copies or substantial portions of the Software.
90
+
91
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
92
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
93
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
94
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
95
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
96
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
97
+ THE SOFTWARE.
98
+
99
+ Contributing
100
+ ============
101
+
102
+ Guidelines
103
+ ----------
104
+
105
+ 1. Guzzle follows PSR-0, PSR-1, and PSR-2.
106
+ 2. Guzzle is meant to be lean and fast with very few dependencies.
107
+ 3. Guzzle has a minimum PHP version requirement of PHP 5.4. Pull requests must
108
+ not require a PHP version greater than PHP 5.4.
109
+ 4. All pull requests must include unit tests to ensure the change works as
110
+ expected and to prevent regressions.
111
+
112
+ Running the tests
113
+ -----------------
114
+
115
+ In order to contribute, you'll need to checkout the source from GitHub and
116
+ install Guzzle's dependencies using Composer:
117
+
118
+ .. code-block:: bash
119
+
120
+ git clone https://github.com/guzzle/guzzle.git
121
+ cd guzzle && curl -s http://getcomposer.org/installer | php && ./composer.phar install --dev
122
+
123
+ Guzzle is unit tested with PHPUnit. Run the tests using the vendored PHPUnit
124
+ binary:
125
+
126
+ .. code-block:: bash
127
+
128
+ vendor/bin/phpunit
129
+
130
+ .. note::
131
+
132
+ You'll need to install node.js v0.5.0 or newer in order to perform
133
+ integration tests on Guzzle's HTTP handlers.
134
+
135
+ Reporting a security vulnerability
136
+ ==================================
137
+
138
+ We want to ensure that Guzzle is a secure HTTP client library for everyone. If
139
+ you've discovered a security vulnerability in Guzzle, we appreciate your help
140
+ in disclosing it to us in a `responsible manner <http://en.wikipedia.org/wiki/Responsible_disclosure>`_.
141
+
142
+ Publicly disclosing a vulnerability can put the entire community at risk. If
143
+ you've discovered a security concern, please email us at
144
+ security@guzzlephp.org. We'll work with you to make sure that we understand the
145
+ scope of the issue, and that we fully address your concern. We consider
146
+ correspondence sent to security@guzzlephp.org our highest priority, and work to
147
+ address any issues that arise as quickly as possible.
148
+
149
+ After a security vulnerability has been corrected, a security hotfix release will
150
+ be deployed as soon as possible.
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/quickstart.rst ADDED
@@ -0,0 +1,448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ==========
2
+ Quickstart
3
+ ==========
4
+
5
+ This page provides a quick introduction to Guzzle and introductory examples.
6
+ If you have not already installed, Guzzle, head over to the :ref:`installation`
7
+ page.
8
+
9
+ Make a Request
10
+ ==============
11
+
12
+ You can send requests with Guzzle using a ``GuzzleHttp\ClientInterface``
13
+ object.
14
+
15
+ Creating a Client
16
+ -----------------
17
+
18
+ The procedural API is simple but not very testable; it's best left for quick
19
+ prototyping. If you want to use Guzzle in a more flexible and testable way,
20
+ then you'll need to use a ``GuzzleHttp\ClientInterface`` object.
21
+
22
+ .. code-block:: php
23
+
24
+ use GuzzleHttp\Client;
25
+
26
+ $client = new Client();
27
+ $response = $client->get('http://httpbin.org/get');
28
+
29
+ // You can use the same methods you saw in the procedural API
30
+ $response = $client->delete('http://httpbin.org/delete');
31
+ $response = $client->head('http://httpbin.org/get');
32
+ $response = $client->options('http://httpbin.org/get');
33
+ $response = $client->patch('http://httpbin.org/patch');
34
+ $response = $client->post('http://httpbin.org/post');
35
+ $response = $client->put('http://httpbin.org/put');
36
+
37
+ You can create a request with a client and then send the request with the
38
+ client when you're ready.
39
+
40
+ .. code-block:: php
41
+
42
+ $request = $client->createRequest('GET', 'http://www.foo.com');
43
+ $response = $client->send($request);
44
+
45
+ Client objects provide a great deal of flexibility in how request are
46
+ transferred including default request options, subscribers that are attached
47
+ to each request, and a base URL that allows you to send requests with relative
48
+ URLs. You can find out all about clients in the :doc:`clients` page of the
49
+ documentation.
50
+
51
+ Using Responses
52
+ ===============
53
+
54
+ In the previous examples, we retrieved a ``$response`` variable. This value is
55
+ actually a ``GuzzleHttp\Message\ResponseInterface`` object and contains lots
56
+ of helpful information.
57
+
58
+ You can get the status code and reason phrase of the response.
59
+
60
+ .. code-block:: php
61
+
62
+ $code = $response->getStatusCode();
63
+ // 200
64
+
65
+ $reason = $response->getReasonPhrase();
66
+ // OK
67
+
68
+ By providing the ``future`` request option to a request, you can send requests
69
+ asynchronously using the promise interface of a future response.
70
+
71
+ .. code-block:: php
72
+
73
+ $client->get('http://httpbin.org', ['future' => true])
74
+ ->then(function ($response) {
75
+ echo $response->getStatusCode();
76
+ });
77
+
78
+ Response Body
79
+ -------------
80
+
81
+ The body of a response can be retrieved and cast to a string.
82
+
83
+ .. code-block:: php
84
+
85
+ $body = $response->getBody();
86
+ echo $body;
87
+ // { "some_json_data" ...}
88
+
89
+ You can also read read bytes from body of a response like a stream.
90
+
91
+ .. code-block:: php
92
+
93
+ $body = $response->getBody();
94
+
95
+ while (!$body->eof()) {
96
+ echo $body->read(1024);
97
+ }
98
+
99
+ JSON Responses
100
+ ~~~~~~~~~~~~~~
101
+
102
+ You can more easily work with JSON responses using the ``json()`` method of a
103
+ response.
104
+
105
+ .. code-block:: php
106
+
107
+ $response = $client->get('http://httpbin.org/get');
108
+ $json = $response->json();
109
+ var_dump($json[0]['origin']);
110
+
111
+ Guzzle internally uses PHP's ``json_decode()`` function to parse responses. If
112
+ Guzzle is unable to parse the JSON response body, then a
113
+ ``GuzzleHttp\Exception\ParseException`` is thrown.
114
+
115
+ XML Responses
116
+ ~~~~~~~~~~~~~
117
+
118
+ You can use a response's ``xml()`` method to more easily work with responses
119
+ that contain XML data.
120
+
121
+ .. code-block:: php
122
+
123
+ $response = $client->get('https://github.com/mtdowling.atom');
124
+ $xml = $response->xml();
125
+ echo $xml->id;
126
+ // tag:github.com,2008:/mtdowling
127
+
128
+ Guzzle internally uses a ``SimpleXMLElement`` object to parse responses. If
129
+ Guzzle is unable to parse the XML response body, then a
130
+ ``GuzzleHttp\Exception\ParseException`` is thrown.
131
+
132
+ Query String Parameters
133
+ =======================
134
+
135
+ Sending query string parameters with a request is easy. You can set query
136
+ string parameters in the request's URL.
137
+
138
+ .. code-block:: php
139
+
140
+ $response = $client->get('http://httpbin.org?foo=bar');
141
+
142
+ You can also specify the query string parameters using the ``query`` request
143
+ option.
144
+
145
+ .. code-block:: php
146
+
147
+ $client->get('http://httpbin.org', [
148
+ 'query' => ['foo' => 'bar']
149
+ ]);
150
+
151
+ And finally, you can build up the query string of a request as needed by
152
+ calling the ``getQuery()`` method of a request and modifying the request's
153
+ ``GuzzleHttp\Query`` object as needed.
154
+
155
+ .. code-block:: php
156
+
157
+ $request = $client->createRequest('GET', 'http://httpbin.org');
158
+ $query = $request->getQuery();
159
+ $query->set('foo', 'bar');
160
+
161
+ // You can use the query string object like an array
162
+ $query['baz'] = 'bam';
163
+
164
+ // The query object can be cast to a string
165
+ echo $query;
166
+ // foo=bar&baz=bam
167
+
168
+ // Setting a value to false or null will cause the "=" sign to be omitted
169
+ $query['empty'] = null;
170
+ echo $query;
171
+ // foo=bar&baz=bam&empty
172
+
173
+ // Use an empty string to include the "=" sign with an empty value
174
+ $query['empty'] = '';
175
+ echo $query;
176
+ // foo=bar&baz=bam&empty=
177
+
178
+ .. _headers:
179
+
180
+ Request and Response Headers
181
+ ----------------------------
182
+
183
+ You can specify request headers when sending or creating requests with a
184
+ client. In the following example, we send the ``X-Foo-Header`` with a value of
185
+ ``value`` by setting the ``headers`` request option.
186
+
187
+ .. code-block:: php
188
+
189
+ $response = $client->get('http://httpbin.org/get', [
190
+ 'headers' => ['X-Foo-Header' => 'value']
191
+ ]);
192
+
193
+ You can view the headers of a response using header specific methods of a
194
+ response class. Headers work exactly the same way for request and response
195
+ object.
196
+
197
+ You can retrieve a header from a request or response using the ``getHeader()``
198
+ method of the object. This method is case-insensitive and by default will
199
+ return a string containing the header field value.
200
+
201
+ .. code-block:: php
202
+
203
+ $response = $client->get('http://www.yahoo.com');
204
+ $length = $response->getHeader('Content-Length');
205
+
206
+ Header fields that contain multiple values can be retrieved as a string or as
207
+ an array. Retrieving the field values as a string will naively concatenate all
208
+ of the header values together with a comma. Because not all header fields
209
+ should be represented this way (e.g., ``Set-Cookie``), you can pass an optional
210
+ flag to the ``getHeader()`` method to retrieve the header values as an array.
211
+
212
+ .. code-block:: php
213
+
214
+ $values = $response->getHeader('Set-Cookie', true);
215
+ foreach ($values as $value) {
216
+ echo $value;
217
+ }
218
+
219
+ You can test if a request or response has a specific header using the
220
+ ``hasHeader()`` method. This method accepts a case-insensitive string and
221
+ returns true if the header is present or false if it is not.
222
+
223
+ You can retrieve all of the headers of a message using the ``getHeaders()``
224
+ method of a request or response. The return value is an associative array where
225
+ the keys represent the header name as it will be sent over the wire, and each
226
+ value is an array of strings associated with the header.
227
+
228
+ .. code-block:: php
229
+
230
+ $headers = $response->getHeaders();
231
+ foreach ($message->getHeaders() as $name => $values) {
232
+ echo $name . ": " . implode(", ", $values);
233
+ }
234
+
235
+ Modifying headers
236
+ -----------------
237
+
238
+ The headers of a message can be modified using the ``setHeader()``,
239
+ ``addHeader()``, ``setHeaders()``, and ``removeHeader()`` methods of a request
240
+ or response object.
241
+
242
+ .. code-block:: php
243
+
244
+ $request = $client->createRequest('GET', 'http://httpbin.org/get');
245
+
246
+ // Set a single value for a header
247
+ $request->setHeader('User-Agent', 'Testing!');
248
+
249
+ // Set multiple values for a header in one call
250
+ $request->setHeader('X-Foo', ['Baz', 'Bar']);
251
+
252
+ // Add a header to the message
253
+ $request->addHeader('X-Foo', 'Bam');
254
+
255
+ echo $request->getHeader('X-Foo');
256
+ // Baz, Bar, Bam
257
+
258
+ // Remove a specific header using a case-insensitive name
259
+ $request->removeHeader('x-foo');
260
+ echo $request->getHeader('X-Foo');
261
+ // Echoes an empty string: ''
262
+
263
+ Uploading Data
264
+ ==============
265
+
266
+ Guzzle provides several methods of uploading data.
267
+
268
+ You can send requests that contain a stream of data by passing a string,
269
+ resource returned from ``fopen``, or a ``GuzzleHttp\Stream\StreamInterface``
270
+ object to the ``body`` request option.
271
+
272
+ .. code-block:: php
273
+
274
+ $r = $client->post('http://httpbin.org/post', ['body' => 'raw data']);
275
+
276
+ You can easily upload JSON data using the ``json`` request option.
277
+
278
+ .. code-block:: php
279
+
280
+ $r = $client->put('http://httpbin.org/put', ['json' => ['foo' => 'bar']]);
281
+
282
+ POST Requests
283
+ -------------
284
+
285
+ In addition to specifying the raw data of a request using the ``body`` request
286
+ option, Guzzle provides helpful abstractions over sending POST data.
287
+
288
+ Sending POST Fields
289
+ ~~~~~~~~~~~~~~~~~~~
290
+
291
+ Sending ``application/x-www-form-urlencoded`` POST requests requires that you
292
+ specify the body of a POST request as an array.
293
+
294
+ .. code-block:: php
295
+
296
+ $response = $client->post('http://httpbin.org/post', [
297
+ 'body' => [
298
+ 'field_name' => 'abc',
299
+ 'other_field' => '123'
300
+ ]
301
+ ]);
302
+
303
+ You can also build up POST requests before sending them.
304
+
305
+ .. code-block:: php
306
+
307
+ $request = $client->createRequest('POST', 'http://httpbin.org/post');
308
+ $postBody = $request->getBody();
309
+
310
+ // $postBody is an instance of GuzzleHttp\Post\PostBodyInterface
311
+ $postBody->setField('foo', 'bar');
312
+ echo $postBody->getField('foo');
313
+ // 'bar'
314
+
315
+ echo json_encode($postBody->getFields());
316
+ // {"foo": "bar"}
317
+
318
+ // Send the POST request
319
+ $response = $client->send($request);
320
+
321
+ Sending POST Files
322
+ ~~~~~~~~~~~~~~~~~~
323
+
324
+ Sending ``multipart/form-data`` POST requests (POST requests that contain
325
+ files) is the same as sending ``application/x-www-form-urlencoded``, except
326
+ some of the array values of the POST fields map to PHP ``fopen`` resources, or
327
+ ``GuzzleHttp\Stream\StreamInterface``, or
328
+ ``GuzzleHttp\Post\PostFileInterface`` objects.
329
+
330
+ .. code-block:: php
331
+
332
+ use GuzzleHttp\Post\PostFile;
333
+
334
+ $response = $client->post('http://httpbin.org/post', [
335
+ 'body' => [
336
+ 'field_name' => 'abc',
337
+ 'file_filed' => fopen('/path/to/file', 'r'),
338
+ 'other_file' => new PostFile('other_file', 'this is the content')
339
+ ]
340
+ ]);
341
+
342
+ Just like when sending POST fields, you can also build up POST requests with
343
+ files before sending them.
344
+
345
+ .. code-block:: php
346
+
347
+ use GuzzleHttp\Post\PostFile;
348
+
349
+ $request = $client->createRequest('POST', 'http://httpbin.org/post');
350
+ $postBody = $request->getBody();
351
+ $postBody->setField('foo', 'bar');
352
+ $postBody->addFile(new PostFile('test', fopen('/path/to/file', 'r')));
353
+ $response = $client->send($request);
354
+
355
+ Cookies
356
+ =======
357
+
358
+ Guzzle can maintain a cookie session for you if instructed using the
359
+ ``cookies`` request option.
360
+
361
+ - Set to ``true`` to use a shared cookie session associated with the client.
362
+ - Pass an associative array containing cookies to send in the request and start
363
+ a new cookie session.
364
+ - Set to a ``GuzzleHttp\Subscriber\CookieJar\CookieJarInterface`` object to use
365
+ an existing cookie jar.
366
+
367
+ Redirects
368
+ =========
369
+
370
+ Guzzle will automatically follow redirects unless you tell it not to. You can
371
+ customize the redirect behavior using the ``allow_redirects`` request option.
372
+
373
+ - Set to true to enable normal redirects with a maximum number of 5 redirects.
374
+ This is the default setting.
375
+ - Set to false to disable redirects.
376
+ - Pass an associative array containing the 'max' key to specify the maximum
377
+ number of redirects and optionally provide a 'strict' key value to specify
378
+ whether or not to use strict RFC compliant redirects (meaning redirect POST
379
+ requests with POST requests vs. doing what most browsers do which is
380
+ redirect POST requests with GET requests).
381
+
382
+ .. code-block:: php
383
+
384
+ $response = $client->get('http://github.com');
385
+ echo $response->getStatusCode();
386
+ // 200
387
+ echo $response->getEffectiveUrl();
388
+ // 'https://github.com/'
389
+
390
+ The following example shows that redirects can be disabled.
391
+
392
+ .. code-block:: php
393
+
394
+ $response = $client->get('http://github.com', ['allow_redirects' => false]);
395
+ echo $response->getStatusCode();
396
+ // 301
397
+ echo $response->getEffectiveUrl();
398
+ // 'http://github.com/'
399
+
400
+ Exceptions
401
+ ==========
402
+
403
+ Guzzle throws exceptions for errors that occur during a transfer.
404
+
405
+ - In the event of a networking error (connection timeout, DNS errors, etc.),
406
+ a ``GuzzleHttp\Exception\RequestException`` is thrown. This exception
407
+ extends from ``GuzzleHttp\Exception\TransferException``. Catching this
408
+ exception will catch any exception that can be thrown while transferring
409
+ (non-parallel) requests.
410
+
411
+ .. code-block:: php
412
+
413
+ use GuzzleHttp\Exception\RequestException;
414
+
415
+ try {
416
+ $client->get('https://github.com/_abc_123_404');
417
+ } catch (RequestException $e) {
418
+ echo $e->getRequest();
419
+ if ($e->hasResponse()) {
420
+ echo $e->getResponse();
421
+ }
422
+ }
423
+
424
+ - A ``GuzzleHttp\Exception\ClientException`` is thrown for 400
425
+ level errors if the ``exceptions`` request option is set to true. This
426
+ exception extends from ``GuzzleHttp\Exception\BadResponseException`` and
427
+ ``GuzzleHttp\Exception\BadResponseException`` extends from
428
+ ``GuzzleHttp\Exception\RequestException``.
429
+
430
+ .. code-block:: php
431
+
432
+ use GuzzleHttp\Exception\ClientException;
433
+
434
+ try {
435
+ $client->get('https://github.com/_abc_123_404');
436
+ } catch (ClientException $e) {
437
+ echo $e->getRequest();
438
+ echo $e->getResponse();
439
+ }
440
+
441
+ - A ``GuzzleHttp\Exception\ServerException`` is thrown for 500 level
442
+ errors if the ``exceptions`` request option is set to true. This
443
+ exception extends from ``GuzzleHttp\Exception\BadResponseException``.
444
+ - A ``GuzzleHttp\Exception\TooManyRedirectsException`` is thrown when too
445
+ many redirects are followed. This exception extends from ``GuzzleHttp\Exception\RequestException``.
446
+
447
+ All of the above exceptions extend from
448
+ ``GuzzleHttp\Exception\TransferException``.
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
1
+ Sphinx>=1.2b1
2
+ guzzle_sphinx_theme>=0.6.0
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/streams.rst ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ Streams
3
+ =======
4
+
5
+ Guzzle uses stream objects to represent request and response message bodies.
6
+ These stream objects allow you to work with various types of data all using a
7
+ common interface.
8
+
9
+ HTTP messages consist of a start-line, headers, and a body. The body of an HTTP
10
+ message can be very small or extremely large. Attempting to represent the body
11
+ of a message as a string can easily consume more memory than intended because
12
+ the body must be stored completely in memory. Attempting to store the body of a
13
+ request or response in memory would preclude the use of that implementation from
14
+ being able to work with large message bodies. The StreamInterface is used in
15
+ order to hide the implementation details of where a stream of data is read from
16
+ or written to.
17
+
18
+ Guzzle's StreamInterface exposes several methods that enable streams to be read
19
+ from, written to, and traversed effectively.
20
+
21
+ Streams expose their capabilities using three methods: ``isReadable()``,
22
+ ``isWritable()``, and ``isSeekable()``. These methods can be used by stream
23
+ collaborators to determine if a stream is capable of their requirements.
24
+
25
+ Each stream instance has various capabilities: they can be read-only,
26
+ write-only, read-write, allow arbitrary random access (seeking forwards or
27
+ backwards to any location), or only allow sequential access (for example in the
28
+ case of a socket or pipe).
29
+
30
+ Creating Streams
31
+ ================
32
+
33
+ The best way to create a stream is using the static factory method,
34
+ ``GuzzleHttp\Stream\Stream::factory()``. This factory accepts strings,
35
+ resources returned from ``fopen()``, an object that implements
36
+ ``__toString()``, and an object that implements
37
+ ``GuzzleHttp\Stream\StreamInterface``.
38
+
39
+ .. code-block:: php
40
+
41
+ use GuzzleHttp\Stream\Stream;
42
+
43
+ $stream = Stream::factory('string data');
44
+ echo $stream;
45
+ // string data
46
+ echo $stream->read(3);
47
+ // str
48
+ echo $stream->getContents();
49
+ // ing data
50
+ var_export($stream->eof());
51
+ // true
52
+ var_export($stream->tell());
53
+ // 11
54
+
55
+ Metadata
56
+ ========
57
+
58
+ Guzzle streams expose stream metadata through the ``getMetadata()`` method.
59
+ This method provides the data you would retrieve when calling PHP's
60
+ `stream_get_meta_data() function <http://php.net/manual/en/function.stream-get-meta-data.php>`_,
61
+ and can optionally expose other custom data.
62
+
63
+ .. code-block:: php
64
+
65
+ use GuzzleHttp\Stream\Stream;
66
+
67
+ $resource = fopen('/path/to/file', 'r');
68
+ $stream = Stream::factory($resource);
69
+ echo $stream->getMetadata('uri');
70
+ // /path/to/file
71
+ var_export($stream->isReadable());
72
+ // true
73
+ var_export($stream->isWritable());
74
+ // false
75
+ var_export($stream->isSeekable());
76
+ // true
77
+
78
+ Stream Decorators
79
+ =================
80
+
81
+ With the small and focused interface, add custom functionality to streams is
82
+ very simple with stream decorators. Guzzle provides several built-in decorators
83
+ that provide additional stream functionality.
84
+
85
+ CachingStream
86
+ -------------
87
+
88
+ The CachingStream is used to allow seeking over previously read bytes on
89
+ non-seekable streams. This can be useful when transferring a non-seekable
90
+ entity body fails due to needing to rewind the stream (for example, resulting
91
+ from a redirect). Data that is read from the remote stream will be buffered in
92
+ a PHP temp stream so that previously read bytes are cached first in memory,
93
+ then on disk.
94
+
95
+ .. code-block:: php
96
+
97
+ use GuzzleHttp\Stream\Stream;
98
+ use GuzzleHttp\Stream\CachingStream;
99
+
100
+ $original = Stream::factory(fopen('http://www.google.com', 'r'));
101
+ $stream = new CachingStream($original);
102
+
103
+ $stream->read(1024);
104
+ echo $stream->tell();
105
+ // 1024
106
+
107
+ $stream->seek(0);
108
+ echo $stream->tell();
109
+ // 0
110
+
111
+ LimitStream
112
+ -----------
113
+
114
+ LimitStream can be used to read a subset or slice of an existing stream object.
115
+ This can be useful for breaking a large file into smaller pieces to be sent in
116
+ chunks (e.g. Amazon S3's multipart upload API).
117
+
118
+ .. code-block:: php
119
+
120
+ use GuzzleHttp\Stream\Stream;
121
+ use GuzzleHttp\Stream\LimitStream;
122
+
123
+ $original = Stream::factory(fopen('/tmp/test.txt', 'r+'));
124
+ echo $original->getSize();
125
+ // >>> 1048576
126
+
127
+ // Limit the size of the body to 1024 bytes and start reading from byte 2048
128
+ $stream = new LimitStream($original, 1024, 2048);
129
+ echo $stream->getSize();
130
+ // >>> 1024
131
+ echo $stream->tell();
132
+ // >>> 0
133
+
134
+ NoSeekStream
135
+ ------------
136
+
137
+ NoSeekStream wraps a stream and does not allow seeking.
138
+
139
+ .. code-block:: php
140
+
141
+ use GuzzleHttp\Stream\Stream;
142
+ use GuzzleHttp\Stream\LimitStream;
143
+
144
+ $original = Stream::factory('foo');
145
+ $noSeek = new NoSeekStream($original);
146
+
147
+ echo $noSeek->read(3);
148
+ // foo
149
+ var_export($noSeek->isSeekable());
150
+ // false
151
+ $noSeek->seek(0);
152
+ var_export($noSeek->read(3));
153
+ // NULL
154
+
155
+ Creating Custom Decorators
156
+ --------------------------
157
+
158
+ Creating a stream decorator is very easy thanks to the
159
+ ``GuzzleHttp\Stream\StreamDecoratorTrait``. This trait provides methods that
160
+ implement ``GuzzleHttp\Stream\StreamInterface`` by proxying to an underlying
161
+ stream. Just ``use`` the ``StreamDecoratorTrait`` and implement your custom
162
+ methods.
163
+
164
+ For example, let's say we wanted to call a specific function each time the last
165
+ byte is read from a stream. This could be implemented by overriding the
166
+ ``read()`` method.
167
+
168
+ .. code-block:: php
169
+
170
+ use GuzzleHttp\Stream\StreamDecoratorTrait;
171
+
172
+ class EofCallbackStream implements StreamInterface
173
+ {
174
+ use StreamDecoratorTrait;
175
+
176
+ private $callback;
177
+
178
+ public function __construct(StreamInterface $stream, callable $callback)
179
+ {
180
+ $this->stream = $stream;
181
+ $this->callback = $callback;
182
+ }
183
+
184
+ public function read($length)
185
+ {
186
+ $result = $this->stream->read($length);
187
+
188
+ // Invoke the callback when EOF is hit.
189
+ if ($this->eof()) {
190
+ call_user_func($this->callback);
191
+ }
192
+
193
+ return $result;
194
+ }
195
+ }
196
+
197
+ This decorator could be added to any existing stream and used like so:
198
+
199
+ .. code-block:: php
200
+
201
+ use GuzzleHttp\Stream\Stream;
202
+
203
+ $original = Stream::factory('foo');
204
+ $eofStream = new EofCallbackStream($original, function () {
205
+ echo 'EOF!';
206
+ });
207
+
208
+ $eofStream->read(2);
209
+ $eofStream->read(1);
210
+ // echoes "EOF!"
211
+ $eofStream->seek(0);
212
+ $eofStream->read(3);
213
+ // echoes "EOF!"
lib/KlarnaCheckout/guzzlehttp/guzzle/docs/testing.rst ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ======================
2
+ Testing Guzzle Clients
3
+ ======================
4
+
5
+ Guzzle provides several tools that will enable you to easily mock the HTTP
6
+ layer without needing to send requests over the internet.
7
+
8
+ * Mock subscriber
9
+ * Mock handler
10
+ * Node.js web server for integration testing
11
+
12
+ Mock Subscriber
13
+ ===============
14
+
15
+ When testing HTTP clients, you often need to simulate specific scenarios like
16
+ returning a successful response, returning an error, or returning specific
17
+ responses in a certain order. Because unit tests need to be predictable, easy
18
+ to bootstrap, and fast, hitting an actual remote API is a test smell.
19
+
20
+ Guzzle provides a mock subscriber that can be attached to clients or requests
21
+ that allows you to queue up a list of responses to use rather than hitting a
22
+ remote API.
23
+
24
+ .. code-block:: php
25
+
26
+ use GuzzleHttp\Client;
27
+ use GuzzleHttp\Subscriber\Mock;
28
+ use GuzzleHttp\Message\Response;
29
+
30
+ $client = new Client();
31
+
32
+ // Create a mock subscriber and queue two responses.
33
+ $mock = new Mock([
34
+ new Response(200, ['X-Foo' => 'Bar']), // Use response object
35
+ "HTTP/1.1 202 OK\r\nContent-Length: 0\r\n\r\n" // Use a response string
36
+ ]);
37
+
38
+ // Add the mock subscriber to the client.
39
+ $client->getEmitter()->attach($mock);
40
+ // The first request is intercepted with the first response.
41
+ echo $client->get('/')->getStatusCode();
42
+ //> 200
43
+ // The second request is intercepted with the second response.
44
+ echo $client->get('/')->getStatusCode();
45
+ //> 202
46
+
47
+ When no more responses are in the queue and a request is sent, an
48
+ ``OutOfBoundsException`` is thrown.
49
+
50
+ History Subscriber
51
+ ==================
52
+
53
+ When using things like the ``Mock`` subscriber, you often need to know if the
54
+ requests you expected to send were sent exactly as you intended. While the mock
55
+ subscriber responds with mocked responses, the ``GuzzleHttp\Subscriber\History``
56
+ subscriber maintains a history of the requests that were sent by a client.
57
+
58
+ .. code-block:: php
59
+
60
+ use GuzzleHttp\Client;
61
+ use GuzzleHttp\Subscriber\History;
62
+
63
+ $client = new Client();
64
+ $history = new History();
65
+
66
+ // Add the history subscriber to the client.
67
+ $client->getEmitter()->attach($history);
68
+
69
+ $client->get('http://httpbin.org/get');
70
+ $client->head('http://httpbin.org/get');
71
+
72
+ // Count the number of transactions
73
+ echo count($history);
74
+ //> 2
75
+ // Get the last request
76
+ $lastRequest = $history->getLastRequest();
77
+ // Get the last response
78
+ $lastResponse = $history->getLastResponse();
79
+
80
+ // Iterate over the transactions that were sent
81
+ foreach ($history as $transaction) {
82
+ echo $transaction['request']->getMethod();
83
+ //> GET, HEAD
84
+ echo $transaction['response']->getStatusCode();
85
+ //> 200, 200
86
+ }
87
+
88
+ The history subscriber can also be printed, revealing the requests and
89
+ responses that were sent as a string, in order.
90
+
91
+ .. code-block:: php
92
+
93
+ echo $history;
94
+
95
+ ::
96
+
97
+ > GET /get HTTP/1.1
98
+ Host: httpbin.org
99
+ User-Agent: Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8
100
+
101
+ < HTTP/1.1 200 OK
102
+ Access-Control-Allow-Origin: *
103
+ Content-Type: application/json
104
+ Date: Tue, 25 Mar 2014 03:53:27 GMT
105
+ Server: gunicorn/0.17.4
106
+ Content-Length: 270
107
+ Connection: keep-alive
108
+
109
+ {
110
+ "headers": {
111
+ "Connection": "close",
112
+ "X-Request-Id": "3d0f7d5c-c937-4394-8248-2b8e03fcccdb",
113
+ "User-Agent": "Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8",
114
+ "Host": "httpbin.org"
115
+ },
116
+ "origin": "76.104.247.1",
117
+ "args": {},
118
+ "url": "http://httpbin.org/get"
119
+ }
120
+
121
+ > HEAD /get HTTP/1.1
122
+ Host: httpbin.org
123
+ User-Agent: Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8
124
+
125
+ < HTTP/1.1 200 OK
126
+ Access-Control-Allow-Origin: *
127
+ Content-length: 270
128
+ Content-Type: application/json
129
+ Date: Tue, 25 Mar 2014 03:53:27 GMT
130
+ Server: gunicorn/0.17.4
131
+ Connection: keep-alive
132
+
133
+ Mock Adapter
134
+ ============
135
+
136
+ In addition to using the Mock subscriber, you can use the
137
+ ``GuzzleHttp\Ring\Client\MockHandler`` as the handler of a client to return the
138
+ same response over and over or return the result of a callable function.
139
+
140
+ Test Web Server
141
+ ===============
142
+
143
+ Using mock responses is almost always enough when testing a web service client.
144
+ When implementing custom :doc:`HTTP handlers <handlers>`, you'll need to send
145
+ actual HTTP requests in order to sufficiently test the handler. However, a
146
+ best practice is to contact a local web server rather than a server over the
147
+ internet.
148
+
149
+ - Tests are more reliable
150
+ - Tests do not require a network connection
151
+ - Tests have no external dependencies
152
+
153
+ Using the test server
154
+ ---------------------
155
+
156
+ .. warning::
157
+
158
+ The following functionality is provided to help developers of Guzzle
159
+ develop HTTP handlers. There is no promise of backwards compatibility
160
+ when it comes to the node.js test server or the ``GuzzleHttp\Tests\Server``
161
+ class. If you are using the test server or ``Server`` class outside of
162
+ guzzlehttp/guzzle, then you will need to configure autoloading and
163
+ ensure the web server is started manually.
164
+
165
+ .. hint::
166
+
167
+ You almost never need to use this test web server. You should only ever
168
+ consider using it when developing HTTP handlers. The test web server
169
+ is not necessary for mocking requests. For that, please use the
170
+ Mock subcribers and History subscriber.
171
+
172
+ Guzzle ships with a node.js test server that receives requests and returns
173
+ responses from a queue. The test server exposes a simple API that is used to
174
+ enqueue responses and inspect the requests that it has received.
175
+
176
+ Any operation on the ``Server`` object will ensure that
177
+ the server is running and wait until it is able to receive requests before
178
+ returning.
179
+
180
+ .. code-block:: php
181
+
182
+ use GuzzleHttp\Client;
183
+ use GuzzleHttp\Tests\Server;
184
+
185
+ // Start the server and queue a response
186
+ Server::enqueue("HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n");
187
+
188
+ $client = new Client(['base_url' => Server::$url]);
189
+ echo $client->get('/foo')->getStatusCode();
190
+ // 200
191
+
192
+ ``GuzzleHttp\Tests\Server`` provides a static interface to the test server. You
193
+ can queue an HTTP response or an array of responses by calling
194
+ ``Server::enqueue()``. This method accepts a string representing an HTTP
195
+ response message, a ``GuzzleHttp\Message\ResponseInterface``, or an array of
196
+ HTTP message strings / ``GuzzleHttp\Message\ResponseInterface`` objects.
197
+
198
+ .. code-block:: php
199
+
200
+ // Queue single response
201
+ Server::enqueue("HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n");
202
+
203
+ // Clear the queue and queue an array of responses
204
+ Server::enqueue([
205
+ "HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n",
206
+ "HTTP/1.1 404 Not Found\r\n\Content-Length: 0r\n\r\n"
207
+ ]);
208
+
209
+ When a response is queued on the test server, the test server will remove any
210
+ previously queued responses. As the server receives requests, queued responses
211
+ are dequeued and returned to the request. When the queue is empty, the server
212
+ will return a 500 response.
213
+
214
+ You can inspect the requests that the server has retrieved by calling
215
+ ``Server::received()``. This method accepts an optional ``$hydrate`` parameter
216
+ that specifies if you are retrieving an array of HTTP requests as strings or an
217
+ array of ``GuzzleHttp\Message\RequestInterface`` objects.
218
+
219
+ .. code-block:: php
220
+
221
+ foreach (Server::received() as $response) {
222
+ echo $response;
223
+ }
224
+
225
+ You can clear the list of received requests from the web server using the
226
+ ``Server::flush()`` method.
227
+
228
+ .. code-block:: php
229
+
230
+ Server::flush();
231
+ echo count(Server::received());
232
+ // 0
lib/KlarnaCheckout/guzzlehttp/guzzle/phpunit.xml.dist ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit bootstrap="./tests/bootstrap.php"
3
+ colors="true">
4
+ <testsuites>
5
+ <testsuite>
6
+ <directory>tests</directory>
7
+ </testsuite>
8
+ </testsuites>
9
+ <filter>
10
+ <whitelist>
11
+ <directory suffix=".php">src</directory>
12
+ <exclude>
13
+ <directory suffix="Interface.php">src/</directory>
14
+ </exclude>
15
+ </whitelist>
16
+ </filter>
17
+ </phpunit>
lib/KlarnaCheckout/guzzlehttp/guzzle/src/BatchResults.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Represents the result of a batch operation. This result container is
6
+ * iterable, countable, and you can can get a result by value using the
7
+ * getResult function.
8
+ *
9
+ * Successful results are anything other than exceptions. Failure results are
10
+ * exceptions.
11
+ *
12
+ * @package GuzzleHttp
13
+ */
14
+ class BatchResults implements \Countable, \IteratorAggregate, \ArrayAccess
15
+ {
16
+ private $hash;
17
+
18
+ /**
19
+ * @param \SplObjectStorage $hash Hash of key objects to result values.
20
+ */
21
+ public function __construct(\SplObjectStorage $hash)
22
+ {
23
+ $this->hash = $hash;
24
+ }
25
+
26
+ /**
27
+ * Get the keys that are available on the batch result.
28
+ *
29
+ * @return array
30
+ */
31
+ public function getKeys()
32
+ {
33
+ return iterator_to_array($this->hash);
34
+ }
35
+
36
+ /**
37
+ * Gets a result from the container for the given object. When getting
38
+ * results for a batch of requests, provide the request object.
39
+ *
40
+ * @param object $forObject Object to retrieve the result for.
41
+ *
42
+ * @return mixed|null
43
+ */
44
+ public function getResult($forObject)
45
+ {
46
+ return isset($this->hash[$forObject]) ? $this->hash[$forObject] : null;
47
+ }
48
+
49
+ /**
50
+ * Get an array of successful results.
51
+ *
52
+ * @return array
53
+ */
54
+ public function getSuccessful()
55
+ {
56
+ $results = [];
57
+ foreach ($this->hash as $key) {
58
+ if (!($this->hash[$key] instanceof \Exception)) {
59
+ $results[] = $this->hash[$key];
60
+ }
61
+ }
62
+
63
+ return $results;
64
+ }
65
+
66
+ /**
67
+ * Get an array of failed results.
68
+ *
69
+ * @return array
70
+ */
71
+ public function getFailures()
72
+ {
73
+ $results = [];
74
+ foreach ($this->hash as $key) {
75
+ if ($this->hash[$key] instanceof \Exception) {
76
+ $results[] = $this->hash[$key];
77
+ }
78
+ }
79
+
80
+ return $results;
81
+ }
82
+
83
+ /**
84
+ * Allows iteration over all batch result values.
85
+ *
86
+ * @return \ArrayIterator
87
+ */
88
+ public function getIterator()
89
+ {
90
+ $results = [];
91
+ foreach ($this->hash as $key) {
92
+ $results[] = $this->hash[$key];
93
+ }
94
+
95
+ return new \ArrayIterator($results);
96
+ }
97
+
98
+ /**
99
+ * Counts the number of elements in the batch result.
100
+ *
101
+ * @return int
102
+ */
103
+ public function count()
104
+ {
105
+ return count($this->hash);
106
+ }
107
+
108
+ /**
109
+ * Checks if the batch contains a specific numerical array index.
110
+ *
111
+ * @param int $key Index to access
112
+ *
113
+ * @return bool
114
+ */
115
+ public function offsetExists($key)
116
+ {
117
+ return $key < count($this->hash);
118
+ }
119
+
120
+ /**
121
+ * Allows access of the batch using a numerical array index.
122
+ *
123
+ * @param int $key Index to access.
124
+ *
125
+ * @return mixed|null
126
+ */
127
+ public function offsetGet($key)
128
+ {
129
+ $i = -1;
130
+ foreach ($this->hash as $obj) {
131
+ if ($key === ++$i) {
132
+ return $this->hash[$obj];
133
+ }
134
+ }
135
+
136
+ return null;
137
+ }
138
+
139
+ public function offsetUnset($key)
140
+ {
141
+ throw new \RuntimeException('Not implemented');
142
+ }
143
+
144
+ public function offsetSet($key, $value)
145
+ {
146
+ throw new \RuntimeException('Not implemented');
147
+ }
148
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Client.php ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\HasEmitterTrait;
5
+ use GuzzleHttp\Message\MessageFactory;
6
+ use GuzzleHttp\Message\MessageFactoryInterface;
7
+ use GuzzleHttp\Message\RequestInterface;
8
+ use GuzzleHttp\Message\FutureResponse;
9
+ use GuzzleHttp\Ring\Core;
10
+ use GuzzleHttp\Ring\Future\FutureInterface;
11
+ use GuzzleHttp\Exception\RequestException;
12
+ use React\Promise\FulfilledPromise;
13
+ use React\Promise\RejectedPromise;
14
+
15
+ /**
16
+ * HTTP client
17
+ */
18
+ class Client implements ClientInterface
19
+ {
20
+ use HasEmitterTrait;
21
+
22
+ /** @var MessageFactoryInterface Request factory used by the client */
23
+ private $messageFactory;
24
+
25
+ /** @var Url Base URL of the client */
26
+ private $baseUrl;
27
+
28
+ /** @var array Default request options */
29
+ private $defaults;
30
+
31
+ /** @var callable Request state machine */
32
+ private $fsm;
33
+
34
+ /**
35
+ * Clients accept an array of constructor parameters.
36
+ *
37
+ * Here's an example of creating a client using an URI template for the
38
+ * client's base_url and an array of default request options to apply
39
+ * to each request:
40
+ *
41
+ * $client = new Client([
42
+ * 'base_url' => [
43
+ * 'http://www.foo.com/{version}/',
44
+ * ['version' => '123']
45
+ * ],
46
+ * 'defaults' => [
47
+ * 'timeout' => 10,
48
+ * 'allow_redirects' => false,
49
+ * 'proxy' => '192.168.16.1:10'
50
+ * ]
51
+ * ]);
52
+ *
53
+ * @param array $config Client configuration settings
54
+ * - base_url: Base URL of the client that is merged into relative URLs.
55
+ * Can be a string or an array that contains a URI template followed
56
+ * by an associative array of expansion variables to inject into the
57
+ * URI template.
58
+ * - handler: callable RingPHP handler used to transfer requests
59
+ * - message_factory: Factory used to create request and response object
60
+ * - defaults: Default request options to apply to each request
61
+ * - emitter: Event emitter used for request events
62
+ * - fsm: (internal use only) The request finite state machine. A
63
+ * function that accepts a transaction and optional final state. The
64
+ * function is responsible for transitioning a request through its
65
+ * lifecycle events.
66
+ */
67
+ public function __construct(array $config = [])
68
+ {
69
+ $this->configureBaseUrl($config);
70
+ $this->configureDefaults($config);
71
+
72
+ if (isset($config['emitter'])) {
73
+ $this->emitter = $config['emitter'];
74
+ }
75
+
76
+ $this->messageFactory = isset($config['message_factory'])
77
+ ? $config['message_factory']
78
+ : new MessageFactory();
79
+
80
+ if (isset($config['fsm'])) {
81
+ $this->fsm = $config['fsm'];
82
+ } else {
83
+ if (isset($config['handler'])) {
84
+ $handler = $config['handler'];
85
+ } elseif (isset($config['adapter'])) {
86
+ $handler = $config['adapter'];
87
+ } else {
88
+ $handler = Utils::getDefaultHandler();
89
+ }
90
+ $this->fsm = new RequestFsm($handler, $this->messageFactory);
91
+ }
92
+ }
93
+
94
+ public function getDefaultOption($keyOrPath = null)
95
+ {
96
+ return $keyOrPath === null
97
+ ? $this->defaults
98
+ : Utils::getPath($this->defaults, $keyOrPath);
99
+ }
100
+
101
+ public function setDefaultOption($keyOrPath, $value)
102
+ {
103
+ Utils::setPath($this->defaults, $keyOrPath, $value);
104
+ }
105
+
106
+ public function getBaseUrl()
107
+ {
108
+ return (string) $this->baseUrl;
109
+ }
110
+
111
+ public function createRequest($method, $url = null, array $options = [])
112
+ {
113
+ $options = $this->mergeDefaults($options);
114
+ // Use a clone of the client's emitter
115
+ $options['config']['emitter'] = clone $this->getEmitter();
116
+ $url = $url || (is_string($url) && strlen($url))
117
+ ? $this->buildUrl($url)
118
+ : (string) $this->baseUrl;
119
+
120
+ return $this->messageFactory->createRequest($method, $url, $options);
121
+ }
122
+
123
+ public function get($url = null, $options = [])
124
+ {
125
+ return $this->send($this->createRequest('GET', $url, $options));
126
+ }
127
+
128
+ public function head($url = null, array $options = [])
129
+ {
130
+ return $this->send($this->createRequest('HEAD', $url, $options));
131
+ }
132
+
133
+ public function delete($url = null, array $options = [])
134
+ {
135
+ return $this->send($this->createRequest('DELETE', $url, $options));
136
+ }
137
+
138
+ public function put($url = null, array $options = [])
139
+ {
140
+ return $this->send($this->createRequest('PUT', $url, $options));
141
+ }
142
+
143
+ public function patch($url = null, array $options = [])
144
+ {
145
+ return $this->send($this->createRequest('PATCH', $url, $options));
146
+ }
147
+
148
+ public function post($url = null, array $options = [])
149
+ {
150
+ return $this->send($this->createRequest('POST', $url, $options));
151
+ }
152
+
153
+ public function options($url = null, array $options = [])
154
+ {
155
+ return $this->send($this->createRequest('OPTIONS', $url, $options));
156
+ }
157
+
158
+ public function send(RequestInterface $request)
159
+ {
160
+ $isFuture = $request->getConfig()->get('future');
161
+ $trans = new Transaction($this, $request, $isFuture);
162
+ $fn = $this->fsm;
163
+
164
+ try {
165
+ $fn($trans);
166
+ if ($isFuture) {
167
+ // Turn the normal response into a future if needed.
168
+ return $trans->response instanceof FutureInterface
169
+ ? $trans->response
170
+ : new FutureResponse(new FulfilledPromise($trans->response));
171
+ }
172
+ // Resolve deep futures if this is not a future
173
+ // transaction. This accounts for things like retries
174
+ // that do not have an immediate side-effect.
175
+ while ($trans->response instanceof FutureInterface) {
176
+ $trans->response = $trans->response->wait();
177
+ }
178
+ return $trans->response;
179
+ } catch (\Exception $e) {
180
+ if ($isFuture) {
181
+ // Wrap the exception in a promise
182
+ return new FutureResponse(new RejectedPromise($e));
183
+ }
184
+ throw RequestException::wrapException($trans->request, $e);
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Get an array of default options to apply to the client
190
+ *
191
+ * @return array
192
+ */
193
+ protected function getDefaultOptions()
194
+ {
195
+ $settings = [
196
+ 'allow_redirects' => true,
197
+ 'exceptions' => true,
198
+ 'decode_content' => true,
199
+ 'verify' => true
200
+ ];
201
+
202
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
203
+ if ($proxy = getenv('HTTP_PROXY')) {
204
+ $settings['proxy']['http'] = $proxy;
205
+ }
206
+
207
+ if ($proxy = getenv('HTTPS_PROXY')) {
208
+ $settings['proxy']['https'] = $proxy;
209
+ }
210
+
211
+ return $settings;
212
+ }
213
+
214
+ /**
215
+ * Expand a URI template and inherit from the base URL if it's relative
216
+ *
217
+ * @param string|array $url URL or an array of the URI template to expand
218
+ * followed by a hash of template varnames.
219
+ * @return string
220
+ * @throws \InvalidArgumentException
221
+ */
222
+ private function buildUrl($url)
223
+ {
224
+ // URI template (absolute or relative)
225
+ if (!is_array($url)) {
226
+ return strpos($url, '://')
227
+ ? (string) $url
228
+ : (string) $this->baseUrl->combine($url);
229
+ }
230
+
231
+ if (!isset($url[1])) {
232
+ throw new \InvalidArgumentException('You must provide a hash of '
233
+ . 'varname options in the second element of a URL array.');
234
+ }
235
+
236
+ // Absolute URL
237
+ if (strpos($url[0], '://')) {
238
+ return Utils::uriTemplate($url[0], $url[1]);
239
+ }
240
+
241
+ // Combine the relative URL with the base URL
242
+ return (string) $this->baseUrl->combine(
243
+ Utils::uriTemplate($url[0], $url[1])
244
+ );
245
+ }
246
+
247
+ private function configureBaseUrl(&$config)
248
+ {
249
+ if (!isset($config['base_url'])) {
250
+ $this->baseUrl = new Url('', '');
251
+ } elseif (!is_array($config['base_url'])) {
252
+ $this->baseUrl = Url::fromString($config['base_url']);
253
+ } elseif (count($config['base_url']) < 2) {
254
+ throw new \InvalidArgumentException('You must provide a hash of '
255
+ . 'varname options in the second element of a base_url array.');
256
+ } else {
257
+ $this->baseUrl = Url::fromString(
258
+ Utils::uriTemplate(
259
+ $config['base_url'][0],
260
+ $config['base_url'][1]
261
+ )
262
+ );
263
+ $config['base_url'] = (string) $this->baseUrl;
264
+ }
265
+ }
266
+
267
+ private function configureDefaults($config)
268
+ {
269
+ if (!isset($config['defaults'])) {
270
+ $this->defaults = $this->getDefaultOptions();
271
+ } else {
272
+ $this->defaults = array_replace(
273
+ $this->getDefaultOptions(),
274
+ $config['defaults']
275
+ );
276
+ }
277
+
278
+ // Add the default user-agent header
279
+ if (!isset($this->defaults['headers'])) {
280
+ $this->defaults['headers'] = [
281
+ 'User-Agent' => Utils::getDefaultUserAgent()
282
+ ];
283
+ } elseif (!Core::hasHeader($this->defaults, 'User-Agent')) {
284
+ // Add the User-Agent header if one was not already set
285
+ $this->defaults['headers']['User-Agent'] = Utils::getDefaultUserAgent();
286
+ }
287
+ }
288
+
289
+ /**
290
+ * Merges default options into the array passed by reference.
291
+ *
292
+ * @param array $options Options to modify by reference
293
+ *
294
+ * @return array
295
+ */
296
+ private function mergeDefaults($options)
297
+ {
298
+ $defaults = $this->defaults;
299
+
300
+ // Case-insensitively merge in default headers if both defaults and
301
+ // options have headers specified.
302
+ if (!empty($defaults['headers']) && !empty($options['headers'])) {
303
+ // Create a set of lowercased keys that are present.
304
+ $lkeys = [];
305
+ foreach (array_keys($options['headers']) as $k) {
306
+ $lkeys[strtolower($k)] = true;
307
+ }
308
+ // Merge in lowercase default keys when not present in above set.
309
+ foreach ($defaults['headers'] as $key => $value) {
310
+ if (!isset($lkeys[strtolower($key)])) {
311
+ $options['headers'][$key] = $value;
312
+ }
313
+ }
314
+ // No longer need to merge in headers.
315
+ unset($defaults['headers']);
316
+ }
317
+
318
+ $result = array_replace_recursive($defaults, $options);
319
+ foreach ($options as $k => $v) {
320
+ if ($v === null) {
321
+ unset($result[$k]);
322
+ }
323
+ }
324
+
325
+ return $result;
326
+ }
327
+
328
+ /**
329
+ * @deprecated Use {@see GuzzleHttp\Pool} instead.
330
+ * @see GuzzleHttp\Pool
331
+ */
332
+ public function sendAll($requests, array $options = [])
333
+ {
334
+ Pool::send($this, $requests, $options);
335
+ }
336
+
337
+ /**
338
+ * @deprecated Use GuzzleHttp\Utils::getDefaultHandler
339
+ */
340
+ public static function getDefaultHandler()
341
+ {
342
+ return Utils::getDefaultHandler();
343
+ }
344
+
345
+ /**
346
+ * @deprecated Use GuzzleHttp\Utils::getDefaultUserAgent
347
+ */
348
+ public static function getDefaultUserAgent()
349
+ {
350
+ return Utils::getDefaultUserAgent();
351
+ }
352
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/ClientInterface.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\HasEmitterInterface;
5
+ use GuzzleHttp\Exception\RequestException;
6
+ use GuzzleHttp\Message\RequestInterface;
7
+ use GuzzleHttp\Message\ResponseInterface;
8
+
9
+ /**
10
+ * Client interface for sending HTTP requests
11
+ */
12
+ interface ClientInterface extends HasEmitterInterface
13
+ {
14
+ const VERSION = '5.3.0';
15
+
16
+ /**
17
+ * Create and return a new {@see RequestInterface} object.
18
+ *
19
+ * Use an absolute path to override the base path of the client, or a
20
+ * relative path to append to the base path of the client. The URL can
21
+ * contain the query string as well. Use an array to provide a URL
22
+ * template and additional variables to use in the URL template expansion.
23
+ *
24
+ * @param string $method HTTP method
25
+ * @param string|array|Url $url URL or URI template
26
+ * @param array $options Array of request options to apply.
27
+ *
28
+ * @return RequestInterface
29
+ */
30
+ public function createRequest($method, $url = null, array $options = []);
31
+
32
+ /**
33
+ * Send a GET request
34
+ *
35
+ * @param string|array|Url $url URL or URI template
36
+ * @param array $options Array of request options to apply.
37
+ *
38
+ * @return ResponseInterface
39
+ * @throws RequestException When an error is encountered
40
+ */
41
+ public function get($url = null, $options = []);
42
+
43
+ /**
44
+ * Send a HEAD request
45
+ *
46
+ * @param string|array|Url $url URL or URI template
47
+ * @param array $options Array of request options to apply.
48
+ *
49
+ * @return ResponseInterface
50
+ * @throws RequestException When an error is encountered
51
+ */
52
+ public function head($url = null, array $options = []);
53
+
54
+ /**
55
+ * Send a DELETE request
56
+ *
57
+ * @param string|array|Url $url URL or URI template
58
+ * @param array $options Array of request options to apply.
59
+ *
60
+ * @return ResponseInterface
61
+ * @throws RequestException When an error is encountered
62
+ */
63
+ public function delete($url = null, array $options = []);
64
+
65
+ /**
66
+ * Send a PUT request
67
+ *
68
+ * @param string|array|Url $url URL or URI template
69
+ * @param array $options Array of request options to apply.
70
+ *
71
+ * @return ResponseInterface
72
+ * @throws RequestException When an error is encountered
73
+ */
74
+ public function put($url = null, array $options = []);
75
+
76
+ /**
77
+ * Send a PATCH request
78
+ *
79
+ * @param string|array|Url $url URL or URI template
80
+ * @param array $options Array of request options to apply.
81
+ *
82
+ * @return ResponseInterface
83
+ * @throws RequestException When an error is encountered
84
+ */
85
+ public function patch($url = null, array $options = []);
86
+
87
+ /**
88
+ * Send a POST request
89
+ *
90
+ * @param string|array|Url $url URL or URI template
91
+ * @param array $options Array of request options to apply.
92
+ *
93
+ * @return ResponseInterface
94
+ * @throws RequestException When an error is encountered
95
+ */
96
+ public function post($url = null, array $options = []);
97
+
98
+ /**
99
+ * Send an OPTIONS request
100
+ *
101
+ * @param string|array|Url $url URL or URI template
102
+ * @param array $options Array of request options to apply.
103
+ *
104
+ * @return ResponseInterface
105
+ * @throws RequestException When an error is encountered
106
+ */
107
+ public function options($url = null, array $options = []);
108
+
109
+ /**
110
+ * Sends a single request
111
+ *
112
+ * @param RequestInterface $request Request to send
113
+ *
114
+ * @return \GuzzleHttp\Message\ResponseInterface
115
+ * @throws \LogicException When the handler does not populate a response
116
+ * @throws RequestException When an error is encountered
117
+ */
118
+ public function send(RequestInterface $request);
119
+
120
+ /**
121
+ * Get default request options of the client.
122
+ *
123
+ * @param string|null $keyOrPath The Path to a particular default request
124
+ * option to retrieve or pass null to retrieve all default request
125
+ * options. The syntax uses "/" to denote a path through nested PHP
126
+ * arrays. For example, "headers/content-type".
127
+ *
128
+ * @return mixed
129
+ */
130
+ public function getDefaultOption($keyOrPath = null);
131
+
132
+ /**
133
+ * Set a default request option on the client so that any request created
134
+ * by the client will use the provided default value unless overridden
135
+ * explicitly when creating a request.
136
+ *
137
+ * @param string|null $keyOrPath The Path to a particular configuration
138
+ * value to set. The syntax uses a path notation that allows you to
139
+ * specify nested configuration values (e.g., 'headers/content-type').
140
+ * @param mixed $value Default request option value to set
141
+ */
142
+ public function setDefaultOption($keyOrPath, $value);
143
+
144
+ /**
145
+ * Get the base URL of the client.
146
+ *
147
+ * @return string Returns the base URL if present
148
+ */
149
+ public function getBaseUrl();
150
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Collection.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Key value pair collection object
6
+ */
7
+ class Collection implements
8
+ \ArrayAccess,
9
+ \IteratorAggregate,
10
+ \Countable,
11
+ ToArrayInterface
12
+ {
13
+ use HasDataTrait;
14
+
15
+ /**
16
+ * @param array $data Associative array of data to set
17
+ */
18
+ public function __construct(array $data = [])
19
+ {
20
+ $this->data = $data;
21
+ }
22
+
23
+ /**
24
+ * Create a new collection from an array, validate the keys, and add default
25
+ * values where missing
26
+ *
27
+ * @param array $config Configuration values to apply.
28
+ * @param array $defaults Default parameters
29
+ * @param array $required Required parameter names
30
+ *
31
+ * @return self
32
+ * @throws \InvalidArgumentException if a parameter is missing
33
+ */
34
+ public static function fromConfig(
35
+ array $config = [],
36
+ array $defaults = [],
37
+ array $required = []
38
+ ) {
39
+ $data = $config + $defaults;
40
+
41
+ if ($missing = array_diff($required, array_keys($data))) {
42
+ throw new \InvalidArgumentException(
43
+ 'Config is missing the following keys: ' .
44
+ implode(', ', $missing));
45
+ }
46
+
47
+ return new self($data);
48
+ }
49
+
50
+ /**
51
+ * Removes all key value pairs
52
+ */
53
+ public function clear()
54
+ {
55
+ $this->data = [];
56
+ }
57
+
58
+ /**
59
+ * Get a specific key value.
60
+ *
61
+ * @param string $key Key to retrieve.
62
+ *
63
+ * @return mixed|null Value of the key or NULL
64
+ */
65
+ public function get($key)
66
+ {
67
+ return isset($this->data[$key]) ? $this->data[$key] : null;
68
+ }
69
+
70
+ /**
71
+ * Set a key value pair
72
+ *
73
+ * @param string $key Key to set
74
+ * @param mixed $value Value to set
75
+ */
76
+ public function set($key, $value)
77
+ {
78
+ $this->data[$key] = $value;
79
+ }
80
+
81
+ /**
82
+ * Add a value to a key. If a key of the same name has already been added,
83
+ * the key value will be converted into an array and the new value will be
84
+ * pushed to the end of the array.
85
+ *
86
+ * @param string $key Key to add
87
+ * @param mixed $value Value to add to the key
88
+ */
89
+ public function add($key, $value)
90
+ {
91
+ if (!array_key_exists($key, $this->data)) {
92
+ $this->data[$key] = $value;
93
+ } elseif (is_array($this->data[$key])) {
94
+ $this->data[$key][] = $value;
95
+ } else {
96
+ $this->data[$key] = array($this->data[$key], $value);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Remove a specific key value pair
102
+ *
103
+ * @param string $key A key to remove
104
+ */
105
+ public function remove($key)
106
+ {
107
+ unset($this->data[$key]);
108
+ }
109
+
110
+ /**
111
+ * Get all keys in the collection
112
+ *
113
+ * @return array
114
+ */
115
+ public function getKeys()
116
+ {
117
+ return array_keys($this->data);
118
+ }
119
+
120
+ /**
121
+ * Returns whether or not the specified key is present.
122
+ *
123
+ * @param string $key The key for which to check the existence.
124
+ *
125
+ * @return bool
126
+ */
127
+ public function hasKey($key)
128
+ {
129
+ return array_key_exists($key, $this->data);
130
+ }
131
+
132
+ /**
133
+ * Checks if any keys contains a certain value
134
+ *
135
+ * @param string $value Value to search for
136
+ *
137
+ * @return mixed Returns the key if the value was found FALSE if the value
138
+ * was not found.
139
+ */
140
+ public function hasValue($value)
141
+ {
142
+ return array_search($value, $this->data, true);
143
+ }
144
+
145
+ /**
146
+ * Replace the data of the object with the value of an array
147
+ *
148
+ * @param array $data Associative array of data
149
+ */
150
+ public function replace(array $data)
151
+ {
152
+ $this->data = $data;
153
+ }
154
+
155
+ /**
156
+ * Add and merge in a Collection or array of key value pair data.
157
+ *
158
+ * @param Collection|array $data Associative array of key value pair data
159
+ */
160
+ public function merge($data)
161
+ {
162
+ foreach ($data as $key => $value) {
163
+ $this->add($key, $value);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Overwrite key value pairs in this collection with all of the data from
169
+ * an array or collection.
170
+ *
171
+ * @param array|\Traversable $data Values to override over this config
172
+ */
173
+ public function overwriteWith($data)
174
+ {
175
+ if (is_array($data)) {
176
+ $this->data = $data + $this->data;
177
+ } elseif ($data instanceof Collection) {
178
+ $this->data = $data->toArray() + $this->data;
179
+ } else {
180
+ foreach ($data as $key => $value) {
181
+ $this->data[$key] = $value;
182
+ }
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Returns a Collection containing all the elements of the collection after
188
+ * applying the callback function to each one.
189
+ *
190
+ * The callable should accept three arguments:
191
+ * - (string) $key
192
+ * - (string) $value
193
+ * - (array) $context
194
+ *
195
+ * The callable must return a the altered or unaltered value.
196
+ *
197
+ * @param callable $closure Map function to apply
198
+ * @param array $context Context to pass to the callable
199
+ *
200
+ * @return Collection
201
+ */
202
+ public function map(callable $closure, array $context = [])
203
+ {
204
+ $collection = new static();
205
+ foreach ($this as $key => $value) {
206
+ $collection[$key] = $closure($key, $value, $context);
207
+ }
208
+
209
+ return $collection;
210
+ }
211
+
212
+ /**
213
+ * Iterates over each key value pair in the collection passing them to the
214
+ * callable. If the callable returns true, the current value from input is
215
+ * returned into the result Collection.
216
+ *
217
+ * The callable must accept two arguments:
218
+ * - (string) $key
219
+ * - (string) $value
220
+ *
221
+ * @param callable $closure Evaluation function
222
+ *
223
+ * @return Collection
224
+ */
225
+ public function filter(callable $closure)
226
+ {
227
+ $collection = new static();
228
+ foreach ($this->data as $key => $value) {
229
+ if ($closure($key, $value)) {
230
+ $collection[$key] = $value;
231
+ }
232
+ }
233
+
234
+ return $collection;
235
+ }
236
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/CookieJar.php ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+ use GuzzleHttp\ToArrayInterface;
7
+
8
+ /**
9
+ * Cookie jar that stores cookies an an array
10
+ */
11
+ class CookieJar implements CookieJarInterface, ToArrayInterface
12
+ {
13
+ /** @var SetCookie[] Loaded cookie data */
14
+ private $cookies = [];
15
+
16
+ /** @var bool */
17
+ private $strictMode;
18
+
19
+ /**
20
+ * @param bool $strictMode Set to true to throw exceptions when invalid
21
+ * cookies are added to the cookie jar.
22
+ * @param array $cookieArray Array of SetCookie objects or a hash of arrays
23
+ * that can be used with the SetCookie constructor
24
+ */
25
+ public function __construct($strictMode = false, $cookieArray = [])
26
+ {
27
+ $this->strictMode = $strictMode;
28
+
29
+ foreach ($cookieArray as $cookie) {
30
+ if (!($cookie instanceof SetCookie)) {
31
+ $cookie = new SetCookie($cookie);
32
+ }
33
+ $this->setCookie($cookie);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Create a new Cookie jar from an associative array and domain.
39
+ *
40
+ * @param array $cookies Cookies to create the jar from
41
+ * @param string $domain Domain to set the cookies to
42
+ *
43
+ * @return self
44
+ */
45
+ public static function fromArray(array $cookies, $domain)
46
+ {
47
+ $cookieJar = new self();
48
+ foreach ($cookies as $name => $value) {
49
+ $cookieJar->setCookie(new SetCookie([
50
+ 'Domain' => $domain,
51
+ 'Name' => $name,
52
+ 'Value' => $value,
53
+ 'Discard' => true
54
+ ]));
55
+ }
56
+
57
+ return $cookieJar;
58
+ }
59
+
60
+ /**
61
+ * Quote the cookie value if it is not already quoted and it contains
62
+ * problematic characters.
63
+ *
64
+ * @param string $value Value that may or may not need to be quoted
65
+ *
66
+ * @return string
67
+ */
68
+ public static function getCookieValue($value)
69
+ {
70
+ if (substr($value, 0, 1) !== '"' &&
71
+ substr($value, -1, 1) !== '"' &&
72
+ strpbrk($value, ';,')
73
+ ) {
74
+ $value = '"' . $value . '"';
75
+ }
76
+
77
+ return $value;
78
+ }
79
+
80
+ public function toArray()
81
+ {
82
+ return array_map(function (SetCookie $cookie) {
83
+ return $cookie->toArray();
84
+ }, $this->getIterator()->getArrayCopy());
85
+ }
86
+
87
+ public function clear($domain = null, $path = null, $name = null)
88
+ {
89
+ if (!$domain) {
90
+ $this->cookies = [];
91
+ return;
92
+ } elseif (!$path) {
93
+ $this->cookies = array_filter(
94
+ $this->cookies,
95
+ function (SetCookie $cookie) use ($path, $domain) {
96
+ return !$cookie->matchesDomain($domain);
97
+ }
98
+ );
99
+ } elseif (!$name) {
100
+ $this->cookies = array_filter(
101
+ $this->cookies,
102
+ function (SetCookie $cookie) use ($path, $domain) {
103
+ return !($cookie->matchesPath($path) &&
104
+ $cookie->matchesDomain($domain));
105
+ }
106
+ );
107
+ } else {
108
+ $this->cookies = array_filter(
109
+ $this->cookies,
110
+ function (SetCookie $cookie) use ($path, $domain, $name) {
111
+ return !($cookie->getName() == $name &&
112
+ $cookie->matchesPath($path) &&
113
+ $cookie->matchesDomain($domain));
114
+ }
115
+ );
116
+ }
117
+ }
118
+
119
+ public function clearSessionCookies()
120
+ {
121
+ $this->cookies = array_filter(
122
+ $this->cookies,
123
+ function (SetCookie $cookie) {
124
+ return !$cookie->getDiscard() && $cookie->getExpires();
125
+ }
126
+ );
127
+ }
128
+
129
+ public function setCookie(SetCookie $cookie)
130
+ {
131
+ // Only allow cookies with set and valid domain, name, value
132
+ $result = $cookie->validate();
133
+ if ($result !== true) {
134
+ if ($this->strictMode) {
135
+ throw new \RuntimeException('Invalid cookie: ' . $result);
136
+ } else {
137
+ $this->removeCookieIfEmpty($cookie);
138
+ return false;
139
+ }
140
+ }
141
+
142
+ // Resolve conflicts with previously set cookies
143
+ foreach ($this->cookies as $i => $c) {
144
+
145
+ // Two cookies are identical, when their path, and domain are
146
+ // identical.
147
+ if ($c->getPath() != $cookie->getPath() ||
148
+ $c->getDomain() != $cookie->getDomain() ||
149
+ $c->getName() != $cookie->getName()
150
+ ) {
151
+ continue;
152
+ }
153
+
154
+ // The previously set cookie is a discard cookie and this one is
155
+ // not so allow the new cookie to be set
156
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
157
+ unset($this->cookies[$i]);
158
+ continue;
159
+ }
160
+
161
+ // If the new cookie's expiration is further into the future, then
162
+ // replace the old cookie
163
+ if ($cookie->getExpires() > $c->getExpires()) {
164
+ unset($this->cookies[$i]);
165
+ continue;
166
+ }
167
+
168
+ // If the value has changed, we better change it
169
+ if ($cookie->getValue() !== $c->getValue()) {
170
+ unset($this->cookies[$i]);
171
+ continue;
172
+ }
173
+
174
+ // The cookie exists, so no need to continue
175
+ return false;
176
+ }
177
+
178
+ $this->cookies[] = $cookie;
179
+
180
+ return true;
181
+ }
182
+
183
+ public function count()
184
+ {
185
+ return count($this->cookies);
186
+ }
187
+
188
+ public function getIterator()
189
+ {
190
+ return new \ArrayIterator(array_values($this->cookies));
191
+ }
192
+
193
+ public function extractCookies(
194
+ RequestInterface $request,
195
+ ResponseInterface $response
196
+ ) {
197
+ if ($cookieHeader = $response->getHeaderAsArray('Set-Cookie')) {
198
+ foreach ($cookieHeader as $cookie) {
199
+ $sc = SetCookie::fromString($cookie);
200
+ if (!$sc->getDomain()) {
201
+ $sc->setDomain($request->getHost());
202
+ }
203
+ $this->setCookie($sc);
204
+ }
205
+ }
206
+ }
207
+
208
+ public function addCookieHeader(RequestInterface $request)
209
+ {
210
+ $values = [];
211
+ $scheme = $request->getScheme();
212
+ $host = $request->getHost();
213
+ $path = $request->getPath();
214
+
215
+ foreach ($this->cookies as $cookie) {
216
+ if ($cookie->matchesPath($path) &&
217
+ $cookie->matchesDomain($host) &&
218
+ !$cookie->isExpired() &&
219
+ (!$cookie->getSecure() || $scheme == 'https')
220
+ ) {
221
+ $values[] = $cookie->getName() . '='
222
+ . self::getCookieValue($cookie->getValue());
223
+ }
224
+ }
225
+
226
+ if ($values) {
227
+ $request->setHeader('Cookie', implode('; ', $values));
228
+ }
229
+ }
230
+
231
+ /**
232
+ * If a cookie already exists and the server asks to set it again with a
233
+ * null value, the cookie must be deleted.
234
+ *
235
+ * @param SetCookie $cookie
236
+ */
237
+ private function removeCookieIfEmpty(SetCookie $cookie)
238
+ {
239
+ $cookieValue = $cookie->getValue();
240
+ if ($cookieValue === null || $cookieValue === '') {
241
+ $this->clear(
242
+ $cookie->getDomain(),
243
+ $cookie->getPath(),
244
+ $cookie->getName()
245
+ );
246
+ }
247
+ }
248
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Stores HTTP cookies.
9
+ *
10
+ * It extracts cookies from HTTP requests, and returns them in HTTP responses.
11
+ * CookieJarInterface instances automatically expire contained cookies when
12
+ * necessary. Subclasses are also responsible for storing and retrieving
13
+ * cookies from a file, database, etc.
14
+ *
15
+ * @link http://docs.python.org/2/library/cookielib.html Inspiration
16
+ */
17
+ interface CookieJarInterface extends \Countable, \IteratorAggregate
18
+ {
19
+ /**
20
+ * Add a Cookie header to a request.
21
+ *
22
+ * If no matching cookies are found in the cookie jar, then no Cookie
23
+ * header is added to the request.
24
+ *
25
+ * @param RequestInterface $request Request object to update
26
+ */
27
+ public function addCookieHeader(RequestInterface $request);
28
+
29
+ /**
30
+ * Extract cookies from an HTTP response and store them in the CookieJar.
31
+ *
32
+ * @param RequestInterface $request Request that was sent
33
+ * @param ResponseInterface $response Response that was received
34
+ */
35
+ public function extractCookies(
36
+ RequestInterface $request,
37
+ ResponseInterface $response
38
+ );
39
+
40
+ /**
41
+ * Sets a cookie in the cookie jar.
42
+ *
43
+ * @param SetCookie $cookie Cookie to set.
44
+ *
45
+ * @return bool Returns true on success or false on failure
46
+ */
47
+ public function setCookie(SetCookie $cookie);
48
+
49
+ /**
50
+ * Remove cookies currently held in the cookie jar.
51
+ *
52
+ * Invoking this method without arguments will empty the whole cookie jar.
53
+ * If given a $domain argument only cookies belonging to that domain will
54
+ * be removed. If given a $domain and $path argument, cookies belonging to
55
+ * the specified path within that domain are removed. If given all three
56
+ * arguments, then the cookie with the specified name, path and domain is
57
+ * removed.
58
+ *
59
+ * @param string $domain Clears cookies matching a domain
60
+ * @param string $path Clears cookies matching a domain and path
61
+ * @param string $name Clears cookies matching a domain, path, and name
62
+ *
63
+ * @return CookieJarInterface
64
+ */
65
+ public function clear($domain = null, $path = null, $name = null);
66
+
67
+ /**
68
+ * Discard all sessions cookies.
69
+ *
70
+ * Removes cookies that don't have an expire field or a have a discard
71
+ * field set to true. To be called when the user agent shuts down according
72
+ * to RFC 2965.
73
+ */
74
+ public function clearSessionCookies();
75
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Utils;
5
+
6
+ /**
7
+ * Persists non-session cookies using a JSON formatted file
8
+ */
9
+ class FileCookieJar extends CookieJar
10
+ {
11
+ /** @var string filename */
12
+ private $filename;
13
+
14
+ /**
15
+ * Create a new FileCookieJar object
16
+ *
17
+ * @param string $cookieFile File to store the cookie data
18
+ *
19
+ * @throws \RuntimeException if the file cannot be found or created
20
+ */
21
+ public function __construct($cookieFile)
22
+ {
23
+ $this->filename = $cookieFile;
24
+
25
+ if (file_exists($cookieFile)) {
26
+ $this->load($cookieFile);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Saves the file when shutting down
32
+ */
33
+ public function __destruct()
34
+ {
35
+ $this->save($this->filename);
36
+ }
37
+
38
+ /**
39
+ * Saves the cookies to a file.
40
+ *
41
+ * @param string $filename File to save
42
+ * @throws \RuntimeException if the file cannot be found or created
43
+ */
44
+ public function save($filename)
45
+ {
46
+ $json = [];
47
+ foreach ($this as $cookie) {
48
+ if ($cookie->getExpires() && !$cookie->getDiscard()) {
49
+ $json[] = $cookie->toArray();
50
+ }
51
+ }
52
+
53
+ if (false === file_put_contents($filename, json_encode($json))) {
54
+ // @codeCoverageIgnoreStart
55
+ throw new \RuntimeException("Unable to save file {$filename}");
56
+ // @codeCoverageIgnoreEnd
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Load cookies from a JSON formatted file.
62
+ *
63
+ * Old cookies are kept unless overwritten by newly loaded ones.
64
+ *
65
+ * @param string $filename Cookie file to load.
66
+ * @throws \RuntimeException if the file cannot be loaded.
67
+ */
68
+ public function load($filename)
69
+ {
70
+ $json = file_get_contents($filename);
71
+ if (false === $json) {
72
+ // @codeCoverageIgnoreStart
73
+ throw new \RuntimeException("Unable to load file {$filename}");
74
+ // @codeCoverageIgnoreEnd
75
+ }
76
+
77
+ $data = Utils::jsonDecode($json, true);
78
+ if (is_array($data)) {
79
+ foreach (Utils::jsonDecode($json, true) as $cookie) {
80
+ $this->setCookie(new SetCookie($cookie));
81
+ }
82
+ } elseif (strlen($data)) {
83
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
84
+ }
85
+ }
86
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\Utils;
5
+
6
+ /**
7
+ * Persists cookies in the client session
8
+ */
9
+ class SessionCookieJar extends CookieJar
10
+ {
11
+ /** @var string session key */
12
+ private $sessionKey;
13
+
14
+ /**
15
+ * Create a new SessionCookieJar object
16
+ *
17
+ * @param string $sessionKey Session key name to store the cookie data in session
18
+ */
19
+ public function __construct($sessionKey)
20
+ {
21
+ $this->sessionKey = $sessionKey;
22
+ $this->load();
23
+ }
24
+
25
+ /**
26
+ * Saves cookies to session when shutting down
27
+ */
28
+ public function __destruct()
29
+ {
30
+ $this->save();
31
+ }
32
+
33
+ /**
34
+ * Save cookies to the client session
35
+ */
36
+ public function save()
37
+ {
38
+ $json = [];
39
+ foreach ($this as $cookie) {
40
+ if ($cookie->getExpires() && !$cookie->getDiscard()) {
41
+ $json[] = $cookie->toArray();
42
+ }
43
+ }
44
+
45
+ $_SESSION[$this->sessionKey] = json_encode($json);
46
+ }
47
+
48
+ /**
49
+ * Load the contents of the client session into the data array
50
+ */
51
+ protected function load()
52
+ {
53
+ $cookieJar = isset($_SESSION[$this->sessionKey])
54
+ ? $_SESSION[$this->sessionKey]
55
+ : null;
56
+
57
+ $data = Utils::jsonDecode($cookieJar, true);
58
+ if (is_array($data)) {
59
+ foreach ($data as $cookie) {
60
+ $this->setCookie(new SetCookie($cookie));
61
+ }
62
+ } elseif (strlen($data)) {
63
+ throw new \RuntimeException("Invalid cookie data");
64
+ }
65
+ }
66
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Cookie/SetCookie.php ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Cookie;
3
+
4
+ use GuzzleHttp\ToArrayInterface;
5
+
6
+ /**
7
+ * Set-Cookie object
8
+ */
9
+ class SetCookie implements ToArrayInterface
10
+ {
11
+ /** @var array */
12
+ private static $defaults = [
13
+ 'Name' => null,
14
+ 'Value' => null,
15
+ 'Domain' => null,
16
+ 'Path' => '/',
17
+ 'Max-Age' => null,
18
+ 'Expires' => null,
19
+ 'Secure' => false,
20
+ 'Discard' => false,
21
+ 'HttpOnly' => false
22
+ ];
23
+
24
+ /** @var array Cookie data */
25
+ private $data;
26
+
27
+ /**
28
+ * Create a new SetCookie object from a string
29
+ *
30
+ * @param string $cookie Set-Cookie header string
31
+ *
32
+ * @return self
33
+ */
34
+ public static function fromString($cookie)
35
+ {
36
+ // Create the default return array
37
+ $data = self::$defaults;
38
+ // Explode the cookie string using a series of semicolons
39
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
40
+ // The name of the cookie (first kvp) must include an equal sign.
41
+ if (empty($pieces) || !strpos($pieces[0], '=')) {
42
+ return new self($data);
43
+ }
44
+
45
+ // Add the cookie pieces into the parsed data array
46
+ foreach ($pieces as $part) {
47
+
48
+ $cookieParts = explode('=', $part, 2);
49
+ $key = trim($cookieParts[0]);
50
+ $value = isset($cookieParts[1])
51
+ ? trim($cookieParts[1], " \n\r\t\0\x0B\"")
52
+ : true;
53
+
54
+ // Only check for non-cookies when cookies have been found
55
+ if (empty($data['Name'])) {
56
+ $data['Name'] = $key;
57
+ $data['Value'] = $value;
58
+ } else {
59
+ foreach (array_keys(self::$defaults) as $search) {
60
+ if (!strcasecmp($search, $key)) {
61
+ $data[$search] = $value;
62
+ continue 2;
63
+ }
64
+ }
65
+ $data[$key] = $value;
66
+ }
67
+ }
68
+
69
+ return new self($data);
70
+ }
71
+
72
+ /**
73
+ * @param array $data Array of cookie data provided by a Cookie parser
74
+ */
75
+ public function __construct(array $data = [])
76
+ {
77
+ $this->data = array_replace(self::$defaults, $data);
78
+ // Extract the Expires value and turn it into a UNIX timestamp if needed
79
+ if (!$this->getExpires() && $this->getMaxAge()) {
80
+ // Calculate the Expires date
81
+ $this->setExpires(time() + $this->getMaxAge());
82
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
83
+ $this->setExpires($this->getExpires());
84
+ }
85
+ }
86
+
87
+ public function __toString()
88
+ {
89
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
90
+ foreach ($this->data as $k => $v) {
91
+ if ($k != 'Name' && $k != 'Value' && $v !== null && $v !== false) {
92
+ if ($k == 'Expires') {
93
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
94
+ } else {
95
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
96
+ }
97
+ }
98
+ }
99
+
100
+ return rtrim($str, '; ');
101
+ }
102
+
103
+ public function toArray()
104
+ {
105
+ return $this->data;
106
+ }
107
+
108
+ /**
109
+ * Get the cookie name
110
+ *
111
+ * @return string
112
+ */
113
+ public function getName()
114
+ {
115
+ return $this->data['Name'];
116
+ }
117
+
118
+ /**
119
+ * Set the cookie name
120
+ *
121
+ * @param string $name Cookie name
122
+ */
123
+ public function setName($name)
124
+ {
125
+ $this->data['Name'] = $name;
126
+ }
127
+
128
+ /**
129
+ * Get the cookie value
130
+ *
131
+ * @return string
132
+ */
133
+ public function getValue()
134
+ {
135
+ return $this->data['Value'];
136
+ }
137
+
138
+ /**
139
+ * Set the cookie value
140
+ *
141
+ * @param string $value Cookie value
142
+ */
143
+ public function setValue($value)
144
+ {
145
+ $this->data['Value'] = $value;
146
+ }
147
+
148
+ /**
149
+ * Get the domain
150
+ *
151
+ * @return string|null
152
+ */
153
+ public function getDomain()
154
+ {
155
+ return $this->data['Domain'];
156
+ }
157
+
158
+ /**
159
+ * Set the domain of the cookie
160
+ *
161
+ * @param string $domain
162
+ */
163
+ public function setDomain($domain)
164
+ {
165
+ $this->data['Domain'] = $domain;
166
+ }
167
+
168
+ /**
169
+ * Get the path
170
+ *
171
+ * @return string
172
+ */
173
+ public function getPath()
174
+ {
175
+ return $this->data['Path'];
176
+ }
177
+
178
+ /**
179
+ * Set the path of the cookie
180
+ *
181
+ * @param string $path Path of the cookie
182
+ */
183
+ public function setPath($path)
184
+ {
185
+ $this->data['Path'] = $path;
186
+ }
187
+
188
+ /**
189
+ * Maximum lifetime of the cookie in seconds
190
+ *
191
+ * @return int|null
192
+ */
193
+ public function getMaxAge()
194
+ {
195
+ return $this->data['Max-Age'];
196
+ }
197
+
198
+ /**
199
+ * Set the max-age of the cookie
200
+ *
201
+ * @param int $maxAge Max age of the cookie in seconds
202
+ */
203
+ public function setMaxAge($maxAge)
204
+ {
205
+ $this->data['Max-Age'] = $maxAge;
206
+ }
207
+
208
+ /**
209
+ * The UNIX timestamp when the cookie Expires
210
+ *
211
+ * @return mixed
212
+ */
213
+ public function getExpires()
214
+ {
215
+ return $this->data['Expires'];
216
+ }
217
+
218
+ /**
219
+ * Set the unix timestamp for which the cookie will expire
220
+ *
221
+ * @param int $timestamp Unix timestamp
222
+ */
223
+ public function setExpires($timestamp)
224
+ {
225
+ $this->data['Expires'] = is_numeric($timestamp)
226
+ ? (int) $timestamp
227
+ : strtotime($timestamp);
228
+ }
229
+
230
+ /**
231
+ * Get whether or not this is a secure cookie
232
+ *
233
+ * @return null|bool
234
+ */
235
+ public function getSecure()
236
+ {
237
+ return $this->data['Secure'];
238
+ }
239
+
240
+ /**
241
+ * Set whether or not the cookie is secure
242
+ *
243
+ * @param bool $secure Set to true or false if secure
244
+ */
245
+ public function setSecure($secure)
246
+ {
247
+ $this->data['Secure'] = $secure;
248
+ }
249
+
250
+ /**
251
+ * Get whether or not this is a session cookie
252
+ *
253
+ * @return null|bool
254
+ */
255
+ public function getDiscard()
256
+ {
257
+ return $this->data['Discard'];
258
+ }
259
+
260
+ /**
261
+ * Set whether or not this is a session cookie
262
+ *
263
+ * @param bool $discard Set to true or false if this is a session cookie
264
+ */
265
+ public function setDiscard($discard)
266
+ {
267
+ $this->data['Discard'] = $discard;
268
+ }
269
+
270
+ /**
271
+ * Get whether or not this is an HTTP only cookie
272
+ *
273
+ * @return bool
274
+ */
275
+ public function getHttpOnly()
276
+ {
277
+ return $this->data['HttpOnly'];
278
+ }
279
+
280
+ /**
281
+ * Set whether or not this is an HTTP only cookie
282
+ *
283
+ * @param bool $httpOnly Set to true or false if this is HTTP only
284
+ */
285
+ public function setHttpOnly($httpOnly)
286
+ {
287
+ $this->data['HttpOnly'] = $httpOnly;
288
+ }
289
+
290
+ /**
291
+ * Check if the cookie matches a path value
292
+ *
293
+ * @param string $path Path to check against
294
+ *
295
+ * @return bool
296
+ */
297
+ public function matchesPath($path)
298
+ {
299
+ return !$this->getPath() || 0 === stripos($path, $this->getPath());
300
+ }
301
+
302
+ /**
303
+ * Check if the cookie matches a domain value
304
+ *
305
+ * @param string $domain Domain to check against
306
+ *
307
+ * @return bool
308
+ */
309
+ public function matchesDomain($domain)
310
+ {
311
+ // Remove the leading '.' as per spec in RFC 6265.
312
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
313
+ $cookieDomain = ltrim($this->getDomain(), '.');
314
+
315
+ // Domain not set or exact match.
316
+ if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
317
+ return true;
318
+ }
319
+
320
+ // Matching the subdomain according to RFC 6265.
321
+ // http://tools.ietf.org/html/rfc6265#section-5.1.3
322
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
323
+ return false;
324
+ }
325
+
326
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/i', $domain);
327
+ }
328
+
329
+ /**
330
+ * Check if the cookie is expired
331
+ *
332
+ * @return bool
333
+ */
334
+ public function isExpired()
335
+ {
336
+ return $this->getExpires() && time() > $this->getExpires();
337
+ }
338
+
339
+ /**
340
+ * Check if the cookie is valid according to RFC 6265
341
+ *
342
+ * @return bool|string Returns true if valid or an error message if invalid
343
+ */
344
+ public function validate()
345
+ {
346
+ // Names must not be empty, but can be 0
347
+ $name = $this->getName();
348
+ if (empty($name) && !is_numeric($name)) {
349
+ return 'The cookie name must not be empty';
350
+ }
351
+
352
+ // Check if any of the invalid characters are present in the cookie name
353
+ if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
354
+ return "Cookie name must not cannot invalid characters: =,; \\t\\r\\n\\013\\014";
355
+ }
356
+
357
+ // Value must not be empty, but can be 0
358
+ $value = $this->getValue();
359
+ if (empty($value) && !is_numeric($value)) {
360
+ return 'The cookie value must not be empty';
361
+ }
362
+
363
+ // Domains must not be empty, but can be 0
364
+ // A "0" is not a valid internet domain, but may be used as server name
365
+ // in a private network.
366
+ $domain = $this->getDomain();
367
+ if (empty($domain) && !is_numeric($domain)) {
368
+ return 'The cookie domain must not be empty';
369
+ }
370
+
371
+ return true;
372
+ }
373
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractEvent.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Basic event class that can be extended.
6
+ */
7
+ abstract class AbstractEvent implements EventInterface
8
+ {
9
+ private $propagationStopped = false;
10
+
11
+ public function isPropagationStopped()
12
+ {
13
+ return $this->propagationStopped;
14
+ }
15
+
16
+ public function stopPropagation()
17
+ {
18
+ $this->propagationStopped = true;
19
+ }
20
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Transaction;
5
+ use GuzzleHttp\ClientInterface;
6
+ use GuzzleHttp\Message\RequestInterface;
7
+
8
+ /**
9
+ * Base class for request events, providing a request and client getter.
10
+ */
11
+ abstract class AbstractRequestEvent extends AbstractEvent
12
+ {
13
+ /** @var Transaction */
14
+ protected $transaction;
15
+
16
+ /**
17
+ * @param Transaction $transaction
18
+ */
19
+ public function __construct(Transaction $transaction)
20
+ {
21
+ $this->transaction = $transaction;
22
+ }
23
+
24
+ /**
25
+ * Get the HTTP client associated with the event.
26
+ *
27
+ * @return ClientInterface
28
+ */
29
+ public function getClient()
30
+ {
31
+ return $this->transaction->client;
32
+ }
33
+
34
+ /**
35
+ * Get the request object
36
+ *
37
+ * @return RequestInterface
38
+ */
39
+ public function getRequest()
40
+ {
41
+ return $this->transaction->request;
42
+ }
43
+
44
+ /**
45
+ * Get the number of transaction retries.
46
+ *
47
+ * @return int
48
+ */
49
+ public function getRetryCount()
50
+ {
51
+ return $this->transaction->retries;
52
+ }
53
+
54
+ /**
55
+ * @return Transaction
56
+ */
57
+ public function getTransaction()
58
+ {
59
+ return $this->transaction;
60
+ }
61
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractRetryableEvent.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Abstract request event that can be retried.
6
+ */
7
+ class AbstractRetryableEvent extends AbstractTransferEvent
8
+ {
9
+ /**
10
+ * Mark the request as needing a retry and stop event propagation.
11
+ *
12
+ * This action allows you to retry a request without emitting the "end"
13
+ * event multiple times for a given request. When retried, the request
14
+ * emits a before event and is then sent again using the client that sent
15
+ * the original request.
16
+ *
17
+ * When retrying, it is important to limit the number of retries you allow
18
+ * to prevent infinite loops.
19
+ *
20
+ * This action can only be taken during the "complete" and "error" events.
21
+ *
22
+ * @param int $afterDelay If specified, the amount of time in milliseconds
23
+ * to delay before retrying. Note that this must
24
+ * be supported by the underlying RingPHP handler
25
+ * to work properly. Set to 0 or provide no value
26
+ * to retry immediately.
27
+ */
28
+ public function retry($afterDelay = 0)
29
+ {
30
+ // Setting the transition state to 'retry' will cause the next state
31
+ // transition of the transaction to retry the request.
32
+ $this->transaction->state = 'retry';
33
+
34
+ if ($afterDelay) {
35
+ $this->transaction->request->getConfig()->set('delay', $afterDelay);
36
+ }
37
+
38
+ $this->stopPropagation();
39
+ }
40
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Message\ResponseInterface;
5
+ use GuzzleHttp\Ring\Future\FutureInterface;
6
+
7
+ /**
8
+ * Event that contains transfer statistics, and can be intercepted.
9
+ */
10
+ abstract class AbstractTransferEvent extends AbstractRequestEvent
11
+ {
12
+ /**
13
+ * Get all transfer information as an associative array if no $name
14
+ * argument is supplied, or gets a specific transfer statistic if
15
+ * a $name attribute is supplied (e.g., 'total_time').
16
+ *
17
+ * @param string $name Name of the transfer stat to retrieve
18
+ *
19
+ * @return mixed|null|array
20
+ */
21
+ public function getTransferInfo($name = null)
22
+ {
23
+ if (!$name) {
24
+ return $this->transaction->transferInfo;
25
+ }
26
+
27
+ return isset($this->transaction->transferInfo[$name])
28
+ ? $this->transaction->transferInfo[$name]
29
+ : null;
30
+ }
31
+
32
+ /**
33
+ * Returns true/false if a response is available.
34
+ *
35
+ * @return bool
36
+ */
37
+ public function hasResponse()
38
+ {
39
+ return !($this->transaction->response instanceof FutureInterface);
40
+ }
41
+
42
+ /**
43
+ * Get the response.
44
+ *
45
+ * @return ResponseInterface|null
46
+ */
47
+ public function getResponse()
48
+ {
49
+ return $this->hasResponse() ? $this->transaction->response : null;
50
+ }
51
+
52
+ /**
53
+ * Intercept the request and associate a response
54
+ *
55
+ * @param ResponseInterface $response Response to set
56
+ */
57
+ public function intercept(ResponseInterface $response)
58
+ {
59
+ $this->transaction->response = $response;
60
+ $this->transaction->exception = null;
61
+ $this->stopPropagation();
62
+ }
63
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/BeforeEvent.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Message\ResponseInterface;
5
+
6
+ /**
7
+ * Event object emitted before a request is sent.
8
+ *
9
+ * This event MAY be emitted multiple times (i.e., if a request is retried).
10
+ * You MAY change the Response associated with the request using the
11
+ * intercept() method of the event.
12
+ */
13
+ class BeforeEvent extends AbstractRequestEvent
14
+ {
15
+ /**
16
+ * Intercept the request and associate a response
17
+ *
18
+ * @param ResponseInterface $response Response to set
19
+ */
20
+ public function intercept(ResponseInterface $response)
21
+ {
22
+ $this->transaction->response = $response;
23
+ $this->transaction->exception = null;
24
+ $this->stopPropagation();
25
+ }
26
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/CompleteEvent.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Event object emitted after a request has been completed.
6
+ *
7
+ * This event MAY be emitted multiple times for a single request. You MAY
8
+ * change the Response associated with the request using the intercept()
9
+ * method of the event.
10
+ *
11
+ * This event allows the request to be retried if necessary using the retry()
12
+ * method of the event.
13
+ */
14
+ class CompleteEvent extends AbstractRetryableEvent {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/Emitter.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Guzzle event emitter.
6
+ *
7
+ * Some of this class is based on the Symfony EventDispatcher component, which
8
+ * ships with the following license:
9
+ *
10
+ * This file is part of the Symfony package.
11
+ *
12
+ * (c) Fabien Potencier <fabien@symfony.com>
13
+ *
14
+ * For the full copyright and license information, please view the LICENSE
15
+ * file that was distributed with this source code.
16
+ *
17
+ * @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
18
+ */
19
+ class Emitter implements EmitterInterface
20
+ {
21
+ /** @var array */
22
+ private $listeners = [];
23
+
24
+ /** @var array */
25
+ private $sorted = [];
26
+
27
+ public function on($eventName, callable $listener, $priority = 0)
28
+ {
29
+ if ($priority === 'first') {
30
+ $priority = isset($this->listeners[$eventName])
31
+ ? max(array_keys($this->listeners[$eventName])) + 1
32
+ : 1;
33
+ } elseif ($priority === 'last') {
34
+ $priority = isset($this->listeners[$eventName])
35
+ ? min(array_keys($this->listeners[$eventName])) - 1
36
+ : -1;
37
+ }
38
+
39
+ $this->listeners[$eventName][$priority][] = $listener;
40
+ unset($this->sorted[$eventName]);
41
+ }
42
+
43
+ public function once($eventName, callable $listener, $priority = 0)
44
+ {
45
+ $onceListener = function (
46
+ EventInterface $event,
47
+ $eventName
48
+ ) use (&$onceListener, $eventName, $listener, $priority) {
49
+ $this->removeListener($eventName, $onceListener);
50
+ $listener($event, $eventName);
51
+ };
52
+
53
+ $this->on($eventName, $onceListener, $priority);
54
+ }
55
+
56
+ public function removeListener($eventName, callable $listener)
57
+ {
58
+ if (empty($this->listeners[$eventName])) {
59
+ return;
60
+ }
61
+
62
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
63
+ if (false !== ($key = array_search($listener, $listeners, true))) {
64
+ unset(
65
+ $this->listeners[$eventName][$priority][$key],
66
+ $this->sorted[$eventName]
67
+ );
68
+ }
69
+ }
70
+ }
71
+
72
+ public function listeners($eventName = null)
73
+ {
74
+ // Return all events in a sorted priority order
75
+ if ($eventName === null) {
76
+ foreach (array_keys($this->listeners) as $eventName) {
77
+ if (empty($this->sorted[$eventName])) {
78
+ $this->listeners($eventName);
79
+ }
80
+ }
81
+ return $this->sorted;
82
+ }
83
+
84
+ // Return the listeners for a specific event, sorted in priority order
85
+ if (empty($this->sorted[$eventName])) {
86
+ $this->sorted[$eventName] = [];
87
+ if (isset($this->listeners[$eventName])) {
88
+ krsort($this->listeners[$eventName], SORT_NUMERIC);
89
+ foreach ($this->listeners[$eventName] as $listeners) {
90
+ foreach ($listeners as $listener) {
91
+ $this->sorted[$eventName][] = $listener;
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ return $this->sorted[$eventName];
98
+ }
99
+
100
+ public function hasListeners($eventName)
101
+ {
102
+ return !empty($this->listeners[$eventName]);
103
+ }
104
+
105
+ public function emit($eventName, EventInterface $event)
106
+ {
107
+ if (isset($this->listeners[$eventName])) {
108
+ foreach ($this->listeners($eventName) as $listener) {
109
+ $listener($event, $eventName);
110
+ if ($event->isPropagationStopped()) {
111
+ break;
112
+ }
113
+ }
114
+ }
115
+
116
+ return $event;
117
+ }
118
+
119
+ public function attach(SubscriberInterface $subscriber)
120
+ {
121
+ foreach ($subscriber->getEvents() as $eventName => $listeners) {
122
+ if (is_array($listeners[0])) {
123
+ foreach ($listeners as $listener) {
124
+ $this->on(
125
+ $eventName,
126
+ [$subscriber, $listener[0]],
127
+ isset($listener[1]) ? $listener[1] : 0
128
+ );
129
+ }
130
+ } else {
131
+ $this->on(
132
+ $eventName,
133
+ [$subscriber, $listeners[0]],
134
+ isset($listeners[1]) ? $listeners[1] : 0
135
+ );
136
+ }
137
+ }
138
+ }
139
+
140
+ public function detach(SubscriberInterface $subscriber)
141
+ {
142
+ foreach ($subscriber->getEvents() as $eventName => $listener) {
143
+ $this->removeListener($eventName, [$subscriber, $listener[0]]);
144
+ }
145
+ }
146
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/EmitterInterface.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Guzzle event emitter.
6
+ */
7
+ interface EmitterInterface
8
+ {
9
+ /**
10
+ * Binds a listener to a specific event.
11
+ *
12
+ * @param string $eventName Name of the event to bind to.
13
+ * @param callable $listener Listener to invoke when triggered.
14
+ * @param int|string $priority The higher this value, the earlier an event
15
+ * listener will be triggered in the chain (defaults to 0). You can
16
+ * pass "first" or "last" to dynamically specify the event priority
17
+ * based on the current event priorities associated with the given
18
+ * event name in the emitter. Use "first" to set the priority to the
19
+ * current highest priority plus one. Use "last" to set the priority to
20
+ * the current lowest event priority minus one.
21
+ */
22
+ public function on($eventName, callable $listener, $priority = 0);
23
+
24
+ /**
25
+ * Binds a listener to a specific event. After the listener is triggered
26
+ * once, it is removed as a listener.
27
+ *
28
+ * @param string $eventName Name of the event to bind to.
29
+ * @param callable $listener Listener to invoke when triggered.
30
+ * @param int $priority The higher this value, the earlier an event
31
+ * listener will be triggered in the chain (defaults to 0)
32
+ */
33
+ public function once($eventName, callable $listener, $priority = 0);
34
+
35
+ /**
36
+ * Removes an event listener from the specified event.
37
+ *
38
+ * @param string $eventName The event to remove a listener from
39
+ * @param callable $listener The listener to remove
40
+ */
41
+ public function removeListener($eventName, callable $listener);
42
+
43
+ /**
44
+ * Gets the listeners of a specific event or all listeners if no event is
45
+ * specified.
46
+ *
47
+ * @param string $eventName The name of the event. Pass null (the default)
48
+ * to retrieve all listeners.
49
+ *
50
+ * @return array The event listeners for the specified event, or all event
51
+ * listeners by event name. The format of the array when retrieving a
52
+ * specific event list is an array of callables. The format of the array
53
+ * when retrieving all listeners is an associative array of arrays of
54
+ * callables.
55
+ */
56
+ public function listeners($eventName = null);
57
+
58
+ /**
59
+ * Checks if the emitter has listeners by the given name.
60
+ *
61
+ * @param string $eventName The name of the event to check.
62
+ *
63
+ * @return bool
64
+ */
65
+ public function hasListeners($eventName);
66
+
67
+ /**
68
+ * Emits an event to all registered listeners.
69
+ *
70
+ * Each event that is bound to the emitted eventName receives a
71
+ * EventInterface, the name of the event, and the event emitter.
72
+ *
73
+ * @param string $eventName The name of the event to dispatch.
74
+ * @param EventInterface $event The event to pass to the event handlers/listeners.
75
+ *
76
+ * @return EventInterface Returns the provided event object
77
+ */
78
+ public function emit($eventName, EventInterface $event);
79
+
80
+ /**
81
+ * Attaches an event subscriber.
82
+ *
83
+ * The subscriber is asked for all the events it is interested in and added
84
+ * as an event listener for each event.
85
+ *
86
+ * @param SubscriberInterface $subscriber Subscriber to attach.
87
+ */
88
+ public function attach(SubscriberInterface $subscriber);
89
+
90
+ /**
91
+ * Detaches an event subscriber.
92
+ *
93
+ * @param SubscriberInterface $subscriber Subscriber to detach.
94
+ */
95
+ public function detach(SubscriberInterface $subscriber);
96
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/EndEvent.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * A terminal event that is emitted when a request transaction has ended.
6
+ *
7
+ * This event is emitted for both successful responses and responses that
8
+ * encountered an exception. You need to check if an exception is present
9
+ * in your listener to know the difference.
10
+ *
11
+ * You MAY intercept the response associated with the event if needed, but keep
12
+ * in mind that the "complete" event will not be triggered as a result.
13
+ */
14
+ class EndEvent extends AbstractTransferEvent
15
+ {
16
+ /**
17
+ * Get the exception that was encountered (if any).
18
+ *
19
+ * This method should be used to check if the request was sent successfully
20
+ * or if it encountered errors.
21
+ *
22
+ * @return \Exception|null
23
+ */
24
+ public function getException()
25
+ {
26
+ return $this->transaction->exception;
27
+ }
28
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/ErrorEvent.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Exception\RequestException;
5
+
6
+ /**
7
+ * Event emitted when an error occurs while sending a request.
8
+ *
9
+ * This event MAY be emitted multiple times. You MAY intercept the exception
10
+ * and inject a response into the event to rescue the request using the
11
+ * intercept() method of the event.
12
+ *
13
+ * This event allows the request to be retried using the "retry" method of the
14
+ * event.
15
+ */
16
+ class ErrorEvent extends AbstractRetryableEvent
17
+ {
18
+ /**
19
+ * Get the exception that was encountered
20
+ *
21
+ * @return RequestException
22
+ */
23
+ public function getException()
24
+ {
25
+ return $this->transaction->exception;
26
+ }
27
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/EventInterface.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Base event interface used when dispatching events to listeners using an
6
+ * event emitter.
7
+ */
8
+ interface EventInterface
9
+ {
10
+ /**
11
+ * Returns whether or not stopPropagation was called on the event.
12
+ *
13
+ * @return bool
14
+ * @see Event::stopPropagation
15
+ */
16
+ public function isPropagationStopped();
17
+
18
+ /**
19
+ * Stops the propagation of the event, preventing subsequent listeners
20
+ * registered to the same event from being invoked.
21
+ */
22
+ public function stopPropagation();
23
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/HasEmitterInterface.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Holds an event emitter
6
+ */
7
+ interface HasEmitterInterface
8
+ {
9
+ /**
10
+ * Get the event emitter of the object
11
+ *
12
+ * @return EmitterInterface
13
+ */
14
+ public function getEmitter();
15
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/HasEmitterTrait.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Trait that implements the methods of HasEmitterInterface
6
+ */
7
+ trait HasEmitterTrait
8
+ {
9
+ /** @var EmitterInterface */
10
+ private $emitter;
11
+
12
+ public function getEmitter()
13
+ {
14
+ if (!$this->emitter) {
15
+ $this->emitter = new Emitter();
16
+ }
17
+
18
+ return $this->emitter;
19
+ }
20
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/ListenerAttacherTrait.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Trait that provides methods for extract event listeners specified in an array
6
+ * and attaching them to an emitter owned by the object or one of its direct
7
+ * dependencies.
8
+ */
9
+ trait ListenerAttacherTrait
10
+ {
11
+ /**
12
+ * Attaches event listeners and properly sets their priorities and whether
13
+ * or not they are are only executed once.
14
+ *
15
+ * @param HasEmitterInterface $object Object that has the event emitter.
16
+ * @param array $listeners Array of hashes representing event
17
+ * event listeners. Each item contains
18
+ * "name", "fn", "priority", & "once".
19
+ */
20
+ private function attachListeners(HasEmitterInterface $object, array $listeners)
21
+ {
22
+ $emitter = $object->getEmitter();
23
+ foreach ($listeners as $el) {
24
+ if ($el['once']) {
25
+ $emitter->once($el['name'], $el['fn'], $el['priority']);
26
+ } else {
27
+ $emitter->on($el['name'], $el['fn'], $el['priority']);
28
+ }
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Extracts the allowed events from the provided array, and ignores anything
34
+ * else in the array. The event listener must be specified as a callable or
35
+ * as an array of event listener data ("name", "fn", "priority", "once").
36
+ *
37
+ * @param array $source Array containing callables or hashes of data to be
38
+ * prepared as event listeners.
39
+ * @param array $events Names of events to look for in the provided $source
40
+ * array. Other keys are ignored.
41
+ * @return array
42
+ */
43
+ private function prepareListeners(array $source, array $events)
44
+ {
45
+ $listeners = [];
46
+ foreach ($events as $name) {
47
+ if (isset($source[$name])) {
48
+ $this->buildListener($name, $source[$name], $listeners);
49
+ }
50
+ }
51
+
52
+ return $listeners;
53
+ }
54
+
55
+ /**
56
+ * Creates a complete event listener definition from the provided array of
57
+ * listener data. Also works recursively if more than one listeners are
58
+ * contained in the provided array.
59
+ *
60
+ * @param string $name Name of the event the listener is for.
61
+ * @param array|callable $data Event listener data to prepare.
62
+ * @param array $listeners Array of listeners, passed by reference.
63
+ *
64
+ * @throws \InvalidArgumentException if the event data is malformed.
65
+ */
66
+ private function buildListener($name, $data, &$listeners)
67
+ {
68
+ static $defaults = ['priority' => 0, 'once' => false];
69
+
70
+ // If a callable is provided, normalize it to the array format.
71
+ if (is_callable($data)) {
72
+ $data = ['fn' => $data];
73
+ }
74
+
75
+ // Prepare the listener and add it to the array, recursively.
76
+ if (isset($data['fn'])) {
77
+ $data['name'] = $name;
78
+ $listeners[] = $data + $defaults;
79
+ } elseif (is_array($data)) {
80
+ foreach ($data as $listenerData) {
81
+ $this->buildListener($name, $listenerData, $listeners);
82
+ }
83
+ } else {
84
+ throw new \InvalidArgumentException('Each event listener must be a '
85
+ . 'callable or an associative array containing a "fn" key.');
86
+ }
87
+ }
88
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/ProgressEvent.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ use GuzzleHttp\Transaction;
5
+
6
+ /**
7
+ * Event object emitted when upload or download progress is made.
8
+ *
9
+ * You can access the progress values using their corresponding public
10
+ * properties:
11
+ *
12
+ * - $downloadSize: The number of bytes that will be downloaded (if known)
13
+ * - $downloaded: The number of bytes that have been downloaded
14
+ * - $uploadSize: The number of bytes that will be uploaded (if known)
15
+ * - $uploaded: The number of bytes that have been uploaded
16
+ */
17
+ class ProgressEvent extends AbstractRequestEvent
18
+ {
19
+ /** @var int Amount of data to be downloaded */
20
+ public $downloadSize;
21
+
22
+ /** @var int Amount of data that has been downloaded */
23
+ public $downloaded;
24
+
25
+ /** @var int Amount of data to upload */
26
+ public $uploadSize;
27
+
28
+ /** @var int Amount of data that has been uploaded */
29
+ public $uploaded;
30
+
31
+ /**
32
+ * @param Transaction $transaction Transaction being sent.
33
+ * @param int $downloadSize Amount of data to download (if known)
34
+ * @param int $downloaded Amount of data that has been downloaded
35
+ * @param int $uploadSize Amount of data to upload (if known)
36
+ * @param int $uploaded Amount of data that had been uploaded
37
+ */
38
+ public function __construct(
39
+ Transaction $transaction,
40
+ $downloadSize,
41
+ $downloaded,
42
+ $uploadSize,
43
+ $uploaded
44
+ ) {
45
+ parent::__construct($transaction);
46
+ $this->downloadSize = $downloadSize;
47
+ $this->downloaded = $downloaded;
48
+ $this->uploadSize = $uploadSize;
49
+ $this->uploaded = $uploaded;
50
+ }
51
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/RequestEvents.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * Contains methods used to manage the request event lifecycle.
6
+ */
7
+ final class RequestEvents
8
+ {
9
+ // Generic event priorities
10
+ const EARLY = 10000;
11
+ const LATE = -10000;
12
+
13
+ // "before" priorities
14
+ const PREPARE_REQUEST = -100;
15
+ const SIGN_REQUEST = -10000;
16
+
17
+ // "complete" and "error" response priorities
18
+ const VERIFY_RESPONSE = 100;
19
+ const REDIRECT_RESPONSE = 200;
20
+
21
+ /**
22
+ * Converts an array of event options into a formatted array of valid event
23
+ * configuration.
24
+ *
25
+ * @param array $options Event array to convert
26
+ * @param array $events Event names to convert in the options array.
27
+ * @param mixed $handler Event handler to utilize
28
+ *
29
+ * @return array
30
+ * @throws \InvalidArgumentException if the event config is invalid
31
+ * @internal
32
+ */
33
+ public static function convertEventArray(
34
+ array $options,
35
+ array $events,
36
+ $handler
37
+ ) {
38
+ foreach ($events as $name) {
39
+ if (!isset($options[$name])) {
40
+ $options[$name] = [$handler];
41
+ } elseif (is_callable($options[$name])) {
42
+ $options[$name] = [$options[$name], $handler];
43
+ } elseif (is_array($options[$name])) {
44
+ if (isset($options[$name]['fn'])) {
45
+ $options[$name] = [$options[$name], $handler];
46
+ } else {
47
+ $options[$name][] = $handler;
48
+ }
49
+ } else {
50
+ throw new \InvalidArgumentException('Invalid event format');
51
+ }
52
+ }
53
+
54
+ return $options;
55
+ }
56
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Event/SubscriberInterface.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Event;
3
+
4
+ /**
5
+ * SubscriberInterface provides an array of events to an
6
+ * EventEmitterInterface when it is registered. The emitter then binds the
7
+ * listeners specified by the EventSubscriber.
8
+ *
9
+ * This interface is based on the SubscriberInterface of the Symfony.
10
+ * @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
11
+ */
12
+ interface SubscriberInterface
13
+ {
14
+ /**
15
+ * Returns an array of event names this subscriber wants to listen to.
16
+ *
17
+ * The returned array keys MUST map to an event name. Each array value
18
+ * MUST be an array in which the first element is the name of a function
19
+ * on the EventSubscriber OR an array of arrays in the aforementioned
20
+ * format. The second element in the array is optional, and if specified,
21
+ * designates the event priority.
22
+ *
23
+ * For example, the following are all valid:
24
+ *
25
+ * - ['eventName' => ['methodName']]
26
+ * - ['eventName' => ['methodName', $priority]]
27
+ * - ['eventName' => [['methodName'], ['otherMethod']]
28
+ * - ['eventName' => [['methodName'], ['otherMethod', $priority]]
29
+ * - ['eventName' => [['methodName', $priority], ['otherMethod', $priority]]
30
+ *
31
+ * @return array
32
+ */
33
+ public function getEvents();
34
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/BadResponseException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when an HTTP error occurs (4xx or 5xx error)
6
+ */
7
+ class BadResponseException extends RequestException {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ClientException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a client error is encountered (4xx codes)
6
+ */
7
+ class ClientException extends BadResponseException {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ConnectException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class ConnectException extends RequestException {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/CouldNotRewindStreamException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class CouldNotRewindStreamException extends RequestException {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ParseException.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use GuzzleHttp\Message\ResponseInterface;
5
+
6
+ /**
7
+ * Exception when a client is unable to parse the response body as XML or JSON
8
+ */
9
+ class ParseException extends TransferException
10
+ {
11
+ /** @var ResponseInterface */
12
+ private $response;
13
+
14
+ public function __construct(
15
+ $message = '',
16
+ ResponseInterface $response = null,
17
+ \Exception $previous = null
18
+ ) {
19
+ parent::__construct($message, 0, $previous);
20
+ $this->response = $response;
21
+ }
22
+ /**
23
+ * Get the associated response
24
+ *
25
+ * @return ResponseInterface|null
26
+ */
27
+ public function getResponse()
28
+ {
29
+ return $this->response;
30
+ }
31
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/RequestException.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+ use GuzzleHttp\Ring\Exception\ConnectException;
7
+ use GuzzleHttp\Exception\ConnectException as HttpConnectException;
8
+ use GuzzleHttp\Ring\Future\FutureInterface;
9
+
10
+ /**
11
+ * HTTP Request exception
12
+ */
13
+ class RequestException extends TransferException
14
+ {
15
+ /** @var RequestInterface */
16
+ private $request;
17
+
18
+ /** @var ResponseInterface */
19
+ private $response;
20
+
21
+ public function __construct(
22
+ $message,
23
+ RequestInterface $request,
24
+ ResponseInterface $response = null,
25
+ \Exception $previous = null
26
+ ) {
27
+ // Set the code of the exception if the response is set and not future.
28
+ $code = $response && !($response instanceof FutureInterface)
29
+ ? $response->getStatusCode()
30
+ : 0;
31
+ parent::__construct($message, $code, $previous);
32
+ $this->request = $request;
33
+ $this->response = $response;
34
+ }
35
+
36
+ /**
37
+ * Wrap non-RequestExceptions with a RequestException
38
+ *
39
+ * @param RequestInterface $request
40
+ * @param \Exception $e
41
+ *
42
+ * @return RequestException
43
+ */
44
+ public static function wrapException(RequestInterface $request, \Exception $e)
45
+ {
46
+ if ($e instanceof RequestException) {
47
+ return $e;
48
+ } elseif ($e instanceof ConnectException) {
49
+ return new HttpConnectException($e->getMessage(), $request, null, $e);
50
+ } else {
51
+ return new RequestException($e->getMessage(), $request, null, $e);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Factory method to create a new exception with a normalized error message
57
+ *
58
+ * @param RequestInterface $request Request
59
+ * @param ResponseInterface $response Response received
60
+ * @param \Exception $previous Previous exception
61
+ *
62
+ * @return self
63
+ */
64
+ public static function create(
65
+ RequestInterface $request,
66
+ ResponseInterface $response = null,
67
+ \Exception $previous = null
68
+ ) {
69
+ if (!$response) {
70
+ return new self('Error completing request', $request, null, $previous);
71
+ }
72
+
73
+ $level = floor($response->getStatusCode() / 100);
74
+ if ($level == '4') {
75
+ $label = 'Client error response';
76
+ $className = __NAMESPACE__ . '\\ClientException';
77
+ } elseif ($level == '5') {
78
+ $label = 'Server error response';
79
+ $className = __NAMESPACE__ . '\\ServerException';
80
+ } else {
81
+ $label = 'Unsuccessful response';
82
+ $className = __CLASS__;
83
+ }
84
+
85
+ $message = $label . ' [url] ' . $request->getUrl()
86
+ . ' [status code] ' . $response->getStatusCode()
87
+ . ' [reason phrase] ' . $response->getReasonPhrase();
88
+
89
+ return new $className($message, $request, $response, $previous);
90
+ }
91
+
92
+ /**
93
+ * Get the request that caused the exception
94
+ *
95
+ * @return RequestInterface
96
+ */
97
+ public function getRequest()
98
+ {
99
+ return $this->request;
100
+ }
101
+
102
+ /**
103
+ * Get the associated response
104
+ *
105
+ * @return ResponseInterface|null
106
+ */
107
+ public function getResponse()
108
+ {
109
+ return $this->response;
110
+ }
111
+
112
+ /**
113
+ * Check if a response was received
114
+ *
115
+ * @return bool
116
+ */
117
+ public function hasResponse()
118
+ {
119
+ return $this->response !== null;
120
+ }
121
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/ServerException.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ /**
5
+ * Exception when a server error is encountered (5xx codes)
6
+ */
7
+ class ServerException extends BadResponseException {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/StateException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class StateException extends TransferException {};
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TooManyRedirectsException extends RequestException {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/TransferException.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Exception;
3
+
4
+ class TransferException extends \RuntimeException {}
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Exception/XmlParseException.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Exception;
4
+
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Exception when a client is unable to parse the response body as XML
9
+ */
10
+ class XmlParseException extends ParseException
11
+ {
12
+ /** @var \LibXMLError */
13
+ protected $error;
14
+
15
+ public function __construct(
16
+ $message = '',
17
+ ResponseInterface $response = null,
18
+ \Exception $previous = null,
19
+ \LibXMLError $error = null
20
+ ) {
21
+ parent::__construct($message, $response, $previous);
22
+ $this->error = $error;
23
+ }
24
+
25
+ /**
26
+ * Get the associated error
27
+ *
28
+ * @return \LibXMLError|null
29
+ */
30
+ public function getError()
31
+ {
32
+ return $this->error;
33
+ }
34
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/HasDataTrait.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Trait implementing ToArrayInterface, \ArrayAccess, \Countable,
6
+ * \IteratorAggregate, and some path style methods.
7
+ */
8
+ trait HasDataTrait
9
+ {
10
+ /** @var array */
11
+ protected $data = [];
12
+
13
+ public function getIterator()
14
+ {
15
+ return new \ArrayIterator($this->data);
16
+ }
17
+
18
+ public function offsetGet($offset)
19
+ {
20
+ return isset($this->data[$offset]) ? $this->data[$offset] : null;
21
+ }
22
+
23
+ public function offsetSet($offset, $value)
24
+ {
25
+ $this->data[$offset] = $value;
26
+ }
27
+
28
+ public function offsetExists($offset)
29
+ {
30
+ return isset($this->data[$offset]);
31
+ }
32
+
33
+ public function offsetUnset($offset)
34
+ {
35
+ unset($this->data[$offset]);
36
+ }
37
+
38
+ public function toArray()
39
+ {
40
+ return $this->data;
41
+ }
42
+
43
+ public function count()
44
+ {
45
+ return count($this->data);
46
+ }
47
+
48
+ /**
49
+ * Get a value from the collection using a path syntax to retrieve nested
50
+ * data.
51
+ *
52
+ * @param string $path Path to traverse and retrieve a value from
53
+ *
54
+ * @return mixed|null
55
+ */
56
+ public function getPath($path)
57
+ {
58
+ return Utils::getPath($this->data, $path);
59
+ }
60
+
61
+ /**
62
+ * Set a value into a nested array key. Keys will be created as needed to
63
+ * set the value.
64
+ *
65
+ * @param string $path Path to set
66
+ * @param mixed $value Value to set at the key
67
+ *
68
+ * @throws \RuntimeException when trying to setPath using a nested path
69
+ * that travels through a scalar value
70
+ */
71
+ public function setPath($path, $value)
72
+ {
73
+ Utils::setPath($this->data, $path, $value);
74
+ }
75
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/AbstractMessage.php ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+
6
+ abstract class AbstractMessage implements MessageInterface
7
+ {
8
+ /** @var array HTTP header collection */
9
+ private $headers = [];
10
+
11
+ /** @var array mapping a lowercase header name to its name over the wire */
12
+ private $headerNames = [];
13
+
14
+ /** @var StreamInterface Message body */
15
+ private $body;
16
+
17
+ /** @var string HTTP protocol version of the message */
18
+ private $protocolVersion = '1.1';
19
+
20
+ public function __toString()
21
+ {
22
+ return static::getStartLineAndHeaders($this)
23
+ . "\r\n\r\n" . $this->getBody();
24
+ }
25
+
26
+ public function getProtocolVersion()
27
+ {
28
+ return $this->protocolVersion;
29
+ }
30
+
31
+ public function getBody()
32
+ {
33
+ return $this->body;
34
+ }
35
+
36
+ public function setBody(StreamInterface $body = null)
37
+ {
38
+ if ($body === null) {
39
+ // Setting a null body will remove the body of the request
40
+ $this->removeHeader('Content-Length');
41
+ $this->removeHeader('Transfer-Encoding');
42
+ }
43
+
44
+ $this->body = $body;
45
+ }
46
+
47
+ public function addHeader($header, $value)
48
+ {
49
+ if (is_array($value)) {
50
+ $current = array_merge($this->getHeaderAsArray($header), $value);
51
+ } else {
52
+ $current = $this->getHeaderAsArray($header);
53
+ $current[] = (string) $value;
54
+ }
55
+
56
+ $this->setHeader($header, $current);
57
+ }
58
+
59
+ public function addHeaders(array $headers)
60
+ {
61
+ foreach ($headers as $name => $header) {
62
+ $this->addHeader($name, $header);
63
+ }
64
+ }
65
+
66
+ public function getHeader($header)
67
+ {
68
+ $name = strtolower($header);
69
+ return isset($this->headers[$name])
70
+ ? implode(', ', $this->headers[$name])
71
+ : '';
72
+ }
73
+
74
+ public function getHeaderAsArray($header)
75
+ {
76
+ $name = strtolower($header);
77
+ return isset($this->headers[$name]) ? $this->headers[$name] : [];
78
+ }
79
+
80
+ public function getHeaders()
81
+ {
82
+ $headers = [];
83
+ foreach ($this->headers as $name => $values) {
84
+ $headers[$this->headerNames[$name]] = $values;
85
+ }
86
+
87
+ return $headers;
88
+ }
89
+
90
+ public function setHeader($header, $value)
91
+ {
92
+ $header = trim($header);
93
+ $name = strtolower($header);
94
+ $this->headerNames[$name] = $header;
95
+
96
+ if (is_array($value)) {
97
+ foreach ($value as &$v) {
98
+ $v = trim($v);
99
+ }
100
+ $this->headers[$name] = $value;
101
+ } else {
102
+ $this->headers[$name] = [trim($value)];
103
+ }
104
+ }
105
+
106
+ public function setHeaders(array $headers)
107
+ {
108
+ $this->headers = $this->headerNames = [];
109
+ foreach ($headers as $key => $value) {
110
+ $this->setHeader($key, $value);
111
+ }
112
+ }
113
+
114
+ public function hasHeader($header)
115
+ {
116
+ return isset($this->headers[strtolower($header)]);
117
+ }
118
+
119
+ public function removeHeader($header)
120
+ {
121
+ $name = strtolower($header);
122
+ unset($this->headers[$name], $this->headerNames[$name]);
123
+ }
124
+
125
+ /**
126
+ * Parse an array of header values containing ";" separated data into an
127
+ * array of associative arrays representing the header key value pair
128
+ * data of the header. When a parameter does not contain a value, but just
129
+ * contains a key, this function will inject a key with a '' string value.
130
+ *
131
+ * @param MessageInterface $message That contains the header
132
+ * @param string $header Header to retrieve from the message
133
+ *
134
+ * @return array Returns the parsed header values.
135
+ */
136
+ public static function parseHeader(MessageInterface $message, $header)
137
+ {
138
+ static $trimmed = "\"' \n\t\r";
139
+ $params = $matches = [];
140
+
141
+ foreach (self::normalizeHeader($message, $header) as $val) {
142
+ $part = [];
143
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
144
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
145
+ $m = $matches[0];
146
+ if (isset($m[1])) {
147
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
148
+ } else {
149
+ $part[] = trim($m[0], $trimmed);
150
+ }
151
+ }
152
+ }
153
+ if ($part) {
154
+ $params[] = $part;
155
+ }
156
+ }
157
+
158
+ return $params;
159
+ }
160
+
161
+ /**
162
+ * Converts an array of header values that may contain comma separated
163
+ * headers into an array of headers with no comma separated values.
164
+ *
165
+ * @param MessageInterface $message That contains the header
166
+ * @param string $header Header to retrieve from the message
167
+ *
168
+ * @return array Returns the normalized header field values.
169
+ */
170
+ public static function normalizeHeader(MessageInterface $message, $header)
171
+ {
172
+ $h = $message->getHeaderAsArray($header);
173
+ for ($i = 0, $total = count($h); $i < $total; $i++) {
174
+ if (strpos($h[$i], ',') === false) {
175
+ continue;
176
+ }
177
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) {
178
+ $h[] = trim($v);
179
+ }
180
+ unset($h[$i]);
181
+ }
182
+
183
+ return $h;
184
+ }
185
+
186
+ /**
187
+ * Gets the start-line and headers of a message as a string
188
+ *
189
+ * @param MessageInterface $message
190
+ *
191
+ * @return string
192
+ */
193
+ public static function getStartLineAndHeaders(MessageInterface $message)
194
+ {
195
+ return static::getStartLine($message)
196
+ . self::getHeadersAsString($message);
197
+ }
198
+
199
+ /**
200
+ * Gets the headers of a message as a string
201
+ *
202
+ * @param MessageInterface $message
203
+ *
204
+ * @return string
205
+ */
206
+ public static function getHeadersAsString(MessageInterface $message)
207
+ {
208
+ $result = '';
209
+ foreach ($message->getHeaders() as $name => $values) {
210
+ $result .= "\r\n{$name}: " . implode(', ', $values);
211
+ }
212
+
213
+ return $result;
214
+ }
215
+
216
+ /**
217
+ * Gets the start line of a message
218
+ *
219
+ * @param MessageInterface $message
220
+ *
221
+ * @return string
222
+ * @throws \InvalidArgumentException
223
+ */
224
+ public static function getStartLine(MessageInterface $message)
225
+ {
226
+ if ($message instanceof RequestInterface) {
227
+ return trim($message->getMethod() . ' '
228
+ . $message->getResource())
229
+ . ' HTTP/' . $message->getProtocolVersion();
230
+ } elseif ($message instanceof ResponseInterface) {
231
+ return 'HTTP/' . $message->getProtocolVersion() . ' '
232
+ . $message->getStatusCode() . ' '
233
+ . $message->getReasonPhrase();
234
+ } else {
235
+ throw new \InvalidArgumentException('Unknown message type');
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Accepts and modifies the options provided to the message in the
241
+ * constructor.
242
+ *
243
+ * Can be overridden in subclasses as necessary.
244
+ *
245
+ * @param array $options Options array passed by reference.
246
+ */
247
+ protected function handleOptions(array &$options)
248
+ {
249
+ if (isset($options['protocol_version'])) {
250
+ $this->protocolVersion = $options['protocol_version'];
251
+ }
252
+ }
253
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/AppliesHeadersInterface.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ /**
5
+ * Applies headers to a request.
6
+ *
7
+ * This interface can be used with Guzzle streams to apply body specific
8
+ * headers to a request during the PREPARE_REQUEST priority of the before event
9
+ *
10
+ * NOTE: a body that implements this interface will prevent a default
11
+ * content-type from being added to a request during the before event. If you
12
+ * want a default content-type to be added, then it will need to be done
13
+ * manually (e.g., using {@see GuzzleHttp\Mimetypes}).
14
+ */
15
+ interface AppliesHeadersInterface
16
+ {
17
+ /**
18
+ * Apply headers to a request appropriate for the current state of the
19
+ * object.
20
+ *
21
+ * @param RequestInterface $request Request
22
+ */
23
+ public function applyRequestHeaders(RequestInterface $request);
24
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/FutureResponse.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Ring\Future\MagicFutureTrait;
5
+ use GuzzleHttp\Ring\Future\FutureInterface;
6
+ use GuzzleHttp\Stream\StreamInterface;
7
+
8
+ /**
9
+ * Represents a response that has not been fulfilled.
10
+ *
11
+ * When created, you must provide a function that is used to dereference the
12
+ * future result and return it's value. The function has no arguments and MUST
13
+ * return an instance of a {@see GuzzleHttp\Message\ResponseInterface} object.
14
+ *
15
+ * You can optionally provide a function in the constructor that can be used to
16
+ * cancel the future from completing if possible. This function has no
17
+ * arguments and returns a boolean value representing whether or not the
18
+ * response could be cancelled.
19
+ *
20
+ * @property ResponseInterface $_value
21
+ */
22
+ class FutureResponse implements ResponseInterface, FutureInterface
23
+ {
24
+ use MagicFutureTrait;
25
+
26
+ /**
27
+ * Returns a FutureResponse that wraps another future.
28
+ *
29
+ * @param FutureInterface $future Future to wrap with a new future
30
+ * @param callable $onFulfilled Invoked when the future fulfilled
31
+ * @param callable $onRejected Invoked when the future rejected
32
+ * @param callable $onProgress Invoked when the future progresses
33
+ *
34
+ * @return FutureResponse
35
+ */
36
+ public static function proxy(
37
+ FutureInterface $future,
38
+ callable $onFulfilled = null,
39
+ callable $onRejected = null,
40
+ callable $onProgress = null
41
+ ) {
42
+ return new FutureResponse(
43
+ $future->then($onFulfilled, $onRejected, $onProgress),
44
+ [$future, 'wait'],
45
+ [$future, 'cancel']
46
+ );
47
+ }
48
+
49
+ public function getStatusCode()
50
+ {
51
+ return $this->_value->getStatusCode();
52
+ }
53
+
54
+ public function setStatusCode($code)
55
+ {
56
+ $this->_value->setStatusCode($code);
57
+ }
58
+
59
+ public function getReasonPhrase()
60
+ {
61
+ return $this->_value->getReasonPhrase();
62
+ }
63
+
64
+ public function setReasonPhrase($phrase)
65
+ {
66
+ $this->_value->setReasonPhrase($phrase);
67
+ }
68
+
69
+ public function getEffectiveUrl()
70
+ {
71
+ return $this->_value->getEffectiveUrl();
72
+ }
73
+
74
+ public function setEffectiveUrl($url)
75
+ {
76
+ $this->_value->setEffectiveUrl($url);
77
+ }
78
+
79
+ public function json(array $config = [])
80
+ {
81
+ return $this->_value->json($config);
82
+ }
83
+
84
+ public function xml(array $config = [])
85
+ {
86
+ return $this->_value->xml($config);
87
+ }
88
+
89
+ public function __toString()
90
+ {
91
+ try {
92
+ return $this->_value->__toString();
93
+ } catch (\Exception $e) {
94
+ trigger_error($e->getMessage(), E_USER_WARNING);
95
+ return '';
96
+ }
97
+ }
98
+
99
+ public function getProtocolVersion()
100
+ {
101
+ return $this->_value->getProtocolVersion();
102
+ }
103
+
104
+ public function setBody(StreamInterface $body = null)
105
+ {
106
+ $this->_value->setBody($body);
107
+ }
108
+
109
+ public function getBody()
110
+ {
111
+ return $this->_value->getBody();
112
+ }
113
+
114
+ public function getHeaders()
115
+ {
116
+ return $this->_value->getHeaders();
117
+ }
118
+
119
+ public function getHeader($header)
120
+ {
121
+ return $this->_value->getHeader($header);
122
+ }
123
+
124
+ public function getHeaderAsArray($header)
125
+ {
126
+ return $this->_value->getHeaderAsArray($header);
127
+ }
128
+
129
+ public function hasHeader($header)
130
+ {
131
+ return $this->_value->hasHeader($header);
132
+ }
133
+
134
+ public function removeHeader($header)
135
+ {
136
+ $this->_value->removeHeader($header);
137
+ }
138
+
139
+ public function addHeader($header, $value)
140
+ {
141
+ $this->_value->addHeader($header, $value);
142
+ }
143
+
144
+ public function addHeaders(array $headers)
145
+ {
146
+ $this->_value->addHeaders($headers);
147
+ }
148
+
149
+ public function setHeader($header, $value)
150
+ {
151
+ $this->_value->setHeader($header, $value);
152
+ }
153
+
154
+ public function setHeaders(array $headers)
155
+ {
156
+ $this->_value->setHeaders($headers);
157
+ }
158
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageFactory.php ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Cookie\CookieJar;
5
+ use GuzzleHttp\Cookie\CookieJarInterface;
6
+ use GuzzleHttp\Event\ListenerAttacherTrait;
7
+ use GuzzleHttp\Post\PostBody;
8
+ use GuzzleHttp\Post\PostFile;
9
+ use GuzzleHttp\Post\PostFileInterface;
10
+ use GuzzleHttp\Query;
11
+ use GuzzleHttp\Stream\Stream;
12
+ use GuzzleHttp\Subscriber\Cookie;
13
+ use GuzzleHttp\Subscriber\HttpError;
14
+ use GuzzleHttp\Subscriber\Redirect;
15
+ use GuzzleHttp\Url;
16
+ use \InvalidArgumentException as Iae;
17
+
18
+ /**
19
+ * Default HTTP request factory used to create Request and Response objects.
20
+ */
21
+ class MessageFactory implements MessageFactoryInterface
22
+ {
23
+ use ListenerAttacherTrait;
24
+
25
+ /** @var HttpError */
26
+ private $errorPlugin;
27
+
28
+ /** @var Redirect */
29
+ private $redirectPlugin;
30
+
31
+ /** @var array */
32
+ private $customOptions;
33
+
34
+ /** @var array Request options passed through to request Config object */
35
+ private static $configMap = [
36
+ 'connect_timeout' => 1, 'timeout' => 1, 'verify' => 1, 'ssl_key' => 1,
37
+ 'cert' => 1, 'proxy' => 1, 'debug' => 1, 'save_to' => 1, 'stream' => 1,
38
+ 'expect' => 1, 'future' => 1
39
+ ];
40
+
41
+ /** @var array Default allow_redirects request option settings */
42
+ private static $defaultRedirect = [
43
+ 'max' => 5,
44
+ 'strict' => false,
45
+ 'referer' => false,
46
+ 'protocols' => ['http', 'https']
47
+ ];
48
+
49
+ /**
50
+ * @param array $customOptions Associative array of custom request option
51
+ * names mapping to functions used to apply
52
+ * the option. The function accepts the request
53
+ * and the option value to apply.
54
+ */
55
+ public function __construct(array $customOptions = [])
56
+ {
57
+ $this->errorPlugin = new HttpError();
58
+ $this->redirectPlugin = new Redirect();
59
+ $this->customOptions = $customOptions;
60
+ }
61
+
62
+ public function createResponse(
63
+ $statusCode,
64
+ array $headers = [],
65
+ $body = null,
66
+ array $options = []
67
+ ) {
68
+ if (null !== $body) {
69
+ $body = Stream::factory($body);
70
+ }
71
+
72
+ return new Response($statusCode, $headers, $body, $options);
73
+ }
74
+
75
+ public function createRequest($method, $url, array $options = [])
76
+ {
77
+ // Handle the request protocol version option that needs to be
78
+ // specified in the request constructor.
79
+ if (isset($options['version'])) {
80
+ $options['config']['protocol_version'] = $options['version'];
81
+ unset($options['version']);
82
+ }
83
+
84
+ $request = new Request($method, $url, [], null,
85
+ isset($options['config']) ? $options['config'] : []);
86
+
87
+ unset($options['config']);
88
+
89
+ // Use a POST body by default
90
+ if ($method == 'POST'
91
+ && !isset($options['body'])
92
+ && !isset($options['json'])
93
+ ) {
94
+ $options['body'] = [];
95
+ }
96
+
97
+ if ($options) {
98
+ $this->applyOptions($request, $options);
99
+ }
100
+
101
+ return $request;
102
+ }
103
+
104
+ /**
105
+ * Create a request or response object from an HTTP message string
106
+ *
107
+ * @param string $message Message to parse
108
+ *
109
+ * @return RequestInterface|ResponseInterface
110
+ * @throws \InvalidArgumentException if unable to parse a message
111
+ */
112
+ public function fromMessage($message)
113
+ {
114
+ static $parser;
115
+ if (!$parser) {
116
+ $parser = new MessageParser();
117
+ }
118
+
119
+ // Parse a response
120
+ if (strtoupper(substr($message, 0, 4)) == 'HTTP') {
121
+ $data = $parser->parseResponse($message);
122
+ return $this->createResponse(
123
+ $data['code'],
124
+ $data['headers'],
125
+ $data['body'] === '' ? null : $data['body'],
126
+ $data
127
+ );
128
+ }
129
+
130
+ // Parse a request
131
+ if (!($data = ($parser->parseRequest($message)))) {
132
+ throw new \InvalidArgumentException('Unable to parse request');
133
+ }
134
+
135
+ return $this->createRequest(
136
+ $data['method'],
137
+ Url::buildUrl($data['request_url']),
138
+ [
139
+ 'headers' => $data['headers'],
140
+ 'body' => $data['body'] === '' ? null : $data['body'],
141
+ 'config' => [
142
+ 'protocol_version' => $data['protocol_version']
143
+ ]
144
+ ]
145
+ );
146
+ }
147
+
148
+ /**
149
+ * Apply POST fields and files to a request to attempt to give an accurate
150
+ * representation.
151
+ *
152
+ * @param RequestInterface $request Request to update
153
+ * @param array $body Body to apply
154
+ */
155
+ protected function addPostData(RequestInterface $request, array $body)
156
+ {
157
+ static $fields = ['string' => true, 'array' => true, 'NULL' => true,
158
+ 'boolean' => true, 'double' => true, 'integer' => true];
159
+
160
+ $post = new PostBody();
161
+ foreach ($body as $key => $value) {
162
+ if (isset($fields[gettype($value)])) {
163
+ $post->setField($key, $value);
164
+ } elseif ($value instanceof PostFileInterface) {
165
+ $post->addFile($value);
166
+ } else {
167
+ $post->addFile(new PostFile($key, $value));
168
+ }
169
+ }
170
+
171
+ if ($request->getHeader('Content-Type') == 'multipart/form-data') {
172
+ $post->forceMultipartUpload(true);
173
+ }
174
+
175
+ $request->setBody($post);
176
+ }
177
+
178
+ protected function applyOptions(
179
+ RequestInterface $request,
180
+ array $options = []
181
+ ) {
182
+ $config = $request->getConfig();
183
+ $emitter = $request->getEmitter();
184
+
185
+ foreach ($options as $key => $value) {
186
+
187
+ if (isset(self::$configMap[$key])) {
188
+ $config[$key] = $value;
189
+ continue;
190
+ }
191
+
192
+ switch ($key) {
193
+
194
+ case 'allow_redirects':
195
+
196
+ if ($value === false) {
197
+ continue;
198
+ }
199
+
200
+ if ($value === true) {
201
+ $value = self::$defaultRedirect;
202
+ } elseif (!is_array($value)) {
203
+ throw new Iae('allow_redirects must be true, false, or array');
204
+ } else {
205
+ // Merge the default settings with the provided settings
206
+ $value += self::$defaultRedirect;
207
+ }
208
+
209
+ $config['redirect'] = $value;
210
+ $emitter->attach($this->redirectPlugin);
211
+ break;
212
+
213
+ case 'decode_content':
214
+
215
+ if ($value === false) {
216
+ continue;
217
+ }
218
+
219
+ $config['decode_content'] = true;
220
+ if ($value !== true) {
221
+ $request->setHeader('Accept-Encoding', $value);
222
+ }
223
+ break;
224
+
225
+ case 'headers':
226
+
227
+ if (!is_array($value)) {
228
+ throw new Iae('header value must be an array');
229
+ }
230
+ foreach ($value as $k => $v) {
231
+ $request->setHeader($k, $v);
232
+ }
233
+ break;
234
+
235
+ case 'exceptions':
236
+
237
+ if ($value === true) {
238
+ $emitter->attach($this->errorPlugin);
239
+ }
240
+ break;
241
+
242
+ case 'body':
243
+
244
+ if (is_array($value)) {
245
+ $this->addPostData($request, $value);
246
+ } elseif ($value !== null) {
247
+ $request->setBody(Stream::factory($value));
248
+ }
249
+ break;
250
+
251
+ case 'auth':
252
+
253
+ if (!$value) {
254
+ continue;
255
+ }
256
+
257
+ if (is_array($value)) {
258
+ $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
259
+ } else {
260
+ $type = strtolower($value);
261
+ }
262
+
263
+ $config['auth'] = $value;
264
+
265
+ if ($type == 'basic') {
266
+ $request->setHeader(
267
+ 'Authorization',
268
+ 'Basic ' . base64_encode("$value[0]:$value[1]")
269
+ );
270
+ } elseif ($type == 'digest') {
271
+ // @todo: Do not rely on curl
272
+ $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
273
+ $config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]");
274
+ }
275
+ break;
276
+
277
+ case 'query':
278
+
279
+ if ($value instanceof Query) {
280
+ $original = $request->getQuery();
281
+ // Do not overwrite existing query string variables by
282
+ // overwriting the object with the query string data passed
283
+ // in the URL
284
+ $value->overwriteWith($original->toArray());
285
+ $request->setQuery($value);
286
+ } elseif (is_array($value)) {
287
+ // Do not overwrite existing query string variables
288
+ $query = $request->getQuery();
289
+ foreach ($value as $k => $v) {
290
+ if (!isset($query[$k])) {
291
+ $query[$k] = $v;
292
+ }
293
+ }
294
+ } else {
295
+ throw new Iae('query must be an array or Query object');
296
+ }
297
+ break;
298
+
299
+ case 'cookies':
300
+
301
+ if ($value === true) {
302
+ static $cookie = null;
303
+ if (!$cookie) {
304
+ $cookie = new Cookie();
305
+ }
306
+ $emitter->attach($cookie);
307
+ } elseif (is_array($value)) {
308
+ $emitter->attach(
309
+ new Cookie(CookieJar::fromArray($value, $request->getHost()))
310
+ );
311
+ } elseif ($value instanceof CookieJarInterface) {
312
+ $emitter->attach(new Cookie($value));
313
+ } elseif ($value !== false) {
314
+ throw new Iae('cookies must be an array, true, or CookieJarInterface');
315
+ }
316
+ break;
317
+
318
+ case 'events':
319
+
320
+ if (!is_array($value)) {
321
+ throw new Iae('events must be an array');
322
+ }
323
+
324
+ $this->attachListeners($request,
325
+ $this->prepareListeners(
326
+ $value,
327
+ ['before', 'complete', 'error', 'progress', 'end']
328
+ )
329
+ );
330
+ break;
331
+
332
+ case 'subscribers':
333
+
334
+ if (!is_array($value)) {
335
+ throw new Iae('subscribers must be an array');
336
+ }
337
+
338
+ foreach ($value as $subscribers) {
339
+ $emitter->attach($subscribers);
340
+ }
341
+ break;
342
+
343
+ case 'json':
344
+
345
+ $request->setBody(Stream::factory(json_encode($value)));
346
+ if (!$request->hasHeader('Content-Type')) {
347
+ $request->setHeader('Content-Type', 'application/json');
348
+ }
349
+ break;
350
+
351
+ default:
352
+
353
+ // Check for custom handler functions.
354
+ if (isset($this->customOptions[$key])) {
355
+ $fn = $this->customOptions[$key];
356
+ $fn($request, $value);
357
+ continue;
358
+ }
359
+
360
+ throw new Iae("No method can handle the {$key} config key");
361
+ }
362
+ }
363
+ }
364
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Url;
5
+
6
+ /**
7
+ * Request and response factory
8
+ */
9
+ interface MessageFactoryInterface
10
+ {
11
+ /**
12
+ * Creates a response
13
+ *
14
+ * @param string $statusCode HTTP status code
15
+ * @param array $headers Response headers
16
+ * @param mixed $body Response body
17
+ * @param array $options Response options
18
+ * - protocol_version: HTTP protocol version
19
+ * - header_factory: Factory used to create headers
20
+ * - And any other options used by a concrete message implementation
21
+ *
22
+ * @return ResponseInterface
23
+ */
24
+ public function createResponse(
25
+ $statusCode,
26
+ array $headers = [],
27
+ $body = null,
28
+ array $options = []
29
+ );
30
+
31
+ /**
32
+ * Create a new request based on the HTTP method.
33
+ *
34
+ * This method accepts an associative array of request options. Below is a
35
+ * brief description of each parameter. See
36
+ * http://docs.guzzlephp.org/en/latest/clients.html#request-options for a much more
37
+ * in-depth description of each parameter.
38
+ *
39
+ * - headers: Associative array of headers to add to the request
40
+ * - body: string|resource|array|StreamInterface request body to send
41
+ * - json: mixed Uploads JSON encoded data using an application/json Content-Type header.
42
+ * - query: Associative array of query string values to add to the request
43
+ * - auth: array|string HTTP auth settings (user, pass[, type="basic"])
44
+ * - version: The HTTP protocol version to use with the request
45
+ * - cookies: true|false|CookieJarInterface To enable or disable cookies
46
+ * - allow_redirects: true|false|array Controls HTTP redirects
47
+ * - save_to: string|resource|StreamInterface Where the response is saved
48
+ * - events: Associative array of event names to callables or arrays
49
+ * - subscribers: Array of event subscribers to add to the request
50
+ * - exceptions: Specifies whether or not exceptions are thrown for HTTP protocol errors
51
+ * - timeout: Timeout of the request in seconds. Use 0 to wait indefinitely
52
+ * - connect_timeout: Number of seconds to wait while trying to connect. (0 to wait indefinitely)
53
+ * - verify: SSL validation. True/False or the path to a PEM file
54
+ * - cert: Path a SSL cert or array of (path, pwd)
55
+ * - ssl_key: Path to a private SSL key or array of (path, pwd)
56
+ * - proxy: Specify an HTTP proxy or hash of protocols to proxies
57
+ * - debug: Set to true or a resource to view handler specific debug info
58
+ * - stream: Set to true to stream a response body rather than download it all up front
59
+ * - expect: true/false/integer Controls the "Expect: 100-Continue" header
60
+ * - config: Associative array of request config collection options
61
+ * - decode_content: true/false/string to control decoding content-encoding responses
62
+ *
63
+ * @param string $method HTTP method (GET, POST, PUT, etc.)
64
+ * @param string|Url $url HTTP URL to connect to
65
+ * @param array $options Array of options to apply to the request
66
+ *
67
+ * @return RequestInterface
68
+ * @link http://docs.guzzlephp.org/en/latest/clients.html#request-options
69
+ */
70
+ public function createRequest($method, $url, array $options = []);
71
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageInterface.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+
6
+ /**
7
+ * Request and response message interface
8
+ */
9
+ interface MessageInterface
10
+ {
11
+ /**
12
+ * Get a string representation of the message
13
+ *
14
+ * @return string
15
+ */
16
+ public function __toString();
17
+
18
+ /**
19
+ * Get the HTTP protocol version of the message
20
+ *
21
+ * @return string
22
+ */
23
+ public function getProtocolVersion();
24
+
25
+ /**
26
+ * Sets the body of the message.
27
+ *
28
+ * The body MUST be a StreamInterface object. Setting the body to null MUST
29
+ * remove the existing body.
30
+ *
31
+ * @param StreamInterface|null $body Body.
32
+ */
33
+ public function setBody(StreamInterface $body = null);
34
+
35
+ /**
36
+ * Get the body of the message
37
+ *
38
+ * @return StreamInterface|null
39
+ */
40
+ public function getBody();
41
+
42
+ /**
43
+ * Gets all message headers.
44
+ *
45
+ * The keys represent the header name as it will be sent over the wire, and
46
+ * each value is an array of strings associated with the header.
47
+ *
48
+ * // Represent the headers as a string
49
+ * foreach ($message->getHeaders() as $name => $values) {
50
+ * echo $name . ": " . implode(", ", $values);
51
+ * }
52
+ *
53
+ * @return array Returns an associative array of the message's headers.
54
+ */
55
+ public function getHeaders();
56
+
57
+ /**
58
+ * Retrieve a header by the given case-insensitive name.
59
+ *
60
+ * @param string $header Case-insensitive header name.
61
+ *
62
+ * @return string
63
+ */
64
+ public function getHeader($header);
65
+
66
+ /**
67
+ * Retrieves a header by the given case-insensitive name as an array of strings.
68
+ *
69
+ * @param string $header Case-insensitive header name.
70
+ *
71
+ * @return string[]
72
+ */
73
+ public function getHeaderAsArray($header);
74
+
75
+ /**
76
+ * Checks if a header exists by the given case-insensitive name.
77
+ *
78
+ * @param string $header Case-insensitive header name.
79
+ *
80
+ * @return bool Returns true if any header names match the given header
81
+ * name using a case-insensitive string comparison. Returns false if
82
+ * no matching header name is found in the message.
83
+ */
84
+ public function hasHeader($header);
85
+
86
+ /**
87
+ * Remove a specific header by case-insensitive name.
88
+ *
89
+ * @param string $header Case-insensitive header name.
90
+ */
91
+ public function removeHeader($header);
92
+
93
+ /**
94
+ * Appends a header value to any existing values associated with the
95
+ * given header name.
96
+ *
97
+ * @param string $header Header name to add
98
+ * @param string $value Value of the header
99
+ */
100
+ public function addHeader($header, $value);
101
+
102
+ /**
103
+ * Merges in an associative array of headers.
104
+ *
105
+ * Each array key MUST be a string representing the case-insensitive name
106
+ * of a header. Each value MUST be either a string or an array of strings.
107
+ * For each value, the value is appended to any existing header of the same
108
+ * name, or, if a header does not already exist by the given name, then the
109
+ * header is added.
110
+ *
111
+ * @param array $headers Associative array of headers to add to the message
112
+ */
113
+ public function addHeaders(array $headers);
114
+
115
+ /**
116
+ * Sets a header, replacing any existing values of any headers with the
117
+ * same case-insensitive name.
118
+ *
119
+ * The header values MUST be a string or an array of strings.
120
+ *
121
+ * @param string $header Header name
122
+ * @param string|array $value Header value(s)
123
+ */
124
+ public function setHeader($header, $value);
125
+
126
+ /**
127
+ * Sets headers, replacing any headers that have already been set on the
128
+ * message.
129
+ *
130
+ * The array keys MUST be a string. The array values must be either a
131
+ * string or an array of strings.
132
+ *
133
+ * @param array $headers Headers to set.
134
+ */
135
+ public function setHeaders(array $headers);
136
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/MessageParser.php ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ /**
5
+ * Request and response parser used by Guzzle
6
+ */
7
+ class MessageParser
8
+ {
9
+ /**
10
+ * Parse an HTTP request message into an associative array of parts.
11
+ *
12
+ * @param string $message HTTP request to parse
13
+ *
14
+ * @return array|bool Returns false if the message is invalid
15
+ */
16
+ public function parseRequest($message)
17
+ {
18
+ if (!($parts = $this->parseMessage($message))) {
19
+ return false;
20
+ }
21
+
22
+ // Parse the protocol and protocol version
23
+ if (isset($parts['start_line'][2])) {
24
+ $startParts = explode('/', $parts['start_line'][2]);
25
+ $protocol = strtoupper($startParts[0]);
26
+ $version = isset($startParts[1]) ? $startParts[1] : '1.1';
27
+ } else {
28
+ $protocol = 'HTTP';
29
+ $version = '1.1';
30
+ }
31
+
32
+ $parsed = [
33
+ 'method' => strtoupper($parts['start_line'][0]),
34
+ 'protocol' => $protocol,
35
+ 'protocol_version' => $version,
36
+ 'headers' => $parts['headers'],
37
+ 'body' => $parts['body']
38
+ ];
39
+
40
+ $parsed['request_url'] = $this->getUrlPartsFromMessage(
41
+ (isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed);
42
+
43
+ return $parsed;
44
+ }
45
+
46
+ /**
47
+ * Parse an HTTP response message into an associative array of parts.
48
+ *
49
+ * @param string $message HTTP response to parse
50
+ *
51
+ * @return array|bool Returns false if the message is invalid
52
+ */
53
+ public function parseResponse($message)
54
+ {
55
+ if (!($parts = $this->parseMessage($message))) {
56
+ return false;
57
+ }
58
+
59
+ list($protocol, $version) = explode('/', trim($parts['start_line'][0]));
60
+
61
+ return [
62
+ 'protocol' => $protocol,
63
+ 'protocol_version' => $version,
64
+ 'code' => $parts['start_line'][1],
65
+ 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
66
+ 'headers' => $parts['headers'],
67
+ 'body' => $parts['body']
68
+ ];
69
+ }
70
+
71
+ /**
72
+ * Parse a message into parts
73
+ *
74
+ * @param string $message Message to parse
75
+ *
76
+ * @return array|bool
77
+ */
78
+ private function parseMessage($message)
79
+ {
80
+ if (!$message) {
81
+ return false;
82
+ }
83
+
84
+ $startLine = null;
85
+ $headers = [];
86
+ $body = '';
87
+
88
+ // Iterate over each line in the message, accounting for line endings
89
+ $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
90
+ for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
91
+
92
+ $line = $lines[$i];
93
+
94
+ // If two line breaks were encountered, then this is the end of body
95
+ if (empty($line)) {
96
+ if ($i < $totalLines - 1) {
97
+ $body = implode('', array_slice($lines, $i + 2));
98
+ }
99
+ break;
100
+ }
101
+
102
+ // Parse message headers
103
+ if (!$startLine) {
104
+ $startLine = explode(' ', $line, 3);
105
+ } elseif (strpos($line, ':')) {
106
+ $parts = explode(':', $line, 2);
107
+ $key = trim($parts[0]);
108
+ $value = isset($parts[1]) ? trim($parts[1]) : '';
109
+ if (!isset($headers[$key])) {
110
+ $headers[$key] = $value;
111
+ } elseif (!is_array($headers[$key])) {
112
+ $headers[$key] = [$headers[$key], $value];
113
+ } else {
114
+ $headers[$key][] = $value;
115
+ }
116
+ }
117
+ }
118
+
119
+ return [
120
+ 'start_line' => $startLine,
121
+ 'headers' => $headers,
122
+ 'body' => $body
123
+ ];
124
+ }
125
+
126
+ /**
127
+ * Create URL parts from HTTP message parts
128
+ *
129
+ * @param string $requestUrl Associated URL
130
+ * @param array $parts HTTP message parts
131
+ *
132
+ * @return array
133
+ */
134
+ private function getUrlPartsFromMessage($requestUrl, array $parts)
135
+ {
136
+ // Parse the URL information from the message
137
+ $urlParts = ['path' => $requestUrl, 'scheme' => 'http'];
138
+
139
+ // Check for the Host header
140
+ if (isset($parts['headers']['Host'])) {
141
+ $urlParts['host'] = $parts['headers']['Host'];
142
+ } elseif (isset($parts['headers']['host'])) {
143
+ $urlParts['host'] = $parts['headers']['host'];
144
+ } else {
145
+ $urlParts['host'] = null;
146
+ }
147
+
148
+ if (false === strpos($urlParts['host'], ':')) {
149
+ $urlParts['port'] = '';
150
+ } else {
151
+ $hostParts = explode(':', $urlParts['host']);
152
+ $urlParts['host'] = trim($hostParts[0]);
153
+ $urlParts['port'] = (int) trim($hostParts[1]);
154
+ if ($urlParts['port'] == 443) {
155
+ $urlParts['scheme'] = 'https';
156
+ }
157
+ }
158
+
159
+ // Check if a query is present
160
+ $path = $urlParts['path'];
161
+ $qpos = strpos($path, '?');
162
+ if ($qpos) {
163
+ $urlParts['query'] = substr($path, $qpos + 1);
164
+ $urlParts['path'] = substr($path, 0, $qpos);
165
+ } else {
166
+ $urlParts['query'] = '';
167
+ }
168
+
169
+ return $urlParts;
170
+ }
171
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/Request.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Collection;
5
+ use GuzzleHttp\Event\HasEmitterTrait;
6
+ use GuzzleHttp\Subscriber\Prepare;
7
+ use GuzzleHttp\Url;
8
+
9
+ /**
10
+ * HTTP request class to send requests
11
+ */
12
+ class Request extends AbstractMessage implements RequestInterface
13
+ {
14
+ use HasEmitterTrait;
15
+
16
+ /** @var Url HTTP Url */
17
+ private $url;
18
+
19
+ /** @var string HTTP method */
20
+ private $method;
21
+
22
+ /** @var Collection Transfer options */
23
+ private $transferOptions;
24
+
25
+ /**
26
+ * @param string $method HTTP method
27
+ * @param string|Url $url HTTP URL to connect to. The URI scheme,
28
+ * host header, and URI are parsed from the full URL. If query string
29
+ * parameters are present they will be parsed as well.
30
+ * @param array|Collection $headers HTTP headers
31
+ * @param mixed $body Body to send with the request
32
+ * @param array $options Array of options to use with the request
33
+ * - emitter: Event emitter to use with the request
34
+ */
35
+ public function __construct(
36
+ $method,
37
+ $url,
38
+ $headers = [],
39
+ $body = null,
40
+ array $options = []
41
+ ) {
42
+ $this->setUrl($url);
43
+ $this->method = strtoupper($method);
44
+ $this->handleOptions($options);
45
+ $this->transferOptions = new Collection($options);
46
+ $this->addPrepareEvent();
47
+
48
+ if ($body !== null) {
49
+ $this->setBody($body);
50
+ }
51
+
52
+ if ($headers) {
53
+ foreach ($headers as $key => $value) {
54
+ $this->addHeader($key, $value);
55
+ }
56
+ }
57
+ }
58
+
59
+ public function __clone()
60
+ {
61
+ if ($this->emitter) {
62
+ $this->emitter = clone $this->emitter;
63
+ }
64
+ $this->transferOptions = clone $this->transferOptions;
65
+ $this->url = clone $this->url;
66
+ }
67
+
68
+ public function setUrl($url)
69
+ {
70
+ $this->url = $url instanceof Url ? $url : Url::fromString($url);
71
+ $this->updateHostHeaderFromUrl();
72
+ }
73
+
74
+ public function getUrl()
75
+ {
76
+ return (string) $this->url;
77
+ }
78
+
79
+ public function setQuery($query)
80
+ {
81
+ $this->url->setQuery($query);
82
+ }
83
+
84
+ public function getQuery()
85
+ {
86
+ return $this->url->getQuery();
87
+ }
88
+
89
+ public function setMethod($method)
90
+ {
91
+ $this->method = strtoupper($method);
92
+ }
93
+
94
+ public function getMethod()
95
+ {
96
+ return $this->method;
97
+ }
98
+
99
+ public function getScheme()
100
+ {
101
+ return $this->url->getScheme();
102
+ }
103
+
104
+ public function setScheme($scheme)
105
+ {
106
+ $this->url->setScheme($scheme);
107
+ }
108
+
109
+ public function getPort()
110
+ {
111
+ return $this->url->getPort();
112
+ }
113
+
114
+ public function setPort($port)
115
+ {
116
+ $this->url->setPort($port);
117
+ $this->updateHostHeaderFromUrl();
118
+ }
119
+
120
+ public function getHost()
121
+ {
122
+ return $this->url->getHost();
123
+ }
124
+
125
+ public function setHost($host)
126
+ {
127
+ $this->url->setHost($host);
128
+ $this->updateHostHeaderFromUrl();
129
+ }
130
+
131
+ public function getPath()
132
+ {
133
+ return '/' . ltrim($this->url->getPath(), '/');
134
+ }
135
+
136
+ public function setPath($path)
137
+ {
138
+ $this->url->setPath($path);
139
+ }
140
+
141
+ public function getResource()
142
+ {
143
+ $resource = $this->getPath();
144
+ if ($query = (string) $this->url->getQuery()) {
145
+ $resource .= '?' . $query;
146
+ }
147
+
148
+ return $resource;
149
+ }
150
+
151
+ public function getConfig()
152
+ {
153
+ return $this->transferOptions;
154
+ }
155
+
156
+ protected function handleOptions(array &$options)
157
+ {
158
+ parent::handleOptions($options);
159
+ // Use a custom emitter if one is specified, and remove it from
160
+ // options that are exposed through getConfig()
161
+ if (isset($options['emitter'])) {
162
+ $this->emitter = $options['emitter'];
163
+ unset($options['emitter']);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Adds a subscriber that ensures a request's body is prepared before
169
+ * sending.
170
+ */
171
+ private function addPrepareEvent()
172
+ {
173
+ static $subscriber;
174
+ if (!$subscriber) {
175
+ $subscriber = new Prepare();
176
+ }
177
+
178
+ $this->getEmitter()->attach($subscriber);
179
+ }
180
+
181
+ private function updateHostHeaderFromUrl()
182
+ {
183
+ $port = $this->url->getPort();
184
+ $scheme = $this->url->getScheme();
185
+ if ($host = $this->url->getHost()) {
186
+ if (($port == 80 && $scheme == 'http') ||
187
+ ($port == 443 && $scheme == 'https')
188
+ ) {
189
+ $this->setHeader('Host', $host);
190
+ } else {
191
+ $this->setHeader('Host', "{$host}:{$port}");
192
+ }
193
+ }
194
+ }
195
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/RequestInterface.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Event\HasEmitterInterface;
5
+ use GuzzleHttp\Query;
6
+
7
+ /**
8
+ * Generic HTTP request interface
9
+ */
10
+ interface RequestInterface extends MessageInterface, HasEmitterInterface
11
+ {
12
+ /**
13
+ * Sets the request URL.
14
+ *
15
+ * The URL MUST be a string, or an object that implements the
16
+ * `__toString()` method.
17
+ *
18
+ * @param string $url Request URL.
19
+ *
20
+ * @throws \InvalidArgumentException If the URL is invalid.
21
+ */
22
+ public function setUrl($url);
23
+
24
+ /**
25
+ * Gets the request URL as a string.
26
+ *
27
+ * @return string Returns the URL as a string.
28
+ */
29
+ public function getUrl();
30
+
31
+ /**
32
+ * Get the resource part of the the request, including the path, query
33
+ * string, and fragment.
34
+ *
35
+ * @return string
36
+ */
37
+ public function getResource();
38
+
39
+ /**
40
+ * Get the collection of key value pairs that will be used as the query
41
+ * string in the request.
42
+ *
43
+ * @return Query
44
+ */
45
+ public function getQuery();
46
+
47
+ /**
48
+ * Set the query string used by the request
49
+ *
50
+ * @param array|Query $query Query to set
51
+ */
52
+ public function setQuery($query);
53
+
54
+ /**
55
+ * Get the HTTP method of the request.
56
+ *
57
+ * @return string
58
+ */
59
+ public function getMethod();
60
+
61
+ /**
62
+ * Set the HTTP method of the request.
63
+ *
64
+ * @param string $method HTTP method
65
+ */
66
+ public function setMethod($method);
67
+
68
+ /**
69
+ * Get the URI scheme of the request (http, https, etc.).
70
+ *
71
+ * @return string
72
+ */
73
+ public function getScheme();
74
+
75
+ /**
76
+ * Set the URI scheme of the request (http, https, etc.).
77
+ *
78
+ * @param string $scheme Scheme to set
79
+ */
80
+ public function setScheme($scheme);
81
+
82
+ /**
83
+ * Get the port scheme of the request (e.g., 80, 443, etc.).
84
+ *
85
+ * @return int
86
+ */
87
+ public function getPort();
88
+
89
+ /**
90
+ * Set the port of the request.
91
+ *
92
+ * Setting a port modifies the Host header of a request as necessary.
93
+ *
94
+ * @param int $port Port to set
95
+ */
96
+ public function setPort($port);
97
+
98
+ /**
99
+ * Get the host of the request.
100
+ *
101
+ * @return string
102
+ */
103
+ public function getHost();
104
+
105
+ /**
106
+ * Set the host of the request including an optional port.
107
+ *
108
+ * Including a port in the host argument will explicitly change the port of
109
+ * the request. If no port is found, the default port of the current
110
+ * request scheme will be utilized.
111
+ *
112
+ * @param string $host Host to set (e.g. www.yahoo.com, www.yahoo.com:80)
113
+ */
114
+ public function setHost($host);
115
+
116
+ /**
117
+ * Get the path of the request (e.g. '/', '/index.html').
118
+ *
119
+ * @return string
120
+ */
121
+ public function getPath();
122
+
123
+ /**
124
+ * Set the path of the request (e.g. '/', '/index.html').
125
+ *
126
+ * @param string|array $path Path to set or array of segments to implode
127
+ */
128
+ public function setPath($path);
129
+
130
+ /**
131
+ * Get the request's configuration options.
132
+ *
133
+ * @return \GuzzleHttp\Collection
134
+ */
135
+ public function getConfig();
136
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/Response.php ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ use GuzzleHttp\Exception\ParseException;
5
+ use GuzzleHttp\Exception\XmlParseException;
6
+ use GuzzleHttp\Stream\StreamInterface;
7
+ use GuzzleHttp\Utils;
8
+
9
+ /**
10
+ * Guzzle HTTP response object
11
+ */
12
+ class Response extends AbstractMessage implements ResponseInterface
13
+ {
14
+ /** @var array Mapping of status codes to reason phrases */
15
+ private static $statusTexts = [
16
+ 100 => 'Continue',
17
+ 101 => 'Switching Protocols',
18
+ 102 => 'Processing',
19
+ 200 => 'OK',
20
+ 201 => 'Created',
21
+ 202 => 'Accepted',
22
+ 203 => 'Non-Authoritative Information',
23
+ 204 => 'No Content',
24
+ 205 => 'Reset Content',
25
+ 206 => 'Partial Content',
26
+ 207 => 'Multi-Status',
27
+ 208 => 'Already Reported',
28
+ 226 => 'IM Used',
29
+ 300 => 'Multiple Choices',
30
+ 301 => 'Moved Permanently',
31
+ 302 => 'Found',
32
+ 303 => 'See Other',
33
+ 304 => 'Not Modified',
34
+ 305 => 'Use Proxy',
35
+ 307 => 'Temporary Redirect',
36
+ 308 => 'Permanent Redirect',
37
+ 400 => 'Bad Request',
38
+ 401 => 'Unauthorized',
39
+ 402 => 'Payment Required',
40
+ 403 => 'Forbidden',
41
+ 404 => 'Not Found',
42
+ 405 => 'Method Not Allowed',
43
+ 406 => 'Not Acceptable',
44
+ 407 => 'Proxy Authentication Required',
45
+ 408 => 'Request Timeout',
46
+ 409 => 'Conflict',
47
+ 410 => 'Gone',
48
+ 411 => 'Length Required',
49
+ 412 => 'Precondition Failed',
50
+ 413 => 'Request Entity Too Large',
51
+ 414 => 'Request-URI Too Long',
52
+ 415 => 'Unsupported Media Type',
53
+ 416 => 'Requested Range Not Satisfiable',
54
+ 417 => 'Expectation Failed',
55
+ 422 => 'Unprocessable Entity',
56
+ 423 => 'Locked',
57
+ 424 => 'Failed Dependency',
58
+ 425 => 'Reserved for WebDAV advanced collections expired proposal',
59
+ 426 => 'Upgrade required',
60
+ 428 => 'Precondition Required',
61
+ 429 => 'Too Many Requests',
62
+ 431 => 'Request Header Fields Too Large',
63
+ 500 => 'Internal Server Error',
64
+ 501 => 'Not Implemented',
65
+ 502 => 'Bad Gateway',
66
+ 503 => 'Service Unavailable',
67
+ 504 => 'Gateway Timeout',
68
+ 505 => 'HTTP Version Not Supported',
69
+ 506 => 'Variant Also Negotiates (Experimental)',
70
+ 507 => 'Insufficient Storage',
71
+ 508 => 'Loop Detected',
72
+ 510 => 'Not Extended',
73
+ 511 => 'Network Authentication Required',
74
+ ];
75
+
76
+ /** @var string The reason phrase of the response (human readable code) */
77
+ private $reasonPhrase;
78
+
79
+ /** @var string The status code of the response */
80
+ private $statusCode;
81
+
82
+ /** @var string The effective URL that returned this response */
83
+ private $effectiveUrl;
84
+
85
+ /**
86
+ * @param int|string $statusCode The response status code (e.g. 200)
87
+ * @param array $headers The response headers
88
+ * @param StreamInterface $body The body of the response
89
+ * @param array $options Response message options
90
+ * - reason_phrase: Set a custom reason phrase
91
+ * - protocol_version: Set a custom protocol version
92
+ */
93
+ public function __construct(
94
+ $statusCode,
95
+ array $headers = [],
96
+ StreamInterface $body = null,
97
+ array $options = []
98
+ ) {
99
+ $this->statusCode = (int) $statusCode;
100
+ $this->handleOptions($options);
101
+
102
+ // Assume a reason phrase if one was not applied as an option
103
+ if (!$this->reasonPhrase &&
104
+ isset(self::$statusTexts[$this->statusCode])
105
+ ) {
106
+ $this->reasonPhrase = self::$statusTexts[$this->statusCode];
107
+ }
108
+
109
+ if ($headers) {
110
+ $this->setHeaders($headers);
111
+ }
112
+
113
+ if ($body) {
114
+ $this->setBody($body);
115
+ }
116
+ }
117
+
118
+ public function getStatusCode()
119
+ {
120
+ return $this->statusCode;
121
+ }
122
+
123
+ public function setStatusCode($code)
124
+ {
125
+ return $this->statusCode = (int) $code;
126
+ }
127
+
128
+ public function getReasonPhrase()
129
+ {
130
+ return $this->reasonPhrase;
131
+ }
132
+
133
+ public function setReasonPhrase($phrase)
134
+ {
135
+ return $this->reasonPhrase = $phrase;
136
+ }
137
+
138
+ public function json(array $config = [])
139
+ {
140
+ try {
141
+ return Utils::jsonDecode(
142
+ (string) $this->getBody(),
143
+ isset($config['object']) ? !$config['object'] : true,
144
+ 512,
145
+ isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0
146
+ );
147
+ } catch (\InvalidArgumentException $e) {
148
+ throw new ParseException(
149
+ $e->getMessage(),
150
+ $this
151
+ );
152
+ }
153
+ }
154
+
155
+ public function xml(array $config = [])
156
+ {
157
+ $disableEntities = libxml_disable_entity_loader(true);
158
+ $internalErrors = libxml_use_internal_errors(true);
159
+
160
+ try {
161
+ // Allow XML to be retrieved even if there is no response body
162
+ $xml = new \SimpleXMLElement(
163
+ (string) $this->getBody() ?: '<root />',
164
+ isset($config['libxml_options']) ? $config['libxml_options'] : LIBXML_NONET,
165
+ false,
166
+ isset($config['ns']) ? $config['ns'] : '',
167
+ isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false
168
+ );
169
+ libxml_disable_entity_loader($disableEntities);
170
+ libxml_use_internal_errors($internalErrors);
171
+ } catch (\Exception $e) {
172
+ libxml_disable_entity_loader($disableEntities);
173
+ libxml_use_internal_errors($internalErrors);
174
+ throw new XmlParseException(
175
+ 'Unable to parse response body into XML: ' . $e->getMessage(),
176
+ $this,
177
+ $e,
178
+ (libxml_get_last_error()) ?: null
179
+ );
180
+ }
181
+
182
+ return $xml;
183
+ }
184
+
185
+ public function getEffectiveUrl()
186
+ {
187
+ return $this->effectiveUrl;
188
+ }
189
+
190
+ public function setEffectiveUrl($url)
191
+ {
192
+ $this->effectiveUrl = $url;
193
+ }
194
+
195
+ /**
196
+ * Accepts and modifies the options provided to the response in the
197
+ * constructor.
198
+ *
199
+ * @param array $options Options array passed by reference.
200
+ */
201
+ protected function handleOptions(array &$options = [])
202
+ {
203
+ parent::handleOptions($options);
204
+ if (isset($options['reason_phrase'])) {
205
+ $this->reasonPhrase = $options['reason_phrase'];
206
+ }
207
+ }
208
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Message/ResponseInterface.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Message;
3
+
4
+ /**
5
+ * Represents an HTTP response message.
6
+ */
7
+ interface ResponseInterface extends MessageInterface
8
+ {
9
+ /**
10
+ * Gets the response Status-Code.
11
+ *
12
+ * The Status-Code is a 3-digit integer result code of the server's attempt
13
+ * to understand and satisfy the request.
14
+ *
15
+ * @return int Status code.
16
+ */
17
+ public function getStatusCode();
18
+
19
+ /**
20
+ * Sets the status code of this response.
21
+ *
22
+ * @param int $code The 3-digit integer result code to set.
23
+ */
24
+ public function setStatusCode($code);
25
+
26
+ /**
27
+ * Gets the response Reason-Phrase, a short textual description of the
28
+ * Status-Code.
29
+ *
30
+ * Because a Reason-Phrase is not a required element in response
31
+ * Status-Line, the Reason-Phrase value MAY be null. Implementations MAY
32
+ * choose to return the default RFC 2616 recommended reason phrase for the
33
+ * response's Status-Code.
34
+ *
35
+ * @return string|null Reason phrase, or null if unknown.
36
+ */
37
+ public function getReasonPhrase();
38
+
39
+ /**
40
+ * Sets the Reason-Phrase of the response.
41
+ *
42
+ * If no Reason-Phrase is specified, implementations MAY choose to default
43
+ * to the RFC 2616 recommended reason phrase for the response's Status-Code.
44
+ *
45
+ * @param string $phrase The Reason-Phrase to set.
46
+ */
47
+ public function setReasonPhrase($phrase);
48
+
49
+ /**
50
+ * Get the effective URL that resulted in this response (e.g. the last
51
+ * redirect URL).
52
+ *
53
+ * @return string
54
+ */
55
+ public function getEffectiveUrl();
56
+
57
+ /**
58
+ * Set the effective URL that resulted in this response (e.g. the last
59
+ * redirect URL).
60
+ *
61
+ * @param string $url Effective URL
62
+ */
63
+ public function setEffectiveUrl($url);
64
+
65
+ /**
66
+ * Parse the JSON response body and return the JSON decoded data.
67
+ *
68
+ * @param array $config Associative array of configuration settings used
69
+ * to control how the JSON data is parsed. Concrete implementations MAY
70
+ * add further configuration settings as needed, but they MUST implement
71
+ * functionality for the following options:
72
+ *
73
+ * - object: Set to true to parse JSON objects as PHP objects rather
74
+ * than associative arrays. Defaults to false.
75
+ * - big_int_strings: When set to true, large integers are converted to
76
+ * strings rather than floats. Defaults to false.
77
+ *
78
+ * Implementations are free to add further configuration settings as
79
+ * needed.
80
+ *
81
+ * @return mixed Returns the JSON decoded data based on the provided
82
+ * parse settings.
83
+ * @throws \RuntimeException if the response body is not in JSON format
84
+ */
85
+ public function json(array $config = []);
86
+
87
+ /**
88
+ * Parse the XML response body and return a \SimpleXMLElement.
89
+ *
90
+ * In order to prevent XXE attacks, this method disables loading external
91
+ * entities. If you rely on external entities, then you must parse the
92
+ * XML response manually by accessing the response body directly.
93
+ *
94
+ * @param array $config Associative array of configuration settings used
95
+ * to control how the XML is parsed. Concrete implementations MAY add
96
+ * further configuration settings as needed, but they MUST implement
97
+ * functionality for the following options:
98
+ *
99
+ * - ns: Set to a string to represent the namespace prefix or URI
100
+ * - ns_is_prefix: Set to true to specify that the NS is a prefix rather
101
+ * than a URI (defaults to false).
102
+ * - libxml_options: Bitwise OR of the libxml option constants
103
+ * listed at http://php.net/manual/en/libxml.constants.php
104
+ * (defaults to LIBXML_NONET)
105
+ *
106
+ * @return \SimpleXMLElement
107
+ * @throws \RuntimeException if the response body is not in XML format
108
+ * @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html
109
+ */
110
+ public function xml(array $config = []);
111
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Mimetypes.php ADDED
@@ -0,0 +1,963 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Provides mappings of file extensions to mimetypes
6
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
7
+ */
8
+ class Mimetypes
9
+ {
10
+ /** @var self */
11
+ protected static $instance;
12
+
13
+ /** @var array Mapping of extension to mimetype */
14
+ protected $mimetypes = array(
15
+ '3dml' => 'text/vnd.in3d.3dml',
16
+ '3g2' => 'video/3gpp2',
17
+ '3gp' => 'video/3gpp',
18
+ '7z' => 'application/x-7z-compressed',
19
+ 'aab' => 'application/x-authorware-bin',
20
+ 'aac' => 'audio/x-aac',
21
+ 'aam' => 'application/x-authorware-map',
22
+ 'aas' => 'application/x-authorware-seg',
23
+ 'abw' => 'application/x-abiword',
24
+ 'ac' => 'application/pkix-attr-cert',
25
+ 'acc' => 'application/vnd.americandynamics.acc',
26
+ 'ace' => 'application/x-ace-compressed',
27
+ 'acu' => 'application/vnd.acucobol',
28
+ 'acutc' => 'application/vnd.acucorp',
29
+ 'adp' => 'audio/adpcm',
30
+ 'aep' => 'application/vnd.audiograph',
31
+ 'afm' => 'application/x-font-type1',
32
+ 'afp' => 'application/vnd.ibm.modcap',
33
+ 'ahead' => 'application/vnd.ahead.space',
34
+ 'ai' => 'application/postscript',
35
+ 'aif' => 'audio/x-aiff',
36
+ 'aifc' => 'audio/x-aiff',
37
+ 'aiff' => 'audio/x-aiff',
38
+ 'air' => 'application/vnd.adobe.air-application-installer-package+zip',
39
+ 'ait' => 'application/vnd.dvb.ait',
40
+ 'ami' => 'application/vnd.amiga.ami',
41
+ 'apk' => 'application/vnd.android.package-archive',
42
+ 'application' => 'application/x-ms-application',
43
+ 'apr' => 'application/vnd.lotus-approach',
44
+ 'asa' => 'text/plain',
45
+ 'asax' => 'application/octet-stream',
46
+ 'asc' => 'application/pgp-signature',
47
+ 'ascx' => 'text/plain',
48
+ 'asf' => 'video/x-ms-asf',
49
+ 'ashx' => 'text/plain',
50
+ 'asm' => 'text/x-asm',
51
+ 'asmx' => 'text/plain',
52
+ 'aso' => 'application/vnd.accpac.simply.aso',
53
+ 'asp' => 'text/plain',
54
+ 'aspx' => 'text/plain',
55
+ 'asx' => 'video/x-ms-asf',
56
+ 'atc' => 'application/vnd.acucorp',
57
+ 'atom' => 'application/atom+xml',
58
+ 'atomcat' => 'application/atomcat+xml',
59
+ 'atomsvc' => 'application/atomsvc+xml',
60
+ 'atx' => 'application/vnd.antix.game-component',
61
+ 'au' => 'audio/basic',
62
+ 'avi' => 'video/x-msvideo',
63
+ 'aw' => 'application/applixware',
64
+ 'axd' => 'text/plain',
65
+ 'azf' => 'application/vnd.airzip.filesecure.azf',
66
+ 'azs' => 'application/vnd.airzip.filesecure.azs',
67
+ 'azw' => 'application/vnd.amazon.ebook',
68
+ 'bat' => 'application/x-msdownload',
69
+ 'bcpio' => 'application/x-bcpio',
70
+ 'bdf' => 'application/x-font-bdf',
71
+ 'bdm' => 'application/vnd.syncml.dm+wbxml',
72
+ 'bed' => 'application/vnd.realvnc.bed',
73
+ 'bh2' => 'application/vnd.fujitsu.oasysprs',
74
+ 'bin' => 'application/octet-stream',
75
+ 'bmi' => 'application/vnd.bmi',
76
+ 'bmp' => 'image/bmp',
77
+ 'book' => 'application/vnd.framemaker',
78
+ 'box' => 'application/vnd.previewsystems.box',
79
+ 'boz' => 'application/x-bzip2',
80
+ 'bpk' => 'application/octet-stream',
81
+ 'btif' => 'image/prs.btif',
82
+ 'bz' => 'application/x-bzip',
83
+ 'bz2' => 'application/x-bzip2',
84
+ 'c' => 'text/x-c',
85
+ 'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
86
+ 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
87
+ 'c4d' => 'application/vnd.clonk.c4group',
88
+ 'c4f' => 'application/vnd.clonk.c4group',
89
+ 'c4g' => 'application/vnd.clonk.c4group',
90
+ 'c4p' => 'application/vnd.clonk.c4group',
91
+ 'c4u' => 'application/vnd.clonk.c4group',
92
+ 'cab' => 'application/vnd.ms-cab-compressed',
93
+ 'car' => 'application/vnd.curl.car',
94
+ 'cat' => 'application/vnd.ms-pki.seccat',
95
+ 'cc' => 'text/x-c',
96
+ 'cct' => 'application/x-director',
97
+ 'ccxml' => 'application/ccxml+xml',
98
+ 'cdbcmsg' => 'application/vnd.contact.cmsg',
99
+ 'cdf' => 'application/x-netcdf',
100
+ 'cdkey' => 'application/vnd.mediastation.cdkey',
101
+ 'cdmia' => 'application/cdmi-capability',
102
+ 'cdmic' => 'application/cdmi-container',
103
+ 'cdmid' => 'application/cdmi-domain',
104
+ 'cdmio' => 'application/cdmi-object',
105
+ 'cdmiq' => 'application/cdmi-queue',
106
+ 'cdx' => 'chemical/x-cdx',
107
+ 'cdxml' => 'application/vnd.chemdraw+xml',
108
+ 'cdy' => 'application/vnd.cinderella',
109
+ 'cer' => 'application/pkix-cert',
110
+ 'cfc' => 'application/x-coldfusion',
111
+ 'cfm' => 'application/x-coldfusion',
112
+ 'cgm' => 'image/cgm',
113
+ 'chat' => 'application/x-chat',
114
+ 'chm' => 'application/vnd.ms-htmlhelp',
115
+ 'chrt' => 'application/vnd.kde.kchart',
116
+ 'cif' => 'chemical/x-cif',
117
+ 'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
118
+ 'cil' => 'application/vnd.ms-artgalry',
119
+ 'cla' => 'application/vnd.claymore',
120
+ 'class' => 'application/java-vm',
121
+ 'clkk' => 'application/vnd.crick.clicker.keyboard',
122
+ 'clkp' => 'application/vnd.crick.clicker.palette',
123
+ 'clkt' => 'application/vnd.crick.clicker.template',
124
+ 'clkw' => 'application/vnd.crick.clicker.wordbank',
125
+ 'clkx' => 'application/vnd.crick.clicker',
126
+ 'clp' => 'application/x-msclip',
127
+ 'cmc' => 'application/vnd.cosmocaller',
128
+ 'cmdf' => 'chemical/x-cmdf',
129
+ 'cml' => 'chemical/x-cml',
130
+ 'cmp' => 'application/vnd.yellowriver-custom-menu',
131
+ 'cmx' => 'image/x-cmx',
132
+ 'cod' => 'application/vnd.rim.cod',
133
+ 'com' => 'application/x-msdownload',
134
+ 'conf' => 'text/plain',
135
+ 'cpio' => 'application/x-cpio',
136
+ 'cpp' => 'text/x-c',
137
+ 'cpt' => 'application/mac-compactpro',
138
+ 'crd' => 'application/x-mscardfile',
139
+ 'crl' => 'application/pkix-crl',
140
+ 'crt' => 'application/x-x509-ca-cert',
141
+ 'cryptonote' => 'application/vnd.rig.cryptonote',
142
+ 'cs' => 'text/plain',
143
+ 'csh' => 'application/x-csh',
144
+ 'csml' => 'chemical/x-csml',
145
+ 'csp' => 'application/vnd.commonspace',
146
+ 'css' => 'text/css',
147
+ 'cst' => 'application/x-director',
148
+ 'csv' => 'text/csv',
149
+ 'cu' => 'application/cu-seeme',
150
+ 'curl' => 'text/vnd.curl',
151
+ 'cww' => 'application/prs.cww',
152
+ 'cxt' => 'application/x-director',
153
+ 'cxx' => 'text/x-c',
154
+ 'dae' => 'model/vnd.collada+xml',
155
+ 'daf' => 'application/vnd.mobius.daf',
156
+ 'dataless' => 'application/vnd.fdsn.seed',
157
+ 'davmount' => 'application/davmount+xml',
158
+ 'dcr' => 'application/x-director',
159
+ 'dcurl' => 'text/vnd.curl.dcurl',
160
+ 'dd2' => 'application/vnd.oma.dd2+xml',
161
+ 'ddd' => 'application/vnd.fujixerox.ddd',
162
+ 'deb' => 'application/x-debian-package',
163
+ 'def' => 'text/plain',
164
+ 'deploy' => 'application/octet-stream',
165
+ 'der' => 'application/x-x509-ca-cert',
166
+ 'dfac' => 'application/vnd.dreamfactory',
167
+ 'dic' => 'text/x-c',
168
+ 'dir' => 'application/x-director',
169
+ 'dis' => 'application/vnd.mobius.dis',
170
+ 'dist' => 'application/octet-stream',
171
+ 'distz' => 'application/octet-stream',
172
+ 'djv' => 'image/vnd.djvu',
173
+ 'djvu' => 'image/vnd.djvu',
174
+ 'dll' => 'application/x-msdownload',
175
+ 'dmg' => 'application/octet-stream',
176
+ 'dms' => 'application/octet-stream',
177
+ 'dna' => 'application/vnd.dna',
178
+ 'doc' => 'application/msword',
179
+ 'docm' => 'application/vnd.ms-word.document.macroenabled.12',
180
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
181
+ 'dot' => 'application/msword',
182
+ 'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
183
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
184
+ 'dp' => 'application/vnd.osgi.dp',
185
+ 'dpg' => 'application/vnd.dpgraph',
186
+ 'dra' => 'audio/vnd.dra',
187
+ 'dsc' => 'text/prs.lines.tag',
188
+ 'dssc' => 'application/dssc+der',
189
+ 'dtb' => 'application/x-dtbook+xml',
190
+ 'dtd' => 'application/xml-dtd',
191
+ 'dts' => 'audio/vnd.dts',
192
+ 'dtshd' => 'audio/vnd.dts.hd',
193
+ 'dump' => 'application/octet-stream',
194
+ 'dvi' => 'application/x-dvi',
195
+ 'dwf' => 'model/vnd.dwf',
196
+ 'dwg' => 'image/vnd.dwg',
197
+ 'dxf' => 'image/vnd.dxf',
198
+ 'dxp' => 'application/vnd.spotfire.dxp',
199
+ 'dxr' => 'application/x-director',
200
+ 'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
201
+ 'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
202
+ 'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
203
+ 'ecma' => 'application/ecmascript',
204
+ 'edm' => 'application/vnd.novadigm.edm',
205
+ 'edx' => 'application/vnd.novadigm.edx',
206
+ 'efif' => 'application/vnd.picsel',
207
+ 'ei6' => 'application/vnd.pg.osasli',
208
+ 'elc' => 'application/octet-stream',
209
+ 'eml' => 'message/rfc822',
210
+ 'emma' => 'application/emma+xml',
211
+ 'eol' => 'audio/vnd.digital-winds',
212
+ 'eot' => 'application/vnd.ms-fontobject',
213
+ 'eps' => 'application/postscript',
214
+ 'epub' => 'application/epub+zip',
215
+ 'es3' => 'application/vnd.eszigno3+xml',
216
+ 'esf' => 'application/vnd.epson.esf',
217
+ 'et3' => 'application/vnd.eszigno3+xml',
218
+ 'etx' => 'text/x-setext',
219
+ 'exe' => 'application/x-msdownload',
220
+ 'exi' => 'application/exi',
221
+ 'ext' => 'application/vnd.novadigm.ext',
222
+ 'ez' => 'application/andrew-inset',
223
+ 'ez2' => 'application/vnd.ezpix-album',
224
+ 'ez3' => 'application/vnd.ezpix-package',
225
+ 'f' => 'text/x-fortran',
226
+ 'f4v' => 'video/x-f4v',
227
+ 'f77' => 'text/x-fortran',
228
+ 'f90' => 'text/x-fortran',
229
+ 'fbs' => 'image/vnd.fastbidsheet',
230
+ 'fcs' => 'application/vnd.isac.fcs',
231
+ 'fdf' => 'application/vnd.fdf',
232
+ 'fe_launch' => 'application/vnd.denovo.fcselayout-link',
233
+ 'fg5' => 'application/vnd.fujitsu.oasysgp',
234
+ 'fgd' => 'application/x-director',
235
+ 'fh' => 'image/x-freehand',
236
+ 'fh4' => 'image/x-freehand',
237
+ 'fh5' => 'image/x-freehand',
238
+ 'fh7' => 'image/x-freehand',
239
+ 'fhc' => 'image/x-freehand',
240
+ 'fig' => 'application/x-xfig',
241
+ 'fli' => 'video/x-fli',
242
+ 'flo' => 'application/vnd.micrografx.flo',
243
+ 'flv' => 'video/x-flv',
244
+ 'flw' => 'application/vnd.kde.kivio',
245
+ 'flx' => 'text/vnd.fmi.flexstor',
246
+ 'fly' => 'text/vnd.fly',
247
+ 'fm' => 'application/vnd.framemaker',
248
+ 'fnc' => 'application/vnd.frogans.fnc',
249
+ 'for' => 'text/x-fortran',
250
+ 'fpx' => 'image/vnd.fpx',
251
+ 'frame' => 'application/vnd.framemaker',
252
+ 'fsc' => 'application/vnd.fsc.weblaunch',
253
+ 'fst' => 'image/vnd.fst',
254
+ 'ftc' => 'application/vnd.fluxtime.clip',
255
+ 'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
256
+ 'fvt' => 'video/vnd.fvt',
257
+ 'fxp' => 'application/vnd.adobe.fxp',
258
+ 'fxpl' => 'application/vnd.adobe.fxp',
259
+ 'fzs' => 'application/vnd.fuzzysheet',
260
+ 'g2w' => 'application/vnd.geoplan',
261
+ 'g3' => 'image/g3fax',
262
+ 'g3w' => 'application/vnd.geospace',
263
+ 'gac' => 'application/vnd.groove-account',
264
+ 'gdl' => 'model/vnd.gdl',
265
+ 'geo' => 'application/vnd.dynageo',
266
+ 'gex' => 'application/vnd.geometry-explorer',
267
+ 'ggb' => 'application/vnd.geogebra.file',
268
+ 'ggt' => 'application/vnd.geogebra.tool',
269
+ 'ghf' => 'application/vnd.groove-help',
270
+ 'gif' => 'image/gif',
271
+ 'gim' => 'application/vnd.groove-identity-message',
272
+ 'gmx' => 'application/vnd.gmx',
273
+ 'gnumeric' => 'application/x-gnumeric',
274
+ 'gph' => 'application/vnd.flographit',
275
+ 'gqf' => 'application/vnd.grafeq',
276
+ 'gqs' => 'application/vnd.grafeq',
277
+ 'gram' => 'application/srgs',
278
+ 'gre' => 'application/vnd.geometry-explorer',
279
+ 'grv' => 'application/vnd.groove-injector',
280
+ 'grxml' => 'application/srgs+xml',
281
+ 'gsf' => 'application/x-font-ghostscript',
282
+ 'gtar' => 'application/x-gtar',
283
+ 'gtm' => 'application/vnd.groove-tool-message',
284
+ 'gtw' => 'model/vnd.gtw',
285
+ 'gv' => 'text/vnd.graphviz',
286
+ 'gxt' => 'application/vnd.geonext',
287
+ 'h' => 'text/x-c',
288
+ 'h261' => 'video/h261',
289
+ 'h263' => 'video/h263',
290
+ 'h264' => 'video/h264',
291
+ 'hal' => 'application/vnd.hal+xml',
292
+ 'hbci' => 'application/vnd.hbci',
293
+ 'hdf' => 'application/x-hdf',
294
+ 'hh' => 'text/x-c',
295
+ 'hlp' => 'application/winhlp',
296
+ 'hpgl' => 'application/vnd.hp-hpgl',
297
+ 'hpid' => 'application/vnd.hp-hpid',
298
+ 'hps' => 'application/vnd.hp-hps',
299
+ 'hqx' => 'application/mac-binhex40',
300
+ 'hta' => 'application/octet-stream',
301
+ 'htc' => 'text/html',
302
+ 'htke' => 'application/vnd.kenameaapp',
303
+ 'htm' => 'text/html',
304
+ 'html' => 'text/html',
305
+ 'hvd' => 'application/vnd.yamaha.hv-dic',
306
+ 'hvp' => 'application/vnd.yamaha.hv-voice',
307
+ 'hvs' => 'application/vnd.yamaha.hv-script',
308
+ 'i2g' => 'application/vnd.intergeo',
309
+ 'icc' => 'application/vnd.iccprofile',
310
+ 'ice' => 'x-conference/x-cooltalk',
311
+ 'icm' => 'application/vnd.iccprofile',
312
+ 'ico' => 'image/x-icon',
313
+ 'ics' => 'text/calendar',
314
+ 'ief' => 'image/ief',
315
+ 'ifb' => 'text/calendar',
316
+ 'ifm' => 'application/vnd.shana.informed.formdata',
317
+ 'iges' => 'model/iges',
318
+ 'igl' => 'application/vnd.igloader',
319
+ 'igm' => 'application/vnd.insors.igm',
320
+ 'igs' => 'model/iges',
321
+ 'igx' => 'application/vnd.micrografx.igx',
322
+ 'iif' => 'application/vnd.shana.informed.interchange',
323
+ 'imp' => 'application/vnd.accpac.simply.imp',
324
+ 'ims' => 'application/vnd.ms-ims',
325
+ 'in' => 'text/plain',
326
+ 'ini' => 'text/plain',
327
+ 'ipfix' => 'application/ipfix',
328
+ 'ipk' => 'application/vnd.shana.informed.package',
329
+ 'irm' => 'application/vnd.ibm.rights-management',
330
+ 'irp' => 'application/vnd.irepository.package+xml',
331
+ 'iso' => 'application/octet-stream',
332
+ 'itp' => 'application/vnd.shana.informed.formtemplate',
333
+ 'ivp' => 'application/vnd.immervision-ivp',
334
+ 'ivu' => 'application/vnd.immervision-ivu',
335
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
336
+ 'jam' => 'application/vnd.jam',
337
+ 'jar' => 'application/java-archive',
338
+ 'java' => 'text/x-java-source',
339
+ 'jisp' => 'application/vnd.jisp',
340
+ 'jlt' => 'application/vnd.hp-jlyt',
341
+ 'jnlp' => 'application/x-java-jnlp-file',
342
+ 'joda' => 'application/vnd.joost.joda-archive',
343
+ 'jpe' => 'image/jpeg',
344
+ 'jpeg' => 'image/jpeg',
345
+ 'jpg' => 'image/jpeg',
346
+ 'jpgm' => 'video/jpm',
347
+ 'jpgv' => 'video/jpeg',
348
+ 'jpm' => 'video/jpm',
349
+ 'js' => 'text/javascript',
350
+ 'json' => 'application/json',
351
+ 'kar' => 'audio/midi',
352
+ 'karbon' => 'application/vnd.kde.karbon',
353
+ 'kfo' => 'application/vnd.kde.kformula',
354
+ 'kia' => 'application/vnd.kidspiration',
355
+ 'kml' => 'application/vnd.google-earth.kml+xml',
356
+ 'kmz' => 'application/vnd.google-earth.kmz',
357
+ 'kne' => 'application/vnd.kinar',
358
+ 'knp' => 'application/vnd.kinar',
359
+ 'kon' => 'application/vnd.kde.kontour',
360
+ 'kpr' => 'application/vnd.kde.kpresenter',
361
+ 'kpt' => 'application/vnd.kde.kpresenter',
362
+ 'ksp' => 'application/vnd.kde.kspread',
363
+ 'ktr' => 'application/vnd.kahootz',
364
+ 'ktx' => 'image/ktx',
365
+ 'ktz' => 'application/vnd.kahootz',
366
+ 'kwd' => 'application/vnd.kde.kword',
367
+ 'kwt' => 'application/vnd.kde.kword',
368
+ 'lasxml' => 'application/vnd.las.las+xml',
369
+ 'latex' => 'application/x-latex',
370
+ 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
371
+ 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
372
+ 'les' => 'application/vnd.hhe.lesson-player',
373
+ 'lha' => 'application/octet-stream',
374
+ 'link66' => 'application/vnd.route66.link66+xml',
375
+ 'list' => 'text/plain',
376
+ 'list3820' => 'application/vnd.ibm.modcap',
377
+ 'listafp' => 'application/vnd.ibm.modcap',
378
+ 'log' => 'text/plain',
379
+ 'lostxml' => 'application/lost+xml',
380
+ 'lrf' => 'application/octet-stream',
381
+ 'lrm' => 'application/vnd.ms-lrm',
382
+ 'ltf' => 'application/vnd.frogans.ltf',
383
+ 'lvp' => 'audio/vnd.lucent.voice',
384
+ 'lwp' => 'application/vnd.lotus-wordpro',
385
+ 'lzh' => 'application/octet-stream',
386
+ 'm13' => 'application/x-msmediaview',
387
+ 'm14' => 'application/x-msmediaview',
388
+ 'm1v' => 'video/mpeg',
389
+ 'm21' => 'application/mp21',
390
+ 'm2a' => 'audio/mpeg',
391
+ 'm2v' => 'video/mpeg',
392
+ 'm3a' => 'audio/mpeg',
393
+ 'm3u' => 'audio/x-mpegurl',
394
+ 'm3u8' => 'application/vnd.apple.mpegurl',
395
+ 'm4a' => 'audio/mp4',
396
+ 'm4u' => 'video/vnd.mpegurl',
397
+ 'm4v' => 'video/mp4',
398
+ 'ma' => 'application/mathematica',
399
+ 'mads' => 'application/mads+xml',
400
+ 'mag' => 'application/vnd.ecowin.chart',
401
+ 'maker' => 'application/vnd.framemaker',
402
+ 'man' => 'text/troff',
403
+ 'mathml' => 'application/mathml+xml',
404
+ 'mb' => 'application/mathematica',
405
+ 'mbk' => 'application/vnd.mobius.mbk',
406
+ 'mbox' => 'application/mbox',
407
+ 'mc1' => 'application/vnd.medcalcdata',
408
+ 'mcd' => 'application/vnd.mcd',
409
+ 'mcurl' => 'text/vnd.curl.mcurl',
410
+ 'mdb' => 'application/x-msaccess',
411
+ 'mdi' => 'image/vnd.ms-modi',
412
+ 'me' => 'text/troff',
413
+ 'mesh' => 'model/mesh',
414
+ 'meta4' => 'application/metalink4+xml',
415
+ 'mets' => 'application/mets+xml',
416
+ 'mfm' => 'application/vnd.mfmp',
417
+ 'mgp' => 'application/vnd.osgeo.mapguide.package',
418
+ 'mgz' => 'application/vnd.proteus.magazine',
419
+ 'mid' => 'audio/midi',
420
+ 'midi' => 'audio/midi',
421
+ 'mif' => 'application/vnd.mif',
422
+ 'mime' => 'message/rfc822',
423
+ 'mj2' => 'video/mj2',
424
+ 'mjp2' => 'video/mj2',
425
+ 'mlp' => 'application/vnd.dolby.mlp',
426
+ 'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
427
+ 'mmf' => 'application/vnd.smaf',
428
+ 'mmr' => 'image/vnd.fujixerox.edmics-mmr',
429
+ 'mny' => 'application/x-msmoney',
430
+ 'mobi' => 'application/x-mobipocket-ebook',
431
+ 'mods' => 'application/mods+xml',
432
+ 'mov' => 'video/quicktime',
433
+ 'movie' => 'video/x-sgi-movie',
434
+ 'mp2' => 'audio/mpeg',
435
+ 'mp21' => 'application/mp21',
436
+ 'mp2a' => 'audio/mpeg',
437
+ 'mp3' => 'audio/mpeg',
438
+ 'mp4' => 'video/mp4',
439
+ 'mp4a' => 'audio/mp4',
440
+ 'mp4s' => 'application/mp4',
441
+ 'mp4v' => 'video/mp4',
442
+ 'mpc' => 'application/vnd.mophun.certificate',
443
+ 'mpe' => 'video/mpeg',
444
+ 'mpeg' => 'video/mpeg',
445
+ 'mpg' => 'video/mpeg',
446
+ 'mpg4' => 'video/mp4',
447
+ 'mpga' => 'audio/mpeg',
448
+ 'mpkg' => 'application/vnd.apple.installer+xml',
449
+ 'mpm' => 'application/vnd.blueice.multipass',
450
+ 'mpn' => 'application/vnd.mophun.application',
451
+ 'mpp' => 'application/vnd.ms-project',
452
+ 'mpt' => 'application/vnd.ms-project',
453
+ 'mpy' => 'application/vnd.ibm.minipay',
454
+ 'mqy' => 'application/vnd.mobius.mqy',
455
+ 'mrc' => 'application/marc',
456
+ 'mrcx' => 'application/marcxml+xml',
457
+ 'ms' => 'text/troff',
458
+ 'mscml' => 'application/mediaservercontrol+xml',
459
+ 'mseed' => 'application/vnd.fdsn.mseed',
460
+ 'mseq' => 'application/vnd.mseq',
461
+ 'msf' => 'application/vnd.epson.msf',
462
+ 'msh' => 'model/mesh',
463
+ 'msi' => 'application/x-msdownload',
464
+ 'msl' => 'application/vnd.mobius.msl',
465
+ 'msty' => 'application/vnd.muvee.style',
466
+ 'mts' => 'model/vnd.mts',
467
+ 'mus' => 'application/vnd.musician',
468
+ 'musicxml' => 'application/vnd.recordare.musicxml+xml',
469
+ 'mvb' => 'application/x-msmediaview',
470
+ 'mwf' => 'application/vnd.mfer',
471
+ 'mxf' => 'application/mxf',
472
+ 'mxl' => 'application/vnd.recordare.musicxml',
473
+ 'mxml' => 'application/xv+xml',
474
+ 'mxs' => 'application/vnd.triscape.mxs',
475
+ 'mxu' => 'video/vnd.mpegurl',
476
+ 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
477
+ 'n3' => 'text/n3',
478
+ 'nb' => 'application/mathematica',
479
+ 'nbp' => 'application/vnd.wolfram.player',
480
+ 'nc' => 'application/x-netcdf',
481
+ 'ncx' => 'application/x-dtbncx+xml',
482
+ 'ngdat' => 'application/vnd.nokia.n-gage.data',
483
+ 'nlu' => 'application/vnd.neurolanguage.nlu',
484
+ 'nml' => 'application/vnd.enliven',
485
+ 'nnd' => 'application/vnd.noblenet-directory',
486
+ 'nns' => 'application/vnd.noblenet-sealer',
487
+ 'nnw' => 'application/vnd.noblenet-web',
488
+ 'npx' => 'image/vnd.net-fpx',
489
+ 'nsf' => 'application/vnd.lotus-notes',
490
+ 'oa2' => 'application/vnd.fujitsu.oasys2',
491
+ 'oa3' => 'application/vnd.fujitsu.oasys3',
492
+ 'oas' => 'application/vnd.fujitsu.oasys',
493
+ 'obd' => 'application/x-msbinder',
494
+ 'oda' => 'application/oda',
495
+ 'odb' => 'application/vnd.oasis.opendocument.database',
496
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
497
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
498
+ 'odft' => 'application/vnd.oasis.opendocument.formula-template',
499
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
500
+ 'odi' => 'application/vnd.oasis.opendocument.image',
501
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
502
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
503
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
504
+ 'odt' => 'application/vnd.oasis.opendocument.text',
505
+ 'oga' => 'audio/ogg',
506
+ 'ogg' => 'audio/ogg',
507
+ 'ogv' => 'video/ogg',
508
+ 'ogx' => 'application/ogg',
509
+ 'onepkg' => 'application/onenote',
510
+ 'onetmp' => 'application/onenote',
511
+ 'onetoc' => 'application/onenote',
512
+ 'onetoc2' => 'application/onenote',
513
+ 'opf' => 'application/oebps-package+xml',
514
+ 'oprc' => 'application/vnd.palm',
515
+ 'org' => 'application/vnd.lotus-organizer',
516
+ 'osf' => 'application/vnd.yamaha.openscoreformat',
517
+ 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
518
+ 'otc' => 'application/vnd.oasis.opendocument.chart-template',
519
+ 'otf' => 'application/x-font-otf',
520
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
521
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
522
+ 'oti' => 'application/vnd.oasis.opendocument.image-template',
523
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
524
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
525
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
526
+ 'oxt' => 'application/vnd.openofficeorg.extension',
527
+ 'p' => 'text/x-pascal',
528
+ 'p10' => 'application/pkcs10',
529
+ 'p12' => 'application/x-pkcs12',
530
+ 'p7b' => 'application/x-pkcs7-certificates',
531
+ 'p7c' => 'application/pkcs7-mime',
532
+ 'p7m' => 'application/pkcs7-mime',
533
+ 'p7r' => 'application/x-pkcs7-certreqresp',
534
+ 'p7s' => 'application/pkcs7-signature',
535
+ 'p8' => 'application/pkcs8',
536
+ 'pas' => 'text/x-pascal',
537
+ 'paw' => 'application/vnd.pawaafile',
538
+ 'pbd' => 'application/vnd.powerbuilder6',
539
+ 'pbm' => 'image/x-portable-bitmap',
540
+ 'pcf' => 'application/x-font-pcf',
541
+ 'pcl' => 'application/vnd.hp-pcl',
542
+ 'pclxl' => 'application/vnd.hp-pclxl',
543
+ 'pct' => 'image/x-pict',
544
+ 'pcurl' => 'application/vnd.curl.pcurl',
545
+ 'pcx' => 'image/x-pcx',
546
+ 'pdb' => 'application/vnd.palm',
547
+ 'pdf' => 'application/pdf',
548
+ 'pfa' => 'application/x-font-type1',
549
+ 'pfb' => 'application/x-font-type1',
550
+ 'pfm' => 'application/x-font-type1',
551
+ 'pfr' => 'application/font-tdpfr',
552
+ 'pfx' => 'application/x-pkcs12',
553
+ 'pgm' => 'image/x-portable-graymap',
554
+ 'pgn' => 'application/x-chess-pgn',
555
+ 'pgp' => 'application/pgp-encrypted',
556
+ 'php' => 'text/x-php',
557
+ 'phps' => 'application/x-httpd-phps',
558
+ 'pic' => 'image/x-pict',
559
+ 'pkg' => 'application/octet-stream',
560
+ 'pki' => 'application/pkixcmp',
561
+ 'pkipath' => 'application/pkix-pkipath',
562
+ 'plb' => 'application/vnd.3gpp.pic-bw-large',
563
+ 'plc' => 'application/vnd.mobius.plc',
564
+ 'plf' => 'application/vnd.pocketlearn',
565
+ 'pls' => 'application/pls+xml',
566
+ 'pml' => 'application/vnd.ctc-posml',
567
+ 'png' => 'image/png',
568
+ 'pnm' => 'image/x-portable-anymap',
569
+ 'portpkg' => 'application/vnd.macports.portpkg',
570
+ 'pot' => 'application/vnd.ms-powerpoint',
571
+ 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
572
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
573
+ 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
574
+ 'ppd' => 'application/vnd.cups-ppd',
575
+ 'ppm' => 'image/x-portable-pixmap',
576
+ 'pps' => 'application/vnd.ms-powerpoint',
577
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
578
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
579
+ 'ppt' => 'application/vnd.ms-powerpoint',
580
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
581
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
582
+ 'pqa' => 'application/vnd.palm',
583
+ 'prc' => 'application/x-mobipocket-ebook',
584
+ 'pre' => 'application/vnd.lotus-freelance',
585
+ 'prf' => 'application/pics-rules',
586
+ 'ps' => 'application/postscript',
587
+ 'psb' => 'application/vnd.3gpp.pic-bw-small',
588
+ 'psd' => 'image/vnd.adobe.photoshop',
589
+ 'psf' => 'application/x-font-linux-psf',
590
+ 'pskcxml' => 'application/pskc+xml',
591
+ 'ptid' => 'application/vnd.pvi.ptid1',
592
+ 'pub' => 'application/x-mspublisher',
593
+ 'pvb' => 'application/vnd.3gpp.pic-bw-var',
594
+ 'pwn' => 'application/vnd.3m.post-it-notes',
595
+ 'pya' => 'audio/vnd.ms-playready.media.pya',
596
+ 'pyv' => 'video/vnd.ms-playready.media.pyv',
597
+ 'qam' => 'application/vnd.epson.quickanime',
598
+ 'qbo' => 'application/vnd.intu.qbo',
599
+ 'qfx' => 'application/vnd.intu.qfx',
600
+ 'qps' => 'application/vnd.publishare-delta-tree',
601
+ 'qt' => 'video/quicktime',
602
+ 'qwd' => 'application/vnd.quark.quarkxpress',
603
+ 'qwt' => 'application/vnd.quark.quarkxpress',
604
+ 'qxb' => 'application/vnd.quark.quarkxpress',
605
+ 'qxd' => 'application/vnd.quark.quarkxpress',
606
+ 'qxl' => 'application/vnd.quark.quarkxpress',
607
+ 'qxt' => 'application/vnd.quark.quarkxpress',
608
+ 'ra' => 'audio/x-pn-realaudio',
609
+ 'ram' => 'audio/x-pn-realaudio',
610
+ 'rar' => 'application/x-rar-compressed',
611
+ 'ras' => 'image/x-cmu-raster',
612
+ 'rb' => 'text/plain',
613
+ 'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
614
+ 'rdf' => 'application/rdf+xml',
615
+ 'rdz' => 'application/vnd.data-vision.rdz',
616
+ 'rep' => 'application/vnd.businessobjects',
617
+ 'res' => 'application/x-dtbresource+xml',
618
+ 'resx' => 'text/xml',
619
+ 'rgb' => 'image/x-rgb',
620
+ 'rif' => 'application/reginfo+xml',
621
+ 'rip' => 'audio/vnd.rip',
622
+ 'rl' => 'application/resource-lists+xml',
623
+ 'rlc' => 'image/vnd.fujixerox.edmics-rlc',
624
+ 'rld' => 'application/resource-lists-diff+xml',
625
+ 'rm' => 'application/vnd.rn-realmedia',
626
+ 'rmi' => 'audio/midi',
627
+ 'rmp' => 'audio/x-pn-realaudio-plugin',
628
+ 'rms' => 'application/vnd.jcp.javame.midlet-rms',
629
+ 'rnc' => 'application/relax-ng-compact-syntax',
630
+ 'roff' => 'text/troff',
631
+ 'rp9' => 'application/vnd.cloanto.rp9',
632
+ 'rpss' => 'application/vnd.nokia.radio-presets',
633
+ 'rpst' => 'application/vnd.nokia.radio-preset',
634
+ 'rq' => 'application/sparql-query',
635
+ 'rs' => 'application/rls-services+xml',
636
+ 'rsd' => 'application/rsd+xml',
637
+ 'rss' => 'application/rss+xml',
638
+ 'rtf' => 'application/rtf',
639
+ 'rtx' => 'text/richtext',
640
+ 's' => 'text/x-asm',
641
+ 'saf' => 'application/vnd.yamaha.smaf-audio',
642
+ 'sbml' => 'application/sbml+xml',
643
+ 'sc' => 'application/vnd.ibm.secure-container',
644
+ 'scd' => 'application/x-msschedule',
645
+ 'scm' => 'application/vnd.lotus-screencam',
646
+ 'scq' => 'application/scvp-cv-request',
647
+ 'scs' => 'application/scvp-cv-response',
648
+ 'scurl' => 'text/vnd.curl.scurl',
649
+ 'sda' => 'application/vnd.stardivision.draw',
650
+ 'sdc' => 'application/vnd.stardivision.calc',
651
+ 'sdd' => 'application/vnd.stardivision.impress',
652
+ 'sdkd' => 'application/vnd.solent.sdkm+xml',
653
+ 'sdkm' => 'application/vnd.solent.sdkm+xml',
654
+ 'sdp' => 'application/sdp',
655
+ 'sdw' => 'application/vnd.stardivision.writer',
656
+ 'see' => 'application/vnd.seemail',
657
+ 'seed' => 'application/vnd.fdsn.seed',
658
+ 'sema' => 'application/vnd.sema',
659
+ 'semd' => 'application/vnd.semd',
660
+ 'semf' => 'application/vnd.semf',
661
+ 'ser' => 'application/java-serialized-object',
662
+ 'setpay' => 'application/set-payment-initiation',
663
+ 'setreg' => 'application/set-registration-initiation',
664
+ 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
665
+ 'sfs' => 'application/vnd.spotfire.sfs',
666
+ 'sgl' => 'application/vnd.stardivision.writer-global',
667
+ 'sgm' => 'text/sgml',
668
+ 'sgml' => 'text/sgml',
669
+ 'sh' => 'application/x-sh',
670
+ 'shar' => 'application/x-shar',
671
+ 'shf' => 'application/shf+xml',
672
+ 'sig' => 'application/pgp-signature',
673
+ 'silo' => 'model/mesh',
674
+ 'sis' => 'application/vnd.symbian.install',
675
+ 'sisx' => 'application/vnd.symbian.install',
676
+ 'sit' => 'application/x-stuffit',
677
+ 'sitx' => 'application/x-stuffitx',
678
+ 'skd' => 'application/vnd.koan',
679
+ 'skm' => 'application/vnd.koan',
680
+ 'skp' => 'application/vnd.koan',
681
+ 'skt' => 'application/vnd.koan',
682
+ 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
683
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
684
+ 'slt' => 'application/vnd.epson.salt',
685
+ 'sm' => 'application/vnd.stepmania.stepchart',
686
+ 'smf' => 'application/vnd.stardivision.math',
687
+ 'smi' => 'application/smil+xml',
688
+ 'smil' => 'application/smil+xml',
689
+ 'snd' => 'audio/basic',
690
+ 'snf' => 'application/x-font-snf',
691
+ 'so' => 'application/octet-stream',
692
+ 'spc' => 'application/x-pkcs7-certificates',
693
+ 'spf' => 'application/vnd.yamaha.smaf-phrase',
694
+ 'spl' => 'application/x-futuresplash',
695
+ 'spot' => 'text/vnd.in3d.spot',
696
+ 'spp' => 'application/scvp-vp-response',
697
+ 'spq' => 'application/scvp-vp-request',
698
+ 'spx' => 'audio/ogg',
699
+ 'src' => 'application/x-wais-source',
700
+ 'sru' => 'application/sru+xml',
701
+ 'srx' => 'application/sparql-results+xml',
702
+ 'sse' => 'application/vnd.kodak-descriptor',
703
+ 'ssf' => 'application/vnd.epson.ssf',
704
+ 'ssml' => 'application/ssml+xml',
705
+ 'st' => 'application/vnd.sailingtracker.track',
706
+ 'stc' => 'application/vnd.sun.xml.calc.template',
707
+ 'std' => 'application/vnd.sun.xml.draw.template',
708
+ 'stf' => 'application/vnd.wt.stf',
709
+ 'sti' => 'application/vnd.sun.xml.impress.template',
710
+ 'stk' => 'application/hyperstudio',
711
+ 'stl' => 'application/vnd.ms-pki.stl',
712
+ 'str' => 'application/vnd.pg.format',
713
+ 'stw' => 'application/vnd.sun.xml.writer.template',
714
+ 'sub' => 'image/vnd.dvb.subtitle',
715
+ 'sus' => 'application/vnd.sus-calendar',
716
+ 'susp' => 'application/vnd.sus-calendar',
717
+ 'sv4cpio' => 'application/x-sv4cpio',
718
+ 'sv4crc' => 'application/x-sv4crc',
719
+ 'svc' => 'application/vnd.dvb.service',
720
+ 'svd' => 'application/vnd.svd',
721
+ 'svg' => 'image/svg+xml',
722
+ 'svgz' => 'image/svg+xml',
723
+ 'swa' => 'application/x-director',
724
+ 'swf' => 'application/x-shockwave-flash',
725
+ 'swi' => 'application/vnd.aristanetworks.swi',
726
+ 'sxc' => 'application/vnd.sun.xml.calc',
727
+ 'sxd' => 'application/vnd.sun.xml.draw',
728
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
729
+ 'sxi' => 'application/vnd.sun.xml.impress',
730
+ 'sxm' => 'application/vnd.sun.xml.math',
731
+ 'sxw' => 'application/vnd.sun.xml.writer',
732
+ 't' => 'text/troff',
733
+ 'tao' => 'application/vnd.tao.intent-module-archive',
734
+ 'tar' => 'application/x-tar',
735
+ 'tcap' => 'application/vnd.3gpp2.tcap',
736
+ 'tcl' => 'application/x-tcl',
737
+ 'teacher' => 'application/vnd.smart.teacher',
738
+ 'tei' => 'application/tei+xml',
739
+ 'teicorpus' => 'application/tei+xml',
740
+ 'tex' => 'application/x-tex',
741
+ 'texi' => 'application/x-texinfo',
742
+ 'texinfo' => 'application/x-texinfo',
743
+ 'text' => 'text/plain',
744
+ 'tfi' => 'application/thraud+xml',
745
+ 'tfm' => 'application/x-tex-tfm',
746
+ 'thmx' => 'application/vnd.ms-officetheme',
747
+ 'tif' => 'image/tiff',
748
+ 'tiff' => 'image/tiff',
749
+ 'tmo' => 'application/vnd.tmobile-livetv',
750
+ 'torrent' => 'application/x-bittorrent',
751
+ 'tpl' => 'application/vnd.groove-tool-template',
752
+ 'tpt' => 'application/vnd.trid.tpt',
753
+ 'tr' => 'text/troff',
754
+ 'tra' => 'application/vnd.trueapp',
755
+ 'trm' => 'application/x-msterminal',
756
+ 'tsd' => 'application/timestamped-data',
757
+ 'tsv' => 'text/tab-separated-values',
758
+ 'ttc' => 'application/x-font-ttf',
759
+ 'ttf' => 'application/x-font-ttf',
760
+ 'ttl' => 'text/turtle',
761
+ 'twd' => 'application/vnd.simtech-mindmapper',
762
+ 'twds' => 'application/vnd.simtech-mindmapper',
763
+ 'txd' => 'application/vnd.genomatix.tuxedo',
764
+ 'txf' => 'application/vnd.mobius.txf',
765
+ 'txt' => 'text/plain',
766
+ 'u32' => 'application/x-authorware-bin',
767
+ 'udeb' => 'application/x-debian-package',
768
+ 'ufd' => 'application/vnd.ufdl',
769
+ 'ufdl' => 'application/vnd.ufdl',
770
+ 'umj' => 'application/vnd.umajin',
771
+ 'unityweb' => 'application/vnd.unity',
772
+ 'uoml' => 'application/vnd.uoml+xml',
773
+ 'uri' => 'text/uri-list',
774
+ 'uris' => 'text/uri-list',
775
+ 'urls' => 'text/uri-list',
776
+ 'ustar' => 'application/x-ustar',
777
+ 'utz' => 'application/vnd.uiq.theme',
778
+ 'uu' => 'text/x-uuencode',
779
+ 'uva' => 'audio/vnd.dece.audio',
780
+ 'uvd' => 'application/vnd.dece.data',
781
+ 'uvf' => 'application/vnd.dece.data',
782
+ 'uvg' => 'image/vnd.dece.graphic',
783
+ 'uvh' => 'video/vnd.dece.hd',
784
+ 'uvi' => 'image/vnd.dece.graphic',
785
+ 'uvm' => 'video/vnd.dece.mobile',
786
+ 'uvp' => 'video/vnd.dece.pd',
787
+ 'uvs' => 'video/vnd.dece.sd',
788
+ 'uvt' => 'application/vnd.dece.ttml+xml',
789
+ 'uvu' => 'video/vnd.uvvu.mp4',
790
+ 'uvv' => 'video/vnd.dece.video',
791
+ 'uvva' => 'audio/vnd.dece.audio',
792
+ 'uvvd' => 'application/vnd.dece.data',
793
+ 'uvvf' => 'application/vnd.dece.data',
794
+ 'uvvg' => 'image/vnd.dece.graphic',
795
+ 'uvvh' => 'video/vnd.dece.hd',
796
+ 'uvvi' => 'image/vnd.dece.graphic',
797
+ 'uvvm' => 'video/vnd.dece.mobile',
798
+ 'uvvp' => 'video/vnd.dece.pd',
799
+ 'uvvs' => 'video/vnd.dece.sd',
800
+ 'uvvt' => 'application/vnd.dece.ttml+xml',
801
+ 'uvvu' => 'video/vnd.uvvu.mp4',
802
+ 'uvvv' => 'video/vnd.dece.video',
803
+ 'uvvx' => 'application/vnd.dece.unspecified',
804
+ 'uvx' => 'application/vnd.dece.unspecified',
805
+ 'vcd' => 'application/x-cdlink',
806
+ 'vcf' => 'text/x-vcard',
807
+ 'vcg' => 'application/vnd.groove-vcard',
808
+ 'vcs' => 'text/x-vcalendar',
809
+ 'vcx' => 'application/vnd.vcx',
810
+ 'vis' => 'application/vnd.visionary',
811
+ 'viv' => 'video/vnd.vivo',
812
+ 'vor' => 'application/vnd.stardivision.writer',
813
+ 'vox' => 'application/x-authorware-bin',
814
+ 'vrml' => 'model/vrml',
815
+ 'vsd' => 'application/vnd.visio',
816
+ 'vsf' => 'application/vnd.vsf',
817
+ 'vss' => 'application/vnd.visio',
818
+ 'vst' => 'application/vnd.visio',
819
+ 'vsw' => 'application/vnd.visio',
820
+ 'vtu' => 'model/vnd.vtu',
821
+ 'vxml' => 'application/voicexml+xml',
822
+ 'w3d' => 'application/x-director',
823
+ 'wad' => 'application/x-doom',
824
+ 'wav' => 'audio/x-wav',
825
+ 'wax' => 'audio/x-ms-wax',
826
+ 'wbmp' => 'image/vnd.wap.wbmp',
827
+ 'wbs' => 'application/vnd.criticaltools.wbs+xml',
828
+ 'wbxml' => 'application/vnd.wap.wbxml',
829
+ 'wcm' => 'application/vnd.ms-works',
830
+ 'wdb' => 'application/vnd.ms-works',
831
+ 'weba' => 'audio/webm',
832
+ 'webm' => 'video/webm',
833
+ 'webp' => 'image/webp',
834
+ 'wg' => 'application/vnd.pmi.widget',
835
+ 'wgt' => 'application/widget',
836
+ 'wks' => 'application/vnd.ms-works',
837
+ 'wm' => 'video/x-ms-wm',
838
+ 'wma' => 'audio/x-ms-wma',
839
+ 'wmd' => 'application/x-ms-wmd',
840
+ 'wmf' => 'application/x-msmetafile',
841
+ 'wml' => 'text/vnd.wap.wml',
842
+ 'wmlc' => 'application/vnd.wap.wmlc',
843
+ 'wmls' => 'text/vnd.wap.wmlscript',
844
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
845
+ 'wmv' => 'video/x-ms-wmv',
846
+ 'wmx' => 'video/x-ms-wmx',
847
+ 'wmz' => 'application/x-ms-wmz',
848
+ 'woff' => 'application/x-font-woff',
849
+ 'wpd' => 'application/vnd.wordperfect',
850
+ 'wpl' => 'application/vnd.ms-wpl',
851
+ 'wps' => 'application/vnd.ms-works',
852
+ 'wqd' => 'application/vnd.wqd',
853
+ 'wri' => 'application/x-mswrite',
854
+ 'wrl' => 'model/vrml',
855
+ 'wsdl' => 'application/wsdl+xml',
856
+ 'wspolicy' => 'application/wspolicy+xml',
857
+ 'wtb' => 'application/vnd.webturbo',
858
+ 'wvx' => 'video/x-ms-wvx',
859
+ 'x32' => 'application/x-authorware-bin',
860
+ 'x3d' => 'application/vnd.hzn-3d-crossword',
861
+ 'xap' => 'application/x-silverlight-app',
862
+ 'xar' => 'application/vnd.xara',
863
+ 'xbap' => 'application/x-ms-xbap',
864
+ 'xbd' => 'application/vnd.fujixerox.docuworks.binder',
865
+ 'xbm' => 'image/x-xbitmap',
866
+ 'xdf' => 'application/xcap-diff+xml',
867
+ 'xdm' => 'application/vnd.syncml.dm+xml',
868
+ 'xdp' => 'application/vnd.adobe.xdp+xml',
869
+ 'xdssc' => 'application/dssc+xml',
870
+ 'xdw' => 'application/vnd.fujixerox.docuworks',
871
+ 'xenc' => 'application/xenc+xml',
872
+ 'xer' => 'application/patch-ops-error+xml',
873
+ 'xfdf' => 'application/vnd.adobe.xfdf',
874
+ 'xfdl' => 'application/vnd.xfdl',
875
+ 'xht' => 'application/xhtml+xml',
876
+ 'xhtml' => 'application/xhtml+xml',
877
+ 'xhvml' => 'application/xv+xml',
878
+ 'xif' => 'image/vnd.xiff',
879
+ 'xla' => 'application/vnd.ms-excel',
880
+ 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
881
+ 'xlc' => 'application/vnd.ms-excel',
882
+ 'xlm' => 'application/vnd.ms-excel',
883
+ 'xls' => 'application/vnd.ms-excel',
884
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
885
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
886
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
887
+ 'xlt' => 'application/vnd.ms-excel',
888
+ 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
889
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
890
+ 'xlw' => 'application/vnd.ms-excel',
891
+ 'xml' => 'application/xml',
892
+ 'xo' => 'application/vnd.olpc-sugar',
893
+ 'xop' => 'application/xop+xml',
894
+ 'xpi' => 'application/x-xpinstall',
895
+ 'xpm' => 'image/x-xpixmap',
896
+ 'xpr' => 'application/vnd.is-xpr',
897
+ 'xps' => 'application/vnd.ms-xpsdocument',
898
+ 'xpw' => 'application/vnd.intercon.formnet',
899
+ 'xpx' => 'application/vnd.intercon.formnet',
900
+ 'xsl' => 'application/xml',
901
+ 'xslt' => 'application/xslt+xml',
902
+ 'xsm' => 'application/vnd.syncml+xml',
903
+ 'xspf' => 'application/xspf+xml',
904
+ 'xul' => 'application/vnd.mozilla.xul+xml',
905
+ 'xvm' => 'application/xv+xml',
906
+ 'xvml' => 'application/xv+xml',
907
+ 'xwd' => 'image/x-xwindowdump',
908
+ 'xyz' => 'chemical/x-xyz',
909
+ 'yaml' => 'text/yaml',
910
+ 'yang' => 'application/yang',
911
+ 'yin' => 'application/yin+xml',
912
+ 'yml' => 'text/yaml',
913
+ 'zaz' => 'application/vnd.zzazz.deck+xml',
914
+ 'zip' => 'application/zip',
915
+ 'zir' => 'application/vnd.zul',
916
+ 'zirz' => 'application/vnd.zul',
917
+ 'zmm' => 'application/vnd.handheld-entertainment+xml'
918
+ );
919
+
920
+ /**
921
+ * Get a singleton instance of the class
922
+ *
923
+ * @return self
924
+ * @codeCoverageIgnore
925
+ */
926
+ public static function getInstance()
927
+ {
928
+ if (!self::$instance) {
929
+ self::$instance = new self();
930
+ }
931
+
932
+ return self::$instance;
933
+ }
934
+
935
+ /**
936
+ * Get a mimetype value from a file extension
937
+ *
938
+ * @param string $extension File extension
939
+ *
940
+ * @return string|null
941
+ *
942
+ */
943
+ public function fromExtension($extension)
944
+ {
945
+ $extension = strtolower($extension);
946
+
947
+ return isset($this->mimetypes[$extension])
948
+ ? $this->mimetypes[$extension]
949
+ : null;
950
+ }
951
+
952
+ /**
953
+ * Get a mimetype from a filename
954
+ *
955
+ * @param string $filename Filename to generate a mimetype from
956
+ *
957
+ * @return string|null
958
+ */
959
+ public function fromFilename($filename)
960
+ {
961
+ return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
962
+ }
963
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Pool.php ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\BeforeEvent;
5
+ use GuzzleHttp\Event\RequestEvents;
6
+ use GuzzleHttp\Message\RequestInterface;
7
+ use GuzzleHttp\Message\ResponseInterface;
8
+ use GuzzleHttp\Ring\Core;
9
+ use GuzzleHttp\Ring\Future\FutureInterface;
10
+ use GuzzleHttp\Event\ListenerAttacherTrait;
11
+ use GuzzleHttp\Event\EndEvent;
12
+ use React\Promise\Deferred;
13
+ use React\Promise\FulfilledPromise;
14
+ use React\Promise\PromiseInterface;
15
+ use React\Promise\RejectedPromise;
16
+
17
+ /**
18
+ * Sends and iterator of requests concurrently using a capped pool size.
19
+ *
20
+ * The Pool object implements FutureInterface, meaning it can be used later
21
+ * when necessary, the requests provided to the pool can be cancelled, and
22
+ * you can check the state of the pool to know if it has been dereferenced
23
+ * (sent) or has been cancelled.
24
+ *
25
+ * When sending the pool, keep in mind that no results are returned: callers
26
+ * are expected to handle results asynchronously using Guzzle's event system.
27
+ * When requests complete, more are added to the pool to ensure that the
28
+ * requested pool size is always filled as much as possible.
29
+ *
30
+ * IMPORTANT: Do not provide a pool size greater that what the utilized
31
+ * underlying RingPHP handler can support. This will result is extremely poor
32
+ * performance.
33
+ */
34
+ class Pool implements FutureInterface
35
+ {
36
+ use ListenerAttacherTrait;
37
+
38
+ /** @var \GuzzleHttp\ClientInterface */
39
+ private $client;
40
+
41
+ /** @var \Iterator Yields requests */
42
+ private $iter;
43
+
44
+ /** @var Deferred */
45
+ private $deferred;
46
+
47
+ /** @var PromiseInterface */
48
+ private $promise;
49
+
50
+ private $waitQueue = [];
51
+ private $eventListeners = [];
52
+ private $poolSize;
53
+ private $isRealized = false;
54
+
55
+ /**
56
+ * The option values for 'before', 'complete', 'error' and 'end' can be a
57
+ * callable, an associative array containing event data, or an array of
58
+ * event data arrays. Event data arrays contain the following keys:
59
+ *
60
+ * - fn: callable to invoke that receives the event
61
+ * - priority: Optional event priority (defaults to 0)
62
+ * - once: Set to true so that the event is removed after it is triggered
63
+ *
64
+ * @param ClientInterface $client Client used to send the requests.
65
+ * @param array|\Iterator $requests Requests to send in parallel
66
+ * @param array $options Associative array of options
67
+ * - pool_size: (callable|int) Maximum number of requests to send
68
+ * concurrently, or a callback that receives
69
+ * the current queue size and returns the
70
+ * number of new requests to send
71
+ * - before: (callable|array) Receives a BeforeEvent
72
+ * - complete: (callable|array) Receives a CompleteEvent
73
+ * - error: (callable|array) Receives a ErrorEvent
74
+ * - end: (callable|array) Receives an EndEvent
75
+ */
76
+ public function __construct(
77
+ ClientInterface $client,
78
+ $requests,
79
+ array $options = []
80
+ ) {
81
+ $this->client = $client;
82
+ $this->iter = $this->coerceIterable($requests);
83
+ $this->deferred = new Deferred();
84
+ $this->promise = $this->deferred->promise();
85
+ $this->poolSize = isset($options['pool_size'])
86
+ ? $options['pool_size'] : 25;
87
+ $this->eventListeners = $this->prepareListeners(
88
+ $options,
89
+ ['before', 'complete', 'error', 'end']
90
+ );
91
+ }
92
+
93
+ /**
94
+ * Sends multiple requests in parallel and returns an array of responses
95
+ * and exceptions that uses the same ordering as the provided requests.
96
+ *
97
+ * IMPORTANT: This method keeps every request and response in memory, and
98
+ * as such, is NOT recommended when sending a large number or an
99
+ * indeterminate number of requests concurrently.
100
+ *
101
+ * @param ClientInterface $client Client used to send the requests
102
+ * @param array|\Iterator $requests Requests to send in parallel
103
+ * @param array $options Passes through the options available in
104
+ * {@see GuzzleHttp\Pool::__construct}
105
+ *
106
+ * @return BatchResults Returns a container for the results.
107
+ * @throws \InvalidArgumentException if the event format is incorrect.
108
+ */
109
+ public static function batch(
110
+ ClientInterface $client,
111
+ $requests,
112
+ array $options = []
113
+ ) {
114
+ $hash = new \SplObjectStorage();
115
+ foreach ($requests as $request) {
116
+ $hash->attach($request);
117
+ }
118
+
119
+ // In addition to the normally run events when requests complete, add
120
+ // and event to continuously track the results of transfers in the hash.
121
+ (new self($client, $requests, RequestEvents::convertEventArray(
122
+ $options,
123
+ ['end'],
124
+ [
125
+ 'priority' => RequestEvents::LATE,
126
+ 'fn' => function (EndEvent $e) use ($hash) {
127
+ $hash[$e->getRequest()] = $e->getException()
128
+ ? $e->getException()
129
+ : $e->getResponse();
130
+ }
131
+ ]
132
+ )))->wait();
133
+
134
+ return new BatchResults($hash);
135
+ }
136
+
137
+ /**
138
+ * Creates a Pool and immediately sends the requests.
139
+ *
140
+ * @param ClientInterface $client Client used to send the requests
141
+ * @param array|\Iterator $requests Requests to send in parallel
142
+ * @param array $options Passes through the options available in
143
+ * {@see GuzzleHttp\Pool::__construct}
144
+ */
145
+ public static function send(
146
+ ClientInterface $client,
147
+ $requests,
148
+ array $options = []
149
+ ) {
150
+ $pool = new self($client, $requests, $options);
151
+ $pool->wait();
152
+ }
153
+
154
+ private function getPoolSize()
155
+ {
156
+ return is_callable($this->poolSize)
157
+ ? call_user_func($this->poolSize, count($this->waitQueue))
158
+ : $this->poolSize;
159
+ }
160
+
161
+ /**
162
+ * Add as many requests as possible up to the current pool limit.
163
+ */
164
+ private function addNextRequests()
165
+ {
166
+ $limit = max($this->getPoolSize() - count($this->waitQueue), 0);
167
+ while ($limit--) {
168
+ if (!$this->addNextRequest()) {
169
+ break;
170
+ }
171
+ }
172
+ }
173
+
174
+ public function wait()
175
+ {
176
+ if ($this->isRealized) {
177
+ return false;
178
+ }
179
+
180
+ // Seed the pool with N number of requests.
181
+ $this->addNextRequests();
182
+
183
+ // Stop if the pool was cancelled while transferring requests.
184
+ if ($this->isRealized) {
185
+ return false;
186
+ }
187
+
188
+ // Wait on any outstanding FutureResponse objects.
189
+ while ($response = array_pop($this->waitQueue)) {
190
+ try {
191
+ $response->wait();
192
+ } catch (\Exception $e) {
193
+ // Eat exceptions because they should be handled asynchronously
194
+ }
195
+ $this->addNextRequests();
196
+ }
197
+
198
+ // Clean up no longer needed state.
199
+ $this->isRealized = true;
200
+ $this->waitQueue = $this->eventListeners = [];
201
+ $this->client = $this->iter = null;
202
+ $this->deferred->resolve(true);
203
+
204
+ return true;
205
+ }
206
+
207
+ /**
208
+ * {@inheritdoc}
209
+ *
210
+ * Attempt to cancel all outstanding requests (requests that are queued for
211
+ * dereferencing). Returns true if all outstanding requests can be
212
+ * cancelled.
213
+ *
214
+ * @return bool
215
+ */
216
+ public function cancel()
217
+ {
218
+ if ($this->isRealized) {
219
+ return false;
220
+ }
221
+
222
+ $success = $this->isRealized = true;
223
+ foreach ($this->waitQueue as $response) {
224
+ if (!$response->cancel()) {
225
+ $success = false;
226
+ }
227
+ }
228
+
229
+ return $success;
230
+ }
231
+
232
+ /**
233
+ * Returns a promise that is invoked when the pool completed. There will be
234
+ * no passed value.
235
+ *
236
+ * {@inheritdoc}
237
+ */
238
+ public function then(
239
+ callable $onFulfilled = null,
240
+ callable $onRejected = null,
241
+ callable $onProgress = null
242
+ ) {
243
+ return $this->promise->then($onFulfilled, $onRejected, $onProgress);
244
+ }
245
+
246
+ public function promise()
247
+ {
248
+ return $this->promise;
249
+ }
250
+
251
+ private function coerceIterable($requests)
252
+ {
253
+ if ($requests instanceof \Iterator) {
254
+ return $requests;
255
+ } elseif (is_array($requests)) {
256
+ return new \ArrayIterator($requests);
257
+ }
258
+
259
+ throw new \InvalidArgumentException('Expected Iterator or array. '
260
+ . 'Found ' . Core::describeType($requests));
261
+ }
262
+
263
+ /**
264
+ * Adds the next request to pool and tracks what requests need to be
265
+ * dereferenced when completing the pool.
266
+ */
267
+ private function addNextRequest()
268
+ {
269
+ add_next:
270
+
271
+ if ($this->isRealized || !$this->iter || !$this->iter->valid()) {
272
+ return false;
273
+ }
274
+
275
+ $request = $this->iter->current();
276
+ $this->iter->next();
277
+
278
+ if (!($request instanceof RequestInterface)) {
279
+ throw new \InvalidArgumentException(sprintf(
280
+ 'All requests in the provided iterator must implement '
281
+ . 'RequestInterface. Found %s',
282
+ Core::describeType($request)
283
+ ));
284
+ }
285
+
286
+ // Be sure to use "lazy" futures, meaning they do not send right away.
287
+ $request->getConfig()->set('future', 'lazy');
288
+ $hash = spl_object_hash($request);
289
+ $this->attachListeners($request, $this->eventListeners);
290
+ $request->getEmitter()->on('before', [$this, '_trackRetries'], RequestEvents::EARLY);
291
+ $response = $this->client->send($request);
292
+ $this->waitQueue[$hash] = $response;
293
+ $promise = $response->promise();
294
+
295
+ // Don't recursively call itself for completed or rejected responses.
296
+ if ($promise instanceof FulfilledPromise
297
+ || $promise instanceof RejectedPromise
298
+ ) {
299
+ try {
300
+ $this->finishResponse($request, $response->wait(), $hash);
301
+ } catch (\Exception $e) {
302
+ $this->finishResponse($request, $e, $hash);
303
+ }
304
+ goto add_next;
305
+ }
306
+
307
+ // Use this function for both resolution and rejection.
308
+ $thenFn = function ($value) use ($request, $hash) {
309
+ $this->finishResponse($request, $value, $hash);
310
+ if (!$request->getConfig()->get('_pool_retries')) {
311
+ $this->addNextRequests();
312
+ }
313
+ };
314
+
315
+ $promise->then($thenFn, $thenFn);
316
+
317
+ return true;
318
+ }
319
+
320
+ public function _trackRetries(BeforeEvent $e)
321
+ {
322
+ $e->getRequest()->getConfig()->set('_pool_retries', $e->getRetryCount());
323
+ }
324
+
325
+ private function finishResponse($request, $value, $hash)
326
+ {
327
+ unset($this->waitQueue[$hash]);
328
+ $result = $value instanceof ResponseInterface
329
+ ? ['request' => $request, 'response' => $value, 'error' => null]
330
+ : ['request' => $request, 'response' => null, 'error' => $value];
331
+ $this->deferred->notify($result);
332
+ }
333
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/MultipartBody.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Stream\AppendStream;
5
+ use GuzzleHttp\Stream\Stream;
6
+ use GuzzleHttp\Stream\StreamDecoratorTrait;
7
+ use GuzzleHttp\Stream\StreamInterface;
8
+
9
+ /**
10
+ * Stream that when read returns bytes for a streaming multipart/form-data body
11
+ */
12
+ class MultipartBody implements StreamInterface
13
+ {
14
+ use StreamDecoratorTrait;
15
+
16
+ private $boundary;
17
+
18
+ /**
19
+ * @param array $fields Associative array of field names to values where
20
+ * each value is a string or array of strings.
21
+ * @param array $files Associative array of PostFileInterface objects
22
+ * @param string $boundary You can optionally provide a specific boundary
23
+ * @throws \InvalidArgumentException
24
+ */
25
+ public function __construct(
26
+ array $fields = [],
27
+ array $files = [],
28
+ $boundary = null
29
+ ) {
30
+ $this->boundary = $boundary ?: uniqid();
31
+ $this->stream = $this->createStream($fields, $files);
32
+ }
33
+
34
+ /**
35
+ * Get the boundary
36
+ *
37
+ * @return string
38
+ */
39
+ public function getBoundary()
40
+ {
41
+ return $this->boundary;
42
+ }
43
+
44
+ public function isWritable()
45
+ {
46
+ return false;
47
+ }
48
+
49
+ /**
50
+ * Get the string needed to transfer a POST field
51
+ */
52
+ private function getFieldString($name, $value)
53
+ {
54
+ return sprintf(
55
+ "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
56
+ $this->boundary,
57
+ $name,
58
+ $value
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Get the headers needed before transferring the content of a POST file
64
+ */
65
+ private function getFileHeaders(PostFileInterface $file)
66
+ {
67
+ $headers = '';
68
+ foreach ($file->getHeaders() as $key => $value) {
69
+ $headers .= "{$key}: {$value}\r\n";
70
+ }
71
+
72
+ return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n";
73
+ }
74
+
75
+ /**
76
+ * Create the aggregate stream that will be used to upload the POST data
77
+ */
78
+ protected function createStream(array $fields, array $files)
79
+ {
80
+ $stream = new AppendStream();
81
+
82
+ foreach ($fields as $name => $fieldValues) {
83
+ foreach ((array) $fieldValues as $value) {
84
+ $stream->addStream(
85
+ Stream::factory($this->getFieldString($name, $value))
86
+ );
87
+ }
88
+ }
89
+
90
+ foreach ($files as $file) {
91
+
92
+ if (!$file instanceof PostFileInterface) {
93
+ throw new \InvalidArgumentException('All POST fields must '
94
+ . 'implement PostFieldInterface');
95
+ }
96
+
97
+ $stream->addStream(
98
+ Stream::factory($this->getFileHeaders($file))
99
+ );
100
+ $stream->addStream($file->getContent());
101
+ $stream->addStream(Stream::factory("\r\n"));
102
+ }
103
+
104
+ // Add the trailing boundary with CRLF
105
+ $stream->addStream(Stream::factory("--{$this->boundary}--\r\n"));
106
+
107
+ return $stream;
108
+ }
109
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostBody.php ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Stream\Exception\CannotAttachException;
6
+ use GuzzleHttp\Stream\StreamInterface;
7
+ use GuzzleHttp\Stream\Stream;
8
+ use GuzzleHttp\Query;
9
+
10
+ /**
11
+ * Holds POST fields and files and creates a streaming body when read methods
12
+ * are called on the object.
13
+ */
14
+ class PostBody implements PostBodyInterface
15
+ {
16
+ /** @var StreamInterface */
17
+ private $body;
18
+
19
+ /** @var callable */
20
+ private $aggregator;
21
+
22
+ private $fields = [];
23
+
24
+ /** @var PostFileInterface[] */
25
+ private $files = [];
26
+ private $forceMultipart = false;
27
+ private $detached = false;
28
+
29
+ /**
30
+ * Applies request headers to a request based on the POST state
31
+ *
32
+ * @param RequestInterface $request Request to update
33
+ */
34
+ public function applyRequestHeaders(RequestInterface $request)
35
+ {
36
+ if ($this->files || $this->forceMultipart) {
37
+ $request->setHeader(
38
+ 'Content-Type',
39
+ 'multipart/form-data; boundary=' . $this->getBody()->getBoundary()
40
+ );
41
+ } elseif ($this->fields && !$request->hasHeader('Content-Type')) {
42
+ $request->setHeader(
43
+ 'Content-Type',
44
+ 'application/x-www-form-urlencoded'
45
+ );
46
+ }
47
+
48
+ if ($size = $this->getSize()) {
49
+ $request->setHeader('Content-Length', $size);
50
+ }
51
+ }
52
+
53
+ public function forceMultipartUpload($force)
54
+ {
55
+ $this->forceMultipart = $force;
56
+ }
57
+
58
+ public function setAggregator(callable $aggregator)
59
+ {
60
+ $this->aggregator = $aggregator;
61
+ }
62
+
63
+ public function setField($name, $value)
64
+ {
65
+ $this->fields[$name] = $value;
66
+ $this->mutate();
67
+ }
68
+
69
+ public function replaceFields(array $fields)
70
+ {
71
+ $this->fields = $fields;
72
+ $this->mutate();
73
+ }
74
+
75
+ public function getField($name)
76
+ {
77
+ return isset($this->fields[$name]) ? $this->fields[$name] : null;
78
+ }
79
+
80
+ public function removeField($name)
81
+ {
82
+ unset($this->fields[$name]);
83
+ $this->mutate();
84
+ }
85
+
86
+ public function getFields($asString = false)
87
+ {
88
+ if (!$asString) {
89
+ return $this->fields;
90
+ }
91
+
92
+ $query = new Query($this->fields);
93
+ $query->setEncodingType(Query::RFC1738);
94
+ $query->setAggregator($this->getAggregator());
95
+
96
+ return (string) $query;
97
+ }
98
+
99
+ public function hasField($name)
100
+ {
101
+ return isset($this->fields[$name]);
102
+ }
103
+
104
+ public function getFile($name)
105
+ {
106
+ foreach ($this->files as $file) {
107
+ if ($file->getName() == $name) {
108
+ return $file;
109
+ }
110
+ }
111
+
112
+ return null;
113
+ }
114
+
115
+ public function getFiles()
116
+ {
117
+ return $this->files;
118
+ }
119
+
120
+ public function addFile(PostFileInterface $file)
121
+ {
122
+ $this->files[] = $file;
123
+ $this->mutate();
124
+ }
125
+
126
+ public function clearFiles()
127
+ {
128
+ $this->files = [];
129
+ $this->mutate();
130
+ }
131
+
132
+ /**
133
+ * Returns the numbers of fields + files
134
+ *
135
+ * @return int
136
+ */
137
+ public function count()
138
+ {
139
+ return count($this->files) + count($this->fields);
140
+ }
141
+
142
+ public function __toString()
143
+ {
144
+ return (string) $this->getBody();
145
+ }
146
+
147
+ public function getContents($maxLength = -1)
148
+ {
149
+ return $this->getBody()->getContents();
150
+ }
151
+
152
+ public function close()
153
+ {
154
+ $this->detach();
155
+ }
156
+
157
+ public function detach()
158
+ {
159
+ $this->detached = true;
160
+ $this->fields = $this->files = [];
161
+
162
+ if ($this->body) {
163
+ $this->body->close();
164
+ $this->body = null;
165
+ }
166
+ }
167
+
168
+ public function attach($stream)
169
+ {
170
+ throw new CannotAttachException();
171
+ }
172
+
173
+ public function eof()
174
+ {
175
+ return $this->getBody()->eof();
176
+ }
177
+
178
+ public function tell()
179
+ {
180
+ return $this->body ? $this->body->tell() : 0;
181
+ }
182
+
183
+ public function isSeekable()
184
+ {
185
+ return true;
186
+ }
187
+
188
+ public function isReadable()
189
+ {
190
+ return true;
191
+ }
192
+
193
+ public function isWritable()
194
+ {
195
+ return false;
196
+ }
197
+
198
+ public function getSize()
199
+ {
200
+ return $this->getBody()->getSize();
201
+ }
202
+
203
+ public function seek($offset, $whence = SEEK_SET)
204
+ {
205
+ return $this->getBody()->seek($offset, $whence);
206
+ }
207
+
208
+ public function read($length)
209
+ {
210
+ return $this->getBody()->read($length);
211
+ }
212
+
213
+ public function write($string)
214
+ {
215
+ return false;
216
+ }
217
+
218
+ public function getMetadata($key = null)
219
+ {
220
+ return $key ? null : [];
221
+ }
222
+
223
+ /**
224
+ * Return a stream object that is built from the POST fields and files.
225
+ *
226
+ * If one has already been created, the previously created stream will be
227
+ * returned.
228
+ */
229
+ private function getBody()
230
+ {
231
+ if ($this->body) {
232
+ return $this->body;
233
+ } elseif ($this->files || $this->forceMultipart) {
234
+ return $this->body = $this->createMultipart();
235
+ } elseif ($this->fields) {
236
+ return $this->body = $this->createUrlEncoded();
237
+ } else {
238
+ return $this->body = Stream::factory();
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Get the aggregator used to join multi-valued field parameters
244
+ *
245
+ * @return callable
246
+ */
247
+ final protected function getAggregator()
248
+ {
249
+ if (!$this->aggregator) {
250
+ $this->aggregator = Query::phpAggregator();
251
+ }
252
+
253
+ return $this->aggregator;
254
+ }
255
+
256
+ /**
257
+ * Creates a multipart/form-data body stream
258
+ *
259
+ * @return MultipartBody
260
+ */
261
+ private function createMultipart()
262
+ {
263
+ // Flatten the nested query string values using the correct aggregator
264
+ return new MultipartBody(
265
+ call_user_func($this->getAggregator(), $this->fields),
266
+ $this->files
267
+ );
268
+ }
269
+
270
+ /**
271
+ * Creates an application/x-www-form-urlencoded stream body
272
+ *
273
+ * @return StreamInterface
274
+ */
275
+ private function createUrlEncoded()
276
+ {
277
+ return Stream::factory($this->getFields(true));
278
+ }
279
+
280
+ /**
281
+ * Get rid of any cached data
282
+ */
283
+ private function mutate()
284
+ {
285
+ $this->body = null;
286
+ }
287
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostBodyInterface.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Message\AppliesHeadersInterface;
5
+ use GuzzleHttp\Stream\StreamInterface;
6
+
7
+ /**
8
+ * Represents a POST body that is sent as either a multipart/form-data stream
9
+ * or application/x-www-urlencoded stream.
10
+ */
11
+ interface PostBodyInterface extends StreamInterface, \Countable, AppliesHeadersInterface
12
+ {
13
+ /**
14
+ * Set a specific field
15
+ *
16
+ * @param string $name Name of the field to set
17
+ * @param string|array $value Value to set
18
+ */
19
+ public function setField($name, $value);
20
+
21
+ /**
22
+ * Set the aggregation strategy that will be used to turn multi-valued
23
+ * fields into a string.
24
+ *
25
+ * The aggregation function accepts a deeply nested array of query string
26
+ * values and returns a flattened associative array of key value pairs.
27
+ *
28
+ * @param callable $aggregator
29
+ */
30
+ public function setAggregator(callable $aggregator);
31
+
32
+ /**
33
+ * Set to true to force a multipart upload even if there are no files.
34
+ *
35
+ * @param bool $force Set to true to force multipart uploads or false to
36
+ * remove this flag.
37
+ */
38
+ public function forceMultipartUpload($force);
39
+
40
+ /**
41
+ * Replace all existing form fields with an array of fields
42
+ *
43
+ * @param array $fields Associative array of fields to set
44
+ */
45
+ public function replaceFields(array $fields);
46
+
47
+ /**
48
+ * Get a specific field by name
49
+ *
50
+ * @param string $name Name of the POST field to retrieve
51
+ *
52
+ * @return string|null
53
+ */
54
+ public function getField($name);
55
+
56
+ /**
57
+ * Remove a field by name
58
+ *
59
+ * @param string $name Name of the field to remove
60
+ */
61
+ public function removeField($name);
62
+
63
+ /**
64
+ * Returns an associative array of names to values or a query string.
65
+ *
66
+ * @param bool $asString Set to true to retrieve the fields as a query
67
+ * string.
68
+ *
69
+ * @return array|string
70
+ */
71
+ public function getFields($asString = false);
72
+
73
+ /**
74
+ * Returns true if a field is set
75
+ *
76
+ * @param string $name Name of the field to set
77
+ *
78
+ * @return bool
79
+ */
80
+ public function hasField($name);
81
+
82
+ /**
83
+ * Get all of the files
84
+ *
85
+ * @return array Returns an array of PostFileInterface objects
86
+ */
87
+ public function getFiles();
88
+
89
+ /**
90
+ * Get a POST file by name.
91
+ *
92
+ * @param string $name Name of the POST file to retrieve
93
+ *
94
+ * @return PostFileInterface|null
95
+ */
96
+ public function getFile($name);
97
+
98
+ /**
99
+ * Add a file to the POST
100
+ *
101
+ * @param PostFileInterface $file File to add
102
+ */
103
+ public function addFile(PostFileInterface $file);
104
+
105
+ /**
106
+ * Remove all files from the collection
107
+ */
108
+ public function clearFiles();
109
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostFile.php ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Mimetypes;
5
+ use GuzzleHttp\Stream\StreamInterface;
6
+ use GuzzleHttp\Stream\Stream;
7
+
8
+ /**
9
+ * Post file upload
10
+ */
11
+ class PostFile implements PostFileInterface
12
+ {
13
+ private $name;
14
+ private $filename;
15
+ private $content;
16
+ private $headers = [];
17
+
18
+ /**
19
+ * @param string $name Name of the form field
20
+ * @param mixed $content Data to send
21
+ * @param string|null $filename Filename content-disposition attribute
22
+ * @param array $headers Array of headers to set on the file
23
+ * (can override any default headers)
24
+ * @throws \RuntimeException when filename is not passed or can't be determined
25
+ */
26
+ public function __construct(
27
+ $name,
28
+ $content,
29
+ $filename = null,
30
+ array $headers = []
31
+ ) {
32
+ $this->headers = $headers;
33
+ $this->name = $name;
34
+ $this->prepareContent($content);
35
+ $this->prepareFilename($filename);
36
+ $this->prepareDefaultHeaders();
37
+ }
38
+
39
+ public function getName()
40
+ {
41
+ return $this->name;
42
+ }
43
+
44
+ public function getFilename()
45
+ {
46
+ return $this->filename;
47
+ }
48
+
49
+ public function getContent()
50
+ {
51
+ return $this->content;
52
+ }
53
+
54
+ public function getHeaders()
55
+ {
56
+ return $this->headers;
57
+ }
58
+
59
+ /**
60
+ * Prepares the contents of a POST file.
61
+ *
62
+ * @param mixed $content Content of the POST file
63
+ */
64
+ private function prepareContent($content)
65
+ {
66
+ $this->content = $content;
67
+
68
+ if (!($this->content instanceof StreamInterface)) {
69
+ $this->content = Stream::factory($this->content);
70
+ } elseif ($this->content instanceof MultipartBody) {
71
+ if (!$this->hasHeader('Content-Disposition')) {
72
+ $disposition = 'form-data; name="' . $this->name .'"';
73
+ $this->headers['Content-Disposition'] = $disposition;
74
+ }
75
+
76
+ if (!$this->hasHeader('Content-Type')) {
77
+ $this->headers['Content-Type'] = sprintf(
78
+ "multipart/form-data; boundary=%s",
79
+ $this->content->getBoundary()
80
+ );
81
+ }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Applies a file name to the POST file based on various checks.
87
+ *
88
+ * @param string|null $filename Filename to apply (or null to guess)
89
+ */
90
+ private function prepareFilename($filename)
91
+ {
92
+ $this->filename = $filename;
93
+
94
+ if (!$this->filename) {
95
+ $this->filename = $this->content->getMetadata('uri');
96
+ }
97
+
98
+ if (!$this->filename || substr($this->filename, 0, 6) === 'php://') {
99
+ $this->filename = $this->name;
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Applies default Content-Disposition and Content-Type headers if needed.
105
+ */
106
+ private function prepareDefaultHeaders()
107
+ {
108
+ // Set a default content-disposition header if one was no provided
109
+ if (!$this->hasHeader('Content-Disposition')) {
110
+ $this->headers['Content-Disposition'] = sprintf(
111
+ 'form-data; name="%s"; filename="%s"',
112
+ $this->name,
113
+ basename($this->filename)
114
+ );
115
+ }
116
+
117
+ // Set a default Content-Type if one was not supplied
118
+ if (!$this->hasHeader('Content-Type')) {
119
+ $this->headers['Content-Type'] = Mimetypes::getInstance()
120
+ ->fromFilename($this->filename) ?: 'text/plain';
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Check if a specific header exists on the POST file by name.
126
+ *
127
+ * @param string $name Case-insensitive header to check
128
+ *
129
+ * @return bool
130
+ */
131
+ private function hasHeader($name)
132
+ {
133
+ return isset(array_change_key_case($this->headers)[strtolower($name)]);
134
+ }
135
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Post/PostFileInterface.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Post;
3
+
4
+ use GuzzleHttp\Stream\StreamInterface;
5
+
6
+ /**
7
+ * Post file upload interface
8
+ */
9
+ interface PostFileInterface
10
+ {
11
+ /**
12
+ * Get the name of the form field
13
+ *
14
+ * @return string
15
+ */
16
+ public function getName();
17
+
18
+ /**
19
+ * Get the full path to the file
20
+ *
21
+ * @return string
22
+ */
23
+ public function getFilename();
24
+
25
+ /**
26
+ * Get the content
27
+ *
28
+ * @return StreamInterface
29
+ */
30
+ public function getContent();
31
+
32
+ /**
33
+ * Gets all POST file headers.
34
+ *
35
+ * The keys represent the header name as it will be sent over the wire, and
36
+ * each value is a string.
37
+ *
38
+ * @return array Returns an associative array of the file's headers.
39
+ */
40
+ public function getHeaders();
41
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Query.php ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Manages query string variables and can aggregate them into a string
6
+ */
7
+ class Query extends Collection
8
+ {
9
+ const RFC3986 = 'RFC3986';
10
+ const RFC1738 = 'RFC1738';
11
+
12
+ /** @var callable Encoding function */
13
+ private $encoding = 'rawurlencode';
14
+ /** @var callable */
15
+ private $aggregator;
16
+
17
+ /**
18
+ * Parse a query string into a Query object
19
+ *
20
+ * $urlEncoding is used to control how the query string is parsed and how
21
+ * it is ultimately serialized. The value can be set to one of the
22
+ * following:
23
+ *
24
+ * - true: (default) Parse query strings using RFC 3986 while still
25
+ * converting "+" to " ".
26
+ * - false: Disables URL decoding of the input string and URL encoding when
27
+ * the query string is serialized.
28
+ * - 'RFC3986': Use RFC 3986 URL encoding/decoding
29
+ * - 'RFC1738': Use RFC 1738 URL encoding/decoding
30
+ *
31
+ * @param string $query Query string to parse
32
+ * @param bool|string $urlEncoding Controls how the input string is decoded
33
+ * and encoded.
34
+ * @return self
35
+ */
36
+ public static function fromString($query, $urlEncoding = true)
37
+ {
38
+ static $qp;
39
+ if (!$qp) {
40
+ $qp = new QueryParser();
41
+ }
42
+
43
+ $q = new static();
44
+
45
+ if ($urlEncoding !== true) {
46
+ $q->setEncodingType($urlEncoding);
47
+ }
48
+
49
+ $qp->parseInto($q, $query, $urlEncoding);
50
+
51
+ return $q;
52
+ }
53
+
54
+ /**
55
+ * Convert the query string parameters to a query string string
56
+ *
57
+ * @return string
58
+ */
59
+ public function __toString()
60
+ {
61
+ if (!$this->data) {
62
+ return '';
63
+ }
64
+
65
+ // The default aggregator is statically cached
66
+ static $defaultAggregator;
67
+
68
+ if (!$this->aggregator) {
69
+ if (!$defaultAggregator) {
70
+ $defaultAggregator = self::phpAggregator();
71
+ }
72
+ $this->aggregator = $defaultAggregator;
73
+ }
74
+
75
+ $result = '';
76
+ $aggregator = $this->aggregator;
77
+ $encoder = $this->encoding;
78
+
79
+ foreach ($aggregator($this->data) as $key => $values) {
80
+ foreach ($values as $value) {
81
+ if ($result) {
82
+ $result .= '&';
83
+ }
84
+ $result .= $encoder($key);
85
+ if ($value !== null) {
86
+ $result .= '=' . $encoder($value);
87
+ }
88
+ }
89
+ }
90
+
91
+ return $result;
92
+ }
93
+
94
+ /**
95
+ * Controls how multi-valued query string parameters are aggregated into a
96
+ * string.
97
+ *
98
+ * $query->setAggregator($query::duplicateAggregator());
99
+ *
100
+ * @param callable $aggregator Callable used to convert a deeply nested
101
+ * array of query string variables into a flattened array of key value
102
+ * pairs. The callable accepts an array of query data and returns a
103
+ * flattened array of key value pairs where each value is an array of
104
+ * strings.
105
+ */
106
+ public function setAggregator(callable $aggregator)
107
+ {
108
+ $this->aggregator = $aggregator;
109
+ }
110
+
111
+ /**
112
+ * Specify how values are URL encoded
113
+ *
114
+ * @param string|bool $type One of 'RFC1738', 'RFC3986', or false to disable encoding
115
+ *
116
+ * @throws \InvalidArgumentException
117
+ */
118
+ public function setEncodingType($type)
119
+ {
120
+ switch ($type) {
121
+ case self::RFC3986:
122
+ $this->encoding = 'rawurlencode';
123
+ break;
124
+ case self::RFC1738:
125
+ $this->encoding = 'urlencode';
126
+ break;
127
+ case false:
128
+ $this->encoding = function ($v) { return $v; };
129
+ break;
130
+ default:
131
+ throw new \InvalidArgumentException('Invalid URL encoding type');
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Query string aggregator that does not aggregate nested query string
137
+ * values and allows duplicates in the resulting array.
138
+ *
139
+ * Example: http://test.com?q=1&q=2
140
+ *
141
+ * @return callable
142
+ */
143
+ public static function duplicateAggregator()
144
+ {
145
+ return function (array $data) {
146
+ return self::walkQuery($data, '', function ($key, $prefix) {
147
+ return is_int($key) ? $prefix : "{$prefix}[{$key}]";
148
+ });
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Aggregates nested query string variables using the same technique as
154
+ * ``http_build_query()``.
155
+ *
156
+ * @param bool $numericIndices Pass false to not include numeric indices
157
+ * when multi-values query string parameters are present.
158
+ *
159
+ * @return callable
160
+ */
161
+ public static function phpAggregator($numericIndices = true)
162
+ {
163
+ return function (array $data) use ($numericIndices) {
164
+ return self::walkQuery(
165
+ $data,
166
+ '',
167
+ function ($key, $prefix) use ($numericIndices) {
168
+ return !$numericIndices && is_int($key)
169
+ ? "{$prefix}[]"
170
+ : "{$prefix}[{$key}]";
171
+ }
172
+ );
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Easily create query aggregation functions by providing a key prefix
178
+ * function to this query string array walker.
179
+ *
180
+ * @param array $query Query string to walk
181
+ * @param string $keyPrefix Key prefix (start with '')
182
+ * @param callable $prefixer Function used to create a key prefix
183
+ *
184
+ * @return array
185
+ */
186
+ public static function walkQuery(array $query, $keyPrefix, callable $prefixer)
187
+ {
188
+ $result = [];
189
+ foreach ($query as $key => $value) {
190
+ if ($keyPrefix) {
191
+ $key = $prefixer($key, $keyPrefix);
192
+ }
193
+ if (is_array($value)) {
194
+ $result += self::walkQuery($value, $key, $prefixer);
195
+ } elseif (isset($result[$key])) {
196
+ $result[$key][] = $value;
197
+ } else {
198
+ $result[$key] = array($value);
199
+ }
200
+ }
201
+
202
+ return $result;
203
+ }
204
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/QueryParser.php ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Parses query strings into a Query object.
6
+ *
7
+ * While parsing, the parser will attempt to determine the most appropriate
8
+ * query string aggregator to use when serializing the parsed query string
9
+ * object back into a string. The hope is that parsing then serializing a
10
+ * query string should be a lossless operation.
11
+ *
12
+ * @internal Use Query::fromString()
13
+ */
14
+ class QueryParser
15
+ {
16
+ private $duplicates;
17
+ private $numericIndices;
18
+
19
+ /**
20
+ * Parse a query string into a Query object.
21
+ *
22
+ * @param Query $query Query object to populate
23
+ * @param string $str Query string to parse
24
+ * @param bool|string $urlEncoding How the query string is encoded
25
+ */
26
+ public function parseInto(Query $query, $str, $urlEncoding = true)
27
+ {
28
+ if ($str === '') {
29
+ return;
30
+ }
31
+
32
+ $result = [];
33
+ $this->duplicates = false;
34
+ $this->numericIndices = true;
35
+ $decoder = self::getDecoder($urlEncoding);
36
+
37
+ foreach (explode('&', $str) as $kvp) {
38
+
39
+ $parts = explode('=', $kvp, 2);
40
+ $key = $decoder($parts[0]);
41
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
42
+
43
+ // Special handling needs to be taken for PHP nested array syntax
44
+ if (strpos($key, '[') !== false) {
45
+ $this->parsePhpValue($key, $value, $result);
46
+ continue;
47
+ }
48
+
49
+ if (!isset($result[$key])) {
50
+ $result[$key] = $value;
51
+ } else {
52
+ $this->duplicates = true;
53
+ if (!is_array($result[$key])) {
54
+ $result[$key] = [$result[$key]];
55
+ }
56
+ $result[$key][] = $value;
57
+ }
58
+ }
59
+
60
+ $query->replace($result);
61
+
62
+ if (!$this->numericIndices) {
63
+ $query->setAggregator(Query::phpAggregator(false));
64
+ } elseif ($this->duplicates) {
65
+ $query->setAggregator(Query::duplicateAggregator());
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Returns a callable that is used to URL decode query keys and values.
71
+ *
72
+ * @param string|bool $type One of true, false, RFC3986, and RFC1738
73
+ *
74
+ * @return callable|string
75
+ */
76
+ private static function getDecoder($type)
77
+ {
78
+ if ($type === true) {
79
+ return function ($value) {
80
+ return rawurldecode(str_replace('+', ' ', $value));
81
+ };
82
+ } elseif ($type == Query::RFC3986) {
83
+ return 'rawurldecode';
84
+ } elseif ($type == Query::RFC1738) {
85
+ return 'urldecode';
86
+ } else {
87
+ return function ($str) { return $str; };
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Parses a PHP style key value pair.
93
+ *
94
+ * @param string $key Key to parse (e.g., "foo[a][b]")
95
+ * @param string|null $value Value to set
96
+ * @param array $result Result to modify by reference
97
+ */
98
+ private function parsePhpValue($key, $value, array &$result)
99
+ {
100
+ $node =& $result;
101
+ $keyBuffer = '';
102
+
103
+ for ($i = 0, $t = strlen($key); $i < $t; $i++) {
104
+ switch ($key[$i]) {
105
+ case '[':
106
+ if ($keyBuffer) {
107
+ $this->prepareNode($node, $keyBuffer);
108
+ $node =& $node[$keyBuffer];
109
+ $keyBuffer = '';
110
+ }
111
+ break;
112
+ case ']':
113
+ $k = $this->cleanKey($node, $keyBuffer);
114
+ $this->prepareNode($node, $k);
115
+ $node =& $node[$k];
116
+ $keyBuffer = '';
117
+ break;
118
+ default:
119
+ $keyBuffer .= $key[$i];
120
+ break;
121
+ }
122
+ }
123
+
124
+ if (isset($node)) {
125
+ $this->duplicates = true;
126
+ $node[] = $value;
127
+ } else {
128
+ $node = $value;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Prepares a value in the array at the given key.
134
+ *
135
+ * If the key already exists, the key value is converted into an array.
136
+ *
137
+ * @param array $node Result node to modify
138
+ * @param string $key Key to add or modify in the node
139
+ */
140
+ private function prepareNode(&$node, $key)
141
+ {
142
+ if (!isset($node[$key])) {
143
+ $node[$key] = null;
144
+ } elseif (!is_array($node[$key])) {
145
+ $node[$key] = [$node[$key]];
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Returns the appropriate key based on the node and key.
151
+ */
152
+ private function cleanKey($node, $key)
153
+ {
154
+ if ($key === '') {
155
+ $key = $node ? (string) count($node) : 0;
156
+ // Found a [] key, so track this to ensure that we disable numeric
157
+ // indexing of keys in the resolved query aggregator.
158
+ $this->numericIndices = false;
159
+ }
160
+
161
+ return $key;
162
+ }
163
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/RequestFsm.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Event\BeforeEvent;
5
+ use GuzzleHttp\Event\ErrorEvent;
6
+ use GuzzleHttp\Event\CompleteEvent;
7
+ use GuzzleHttp\Event\EndEvent;
8
+ use GuzzleHttp\Exception\StateException;
9
+ use GuzzleHttp\Exception\RequestException;
10
+ use GuzzleHttp\Message\FutureResponse;
11
+ use GuzzleHttp\Message\MessageFactoryInterface;
12
+ use GuzzleHttp\Ring\Future\FutureInterface;
13
+
14
+ /**
15
+ * Responsible for transitioning requests through lifecycle events.
16
+ */
17
+ class RequestFsm
18
+ {
19
+ private $handler;
20
+ private $mf;
21
+ private $maxTransitions;
22
+
23
+ public function __construct(
24
+ callable $handler,
25
+ MessageFactoryInterface $messageFactory,
26
+ $maxTransitions = 200
27
+ ) {
28
+ $this->mf = $messageFactory;
29
+ $this->maxTransitions = $maxTransitions;
30
+ $this->handler = $handler;
31
+ }
32
+
33
+ /**
34
+ * Runs the state machine until a terminal state is entered or the
35
+ * optionally supplied $finalState is entered.
36
+ *
37
+ * @param Transaction $trans Transaction being transitioned.
38
+ *
39
+ * @throws \Exception if a terminal state throws an exception.
40
+ */
41
+ public function __invoke(Transaction $trans)
42
+ {
43
+ $trans->_transitionCount = 0;
44
+
45
+ if (!$trans->state) {
46
+ $trans->state = 'before';
47
+ }
48
+
49
+ transition:
50
+
51
+ if (++$trans->_transitionCount > $this->maxTransitions) {
52
+ throw new StateException("Too many state transitions were "
53
+ . "encountered ({$trans->_transitionCount}). This likely "
54
+ . "means that a combination of event listeners are in an "
55
+ . "infinite loop.");
56
+ }
57
+
58
+ switch ($trans->state) {
59
+ case 'before': goto before;
60
+ case 'complete': goto complete;
61
+ case 'error': goto error;
62
+ case 'retry': goto retry;
63
+ case 'send': goto send;
64
+ case 'end': goto end;
65
+ default: throw new StateException("Invalid state: {$trans->state}");
66
+ }
67
+
68
+ before: {
69
+ try {
70
+ $trans->request->getEmitter()->emit('before', new BeforeEvent($trans));
71
+ $trans->state = 'send';
72
+ if ((bool) $trans->response) {
73
+ $trans->state = 'complete';
74
+ }
75
+ } catch (\Exception $e) {
76
+ $trans->state = 'error';
77
+ $trans->exception = $e;
78
+ }
79
+ goto transition;
80
+ }
81
+
82
+ complete: {
83
+ try {
84
+ if ($trans->response instanceof FutureInterface) {
85
+ // Futures will have their own end events emitted when
86
+ // dereferenced.
87
+ return;
88
+ }
89
+ $trans->state = 'end';
90
+ $trans->response->setEffectiveUrl($trans->request->getUrl());
91
+ $trans->request->getEmitter()->emit('complete', new CompleteEvent($trans));
92
+ } catch (\Exception $e) {
93
+ $trans->state = 'error';
94
+ $trans->exception = $e;
95
+ }
96
+ goto transition;
97
+ }
98
+
99
+ error: {
100
+ try {
101
+ // Convert non-request exception to a wrapped exception
102
+ $trans->exception = RequestException::wrapException(
103
+ $trans->request, $trans->exception
104
+ );
105
+ $trans->state = 'end';
106
+ $trans->request->getEmitter()->emit('error', new ErrorEvent($trans));
107
+ // An intercepted request (not retried) transitions to complete
108
+ if (!$trans->exception && $trans->state !== 'retry') {
109
+ $trans->state = 'complete';
110
+ }
111
+ } catch (\Exception $e) {
112
+ $trans->state = 'end';
113
+ $trans->exception = $e;
114
+ }
115
+ goto transition;
116
+ }
117
+
118
+ retry: {
119
+ $trans->retries++;
120
+ $trans->response = null;
121
+ $trans->exception = null;
122
+ $trans->state = 'before';
123
+ goto transition;
124
+ }
125
+
126
+ send: {
127
+ $fn = $this->handler;
128
+ $trans->response = FutureResponse::proxy(
129
+ $fn(RingBridge::prepareRingRequest($trans)),
130
+ function ($value) use ($trans) {
131
+ RingBridge::completeRingResponse($trans, $value, $this->mf, $this);
132
+ $this($trans);
133
+ return $trans->response;
134
+ }
135
+ );
136
+ return;
137
+ }
138
+
139
+ end: {
140
+ $trans->request->getEmitter()->emit('end', new EndEvent($trans));
141
+ // Throw exceptions in the terminal event if the exception
142
+ // was not handled by an "end" event listener.
143
+ if ($trans->exception) {
144
+ if (!($trans->exception instanceof RequestException)) {
145
+ $trans->exception = RequestException::wrapException(
146
+ $trans->request, $trans->exception
147
+ );
148
+ }
149
+ throw $trans->exception;
150
+ }
151
+ }
152
+ }
153
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/RingBridge.php ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Message\MessageFactoryInterface;
5
+ use GuzzleHttp\Message\RequestInterface;
6
+ use GuzzleHttp\Event\ProgressEvent;
7
+ use GuzzleHttp\Message\Request;
8
+ use GuzzleHttp\Ring\Core;
9
+ use GuzzleHttp\Stream\Stream;
10
+ use GuzzleHttp\Exception\RequestException;
11
+
12
+ /**
13
+ * Provides the bridge between Guzzle requests and responses and Guzzle Ring.
14
+ */
15
+ class RingBridge
16
+ {
17
+ /**
18
+ * Creates a Ring request from a request object.
19
+ *
20
+ * This function does not hook up the "then" and "progress" events that
21
+ * would be required for actually sending a Guzzle request through a
22
+ * RingPHP handler.
23
+ *
24
+ * @param RequestInterface $request Request to convert.
25
+ *
26
+ * @return array Converted Guzzle Ring request.
27
+ */
28
+ public static function createRingRequest(RequestInterface $request)
29
+ {
30
+ $options = $request->getConfig()->toArray();
31
+ $url = $request->getUrl();
32
+ // No need to calculate the query string twice (in URL and query).
33
+ $qs = ($pos = strpos($url, '?')) ? substr($url, $pos + 1) : null;
34
+
35
+ return [
36
+ 'scheme' => $request->getScheme(),
37
+ 'http_method' => $request->getMethod(),
38
+ 'url' => $url,
39
+ 'uri' => $request->getPath(),
40
+ 'headers' => $request->getHeaders(),
41
+ 'body' => $request->getBody(),
42
+ 'version' => $request->getProtocolVersion(),
43
+ 'client' => $options,
44
+ 'query_string' => $qs,
45
+ 'future' => isset($options['future']) ? $options['future'] : false
46
+ ];
47
+ }
48
+
49
+ /**
50
+ * Creates a Ring request from a request object AND prepares the callbacks.
51
+ *
52
+ * @param Transaction $trans Transaction to update.
53
+ *
54
+ * @return array Converted Guzzle Ring request.
55
+ */
56
+ public static function prepareRingRequest(Transaction $trans)
57
+ {
58
+ // Clear out the transaction state when initiating.
59
+ $trans->exception = null;
60
+ $request = self::createRingRequest($trans->request);
61
+
62
+ // Emit progress events if any progress listeners are registered.
63
+ if ($trans->request->getEmitter()->hasListeners('progress')) {
64
+ $emitter = $trans->request->getEmitter();
65
+ $request['client']['progress'] = function ($a, $b, $c, $d) use ($trans, $emitter) {
66
+ $emitter->emit('progress', new ProgressEvent($trans, $a, $b, $c, $d));
67
+ };
68
+ }
69
+
70
+ return $request;
71
+ }
72
+
73
+ /**
74
+ * Handles the process of processing a response received from a ring
75
+ * handler. The created response is added to the transaction, and the
76
+ * transaction stat is set appropriately.
77
+ *
78
+ * @param Transaction $trans Owns request and response.
79
+ * @param array $response Ring response array
80
+ * @param MessageFactoryInterface $messageFactory Creates response objects.
81
+ */
82
+ public static function completeRingResponse(
83
+ Transaction $trans,
84
+ array $response,
85
+ MessageFactoryInterface $messageFactory
86
+ ) {
87
+ $trans->state = 'complete';
88
+ $trans->transferInfo = isset($response['transfer_stats'])
89
+ ? $response['transfer_stats'] : [];
90
+
91
+ if (!empty($response['status'])) {
92
+ $options = [];
93
+ if (isset($response['version'])) {
94
+ $options['protocol_version'] = $response['version'];
95
+ }
96
+ if (isset($response['reason'])) {
97
+ $options['reason_phrase'] = $response['reason'];
98
+ }
99
+ $trans->response = $messageFactory->createResponse(
100
+ $response['status'],
101
+ isset($response['headers']) ? $response['headers'] : [],
102
+ isset($response['body']) ? $response['body'] : null,
103
+ $options
104
+ );
105
+ if (isset($response['effective_url'])) {
106
+ $trans->response->setEffectiveUrl($response['effective_url']);
107
+ }
108
+ } elseif (empty($response['error'])) {
109
+ // When nothing was returned, then we need to add an error.
110
+ $response['error'] = self::getNoRingResponseException($trans->request);
111
+ }
112
+
113
+ if (isset($response['error'])) {
114
+ $trans->state = 'error';
115
+ $trans->exception = $response['error'];
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Creates a Guzzle request object using a ring request array.
121
+ *
122
+ * @param array $request Ring request
123
+ *
124
+ * @return Request
125
+ * @throws \InvalidArgumentException for incomplete requests.
126
+ */
127
+ public static function fromRingRequest(array $request)
128
+ {
129
+ $options = [];
130
+ if (isset($request['version'])) {
131
+ $options['protocol_version'] = $request['version'];
132
+ }
133
+
134
+ if (!isset($request['http_method'])) {
135
+ throw new \InvalidArgumentException('No http_method');
136
+ }
137
+
138
+ return new Request(
139
+ $request['http_method'],
140
+ Core::url($request),
141
+ isset($request['headers']) ? $request['headers'] : [],
142
+ isset($request['body']) ? Stream::factory($request['body']) : null,
143
+ $options
144
+ );
145
+ }
146
+
147
+ /**
148
+ * Get an exception that can be used when a RingPHP handler does not
149
+ * populate a response.
150
+ *
151
+ * @param RequestInterface $request
152
+ *
153
+ * @return RequestException
154
+ */
155
+ public static function getNoRingResponseException(RequestInterface $request)
156
+ {
157
+ $message = <<<EOT
158
+ Sending the request did not return a response, exception, or populate the
159
+ transaction with a response. This is most likely due to an incorrectly
160
+ implemented RingPHP handler. If you are simply trying to mock responses,
161
+ then it is recommended to use the GuzzleHttp\Ring\Client\MockHandler.
162
+ EOT;
163
+ return new RequestException($message, $request);
164
+ }
165
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Cookie.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Cookie\CookieJar;
5
+ use GuzzleHttp\Cookie\CookieJarInterface;
6
+ use GuzzleHttp\Event\BeforeEvent;
7
+ use GuzzleHttp\Event\CompleteEvent;
8
+ use GuzzleHttp\Event\RequestEvents;
9
+ use GuzzleHttp\Event\SubscriberInterface;
10
+
11
+ /**
12
+ * Adds, extracts, and persists cookies between HTTP requests
13
+ */
14
+ class Cookie implements SubscriberInterface
15
+ {
16
+ /** @var CookieJarInterface */
17
+ private $cookieJar;
18
+
19
+ /**
20
+ * @param CookieJarInterface $cookieJar Cookie jar used to hold cookies
21
+ */
22
+ public function __construct(CookieJarInterface $cookieJar = null)
23
+ {
24
+ $this->cookieJar = $cookieJar ?: new CookieJar();
25
+ }
26
+
27
+ public function getEvents()
28
+ {
29
+ // Fire the cookie plugin complete event before redirecting
30
+ return [
31
+ 'before' => ['onBefore'],
32
+ 'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10]
33
+ ];
34
+ }
35
+
36
+ /**
37
+ * Get the cookie cookieJar
38
+ *
39
+ * @return CookieJarInterface
40
+ */
41
+ public function getCookieJar()
42
+ {
43
+ return $this->cookieJar;
44
+ }
45
+
46
+ public function onBefore(BeforeEvent $event)
47
+ {
48
+ $this->cookieJar->addCookieHeader($event->getRequest());
49
+ }
50
+
51
+ public function onComplete(CompleteEvent $event)
52
+ {
53
+ $this->cookieJar->extractCookies(
54
+ $event->getRequest(),
55
+ $event->getResponse()
56
+ );
57
+ }
58
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/History.php ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\CompleteEvent;
5
+ use GuzzleHttp\Event\ErrorEvent;
6
+ use GuzzleHttp\Event\RequestEvents;
7
+ use GuzzleHttp\Event\SubscriberInterface;
8
+ use GuzzleHttp\Message\RequestInterface;
9
+ use GuzzleHttp\Message\ResponseInterface;
10
+
11
+ /**
12
+ * Maintains a list of requests and responses sent using a request or client
13
+ */
14
+ class History implements SubscriberInterface, \IteratorAggregate, \Countable
15
+ {
16
+ /** @var int The maximum number of requests to maintain in the history */
17
+ private $limit;
18
+
19
+ /** @var array Requests and responses that have passed through the plugin */
20
+ private $transactions = [];
21
+
22
+ public function __construct($limit = 10)
23
+ {
24
+ $this->limit = $limit;
25
+ }
26
+
27
+ public function getEvents()
28
+ {
29
+ return [
30
+ 'complete' => ['onComplete', RequestEvents::EARLY],
31
+ 'error' => ['onError', RequestEvents::EARLY],
32
+ ];
33
+ }
34
+
35
+ /**
36
+ * Convert to a string that contains all request and response headers
37
+ *
38
+ * @return string
39
+ */
40
+ public function __toString()
41
+ {
42
+ $lines = array();
43
+ foreach ($this->transactions as $entry) {
44
+ $response = isset($entry['response']) ? $entry['response'] : '';
45
+ $lines[] = '> ' . trim($entry['sent_request'])
46
+ . "\n\n< " . trim($response) . "\n";
47
+ }
48
+
49
+ return implode("\n", $lines);
50
+ }
51
+
52
+ public function onComplete(CompleteEvent $event)
53
+ {
54
+ $this->add($event->getRequest(), $event->getResponse());
55
+ }
56
+
57
+ public function onError(ErrorEvent $event)
58
+ {
59
+ // Only track when no response is present, meaning this didn't ever
60
+ // emit a complete event
61
+ if (!$event->getResponse()) {
62
+ $this->add($event->getRequest());
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Returns an Iterator that yields associative array values where each
68
+ * associative array contains the following key value pairs:
69
+ *
70
+ * - request: Representing the actual request that was received.
71
+ * - sent_request: A clone of the request that will not be mutated.
72
+ * - response: The response that was received (if available).
73
+ *
74
+ * @return \Iterator
75
+ */
76
+ public function getIterator()
77
+ {
78
+ return new \ArrayIterator($this->transactions);
79
+ }
80
+
81
+ /**
82
+ * Get all of the requests sent through the plugin.
83
+ *
84
+ * Requests can be modified after they are logged by the history
85
+ * subscriber. By default this method will return the actual request
86
+ * instances that were received. Pass true to this method if you wish to
87
+ * get copies of the requests that represent the request state when it was
88
+ * initially logged by the history subscriber.
89
+ *
90
+ * @param bool $asSent Set to true to get clones of the requests that have
91
+ * not been mutated since the request was received by
92
+ * the history subscriber.
93
+ *
94
+ * @return RequestInterface[]
95
+ */
96
+ public function getRequests($asSent = false)
97
+ {
98
+ return array_map(function ($t) use ($asSent) {
99
+ return $asSent ? $t['sent_request'] : $t['request'];
100
+ }, $this->transactions);
101
+ }
102
+
103
+ /**
104
+ * Get the number of requests in the history
105
+ *
106
+ * @return int
107
+ */
108
+ public function count()
109
+ {
110
+ return count($this->transactions);
111
+ }
112
+
113
+ /**
114
+ * Get the last request sent.
115
+ *
116
+ * Requests can be modified after they are logged by the history
117
+ * subscriber. By default this method will return the actual request
118
+ * instance that was received. Pass true to this method if you wish to get
119
+ * a copy of the request that represents the request state when it was
120
+ * initially logged by the history subscriber.
121
+ *
122
+ * @param bool $asSent Set to true to get a clone of the last request that
123
+ * has not been mutated since the request was received
124
+ * by the history subscriber.
125
+ *
126
+ * @return RequestInterface
127
+ */
128
+ public function getLastRequest($asSent = false)
129
+ {
130
+ return $asSent
131
+ ? end($this->transactions)['sent_request']
132
+ : end($this->transactions)['request'];
133
+ }
134
+
135
+ /**
136
+ * Get the last response in the history
137
+ *
138
+ * @return ResponseInterface|null
139
+ */
140
+ public function getLastResponse()
141
+ {
142
+ return end($this->transactions)['response'];
143
+ }
144
+
145
+ /**
146
+ * Clears the history
147
+ */
148
+ public function clear()
149
+ {
150
+ $this->transactions = array();
151
+ }
152
+
153
+ /**
154
+ * Add a request to the history
155
+ *
156
+ * @param RequestInterface $request Request to add
157
+ * @param ResponseInterface $response Response of the request
158
+ */
159
+ private function add(
160
+ RequestInterface $request,
161
+ ResponseInterface $response = null
162
+ ) {
163
+ $this->transactions[] = [
164
+ 'request' => $request,
165
+ 'sent_request' => clone $request,
166
+ 'response' => $response
167
+ ];
168
+ if (count($this->transactions) > $this->limit) {
169
+ array_shift($this->transactions);
170
+ }
171
+ }
172
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/HttpError.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\CompleteEvent;
5
+ use GuzzleHttp\Event\RequestEvents;
6
+ use GuzzleHttp\Event\SubscriberInterface;
7
+ use GuzzleHttp\Exception\RequestException;
8
+
9
+ /**
10
+ * Throws exceptions when a 4xx or 5xx response is received
11
+ */
12
+ class HttpError implements SubscriberInterface
13
+ {
14
+ public function getEvents()
15
+ {
16
+ return ['complete' => ['onComplete', RequestEvents::VERIFY_RESPONSE]];
17
+ }
18
+
19
+ /**
20
+ * Throw a RequestException on an HTTP protocol error
21
+ *
22
+ * @param CompleteEvent $event Emitted event
23
+ * @throws RequestException
24
+ */
25
+ public function onComplete(CompleteEvent $event)
26
+ {
27
+ $code = (string) $event->getResponse()->getStatusCode();
28
+ // Throw an exception for an unsuccessful response
29
+ if ($code[0] >= 4) {
30
+ throw RequestException::create(
31
+ $event->getRequest(),
32
+ $event->getResponse()
33
+ );
34
+ }
35
+ }
36
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Mock.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\RequestEvents;
5
+ use GuzzleHttp\Event\SubscriberInterface;
6
+ use GuzzleHttp\Event\BeforeEvent;
7
+ use GuzzleHttp\Exception\RequestException;
8
+ use GuzzleHttp\Message\MessageFactory;
9
+ use GuzzleHttp\Message\ResponseInterface;
10
+ use GuzzleHttp\Stream\StreamInterface;
11
+
12
+ /**
13
+ * Queues mock responses or exceptions and delivers mock responses or
14
+ * exceptions in a fifo order.
15
+ */
16
+ class Mock implements SubscriberInterface, \Countable
17
+ {
18
+ /** @var array Array of mock responses / exceptions */
19
+ private $queue = [];
20
+
21
+ /** @var bool Whether or not to consume an entity body when mocking */
22
+ private $readBodies;
23
+
24
+ /** @var MessageFactory */
25
+ private $factory;
26
+
27
+ /**
28
+ * @param array $items Array of responses or exceptions to queue
29
+ * @param bool $readBodies Set to false to not consume the entity body of
30
+ * a request when a mock is served.
31
+ */
32
+ public function __construct(array $items = [], $readBodies = true)
33
+ {
34
+ $this->factory = new MessageFactory();
35
+ $this->readBodies = $readBodies;
36
+ $this->addMultiple($items);
37
+ }
38
+
39
+ public function getEvents()
40
+ {
41
+ // Fire the event last, after signing
42
+ return ['before' => ['onBefore', RequestEvents::SIGN_REQUEST - 10]];
43
+ }
44
+
45
+ /**
46
+ * @throws \OutOfBoundsException|\Exception
47
+ */
48
+ public function onBefore(BeforeEvent $event)
49
+ {
50
+ if (!$item = array_shift($this->queue)) {
51
+ throw new \OutOfBoundsException('Mock queue is empty');
52
+ } elseif ($item instanceof RequestException) {
53
+ throw $item;
54
+ }
55
+
56
+ // Emulate reading a response body
57
+ $request = $event->getRequest();
58
+ if ($this->readBodies && $request->getBody()) {
59
+ while (!$request->getBody()->eof()) {
60
+ $request->getBody()->read(8096);
61
+ }
62
+ }
63
+
64
+ $saveTo = $event->getRequest()->getConfig()->get('save_to');
65
+
66
+ if (null !== $saveTo) {
67
+ $body = $item->getBody();
68
+
69
+ if (is_resource($saveTo)) {
70
+ fwrite($saveTo, $body);
71
+ } elseif (is_string($saveTo)) {
72
+ file_put_contents($saveTo, $body);
73
+ } elseif ($saveTo instanceof StreamInterface) {
74
+ $saveTo->write($body);
75
+ }
76
+ }
77
+
78
+ $event->intercept($item);
79
+ }
80
+
81
+ public function count()
82
+ {
83
+ return count($this->queue);
84
+ }
85
+
86
+ /**
87
+ * Add a response to the end of the queue
88
+ *
89
+ * @param string|ResponseInterface $response Response or path to response file
90
+ *
91
+ * @return self
92
+ * @throws \InvalidArgumentException if a string or Response is not passed
93
+ */
94
+ public function addResponse($response)
95
+ {
96
+ if (is_string($response)) {
97
+ $response = file_exists($response)
98
+ ? $this->factory->fromMessage(file_get_contents($response))
99
+ : $this->factory->fromMessage($response);
100
+ } elseif (!($response instanceof ResponseInterface)) {
101
+ throw new \InvalidArgumentException('Response must a message '
102
+ . 'string, response object, or path to a file');
103
+ }
104
+
105
+ $this->queue[] = $response;
106
+
107
+ return $this;
108
+ }
109
+
110
+ /**
111
+ * Add an exception to the end of the queue
112
+ *
113
+ * @param RequestException $e Exception to throw when the request is executed
114
+ *
115
+ * @return self
116
+ */
117
+ public function addException(RequestException $e)
118
+ {
119
+ $this->queue[] = $e;
120
+
121
+ return $this;
122
+ }
123
+
124
+ /**
125
+ * Add multiple items to the queue
126
+ *
127
+ * @param array $items Items to add
128
+ */
129
+ public function addMultiple(array $items)
130
+ {
131
+ foreach ($items as $item) {
132
+ if ($item instanceof RequestException) {
133
+ $this->addException($item);
134
+ } else {
135
+ $this->addResponse($item);
136
+ }
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Clear the queue
142
+ */
143
+ public function clearQueue()
144
+ {
145
+ $this->queue = [];
146
+ }
147
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Prepare.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\BeforeEvent;
5
+ use GuzzleHttp\Event\RequestEvents;
6
+ use GuzzleHttp\Event\SubscriberInterface;
7
+ use GuzzleHttp\Message\AppliesHeadersInterface;
8
+ use GuzzleHttp\Message\RequestInterface;
9
+ use GuzzleHttp\Mimetypes;
10
+ use GuzzleHttp\Stream\StreamInterface;
11
+
12
+ /**
13
+ * Prepares requests with a body before sending
14
+ *
15
+ * **Request Options**
16
+ *
17
+ * - expect: Set to true to enable the "Expect: 100-Continue" header for a
18
+ * request that send a body. Set to false to disable "Expect: 100-Continue".
19
+ * Set to a number so that the size of the payload must be greater than the
20
+ * number in order to send the Expect header. Setting to a number will send
21
+ * the Expect header for all requests in which the size of the payload cannot
22
+ * be determined or where the body is not rewindable.
23
+ */
24
+ class Prepare implements SubscriberInterface
25
+ {
26
+ public function getEvents()
27
+ {
28
+ return ['before' => ['onBefore', RequestEvents::PREPARE_REQUEST]];
29
+ }
30
+
31
+ public function onBefore(BeforeEvent $event)
32
+ {
33
+ $request = $event->getRequest();
34
+
35
+ // Set the appropriate Content-Type for a request if one is not set and
36
+ // there are form fields
37
+ if (!($body = $request->getBody())) {
38
+ return;
39
+ }
40
+
41
+ $this->addContentLength($request, $body);
42
+
43
+ if ($body instanceof AppliesHeadersInterface) {
44
+ // Synchronize the body with the request headers
45
+ $body->applyRequestHeaders($request);
46
+ } elseif (!$request->hasHeader('Content-Type')) {
47
+ $this->addContentType($request, $body);
48
+ }
49
+
50
+ $this->addExpectHeader($request, $body);
51
+ }
52
+
53
+ private function addContentType(
54
+ RequestInterface $request,
55
+ StreamInterface $body
56
+ ) {
57
+ if (!($uri = $body->getMetadata('uri'))) {
58
+ return;
59
+ }
60
+
61
+ // Guess the content-type based on the stream's "uri" metadata value.
62
+ // The file extension is used to determine the appropriate mime-type.
63
+ if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) {
64
+ $request->setHeader('Content-Type', $contentType);
65
+ }
66
+ }
67
+
68
+ private function addContentLength(
69
+ RequestInterface $request,
70
+ StreamInterface $body
71
+ ) {
72
+ // Set the Content-Length header if it can be determined, and never
73
+ // send a Transfer-Encoding: chunked and Content-Length header in
74
+ // the same request.
75
+ if ($request->hasHeader('Content-Length')) {
76
+ // Remove transfer-encoding if content-length is set.
77
+ $request->removeHeader('Transfer-Encoding');
78
+ return;
79
+ }
80
+
81
+ if ($request->hasHeader('Transfer-Encoding')) {
82
+ return;
83
+ }
84
+
85
+ if (null !== ($size = $body->getSize())) {
86
+ $request->setHeader('Content-Length', $size);
87
+ $request->removeHeader('Transfer-Encoding');
88
+ } elseif ('1.1' == $request->getProtocolVersion()) {
89
+ // Use chunked Transfer-Encoding if there is no determinable
90
+ // content-length header and we're using HTTP/1.1.
91
+ $request->setHeader('Transfer-Encoding', 'chunked');
92
+ $request->removeHeader('Content-Length');
93
+ }
94
+ }
95
+
96
+ private function addExpectHeader(
97
+ RequestInterface $request,
98
+ StreamInterface $body
99
+ ) {
100
+ // Determine if the Expect header should be used
101
+ if ($request->hasHeader('Expect')) {
102
+ return;
103
+ }
104
+
105
+ $expect = $request->getConfig()['expect'];
106
+
107
+ // Return if disabled or if you're not using HTTP/1.1
108
+ if ($expect === false || $request->getProtocolVersion() !== '1.1') {
109
+ return;
110
+ }
111
+
112
+ // The expect header is unconditionally enabled
113
+ if ($expect === true) {
114
+ $request->setHeader('Expect', '100-Continue');
115
+ return;
116
+ }
117
+
118
+ // By default, send the expect header when the payload is > 1mb
119
+ if ($expect === null) {
120
+ $expect = 1048576;
121
+ }
122
+
123
+ // Always add if the body cannot be rewound, the size cannot be
124
+ // determined, or the size is greater than the cutoff threshold
125
+ $size = $body->getSize();
126
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
127
+ $request->setHeader('Expect', '100-Continue');
128
+ }
129
+ }
130
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Subscriber/Redirect.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Subscriber;
3
+
4
+ use GuzzleHttp\Event\CompleteEvent;
5
+ use GuzzleHttp\Event\RequestEvents;
6
+ use GuzzleHttp\Event\SubscriberInterface;
7
+ use GuzzleHttp\Exception\BadResponseException;
8
+ use GuzzleHttp\Exception\CouldNotRewindStreamException;
9
+ use GuzzleHttp\Exception\TooManyRedirectsException;
10
+ use GuzzleHttp\Message\RequestInterface;
11
+ use GuzzleHttp\Message\ResponseInterface;
12
+ use GuzzleHttp\Url;
13
+
14
+ /**
15
+ * Subscriber used to implement HTTP redirects.
16
+ *
17
+ * **Request options**
18
+ *
19
+ * - redirect: Associative array containing the 'max', 'strict', and 'referer'
20
+ * keys.
21
+ *
22
+ * - max: Maximum number of redirects allowed per-request
23
+ * - strict: You can use strict redirects by setting this value to ``true``.
24
+ * Strict redirects adhere to strict RFC compliant redirection (e.g.,
25
+ * redirect POST with POST) vs doing what most clients do (e.g., redirect
26
+ * POST request with a GET request).
27
+ * - referer: Set to true to automatically add the "Referer" header when a
28
+ * redirect request is sent.
29
+ * - protocols: Array of allowed protocols. Defaults to 'http' and 'https'.
30
+ * When a redirect attempts to utilize a protocol that is not white listed,
31
+ * an exception is thrown.
32
+ */
33
+ class Redirect implements SubscriberInterface
34
+ {
35
+ public function getEvents()
36
+ {
37
+ return ['complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE]];
38
+ }
39
+
40
+ /**
41
+ * Rewind the entity body of the request if needed
42
+ *
43
+ * @param RequestInterface $redirectRequest
44
+ * @throws CouldNotRewindStreamException
45
+ */
46
+ public static function rewindEntityBody(RequestInterface $redirectRequest)
47
+ {
48
+ // Rewind the entity body of the request if needed
49
+ if ($body = $redirectRequest->getBody()) {
50
+ // Only rewind the body if some of it has been read already, and
51
+ // throw an exception if the rewind fails
52
+ if ($body->tell() && !$body->seek(0)) {
53
+ throw new CouldNotRewindStreamException(
54
+ 'Unable to rewind the non-seekable request body after redirecting',
55
+ $redirectRequest
56
+ );
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Called when a request receives a redirect response
63
+ *
64
+ * @param CompleteEvent $event Event emitted
65
+ * @throws TooManyRedirectsException
66
+ */
67
+ public function onComplete(CompleteEvent $event)
68
+ {
69
+ $response = $event->getResponse();
70
+
71
+ if (substr($response->getStatusCode(), 0, 1) != '3'
72
+ || !$response->hasHeader('Location')
73
+ ) {
74
+ return;
75
+ }
76
+
77
+ $request = $event->getRequest();
78
+ $config = $request->getConfig();
79
+
80
+ // Increment the redirect and initialize the redirect state.
81
+ if ($redirectCount = $config['redirect_count']) {
82
+ $config['redirect_count'] = ++$redirectCount;
83
+ } else {
84
+ $config['redirect_scheme'] = $request->getScheme();
85
+ $config['redirect_count'] = $redirectCount = 1;
86
+ }
87
+
88
+ $max = $config->getPath('redirect/max') ?: 5;
89
+
90
+ if ($redirectCount > $max) {
91
+ throw new TooManyRedirectsException(
92
+ "Will not follow more than {$redirectCount} redirects",
93
+ $request
94
+ );
95
+ }
96
+
97
+ $this->modifyRedirectRequest($request, $response);
98
+ $event->retry();
99
+ }
100
+
101
+ private function modifyRedirectRequest(
102
+ RequestInterface $request,
103
+ ResponseInterface $response
104
+ ) {
105
+ $config = $request->getConfig();
106
+ $protocols = $config->getPath('redirect/protocols') ?: ['http', 'https'];
107
+
108
+ // Use a GET request if this is an entity enclosing request and we are
109
+ // not forcing RFC compliance, but rather emulating what all browsers
110
+ // would do.
111
+ $statusCode = $response->getStatusCode();
112
+ if ($statusCode == 303 ||
113
+ ($statusCode <= 302 && $request->getBody() && !$config->getPath('redirect/strict'))
114
+ ) {
115
+ $request->setMethod('GET');
116
+ $request->setBody(null);
117
+ }
118
+
119
+ $previousUrl = $request->getUrl();
120
+ $this->setRedirectUrl($request, $response, $protocols);
121
+ $this->rewindEntityBody($request);
122
+
123
+ // Add the Referer header if it is told to do so and only
124
+ // add the header if we are not redirecting from https to http.
125
+ if ($config->getPath('redirect/referer')
126
+ && ($request->getScheme() == 'https' || $request->getScheme() == $config['redirect_scheme'])
127
+ ) {
128
+ $url = Url::fromString($previousUrl);
129
+ $url->setUsername(null);
130
+ $url->setPassword(null);
131
+ $request->setHeader('Referer', (string) $url);
132
+ } else {
133
+ $request->removeHeader('Referer');
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Set the appropriate URL on the request based on the location header
139
+ *
140
+ * @param RequestInterface $request
141
+ * @param ResponseInterface $response
142
+ * @param array $protocols
143
+ */
144
+ private function setRedirectUrl(
145
+ RequestInterface $request,
146
+ ResponseInterface $response,
147
+ array $protocols
148
+ ) {
149
+ $location = $response->getHeader('Location');
150
+ $location = Url::fromString($location);
151
+
152
+ // Combine location with the original URL if it is not absolute.
153
+ if (!$location->isAbsolute()) {
154
+ $originalUrl = Url::fromString($request->getUrl());
155
+ // Remove query string parameters and just take what is present on
156
+ // the redirect Location header
157
+ $originalUrl->getQuery()->clear();
158
+ $location = $originalUrl->combine($location);
159
+ }
160
+
161
+ // Ensure that the redirect URL is allowed based on the protocols.
162
+ if (!in_array($location->getScheme(), $protocols)) {
163
+ throw new BadResponseException(
164
+ sprintf(
165
+ 'Redirect URL, %s, does not use one of the allowed redirect protocols: %s',
166
+ $location,
167
+ implode(', ', $protocols)
168
+ ),
169
+ $request,
170
+ $response
171
+ );
172
+ }
173
+
174
+ $request->setUrl($location);
175
+ }
176
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/ToArrayInterface.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * An object that can be represented as an array
6
+ */
7
+ interface ToArrayInterface
8
+ {
9
+ /**
10
+ * Get the array representation of an object
11
+ *
12
+ * @return array
13
+ */
14
+ public function toArray();
15
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Transaction.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Message\RequestInterface;
5
+ use GuzzleHttp\Message\ResponseInterface;
6
+
7
+ /**
8
+ * Represents the relationship between a client, request, and response.
9
+ *
10
+ * You can access the request, response, and client using their corresponding
11
+ * public properties.
12
+ */
13
+ class Transaction
14
+ {
15
+ /**
16
+ * HTTP client used to transfer the request.
17
+ *
18
+ * @var ClientInterface
19
+ */
20
+ public $client;
21
+
22
+ /**
23
+ * The request that is being sent.
24
+ *
25
+ * @var RequestInterface
26
+ */
27
+ public $request;
28
+
29
+ /**
30
+ * The response associated with the transaction. A response will not be
31
+ * present when a networking error occurs or an error occurs before sending
32
+ * the request.
33
+ *
34
+ * @var ResponseInterface|null
35
+ */
36
+ public $response;
37
+
38
+ /**
39
+ * Exception associated with the transaction. If this exception is present
40
+ * when processing synchronous or future commands, then it is thrown. When
41
+ * intercepting a failed transaction, you MUST set this value to null in
42
+ * order to prevent the exception from being thrown.
43
+ *
44
+ * @var \Exception
45
+ */
46
+ public $exception;
47
+
48
+ /**
49
+ * Associative array of handler specific transfer statistics and custom
50
+ * key value pair information. When providing similar information, handlers
51
+ * should follow the same key value pair naming conventions as PHP's
52
+ * curl_getinfo() (http://php.net/manual/en/function.curl-getinfo.php).
53
+ *
54
+ * @var array
55
+ */
56
+ public $transferInfo = [];
57
+
58
+ /**
59
+ * The number of transaction retries.
60
+ *
61
+ * @var int
62
+ */
63
+ public $retries = 0;
64
+
65
+ /**
66
+ * The transaction's current state.
67
+ *
68
+ * @var string
69
+ */
70
+ public $state;
71
+
72
+ /**
73
+ * Whether or not this is a future transaction. This value should not be
74
+ * changed after the future is constructed.
75
+ *
76
+ * @var bool
77
+ */
78
+ public $future;
79
+
80
+ /**
81
+ * The number of state transitions that this transaction has been through.
82
+ *
83
+ * @var int
84
+ * @internal This is for internal use only. If you modify this, then you
85
+ * are asking for trouble.
86
+ */
87
+ public $_transitionCount = 0;
88
+
89
+ /**
90
+ * @param ClientInterface $client Client that is used to send the requests
91
+ * @param RequestInterface $request Request to send
92
+ * @param bool $future Whether or not this is a future request.
93
+ */
94
+ public function __construct(
95
+ ClientInterface $client,
96
+ RequestInterface $request,
97
+ $future = false
98
+ ) {
99
+ $this->client = $client;
100
+ $this->request = $request;
101
+ $this->_future = $future;
102
+ }
103
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/UriTemplate.php ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ /**
5
+ * Expands URI templates. Userland implementation of PECL uri_template.
6
+ *
7
+ * @link http://tools.ietf.org/html/rfc6570
8
+ */
9
+ class UriTemplate
10
+ {
11
+ /** @var string URI template */
12
+ private $template;
13
+
14
+ /** @var array Variables to use in the template expansion */
15
+ private $variables;
16
+
17
+ /** @var array Hash for quick operator lookups */
18
+ private static $operatorHash = array(
19
+ '' => array('prefix' => '', 'joiner' => ',', 'query' => false),
20
+ '+' => array('prefix' => '', 'joiner' => ',', 'query' => false),
21
+ '#' => array('prefix' => '#', 'joiner' => ',', 'query' => false),
22
+ '.' => array('prefix' => '.', 'joiner' => '.', 'query' => false),
23
+ '/' => array('prefix' => '/', 'joiner' => '/', 'query' => false),
24
+ ';' => array('prefix' => ';', 'joiner' => ';', 'query' => true),
25
+ '?' => array('prefix' => '?', 'joiner' => '&', 'query' => true),
26
+ '&' => array('prefix' => '&', 'joiner' => '&', 'query' => true)
27
+ );
28
+
29
+ /** @var array Delimiters */
30
+ private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$',
31
+ '&', '\'', '(', ')', '*', '+', ',', ';', '=');
32
+
33
+ /** @var array Percent encoded delimiters */
34
+ private static $delimsPct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D',
35
+ '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
36
+ '%3B', '%3D');
37
+
38
+ public function expand($template, array $variables)
39
+ {
40
+ if (false === strpos($template, '{')) {
41
+ return $template;
42
+ }
43
+
44
+ $this->template = $template;
45
+ $this->variables = $variables;
46
+
47
+ return preg_replace_callback(
48
+ '/\{([^\}]+)\}/',
49
+ [$this, 'expandMatch'],
50
+ $this->template
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Parse an expression into parts
56
+ *
57
+ * @param string $expression Expression to parse
58
+ *
59
+ * @return array Returns an associative array of parts
60
+ */
61
+ private function parseExpression($expression)
62
+ {
63
+ $result = array();
64
+
65
+ if (isset(self::$operatorHash[$expression[0]])) {
66
+ $result['operator'] = $expression[0];
67
+ $expression = substr($expression, 1);
68
+ } else {
69
+ $result['operator'] = '';
70
+ }
71
+
72
+ foreach (explode(',', $expression) as $value) {
73
+ $value = trim($value);
74
+ $varspec = array();
75
+ if ($colonPos = strpos($value, ':')) {
76
+ $varspec['value'] = substr($value, 0, $colonPos);
77
+ $varspec['modifier'] = ':';
78
+ $varspec['position'] = (int) substr($value, $colonPos + 1);
79
+ } elseif (substr($value, -1) == '*') {
80
+ $varspec['modifier'] = '*';
81
+ $varspec['value'] = substr($value, 0, -1);
82
+ } else {
83
+ $varspec['value'] = (string) $value;
84
+ $varspec['modifier'] = '';
85
+ }
86
+ $result['values'][] = $varspec;
87
+ }
88
+
89
+ return $result;
90
+ }
91
+
92
+ /**
93
+ * Process an expansion
94
+ *
95
+ * @param array $matches Matches met in the preg_replace_callback
96
+ *
97
+ * @return string Returns the replacement string
98
+ */
99
+ private function expandMatch(array $matches)
100
+ {
101
+ static $rfc1738to3986 = array('+' => '%20', '%7e' => '~');
102
+
103
+ $replacements = array();
104
+ $parsed = self::parseExpression($matches[1]);
105
+ $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
106
+ $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
107
+ $useQuery = self::$operatorHash[$parsed['operator']]['query'];
108
+
109
+ foreach ($parsed['values'] as $value) {
110
+
111
+ if (!isset($this->variables[$value['value']])) {
112
+ continue;
113
+ }
114
+
115
+ $variable = $this->variables[$value['value']];
116
+ $actuallyUseQuery = $useQuery;
117
+ $expanded = '';
118
+
119
+ if (is_array($variable)) {
120
+
121
+ $isAssoc = $this->isAssoc($variable);
122
+ $kvp = array();
123
+ foreach ($variable as $key => $var) {
124
+
125
+ if ($isAssoc) {
126
+ $key = rawurlencode($key);
127
+ $isNestedArray = is_array($var);
128
+ } else {
129
+ $isNestedArray = false;
130
+ }
131
+
132
+ if (!$isNestedArray) {
133
+ $var = rawurlencode($var);
134
+ if ($parsed['operator'] == '+' ||
135
+ $parsed['operator'] == '#'
136
+ ) {
137
+ $var = $this->decodeReserved($var);
138
+ }
139
+ }
140
+
141
+ if ($value['modifier'] == '*') {
142
+ if ($isAssoc) {
143
+ if ($isNestedArray) {
144
+ // Nested arrays must allow for deeply nested
145
+ // structures.
146
+ $var = strtr(
147
+ http_build_query([$key => $var]),
148
+ $rfc1738to3986
149
+ );
150
+ } else {
151
+ $var = $key . '=' . $var;
152
+ }
153
+ } elseif ($key > 0 && $actuallyUseQuery) {
154
+ $var = $value['value'] . '=' . $var;
155
+ }
156
+ }
157
+
158
+ $kvp[$key] = $var;
159
+ }
160
+
161
+ if (empty($variable)) {
162
+ $actuallyUseQuery = false;
163
+ } elseif ($value['modifier'] == '*') {
164
+ $expanded = implode($joiner, $kvp);
165
+ if ($isAssoc) {
166
+ // Don't prepend the value name when using the explode
167
+ // modifier with an associative array.
168
+ $actuallyUseQuery = false;
169
+ }
170
+ } else {
171
+ if ($isAssoc) {
172
+ // When an associative array is encountered and the
173
+ // explode modifier is not set, then the result must be
174
+ // a comma separated list of keys followed by their
175
+ // respective values.
176
+ foreach ($kvp as $k => &$v) {
177
+ $v = $k . ',' . $v;
178
+ }
179
+ }
180
+ $expanded = implode(',', $kvp);
181
+ }
182
+
183
+ } else {
184
+ if ($value['modifier'] == ':') {
185
+ $variable = substr($variable, 0, $value['position']);
186
+ }
187
+ $expanded = rawurlencode($variable);
188
+ if ($parsed['operator'] == '+' || $parsed['operator'] == '#') {
189
+ $expanded = $this->decodeReserved($expanded);
190
+ }
191
+ }
192
+
193
+ if ($actuallyUseQuery) {
194
+ if (!$expanded && $joiner != '&') {
195
+ $expanded = $value['value'];
196
+ } else {
197
+ $expanded = $value['value'] . '=' . $expanded;
198
+ }
199
+ }
200
+
201
+ $replacements[] = $expanded;
202
+ }
203
+
204
+ $ret = implode($joiner, $replacements);
205
+ if ($ret && $prefix) {
206
+ return $prefix . $ret;
207
+ }
208
+
209
+ return $ret;
210
+ }
211
+
212
+ /**
213
+ * Determines if an array is associative.
214
+ *
215
+ * This makes the assumption that input arrays are sequences or hashes.
216
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
217
+ * should work in almost every case where input is supplied for a URI
218
+ * template.
219
+ *
220
+ * @param array $array Array to check
221
+ *
222
+ * @return bool
223
+ */
224
+ private function isAssoc(array $array)
225
+ {
226
+ return $array && array_keys($array)[0] !== 0;
227
+ }
228
+
229
+ /**
230
+ * Removes percent encoding on reserved characters (used with + and #
231
+ * modifiers).
232
+ *
233
+ * @param string $string String to fix
234
+ *
235
+ * @return string
236
+ */
237
+ private function decodeReserved($string)
238
+ {
239
+ return str_replace(self::$delimsPct, self::$delims, $string);
240
+ }
241
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Url.php ADDED
@@ -0,0 +1,595 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Ring\Core;
5
+
6
+ /**
7
+ * Parses and generates URLs based on URL parts
8
+ */
9
+ class Url
10
+ {
11
+ private $scheme;
12
+ private $host;
13
+ private $port;
14
+ private $username;
15
+ private $password;
16
+ private $path = '';
17
+ private $fragment;
18
+ private static $defaultPorts = ['http' => 80, 'https' => 443, 'ftp' => 21];
19
+ private static $pathPattern = '/[^a-zA-Z0-9\-\._~!\$&\'\(\)\*\+,;=%:@\/]+|%(?![A-Fa-f0-9]{2})/';
20
+ private static $queryPattern = '/[^a-zA-Z0-9\-\._~!\$\'\(\)\*\+,;%:@\/\?=&]+|%(?![A-Fa-f0-9]{2})/';
21
+ /** @var Query|string Query part of the URL */
22
+ private $query;
23
+
24
+ /**
25
+ * Factory method to create a new URL from a URL string
26
+ *
27
+ * @param string $url Full URL used to create a Url object
28
+ *
29
+ * @return Url
30
+ * @throws \InvalidArgumentException
31
+ */
32
+ public static function fromString($url)
33
+ {
34
+ static $defaults = ['scheme' => null, 'host' => null,
35
+ 'path' => null, 'port' => null, 'query' => null,
36
+ 'user' => null, 'pass' => null, 'fragment' => null];
37
+
38
+ if (false === ($parts = parse_url($url))) {
39
+ throw new \InvalidArgumentException('Unable to parse malformed '
40
+ . 'url: ' . $url);
41
+ }
42
+
43
+ $parts += $defaults;
44
+
45
+ // Convert the query string into a Query object
46
+ if ($parts['query'] || 0 !== strlen($parts['query'])) {
47
+ $parts['query'] = Query::fromString($parts['query']);
48
+ }
49
+
50
+ return new static($parts['scheme'], $parts['host'], $parts['user'],
51
+ $parts['pass'], $parts['port'], $parts['path'], $parts['query'],
52
+ $parts['fragment']);
53
+ }
54
+
55
+ /**
56
+ * Build a URL from parse_url parts. The generated URL will be a relative
57
+ * URL if a scheme or host are not provided.
58
+ *
59
+ * @param array $parts Array of parse_url parts
60
+ *
61
+ * @return string
62
+ */
63
+ public static function buildUrl(array $parts)
64
+ {
65
+ $url = $scheme = '';
66
+
67
+ if (!empty($parts['scheme'])) {
68
+ $scheme = $parts['scheme'];
69
+ $url .= $scheme . ':';
70
+ }
71
+
72
+ if (!empty($parts['host'])) {
73
+ $url .= '//';
74
+ if (isset($parts['user'])) {
75
+ $url .= $parts['user'];
76
+ if (isset($parts['pass'])) {
77
+ $url .= ':' . $parts['pass'];
78
+ }
79
+ $url .= '@';
80
+ }
81
+
82
+ $url .= $parts['host'];
83
+
84
+ // Only include the port if it is not the default port of the scheme
85
+ if (isset($parts['port']) &&
86
+ (!isset(self::$defaultPorts[$scheme]) ||
87
+ $parts['port'] != self::$defaultPorts[$scheme])
88
+ ) {
89
+ $url .= ':' . $parts['port'];
90
+ }
91
+ }
92
+
93
+ // Add the path component if present
94
+ if (isset($parts['path']) && strlen($parts['path'])) {
95
+ // Always ensure that the path begins with '/' if set and something
96
+ // is before the path
97
+ if (!empty($parts['host']) && $parts['path'][0] != '/') {
98
+ $url .= '/';
99
+ }
100
+ $url .= $parts['path'];
101
+ }
102
+
103
+ // Add the query string if present
104
+ if (isset($parts['query'])) {
105
+ $queryStr = (string) $parts['query'];
106
+ if ($queryStr || $queryStr === '0') {
107
+ $url .= '?' . $queryStr;
108
+ }
109
+ }
110
+
111
+ // Ensure that # is only added to the url if fragment contains anything.
112
+ if (isset($parts['fragment'])) {
113
+ $url .= '#' . $parts['fragment'];
114
+ }
115
+
116
+ return $url;
117
+ }
118
+
119
+ /**
120
+ * Create a new URL from URL parts
121
+ *
122
+ * @param string $scheme Scheme of the URL
123
+ * @param string $host Host of the URL
124
+ * @param string $username Username of the URL
125
+ * @param string $password Password of the URL
126
+ * @param int $port Port of the URL
127
+ * @param string $path Path of the URL
128
+ * @param Query|array|string $query Query string of the URL
129
+ * @param string $fragment Fragment of the URL
130
+ */
131
+ public function __construct(
132
+ $scheme,
133
+ $host,
134
+ $username = null,
135
+ $password = null,
136
+ $port = null,
137
+ $path = null,
138
+ $query = null,
139
+ $fragment = null
140
+ ) {
141
+ $this->scheme = strtolower($scheme);
142
+ $this->host = $host;
143
+ $this->port = $port;
144
+ $this->username = $username;
145
+ $this->password = $password;
146
+ $this->fragment = $fragment;
147
+
148
+ if ($query) {
149
+ $this->setQuery($query);
150
+ }
151
+
152
+ $this->setPath($path);
153
+ }
154
+
155
+ /**
156
+ * Clone the URL
157
+ */
158
+ public function __clone()
159
+ {
160
+ if ($this->query instanceof Query) {
161
+ $this->query = clone $this->query;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Returns the URL as a URL string
167
+ *
168
+ * @return string
169
+ */
170
+ public function __toString()
171
+ {
172
+ return static::buildUrl($this->getParts());
173
+ }
174
+
175
+ /**
176
+ * Get the parts of the URL as an array
177
+ *
178
+ * @return array
179
+ */
180
+ public function getParts()
181
+ {
182
+ return array(
183
+ 'scheme' => $this->scheme,
184
+ 'user' => $this->username,
185
+ 'pass' => $this->password,
186
+ 'host' => $this->host,
187
+ 'port' => $this->port,
188
+ 'path' => $this->path,
189
+ 'query' => $this->query,
190
+ 'fragment' => $this->fragment,
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Set the host of the request.
196
+ *
197
+ * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com)
198
+ *
199
+ * @return Url
200
+ */
201
+ public function setHost($host)
202
+ {
203
+ if (strpos($host, ':') === false) {
204
+ $this->host = $host;
205
+ } else {
206
+ list($host, $port) = explode(':', $host);
207
+ $this->host = $host;
208
+ $this->setPort($port);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Get the host part of the URL
214
+ *
215
+ * @return string
216
+ */
217
+ public function getHost()
218
+ {
219
+ return $this->host;
220
+ }
221
+
222
+ /**
223
+ * Set the scheme part of the URL (http, https, ftp, etc.)
224
+ *
225
+ * @param string $scheme Scheme to set
226
+ */
227
+ public function setScheme($scheme)
228
+ {
229
+ // Remove the default port if one is specified
230
+ if ($this->port
231
+ && isset(self::$defaultPorts[$this->scheme])
232
+ && self::$defaultPorts[$this->scheme] == $this->port
233
+ ) {
234
+ $this->port = null;
235
+ }
236
+
237
+ $this->scheme = strtolower($scheme);
238
+ }
239
+
240
+ /**
241
+ * Get the scheme part of the URL
242
+ *
243
+ * @return string
244
+ */
245
+ public function getScheme()
246
+ {
247
+ return $this->scheme;
248
+ }
249
+
250
+ /**
251
+ * Set the port part of the URL
252
+ *
253
+ * @param int $port Port to set
254
+ */
255
+ public function setPort($port)
256
+ {
257
+ $this->port = $port;
258
+ }
259
+
260
+ /**
261
+ * Get the port part of the URl.
262
+ *
263
+ * If no port was set, this method will return the default port for the
264
+ * scheme of the URI.
265
+ *
266
+ * @return int|null
267
+ */
268
+ public function getPort()
269
+ {
270
+ if ($this->port) {
271
+ return $this->port;
272
+ } elseif (isset(self::$defaultPorts[$this->scheme])) {
273
+ return self::$defaultPorts[$this->scheme];
274
+ }
275
+
276
+ return null;
277
+ }
278
+
279
+ /**
280
+ * Set the path part of the URL.
281
+ *
282
+ * The provided URL is URL encoded as necessary.
283
+ *
284
+ * @param string $path Path string to set
285
+ */
286
+ public function setPath($path)
287
+ {
288
+ $this->path = self::encodePath($path);
289
+ }
290
+
291
+ /**
292
+ * Removes dot segments from a URL
293
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
294
+ */
295
+ public function removeDotSegments()
296
+ {
297
+ static $noopPaths = ['' => true, '/' => true, '*' => true];
298
+ static $ignoreSegments = ['.' => true, '..' => true];
299
+
300
+ if (isset($noopPaths[$this->path])) {
301
+ return;
302
+ }
303
+
304
+ $results = [];
305
+ $segments = $this->getPathSegments();
306
+ foreach ($segments as $segment) {
307
+ if ($segment == '..') {
308
+ array_pop($results);
309
+ } elseif (!isset($ignoreSegments[$segment])) {
310
+ $results[] = $segment;
311
+ }
312
+ }
313
+
314
+ $newPath = implode('/', $results);
315
+
316
+ // Add the leading slash if necessary
317
+ if (substr($this->path, 0, 1) === '/' &&
318
+ substr($newPath, 0, 1) !== '/'
319
+ ) {
320
+ $newPath = '/' . $newPath;
321
+ }
322
+
323
+ // Add the trailing slash if necessary
324
+ if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
325
+ $newPath .= '/';
326
+ }
327
+
328
+ $this->path = $newPath;
329
+ }
330
+
331
+ /**
332
+ * Add a relative path to the currently set path.
333
+ *
334
+ * @param string $relativePath Relative path to add
335
+ */
336
+ public function addPath($relativePath)
337
+ {
338
+ if ($relativePath != '/' &&
339
+ is_string($relativePath) &&
340
+ strlen($relativePath) > 0
341
+ ) {
342
+ // Add a leading slash if needed
343
+ if ($relativePath[0] !== '/' &&
344
+ substr($this->path, -1, 1) !== '/'
345
+ ) {
346
+ $relativePath = '/' . $relativePath;
347
+ }
348
+
349
+ $this->setPath($this->path . $relativePath);
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Get the path part of the URL
355
+ *
356
+ * @return string
357
+ */
358
+ public function getPath()
359
+ {
360
+ return $this->path;
361
+ }
362
+
363
+ /**
364
+ * Get the path segments of the URL as an array
365
+ *
366
+ * @return array
367
+ */
368
+ public function getPathSegments()
369
+ {
370
+ return explode('/', $this->path);
371
+ }
372
+
373
+ /**
374
+ * Set the password part of the URL
375
+ *
376
+ * @param string $password Password to set
377
+ */
378
+ public function setPassword($password)
379
+ {
380
+ $this->password = $password;
381
+ }
382
+
383
+ /**
384
+ * Get the password part of the URL
385
+ *
386
+ * @return null|string
387
+ */
388
+ public function getPassword()
389
+ {
390
+ return $this->password;
391
+ }
392
+
393
+ /**
394
+ * Set the username part of the URL
395
+ *
396
+ * @param string $username Username to set
397
+ */
398
+ public function setUsername($username)
399
+ {
400
+ $this->username = $username;
401
+ }
402
+
403
+ /**
404
+ * Get the username part of the URl
405
+ *
406
+ * @return null|string
407
+ */
408
+ public function getUsername()
409
+ {
410
+ return $this->username;
411
+ }
412
+
413
+ /**
414
+ * Get the query part of the URL as a Query object
415
+ *
416
+ * @return Query
417
+ */
418
+ public function getQuery()
419
+ {
420
+ // Convert the query string to a query object if not already done.
421
+ if (!$this->query instanceof Query) {
422
+ $this->query = $this->query === null
423
+ ? new Query()
424
+ : Query::fromString($this->query);
425
+ }
426
+
427
+ return $this->query;
428
+ }
429
+
430
+ /**
431
+ * Set the query part of the URL.
432
+ *
433
+ * You may provide a query string as a string and pass $rawString as true
434
+ * to provide a query string that is not parsed until a call to getQuery()
435
+ * is made. Setting a raw query string will still encode invalid characters
436
+ * in a query string.
437
+ *
438
+ * @param Query|string|array $query Query string value to set. Can
439
+ * be a string that will be parsed into a Query object, an array
440
+ * of key value pairs, or a Query object.
441
+ * @param bool $rawString Set to true when providing a raw query string.
442
+ *
443
+ * @throws \InvalidArgumentException
444
+ */
445
+ public function setQuery($query, $rawString = false)
446
+ {
447
+ if ($query instanceof Query) {
448
+ $this->query = $query;
449
+ } elseif (is_string($query)) {
450
+ if (!$rawString) {
451
+ $this->query = Query::fromString($query);
452
+ } else {
453
+ // Ensure the query does not have illegal characters.
454
+ $this->query = preg_replace_callback(
455
+ self::$queryPattern,
456
+ [__CLASS__, 'encodeMatch'],
457
+ $query
458
+ );
459
+ }
460
+
461
+ } elseif (is_array($query)) {
462
+ $this->query = new Query($query);
463
+ } else {
464
+ throw new \InvalidArgumentException('Query must be a Query, '
465
+ . 'array, or string. Got ' . Core::describeType($query));
466
+ }
467
+ }
468
+
469
+ /**
470
+ * Get the fragment part of the URL
471
+ *
472
+ * @return null|string
473
+ */
474
+ public function getFragment()
475
+ {
476
+ return $this->fragment;
477
+ }
478
+
479
+ /**
480
+ * Set the fragment part of the URL
481
+ *
482
+ * @param string $fragment Fragment to set
483
+ */
484
+ public function setFragment($fragment)
485
+ {
486
+ $this->fragment = $fragment;
487
+ }
488
+
489
+ /**
490
+ * Check if this is an absolute URL
491
+ *
492
+ * @return bool
493
+ */
494
+ public function isAbsolute()
495
+ {
496
+ return $this->scheme && $this->host;
497
+ }
498
+
499
+ /**
500
+ * Combine the URL with another URL and return a new URL instance.
501
+ *
502
+ * Follows the rules specific in RFC 3986 section 5.4.
503
+ *
504
+ * @param string $url Relative URL to combine with
505
+ *
506
+ * @return Url
507
+ * @throws \InvalidArgumentException
508
+ * @link http://tools.ietf.org/html/rfc3986#section-5.4
509
+ */
510
+ public function combine($url)
511
+ {
512
+ $url = static::fromString($url);
513
+
514
+ // Use the more absolute URL as the base URL
515
+ if (!$this->isAbsolute() && $url->isAbsolute()) {
516
+ $url = $url->combine($this);
517
+ }
518
+
519
+ $parts = $url->getParts();
520
+
521
+ // Passing a URL with a scheme overrides everything
522
+ if ($parts['scheme']) {
523
+ return clone $url;
524
+ }
525
+
526
+ // Setting a host overrides the entire rest of the URL
527
+ if ($parts['host']) {
528
+ return new static(
529
+ $this->scheme,
530
+ $parts['host'],
531
+ $parts['user'],
532
+ $parts['pass'],
533
+ $parts['port'],
534
+ $parts['path'],
535
+ $parts['query'] instanceof Query
536
+ ? clone $parts['query']
537
+ : $parts['query'],
538
+ $parts['fragment']
539
+ );
540
+ }
541
+
542
+ if (!$parts['path'] && $parts['path'] !== '0') {
543
+ // The relative URL has no path, so check if it is just a query
544
+ $path = $this->path ?: '';
545
+ $query = $parts['query'] ?: $this->query;
546
+ } else {
547
+ $query = $parts['query'];
548
+ if ($parts['path'][0] == '/' || !$this->path) {
549
+ // Overwrite the existing path if the rel path starts with "/"
550
+ $path = $parts['path'];
551
+ } else {
552
+ // If the relative URL does not have a path or the base URL
553
+ // path does not end in a "/" then overwrite the existing path
554
+ // up to the last "/"
555
+ $path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path'];
556
+ }
557
+ }
558
+
559
+ $result = new self(
560
+ $this->scheme,
561
+ $this->host,
562
+ $this->username,
563
+ $this->password,
564
+ $this->port,
565
+ $path,
566
+ $query instanceof Query ? clone $query : $query,
567
+ $parts['fragment']
568
+ );
569
+
570
+ if ($path) {
571
+ $result->removeDotSegments();
572
+ }
573
+
574
+ return $result;
575
+ }
576
+
577
+ /**
578
+ * Encodes the path part of a URL without double-encoding percent-encoded
579
+ * key value pairs.
580
+ *
581
+ * @param string $path Path to encode
582
+ *
583
+ * @return string
584
+ */
585
+ public static function encodePath($path)
586
+ {
587
+ static $cb = [__CLASS__, 'encodeMatch'];
588
+ return preg_replace_callback(self::$pathPattern, $cb, $path);
589
+ }
590
+
591
+ private static function encodeMatch(array $match)
592
+ {
593
+ return rawurlencode($match[0]);
594
+ }
595
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/src/Utils.php ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp;
3
+
4
+ use GuzzleHttp\Ring\Client\CurlHandler;
5
+ use GuzzleHttp\Ring\Client\CurlMultiHandler;
6
+ use GuzzleHttp\Ring\Client\StreamHandler;
7
+ use GuzzleHttp\Ring\Client\Middleware;
8
+
9
+ /**
10
+ * Utility methods used throughout Guzzle.
11
+ */
12
+ final class Utils
13
+ {
14
+ /**
15
+ * Gets a value from an array using a path syntax to retrieve nested data.
16
+ *
17
+ * This method does not allow for keys that contain "/". You must traverse
18
+ * the array manually or using something more advanced like JMESPath to
19
+ * work with keys that contain "/".
20
+ *
21
+ * // Get the bar key of a set of nested arrays.
22
+ * // This is equivalent to $collection['foo']['baz']['bar'] but won't
23
+ * // throw warnings for missing keys.
24
+ * GuzzleHttp\get_path($data, 'foo/baz/bar');
25
+ *
26
+ * @param array $data Data to retrieve values from
27
+ * @param string $path Path to traverse and retrieve a value from
28
+ *
29
+ * @return mixed|null
30
+ */
31
+ public static function getPath($data, $path)
32
+ {
33
+ $path = explode('/', $path);
34
+
35
+ while (null !== ($part = array_shift($path))) {
36
+ if (!is_array($data) || !isset($data[$part])) {
37
+ return null;
38
+ }
39
+ $data = $data[$part];
40
+ }
41
+
42
+ return $data;
43
+ }
44
+
45
+ /**
46
+ * Set a value in a nested array key. Keys will be created as needed to set
47
+ * the value.
48
+ *
49
+ * This function does not support keys that contain "/" or "[]" characters
50
+ * because these are special tokens used when traversing the data structure.
51
+ * A value may be prepended to an existing array by using "[]" as the final
52
+ * key of a path.
53
+ *
54
+ * GuzzleHttp\get_path($data, 'foo/baz'); // null
55
+ * GuzzleHttp\set_path($data, 'foo/baz/[]', 'a');
56
+ * GuzzleHttp\set_path($data, 'foo/baz/[]', 'b');
57
+ * GuzzleHttp\get_path($data, 'foo/baz');
58
+ * // Returns ['a', 'b']
59
+ *
60
+ * @param array $data Data to modify by reference
61
+ * @param string $path Path to set
62
+ * @param mixed $value Value to set at the key
63
+ *
64
+ * @throws \RuntimeException when trying to setPath using a nested path
65
+ * that travels through a scalar value.
66
+ */
67
+ public static function setPath(&$data, $path, $value)
68
+ {
69
+ $queue = explode('/', $path);
70
+ // Optimization for simple sets.
71
+ if (count($queue) === 1) {
72
+ $data[$path] = $value;
73
+ return;
74
+ }
75
+
76
+ $current =& $data;
77
+ while (null !== ($key = array_shift($queue))) {
78
+ if (!is_array($current)) {
79
+ throw new \RuntimeException("Trying to setPath {$path}, but "
80
+ . "{$key} is set and is not an array");
81
+ } elseif (!$queue) {
82
+ if ($key == '[]') {
83
+ $current[] = $value;
84
+ } else {
85
+ $current[$key] = $value;
86
+ }
87
+ } elseif (isset($current[$key])) {
88
+ $current =& $current[$key];
89
+ } else {
90
+ $current[$key] = [];
91
+ $current =& $current[$key];
92
+ }
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Expands a URI template
98
+ *
99
+ * @param string $template URI template
100
+ * @param array $variables Template variables
101
+ *
102
+ * @return string
103
+ */
104
+ public static function uriTemplate($template, array $variables)
105
+ {
106
+ if (function_exists('\\uri_template')) {
107
+ return \uri_template($template, $variables);
108
+ }
109
+
110
+ static $uriTemplate;
111
+ if (!$uriTemplate) {
112
+ $uriTemplate = new UriTemplate();
113
+ }
114
+
115
+ return $uriTemplate->expand($template, $variables);
116
+ }
117
+
118
+ /**
119
+ * Wrapper for JSON decode that implements error detection with helpful
120
+ * error messages.
121
+ *
122
+ * @param string $json JSON data to parse
123
+ * @param bool $assoc When true, returned objects will be converted
124
+ * into associative arrays.
125
+ * @param int $depth User specified recursion depth.
126
+ * @param int $options Bitmask of JSON decode options.
127
+ *
128
+ * @return mixed
129
+ * @throws \InvalidArgumentException if the JSON cannot be parsed.
130
+ * @link http://www.php.net/manual/en/function.json-decode.php
131
+ */
132
+ public static function jsonDecode($json, $assoc = false, $depth = 512, $options = 0)
133
+ {
134
+ static $jsonErrors = [
135
+ JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
136
+ JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
137
+ JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
138
+ JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
139
+ JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
140
+ ];
141
+
142
+ $data = \json_decode($json, $assoc, $depth, $options);
143
+
144
+ if (JSON_ERROR_NONE !== json_last_error()) {
145
+ $last = json_last_error();
146
+ throw new \InvalidArgumentException(
147
+ 'Unable to parse JSON data: '
148
+ . (isset($jsonErrors[$last])
149
+ ? $jsonErrors[$last]
150
+ : 'Unknown error')
151
+ );
152
+ }
153
+
154
+ return $data;
155
+ }
156
+
157
+ /**
158
+ * Get the default User-Agent string to use with Guzzle
159
+ *
160
+ * @return string
161
+ */
162
+ public static function getDefaultUserAgent()
163
+ {
164
+ static $defaultAgent = '';
165
+ if (!$defaultAgent) {
166
+ $defaultAgent = 'Guzzle/' . ClientInterface::VERSION;
167
+ if (extension_loaded('curl')) {
168
+ $defaultAgent .= ' curl/' . curl_version()['version'];
169
+ }
170
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
171
+ }
172
+
173
+ return $defaultAgent;
174
+ }
175
+
176
+ /**
177
+ * Create a default handler to use based on the environment
178
+ *
179
+ * @throws \RuntimeException if no viable Handler is available.
180
+ */
181
+ public static function getDefaultHandler()
182
+ {
183
+ $default = $future = null;
184
+
185
+ if (extension_loaded('curl')) {
186
+ $config = [
187
+ 'select_timeout' => getenv('GUZZLE_CURL_SELECT_TIMEOUT') ?: 1
188
+ ];
189
+ if ($maxHandles = getenv('GUZZLE_CURL_MAX_HANDLES')) {
190
+ $config['max_handles'] = $maxHandles;
191
+ }
192
+ if (function_exists('curl_reset')) {
193
+ $default = new CurlHandler();
194
+ $future = new CurlMultiHandler($config);
195
+ } else {
196
+ $default = new CurlMultiHandler($config);
197
+ }
198
+ }
199
+
200
+ if (ini_get('allow_url_fopen')) {
201
+ $default = !$default
202
+ ? new StreamHandler()
203
+ : Middleware::wrapStreaming($default, new StreamHandler());
204
+ } elseif (!$default) {
205
+ throw new \RuntimeException('Guzzle requires cURL, the '
206
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
207
+ }
208
+
209
+ return $future ? Middleware::wrapFuture($default, $future) : $default;
210
+ }
211
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/tests/BatchResultsTest.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests;
3
+
4
+ use GuzzleHttp\BatchResults;
5
+
6
+ /**
7
+ * @covers \GuzzleHttp\BatchResults
8
+ */
9
+ class BatchResultsTest extends \PHPUnit_Framework_TestCase
10
+ {
11
+ public function testExposesResults()
12
+ {
13
+ $a = new \stdClass();
14
+ $b = new \stdClass();
15
+ $c = new \stdClass();
16
+ $hash = new \SplObjectStorage();
17
+ $hash[$a] = '1';
18
+ $hash[$b] = '2';
19
+ $hash[$c] = new \Exception('foo');
20
+
21
+ $batch = new BatchResults($hash);
22
+ $this->assertCount(3, $batch);
23
+ $this->assertEquals([$a, $b, $c], $batch->getKeys());
24
+ $this->assertEquals([$hash[$c]], $batch->getFailures());
25
+ $this->assertEquals(['1', '2'], $batch->getSuccessful());
26
+ $this->assertEquals('1', $batch->getResult($a));
27
+ $this->assertNull($batch->getResult(new \stdClass()));
28
+ $this->assertTrue(isset($batch[0]));
29
+ $this->assertFalse(isset($batch[10]));
30
+ $this->assertEquals('1', $batch[0]);
31
+ $this->assertEquals('2', $batch[1]);
32
+ $this->assertNull($batch[100]);
33
+ $this->assertInstanceOf('Exception', $batch[2]);
34
+
35
+ $results = iterator_to_array($batch);
36
+ $this->assertEquals(['1', '2', $hash[$c]], $results);
37
+ }
38
+
39
+ /**
40
+ * @expectedException \RuntimeException
41
+ */
42
+ public function testCannotSetByIndex()
43
+ {
44
+ $hash = new \SplObjectStorage();
45
+ $batch = new BatchResults($hash);
46
+ $batch[10] = 'foo';
47
+ }
48
+
49
+ /**
50
+ * @expectedException \RuntimeException
51
+ */
52
+ public function testCannotUnsetByIndex()
53
+ {
54
+ $hash = new \SplObjectStorage();
55
+ $batch = new BatchResults($hash);
56
+ unset($batch[10]);
57
+ }
58
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/tests/ClientTest.php ADDED
@@ -0,0 +1,647 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests;
3
+
4
+ use GuzzleHttp\Client;
5
+ use GuzzleHttp\Event\BeforeEvent;
6
+ use GuzzleHttp\Event\ErrorEvent;
7
+ use GuzzleHttp\Message\MessageFactory;
8
+ use GuzzleHttp\Message\Response;
9
+ use GuzzleHttp\Exception\RequestException;
10
+ use GuzzleHttp\Query;
11
+ use GuzzleHttp\Ring\Client\MockHandler;
12
+ use GuzzleHttp\Ring\Future\FutureArray;
13
+ use GuzzleHttp\Subscriber\History;
14
+ use GuzzleHttp\Subscriber\Mock;
15
+ use GuzzleHttp\Url;
16
+ use GuzzleHttp\Utils;
17
+ use React\Promise\Deferred;
18
+
19
+ /**
20
+ * @covers GuzzleHttp\Client
21
+ */
22
+ class ClientTest extends \PHPUnit_Framework_TestCase
23
+ {
24
+ /** @callable */
25
+ private $ma;
26
+
27
+ public function setup()
28
+ {
29
+ $this->ma = function () {
30
+ throw new \RuntimeException('Should not have been called.');
31
+ };
32
+ }
33
+
34
+ public function testUsesDefaultDefaultOptions()
35
+ {
36
+ $client = new Client();
37
+ $this->assertTrue($client->getDefaultOption('allow_redirects'));
38
+ $this->assertTrue($client->getDefaultOption('exceptions'));
39
+ $this->assertTrue($client->getDefaultOption('verify'));
40
+ }
41
+
42
+ public function testUsesProvidedDefaultOptions()
43
+ {
44
+ $client = new Client([
45
+ 'defaults' => [
46
+ 'allow_redirects' => false,
47
+ 'query' => ['foo' => 'bar']
48
+ ]
49
+ ]);
50
+ $this->assertFalse($client->getDefaultOption('allow_redirects'));
51
+ $this->assertTrue($client->getDefaultOption('exceptions'));
52
+ $this->assertTrue($client->getDefaultOption('verify'));
53
+ $this->assertEquals(['foo' => 'bar'], $client->getDefaultOption('query'));
54
+ }
55
+
56
+ public function testCanSpecifyBaseUrl()
57
+ {
58
+ $this->assertSame('', (new Client())->getBaseUrl());
59
+ $this->assertEquals('http://foo', (new Client([
60
+ 'base_url' => 'http://foo'
61
+ ]))->getBaseUrl());
62
+ }
63
+
64
+ public function testCanSpecifyBaseUrlUriTemplate()
65
+ {
66
+ $client = new Client(['base_url' => ['http://foo.com/{var}/', ['var' => 'baz']]]);
67
+ $this->assertEquals('http://foo.com/baz/', $client->getBaseUrl());
68
+ }
69
+
70
+ /**
71
+ * @expectedException \InvalidArgumentException
72
+ */
73
+ public function testValidatesUriTemplateValue()
74
+ {
75
+ new Client(['base_url' => ['http://foo.com/']]);
76
+ }
77
+
78
+ /**
79
+ * @expectedException \Exception
80
+ * @expectedExceptionMessage Foo
81
+ */
82
+ public function testCanSpecifyHandler()
83
+ {
84
+ $client = new Client(['handler' => function () {
85
+ throw new \Exception('Foo');
86
+ }]);
87
+ $client->get('http://httpbin.org');
88
+ }
89
+
90
+ /**
91
+ * @expectedException \Exception
92
+ * @expectedExceptionMessage Foo
93
+ */
94
+ public function testCanSpecifyHandlerAsAdapter()
95
+ {
96
+ $client = new Client(['adapter' => function () {
97
+ throw new \Exception('Foo');
98
+ }]);
99
+ $client->get('http://httpbin.org');
100
+ }
101
+
102
+ /**
103
+ * @expectedException \Exception
104
+ * @expectedExceptionMessage Foo
105
+ */
106
+ public function testCanSpecifyMessageFactory()
107
+ {
108
+ $factory = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface')
109
+ ->setMethods(['createRequest'])
110
+ ->getMockForAbstractClass();
111
+ $factory->expects($this->once())
112
+ ->method('createRequest')
113
+ ->will($this->throwException(new \Exception('Foo')));
114
+ $client = new Client(['message_factory' => $factory]);
115
+ $client->get();
116
+ }
117
+
118
+ public function testCanSpecifyEmitter()
119
+ {
120
+ $emitter = $this->getMockBuilder('GuzzleHttp\Event\EmitterInterface')
121
+ ->setMethods(['listeners'])
122
+ ->getMockForAbstractClass();
123
+ $emitter->expects($this->once())
124
+ ->method('listeners')
125
+ ->will($this->returnValue('foo'));
126
+
127
+ $client = new Client(['emitter' => $emitter]);
128
+ $this->assertEquals('foo', $client->getEmitter()->listeners());
129
+ }
130
+
131
+ public function testAddsDefaultUserAgentHeaderWithDefaultOptions()
132
+ {
133
+ $client = new Client(['defaults' => ['allow_redirects' => false]]);
134
+ $this->assertFalse($client->getDefaultOption('allow_redirects'));
135
+ $this->assertEquals(
136
+ ['User-Agent' => Utils::getDefaultUserAgent()],
137
+ $client->getDefaultOption('headers')
138
+ );
139
+ }
140
+
141
+ public function testAddsDefaultUserAgentHeaderWithoutDefaultOptions()
142
+ {
143
+ $client = new Client();
144
+ $this->assertEquals(
145
+ ['User-Agent' => Utils::getDefaultUserAgent()],
146
+ $client->getDefaultOption('headers')
147
+ );
148
+ }
149
+
150
+ private function getRequestClient()
151
+ {
152
+ $client = $this->getMockBuilder('GuzzleHttp\Client')
153
+ ->setMethods(['send'])
154
+ ->getMock();
155
+ $client->expects($this->once())
156
+ ->method('send')
157
+ ->will($this->returnArgument(0));
158
+
159
+ return $client;
160
+ }
161
+
162
+ public function requestMethodProvider()
163
+ {
164
+ return [
165
+ ['GET', false],
166
+ ['HEAD', false],
167
+ ['DELETE', false],
168
+ ['OPTIONS', false],
169
+ ['POST', 'foo'],
170
+ ['PUT', 'foo'],
171
+ ['PATCH', 'foo']
172
+ ];
173
+ }
174
+
175
+ /**
176
+ * @dataProvider requestMethodProvider
177
+ */
178
+ public function testClientProvidesMethodShortcut($method, $body)
179
+ {
180
+ $client = $this->getRequestClient();
181
+ if ($body) {
182
+ $request = $client->{$method}('http://foo.com', [
183
+ 'headers' => ['X-Baz' => 'Bar'],
184
+ 'body' => $body,
185
+ 'query' => ['a' => 'b']
186
+ ]);
187
+ } else {
188
+ $request = $client->{$method}('http://foo.com', [
189
+ 'headers' => ['X-Baz' => 'Bar'],
190
+ 'query' => ['a' => 'b']
191
+ ]);
192
+ }
193
+ $this->assertEquals($method, $request->getMethod());
194
+ $this->assertEquals('Bar', $request->getHeader('X-Baz'));
195
+ $this->assertEquals('a=b', $request->getQuery());
196
+ if ($body) {
197
+ $this->assertEquals($body, $request->getBody());
198
+ }
199
+ }
200
+
201
+ public function testClientMergesDefaultOptionsWithRequestOptions()
202
+ {
203
+ $f = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface')
204
+ ->setMethods(array('createRequest'))
205
+ ->getMockForAbstractClass();
206
+
207
+ $o = null;
208
+ // Intercept the creation
209
+ $f->expects($this->once())
210
+ ->method('createRequest')
211
+ ->will($this->returnCallback(
212
+ function ($method, $url, array $options = []) use (&$o) {
213
+ $o = $options;
214
+ return (new MessageFactory())->createRequest($method, $url, $options);
215
+ }
216
+ ));
217
+
218
+ $client = new Client([
219
+ 'message_factory' => $f,
220
+ 'defaults' => [
221
+ 'headers' => ['Foo' => 'Bar'],
222
+ 'query' => ['baz' => 'bam'],
223
+ 'exceptions' => false
224
+ ]
225
+ ]);
226
+
227
+ $request = $client->createRequest('GET', 'http://foo.com?a=b', [
228
+ 'headers' => ['Hi' => 'there', '1' => 'one'],
229
+ 'allow_redirects' => false,
230
+ 'query' => ['t' => 1]
231
+ ]);
232
+
233
+ $this->assertFalse($o['allow_redirects']);
234
+ $this->assertFalse($o['exceptions']);
235
+ $this->assertEquals('Bar', $request->getHeader('Foo'));
236
+ $this->assertEquals('there', $request->getHeader('Hi'));
237
+ $this->assertEquals('one', $request->getHeader('1'));
238
+ $this->assertEquals('a=b&baz=bam&t=1', $request->getQuery());
239
+ }
240
+
241
+ public function testClientMergesDefaultHeadersCaseInsensitively()
242
+ {
243
+ $client = new Client(['defaults' => ['headers' => ['Foo' => 'Bar']]]);
244
+ $request = $client->createRequest('GET', 'http://foo.com?a=b', [
245
+ 'headers' => ['foo' => 'custom', 'user-agent' => 'test']
246
+ ]);
247
+ $this->assertEquals('test', $request->getHeader('User-Agent'));
248
+ $this->assertEquals('custom', $request->getHeader('Foo'));
249
+ }
250
+
251
+ public function testCanOverrideDefaultOptionWithNull()
252
+ {
253
+ $client = new Client(['defaults' => ['proxy' => 'invalid!']]);
254
+ $request = $client->createRequest('GET', 'http://foo.com?a=b', [
255
+ 'proxy' => null
256
+ ]);
257
+ $this->assertFalse($request->getConfig()->hasKey('proxy'));
258
+ }
259
+
260
+ public function testDoesNotOverwriteExistingUA()
261
+ {
262
+ $client = new Client(['defaults' => [
263
+ 'headers' => ['User-Agent' => 'test']
264
+ ]]);
265
+ $this->assertEquals(
266
+ ['User-Agent' => 'test'],
267
+ $client->getDefaultOption('headers')
268
+ );
269
+ }
270
+
271
+ public function testUsesBaseUrlWhenNoUrlIsSet()
272
+ {
273
+ $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
274
+ $this->assertEquals(
275
+ 'http://www.foo.com/baz?bam=bar',
276
+ $client->createRequest('GET')->getUrl()
277
+ );
278
+ }
279
+
280
+ public function testUsesBaseUrlCombinedWithProvidedUrl()
281
+ {
282
+ $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
283
+ $this->assertEquals(
284
+ 'http://www.foo.com/bar/bam',
285
+ $client->createRequest('GET', 'bar/bam')->getUrl()
286
+ );
287
+ }
288
+
289
+ public function testFalsyPathsAreCombinedWithBaseUrl()
290
+ {
291
+ $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
292
+ $this->assertEquals(
293
+ 'http://www.foo.com/0',
294
+ $client->createRequest('GET', '0')->getUrl()
295
+ );
296
+ }
297
+
298
+ public function testUsesBaseUrlCombinedWithProvidedUrlViaUriTemplate()
299
+ {
300
+ $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
301
+ $this->assertEquals(
302
+ 'http://www.foo.com/bar/123',
303
+ $client->createRequest('GET', ['bar/{bam}', ['bam' => '123']])->getUrl()
304
+ );
305
+ }
306
+
307
+ public function testSettingAbsoluteUrlOverridesBaseUrl()
308
+ {
309
+ $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
310
+ $this->assertEquals(
311
+ 'http://www.foo.com/foo',
312
+ $client->createRequest('GET', '/foo')->getUrl()
313
+ );
314
+ }
315
+
316
+ public function testSettingAbsoluteUriTemplateOverridesBaseUrl()
317
+ {
318
+ $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
319
+ $this->assertEquals(
320
+ 'http://goo.com/1',
321
+ $client->createRequest(
322
+ 'GET',
323
+ ['http://goo.com/{bar}', ['bar' => '1']]
324
+ )->getUrl()
325
+ );
326
+ }
327
+
328
+ public function testCanSetRelativeUrlStartingWithHttp()
329
+ {
330
+ $client = new Client(['base_url' => 'http://www.foo.com']);
331
+ $this->assertEquals(
332
+ 'http://www.foo.com/httpfoo',
333
+ $client->createRequest('GET', 'httpfoo')->getUrl()
334
+ );
335
+ }
336
+
337
+ /**
338
+ * Test that base URLs ending with a slash are resolved as per RFC3986.
339
+ *
340
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.3
341
+ */
342
+ public function testMultipleSubdirectoryWithSlash()
343
+ {
344
+ $client = new Client(['base_url' => 'http://www.foo.com/bar/bam/']);
345
+ $this->assertEquals(
346
+ 'http://www.foo.com/bar/bam/httpfoo',
347
+ $client->createRequest('GET', 'httpfoo')->getUrl()
348
+ );
349
+ }
350
+
351
+ /**
352
+ * Test that base URLs ending without a slash are resolved as per RFC3986.
353
+ *
354
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.3
355
+ */
356
+ public function testMultipleSubdirectoryNoSlash()
357
+ {
358
+ $client = new Client(['base_url' => 'http://www.foo.com/bar/bam']);
359
+ $this->assertEquals(
360
+ 'http://www.foo.com/bar/httpfoo',
361
+ $client->createRequest('GET', 'httpfoo')->getUrl()
362
+ );
363
+ }
364
+
365
+ public function testClientSendsRequests()
366
+ {
367
+ $mock = new MockHandler(['status' => 200, 'headers' => []]);
368
+ $client = new Client(['handler' => $mock]);
369
+ $response = $client->get('http://test.com');
370
+ $this->assertEquals(200, $response->getStatusCode());
371
+ $this->assertEquals('http://test.com', $response->getEffectiveUrl());
372
+ }
373
+
374
+ public function testSendingRequestCanBeIntercepted()
375
+ {
376
+ $response = new Response(200);
377
+ $client = new Client(['handler' => $this->ma]);
378
+ $client->getEmitter()->on(
379
+ 'before',
380
+ function (BeforeEvent $e) use ($response) {
381
+ $e->intercept($response);
382
+ }
383
+ );
384
+ $this->assertSame($response, $client->get('http://test.com'));
385
+ $this->assertEquals('http://test.com', $response->getEffectiveUrl());
386
+ }
387
+
388
+ /**
389
+ * @expectedException \GuzzleHttp\Exception\RequestException
390
+ * @expectedExceptionMessage Argument 1 passed to GuzzleHttp\Message\FutureResponse::proxy() must implement interface GuzzleHttp\Ring\Future\FutureInterface
391
+ */
392
+ public function testEnsuresResponseIsPresentAfterSending()
393
+ {
394
+ $handler = function () {};
395
+ $client = new Client(['handler' => $handler]);
396
+ $client->get('http://httpbin.org');
397
+ }
398
+
399
+ /**
400
+ * @expectedException \GuzzleHttp\Exception\RequestException
401
+ * @expectedExceptionMessage Waiting did not resolve future
402
+ */
403
+ public function testEnsuresResponseIsPresentAfterDereferencing()
404
+ {
405
+ $deferred = new Deferred();
406
+ $handler = new MockHandler(function () use ($deferred) {
407
+ return new FutureArray(
408
+ $deferred->promise(),
409
+ function () {}
410
+ );
411
+ });
412
+ $client = new Client(['handler' => $handler]);
413
+ $response = $client->get('http://httpbin.org');
414
+ $response->wait();
415
+ }
416
+
417
+ public function testClientHandlesErrorsDuringBeforeSend()
418
+ {
419
+ $client = new Client();
420
+ $client->getEmitter()->on('before', function ($e) {
421
+ throw new \Exception('foo');
422
+ });
423
+ $client->getEmitter()->on('error', function (ErrorEvent $e) {
424
+ $e->intercept(new Response(200));
425
+ });
426
+ $this->assertEquals(
427
+ 200,
428
+ $client->get('http://test.com')->getStatusCode()
429
+ );
430
+ }
431
+
432
+ /**
433
+ * @expectedException \GuzzleHttp\Exception\RequestException
434
+ * @expectedExceptionMessage foo
435
+ */
436
+ public function testClientHandlesErrorsDuringBeforeSendAndThrowsIfUnhandled()
437
+ {
438
+ $client = new Client();
439
+ $client->getEmitter()->on('before', function (BeforeEvent $e) {
440
+ throw new RequestException('foo', $e->getRequest());
441
+ });
442
+ $client->get('http://httpbin.org');
443
+ }
444
+
445
+ /**
446
+ * @expectedException \GuzzleHttp\Exception\RequestException
447
+ * @expectedExceptionMessage foo
448
+ */
449
+ public function testClientWrapsExceptions()
450
+ {
451
+ $client = new Client();
452
+ $client->getEmitter()->on('before', function (BeforeEvent $e) {
453
+ throw new \Exception('foo');
454
+ });
455
+ $client->get('http://httpbin.org');
456
+ }
457
+
458
+ public function testCanInjectResponseForFutureError()
459
+ {
460
+ $calledFuture = false;
461
+ $deferred = new Deferred();
462
+ $future = new FutureArray(
463
+ $deferred->promise(),
464
+ function () use ($deferred, &$calledFuture) {
465
+ $calledFuture = true;
466
+ $deferred->resolve(['error' => new \Exception('Noo!')]);
467
+ }
468
+ );
469
+ $mock = new MockHandler($future);
470
+ $client = new Client(['handler' => $mock]);
471
+ $called = 0;
472
+ $response = $client->get('http://localhost:123/foo', [
473
+ 'future' => true,
474
+ 'events' => [
475
+ 'error' => function (ErrorEvent $e) use (&$called) {
476
+ $called++;
477
+ $e->intercept(new Response(200));
478
+ }
479
+ ]
480
+ ]);
481
+ $this->assertEquals(0, $called);
482
+ $this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $response);
483
+ $this->assertEquals(200, $response->getStatusCode());
484
+ $this->assertTrue($calledFuture);
485
+ $this->assertEquals(1, $called);
486
+ }
487
+
488
+ public function testCanReturnFutureResults()
489
+ {
490
+ $called = false;
491
+ $deferred = new Deferred();
492
+ $future = new FutureArray(
493
+ $deferred->promise(),
494
+ function () use ($deferred, &$called) {
495
+ $called = true;
496
+ $deferred->resolve(['status' => 201, 'headers' => []]);
497
+ }
498
+ );
499
+ $mock = new MockHandler($future);
500
+ $client = new Client(['handler' => $mock]);
501
+ $response = $client->get('http://localhost:123/foo', ['future' => true]);
502
+ $this->assertFalse($called);
503
+ $this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $response);
504
+ $this->assertEquals(201, $response->getStatusCode());
505
+ $this->assertTrue($called);
506
+ }
507
+
508
+ public function testThrowsExceptionsWhenDereferenced()
509
+ {
510
+ $calledFuture = false;
511
+ $deferred = new Deferred();
512
+ $future = new FutureArray(
513
+ $deferred->promise(),
514
+ function () use ($deferred, &$calledFuture) {
515
+ $calledFuture = true;
516
+ $deferred->resolve(['error' => new \Exception('Noop!')]);
517
+ }
518
+ );
519
+ $client = new Client(['handler' => new MockHandler($future)]);
520
+ try {
521
+ $res = $client->get('http://localhost:123/foo', ['future' => true]);
522
+ $res->wait();
523
+ $this->fail('Did not throw');
524
+ } catch (RequestException $e) {
525
+ $this->assertEquals(1, $calledFuture);
526
+ }
527
+ }
528
+
529
+ /**
530
+ * @expectedExceptionMessage Noo!
531
+ * @expectedException \GuzzleHttp\Exception\RequestException
532
+ */
533
+ public function testThrowsExceptionsSynchronously()
534
+ {
535
+ $client = new Client([
536
+ 'handler' => new MockHandler(['error' => new \Exception('Noo!')])
537
+ ]);
538
+ $client->get('http://localhost:123/foo');
539
+ }
540
+
541
+ public function testCanSetDefaultValues()
542
+ {
543
+ $client = new Client(['foo' => 'bar']);
544
+ $client->setDefaultOption('headers/foo', 'bar');
545
+ $this->assertNull($client->getDefaultOption('foo'));
546
+ $this->assertEquals('bar', $client->getDefaultOption('headers/foo'));
547
+ }
548
+
549
+ public function testSendsAllInParallel()
550
+ {
551
+ $client = new Client();
552
+ $client->getEmitter()->attach(new Mock([
553
+ new Response(200),
554
+ new Response(201),
555
+ new Response(202),
556
+ ]));
557
+ $history = new History();
558
+ $client->getEmitter()->attach($history);
559
+
560
+ $requests = [
561
+ $client->createRequest('GET', 'http://test.com'),
562
+ $client->createRequest('POST', 'http://test.com'),
563
+ $client->createRequest('PUT', 'http://test.com')
564
+ ];
565
+
566
+ $client->sendAll($requests);
567
+ $requests = array_map(function($r) {
568
+ return $r->getMethod();
569
+ }, $history->getRequests());
570
+ $this->assertContains('GET', $requests);
571
+ $this->assertContains('POST', $requests);
572
+ $this->assertContains('PUT', $requests);
573
+ }
574
+
575
+ public function testCanDisableAuthPerRequest()
576
+ {
577
+ $client = new Client(['defaults' => ['auth' => 'foo']]);
578
+ $request = $client->createRequest('GET', 'http://test.com');
579
+ $this->assertEquals('foo', $request->getConfig()['auth']);
580
+ $request = $client->createRequest('GET', 'http://test.com', ['auth' => null]);
581
+ $this->assertFalse($request->getConfig()->hasKey('auth'));
582
+ }
583
+
584
+ public function testUsesProxyEnvironmentVariables()
585
+ {
586
+ $http = getenv('HTTP_PROXY');
587
+ $https = getenv('HTTPS_PROXY');
588
+
589
+ $client = new Client();
590
+ $this->assertNull($client->getDefaultOption('proxy'));
591
+
592
+ putenv('HTTP_PROXY=127.0.0.1');
593
+ $client = new Client();
594
+ $this->assertEquals(
595
+ ['http' => '127.0.0.1'],
596
+ $client->getDefaultOption('proxy')
597
+ );
598
+
599
+ putenv('HTTPS_PROXY=127.0.0.2');
600
+ $client = new Client();
601
+ $this->assertEquals(
602
+ ['http' => '127.0.0.1', 'https' => '127.0.0.2'],
603
+ $client->getDefaultOption('proxy')
604
+ );
605
+
606
+ putenv("HTTP_PROXY=$http");
607
+ putenv("HTTPS_PROXY=$https");
608
+ }
609
+
610
+ public function testReturnsFutureForErrorWhenRequested()
611
+ {
612
+ $client = new Client(['handler' => new MockHandler(['status' => 404])]);
613
+ $request = $client->createRequest('GET', 'http://localhost:123/foo', [
614
+ 'future' => true
615
+ ]);
616
+ $res = $client->send($request);
617
+ $this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $res);
618
+ try {
619
+ $res->wait();
620
+ $this->fail('did not throw');
621
+ } catch (RequestException $e) {
622
+ $this->assertContains('404', $e->getMessage());
623
+ }
624
+ }
625
+
626
+ public function testReturnsFutureForResponseWhenRequested()
627
+ {
628
+ $client = new Client(['handler' => new MockHandler(['status' => 200])]);
629
+ $request = $client->createRequest('GET', 'http://localhost:123/foo', [
630
+ 'future' => true
631
+ ]);
632
+ $res = $client->send($request);
633
+ $this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $res);
634
+ $this->assertEquals(200, $res->getStatusCode());
635
+ }
636
+
637
+ public function testCanUseUrlWithCustomQuery()
638
+ {
639
+ $client = new Client();
640
+ $url = Url::fromString('http://foo.com/bar');
641
+ $query = new Query(['baz' => '123%20']);
642
+ $query->setEncodingType(false);
643
+ $url->setQuery($query);
644
+ $r = $client->createRequest('GET', $url);
645
+ $this->assertEquals('http://foo.com/bar?baz=123%20', $r->getUrl());
646
+ }
647
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/tests/CollectionTest.php ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Tests;
4
+
5
+ use GuzzleHttp\Collection;
6
+
7
+ class CollectionTest extends \PHPUnit_Framework_TestCase
8
+ {
9
+ /** @var Collection */
10
+ protected $coll;
11
+
12
+ protected function setUp()
13
+ {
14
+ $this->coll = new Collection();
15
+ }
16
+
17
+ public function testConstructorCanBeCalledWithNoParams()
18
+ {
19
+ $this->coll = new Collection();
20
+ $p = $this->coll->toArray();
21
+ $this->assertEmpty($p, '-> Collection must be empty when no data is passed');
22
+ }
23
+
24
+ public function testConstructorCanBeCalledWithParams()
25
+ {
26
+ $testData = array(
27
+ 'test' => 'value',
28
+ 'test_2' => 'value2'
29
+ );
30
+ $this->coll = new Collection($testData);
31
+ $this->assertEquals($this->coll->toArray(), $testData);
32
+ $this->assertEquals($this->coll->toArray(), $this->coll->toArray());
33
+ }
34
+
35
+ public function testImplementsIteratorAggregate()
36
+ {
37
+ $this->coll->set('key', 'value');
38
+ $this->assertInstanceOf('ArrayIterator', $this->coll->getIterator());
39
+ $this->assertEquals(1, count($this->coll));
40
+ $total = 0;
41
+ foreach ($this->coll as $key => $value) {
42
+ $this->assertEquals('key', $key);
43
+ $this->assertEquals('value', $value);
44
+ $total++;
45
+ }
46
+ $this->assertEquals(1, $total);
47
+ }
48
+
49
+ public function testCanAddValuesToExistingKeysByUsingArray()
50
+ {
51
+ $this->coll->add('test', 'value1');
52
+ $this->assertEquals($this->coll->toArray(), array('test' => 'value1'));
53
+ $this->coll->add('test', 'value2');
54
+ $this->assertEquals($this->coll->toArray(), array('test' => array('value1', 'value2')));
55
+ $this->coll->add('test', 'value3');
56
+ $this->assertEquals($this->coll->toArray(), array('test' => array('value1', 'value2', 'value3')));
57
+ }
58
+
59
+ public function testHandlesMergingInDisparateDataSources()
60
+ {
61
+ $params = array(
62
+ 'test' => 'value1',
63
+ 'test2' => 'value2',
64
+ 'test3' => array('value3', 'value4')
65
+ );
66
+ $this->coll->merge($params);
67
+ $this->assertEquals($this->coll->toArray(), $params);
68
+ $this->coll->merge(new Collection(['test4' => 'hi']));
69
+ $this->assertEquals(
70
+ $this->coll->toArray(),
71
+ $params + ['test4' => 'hi']
72
+ );
73
+ }
74
+
75
+ public function testCanClearAllDataOrSpecificKeys()
76
+ {
77
+ $this->coll->merge(array(
78
+ 'test' => 'value1',
79
+ 'test2' => 'value2'
80
+ ));
81
+
82
+ // Clear a specific parameter by name
83
+ $this->coll->remove('test');
84
+
85
+ $this->assertEquals($this->coll->toArray(), array(
86
+ 'test2' => 'value2'
87
+ ));
88
+
89
+ // Clear all parameters
90
+ $this->coll->clear();
91
+
92
+ $this->assertEquals($this->coll->toArray(), array());
93
+ }
94
+
95
+ public function testProvidesKeys()
96
+ {
97
+ $this->assertEquals(array(), $this->coll->getKeys());
98
+ $this->coll->merge(array(
99
+ 'test1' => 'value1',
100
+ 'test2' => 'value2'
101
+ ));
102
+ $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys());
103
+ // Returns the cached array previously returned
104
+ $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys());
105
+ $this->coll->remove('test1');
106
+ $this->assertEquals(array('test2'), $this->coll->getKeys());
107
+ $this->coll->add('test3', 'value3');
108
+ $this->assertEquals(array('test2', 'test3'), $this->coll->getKeys());
109
+ }
110
+
111
+ public function testChecksIfHasKey()
112
+ {
113
+ $this->assertFalse($this->coll->hasKey('test'));
114
+ $this->coll->add('test', 'value');
115
+ $this->assertEquals(true, $this->coll->hasKey('test'));
116
+ $this->coll->add('test2', 'value2');
117
+ $this->assertEquals(true, $this->coll->hasKey('test'));
118
+ $this->assertEquals(true, $this->coll->hasKey('test2'));
119
+ $this->assertFalse($this->coll->hasKey('testing'));
120
+ $this->assertEquals(false, $this->coll->hasKey('AB-C', 'junk'));
121
+ }
122
+
123
+ public function testChecksIfHasValue()
124
+ {
125
+ $this->assertFalse($this->coll->hasValue('value'));
126
+ $this->coll->add('test', 'value');
127
+ $this->assertEquals('test', $this->coll->hasValue('value'));
128
+ $this->coll->add('test2', 'value2');
129
+ $this->assertEquals('test', $this->coll->hasValue('value'));
130
+ $this->assertEquals('test2', $this->coll->hasValue('value2'));
131
+ $this->assertFalse($this->coll->hasValue('val'));
132
+ }
133
+
134
+ public function testImplementsCount()
135
+ {
136
+ $data = new Collection();
137
+ $this->assertEquals(0, $data->count());
138
+ $data->add('key', 'value');
139
+ $this->assertEquals(1, count($data));
140
+ $data->add('key', 'value2');
141
+ $this->assertEquals(1, count($data));
142
+ $data->add('key_2', 'value3');
143
+ $this->assertEquals(2, count($data));
144
+ }
145
+
146
+ public function testAddParamsByMerging()
147
+ {
148
+ $params = array(
149
+ 'test' => 'value1',
150
+ 'test2' => 'value2',
151
+ 'test3' => array('value3', 'value4')
152
+ );
153
+
154
+ // Add some parameters
155
+ $this->coll->merge($params);
156
+
157
+ // Add more parameters by merging them in
158
+ $this->coll->merge(array(
159
+ 'test' => 'another',
160
+ 'different_key' => 'new value'
161
+ ));
162
+
163
+ $this->assertEquals(array(
164
+ 'test' => array('value1', 'another'),
165
+ 'test2' => 'value2',
166
+ 'test3' => array('value3', 'value4'),
167
+ 'different_key' => 'new value'
168
+ ), $this->coll->toArray());
169
+ }
170
+
171
+ public function testAllowsFunctionalFilter()
172
+ {
173
+ $this->coll->merge(array(
174
+ 'fruit' => 'apple',
175
+ 'number' => 'ten',
176
+ 'prepositions' => array('about', 'above', 'across', 'after'),
177
+ 'same_number' => 'ten'
178
+ ));
179
+
180
+ $filtered = $this->coll->filter(function ($key, $value) {
181
+ return $value == 'ten';
182
+ });
183
+
184
+ $this->assertNotSame($filtered, $this->coll);
185
+
186
+ $this->assertEquals(array(
187
+ 'number' => 'ten',
188
+ 'same_number' => 'ten'
189
+ ), $filtered->toArray());
190
+ }
191
+
192
+ public function testAllowsFunctionalMapping()
193
+ {
194
+ $this->coll->merge(array(
195
+ 'number_1' => 1,
196
+ 'number_2' => 2,
197
+ 'number_3' => 3
198
+ ));
199
+
200
+ $mapped = $this->coll->map(function ($key, $value) {
201
+ return $value * $value;
202
+ });
203
+
204
+ $this->assertNotSame($mapped, $this->coll);
205
+
206
+ $this->assertEquals(array(
207
+ 'number_1' => 1,
208
+ 'number_2' => 4,
209
+ 'number_3' => 9
210
+ ), $mapped->toArray());
211
+ }
212
+
213
+ public function testImplementsArrayAccess()
214
+ {
215
+ $this->coll->merge(array(
216
+ 'k1' => 'v1',
217
+ 'k2' => 'v2'
218
+ ));
219
+
220
+ $this->assertTrue($this->coll->offsetExists('k1'));
221
+ $this->assertFalse($this->coll->offsetExists('Krull'));
222
+
223
+ $this->coll->offsetSet('k3', 'v3');
224
+ $this->assertEquals('v3', $this->coll->offsetGet('k3'));
225
+ $this->assertEquals('v3', $this->coll->get('k3'));
226
+
227
+ $this->coll->offsetUnset('k1');
228
+ $this->assertFalse($this->coll->offsetExists('k1'));
229
+ }
230
+
231
+ public function testCanReplaceAllData()
232
+ {
233
+ $this->coll->replace(array('a' => '123'));
234
+ $this->assertEquals(array('a' => '123'), $this->coll->toArray());
235
+ }
236
+
237
+ public function testPreparesFromConfig()
238
+ {
239
+ $c = Collection::fromConfig(array(
240
+ 'a' => '123',
241
+ 'base_url' => 'http://www.test.com/'
242
+ ), array(
243
+ 'a' => 'xyz',
244
+ 'b' => 'lol'
245
+ ), array('a'));
246
+
247
+ $this->assertInstanceOf('GuzzleHttp\Collection', $c);
248
+ $this->assertEquals(array(
249
+ 'a' => '123',
250
+ 'b' => 'lol',
251
+ 'base_url' => 'http://www.test.com/'
252
+ ), $c->toArray());
253
+
254
+ try {
255
+ Collection::fromConfig(array(), array(), array('a'));
256
+ $this->fail('Exception not throw when missing config');
257
+ } catch (\InvalidArgumentException $e) {
258
+ }
259
+ }
260
+
261
+ function falseyDataProvider()
262
+ {
263
+ return array(
264
+ array(false, false),
265
+ array(null, null),
266
+ array('', ''),
267
+ array(array(), array()),
268
+ array(0, 0),
269
+ );
270
+ }
271
+
272
+ /**
273
+ * @dataProvider falseyDataProvider
274
+ */
275
+ public function testReturnsCorrectData($a, $b)
276
+ {
277
+ $c = new Collection(array('value' => $a));
278
+ $this->assertSame($b, $c->get('value'));
279
+ }
280
+
281
+ public function testRetrievesNestedKeysUsingPath()
282
+ {
283
+ $data = array(
284
+ 'foo' => 'bar',
285
+ 'baz' => array(
286
+ 'mesa' => array(
287
+ 'jar' => 'jar'
288
+ )
289
+ )
290
+ );
291
+ $collection = new Collection($data);
292
+ $this->assertEquals('bar', $collection->getPath('foo'));
293
+ $this->assertEquals('jar', $collection->getPath('baz/mesa/jar'));
294
+ $this->assertNull($collection->getPath('wewewf'));
295
+ $this->assertNull($collection->getPath('baz/mesa/jar/jar'));
296
+ }
297
+
298
+ public function testFalseyKeysStillDescend()
299
+ {
300
+ $collection = new Collection(array(
301
+ '0' => array(
302
+ 'a' => 'jar'
303
+ ),
304
+ 1 => 'other'
305
+ ));
306
+ $this->assertEquals('jar', $collection->getPath('0/a'));
307
+ $this->assertEquals('other', $collection->getPath('1'));
308
+ }
309
+
310
+ public function getPathProvider()
311
+ {
312
+ $data = array(
313
+ 'foo' => 'bar',
314
+ 'baz' => array(
315
+ 'mesa' => array(
316
+ 'jar' => 'jar',
317
+ 'array' => array('a', 'b', 'c')
318
+ ),
319
+ 'bar' => array(
320
+ 'baz' => 'bam',
321
+ 'array' => array('d', 'e', 'f')
322
+ )
323
+ ),
324
+ 'bam' => array(
325
+ array('foo' => 1),
326
+ array('foo' => 2),
327
+ array('array' => array('h', 'i'))
328
+ )
329
+ );
330
+ $c = new Collection($data);
331
+
332
+ return array(
333
+ // Simple path selectors
334
+ array($c, 'foo', 'bar'),
335
+ array($c, 'baz', $data['baz']),
336
+ array($c, 'bam', $data['bam']),
337
+ array($c, 'baz/mesa', $data['baz']['mesa']),
338
+ array($c, 'baz/mesa/jar', 'jar'),
339
+ // Does not barf on missing keys
340
+ array($c, 'fefwfw', null),
341
+ array($c, 'baz/mesa/array', $data['baz']['mesa']['array'])
342
+ );
343
+ }
344
+
345
+ /**
346
+ * @dataProvider getPathProvider
347
+ */
348
+ public function testGetPath(Collection $c, $path, $expected, $separator = '/')
349
+ {
350
+ $this->assertEquals($expected, $c->getPath($path, $separator));
351
+ }
352
+
353
+ public function testOverridesSettings()
354
+ {
355
+ $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
356
+ $c->overwriteWith(array('foo' => 10, 'bar' => 300));
357
+ $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray());
358
+ }
359
+
360
+ public function testOverwriteWithCollection()
361
+ {
362
+ $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
363
+ $b = new Collection(array('foo' => 10, 'bar' => 300));
364
+ $c->overwriteWith($b);
365
+ $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray());
366
+ }
367
+
368
+ public function testOverwriteWithTraversable()
369
+ {
370
+ $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
371
+ $b = new Collection(array('foo' => 10, 'bar' => 300));
372
+ $c->overwriteWith($b->getIterator());
373
+ $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray());
374
+ }
375
+
376
+ public function testCanSetNestedPathValueThatDoesNotExist()
377
+ {
378
+ $c = new Collection(array());
379
+ $c->setPath('foo/bar/baz/123', 'hi');
380
+ $this->assertEquals('hi', $c['foo']['bar']['baz']['123']);
381
+ }
382
+
383
+ public function testCanSetNestedPathValueThatExists()
384
+ {
385
+ $c = new Collection(array('foo' => array('bar' => 'test')));
386
+ $c->setPath('foo/bar', 'hi');
387
+ $this->assertEquals('hi', $c['foo']['bar']);
388
+ }
389
+
390
+ /**
391
+ * @expectedException \RuntimeException
392
+ */
393
+ public function testVerifiesNestedPathIsValidAtExactLevel()
394
+ {
395
+ $c = new Collection(array('foo' => 'bar'));
396
+ $c->setPath('foo/bar', 'hi');
397
+ $this->assertEquals('hi', $c['foo']['bar']);
398
+ }
399
+
400
+ /**
401
+ * @expectedException \RuntimeException
402
+ */
403
+ public function testVerifiesThatNestedPathIsValidAtAnyLevel()
404
+ {
405
+ $c = new Collection(array('foo' => 'bar'));
406
+ $c->setPath('foo/bar/baz', 'test');
407
+ }
408
+
409
+ public function testCanAppendToNestedPathValues()
410
+ {
411
+ $c = new Collection();
412
+ $c->setPath('foo/bar/[]', 'a');
413
+ $c->setPath('foo/bar/[]', 'b');
414
+ $this->assertEquals(['a', 'b'], $c['foo']['bar']);
415
+ }
416
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/CookieJarTest.php ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Tests\CookieJar;
4
+
5
+ use GuzzleHttp\Cookie\CookieJar;
6
+ use GuzzleHttp\Cookie\SetCookie;
7
+ use GuzzleHttp\Message\Request;
8
+ use GuzzleHttp\Message\Response;
9
+
10
+ /**
11
+ * @covers GuzzleHttp\Cookie\CookieJar
12
+ */
13
+ class CookieJarTest extends \PHPUnit_Framework_TestCase
14
+ {
15
+ /** @var CookieJar */
16
+ private $jar;
17
+
18
+ public function setUp()
19
+ {
20
+ $this->jar = new CookieJar();
21
+ }
22
+
23
+ protected function getTestCookies()
24
+ {
25
+ return [
26
+ new SetCookie(['Name' => 'foo', 'Value' => 'bar', 'Domain' => 'foo.com', 'Path' => '/', 'Discard' => true]),
27
+ new SetCookie(['Name' => 'test', 'Value' => '123', 'Domain' => 'baz.com', 'Path' => '/foo', 'Expires' => 2]),
28
+ new SetCookie(['Name' => 'you', 'Value' => '123', 'Domain' => 'bar.com', 'Path' => '/boo', 'Expires' => time() + 1000])
29
+ ];
30
+ }
31
+
32
+ public function testQuotesBadCookieValues()
33
+ {
34
+ $this->assertEquals('foo', CookieJar::getCookieValue('foo'));
35
+ $this->assertEquals('"foo,bar"', CookieJar::getCookieValue('foo,bar'));
36
+ }
37
+
38
+ public function testCreatesFromArray()
39
+ {
40
+ $jar = CookieJar::fromArray([
41
+ 'foo' => 'bar',
42
+ 'baz' => 'bam'
43
+ ], 'example.com');
44
+ $this->assertCount(2, $jar);
45
+ }
46
+
47
+ /**
48
+ * Provides test data for cookie cookieJar retrieval
49
+ */
50
+ public function getCookiesDataProvider()
51
+ {
52
+ return [
53
+ [['foo', 'baz', 'test', 'muppet', 'googoo'], '', '', '', false],
54
+ [['foo', 'baz', 'muppet', 'googoo'], '', '', '', true],
55
+ [['googoo'], 'www.example.com', '', '', false],
56
+ [['muppet', 'googoo'], 'test.y.example.com', '', '', false],
57
+ [['foo', 'baz'], 'example.com', '', '', false],
58
+ [['muppet'], 'x.y.example.com', '/acme/', '', false],
59
+ [['muppet'], 'x.y.example.com', '/acme/test/', '', false],
60
+ [['googoo'], 'x.y.example.com', '/test/acme/test/', '', false],
61
+ [['foo', 'baz'], 'example.com', '', '', false],
62
+ [['baz'], 'example.com', '', 'baz', false],
63
+ ];
64
+ }
65
+
66
+ public function testStoresAndRetrievesCookies()
67
+ {
68
+ $cookies = $this->getTestCookies();
69
+ foreach ($cookies as $cookie) {
70
+ $this->assertTrue($this->jar->setCookie($cookie));
71
+ }
72
+
73
+ $this->assertEquals(3, count($this->jar));
74
+ $this->assertEquals(3, count($this->jar->getIterator()));
75
+ $this->assertEquals($cookies, $this->jar->getIterator()->getArrayCopy());
76
+ }
77
+
78
+ public function testRemovesTemporaryCookies()
79
+ {
80
+ $cookies = $this->getTestCookies();
81
+ foreach ($this->getTestCookies() as $cookie) {
82
+ $this->jar->setCookie($cookie);
83
+ }
84
+ $this->jar->clearSessionCookies();
85
+ $this->assertEquals(
86
+ [$cookies[1], $cookies[2]],
87
+ $this->jar->getIterator()->getArrayCopy()
88
+ );
89
+ }
90
+
91
+ public function testRemovesSelectively()
92
+ {
93
+ foreach ($this->getTestCookies() as $cookie) {
94
+ $this->jar->setCookie($cookie);
95
+ }
96
+
97
+ // Remove foo.com cookies
98
+ $this->jar->clear('foo.com');
99
+ $this->assertEquals(2, count($this->jar));
100
+ // Try again, removing no further cookies
101
+ $this->jar->clear('foo.com');
102
+ $this->assertEquals(2, count($this->jar));
103
+
104
+ // Remove bar.com cookies with path of /boo
105
+ $this->jar->clear('bar.com', '/boo');
106
+ $this->assertEquals(1, count($this->jar));
107
+
108
+ // Remove cookie by name
109
+ $this->jar->clear(null, null, 'test');
110
+ $this->assertEquals(0, count($this->jar));
111
+ }
112
+
113
+ public function testDoesNotAddIncompleteCookies()
114
+ {
115
+ $this->assertEquals(false, $this->jar->setCookie(new SetCookie()));
116
+ $this->assertFalse($this->jar->setCookie(new SetCookie(array(
117
+ 'Name' => 'foo'
118
+ ))));
119
+ $this->assertFalse($this->jar->setCookie(new SetCookie(array(
120
+ 'Name' => false
121
+ ))));
122
+ $this->assertFalse($this->jar->setCookie(new SetCookie(array(
123
+ 'Name' => true
124
+ ))));
125
+ $this->assertFalse($this->jar->setCookie(new SetCookie(array(
126
+ 'Name' => 'foo',
127
+ 'Domain' => 'foo.com'
128
+ ))));
129
+ }
130
+
131
+ public function testDoesAddValidCookies()
132
+ {
133
+ $this->assertTrue($this->jar->setCookie(new SetCookie(array(
134
+ 'Name' => 'foo',
135
+ 'Domain' => 'foo.com',
136
+ 'Value' => 0
137
+ ))));
138
+ $this->assertTrue($this->jar->setCookie(new SetCookie(array(
139
+ 'Name' => 'foo',
140
+ 'Domain' => 'foo.com',
141
+ 'Value' => 0.0
142
+ ))));
143
+ $this->assertTrue($this->jar->setCookie(new SetCookie(array(
144
+ 'Name' => 'foo',
145
+ 'Domain' => 'foo.com',
146
+ 'Value' => '0'
147
+ ))));
148
+ }
149
+
150
+ public function testOverwritesCookiesThatAreOlderOrDiscardable()
151
+ {
152
+ $t = time() + 1000;
153
+ $data = array(
154
+ 'Name' => 'foo',
155
+ 'Value' => 'bar',
156
+ 'Domain' => '.example.com',
157
+ 'Path' => '/',
158
+ 'Max-Age' => '86400',
159
+ 'Secure' => true,
160
+ 'Discard' => true,
161
+ 'Expires' => $t
162
+ );
163
+
164
+ // Make sure that the discard cookie is overridden with the non-discard
165
+ $this->assertTrue($this->jar->setCookie(new SetCookie($data)));
166
+ $this->assertEquals(1, count($this->jar));
167
+
168
+ $data['Discard'] = false;
169
+ $this->assertTrue($this->jar->setCookie(new SetCookie($data)));
170
+ $this->assertEquals(1, count($this->jar));
171
+
172
+ $c = $this->jar->getIterator()->getArrayCopy();
173
+ $this->assertEquals(false, $c[0]->getDiscard());
174
+
175
+ // Make sure it doesn't duplicate the cookie
176
+ $this->jar->setCookie(new SetCookie($data));
177
+ $this->assertEquals(1, count($this->jar));
178
+
179
+ // Make sure the more future-ful expiration date supersede the other
180
+ $data['Expires'] = time() + 2000;
181
+ $this->assertTrue($this->jar->setCookie(new SetCookie($data)));
182
+ $this->assertEquals(1, count($this->jar));
183
+ $c = $this->jar->getIterator()->getArrayCopy();
184
+ $this->assertNotEquals($t, $c[0]->getExpires());
185
+ }
186
+
187
+ public function testOverwritesCookiesThatHaveChanged()
188
+ {
189
+ $t = time() + 1000;
190
+ $data = array(
191
+ 'Name' => 'foo',
192
+ 'Value' => 'bar',
193
+ 'Domain' => '.example.com',
194
+ 'Path' => '/',
195
+ 'Max-Age' => '86400',
196
+ 'Secure' => true,
197
+ 'Discard' => true,
198
+ 'Expires' => $t
199
+ );
200
+
201
+ // Make sure that the discard cookie is overridden with the non-discard
202
+ $this->assertTrue($this->jar->setCookie(new SetCookie($data)));
203
+
204
+ $data['Value'] = 'boo';
205
+ $this->assertTrue($this->jar->setCookie(new SetCookie($data)));
206
+ $this->assertEquals(1, count($this->jar));
207
+
208
+ // Changing the value plus a parameter also must overwrite the existing one
209
+ $data['Value'] = 'zoo';
210
+ $data['Secure'] = false;
211
+ $this->assertTrue($this->jar->setCookie(new SetCookie($data)));
212
+ $this->assertEquals(1, count($this->jar));
213
+
214
+ $c = $this->jar->getIterator()->getArrayCopy();
215
+ $this->assertEquals('zoo', $c[0]->getValue());
216
+ }
217
+
218
+ public function testAddsCookiesFromResponseWithRequest()
219
+ {
220
+ $response = new Response(200, array(
221
+ 'Set-Cookie' => "fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT;"
222
+ ));
223
+ $request = new Request('GET', 'http://www.example.com');
224
+ $this->jar->extractCookies($request, $response);
225
+ $this->assertEquals(1, count($this->jar));
226
+ }
227
+
228
+ public function getMatchingCookiesDataProvider()
229
+ {
230
+ return array(
231
+ array('https://example.com', 'foo=bar; baz=foobar'),
232
+ array('http://example.com', ''),
233
+ array('https://example.com:8912', 'foo=bar; baz=foobar'),
234
+ array('https://foo.example.com', 'foo=bar; baz=foobar'),
235
+ array('http://foo.example.com/test/acme/', 'googoo=gaga')
236
+ );
237
+ }
238
+
239
+ /**
240
+ * @dataProvider getMatchingCookiesDataProvider
241
+ */
242
+ public function testReturnsCookiesMatchingRequests($url, $cookies)
243
+ {
244
+ $bag = [
245
+ new SetCookie([
246
+ 'Name' => 'foo',
247
+ 'Value' => 'bar',
248
+ 'Domain' => 'example.com',
249
+ 'Path' => '/',
250
+ 'Max-Age' => '86400',
251
+ 'Secure' => true
252
+ ]),
253
+ new SetCookie([
254
+ 'Name' => 'baz',
255
+ 'Value' => 'foobar',
256
+ 'Domain' => 'example.com',
257
+ 'Path' => '/',
258
+ 'Max-Age' => '86400',
259
+ 'Secure' => true
260
+ ]),
261
+ new SetCookie([
262
+ 'Name' => 'test',
263
+ 'Value' => '123',
264
+ 'Domain' => 'www.foobar.com',
265
+ 'Path' => '/path/',
266
+ 'Discard' => true
267
+ ]),
268
+ new SetCookie([
269
+ 'Name' => 'muppet',
270
+ 'Value' => 'cookie_monster',
271
+ 'Domain' => '.y.example.com',
272
+ 'Path' => '/acme/',
273
+ 'Expires' => time() + 86400
274
+ ]),
275
+ new SetCookie([
276
+ 'Name' => 'googoo',
277
+ 'Value' => 'gaga',
278
+ 'Domain' => '.example.com',
279
+ 'Path' => '/test/acme/',
280
+ 'Max-Age' => 1500
281
+ ])
282
+ ];
283
+
284
+ foreach ($bag as $cookie) {
285
+ $this->jar->setCookie($cookie);
286
+ }
287
+
288
+ $request = new Request('GET', $url);
289
+ $this->jar->addCookieHeader($request);
290
+ $this->assertEquals($cookies, $request->getHeader('Cookie'));
291
+ }
292
+
293
+ /**
294
+ * @expectedException \RuntimeException
295
+ * @expectedExceptionMessage Invalid cookie: Cookie name must not cannot invalid characters:
296
+ */
297
+ public function testThrowsExceptionWithStrictMode()
298
+ {
299
+ $a = new CookieJar(true);
300
+ $a->setCookie(new SetCookie(['Name' => "abc\n", 'Value' => 'foo', 'Domain' => 'bar']));
301
+ }
302
+
303
+ public function testDeletesCookiesByName()
304
+ {
305
+ $cookies = $this->getTestCookies();
306
+ $cookies[] = new SetCookie([
307
+ 'Name' => 'other',
308
+ 'Value' => '123',
309
+ 'Domain' => 'bar.com',
310
+ 'Path' => '/boo',
311
+ 'Expires' => time() + 1000
312
+ ]);
313
+ $jar = new CookieJar();
314
+ foreach ($cookies as $cookie) {
315
+ $jar->setCookie($cookie);
316
+ }
317
+ $this->assertCount(4, $jar);
318
+ $jar->clear('bar.com', '/boo', 'other');
319
+ $this->assertCount(3, $jar);
320
+ $names = array_map(function (SetCookie $c) {
321
+ return $c->getName();
322
+ }, $jar->getIterator()->getArrayCopy());
323
+ $this->assertEquals(['foo', 'test', 'you'], $names);
324
+ }
325
+
326
+ public function testCanConvertToAndLoadFromArray()
327
+ {
328
+ $jar = new CookieJar(true);
329
+ foreach ($this->getTestCookies() as $cookie) {
330
+ $jar->setCookie($cookie);
331
+ }
332
+ $this->assertCount(3, $jar);
333
+ $arr = $jar->toArray();
334
+ $this->assertCount(3, $arr);
335
+ $newCookieJar = new CookieJar(false, $arr);
336
+ $this->assertCount(3, $newCookieJar);
337
+ $this->assertSame($jar->toArray(), $newCookieJar->toArray());
338
+ }
339
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/FileCookieJarTest.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace GuzzleHttp\Tests\CookieJar;
3
+
4
+ use GuzzleHttp\Cookie\FileCookieJar;
5
+ use GuzzleHttp\Cookie\SetCookie;
6
+
7
+ /**
8
+ * @covers GuzzleHttp\Cookie\FileCookieJar
9
+ */
10
+ class FileCookieJarTest extends \PHPUnit_Framework_TestCase
11
+ {
12
+ private $file;
13
+
14
+ public function setUp()
15
+ {
16
+ $this->file = tempnam('/tmp', 'file-cookies');
17
+ }
18
+
19
+ /**
20
+ * @expectedException \RuntimeException
21
+ */
22
+ public function testValidatesCookieFile()
23
+ {
24
+ file_put_contents($this->file, 'true');
25
+ new FileCookieJar($this->file);
26
+ }
27
+
28
+ public function testLoadsFromFileFile()
29
+ {
30
+ $jar = new FileCookieJar($this->file);
31
+ $this->assertEquals([], $jar->getIterator()->getArrayCopy());
32
+ unlink($this->file);
33
+ }
34
+
35
+ public function testPersistsToFileFile()
36
+ {
37
+ $jar = new FileCookieJar($this->file);
38
+ $jar->setCookie(new SetCookie([
39
+ 'Name' => 'foo',
40
+ 'Value' => 'bar',
41
+ 'Domain' => 'foo.com',
42
+ 'Expires' => time() + 1000
43
+ ]));
44
+ $jar->setCookie(new SetCookie([
45
+ 'Name' => 'baz',
46
+ 'Value' => 'bar',
47
+ 'Domain' => 'foo.com',
48
+ 'Expires' => time() + 1000
49
+ ]));
50
+ $jar->setCookie(new SetCookie([
51
+ 'Name' => 'boo',
52
+ 'Value' => 'bar',
53
+ 'Domain' => 'foo.com',
54
+ ]));
55
+
56
+ $this->assertEquals(3, count($jar));
57
+ unset($jar);
58
+
59
+ // Make sure it wrote to the file
60
+ $contents = file_get_contents($this->file);
61
+ $this->assertNotEmpty($contents);
62
+
63
+ // Load the cookieJar from the file
64
+ $jar = new FileCookieJar($this->file);
65
+
66
+ // Weeds out temporary and session cookies
67
+ $this->assertEquals(2, count($jar));
68
+ unset($jar);
69
+ unlink($this->file);
70
+ }
71
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/SessionCookieJarTest.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Tests\CookieJar;
4
+
5
+ use GuzzleHttp\Cookie\SessionCookieJar;
6
+ use GuzzleHttp\Cookie\SetCookie;
7
+
8
+ /**
9
+ * @covers GuzzleHttp\Cookie\SessionCookieJar
10
+ */
11
+ class SessionCookieJarTest extends \PHPUnit_Framework_TestCase
12
+ {
13
+ private $sessionVar;
14
+
15
+ public function setUp()
16
+ {
17
+ $this->sessionVar = 'sessionKey';
18
+
19
+ if (!isset($_SESSION)) {
20
+ $_SESSION = array();
21
+ }
22
+ }
23
+
24
+ /**
25
+ * @expectedException \RuntimeException
26
+ */
27
+ public function testValidatesCookieSession()
28
+ {
29
+ $_SESSION[$this->sessionVar] = 'true';
30
+ new SessionCookieJar($this->sessionVar);
31
+ }
32
+
33
+ public function testLoadsFromSession()
34
+ {
35
+ $jar = new SessionCookieJar($this->sessionVar);
36
+ $this->assertEquals([], $jar->getIterator()->getArrayCopy());
37
+ unset($_SESSION[$this->sessionVar]);
38
+ }
39
+
40
+ public function testPersistsToSession()
41
+ {
42
+ $jar = new SessionCookieJar($this->sessionVar);
43
+ $jar->setCookie(new SetCookie([
44
+ 'Name' => 'foo',
45
+ 'Value' => 'bar',
46
+ 'Domain' => 'foo.com',
47
+ 'Expires' => time() + 1000
48
+ ]));
49
+ $jar->setCookie(new SetCookie([
50
+ 'Name' => 'baz',
51
+ 'Value' => 'bar',
52
+ 'Domain' => 'foo.com',
53
+ 'Expires' => time() + 1000
54
+ ]));
55
+ $jar->setCookie(new SetCookie([
56
+ 'Name' => 'boo',
57
+ 'Value' => 'bar',
58
+ 'Domain' => 'foo.com',
59
+ ]));
60
+
61
+ $this->assertEquals(3, count($jar));
62
+ unset($jar);
63
+
64
+ // Make sure it wrote to the sessionVar in $_SESSION
65
+ $contents = $_SESSION[$this->sessionVar];
66
+ $this->assertNotEmpty($contents);
67
+
68
+ // Load the cookieJar from the file
69
+ $jar = new SessionCookieJar($this->sessionVar);
70
+
71
+ // Weeds out temporary and session cookies
72
+ $this->assertEquals(2, count($jar));
73
+ unset($jar);
74
+ unset($_SESSION[$this->sessionVar]);
75
+ }
76
+ }
lib/KlarnaCheckout/guzzlehttp/guzzle/tests/Cookie/SetCookieTest.php ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace GuzzleHttp\Tests\CookieJar;
4
+
5
+ use GuzzleHttp\Cookie\SetCookie;
6
+
7
+ /**
8
+ * @covers GuzzleHttp\Cookie\SetCookie
9
+ */
10
+ class SetCookieTest extends \PHPUnit_Framework_TestCase
11
+ {
12
+ public function testInitializesDefaultValues()
13
+ {
14
+ $cookie = new SetCookie();
15
+ $this->assertEquals('/', $cookie->getPath());
16
+ }
17
+
18
+ public function testConvertsDateTimeMaxAgeToUnixTimestamp()
19
+ {
20
+ $cookie = new SetCookie(['Expires' => 'November 20, 1984']);
21
+ $this->assertInternalType('integer', $cookie->getExpires());
22
+ }
23
+
24
+ public function testAddsExpiresBasedOnMaxAge()
25
+ {
26
+ $t = time();
27
+ $cookie = new SetCookie(['Max-Age' => 100]);
28
+ $this->assertEquals($t + 100, $cookie->getExpires());
29
+ }
30
+
31
+ public function testHoldsValues()
32
+ {
33
+ $t = time();
34
+ $data = array(
35
+ 'Name' => 'foo',
36
+ 'Value' => 'baz',
37
+ 'Path' => '/bar',
38
+ 'Domain' => 'baz.com',
39
+ 'Expires' => $t,
40
+ 'Max-Age' => 100,
41
+ 'Secure' => true,
42
+ 'Discard' => true,
43
+ 'HttpOnly' => true,
44
+ 'foo' => 'baz',
45
+ 'bar' => 'bam'
46
+ );
47
+
48
+ $cookie = new SetCookie($data);
49
+ $this->assertEquals($data, $cookie->toArray());
50
+
51
+ $this->assertEquals('foo', $cookie->getName());
52
+ $this->assertEquals('baz', $cookie->getValue());
53
+ $this->assertEquals('baz.com', $cookie->getDomain());
54
+ $this->assertEquals('/bar', $cookie->getPath());
55
+ $this->assertEquals($t, $cookie->getExpires());
56
+ $this->assertEquals(100, $cookie->getMaxAge());
57
+ $this->assertTrue($cookie->getSecure());
58
+ $this->assertTrue($cookie->getDiscard());
59
+ $this->assertTrue($cookie->getHttpOnly());
60
+ $this->assertEquals('baz', $cookie->toArray()['foo']);
61
+ $this->assertEquals('bam', $cookie->toArray()['bar']);
62
+
63
+ $cookie->setName('a');
64
+ $cookie->setValue('b');
65
+ $cookie->setPath('c');
66
+ $cookie->setDomain('bar.com');
67
+ $cookie->setExpires(10);
68
+ $cookie->setMaxAge(200);
69
+ $cookie->setSecure(false);
70
+ $cookie->setHttpOnly(false);
71
+ $cookie->setDiscard(false);
72
+
73
+ $this->assertEquals('a', $cookie->getName());
74
+ $this->assertEquals('b', $cookie->getValue());
75
+ $this->assertEquals('c', $cookie->getPath());
76
+ $this->assertEquals('bar.com', $cookie->getDomain());
77
+ $this->assertEquals(10, $cookie->getExpires());
78
+ $this->assertEquals(200, $cookie->getMaxAge());
79
+ $this->assertFalse($cookie->getSecure());
80
+ $this->assertFalse($cookie->getDiscard());
81
+ $this->assertFalse($cookie->getHttpOnly());
82
+ }
83
+
84
+ public function testDeterminesIfExpired()
85
+ {
86
+ $c = new SetCookie();
87
+ $c->setExpires(10);
88
+ $this->assertTrue($c->isExpired());
89
+ $c->setExpires(time() + 10000);
90
+ $this->assertFalse($c->isExpired());
91
+ }
92
+
93
+ public function testMatchesDomain()
94
+ {
95
+ $cookie = new SetCookie();
96
+ $this->assertTrue($cookie->matchesDomain('baz.com'));
97
+
98
+ $cookie->setDomain('baz.com');
99
+ $this->assertTrue($cookie->matchesDomain('baz.com'));
100
+ $this->assertFalse($cookie->matchesDomain('bar.com'));
101
+
102
+ $cookie->setDomain('.baz.com');
103
+ $this->assertTrue($cookie->matchesDomain('.baz.com'));
104
+ $this->assertTrue($cookie->matchesDomain('foo.baz.com'));
105
+ $this->assertFalse($cookie->matchesDomain('baz.bar.com'));
106
+ $this->assertTrue($cookie->matchesDomain('baz.com'));
107
+
108
+ $cookie->setDomain('.127.0.0.1');
109
+ $this->assertTrue($cookie->matchesDomain('127.0.0.1'));
110
+
111
+ $cookie->setDomain('127.0.0.1');
112
+ $this->assertTrue($cookie->matchesDomain('127.0.0.1'));
113
+
114
+ $cookie->setDomain('.com.');
115
+ $this->assertFalse($cookie->matchesDomain('baz.com'));
116
+
117
+ $cookie->setDomain('.local');
118
+ $this->assertTrue($cookie->matchesDomain('example.local'));
119
+ }
120
+
121
+ public function testMatchesPath()
122
+ {
123
+ $cookie = new SetCookie();
124
+ $this->assertTrue($cookie->matchesPath('/foo'));
125
+
126
+ $cookie->setPath('/foo');
127
+ $this->assertTrue($cookie->matchesPath('/foo'));
128
+ $this->assertTrue($cookie->matchesPath('/foo/bar'));
129
+ $this->assertFalse($cookie->matchesPath('/bar'));
130
+ }
131
+
132
+ public function cookieValidateProvider()
133
+ {
134
+ return array(
135
+ array('foo', 'baz', 'bar', true),
136
+ array('0', '0', '0', true),
137
+ array('', 'baz', 'bar', 'The cookie name must not be empty'),
138
+ array('foo', '', 'bar', 'The cookie value must not be empty'),
139
+ array('foo', 'baz', '', 'The cookie domain must not be empty'),
140
+ array("foo\r", 'baz', '0', 'Cookie name must not cannot invalid characters: =,; \t\r\n\013\014'),
141
+ );
142
+ }
143
+
144
+ /**
145
+ * @dataProvider cookieValidateProvider
146
+ */
147
+ public function testValidatesCookies($name, $value, $domain, $result)
148
+ {
149
+ $cookie = new SetCookie(array(
150
+ 'Name' => $name,
151
+ 'Value' => $value,
152
+ 'Domain' => $domain
153
+ ));
154
+ $this->assertSame($result, $cookie->validate());
155
+ }
156
+
157
+ public function testDoesNotMatchIp()
158
+ {
159
+ $cookie = new SetCookie(['Domain' => '192.168.16.']);
160
+ $this->assertFalse($cookie->matchesDomain('192.168.16.121'));
161
+ }
162
+
163
+ public function testConvertsToString()
164
+ {
165
+ $t = 1382916008;
166
+ $cookie = new SetCookie([
167
+ 'Name' => 'test',
168
+ 'Value' => '123',
169
+ 'Domain' => 'foo.com',
170
+ 'Expires' => $t,
171
+ 'Path' => '/abc',
172
+ 'HttpOnly' => true,
173
+ 'Secure' => true
174
+ ]);
175
+ $this->assertEquals(
176
+ 'test=123; Domain=foo.com; Path=/abc; Expires=Sun, 27 Oct 2013 23:20:08 GMT; Secure; HttpOnly',
177
+ (string) $cookie
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Provides the parsed information from a cookie
183
+ *
184
+ * @return array
185
+ */
186
+ public function cookieParserDataProvider()
187
+ {
188
+ return array(
189
+ array(
190
+ 'ASIHTTPRequestTestCookie=This+is+the+value; expires=Sat, 26-Jul-2008 17:00:42 GMT; path=/tests; domain=allseeing-i.com; PHPSESSID=6c951590e7a9359bcedde25cda73e43c; path=/";',
191
+ array(
192
+ 'Domain' => 'allseeing-i.com',
193
+ 'Path' => '/',
194
+ 'PHPSESSID' => '6c951590e7a9359bcedde25cda73e43c',
195
+ 'Max-Age' => NULL,
196
+ 'Expires' => 'Sat, 26-Jul-2008 17:00:42 GMT',
197
+ 'Secure' => NULL,
198
+ 'Discard' => NULL,
199
+ 'Name' => 'ASIHTTPRequestTestCookie',
200
+ 'Value' => 'This+is+the+value',
201
+ 'HttpOnly' => false
202
+ )
203
+ ),
204
+ array('', []),
205
+ array('foo', []),
206
+ // Test setting a blank value for a cookie
207
+ array(array(
208
+ 'foo=', 'foo =', 'foo =;', 'foo= ;', 'foo =', 'foo= '),
209
+ array(
210
+ 'Name' => 'foo',
211
+ 'Value' => '',
212
+ 'Discard' => null,
213
+ 'Domain' => null,
214
+ 'Expires' => null,
215
+ 'Max-Age' => null,
216
+ 'Path' => '/',
217
+ 'Secure' => null,
218
+ 'HttpOnly' => false
219
+ )
220
+ ),
221
+ // Test setting a value and removing quotes
222
+ array(array(
223
+ 'foo=1', 'foo =1', 'foo =1;', 'foo=1 ;', 'foo =1', 'foo= 1', 'foo = 1 ;', 'foo="1"', 'foo="1";', 'foo= "1";'),
224
+ array(
225
+ 'Name' => 'foo',
226
+ 'Value' => '1',
227
+ 'Discard' => null,
228
+ 'Domain' => null,
229
+ 'Expires' => null,
230
+ 'Max-Age' => null,
231
+ 'Path' => '/',
232
+ 'Secure' => null,
233
+ 'HttpOnly' => false
234
+ )
235
+ ),
236
+ // Some of the following tests are based on http://framework.zend.com/svn/framework/standard/trunk/tests/Zend/Http/CookieTest.php
237
+ array(
238
+ 'justacookie=foo; domain=example.com',
239
+ array(
240
+ 'Name' => 'justacookie',
241
+ 'Value' => 'foo',
242
+ 'Domain' => 'example.com',
243
+ 'Discard' => null,
244
+ 'Expires' => null,
245
+ 'Max-Age' => null,
246
+ 'Path' => '/',
247
+ 'Secure' => null,
248
+ 'HttpOnly' => false
249
+ )
250
+ ),
251
+ array(
252
+ 'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
253
+ array(
254
+ 'Name' => 'expires',
255
+ 'Value' => 'tomorrow',
256
+ 'Domain' => '.example.com',
257
+ 'Path' => '/Space Out/',
258
+ 'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
259
+ 'Discard' => null,
260
+ 'Secure' => true,
261
+ 'Max-Age' => null,
262
+ 'HttpOnly' => false
263
+ )
264
+ ),
265
+ array(
266
+ 'domain=unittests; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=example.com; path=/some value/',
267
+ array(
268
+ 'Name' => 'domain',
269
+ 'Value' => 'unittests',
270
+ 'Domain' => 'example.com',
271
+ 'Path' => '/some value/',
272
+ 'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
273
+ 'Secure' => false,
274
+ 'Discard' => null,
275
+ 'Max-Age' => null,
276
+ 'HttpOnly' => false
277
+ )
278
+ ),
279
+ array(
280
+ 'path=indexAction; path=/; domain=.foo.com; expires=Tue, 21-Nov-2006 08:33:44 GMT',
281
+ array(
282
+ 'Name' => 'path',
283
+ 'Value' => 'indexAction',
284
+ 'Domain' => '.foo.com',
285
+ 'Path' => '/',
286
+ 'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
287
+ 'Secure' => false,
288
+ 'Discard' => null,
289
+ 'Max-Age' => null,
290
+ 'HttpOnly' => false
291
+ )
292
+ ),
293
+ array(
294
+ 'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com; version=1; Max-Age=86400',
295
+ array(
296
+ 'Name' => 'secure',
297
+ 'Value' => 'sha1',
298
+ 'Domain' => 'some.really.deep.domain.com',
299
+ 'Path' => '/',
300
+ 'Secure' => true,
301
+ 'Discard' => null,
302
+ 'Expires' => time() + 86400,
303
+ 'Max-Age' => 86400,
304
+ 'HttpOnly'