Skip to content

Commit

Permalink
feat(core): release v2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
m.vela committed Jul 15, 2019
1 parent 1f9576a commit 558e23f
Show file tree
Hide file tree
Showing 357 changed files with 23,438 additions and 2,539 deletions.
110 changes: 61 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@

> Codebase for Payvision PHP SDK
This is the official PHP SDK for Payvision payments platform (<https://www.payvision.com>).
It can be used to make use of the following features of the [Payvision API](https://developers.acehubpaymentservices.com/reference):

- Make payment requests
- Make refund requests
- Get transaction status updates
This is the official PHP SDK for the Payvision payment platform (<https://www.payvision.com>).
It can be used to make use of the following features of the Payvision API:

- Payments
- Make payment requests
- Make capture requests
- Make cancel requests
- Make refund requests
- Get transaction status updates
- Paymentlink
- Make new paymentlink
- Get status of existing paymentlink
- Cancel existing paymentlink
- Checkout
- Initialize new checkout
- Get checkout status
- Webhooks
- Convert RAW webhook data to the proper objects

## Install

Expand All @@ -26,16 +38,15 @@ To initialize the API Connection, refer to the following code snippet:
$apiConnection = new ApiConnection(
'username',
'password',
'business ID',
ApiConnection::URI_TEST, // =URL to connect to, optional
false // debug mode, see debugging
);

#### Debugging the API

The API uses the [Guzzle HTTP Client](http://docs.guzzlephp.org/en/stable/).
The debug-property is passed through to the Guzzle Client. See
<http://docs.guzzlephp.org/en/stable/request-options.html#debug> for more
The API uses the [Guzzle HTTP Client](http://docs.guzzlephp.org/en/stable/).
The debug-property is passed through to the Guzzle Client. See
<http://docs.guzzlephp.org/en/stable/request-options.html#debug> for more
information about debugging.

### Creating a payment request
Expand Down Expand Up @@ -66,96 +77,97 @@ a JSON body like this:
}
}
}

To create this identical request using the PHP SDK, you can use one of
the composite builders:

use Payvision\SDK\Domain\Payments\Service\Builder\Composite\Request\Object as RequestObjectBuilder;
use Payvision\SDK\Domain\Payments\ValueObject\Request\Object as RequestObject;
use Payvision\SDK\Domain\Payments\Service\Builder\Composite\Payment\Request as PaymentRequestBuilder;
use Payvision\SDK\Domain\Payments\ValueObject\Payment\Request as PaymentRequest;

$this->requestObjectBuilder->header()->setBusinessId('{businessId}');
$this->requestObjectBuilder->body()->card()
/** @var $paymentRequestBuilder PaymentRequestBuilder */
$paymentRequestBuilder->header()->setBusinessId('{businessId}');
$paymentRequestBuilder->body()->card()
->setHolderName('John Doe')
->setNumber('4111111111111111')
->setExpiryMonth(3)
->setExpiryYear(2020)
$this->requestObjectBuilder->body()->transaction()
$paymentRequestBuilder->body()->transaction()
->setAmount(1.00)
->setBrandId(1010)
->setTrackingCode('7F4BFD5D-55E4-4775-81F7-0784188876C7')
->setCurrencyCode('EUR');
$this->requestObjectBuilder->setAction(RequestObject::ACTION_AUTHORIZE);
$requestObject = $this->requestObjectBuilder->build();

$paymentRequestBuilder->setAction(PaymentRequest::ACTION_AUTHORIZE);
$requestObject = $paymentRequestBuilder->build();
At this point, you have a PHP representation of the JSON object that is to
be sent to the API, but it is not yet the actual request. For example: we
be sent to the API, but it is not yet the actual request. For example: we
still need to know the URL where it needs to be sent to, and what kind of
response we can expect from the API.
response we can expect from the API.

To do this we need to transform our payment request to an API request:

use Payvision\SDK\Application\Payments\Service\RequestBuilder;
$apiRequest = RequestBuilder::newPayment($requestObject);

use Payvision\SDK\Application\Payments\Service\RequestBuilder;
$apiRequest = RequestBuilder::newPayment($requestObject);
Now we have an API Request that we can execute using our API Connection:

$apiResponse = $apiConnection->execute($apiRequest);

### Handling the responses

The `$apiResponse` in the above example is an object of the type that is
defined in the request. To know what kind of type this is, you can use
defined in the request. To know what kind of type this is, you can use
`$apiRequest->getResponseObjectByStatusCode(200)`.

If the API returns a non-2XX status, an exception is thrown of the type
`Payvision\SDK\Exception\Api\ErrorResponse`. This exception has the
`Payvision\SDK\Exception\Api\ErrorResponse`. This exception has the
error object with more information about what went wrong:

try {
$apiResponse = $apiConnection->execute($apiRequest);
} catch (ErrorResponse $errorResponseException) {
/** \Payvision\SDK\Domain\Payments\ValueObject\Response\Error $apiResponse */
/** \Payvision\SDK\Domain\Payments\ValueObject\Payment\Response $apiResponse */
$errorResponse = $errorResponseException->getErrorResponse();
}

## Webhooks

Webhooks can also be handled by the SDK. In order to do so you need the
Webhooks can also be handled by the SDK. In order to do so you need the
following input data:

- The Event Signature (also known as a Json Web Token (JWT). This is sent in the header)
- The secret that is used to sign the JWT
- The body of the webhook (as string).
- The Event Signature (also known as a Json Web Token (JWT). This is sent in the header)
- The secret that is used to sign the JWT
- The body of the webhook (as string).

You can pass this data to the `EventBuilder` service of the webhook:

use Payvision\SDK\Application\Reflection\JsonToObject;
use Payvision\SDK\Application\Webhook\Service\EventBuilder;
use Payvision\SDK\Domain\Webhook\Service\Validator;

$eventBuilderService = new EventBuilder(
new Validator(),
new JsonToObject()
);

$event = $eventBuilderService->generateEvent(
'event signature',
'secret',
'json body'
);

Since the payload of the webhook event can be a variety of objects, the
`Event::getPayload()` cannot be type-hinted. So you might want to do some
extra checks on this:

$payload = $event->getPayload();
if ($payload instanceof \Payvision\SDK\Domain\Payments\ValueObject\Response\Request) {
...
}
}

If you don't want this (because it might miss auto-completion in your IDE because of this), you
can also use `EventBuilder::generateDecoratedEvent()` to get a `EventDecorator`
that provides extra functionality so you don't have to guess what the
can also use `EventBuilder::generateDecoratedEvent()` to get a `EventDecorator`
that provides extra functionality so you don't have to guess what the
payload is:

$decoratedEvent = $eventBuilderService->generateDecoratedEvent(
Expand All @@ -164,8 +176,8 @@ payload is:
'json body'
);

if ($decoratedEvent->getPayloadType() === \Payvision\SDK\Domain\Webhook\Service\EventDecorator::TYPE_REQUEST) {
$payload = $decoratedEvent->getRequestResponse();
if ($decoratedEvent->getPayloadType() === \Payvision\SDK\Domain\Webhook\Service\EventDecorator::TYPE_PAYMENT) {
$payload = $decoratedEvent->getPaymentResponse();
}

The decorator also has some additional checks to make sure that the payload is known.
Expand All @@ -178,29 +190,29 @@ information, targeted at developers:
### Architecture

The SDK is setup in a Domain Driven way. At the core are Value Objects,
which are the stateless building blocks that are used in the API. Above
that there are the aggregates, these combine the various Value Objects
into implementations.
which are the stateless, immutable building blocks that are used in the API.
Value Objects can have other value objects as child-properties.

Aggregates are then converted to request objects, which are send to the
API, which in turn returns a response object. Logic goes from bottom to
top, dependencies go from top to bottom:
Top-level Value Objects (like a Payment Request) are converted to API
request objects, which are send to the API, which in turn returns a
response object. Logic goes from bottom to top, dependencies go from top
to bottom:

+-------------------+
| Value Object | Example: Transaction, Bank, Card, etc.
| | These can be built manually, or by using the (composite) builders
+-------------------+
Request Builder Builds request out of aggregate using reflection.
+-------------------+
| Request |
| Request |
+-------------------+
API Client Does the request to the external API
Response Builder Generates a response object out of the API response data using reflection.
+-------------------+
| Response | Example: PaymentResponse
+-------------------+
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "payvision/payvision-sdk-php",
"description": "Payvision PHP SDK",
"type": "library",
"version": "1.0.0",
"version": "2.0.0",
"license": "MIT",
"require": {
"php": "^7.0.13|^7.1",
Expand All @@ -18,7 +18,7 @@
},
"autoload-dev": {
"psr-4": {
"Payvision\\SDK\\Test\\": "tests"
"Payvision\\SDK\\Test\\": "tests/Test"
}
},
"require-dev": {
Expand Down
9 changes: 7 additions & 2 deletions phpcs.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
@license see LICENSE.txt
@copyright Copyright (c) 2018-2019 Payvision B.V. (https://www.payvision.com/)
@copyright Copyright (c) 2018 Payvision B.V. (https://www.payvision.com/)
@license see LICENCE.TXT
-->
<ruleset>
<!-- include root folder of project -->
Expand All @@ -13,6 +13,11 @@

<!-- This code is generated and therefore excluded from static code analysis: -->
<exclude-pattern>./src/Domain/Payments</exclude-pattern>
<exclude-pattern>./src/Domain/Checkouts</exclude-pattern>
<exclude-pattern>./src/Domain/Paymentlink</exclude-pattern>
<exclude-pattern>./src/Application/Payments</exclude-pattern>
<exclude-pattern>./src/Application/Checkouts</exclude-pattern>
<exclude-pattern>./src/Application/Paymentlink</exclude-pattern>

<!-- Arguments -->
<arg value="sp"/>
Expand Down
80 changes: 80 additions & 0 deletions src/Application/Checkouts/Service/RequestBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2018-2019 Payvision B.V. (https://www.payvision.com/)
* @license see LICENCE.TXT
*
* Warning! This file is auto-generated! Any changes made to this file will be deleted in the future!
*/

namespace Payvision\SDK\Application\Checkouts\Service;

use Payvision\SDK\Domain\Checkouts\ValueObject\Checkout\Request as CheckoutRequest;
use Payvision\SDK\Domain\Checkouts\ValueObject\Checkout\Response as CheckoutResponse;
use Payvision\SDK\Domain\Checkouts\ValueObject\Status\Response as StatusResponse;
use Payvision\SDK\Application\Request\Builder;
use Payvision\SDK\Application\ApiRequest;

class RequestBuilder
{
public static function newCheckout(
CheckoutRequest $input

): ApiRequest
{
$jsonBody = Builder::toArray($input);
return new ApiRequest(
'checkouts',
'POST',
self::getParameters($jsonBody),
$jsonBody['header'] ?? [],
$jsonBody['body'] ?? [],
[],
[
200 => CheckoutResponse::class,
400 => CheckoutResponse::class,
500 => CheckoutResponse::class,
501 => CheckoutResponse::class,
]
);
}

public static function getCheckoutStatus(

string $id,
string $businessId
): ApiRequest
{
return new ApiRequest(
\str_replace('{id}', $id, 'checkouts/{id}'),
'GET',
[],
[],
[],
[
'businessId' => $businessId
],
[
200 => StatusResponse::class,
400 => StatusResponse::class,
500 => StatusResponse::class,
501 => StatusResponse::class,
]
);
}

private static function getParameters(array $input): array
{
$parameters = [];

foreach ($input as $key => $value) {
if ($key !== 'header' && $key !== 'body') {
$parameters[$key] = $value;
}
}

return $parameters;
}
}
Loading

0 comments on commit 558e23f

Please sign in to comment.