From 94beefbff5c7511d2a60496a814811c0b4b692ea Mon Sep 17 00:00:00 2001 From: lyubomir-sumup <39481092+lyubomir-sumup@users.noreply.github.com> Date: Mon, 14 Jan 2019 15:06:58 +0200 Subject: [PATCH] Initial implementation (#1) * Implement basic authentication * Move the authentication to a service * Improve authentication and error handling * Implement the Checkouts Service * Add comments for the checkouts service * Implement the Customers Service * Refactor authorization to be a service * Improve Customers' methods and refactor all paths for readability * Implement the Transactions Service * Improve Checkouts Service with pay method * Remove method for creating payment instruments * Implement the Merchant Service * Add exceptions in the code * Add configuration for default access token and fix imports * Add basic tests for the application configuration class * Add configuration for tests coverage * Add tests for exceptions * Add tests for response * Add tests for access token * Remove dead code * Add license of the project * Remove tests and udpate metadata * Remove tests * Add payouts service and fix metadata * Refactor exception messages * Refactor services to send headers * Add support for using cURL or GuzzleHttp as HTTP client * Improve error handling for cURL requests * Send custom headers and fix annotations * Improve code stability * Add basic documentation for usage * Change version * Fix minor spelling mistakes * Fix spelling Co-Authored-By: lyubomir-sumup <39481092+lyubomir-sumup@users.noreply.github.com> * Fix spelling Co-Authored-By: lyubomir-sumup <39481092+lyubomir-sumup@users.noreply.github.com> * Insert a space after all if statements * Refactor code with improvements and optimizations after the code review * Refactor code for customer service to be more maintainable * Improve documentations abouth authorizations * Improve documentation about exceptions handling * Remove composer.lock * Improve documentation about some services * Improve configuration interface and update documentation --- .gitignore | 6 +- LICENSE | 24 ++ README.md | 222 ++++++++++- composer.json | 26 ++ .../Application/ApplicationConfiguration.php | 355 ++++++++++++++++++ .../ApplicationConfigurationInterface.php | 95 +++++ src/SumUp/Authentication/AccessToken.php | 124 ++++++ .../Exceptions/SumUpArgumentException.php | 12 + .../SumUpAuthenticationException.php | 12 + .../SumUpConfigurationException.php | 12 + .../Exceptions/SumUpConnectionException.php | 12 + .../Exceptions/SumUpResponseException.php | 12 + src/SumUp/Exceptions/SumUpSDKException.php | 12 + src/SumUp/Exceptions/SumUpServerException.php | 12 + .../Exceptions/SumUpValidationException.php | 43 +++ src/SumUp/HttpClients/HttpClientsFactory.php | 59 +++ src/SumUp/HttpClients/Response.php | 106 ++++++ src/SumUp/HttpClients/SumUpCUrlClient.php | 117 ++++++ .../HttpClients/SumUpGuzzleHttpClient.php | 112 ++++++ .../HttpClients/SumUpHttpClientInterface.php | 21 ++ src/SumUp/Services/Authorization.php | 217 +++++++++++ src/SumUp/Services/Checkouts.php | 204 ++++++++++ src/SumUp/Services/Customers.php | 219 +++++++++++ src/SumUp/Services/Merchant.php | 123 ++++++ src/SumUp/Services/Payouts.php | 137 +++++++ src/SumUp/Services/SumUpService.php | 12 + src/SumUp/Services/Transactions.php | 210 +++++++++++ src/SumUp/SumUp.php | 193 ++++++++++ src/SumUp/Utils/Exceptions.php | 23 ++ src/SumUp/Utils/Headers.php | 91 +++++ 30 files changed, 2817 insertions(+), 6 deletions(-) create mode 100644 LICENSE create mode 100644 composer.json create mode 100644 src/SumUp/Application/ApplicationConfiguration.php create mode 100644 src/SumUp/Application/ApplicationConfigurationInterface.php create mode 100644 src/SumUp/Authentication/AccessToken.php create mode 100644 src/SumUp/Exceptions/SumUpArgumentException.php create mode 100644 src/SumUp/Exceptions/SumUpAuthenticationException.php create mode 100644 src/SumUp/Exceptions/SumUpConfigurationException.php create mode 100644 src/SumUp/Exceptions/SumUpConnectionException.php create mode 100644 src/SumUp/Exceptions/SumUpResponseException.php create mode 100644 src/SumUp/Exceptions/SumUpSDKException.php create mode 100644 src/SumUp/Exceptions/SumUpServerException.php create mode 100644 src/SumUp/Exceptions/SumUpValidationException.php create mode 100644 src/SumUp/HttpClients/HttpClientsFactory.php create mode 100644 src/SumUp/HttpClients/Response.php create mode 100644 src/SumUp/HttpClients/SumUpCUrlClient.php create mode 100644 src/SumUp/HttpClients/SumUpGuzzleHttpClient.php create mode 100644 src/SumUp/HttpClients/SumUpHttpClientInterface.php create mode 100644 src/SumUp/Services/Authorization.php create mode 100644 src/SumUp/Services/Checkouts.php create mode 100644 src/SumUp/Services/Customers.php create mode 100644 src/SumUp/Services/Merchant.php create mode 100644 src/SumUp/Services/Payouts.php create mode 100644 src/SumUp/Services/SumUpService.php create mode 100644 src/SumUp/Services/Transactions.php create mode 100644 src/SumUp/SumUp.php create mode 100644 src/SumUp/Utils/Exceptions.php create mode 100644 src/SumUp/Utils/Headers.php diff --git a/.gitignore b/.gitignore index a67d42b..91cc747 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ composer.phar +composer.lock /vendor/ - -# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control -# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file -# composer.lock +**/coverage diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..27e8bac --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +SumUp SDK License + +SumUp Payments Limited, UK company number 07836562, (“SumUp”), is providing or making available the software code (the “Software”) and all other documents, specifications and other items (the “Documentation”) for use under the terms of this software development kit license agreement (the “Agreement”). By downloading or otherwise gaining access to the Software and Documentation you agree to be bound by this Agreement. SumUp may at any time subject to SumUp’s notice to you in writing or by e-mail renew, modify or amend this Agreement from time to time. SumUp will then make such new version of this Agreement available to you via email or by other means of communication. If you continue to use the Software and Documentation, you are deemed to have accepted such renewal, modification or amendment. If you agree to this Agreement on behalf of your employer or another legal entity, you warrant that you have the right to enter into this Agreement on behalf of such other party. + +1. License grant, etc. +Subject to the terms of this Agreement, SumUp hereby grants to you a non-exclusive, non-transferable, non sub-licensable, worldwide, royalty free license to use the Software and Documentation to develop your software applications, in which the Software and Documentation will be incorporated and which will provide access to SumUp's services. SumUp may without prior notice to you change the form and nature of the Software and Documentation that SumUp provides which may lead to that future versions of the Software and Documentation may be incompatible with software applications developed on previous versions of the Software and Documentation. Furthermore, SumUp may stop (permanently or temporarily) providing the Software and Documentation (or any features within the Software and Documentation) to you or to users generally, at SumUp's sole discretion without prior notice to you. SumUp may make updates of the Software and Documentation at any time, but shall have no obligation what so ever to provide any updates of the Software and Documentation to you. Except to the extent expressly permitted by any applicable third party license, you may not copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the Software or Documentation or any part of the Software or Documentation or any services provided by the Software or Documentation. You may not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the Software or Documentation. You must comply with all third party licenses in order to use the third party software contained in the Software. No title to the intellectual property in the Software or Documentation is transferred to you under the terms of this Agreement. You do not acquire any rights to the Software or Documentation except as expressly set forth in this Agreement. You agree to use the Software and Documentation for development of your software applications only and for purposes that are permitted by (a) this Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software (including encryption software) to and from the European Union, the United States or other relevant countries). You agree that you will not engage in any activity with the Software or Documentation, including the development or distribution of applications that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of SumUp or any third party. All ownership and intellectual property rights in the Software and Documentation and any copies and derivative works thereof (regardless of form or media in or on which the original or other copies may exist), including but not limited to patents, design rights, copyrights, trade marks, trade-secrets and proprietary know-how, shall be owned by and vested in SumUp, or SumUp's licensors, and nothing in this Agreement shall constitute or be interpreted as a transfer of such rights from SumUp to you. You are solely entitled to the limited license to the Software or Documentation specifically granted under this Agreement. You acknowledge that the structure and code of the Software are valuable trade secrets of SumUp which shall remain the sole property of SumUp. At present, the Software and Documentation is provided by SumUp to you free of charge. However, SumUp has the right to at any time, if deemed necessary by SumUp, charge you a license fee for the Software and Documentation. If SumUp decides at its own discretion to charge you for the access to and use of the Software and Documentation, SumUp will provide you with an invoice stating inter alia the amount and the bank account number to which you shall transfer such license fee. + +2. Disclaimer. +SumUp licenses the Software and Documentation to you only on an "as is" basis without warranties or conditions of any kind, either express or implied, including without limitation any warranties or conditions of title, non-infringement, merchantability or fitness for a particular purpose. SumUp makes no warranty that the Software and Documentation will be error-free. Each user of the Software or Documentation is solely responsible for determining the appropriateness of using the Software and Documentation and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs, or equipment, and unavailability or interruption of operations. Use of the Software and Documentation is made with the understanding that SumUp will not provide you with any technical or customer support or maintenance. + +3. Limitation of liability. +Neither SumUp nor its subsidiaries, affiliates, officers, agents or other partners, and employees shall be liable for loss or damage arising out of this Agreement or from the use of the Software or Documentation. In no event will SumUp or its subsidiaries, affiliates, officers, agents or other partners, and employees be liable to you or any third party for any direct, indirect, consequential, incidental, or special damages including lost profits, lost savings, costs, fees, or expenses of any kind arising out of any provision of this agreement or the use or the inability to use the Software or Documentation, however caused and under any theory of liability, whether in contract, strict liability or tort including negligence or otherwise), even if advised of the possibility of such damages. SumUp's aggregate liability and that of its suppliers under or in connection with this Agreement shall be limited to the amount paid by you for the Software and Documentation. + +4. Indemnity. +You shall indemnify and hold SumUp and its subsidiaries, affiliates, officers, agents or other partners, and employees, harmless from any claim or demand (including without limitation attorneys’ fees) made by any third party due to or arising out of your use of the Software and Documentation, your breach of this Agreement or your violation of any rights of another person or entity. You agree that you are solely responsible for (and that SumUp has no responsibility to you or to any third party for) any breach of your obligations under this Agreement, any applicable third party contract or any applicable law or regulation, and for the consequences (including any loss or damage which SumUp or any third party may suffer) of any such breach. You may not enter into any settlement or like agreement with any third party that affects SumUp’s right or binds SumUp in any way, without the prior written consent of SumUp. + +5. Confidentiality. +You are aware that the Software and Documentation constitute trade secrets and contains confidential information (”Confidential Information”). You agree to protect all Confidential Information using at least the same degree of care that you use to protect your own confidential information, however not less than a reasonable degree of care. You agree to use Confidential Information solely for the purpose of exercising your rights and performing your obligations under this Agreement and agree not to use the Confidential Information for any other purpose, without SumUp’s prior written consent. Furthermore, you agree not to make the Software and Documentation available to a third party without SumUp’s prior written consent and to with take all reasonable measures to ensure that any Confidential Information is not disclosed or otherwise furnished, directly or indirectly, to any third party. Your confidentiality obligation hereunder shall not apply to Confidential Information which You can evidence: (i) is already known by you when received; (ii) is or has becomes public knowledge other than through a breach of this Agreement; (iii) is received from a third party who lawfully acquired it and who is under no obligation restricting its disclosure; or (iv) is to be made publicly available due to a court order, a decision by a public body or as otherwise required by mandatory law. You agree to impose on your employees and consultants, if applicable, in an appropriate manner, the obligations regarding the use of the Software and Documentation set forth in this Agreement and the obligation of confidentiality set out hereunder. You shall be liable in relation to SumUp for your employees’ and consultants’ actions and for their observance of this Agreement and the obligation of confidentiality set out hereunder. Your obligations of confidentiality hereunder shall be valid during the term of this Agreement and continue for a period thereafter of five (5) years after expiration or termination of the Agreement, regardless of the reason therefore. + +6. Term. +This Agreement shall commence as set forth above, and continue to be in full force until terminated. SumUp has the right to terminate the Agreement if you fail to comply with any term of the Agreement. Furthermore, either party may terminate this Agreement for its convenience effective thirty (30) days after providing the other party written notice of termination. Upon termination of this Agreement for whatever reason, you agree to immediately cease all use of the Software and Documentation and to erase and destroy all copies of the Software and Documentation in your possession or control. SumUp will not have any liability to compensate you for any damages which you may suffer due to SumUp’s termination of this Agreement. + +7. Governing law and dispute resolution. +This Agreement shall be governed by and construed in accordance with English substantive law. Any dispute, controversy or claim arising out of or in connection with this Agreement, or the breach, termination or invalidity thereof, shall be finally settled by arbitration administered by the Courts of England. diff --git a/README.md b/README.md index 7c682d7..b890ac3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,220 @@ -# sumup-ecom-php-sdk -SumUp eCom PHP SDK +# SumUp Ecommerce PHP SDK + +## Overview + +This repository contains the open source PHP SDK that allows you to integrate quickly with the SumUp's ecommerce [API](https://developer.sumup.com/rest-api) endpoints. As a transport layer it support cURL or [GuzzleHttp](https://packagist.org/packages/guzzlehttp/guzzle) but they are not required if you provide your own. + +## Installation + +The SumUp eCom PHP SDK can be installed with [Composer](https://getcomposer.org/). Run the following command: + +``` +composer require sumup/sumup-ecom-php-sdk +``` + +> **Note:** This version of the SumUp SDK for PHP requires PHP 5.6 or greater. + +## Basic usage + +```php +try { + $sumup = new \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', + 'code' => 'YOUR-AUTHORIZATION-CODE' + ]); + $checkoutService = $sumup->getCheckoutService(); + $checkoutResponse = $checkoutService->create(/* pass here the required arguments */); +// use the variable $checkoutResponse +} catch(\SumUp\Exceptions\SumUpSDKException $e) { + echo 'SumUp SDK error: ' . $e->getMessage(); +} +``` + +## Configurations + +```php +$sumup = new \SumUp\SumUp([ +// 'config-name': 'config-value' +]); +``` + +| Name | Description | Value | Default value | Required | +|--- |--- |--- |--- |--- | +|app_id | This is the client id that you receive after you [register](https://developer.sumup.com/docs/register-app) your application in SumUp | `string`| *No default value* | Yes | +|app_secret | This is the client secret that corresponds to the client id | `string` | *No default value* | Yes | +|grant_type | This indicates which authorization flow should be used to acquire OAuth token | One of: `authorization_code`, `client_credentials`, `password` | '`authorization_code`' | No | +|scopes | This is an array with all the [authorization scopes](https://developer.sumup.com/docs/authorization#authorization-scopes) that you need for your application | `array` with possible values: `payments`, `transactions.history`, `user.app-settings`, `user.profile_readonly`, `user.profile`, `user.subaccounts`, `user.payout-settings`, `balance`, `products` | `['payments', 'transactions.history', 'user.app-settings', 'user.profile_readonly']` | No | +|code | This is the code returned at the last step from [authorization code flow](https://developer.sumup.com/docs/authorization#authorization-flows) | `string` | `null` | Conditional (required only if `grant_type => 'authorization_code'`) | +|username | This is your SumUp's username if you want to use password authorization flow | `string` | `null` | Conditional (required only if `grant_type => 'password'`) | +|password | This is your SumUp's password if you want to use password authorization flow | `string` | `null` | Conditional (required only if `grant_type => 'password'`) | +|access_token | This is the value of a valid access token that is acquired through other methods. It is used if you don't want to request new access token | `string` | `null` | No | +|refresh_token | This is the refresh token through which can be requested new access token | `string` | `null` | No | +|use_guzzlehttp_over_curl | This is a configuration whether to use GuzzleHttp if both GuzzleHttp library and cURL module are installed. | `bool` | `false` | No | +|custom_headers | This sends custom headers with every http request to SumUp server | `array` with key-value pairs containing the header's name (as key) and the header's value (as value) | `[]` | No | + +## Authorization + +Every time you make an instance of the `\SumUp\SumUp` class you get a valid OAuth 2.0 access token. The access token is then passed automatically to every service call you make but of course you can override this (see examples below). In case you need the access token you can access it like this: + +```php +$sumup = \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', +// other configurations +]); +$accessToken = $sumup->getAccessToken(); +// use the accessToken object as you need to +echo $accessToken->getValue() . ' ' . $accessToken->getRefreshToken(); +``` + +This SDK supports 3 authorization flows which are described in [this guide](https://developer.sumup.com/docs/authorization). + +### Authorization code flow + +```php +$sumup = new \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', + 'grant_type' => 'authorization_code', + 'scope' => ['payments', 'transactions.history', 'user.app-settings', 'user.profile_readonly'], + 'code' => 'YOUR-AUTHORIZATION-CODE' +]); +``` + +For more information about this flow read more in [this guide](https://developer.sumup.com/docs/authorization#authorization-code-flow). + +### Client credentials flow + +```php +$sumup = new \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', + 'grant_type' => 'client_credentials', + 'scope' => ['payments', 'transactions.history', 'user.app-settings', 'user.profile_readonly'] +]); +``` + +For more information about this flow read more in [this guide](https://developer.sumup.com/docs/authorization#client-credentials-flow). + +### Password flow + +```php +$sumup = new \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', + 'grant_type' => 'password', + 'scope' => ['payments', 'transactions.history', 'user.app-settings', 'user.profile_readonly'], + 'username' => 'YOUR-SUMUP-USERNAME', + 'password' => 'YOUR-SUMUP-PASSWORD' +]); +``` + +### Reuse access token + +In case you **already have a valid access token** you can **reuse it** like this: + +```php +$sumup = new \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', + 'scope' => ['payments', 'transactions.history', 'user.app-settings', 'user.profile_readonly'], + 'access_token' => 'VALID-ACCESS-TOKEN' +]); +``` + +### Use refresh token + +Here is how to get a **new access token from a refresh token**: + +```php +$sumup = new \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', + 'scope' => ['payments', 'transactions.history', 'user.app-settings', 'user.profile_readonly'], + 'refresh_token' => 'REFRESH-TOKEN' +]); +$sumup->refreshToken(); +``` + +### Override access token + +You can always **initialize** some **service** with a new **access token** like this: + +```php +$checkoutService = $sumup->getCheckoutService('VALID-ACCESS-TOKEN'); +``` + +## Services + +To get a particular service you first need to create a `\SumUp\SumUp` object. Then from this object you can get any of the services we support in the SDK. + +Here is an example how to get transactions history: + +```php +try { + $sumup = new \SumUp\SumUp([ + 'app_id' => 'YOUR-CLIENT-ID', + 'app_secret' => 'YOUR-CLIENT-SECRET', + 'grant_type' => 'authorization_code', + 'scope' => ['payments', 'transactions.history', 'user.app-settings', 'user.profile_readonly'], + 'code' => 'YOUR-AUTHORIZATION-CODE' + ]); + $transactionsService = $sumup->getTransactionService(); + $filters = [ + 'limit' => 100, + 'statuses' => ['SUCCESSFUL', 'REFUND'] + ]; + $transactionsHistory = $transactionsService->getTransactionHistory($filters)->getBody(); +// you can now iterate over the result in $transactionsHistory +} catch (\SumUp\Exceptions\SumUpSDKException $e) { +// handle exceptions +} +``` + +> All services' methods return response of type `\SumUp\HttpClients\Response` or throw an exception (view [exceptions handling](https://github.com/sumup/sumup-ecom-php-sdk#exceptions-handling)). + +## Exceptions handling + +Exceptions handling is an important part of our code. We pay attention to this detail and **we recommend to wrap every statement from this SDK with a `try {} catch() {}` clause**. + +You should at least handle `\SumUp\Exceptions\SumUpSDKException` exception but if you want you can handle all sorts of exceptions. + +```php +try { + $sumup = new \SumUp\SumUp(/* configuration */); +} catch (\SumUp\Exceptions\SumUpAuthenticationException $e) { + echo $e->getCode() . ': ' . $e->getMessage(); +} catch (\SumUp\Exceptions\SumUpResponseException $e) { + echo $e->getCode() . ': ' . $e->getMessage(); +} catch (\SumUp\Exceptions\SumUpSDKException $e) { + echo $e->getCode() . ': ' . $e->getMessage(); +} +``` + +Here is a table with all the exceptions that are thrown from this SDK: + +| Exception | Conditions | +|--- |--- | +|`\SumUp\Exceptions\SumUpAuthenticationException`| This exception is thrown when there is no access token or it is already expired. | +|`\SumUp\Exceptions\SumUpConnectionException` | This exception is thrown when there is connectivity issues over the network. | +|`\SumUp\Exceptions\SumUpResponseException` | This exception is thrown when there are some [4xx http errors](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors) such as `404 Not Found`. | +|`\SumUp\Exceptions\SumUpValidationException` | This exception is thrown when there is one or more wrong data send to the server. In the message there is information about which field(s) is incorrect. | +|`\SumUp\Exceptions\SumUpServerException` | This exception is thrown when there are http errors of [5xx](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors). | +|`\SumUp\Exceptions\SumUpConfigurationException` | This exception is thrown when you provide a bad configuration for initialization of the `\SumUp\SumUp` object. | +|`\SumUp\Exceptions\SumUpArgumentException` | This exception is thrown when you don't provide a mandatory argument to a function. | +|`\SumUp\Exceptions\SumUpSDKException` | This is the main exception which others inherit from. So this is the last exception to handle in your code if you want to catch many exceptions.| + +## Roadmap + +| Version | Status | PHP Version | +|--- |--- |--- | +| 1.x | Latest | \>= 5.6 | + +## License + +For information about the license see the [license](https://github.com/sumup/sumup-ecom-php-sdk/blob/master/LICENSE) file. + +## Contact us + +If you have found a bug or you lack some functionality please [open an issue](https://github.com/sumup/sumup-ecom-php-sdk/issues/new). If you have other issues when integrating with SumUp's API you can send an email to [integration@sumup.com](mailto:integration@sumup.com). diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..5be75e1 --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "sumup/sumup-ecom-php-sdk", + "description": "SumUp eCom SDK for PHP", + "type": "library", + "version": "1.0.0-rc", + "keywords": ["sumup", "sdk", "payment processing", "ecommerce", "payment", "checkout"], + "homepage": "https://developer.sumup.com", + "authors": [ + { + "name": "SumUp", + "email": "integration@sumup.com", + "homepage": "https://github.com/sumup" + } + ], + "require": { + "php": "^5.6|^7.0" + }, + "suggest": { + "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client" + }, + "autoload": { + "psr-4": { + "SumUp\\": "src/SumUp/" + } + } +} diff --git a/src/SumUp/Application/ApplicationConfiguration.php b/src/SumUp/Application/ApplicationConfiguration.php new file mode 100644 index 0000000..834f85d --- /dev/null +++ b/src/SumUp/Application/ApplicationConfiguration.php @@ -0,0 +1,355 @@ + null, + 'app_secret' => null, + 'grant_type' => 'authorization_code', + 'base_uri' => 'https://api.sumup.com', + 'scopes' => [], + 'code' => null, + 'access_token' => null, + 'refresh_token' => null, + 'username' => null, + 'password' => null, + 'use_guzzlehttp_over_curl' => false, + 'custom_headers' => [] + ], $config); + + $this->setAppId($config['app_id']); + $this->setAppSecret($config['app_secret']); + $this->setScopes($config['scopes']); + $this->setGrantType($config['grant_type']); + $this->baseURL = $config['base_uri']; + $this->username = $config['username']; + $this->password = $config['password']; + $this->code = $config['code']; + $this->accessToken = $config['access_token']; + $this->refreshToken = $config['refresh_token']; + $this->setForceGuzzle($config['use_guzzlehttp_over_curl']); + $this->setCustomHeaders($config['custom_headers']); + } + + /** + * Returns the client ID. + * + * @return string + */ + public function getAppId() + { + return $this->appId; + } + + /** + * Returns the client secret. + * + * @return string + */ + public function getAppSecret() + { + return $this->appSecret; + } + + /** + * Returns the scopes. + * + * @return array + */ + public function getScopes() + { + return $this->scopes; + } + + /** + * Returns the scopes formatted as they should appear in the request. + * + * @return string + */ + public function getFormattedScopes() + { + return implode(' ', $this->scopes); + } + + /** + * Returns the base URL of the SumUp API. + * + * @return string + */ + public function getBaseURL() + { + return $this->baseURL; + } + + /** + * Returns authorization code. + * + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * Returns grant type. + * + * @return string; + */ + public function getGrantType() + { + return $this->grantType; + } + + /** + * Returns merchant's username. + * + * @return string + */ + public function getUsername() + { + return $this->username; + } + + /** + * Returns merchant's password. + * + * @return string + */ + public function getPassword() + { + return $this->password; + } + + /** + * Returns initial access token. + * + * @return null|string + */ + public function getAccessToken() + { + return $this->accessToken; + } + + /** + * Returns initial refresh token. + * + * @return null|string + */ + public function getRefreshToken() + { + return $this->refreshToken; + } + + /** + * Returns the flag whether to use GuzzleHttp. + * + * @return bool + */ + public function getForceGuzzle() + { + return $this->forceGuzzle; + } + + /** + * Returns associative array with custom headers. + * + * @return array + */ + public function getCustomHeaders() + { + return $this->customHeaders; + } + + /** + * Set application ID. + * + * @param string $appId + * + * @throws SumUpConfigurationException + */ + protected function setAppId($appId) + { + if (empty($appId)) { + throw new SumUpConfigurationException('Missing mandatory parameter app_id'); + } + $this->appId = $appId; + } + + /** + * Set application secret. + * + * @param string $appSecret + * + * @throws SumUpConfigurationException + */ + protected function setAppSecret($appSecret) + { + if (empty($appSecret)) { + throw new SumUpConfigurationException('Missing mandatory parameter app_secret'); + } + $this->appSecret = $appSecret; + } + + /** + * Set the authorization grant type. + * + * @param array $grantType + * + * @throws SumUpConfigurationException + */ + protected function setGrantType($grantType) + { + if (!in_array($grantType, $this::GRANT_TYPES)) { + throw new SumUpConfigurationException('Invalid parameter for "grant_type". Allowed values are: ' . implode($this::GRANT_TYPES, ' | ') . '.'); + } + $this->grantType = $grantType; + } + + /** + * Set the scopes and always include the default ones. + * + * @param array $scopes + */ + protected function setScopes(array $scopes = []) + { + $this->scopes = array_unique(array_merge($this::DEFAULT_SCOPES, $scopes), SORT_REGULAR);; + } + + /** + * Set the flag whether to use GuzzleHttp. + * + * @param bool $forceGuzzle + * + * @throws SumUpConfigurationException + */ + protected function setForceGuzzle($forceGuzzle) + { + if (!is_bool($forceGuzzle)) { + throw new SumUpConfigurationException('Invalid value for boolean parameter use_guzzlehttp_over_curl.'); + } + $this->forceGuzzle = $forceGuzzle; + } + + /** + * Set the associative array with custom headers. + * + * @param array $customHeaders + */ + public function setCustomHeaders($customHeaders) + { + $this->customHeaders = is_array($customHeaders) ? $customHeaders : []; + } +} diff --git a/src/SumUp/Application/ApplicationConfigurationInterface.php b/src/SumUp/Application/ApplicationConfigurationInterface.php new file mode 100644 index 0000000..d66d03d --- /dev/null +++ b/src/SumUp/Application/ApplicationConfigurationInterface.php @@ -0,0 +1,95 @@ +value = $value; + } + if ($type) { + $this->type = $type; + } + if ($expiresIn) { + $this->expiresIn = $expiresIn; + } + if ($scope) { + $this->scope = $scope; + } + if ($refreshToken) { + $this->refreshToken = $refreshToken; + } + } + + /** + * Returns the access token. + * + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * Returns the type of the access token. + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Returns the total number of seconds that the token will be valid. + * + * @return int + */ + public function getExpiresIn() + { + return $this->expiresIn; + } + + /** + * Returns the scopes for the current access token. + * + * @return array + */ + public function getScopes() + { + return $this->scope; + } + + /** + * Returns the refresh token if any. + * + * @return null|string + */ + public function getRefreshToken() + { + return $this->refreshToken; + } +} diff --git a/src/SumUp/Exceptions/SumUpArgumentException.php b/src/SumUp/Exceptions/SumUpArgumentException.php new file mode 100644 index 0000000..27ca933 --- /dev/null +++ b/src/SumUp/Exceptions/SumUpArgumentException.php @@ -0,0 +1,12 @@ +fields = $fields; + $message = self::VALIDATION_ERROR_BASE . implode(', ', $fields); + parent::__construct($message, $code, $previous); + } + + /** + * Returns the fields that failed the server validation. + * + * @return array + */ + public function getInvalidFields() + { + return $this->fields; + } +} diff --git a/src/SumUp/HttpClients/HttpClientsFactory.php b/src/SumUp/HttpClients/HttpClientsFactory.php new file mode 100644 index 0000000..63af7c5 --- /dev/null +++ b/src/SumUp/HttpClients/HttpClientsFactory.php @@ -0,0 +1,59 @@ +getBaseURL(), $appConfig->getForceGuzzle(), $appConfig->getCustomHeaders()); + } + + /** + * Detect the default HTTP client. + * + * @param string $baseURL + * @param bool $forceUseGuzzle + * + * @return SumUpCUrlClient|SumUpGuzzleHttpClient + * + * @throws SumUpConfigurationException + */ + private static function detectDefaultClient($baseURL, $forceUseGuzzle, $customHeaders) + { + if (extension_loaded('curl') && !$forceUseGuzzle) { + return new SumUpCUrlClient($baseURL, $customHeaders); + } + if (class_exists('GuzzleHttp\Client')) { + return new SumUpGuzzleHttpClient($baseURL, $customHeaders); + } + + throw new SumUpConfigurationException('No default http client found. Please install cURL or GuzzleHttp.'); + } +} diff --git a/src/SumUp/HttpClients/Response.php b/src/SumUp/HttpClients/Response.php new file mode 100644 index 0000000..9488051 --- /dev/null +++ b/src/SumUp/HttpClients/Response.php @@ -0,0 +1,106 @@ +httpResponseCode = $httpResponseCode; + $this->body = $body; + $this->parseResponseForErrors(); + } + + /** + * Get HTTP response code. + * + * @return number + */ + public function getHttpResponseCode() + { + return $this->httpResponseCode; + } + + /** + * Get the response body. + * + * @return array|mixed + */ + public function getBody() + { + return $this->body; + } + + /** + * Parses the response for containing errors. + * + * @return mixed + * + * @throws SumUpAuthenticationException + * @throws SumUpResponseException + * @throws SumUpValidationException + * @throws SumUpServerException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + protected function parseResponseForErrors() + { + if (isset($this->body->error_code) && $this->body->error_code === 'NOT_AUTHORIZED') { + throw new SumUpAuthenticationException($this->body->error_message, $this->httpResponseCode); + } + if (isset($this->body->error_code) && $this->body->error_code === 'MISSING') { + throw new SumUpValidationException([$this->body->param], $this->httpResponseCode); + } + if (is_array($this->body) && sizeof($this->body) > 0 && isset($this->body[0]->error_code) && $this->body[0]->error_code === 'MISSING') { + $invalidFields = []; + foreach ($this->body as $errorObject) { + $invalidFields[] = $errorObject->param; + } + throw new SumUpValidationException($invalidFields, $this->httpResponseCode); + } + if ($this->httpResponseCode >= 500) { + $message = (is_null($this->body) && is_null($this->body->message)) ? $this->body : $this->body->message; + throw new SumUpServerException($message, $this->httpResponseCode); + } + if ($this->httpResponseCode >= 400) { + $message = (is_null($this->body) && is_null($this->body->message)) ? $this->body : $this->body->message; + throw new SumUpResponseException($message, $this->httpResponseCode); + } + } +} \ No newline at end of file diff --git a/src/SumUp/HttpClients/SumUpCUrlClient.php b/src/SumUp/HttpClients/SumUpCUrlClient.php new file mode 100644 index 0000000..f4b2c58 --- /dev/null +++ b/src/SumUp/HttpClients/SumUpCUrlClient.php @@ -0,0 +1,117 @@ +baseUrl = $baseUrl; + $this->customHeaders = $customHeaders; + } + + /** + * @param string $method The request method. + * @param string $url The endpoint to send the request to. + * @param string $body The body of the request. + * @param array $headers The headers of the request. + * + * @return Response + * + * @throws SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpValidationException + * @throws SumUpSDKException + */ + public function send($method, $url, $body, $headers = []) + { + $reqHeaders = array_merge($headers, $this->customHeaders); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + curl_setopt($ch, CURLOPT_URL, $this->baseUrl . $url); + curl_setopt($ch, CURLOPT_HTTPHEADER, $this->formatHeaders($reqHeaders)); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true ); + if (!empty($body)) { + $payload = json_encode($body); + curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); + } + + $response = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + $error = curl_error($ch); + if ($error) { + curl_close ($ch); + throw new SumUpConnectionException($error, $code); + } + + curl_close ($ch); + return new Response($code, $this->parseBody($response)); + } + + /** + * Format the headers to be compatible with cURL. + * + * @param array|null $headers + * + * @return array + */ + private function formatHeaders($headers = null) + { + if (count($headers) == 0) { + return $headers; + } + + $keys = array_keys($headers); + $formattedHeaders = []; + foreach($keys as $key) { + $formattedHeaders[] = $key . ': ' . $headers[$key]; + } + return $formattedHeaders; + } + + /** + * Returns JSON encoded the response's body if it is of JSON type. + * + * @param $response + * + * @return mixed + */ + private function parseBody($response) + { + $jsonBody = json_decode($response); + if (isset($jsonBody)) { + return $jsonBody; + } + return $response; + } +} \ No newline at end of file diff --git a/src/SumUp/HttpClients/SumUpGuzzleHttpClient.php b/src/SumUp/HttpClients/SumUpGuzzleHttpClient.php new file mode 100644 index 0000000..da3b26f --- /dev/null +++ b/src/SumUp/HttpClients/SumUpGuzzleHttpClient.php @@ -0,0 +1,112 @@ +guzzleClient = new Client(['base_uri' => $baseUrl]); + $this->customHeaders = $customHeaders; + } + + /** + * @param string $method The request method. + * @param string $url The endpoint to send the request to. + * @param string $body The body of the request. + * @param array $headers The headers of the request. + * + * @return Response + * + * @throws SumUpConnectionException + * @throws SumUpServerException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpValidationException + * @throws SumUpSDKException + */ + public function send($method, $url, $body, $headers = []) + { + $options = [ + 'headers' => array_merge($headers, $this->customHeaders), + 'json' => $body + ]; + + $request = new Request($method, $url); + + try { + $response = $this->guzzleClient->send($request, $options); + } catch (ConnectException $e) { + throw new SumUpConnectionException($e->getMessage(), $e->getCode(), $e->getPrevious()); + } catch (ClientException $e) { + $response = $e->getResponse(); + $body = $this->parseBody($response); + return new Response($response->getStatusCode(), $body); + } catch (ServerException $e) { + $response = $e->getResponse(); + $body = $this->parseBody($response); + if (isset($body) && isset($body->message)) { + $message = $body->message; + } else { + $message = $body; + } + throw new SumUpServerException($message, $e->getCode(), $e->getPrevious()); + } catch (\GuzzleHttp\Exception\GuzzleException $e) { + throw new SumUpSDKException($e->getMessage(), $e->getCode(), $e->getPrevious()); + } catch (\Exception $e) { + throw new SumUpSDKException($e->getMessage(), $e->getCode(), $e->getPrevious()); + } + $body = $this->parseBody($response); + return new Response($response->getStatusCode(), $body); + } + + /** + * Returns JSON encoded the response's body if it is of JSON type. + * + * @param $response + * + * @return mixed + */ + private function parseBody($response) + { + $jsonBody = json_decode($response->getBody()); + if (isset($jsonBody)) { + return $jsonBody; + } + return $response->getBody(); + } +} diff --git a/src/SumUp/HttpClients/SumUpHttpClientInterface.php b/src/SumUp/HttpClients/SumUpHttpClientInterface.php new file mode 100644 index 0000000..75af650 --- /dev/null +++ b/src/SumUp/HttpClients/SumUpHttpClientInterface.php @@ -0,0 +1,21 @@ +appConfig = $config; + } + + /** + * Returns an access token according to the grant_type. + * + * @param SumUpHttpClientInterface $client + * + * @return null|AccessToken + * + * @throws SumUpConfigurationException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getToken(SumUpHttpClientInterface $client) + { + $accessToken = null; + if (!empty($this->appConfig->getAccessToken())) { + $accessToken = new AccessToken( + $this->appConfig->getAccessToken(), + '', + 0, + $this->appConfig->getScopes(), + $this->appConfig->getRefreshToken() + ); + } else if (!empty($this->appConfig->getRefreshToken())) { + $accessToken = new AccessToken( + '', + '', + 0, + $this->appConfig->getScopes(), + $this->appConfig->getRefreshToken() + ); + } else { + switch ($this->appConfig->getGrantType()) { + case 'authorization_code': + $accessToken = $this->getTokenByCode($client); + break; + case 'client_credentials': + $accessToken = $this->getTokenByClientCredentials($client); + break; + case 'password': + $accessToken = $this->getTokenByPassword($client); + break; + } + } + return $accessToken; + } + + /** + * Returns an access token for the grant type "authorization_code". + * + * @param SumUpHttpClientInterface $client + * + * @return AccessToken + * + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getTokenByCode(SumUpHttpClientInterface $client) + { + $payload = [ + 'grant_type' => 'authorization_code', + 'client_id' => $this->appConfig->getAppId(), + 'client_secret' => $this->appConfig->getAppSecret(), + 'scope' => $this->appConfig->getFormattedScopes(), + 'code' => $this->appConfig->getCode() + ]; + $headers = Headers::getStandardHeaders(); + $response = $client->send( 'POST', '/token', $payload, $headers); + $resBody = $response->getBody(); + $scopes = []; + if (!empty($resBody->scope)) { + $scopes = explode(' ', $resBody->scope); + } + return new AccessToken($resBody->access_token, $resBody->token_type, $resBody->expires_in, $scopes, $resBody->refresh_token); + } + + /** + * Returns an access token for the grant type "client_credentials". + * + * @param SumUpHttpClientInterface $client + * + * @return AccessToken + * + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getTokenByClientCredentials(SumUpHttpClientInterface $client) + { + $payload = [ + 'grant_type' => 'client_credentials', + 'client_id' => $this->appConfig->getAppId(), + 'client_secret' => $this->appConfig->getAppSecret(), + 'scope' => $this->appConfig->getFormattedScopes() + ]; + $headers = Headers::getStandardHeaders(); + $response = $client->send( 'POST', '/token', $payload, $headers); + $resBody = $response->getBody(); + return new AccessToken($resBody->access_token, $resBody->token_type, $resBody->expires_in); + } + + /** + * Returns an access token for the grant type "password". + * + * @param SumUpHttpClientInterface $client + * + * @return AccessToken + * + * @throws SumUpConfigurationException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getTokenByPassword(SumUpHttpClientInterface $client) + { + if (empty($this->appConfig->getUsername())) { + throw new SumUpConfigurationException(ExceptionMessages::getMissingParamMsg('username')); + } + if (empty($this->appConfig->getPassword())) { + throw new SumUpConfigurationException(ExceptionMessages::getMissingParamMsg("password")); + } + $payload = [ + 'grant_type' => 'password', + 'client_id' => $this->appConfig->getAppId(), + 'client_secret' => $this->appConfig->getAppSecret(), + 'scope' => $this->appConfig->getFormattedScopes(), + 'username' => $this->appConfig->getUsername(), + 'password' => $this->appConfig->getPassword() + ]; + $headers = Headers::getStandardHeaders(); + $response = $client->send( 'POST', '/token', $payload, $headers); + $resBody = $response->getBody(); + $scopes = []; + if (!empty($resBody->scope)) { + $scopes = explode(' ', $resBody->scope); + } + return new AccessToken($resBody->access_token, $resBody->token_type, $resBody->expires_in, $scopes, $resBody->refresh_token); + } + + /** + * Refresh access token. + * + * @param SumUpHttpClientInterface $client + * @param string $refreshToken + * + * @return AccessToken + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function refreshToken(SumUpHttpClientInterface $client, $refreshToken) + { + if (empty($refreshToken)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('refresh token')); + } + $payload = [ + 'grant_type' => 'refresh_token', + 'client_id' => $this->appConfig->getAppId(), + 'client_secret' => $this->appConfig->getAppSecret(), + 'refresh_token' => $refreshToken, + 'scope' => $this->appConfig->getFormattedScopes() + ]; + $headers = Headers::getStandardHeaders(); + $response = $client->send( 'POST', '/token', $payload, $headers); + $resBody = $response->getBody(); + $scopes = []; + if (!empty($resBody->scope)) { + $scopes = explode(' ', $resBody->scope); + } + return new AccessToken($resBody->access_token, $resBody->token_type, $resBody->expires_in, $scopes, $resBody->refresh_token); + } +} diff --git a/src/SumUp/Services/Checkouts.php b/src/SumUp/Services/Checkouts.php new file mode 100644 index 0000000..0b9aed7 --- /dev/null +++ b/src/SumUp/Services/Checkouts.php @@ -0,0 +1,204 @@ +client = $client; + $this->accessToken = $accessToken; + } + + /** + * Create new checkout. + * + * @param number $amount + * @param string $currency + * @param string $checkoutRef + * @param string $payToEmail + * @param string $description + * @param null $payFromEmail + * @param null $returnURL + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function create($amount, $currency, $checkoutRef, $payToEmail, $description = '', $payFromEmail = null, $returnURL = null) + { + if (empty($amount) || !is_numeric($amount)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('amount')); + } + if (empty($currency)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('currency')); + } + if (empty($checkoutRef)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('checkout reference id')); + } + if (empty($payToEmail)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('pay to email')); + } + $payload = [ + 'amount' => $amount, + 'currency' => $currency, + 'checkout_reference' => $checkoutRef, + 'pay_to_email' => $payToEmail, + 'description' => $description + ]; + if (isset($payFromEmail)) { + $payload['pay_from_email'] = $payFromEmail; + } + if (isset($returnURL)) { + $payload['return_url'] = $returnURL; + } + $path = '/v0.1/checkouts'; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send( 'POST', $path, $payload, $headers); + } + + /** + * Get single checkout by provided checkout ID. + * + * @param string $checkoutId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function findById($checkoutId) + { + if (empty($checkoutId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('checkout id')); + } + $path = '/v0.1/checkouts/' . $checkoutId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Get single checkout by provided checkout reference ID. + * + * @param string $referenceId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function findByReferenceId($referenceId) + { + if (empty($referenceId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('reference id')); + } + $path = '/v0.1/checkouts?checkout_reference=' . $referenceId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Delete a checkout. + * + * @param string $checkoutId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function delete($checkoutId) + { + if (empty($checkoutId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('checkout id')); + } + $path = '/v0.1/checkouts/' . $checkoutId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('DELETE', $path, [], $headers); + } + + /** + * Pay a checkout with tokenized card. + * + * @param string $checkoutId + * @param string $customerId + * @param string $cardToken + * @param int $installments + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function pay($checkoutId, $customerId, $cardToken, $installments = 1) + { + if (empty($checkoutId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('checkout id')); + } + if (empty($customerId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('customer id')); + } + if (empty($cardToken)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('card token')); + } + if (empty($installments) || !is_int($installments)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('installments')); + } + $payload = [ + 'payment_type' => 'card', + 'customer_id' => $customerId, + 'token' => $cardToken, + 'installments' => $installments + ]; + $path = '/v0.1/checkouts/' . $checkoutId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('PUT', $path, $payload, $headers); + } +} diff --git a/src/SumUp/Services/Customers.php b/src/SumUp/Services/Customers.php new file mode 100644 index 0000000..e01b40a --- /dev/null +++ b/src/SumUp/Services/Customers.php @@ -0,0 +1,219 @@ +client = $client; + $this->accessToken = $accessToken; + } + + /** + * Create new customer. + * + * @param $customerId + * @param array $customerDetails + * @param array $customerAddress + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function create($customerId, array $customerDetails = [], array $customerAddress = []) + { + if (empty($customerId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('customer id')); + } + + $details = array_merge([ + 'first_name' => null, + 'last_name' => null, + 'email' => null, + 'phone' => null + ], $customerDetails); + $details = array_filter($details); + + $address = array_merge([ + 'city' => null, + 'country' => null, + 'line1' => null, + 'line2' => null, + 'state' => null, + 'postalCode' => null + ], $customerAddress); + $address = array_filter($address); + + if (sizeof($address) > 0) { + $details['address'] = $address; + } + + $payload = [ + 'customer_id' => $customerId, + 'personal_details' => $details + ]; + $path = '/v0.1/customers'; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('POST', $path, $payload, $headers); + } + + /** + * Update existing customer. + * + * @param $customerId + * @param array $customerDetails + * @param array $customerAddress + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function update($customerId, array $customerDetails = [], array $customerAddress = []) + { + if (empty($customerId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('customer id')); + } + + $details = array_merge([ + 'first_name' => null, + 'last_name' => null, + 'email' => null, + 'phone' => null + ], $customerDetails); + $details = array_filter($details); + + $address = array_merge([ + 'city' => null, + 'country' => null, + 'line1' => null, + 'line2' => null, + 'state' => null, + 'postalCode' => null + ], $customerAddress); + $address = array_filter($address); + + if (sizeof($address) > 0) { + $details['address'] = $address; + } + $payload = [ + 'customer_id' => $customerId, + 'personal_details' => $details + ]; + $path = '/v0.1/customers/' . $customerId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('PUT', $path, $payload, $headers); + } + + /** + * Get customer by ID. + * + * @param $customerId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function get($customerId) + { + if (empty($customerId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('customer id')); + } + $path = '/v0.1/customers/' . $customerId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Get payment instruments for a customer. + * + * @param $customerId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getPaymentInstruments($customerId) + { + if (empty($customerId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('customer id')); + } + $path = '/v0.1/customers/' . $customerId . '/payment-instruments'; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Deactivate payment instrument for a customer. + * + * @param $customerId + * @param $cardToken + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function deletePaymentInstruments($customerId, $cardToken) + { + if (empty($customerId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('customer id')); + } + if (empty($cardToken)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('card token')); + } + $path = '/v0.1/customers/' . $customerId . '/payment-instruments/' . $cardToken; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('DELETE', $path, [], $headers); + } +} diff --git a/src/SumUp/Services/Merchant.php b/src/SumUp/Services/Merchant.php new file mode 100644 index 0000000..dcf3c36 --- /dev/null +++ b/src/SumUp/Services/Merchant.php @@ -0,0 +1,123 @@ +client = $client; + $this->accessToken = $accessToken; + } + + /** + * Get merchant's profile. + * + * @return \SumUp\HttpClients\Response + * + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getProfile() + { + $path = '/v0.1/me/merchant-profile'; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Update merchant's profile. + * + * @param array $data + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function updateProfile(array $data) + { + if (empty($data)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('payload data')); + } + $path = '/v0.1/me/merchant-profile'; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('PUT', $path, $data, $headers); + } + + /** + * Get data for doing business as. + * + * @return \SumUp\HttpClients\Response + * + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getDoingBusinessAs() + { + $path = '/v0.1/me/merchant-profile/doing-business-as'; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Update data for doing business as. + * + * @param array $data + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function updateDoingBusinessAs(array $data) + { + if (empty($data)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('payload data')); + } + $path = '/v0.1/me/merchant-profile/doing-business-as'; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('PUT', $path, $data, $headers); + } +} diff --git a/src/SumUp/Services/Payouts.php b/src/SumUp/Services/Payouts.php new file mode 100644 index 0000000..2e100a5 --- /dev/null +++ b/src/SumUp/Services/Payouts.php @@ -0,0 +1,137 @@ +client = $client; + $this->accessToken = $accessToken; + } + + /** + * Get a list of payouts. + * + * @param string $startDate + * @param string $endDate + * @param int $limit + * @param bool $descendingOrder + * @param string $format + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getPayouts($startDate, $endDate, $limit = 10, $descendingOrder = true, $format = 'json') + { + if (empty($startDate)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('start date')); + } + if (empty($endDate)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('end date')); + } + if (empty($limit) || !is_int($limit)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('limit')); + } + if (empty($descendingOrder)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('order')); + } + if (empty($format)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('format')); + } + $filters = [ + 'start_date' => $startDate, + 'end_date' => $endDate, + 'limit' => $limit, + 'order' => $descendingOrder ? 'desc' : 'asc', + 'format' => $format + ]; + $queryParams = http_build_query($filters); + $path = '/v0.1/me/financials/payouts?' . $queryParams; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, null, $headers); + } + + /** + * Get a list of payed out transactions. + * + * @param string $startDate + * @param string $endDate + * @param int $limit + * @param bool $descendingOrder + * @param string $format + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getTransactions($startDate, $endDate, $limit = 10, $descendingOrder = true, $format = 'json') + { + if (empty($startDate)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('start date')); + } + if (empty($endDate)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('end date')); + } + if (empty($limit) || !is_int($limit)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('limit')); + } + if (empty($descendingOrder)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('order')); + } + if (empty($format)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('format')); + } + $filters = [ + 'start_date' => $startDate, + 'end_date' => $endDate, + 'limit' => $limit, + 'order' => $descendingOrder ? 'desc' : 'asc', + 'format' => $format + ]; + $queryParams = http_build_query($filters); + $path = '/v0.1/me/financials/transactions?' . $queryParams; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, null, $headers); + } +} diff --git a/src/SumUp/Services/SumUpService.php b/src/SumUp/Services/SumUpService.php new file mode 100644 index 0000000..22c2cc7 --- /dev/null +++ b/src/SumUp/Services/SumUpService.php @@ -0,0 +1,12 @@ +client = $client; + $this->accessToken = $accessToken; + } + + /** + * Get single transaction by transaction ID. + * + * @param $transactionId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function findById($transactionId) + { + if (empty($transactionId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('transaction id')); + } + $path = '/v0.1/me/transactions?id=' . $transactionId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Get single transaction by internal ID. + * + * @param $internalId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function findByInternalId($internalId) + { + if (empty($internalId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('internal id')); + } + $path = '/v0.1/me/transactions?internal_id=' . $internalId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Get single transaction by transaction code. + * + * @param $transactionCode + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function findByTransactionCode($transactionCode) + { + if (empty($transactionCode)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('transaction code')); + } + $path = '/v0.1/me/transactions?transaction_code=' . $transactionCode; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Get a list of transactions. + * + * @param array $filters + * + * @return \SumUp\HttpClients\Response + * + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getTransactionHistory($filters = []) + { + $filters = array_merge([ + 'order' => 'ascending', + 'limit' => 10, + 'user_id' => null, + 'users' => [], + 'statuses' => [], + 'payment_types' => [], + 'types' => [], + 'changes_since' => null, + 'newest_time' => null, + 'newest_ref' => null, + 'oldest_time' => null, + 'oldest_ref' => null, + ], $filters); + + $queryParams = http_build_query($filters); + /** + * Remove index from the [] because the server doesn't support it this way. + */ + $queryParams = preg_replace('/%5B[0-9]+%5D/', '%5B%5D', $queryParams); + + $path = '/v0.1/me/transactions/history?' . $queryParams; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } + + /** + * Refund a transaction partially or fully. + * + * @param $transactionId + * @param $amount + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function refund($transactionId, $amount) + { + if (empty($transactionId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('transaction id')); + } + if (empty($amount)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('amount')); + } + $payload = [ + 'amount' => $amount + ]; + $path = '/v0.1/me/refund/' . $transactionId; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('POST', $path, $payload, $headers); + } + + /** + * Get a receipt for a transaction. + * + * @param $transactionId + * @param $merchantId + * + * @return \SumUp\HttpClients\Response + * + * @throws SumUpArgumentException + * @throws \SumUp\Exceptions\SumUpConnectionException + * @throws \SumUp\Exceptions\SumUpResponseException + * @throws \SumUp\Exceptions\SumUpAuthenticationException + * @throws \SumUp\Exceptions\SumUpSDKException + */ + public function getReceipt($transactionId, $merchantId) + { + if (empty($transactionId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('transaction id')); + } + if (empty($merchantId)) { + throw new SumUpArgumentException(ExceptionMessages::getMissingParamMsg('merchant id')); + } + $queryParams = http_build_query(['mid' => $merchantId]); + $path = '/v1.0/receipts/' . $transactionId . '?' . $queryParams; + $headers = array_merge(Headers::getStandardHeaders(), Headers::getAuth($this->accessToken)); + return $this->client->send('GET', $path, [], $headers); + } +} diff --git a/src/SumUp/SumUp.php b/src/SumUp/SumUp.php new file mode 100644 index 0000000..20c5ed2 --- /dev/null +++ b/src/SumUp/SumUp.php @@ -0,0 +1,193 @@ +appConfig = new ApplicationConfiguration($config); + $this->client = HttpClientsFactory::createHttpClient($this->appConfig, $customHttpClient); + $authorizationService = new Authorization($this->appConfig); + $this->accessToken = $authorizationService->getToken($this->client, $this->appConfig); + } + + /** + * Returns the access token. + * + * @return Authentication\AccessToken + */ + public function getAccessToken() + { + return $this->accessToken; + } + + /** + * Refresh the access token. + * + * @param string $refreshToken + * + * @return Authentication\AccessToken + * + * @throws SumUpSDKException + */ + public function refreshToken($refreshToken = null) + { + if (isset($refreshToken)) { + $rToken = $refreshToken; + } else if (!isset($refreshToken) && !isset($this->accessToken)) { + throw new SumUpConfigurationException('There is no refresh token'); + } else { + $rToken = $this->accessToken->getRefreshToken(); + } + $authorizationService = new Authorization($this->appConfig); + $this->accessToken = $authorizationService->refreshToken($this->client, $rToken); + return $this->accessToken; + } + + /** + * Get the service for authorization. + * + * @param ApplicationConfigurationInterface|null $config + * + * @return Authorization + */ + public function getAuthorizationService(ApplicationConfigurationInterface $config = null) + { + if (empty($config)) { + $cfg = $this->appConfig; + } else { + $cfg = $config; + } + return new Authorization($cfg); + } + + /** + * Get the service for checkouts management. + * + * @param AccessToken|null $accessToken + * + * @return Checkouts + */ + public function getCheckoutService(AccessToken $accessToken = null) + { + if (!empty($accessToken)) { + $accToken = $accessToken; + } else { + $accToken = $this->accessToken; + } + return new Checkouts($this->client, $accToken); + } + + /** + * Get the service for customers management. + * + * @param AccessToken|null $accessToken + * + * @return Customers + */ + public function getCustomerService(AccessToken $accessToken = null) + { + if (!empty($accessToken)) { + $accToken = $accessToken; + } else { + $accToken = $this->accessToken; + } + return new Customers($this->client, $accToken); + } + + /** + * Get the service for transactions management. + * + * @param AccessToken|null $accessToken + * + * @return Transactions + */ + public function getTransactionService(AccessToken $accessToken = null) + { + if (!empty($accessToken)) { + $accToken = $accessToken; + } else { + $accToken = $this->accessToken; + } + return new Transactions($this->client, $accToken); + } + + /** + * Get the service for merchant management. + * + * @param AccessToken|null $accessToken + * + * @return Merchant + */ + public function getMerchantService(AccessToken $accessToken = null) + { + if (!empty($accessToken)) { + $accToken = $accessToken; + } else { + $accToken = $this->accessToken; + } + return new Merchant($this->client, $accToken); + } + + /** + * Get the service for payouts. + * + * @param AccessToken|null $accessToken + * + * @return Payouts + */ + public function getPayoutService(AccessToken $accessToken = null) + { + if (!empty($accessToken)) { + $accToken = $accessToken; + } else { + $accToken = $this->accessToken; + } + return new Payouts($this->client, $accToken); + } +} diff --git a/src/SumUp/Utils/Exceptions.php b/src/SumUp/Utils/Exceptions.php new file mode 100644 index 0000000..ac7e951 --- /dev/null +++ b/src/SumUp/Utils/Exceptions.php @@ -0,0 +1,23 @@ + 'application/json']; + } + + /** + * Get the common header for Content-Type: application/x-www-form-urlencoded. + * + * @return array + */ + public static function getCTForm() + { + return ['Content-Type' => 'application/x-www-form-urlencoded']; + } + + /** + * Get the authorization header with token. + * + * @param AccessToken $accessToken + * + * @return array + */ + public static function getAuth(AccessToken $accessToken) + { + return ['Authorization' => 'Bearer ' . $accessToken->getValue()]; + } + + /** + * Get custom array. + * + * @return array + */ + public static function getTrk() + { + $version = self::getProjectVersion(); + return ['X-SDK' => 'PHP/v' . $version]; + } + + /** + * Get the version of the project accroding to the composer.json + * + * @return string + */ + public static function getProjectVersion() + { + if (is_null(self::$cacheVersion)) { + $pathToComposer = realpath(dirname(__FILE__) . '/../../../composer.json'); + $content = file_get_contents($pathToComposer); + $content = json_decode($content, true); + self::$cacheVersion = $content['version']; + } + + return self::$cacheVersion; + } + + /** + * Get standard headers needed for every request. + * + * @return array + */ + public static function getStandardHeaders() + { + $headers = self::getCTJson(); + $headers += self::getTrk(); + return $headers; + } +}