Skip to content

Commit 7a384f8

Browse files
author
Raúl
authored
Merge pull request #59 from afterpay/improvement/persistance
Adding callback calls as a new Persistence behaviour
2 parents 3ed8c82 + 4862dcf commit 7a384f8

File tree

4 files changed

+161
-53
lines changed

4 files changed

+161
-53
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Version 1.6.0
4+
5+
_Wed 30 Nov 2022_
6+
7+
- Added new Persistence option using callbacks from host (EIT-2275)
8+
39
## Version 1.5.0
410

511
_Fri 26 Aug 2022_

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "afterpay-global/afterpay-sdk-php",
33
"license": "Apache-2.0",
44
"description": "Official Afterpay SDK for PHP",
5-
"version": "1.5.0",
5+
"version": "1.6.0",
66
"authors": [
77
{
88
"name": "Afterpay",

src/Config.php

+40-8
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,36 @@ final class Config
9090
'type' => 'string',
9191
'src' => '.env.php'
9292
],
93+
/**
94+
* These are callback settings - used for persistence abstraction on e-commerce platforms.
95+
*/
96+
'callback.active' => [
97+
'type' => 'boolean'
98+
],
99+
'callback.getLastUpdateDate' => [
100+
'type' => 'string'
101+
],
102+
'callback.setLastUpdateDate' => [
103+
'type' => 'string'
104+
],
105+
'callback.getOrderMinimum' => [
106+
'type' => 'string'
107+
],
108+
'callback.setOrderMinimum' => [
109+
'type' => 'string'
110+
],
111+
'callback.getOrderMaximum' => [
112+
'type' => 'string'
113+
],
114+
'callback.setOrderMaximum' => [
115+
'type' => 'string'
116+
],
117+
'callback.getCurrency' => [
118+
'type' => 'string'
119+
],
120+
'persistence.lifespan' => [
121+
'type' => 'integer'
122+
],
93123
/**
94124
* These are test settings - used only by the Test classes for automated testing.
95125
*/
@@ -189,7 +219,7 @@ private static function loadEnvConfig()
189219
}
190220
} else {
191221
foreach (self::$data as $property => $data) {
192-
if ($data[ 'src' ] == '.env.php') {
222+
if (isset($data[ 'src' ]) && $data[ 'src' ] == '.env.php') {
193223
$value = getenv(self::lowerCamelDotNotationToAllcapSnakeCase($property));
194224

195225
if ($value !== false) {
@@ -264,13 +294,15 @@ public static function set($property, $value)
264294
public static function get($property)
265295
{
266296
if (array_key_exists($property, self::$data)) {
267-
if (self::$data[ $property ][ 'src' ] == '.env.php') {
268-
if (! self::$envConfigLoaded) {
269-
self::loadEnvConfig();
270-
}
271-
} elseif (self::$data[ $property ][ 'src' ] == 'composer.json') {
272-
if (! self::$composerJsonLoaded) {
273-
self::loadComposerJson();
297+
if (isset(self::$data[ $property ][ 'src' ])) {
298+
if (self::$data[ $property ][ 'src' ] == '.env.php') {
299+
if (! self::$envConfigLoaded) {
300+
self::loadEnvConfig();
301+
}
302+
} elseif (self::$data[ $property ][ 'src' ] == 'composer.json') {
303+
if (! self::$composerJsonLoaded) {
304+
self::loadComposerJson();
305+
}
274306
}
275307
}
276308

src/PersistentStorage.php

+114-44
Original file line numberDiff line numberDiff line change
@@ -91,56 +91,82 @@ public static function testConnection()
9191
private $db_user;
9292
private $db_pass;
9393
private $db_connection;
94+
private $callback_active;
95+
private $callback_getLastUpdateDate;
96+
private $callback_setLastUpdateDate;
97+
private $callback_getOrderMinimum;
98+
private $callback_setOrderMinimum;
99+
private $callback_getOrderMaximum;
100+
private $callback_setOrderMaximum;
101+
private $callback_getCurrency;
94102

95103
public function __construct()
96104
{
97-
//echo get_class( $this ) . "::__construct()\n";
98-
99105
$this->db_api = Config::get('db.api');
100-
$this->db_host = Config::get('db.host');
101-
$this->db_port = Config::get('db.port');
102-
$this->db_database = Config::get('db.database');
103-
$this->db_tablePrefix = Config::get('db.tablePrefix');
104-
$this->db_user = Config::get('db.user');
105-
$this->db_pass = Config::get('db.pass');
106-
107-
if ($this->db_api == 'mysqli') {
108-
if (extension_loaded('mysqli')) {
109-
/**
110-
* @see https://www.php.net/manual/en/mysqli.construct.php
111-
*/
106+
$this->callback_active = Config::get('callback.active');
112107

113-
if (empty($this->db_host)) {
114-
$this->db_host = ini_get('mysqli.default_host');
108+
$lifespan = Config::get('persistence.lifespan');
109+
if (!empty($lifespan)) {
110+
foreach ($this->data as &$merchantProperty) {
111+
if (isset($merchantProperty[ 'lifespan' ])) {
112+
$merchantProperty[ 'lifespan' ] = $lifespan;
115113
}
114+
}
115+
}
116116

117-
if (empty($this->db_user)) {
118-
$this->db_user = ini_get('mysqli.default_user');
119-
}
117+
if (!empty($this->db_api)) {
118+
$this->db_host = Config::get('db.host');
119+
$this->db_port = Config::get('db.port');
120+
$this->db_database = Config::get('db.database');
121+
$this->db_tablePrefix = Config::get('db.tablePrefix');
122+
$this->db_user = Config::get('db.user');
123+
$this->db_pass = Config::get('db.pass');
124+
if ($this->db_api == 'mysqli') {
125+
if (extension_loaded('mysqli')) {
126+
/**
127+
* @see https://www.php.net/manual/en/mysqli.construct.php
128+
*/
120129

121-
if (empty($this->db_pass)) {
122-
$this->db_pass = ini_get('mysqli.default_pw');
123-
}
130+
if (empty($this->db_host)) {
131+
$this->db_host = ini_get('mysqli.default_host');
132+
}
124133

125-
if (empty($this->db_port)) {
126-
$this->db_port = ini_get('mysqli.default_port');
127-
}
134+
if (empty($this->db_user)) {
135+
$this->db_user = ini_get('mysqli.default_user');
136+
}
137+
138+
if (empty($this->db_pass)) {
139+
$this->db_pass = ini_get('mysqli.default_pw');
140+
}
141+
142+
if (empty($this->db_port)) {
143+
$this->db_port = ini_get('mysqli.default_port');
144+
}
128145

129-
# It's safe to suppress any errors/warnings/notices here because
130-
# if we can't connect we'll throw an Exception anyway.
131-
set_error_handler(function () {
132-
});
133-
$this->db_connection = new \mysqli($this->db_host, $this->db_user, $this->db_pass, $this->db_database, $this->db_port);
134-
restore_error_handler();
146+
# It's safe to suppress any errors/warnings/notices here because
147+
# if we can't connect we'll throw an Exception anyway.
148+
set_error_handler(function () {
149+
});
150+
$this->db_connection = new \mysqli($this->db_host, $this->db_user, $this->db_pass, $this->db_database, $this->db_port);
151+
restore_error_handler();
135152

136-
if ($this->db_connection->connect_errno) {
137-
throw new Exception($this->db_connection->connect_error, $this->db_connection->connect_errno);
153+
if ($this->db_connection->connect_errno) {
154+
throw new Exception($this->db_connection->connect_error, $this->db_connection->connect_errno);
155+
}
156+
} else {
157+
throw new Exception("Required extension 'mysqli' not loaded");
138158
}
139159
} else {
140-
throw new Exception("Required extension 'mysqli' not loaded");
160+
throw new Exception("No available database API");
141161
}
142-
} else {
143-
throw new Exception("No available database API");
162+
} elseif (isset($this->callback_active) && $this->callback_active === true) {
163+
$this->callback_getLastUpdateDate = Config::get('callback.getLastUpdateDate');
164+
$this->callback_setLastUpdateDate = Config::get('callback.setLastUpdateDate');
165+
$this->callback_getOrderMinimum = Config::get('callback.getOrderMinimum');
166+
$this->callback_setOrderMinimum = Config::get('callback.setOrderMinimum');
167+
$this->callback_getOrderMaximum = Config::get('callback.getOrderMaximum');
168+
$this->callback_setOrderMaximum = Config::get('callback.setOrderMaximum');
169+
$this->callback_getCurrency = Config::get('callback.getCurrency');
144170
}
145171
}
146172

@@ -160,14 +186,6 @@ public function __destruct()
160186
private function getProperty($property, $merchant)
161187
{
162188
if (array_key_exists($property, $this->data)) {
163-
/**
164-
* E.g. Given the default value of $this->db_tablePrefix ("afterpay_"):
165-
* "Afterpay\SDK\Money" --> "\Money" --> "Money" --> "afterpay_Money"
166-
*
167-
* @todo Create a method for converting UpperCamelCase to snake_case
168-
* because the mysqli driver may be case insensitive.
169-
*/
170-
$table_name = preg_replace('/[^a-z0-9_]+/i', '', $this->db_tablePrefix . substr(strrchr($this->data[ $property ][ 'type' ], '\\'), 1));
171189
$need_to_get_fresh_data = false;
172190
$properties_to_update = [];
173191
$return = null;
@@ -180,6 +198,14 @@ private function getProperty($property, $merchant)
180198
}
181199

182200
if ($this->db_api == 'mysqli') {
201+
/**
202+
* E.g. Given the default value of $this->db_tablePrefix ("afterpay_"):
203+
* "Afterpay\SDK\Money" --> "\Money" --> "Money" --> "afterpay_Money"
204+
*
205+
* @todo Create a method for converting UpperCamelCase to snake_case
206+
* because the mysqli driver may be case insensitive.
207+
*/
208+
$table_name = preg_replace('/[^a-z0-9_]+/i', '', $this->db_tablePrefix . substr(strrchr($this->data[ $property ][ 'type' ], '\\'), 1));
183209
$escaped_table_name = $this->db_connection->real_escape_string($table_name);
184210

185211
if (in_array($property, [ 'orderMinimum', 'orderMaximum' ])) {
@@ -279,6 +305,33 @@ private function getProperty($property, $merchant)
279305
}
280306
}
281307
}
308+
} elseif ($this->callback_active == true) {
309+
$callbackGetFnName = 'callback_get' . ucfirst($property);
310+
$callbackSetFnName = 'callback_set' . ucfirst($property);
311+
$updatedAt = date('Y-m-d H:i:s', strtotime('-1 year'));
312+
if (is_callable($this->callback_getLastUpdateDate)) {
313+
$updatedAt = call_user_func($this->callback_getLastUpdateDate);
314+
} else {
315+
throw new Exception("Function '{$this->callback_getLastUpdateDate}' is not callable or doesn't exist");
316+
}
317+
if (time() - strtotime($updatedAt) > $this->data[ $property ][ 'lifespan' ]) {
318+
// update minimum and maximum values
319+
$properties_to_update[] = $property;
320+
$need_to_get_fresh_data = true;
321+
} else {
322+
if (is_callable($this->{$callbackGetFnName})) {
323+
if (is_callable($this->callback_getCurrency)) {
324+
$return = new Money([
325+
'amount' => call_user_func($this->{$callbackGetFnName}),
326+
'currency' => call_user_func($this->callback_getCurrency),
327+
]);
328+
} else {
329+
throw new Exception("Function '{$this->callback_getCurrency}' is not callable or doesn't exist");
330+
}
331+
} else {
332+
throw new Exception("Function '{$this->{$callbackGetFnName}}' is not callable or doesn't exist");
333+
}
334+
}
282335
} else {
283336
$need_to_get_fresh_data = true;
284337
}
@@ -334,6 +387,23 @@ private function getProperty($property, $merchant)
334387
);
335388
$update_stmt->execute();
336389
$update_stmt->close();
390+
} elseif ($this->callback_active == true) {
391+
if (is_callable($this->callback_setOrderMinimum) && isset($responseBody->minimumAmount)) {
392+
call_user_func($this->callback_setOrderMinimum, $responseBody->minimumAmount->amount);
393+
} else {
394+
throw new Exception("Function '{$this->callback_setOrderMinimum}' is not callable or doesn't exist");
395+
}
396+
if (is_callable($this->callback_setOrderMaximum) && isset($responseBody->maximumAmount)) {
397+
call_user_func($this->callback_setOrderMaximum, $responseBody->maximumAmount->amount);
398+
} else {
399+
throw new Exception("Function '{$this->callback_setOrderMaximum}' is not callable or doesn't exist");
400+
}
401+
if (is_callable($this->callback_setLastUpdateDate)) {
402+
$now = date('Y-m-d H:i:s');
403+
call_user_func($this->callback_setLastUpdateDate, $now);
404+
} else {
405+
throw new Exception("Function '{$this->callback_setLastUpdateDate}' is not callable or doesn't exist");
406+
}
337407
}
338408
} else {
339409
if ($this->db_api == 'mysqli') {

0 commit comments

Comments
 (0)