Skip to content

Commit c8f7ea3

Browse files
Add shape validator; fix date for fingerprints
1 parent ae18ae7 commit c8f7ea3

5 files changed

Lines changed: 148 additions & 5 deletions

File tree

src/MerchantApi/MerchantApi.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* @property Balance balance
1818
* @property Profile profile
1919
* @property StatusCodes status_codes
20+
* @property PermissionRequests permission_requests
2021
*/
2122
class MerchantApi extends SettleApi
2223
{
@@ -35,6 +36,7 @@ protected function getMagicProperties()
3536
'settlements' => Settlements::class,
3637
'short_links' => ShortLinks::class,
3738
'status_codes' => StatusCodes::class,
39+
'permission_requests' => PermissionRequests::class,
3840
];
3941
}
4042
}

src/SettleApi.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ final public function __construct(SettleApiClient $api_client)
2424
* @param string $method
2525
* @param string $path
2626
* @param array $data
27+
* @param array $shape
2728
* @return array
2829
* @throws SettleApiException
2930
*/
30-
final protected function call(string $method, string $path, array $data = [])
31+
final protected function call(string $method, string $path, array $data = [], $shape = [])
3132
{
32-
return $this->api_client->call($method, $path, $data);
33+
return $this->api_client->call($method, $path, $data, $shape);
3334
}
3435

3536
/**

src/SettleApiClient.php

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace SettleApi;
44

5+
use DateTime;
6+
use DateTimeZone;
7+
58
/**
69
* Class SettleApiClient
710
* @package SettleApi
@@ -14,6 +17,7 @@ class SettleApiClient
1417
protected string $publicKey;
1518
protected string $privateKey;
1619
protected bool $isSandbox;
20+
protected bool $validateShapes = true;
1721

1822
const BASE_URL_PRODUCTION = 'https://api.settle.eu/merchant/v1/';
1923
const BASE_URL_SANDBOX = 'https://api.sandbox.settle.eu/merchant/v1/';
@@ -69,15 +73,37 @@ public function setIsSandbox($isSandbox)
6973
$this->isSandbox = $isSandbox;
7074
}
7175

76+
/**
77+
* @return bool
78+
*/
79+
public function getValidateShapes()
80+
{
81+
return $this->validateShapes;
82+
}
83+
84+
/**
85+
* @param $validateShapes
86+
*/
87+
public function setValidateShapes($validateShapes)
88+
{
89+
$this->validateShapes = $validateShapes;
90+
}
91+
7292
/**
7393
* @param string $method
7494
* @param string $path
7595
* @param array $postFields
96+
* @param array $shape
7697
* @return array|bool
7798
* @throws SettleApiException
7899
*/
79-
public function call(string $method, string $path, array $postFields = [])
100+
public function call(string $method, string $path, array $postFields = [], $shape = [])
80101
{
102+
if ($this->validateShapes && !empty($shape)) {
103+
$validator = new ShapeValidator($shape, $postFields);
104+
$validator->validate();
105+
}
106+
81107
$method = strtoupper($method);
82108
$path = ltrim($path, '/');
83109
$url = $this->getApiBaseUrl() . $path;
@@ -111,12 +137,17 @@ public function call(string $method, string $path, array $postFields = [])
111137
case $httpCode >= 200 && $httpCode < 300:
112138
return $response;
113139

140+
case $httpCode == 404:
141+
throw new SettleApiException("The resource could not be found.", $httpCode);
142+
114143
default:
115144
if ($response !== null) {
116145
$message = $response['error_description'] ?? $response['error_detail'] ?? $response['error_type'] ?? 'Something went wrong.';
117146
throw new SettleApiException($message, $httpCode);
118147
}
119-
throw new SettleApiException('Something went wrong.', $httpCode);
148+
149+
$errorMessage = !empty($response_body) ? $response_body : 'Something went wrong.';
150+
throw new SettleApiException($errorMessage, $httpCode);
120151
}
121152
}
122153

@@ -146,10 +177,11 @@ protected function getHeaders(string $method, string $url, array $postFields): a
146177
'Content-Length: ' . strlen($content),
147178
];
148179

180+
$date = (new DateTime())->setTimezone(new DateTimeZone('UTC'));
149181
$settle_headers = [
150182
'x-settle-merchant' => $this->merchantId,
151183
'x-settle-user' => $this->userId,
152-
'x-settle-timestamp' => date('Y-m-d H:i:s'),
184+
'x-settle-timestamp' => $date->format('Y-m-d H:i:s'),
153185
'x-settle-content-digest' => 'SHA256=' . $content_digest,
154186
];
155187

src/SettleApiException.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,31 @@
33
namespace SettleApi;
44

55
use Exception;
6+
use Throwable;
67

78
/**
89
* Class SettleApiException
910
* @package SettleApi
1011
*/
1112
class SettleApiException extends Exception
1213
{
14+
/**
15+
* @var array A list of error messages for every field (array key)
16+
*/
17+
protected $validationErrors;
18+
19+
public function __construct($message = "", $code = 0, Throwable $previous = null, $validationErrors = [])
20+
{
21+
parent::__construct($message, $code, $previous);
22+
23+
$this->validationErrors = $validationErrors;
24+
}
25+
26+
/**
27+
* @return array A list of error messages for every field (array key)
28+
*/
29+
public function getValidationErrors()
30+
{
31+
return $this->validationErrors;
32+
}
1333
}

src/ShapeValidator.php

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
4+
namespace SettleApi;
5+
6+
7+
class ShapeValidator
8+
{
9+
protected $shape;
10+
protected $data;
11+
12+
/**
13+
* @param array $shape
14+
* @param array $data
15+
*/
16+
public function __construct($shape = [], $data = [])
17+
{
18+
$this->shape = $shape;
19+
$this->data = $data;
20+
}
21+
22+
public function validate()
23+
{
24+
$errors = [];
25+
26+
$extra_keys = array_diff(array_keys($this->data), array_keys($this->shape));
27+
foreach($extra_keys as $extra_key) {
28+
$errors[$extra_key] = "Field '{$extra_key}' is not supported.";
29+
}
30+
31+
foreach($this->shape as $key => $rules) {
32+
if (!is_array($rules)) $rules = explode('|', $rules);
33+
34+
$error = $this->validateField($key, $rules);
35+
36+
if ($error != '') {
37+
$errors[$key] = $error;
38+
}
39+
}
40+
41+
if (!empty($errors)) {
42+
throw new SettleApiException("Shape validation error", 400, null, $errors);
43+
}
44+
}
45+
46+
/**
47+
* @param string $key
48+
* @param array $rules
49+
* @return string
50+
*/
51+
protected function validateField($key, $rules)
52+
{
53+
$error = '';
54+
$value = $this->data[$key] ?? null;
55+
56+
foreach ($rules as $rule) {
57+
$error = $this->validateValue($key, $value, $rule);
58+
if ($error != '') break;
59+
}
60+
61+
return $error;
62+
}
63+
64+
protected function validateValue($key, $value, $rule)
65+
{
66+
$error = '';
67+
68+
switch($rule) {
69+
case 'required':
70+
if (is_null($value)) {
71+
$error = "Field '{$key}' is required.";
72+
}
73+
break;
74+
case 'string':
75+
if (!is_null($value) && !is_string($value)) {
76+
$error = "Field '{$key}' is must be a string.";
77+
}
78+
break;
79+
case 'numeric':
80+
if (!is_null($value) && !is_numeric($value)) {
81+
$error = "Field '{$key}' is must have numeric value.";
82+
}
83+
break;
84+
}
85+
86+
return $error;
87+
}
88+
}

0 commit comments

Comments
 (0)