From 4b4e10ca857e8bf14ceddfd582ebbd00fc97a26d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 08:53:15 +0100 Subject: [PATCH 01/24] Url encoded headers --- src/Utilities/RequestParser.php | 25 ++++++++++--- .../JWSVerifiedPaymentNotification.php | 37 +++++++++++-------- .../JWSVerifiedPaymentNotificationTest.php | 21 +++++++++++ 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/Utilities/RequestParser.php b/src/Utilities/RequestParser.php index 2783706..07e1b24 100644 --- a/src/Utilities/RequestParser.php +++ b/src/Utilities/RequestParser.php @@ -4,10 +4,13 @@ class RequestParser { + /** @var string|null */ + private $rawBody; + /** @return string */ public function getContentType() { - return $_SERVER['CONTENT_TYPE'] ?: ''; + return isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : ''; } /** @@ -17,11 +20,14 @@ public function getContentType() */ public function getParsedContent() { - if ('application/json' === $this->getContentType()) { - $body = file_get_contents('php://input'); + if (strpos($this->getContentType(), 'application/json') !== false) { + $body = $this->getRawBody(); $jsonData = json_decode($body, true); + if (is_null($jsonData)) { - throw new TpayException('Invalid JSON body. Json Error: '.json_last_error_msg().' Body: '.$body); + throw new TpayException( + 'Invalid JSON body. Json Error: ' . json_last_error_msg() . ' Body: ' . $body + ); } return $jsonData; @@ -33,7 +39,7 @@ public function getParsedContent() /** @return string */ public function getPayload() { - return file_get_contents('php://input'); + return $this->getRawBody(); } /** @@ -50,4 +56,13 @@ public function getSignature() return $jws; } + + private function getRawBody() + { + if ($this->rawBody === null) { + $this->rawBody = file_get_contents('php://input'); + } + + return $this->rawBody; + } } diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index 68fa065..accfe26 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -164,12 +164,12 @@ private function getResourcePrefix() */ private function getNotificationObject() { - if ('application/json' === $this->requestParser->getContentType()) { - $jsonData = $this->requestParser->getParsedContent(); - if (!isset($jsonData['type'])) { - throw new TpayException('Not recognised or invalid notification type. JSON: '.json_encode($jsonData)); - } - switch ($jsonData['type']) { + $source = $this->requestParser->getParsedContent(); + + if (isset($source['tr_id'])) { + $requestBody = new BasicPayment(); + } elseif (isset($source['type'])) { + switch ($source['type']) { case 'tokenization': $requestBody = new Tokenization(); break; @@ -180,24 +180,29 @@ private function getNotificationObject() $requestBody = new MarketplaceTransaction(); break; default: - throw new TpayException('Not recognised or invalid notification type. JSON: '.json_encode($jsonData)); + throw new TpayException( + 'Not recognised or invalid notification type: ' . $source['type'] + ); } - if (!isset($jsonData['data'])) { - throw new TpayException('Not recognised or invalid notification type. JSON: '.json_encode($jsonData)); + if (!isset($source['data'])) { + throw new TpayException('Not recognised or invalid notification type: '.json_encode($source)); } - $source = $jsonData['data']; + $source = $source['data']; } else { - $source = $this->requestParser->getParsedContent(); - if (!isset($source['tr_id'])) { - throw new TpayException('Not recognised or invalid notification type. POST: '.json_encode($source)); - } - $requestBody = new BasicPayment(); + throw new TpayException( + 'Cannot determine notification type. POST payload: ' . json_encode($source) + ); } + foreach ($source as $parameter => $value) { if (isset($requestBody->{$parameter})) { - $source[$parameter] = Util::cast($value, $requestBody->{$parameter}->getType()); + $source[$parameter] = Util::cast( + $value, + $requestBody->{$parameter}->getType() + ); } } + $this->Manager ->setRequestBody($requestBody) ->setFields($source, false); diff --git a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php index 5cf25f3..88dfd96 100644 --- a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php +++ b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php @@ -87,6 +87,9 @@ public function positiveValidationProvider() $data = json_decode($payload, true); $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $payload = http_build_query($data); + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $payload = <<<'JSON' { "type": "token_update", @@ -98,6 +101,9 @@ public function positiveValidationProvider() $data = json_decode($payload, true); $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, TokenUpdate::class, 'token', '1234567890123456789012345678901234567890123456789012345678901234']; + $payload = http_build_query($data); + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, TokenUpdate::class, 'token', '1234567890123456789012345678901234567890123456789012345678901234']; + $payload = <<<'JSON' { "type": "marketplace_transaction", @@ -118,6 +124,9 @@ public function positiveValidationProvider() $data = json_decode($payload, true); $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, MarketplaceTransaction::class, 'transactionId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $payload = http_build_query($data); + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, MarketplaceTransaction::class, 'transactionId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $id = '12345'; $tr_id = 'TR-1234-89012345678901234567890'; $tr_amount = '144.69'; @@ -203,21 +212,33 @@ public function negativeValidationProvider() $data = json_decode($payload, true); $result[] = ['application/json', $data, $payload, 'x', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, 'x', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + // invalid signature (malformed token) $result[] = ['application/json', $data, $payload, 'fdsafsdfafdasfadsf', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, 'fdsafsdfafdasfadsf', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + // invalid signature (payload difference) $result[] = ['application/json', $data, $payload, $this->sign($payload.'4324324324234', true), 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload.'4324324324234', true), 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + // invalid signature (invalid algorithm) $result[] = ['application/json', $data, $payload, $this->encode(json_encode(['alg' => 'none'])).'..fadsfdasfdsf', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->encode(json_encode(['alg' => 'none'])).'..fadsfdasfdsf', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + // invalid signature (not trusted signature URL) $result[] = ['application/json', $data, $payload, $this->encode(json_encode(['alg' => 'RS256', 'x5u' => 'https://example.com/hostile.pem'])).'..fadsfdasfdsf', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->encode(json_encode(['alg' => 'RS256', 'x5u' => 'https://example.com/hostile.pem'])).'..fadsfdasfdsf', 'x', true, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + // invalid signature (prod certificate in sandbox environment) $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', false, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', false, Tokenization::class, 'tokenizationId', 'TO-1234-890123456789012345678901234567890123456789012345678901234']; + // invalid md5sum $id = '12345'; $tr_id = 'TR-1234-89012345678901234567890'; From b6f35a60d5fad62451b6a9234e19fec9575de7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 08:57:21 +0100 Subject: [PATCH 02/24] fixer --- src/Utilities/RequestParser.php | 6 +++--- src/Webhook/JWSVerifiedPaymentNotification.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Utilities/RequestParser.php b/src/Utilities/RequestParser.php index 07e1b24..1b60628 100644 --- a/src/Utilities/RequestParser.php +++ b/src/Utilities/RequestParser.php @@ -20,13 +20,13 @@ public function getContentType() */ public function getParsedContent() { - if (strpos($this->getContentType(), 'application/json') !== false) { + if (false !== strpos($this->getContentType(), 'application/json')) { $body = $this->getRawBody(); $jsonData = json_decode($body, true); if (is_null($jsonData)) { throw new TpayException( - 'Invalid JSON body. Json Error: ' . json_last_error_msg() . ' Body: ' . $body + 'Invalid JSON body. Json Error: '.json_last_error_msg().' Body: '.$body ); } @@ -59,7 +59,7 @@ public function getSignature() private function getRawBody() { - if ($this->rawBody === null) { + if (null === $this->rawBody) { $this->rawBody = file_get_contents('php://input'); } diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index accfe26..5f84e85 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -181,7 +181,7 @@ private function getNotificationObject() break; default: throw new TpayException( - 'Not recognised or invalid notification type: ' . $source['type'] + 'Not recognised or invalid notification type: '.$source['type'] ); } if (!isset($source['data'])) { @@ -190,7 +190,7 @@ private function getNotificationObject() $source = $source['data']; } else { throw new TpayException( - 'Cannot determine notification type. POST payload: ' . json_encode($source) + 'Cannot determine notification type. POST payload: '.json_encode($source) ); } From f5ee7b9225b86b955d005291f13732aef659ff54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 08:58:39 +0100 Subject: [PATCH 03/24] fixer --- src/Utilities/RequestParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/RequestParser.php b/src/Utilities/RequestParser.php index 1b60628..f15c973 100644 --- a/src/Utilities/RequestParser.php +++ b/src/Utilities/RequestParser.php @@ -4,7 +4,7 @@ class RequestParser { - /** @var string|null */ + /** @var null|string */ private $rawBody; /** @return string */ From da2d34ed1595ff5877829a5e8137ce80fd6695ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:13:55 +0100 Subject: [PATCH 04/24] composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5dd7fcf..44d8516 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^5.7.27 || ^9.6.10", + "phpunit/phpunit": "^7.5 || ^9.6.10", "psx/cache": "^v1.0.2" }, "autoload": { From dabd36b8b6688ae13c300948e6a4338e588f6253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:15:35 +0100 Subject: [PATCH 05/24] composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 44d8516..0666f8e 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^7.5 || ^9.6.10", + "phpunit/phpunit": "^5.7 || ^7.5 || ^9.6", "psx/cache": "^v1.0.2" }, "autoload": { From db95103361fcb1f30ef4d293546dd2c602696aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:21:41 +0100 Subject: [PATCH 06/24] composer --- .github/actions/composer-install/action.yml | 5 +++++ composer.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/actions/composer-install/action.yml b/.github/actions/composer-install/action.yml index 5e895cf..00e30dd 100644 --- a/.github/actions/composer-install/action.yml +++ b/.github/actions/composer-install/action.yml @@ -4,6 +4,11 @@ description: "Install composer dependencies with cache" runs: using: composite steps: + - name: Configure Composer PHP platform + shell: bash + run: | + composer config platform.php "${{ matrix.php-version }}" + - name: Get Composer cache dir id: composer-cache shell: bash diff --git a/composer.json b/composer.json index 0666f8e..5dd7fcf 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^5.7 || ^7.5 || ^9.6", + "phpunit/phpunit": "^5.7.27 || ^9.6.10", "psx/cache": "^v1.0.2" }, "autoload": { From 6a2ac74962b1c7c17265978ce840fe0321ba75ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:23:09 +0100 Subject: [PATCH 07/24] composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5dd7fcf..b99ae60 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^5.7.27 || ^9.6.10", + "phpunit/phpunit": "^5.7.27 || ^7.5 || ^9.6", "psx/cache": "^v1.0.2" }, "autoload": { From 3a6465e6964e85f4728c07c0b2d680d0df70751c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:26:06 +0100 Subject: [PATCH 08/24] composer --- .github/actions/composer-install/action.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/actions/composer-install/action.yml b/.github/actions/composer-install/action.yml index 00e30dd..5e895cf 100644 --- a/.github/actions/composer-install/action.yml +++ b/.github/actions/composer-install/action.yml @@ -4,11 +4,6 @@ description: "Install composer dependencies with cache" runs: using: composite steps: - - name: Configure Composer PHP platform - shell: bash - run: | - composer config platform.php "${{ matrix.php-version }}" - - name: Get Composer cache dir id: composer-cache shell: bash From 6625f5a5926dd56d7fbd1855af9247bd8cfc3eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:35:13 +0100 Subject: [PATCH 09/24] composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b99ae60..5dd7fcf 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^5.7.27 || ^7.5 || ^9.6", + "phpunit/phpunit": "^5.7.27 || ^9.6.10", "psx/cache": "^v1.0.2" }, "autoload": { From 17328d129827f535697561c1741e140947885f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:54:50 +0100 Subject: [PATCH 10/24] composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5dd7fcf..2ef8d17 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^5.7.27 || ^9.6.10", + "phpunit/phpunit": "^5.7 || ^7.5 || ^9.5", "psx/cache": "^v1.0.2" }, "autoload": { From 9d8c501d80bdd02ce55011e344a79a9d7039175f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 09:59:11 +0100 Subject: [PATCH 11/24] composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2ef8d17..4ffe260 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": "^5.7 || ^7.5 || ^9.5", + "phpunit/phpunit": ">=5.7 <7.0 || >=7.5 <9.0 || >=9.5 <10.0", "psx/cache": "^v1.0.2" }, "autoload": { From c35978b1ca3e5d4a2d59a4cbaf02bd989abd86a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Thu, 5 Feb 2026 10:01:46 +0100 Subject: [PATCH 12/24] composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4ffe260..b41ecd1 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "ext-openssl": "*", "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpunit/phpunit": ">=5.7 <7.0 || >=7.5 <9.0 || >=9.5 <10.0", + "phpunit/phpunit": "^5.7 || ^7.5 || ^8.5 || ^9.5", "psx/cache": "^v1.0.2" }, "autoload": { From 430ccb8637cdfc20627fc3ebdcd4cf3dddcfb429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 09:15:18 +0100 Subject: [PATCH 13/24] Blik alias notification --- .../Notification/BlikAlias/ExpirationDate.php | 10 ++++++ .../Fields/Notification/BlikAlias/Type.php | 10 ++++++ .../Fields/Notification/BlikAlias/Value.php | 10 ++++++ .../NotificationBody/BlikAliasRegister.php | 35 +++++++++++++++++++ .../NotificationBody/BlikAliasUnregister.php | 29 +++++++++++++++ .../JWSVerifiedPaymentNotification.php | 29 ++++++++++++--- .../JWSVerifiedPaymentNotificationTest.php | 33 +++++++++++++++++ 7 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 src/Model/Fields/Notification/BlikAlias/ExpirationDate.php create mode 100644 src/Model/Fields/Notification/BlikAlias/Type.php create mode 100644 src/Model/Fields/Notification/BlikAlias/Value.php create mode 100644 src/Model/Objects/NotificationBody/BlikAliasRegister.php create mode 100644 src/Model/Objects/NotificationBody/BlikAliasUnregister.php diff --git a/src/Model/Fields/Notification/BlikAlias/ExpirationDate.php b/src/Model/Fields/Notification/BlikAlias/ExpirationDate.php new file mode 100644 index 0000000..a0166de --- /dev/null +++ b/src/Model/Fields/Notification/BlikAlias/ExpirationDate.php @@ -0,0 +1,10 @@ + Value::class, + 'type' => Type::class, + 'expirationDate' => ExpirationDate::class, + ]; + + /** @var Value */ + public $value; + + /** @var Type */ + public $type; + + /** @var ExpirationDate */ + public $expirationDate; + + public function getRequiredFields() + { + return [ + $this->value, + $this->type, + $this->expirationDate, + ]; + } +} diff --git a/src/Model/Objects/NotificationBody/BlikAliasUnregister.php b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php new file mode 100644 index 0000000..8138c72 --- /dev/null +++ b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php @@ -0,0 +1,29 @@ + Value::class, + 'type' => Type::class, + ]; + + /** @var Value */ + public $value; + + /** @var Type */ + public $type; + + public function getRequiredFields() + { + return [ + $this->value, + $this->type, + ]; + } +} diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index 5f84e85..a7d1942 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -3,6 +3,8 @@ namespace Tpay\OpenApi\Webhook; use Tpay\OpenApi\Model\Objects\NotificationBody\BasicPayment; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasUnregister; use Tpay\OpenApi\Model\Objects\NotificationBody\MarketplaceTransaction; use Tpay\OpenApi\Model\Objects\NotificationBody\Tokenization; use Tpay\OpenApi\Model\Objects\NotificationBody\TokenUpdate; @@ -179,15 +181,19 @@ private function getNotificationObject() case 'marketplace_transaction': $requestBody = new MarketplaceTransaction(); break; + case 'ALIAS_REGISTER': + $requestBody = new BlikAliasRegister(); + break; + case 'ALIAS_UNREGISTER': + $requestBody = new BlikAliasUnregister(); + break; default: throw new TpayException( 'Not recognised or invalid notification type: '.$source['type'] ); } - if (!isset($source['data'])) { - throw new TpayException('Not recognised or invalid notification type: '.json_encode($source)); - } - $source = $source['data']; + + $source = $this->getSourceData($source); } else { throw new TpayException( 'Cannot determine notification type. POST payload: '.json_encode($source) @@ -209,4 +215,19 @@ private function getNotificationObject() return $this->Manager->getRequestBody(); } + + /** @return array + * @throws TpayException + */ + private function getSourceData($sourceData) + { + if (isset($sourceData['data'])) { + return $sourceData['data']; + } + if (isset($sourceData['msg_value'])) { + return $sourceData['msg_value']; + } + + throw new TpayException('Not recognised or invalid notification type: '.json_encode($sourceData)); + } } diff --git a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php index 88dfd96..808c58c 100644 --- a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php +++ b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php @@ -4,6 +4,8 @@ use PHPUnit\Framework\TestCase; use Tpay\OpenApi\Model\Objects\NotificationBody\BasicPayment; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasUnregister; use Tpay\OpenApi\Model\Objects\NotificationBody\MarketplaceTransaction; use Tpay\OpenApi\Model\Objects\NotificationBody\Tokenization; use Tpay\OpenApi\Model\Objects\NotificationBody\TokenUpdate; @@ -186,6 +188,37 @@ public function positiveValidationProvider() $payload = http_build_query($data); $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), self::CORRECT_CODE, true, BasicPayment::class, 'tokenPaymentData_tokenValue', '1234567890123456']; + $payload = <<<'JSON' +{ + "type": "ALIAS_REGISTER", + "msg_value": { + "value": "user_unique_alias_123", + "type": "UID", + "expirationDate": "2024-12-10 09:27:59" + } +} +JSON; + $data = json_decode($payload, true); + $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasRegister::class, 'value', 'user_unique_alias_123']; + + $payload = http_build_query($data); + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasRegister::class, 'value', 'user_unique_alias_123']; + + $payload = <<<'JSON' +{ + "type": "ALIAS_UNREGISTER", + "msg_value": { + "value": "user_unique_alias_456", + "type": "UID" + } +} +JSON; + $data = json_decode($payload, true); + $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'value', 'user_unique_alias_456']; + + $payload = http_build_query($data); + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'value', 'user_unique_alias_456']; + return $result; } From de9b46156f2c59050e006d75d41fc2ef0bc9d794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 09:17:56 +0100 Subject: [PATCH 14/24] fixer --- src/Model/Fields/Notification/BlikAlias/ExpirationDate.php | 2 +- src/Model/Fields/Notification/BlikAlias/Type.php | 2 +- src/Model/Fields/Notification/BlikAlias/Value.php | 2 +- src/Webhook/JWSVerifiedPaymentNotification.php | 6 +++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Model/Fields/Notification/BlikAlias/ExpirationDate.php b/src/Model/Fields/Notification/BlikAlias/ExpirationDate.php index a0166de..e5f870b 100644 --- a/src/Model/Fields/Notification/BlikAlias/ExpirationDate.php +++ b/src/Model/Fields/Notification/BlikAlias/ExpirationDate.php @@ -7,4 +7,4 @@ class ExpirationDate extends Field { protected $type = self::STRING; -} \ No newline at end of file +} diff --git a/src/Model/Fields/Notification/BlikAlias/Type.php b/src/Model/Fields/Notification/BlikAlias/Type.php index 344d5f1..b4b036a 100644 --- a/src/Model/Fields/Notification/BlikAlias/Type.php +++ b/src/Model/Fields/Notification/BlikAlias/Type.php @@ -7,4 +7,4 @@ class Type extends Field { protected $type = self::STRING; -} \ No newline at end of file +} diff --git a/src/Model/Fields/Notification/BlikAlias/Value.php b/src/Model/Fields/Notification/BlikAlias/Value.php index 4a22a59..eba0efa 100644 --- a/src/Model/Fields/Notification/BlikAlias/Value.php +++ b/src/Model/Fields/Notification/BlikAlias/Value.php @@ -7,4 +7,4 @@ class Value extends Field { protected $type = self::STRING; -} \ No newline at end of file +} diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index a7d1942..ade6bab 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -216,7 +216,11 @@ private function getNotificationObject() return $this->Manager->getRequestBody(); } - /** @return array + /** + * @param mixed $sourceData + * + * @return array + * * @throws TpayException */ private function getSourceData($sourceData) From d0d4960e7c2faa9788a9c4e9078d3f0115b7368a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 09:18:53 +0100 Subject: [PATCH 15/24] fixer --- src/Webhook/JWSVerifiedPaymentNotification.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index ade6bab..95e7523 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -219,9 +219,9 @@ private function getNotificationObject() /** * @param mixed $sourceData * - * @return array - * * @throws TpayException + * + * @return array */ private function getSourceData($sourceData) { From b8f3a1e847659bf23680ad4edcf054abc24a8522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 09:48:51 +0100 Subject: [PATCH 16/24] fixer --- .../Notifications/AllNotificationsExample.php | 24 ++++++++++++ .../JWSVerifiedPaymentNotification.php | 39 +++++++++---------- .../JWSVerifiedPaymentNotificationTest.php | 4 +- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/examples/Notifications/AllNotificationsExample.php b/examples/Notifications/AllNotificationsExample.php index 10c8d07..7e3e50b 100644 --- a/examples/Notifications/AllNotificationsExample.php +++ b/examples/Notifications/AllNotificationsExample.php @@ -6,6 +6,8 @@ use PSX\Cache\SimpleCache; use Tpay\Example\ExamplesConfig; use Tpay\OpenApi\Model\Objects\NotificationBody\BasicPayment; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasUnregister; use Tpay\OpenApi\Model\Objects\NotificationBody\MarketplaceTransaction; use Tpay\OpenApi\Model\Objects\NotificationBody\Tokenization; use Tpay\OpenApi\Model\Objects\NotificationBody\TokenUpdate; @@ -81,6 +83,28 @@ public function getVerifiedNotification() // $marketplaceTransactionProcessor->process($notification) exit('{"result":true}'); } + if ($notification instanceof BlikAliasRegister) { + // Notification about successful blik alias registered + + $value = $notification->value->getValue(); + // The above example will check the notification and return the value for future transactions, + // correlate this value with the payer/user of your system for subsequent payment handling + // You can access any notification field by $notification->fieldName + + //$blikAliasRegisteredProcessor->process($notification) + exit('{"result":true}'); + } + + if ($notification instanceof BlikAliasUnregister) { + // Notification about successful blik alias registered + + $value = $notification->value->getValue(); + // The above example will check the notification and return the value of deleted token + // You can access any notification field by $notification->fieldName + + //$blikAliasRegisteredProcessor->process($notification) + exit('{"result":true}'); + } // Ignore and silence other notification types if not expected http_response_code(404); diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index 95e7523..9e30f8e 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -181,6 +181,19 @@ private function getNotificationObject() case 'marketplace_transaction': $requestBody = new MarketplaceTransaction(); break; + default: + throw new TpayException( + 'Not recognised or invalid notification type: '.$source['type'] + ); + } + + if (!isset($source['data'])) { + throw new TpayException('Not recognised or invalid notification type: '.json_encode($source)); + } + + $source = $source['data']; + } elseif (isset($source['event'])) { + switch ($source['event']) { case 'ALIAS_REGISTER': $requestBody = new BlikAliasRegister(); break; @@ -189,11 +202,14 @@ private function getNotificationObject() break; default: throw new TpayException( - 'Not recognised or invalid notification type: '.$source['type'] + 'Not recognised or invalid notification event: '.$source['event'] ); } + if (!isset($source['msg_value'])) { + throw new TpayException('Not recognised or invalid notification event: '.json_encode($source)); + } - $source = $this->getSourceData($source); + $source = $source['msg_value']; } else { throw new TpayException( 'Cannot determine notification type. POST payload: '.json_encode($source) @@ -215,23 +231,4 @@ private function getNotificationObject() return $this->Manager->getRequestBody(); } - - /** - * @param mixed $sourceData - * - * @throws TpayException - * - * @return array - */ - private function getSourceData($sourceData) - { - if (isset($sourceData['data'])) { - return $sourceData['data']; - } - if (isset($sourceData['msg_value'])) { - return $sourceData['msg_value']; - } - - throw new TpayException('Not recognised or invalid notification type: '.json_encode($sourceData)); - } } diff --git a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php index 808c58c..51d8735 100644 --- a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php +++ b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php @@ -190,7 +190,7 @@ public function positiveValidationProvider() $payload = <<<'JSON' { - "type": "ALIAS_REGISTER", + "event": "ALIAS_REGISTER", "msg_value": { "value": "user_unique_alias_123", "type": "UID", @@ -206,7 +206,7 @@ public function positiveValidationProvider() $payload = <<<'JSON' { - "type": "ALIAS_UNREGISTER", + "event": "ALIAS_UNREGISTER", "msg_value": { "value": "user_unique_alias_456", "type": "UID" From f97bec3e1a0fcaf7a6e38bbb095732c0aad77542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 09:49:52 +0100 Subject: [PATCH 17/24] fixer --- examples/Notifications/AllNotificationsExample.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Notifications/AllNotificationsExample.php b/examples/Notifications/AllNotificationsExample.php index 7e3e50b..c5e0b14 100644 --- a/examples/Notifications/AllNotificationsExample.php +++ b/examples/Notifications/AllNotificationsExample.php @@ -91,7 +91,7 @@ public function getVerifiedNotification() // correlate this value with the payer/user of your system for subsequent payment handling // You can access any notification field by $notification->fieldName - //$blikAliasRegisteredProcessor->process($notification) + // $blikAliasRegisteredProcessor->process($notification) exit('{"result":true}'); } @@ -102,7 +102,7 @@ public function getVerifiedNotification() // The above example will check the notification and return the value of deleted token // You can access any notification field by $notification->fieldName - //$blikAliasRegisteredProcessor->process($notification) + // $blikAliasRegisteredProcessor->process($notification) exit('{"result":true}'); } From 3c0dea6a10dce9f75371d93f473fe11e21a573e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 11:58:30 +0100 Subject: [PATCH 18/24] CR --- examples/Notifications/AllNotificationsExample.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/Notifications/AllNotificationsExample.php b/examples/Notifications/AllNotificationsExample.php index c5e0b14..867c08b 100644 --- a/examples/Notifications/AllNotificationsExample.php +++ b/examples/Notifications/AllNotificationsExample.php @@ -92,7 +92,7 @@ public function getVerifiedNotification() // You can access any notification field by $notification->fieldName // $blikAliasRegisteredProcessor->process($notification) - exit('{"result":true}'); + exit('TRUE'); } if ($notification instanceof BlikAliasUnregister) { @@ -103,7 +103,7 @@ public function getVerifiedNotification() // You can access any notification field by $notification->fieldName // $blikAliasRegisteredProcessor->process($notification) - exit('{"result":true}'); + exit('TRUE'); } // Ignore and silence other notification types if not expected From 2e805ba7480db5c9f97fa84e049c962e2ae4d9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 11:59:05 +0100 Subject: [PATCH 19/24] CR --- examples/Notifications/AllNotificationsExample.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Notifications/AllNotificationsExample.php b/examples/Notifications/AllNotificationsExample.php index 867c08b..1870fe9 100644 --- a/examples/Notifications/AllNotificationsExample.php +++ b/examples/Notifications/AllNotificationsExample.php @@ -96,7 +96,7 @@ public function getVerifiedNotification() } if ($notification instanceof BlikAliasUnregister) { - // Notification about successful blik alias registered + // Notification about successful blik alias unregistered $value = $notification->value->getValue(); // The above example will check the notification and return the value of deleted token From 6963432124d417e07730b7812f51f3ee13b15d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 16:48:06 +0100 Subject: [PATCH 20/24] CR --- src/Factory/ArrayObjectFactory.php | 11 ++++ .../Fields/Notification/BlikAlias/Event.php | 11 ++++ .../Notification/BlikAlias/ExpirationDate.php | 1 + .../Fields/Notification/BlikAlias/Id.php | 11 ++++ .../Fields/Notification/BlikAlias/Type.php | 1 + .../Fields/Notification/BlikAlias/Value.php | 1 + .../BlikAlias/BlikAliasRegisterItem.php | 44 ++++++++++++++ .../BlikAlias/BlikAliasUnregisterItem.php | 37 ++++++++++++ .../NotificationBody/BlikAliasRegister.php | 35 ++++++----- .../NotificationBody/BlikAliasUnregister.php | 31 ++++++---- .../JWSVerifiedPaymentNotification.php | 58 +++++++++++++++---- .../JWSVerifiedPaymentNotificationTest.php | 45 +++++++++----- 12 files changed, 235 insertions(+), 51 deletions(-) create mode 100644 src/Model/Fields/Notification/BlikAlias/Event.php create mode 100644 src/Model/Fields/Notification/BlikAlias/Id.php create mode 100644 src/Model/Objects/NotificationBody/BlikAlias/BlikAliasRegisterItem.php create mode 100644 src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php diff --git a/src/Factory/ArrayObjectFactory.php b/src/Factory/ArrayObjectFactory.php index 983d97c..114fad0 100644 --- a/src/Factory/ArrayObjectFactory.php +++ b/src/Factory/ArrayObjectFactory.php @@ -9,6 +9,8 @@ use Tpay\OpenApi\Model\Objects\Merchant\Address as MerchantAddress; use Tpay\OpenApi\Model\Objects\Merchant\ContactPerson; use Tpay\OpenApi\Model\Objects\Merchant\PointOfSale as MerchantPointOfSale; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAlias; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; use Tpay\OpenApi\Model\Objects\Objects; use Tpay\OpenApi\Model\Objects\RequestBody\Account; use Tpay\OpenApi\Model\Objects\RequestBody\Merchant; @@ -51,6 +53,15 @@ public function create($fieldName, $parentObject) } } + if ($parentObject instanceof BlikAliasRegister) { + switch ($fieldName) { + case 'msg_value': + return new BlikAlias(); + default: + throw new InvalidArgumentException(sprintf('Unsupported field "%s" in %s', $fieldName, $parentObject->getName())); + } + } + throw new InvalidArgumentException(sprintf('Field %s as array is not supported in %s object', $fieldName, $parentObject->getName())); } } diff --git a/src/Model/Fields/Notification/BlikAlias/Event.php b/src/Model/Fields/Notification/BlikAlias/Event.php new file mode 100644 index 0000000..7a4997e --- /dev/null +++ b/src/Model/Fields/Notification/BlikAlias/Event.php @@ -0,0 +1,11 @@ + Value::class, + 'type' => Type::class, + 'expirationDate' => ExpirationDate::class, + ]; + + /** @var Value */ + public $value; + + /** @var Type */ + public $type; + + /** @var ExpirationDate */ + public $expirationDate; + + public function getRequiredFields() + { + return [ + $this->value, + $this->type, + $this->expirationDate, + ]; + } + + public function toArray() + { + return [ + 'value' => $this->value->getValue(), + 'type' => $this->type->getValue(), + 'expirationDate' => $this->expirationDate->getValue(), + ]; + } +} \ No newline at end of file diff --git a/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php b/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php new file mode 100644 index 0000000..2f76863 --- /dev/null +++ b/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php @@ -0,0 +1,37 @@ + Value::class, + 'type' => Type::class, + ]; + + /** @var Value */ + public $value; + + /** @var Type */ + public $type; + + public function getRequiredFields() + { + return [ + $this->value, + $this->type, + ]; + } + + public function toArray() + { + return [ + 'value' => $this->value->getValue(), + 'type' => $this->type->getValue(), + ]; + } +} \ No newline at end of file diff --git a/src/Model/Objects/NotificationBody/BlikAliasRegister.php b/src/Model/Objects/NotificationBody/BlikAliasRegister.php index 2c87426..1ca2733 100644 --- a/src/Model/Objects/NotificationBody/BlikAliasRegister.php +++ b/src/Model/Objects/NotificationBody/BlikAliasRegister.php @@ -2,34 +2,39 @@ namespace Tpay\OpenApi\Model\Objects\NotificationBody; -use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\ExpirationDate; -use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Type; -use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Value; +use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Event; +use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Id; +use Tpay\OpenApi\Model\Fields\Notification\Md5sum; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAlias\BlikAliasRegisterItem; use Tpay\OpenApi\Model\Objects\Objects; class BlikAliasRegister extends Objects { const OBJECT_FIELDS = [ - 'value' => Value::class, - 'type' => Type::class, - 'expirationDate' => ExpirationDate::class, + 'id' => Id::class, + 'event' => Event::class, + 'msg_value' => [BlikAliasRegisterItem::class], + 'md5sum' => Md5sum::class, ]; - /** @var Value */ - public $value; + /** @var Id */ + public $id; - /** @var Type */ - public $type; + /** @var Event */ + public $event; - /** @var ExpirationDate */ - public $expirationDate; + /** @var BlikAliasRegisterItem[] */ + public $msg_value; + + /** @var Md5sum */ + public $md5sum; public function getRequiredFields() { return [ - $this->value, - $this->type, - $this->expirationDate, + $this->id, + $this->event, + $this->msg_value, ]; } } diff --git a/src/Model/Objects/NotificationBody/BlikAliasUnregister.php b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php index 8138c72..8cc1d43 100644 --- a/src/Model/Objects/NotificationBody/BlikAliasUnregister.php +++ b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php @@ -2,28 +2,39 @@ namespace Tpay\OpenApi\Model\Objects\NotificationBody; -use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Type; -use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Value; +use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Event; +use Tpay\OpenApi\Model\Fields\Notification\BlikAlias\Id; +use Tpay\OpenApi\Model\Fields\Notification\Md5sum; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAlias\BlikAliasUnregisterItem; use Tpay\OpenApi\Model\Objects\Objects; class BlikAliasUnregister extends Objects { const OBJECT_FIELDS = [ - 'value' => Value::class, - 'type' => Type::class, + 'id' => Id::class, + 'event' => Event::class, + 'msg_value' => [BlikAliasUnregisterItem::class], + 'md5sum' => Md5sum::class, ]; - /** @var Value */ - public $value; + /** @var Id */ + public $id; - /** @var Type */ - public $type; + /** @var Event */ + public $event; + + /** @var BlikAliasUnregisterItem[] */ + public $msg_value; + + /** @var Md5sum */ + public $md5sum; public function getRequiredFields() { return [ - $this->value, - $this->type, + $this->id, + $this->event, + $this->msg_value, ]; } } diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index 9e30f8e..6e243a6 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -2,6 +2,8 @@ namespace Tpay\OpenApi\Webhook; +use Tpay\OpenApi\Factory\ArrayObjectFactory; +use Tpay\OpenApi\Model\Fields\Field; use Tpay\OpenApi\Model\Objects\NotificationBody\BasicPayment; use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasUnregister; @@ -33,6 +35,9 @@ class JWSVerifiedPaymentNotification extends Notification /** @var CertificateProvider */ private $certificateProvider; + /** @var ArrayObjectFactory */ + private $factory; + /** * @param string $merchantSecret string Merchant notification check secret * @param bool $productionMode true for prod or false for sandbox environment @@ -47,6 +52,7 @@ public function __construct( $this->merchantSecret = $merchantSecret; $this->requestParser = null === $requestParser ? new RequestParser() : $requestParser; $this->certificateProvider = $certificateProvider; + $this->factory = new ArrayObjectFactory(); parent::__construct(); } @@ -205,25 +211,16 @@ private function getNotificationObject() 'Not recognised or invalid notification event: '.$source['event'] ); } - if (!isset($source['msg_value'])) { + if (!isset($source['msg_value']) || !is_array($source['msg_value'])) { throw new TpayException('Not recognised or invalid notification event: '.json_encode($source)); } - - $source = $source['msg_value']; } else { throw new TpayException( 'Cannot determine notification type. POST payload: '.json_encode($source) ); } - foreach ($source as $parameter => $value) { - if (isset($requestBody->{$parameter})) { - $source[$parameter] = Util::cast( - $value, - $requestBody->{$parameter}->getType() - ); - } - } + $source = $this->castRequestBody($source, $requestBody); $this->Manager ->setRequestBody($requestBody) @@ -231,4 +228,43 @@ private function getNotificationObject() return $this->Manager->getRequestBody(); } + + private function castRequestBody($source, $requestBody) + { + $fields = []; + $definitions = $requestBody::OBJECT_FIELDS; + + foreach ($source as $parameter => $value) { + if (!isset($definitions[$parameter])) { + continue; + } + + $definition = $definitions[$parameter]; + + if (is_array($definition) && is_array($value)) { + $objectClass = $definition[0]; + $items = []; + + foreach ($value as $item) { + $object = new $objectClass(); + $items[] = $this->castRequestBody($item, $object); + } + + $fields[$parameter] = $items; + continue; + } + + if (is_string($definition)) { + /** @var Field $field */ + $field = new $definition(); + + $fields[$parameter] = Util::cast( + $value, + $field->getType() + ); + } + } + + return $fields; + } } diff --git a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php index 51d8735..45b0c82 100644 --- a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php +++ b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php @@ -4,6 +4,8 @@ use PHPUnit\Framework\TestCase; use Tpay\OpenApi\Model\Objects\NotificationBody\BasicPayment; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAlias\BlikAliasRegisterItem; +use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAlias\BlikAliasUnregisterItem; use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasUnregister; use Tpay\OpenApi\Model\Objects\NotificationBody\MarketplaceTransaction; @@ -35,7 +37,7 @@ class JWSVerifiedPaymentNotificationTest extends TestCase * @param mixed $fieldName * @param mixed $fieldValue */ - public function testPositiveValidationCases($contentType, $data, $payload, $signature, $secret, $productionMode, $expectedClass, $fieldName, $fieldValue) + public function testPositiveValidationCases($contentType, $data, $payload, $signature, $secret, $productionMode, $expectedClass, $fieldName, $fieldValue, $expectedItemClass = null) { $requestMock = new RequestParserMock($contentType, $data, $payload, $signature); $certificateMock = $this->getCertificateMock(); @@ -45,7 +47,14 @@ public function testPositiveValidationCases($contentType, $data, $payload, $sign $notificationObject = $notification->getNotification(); $this->assertInstanceOf($expectedClass, $notificationObject); - $this->assertEquals($notificationObject->{$fieldName}->getValue(), $fieldValue); + + $field = $notificationObject->{$fieldName}; + if (is_array($field)) { + $this->assertInstanceOf($expectedItemClass, $field[0]); + $this->assertEquals($fieldValue, $field[0]->toArray()); + } else { + $this->assertEquals($field->getValue(), $fieldValue); + } } /** @@ -190,34 +199,40 @@ public function positiveValidationProvider() $payload = <<<'JSON' { + "id": "1010", "event": "ALIAS_REGISTER", - "msg_value": { - "value": "user_unique_alias_123", - "type": "UID", - "expirationDate": "2024-12-10 09:27:59" - } + "msg_value": [ + { + "value": "user_unique_alias_123", + "type": "UID", + "expirationDate": "2024-12-10 09:27:59" + } + ] } JSON; $data = json_decode($payload, true); - $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasRegister::class, 'value', 'user_unique_alias_123']; + $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasRegister::class, 'msg_value', ['value' => 'user_unique_alias_123', 'type' => 'UID', 'expirationDate' => '2024-12-10 09:27:59'], BlikAliasRegisterItem::class]; $payload = http_build_query($data); - $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasRegister::class, 'value', 'user_unique_alias_123']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasRegister::class, 'msg_value', ['value' => 'user_unique_alias_123', 'type' => 'UID', 'expirationDate' => '2024-12-10 09:27:59'], BlikAliasRegisterItem::class]; $payload = <<<'JSON' { + "id": "1010", "event": "ALIAS_UNREGISTER", - "msg_value": { - "value": "user_unique_alias_456", - "type": "UID" - } + "msg_value": [ + { + "value": "user_unique_alias_456", + "type": "UID" + } + ] } JSON; $data = json_decode($payload, true); - $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'value', 'user_unique_alias_456']; + $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'msg_value', ['value' => 'user_unique_alias_456', 'type' => 'UID'], BlikAliasUnregisterItem::class]; $payload = http_build_query($data); - $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'value', 'user_unique_alias_456']; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'msg_value', ['value' => 'user_unique_alias_456', 'type' => 'UID',], BlikAliasUnregisterItem::class]; return $result; } From 9d0e803789632b1a1190f65670e64a5ae4aa1416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 16:50:13 +0100 Subject: [PATCH 21/24] CR --- src/Factory/ArrayObjectFactory.php | 11 ----------- src/Webhook/JWSVerifiedPaymentNotification.php | 5 ----- 2 files changed, 16 deletions(-) diff --git a/src/Factory/ArrayObjectFactory.php b/src/Factory/ArrayObjectFactory.php index 114fad0..983d97c 100644 --- a/src/Factory/ArrayObjectFactory.php +++ b/src/Factory/ArrayObjectFactory.php @@ -9,8 +9,6 @@ use Tpay\OpenApi\Model\Objects\Merchant\Address as MerchantAddress; use Tpay\OpenApi\Model\Objects\Merchant\ContactPerson; use Tpay\OpenApi\Model\Objects\Merchant\PointOfSale as MerchantPointOfSale; -use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAlias; -use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; use Tpay\OpenApi\Model\Objects\Objects; use Tpay\OpenApi\Model\Objects\RequestBody\Account; use Tpay\OpenApi\Model\Objects\RequestBody\Merchant; @@ -53,15 +51,6 @@ public function create($fieldName, $parentObject) } } - if ($parentObject instanceof BlikAliasRegister) { - switch ($fieldName) { - case 'msg_value': - return new BlikAlias(); - default: - throw new InvalidArgumentException(sprintf('Unsupported field "%s" in %s', $fieldName, $parentObject->getName())); - } - } - throw new InvalidArgumentException(sprintf('Field %s as array is not supported in %s object', $fieldName, $parentObject->getName())); } } diff --git a/src/Webhook/JWSVerifiedPaymentNotification.php b/src/Webhook/JWSVerifiedPaymentNotification.php index 6e243a6..085b374 100644 --- a/src/Webhook/JWSVerifiedPaymentNotification.php +++ b/src/Webhook/JWSVerifiedPaymentNotification.php @@ -2,7 +2,6 @@ namespace Tpay\OpenApi\Webhook; -use Tpay\OpenApi\Factory\ArrayObjectFactory; use Tpay\OpenApi\Model\Fields\Field; use Tpay\OpenApi\Model\Objects\NotificationBody\BasicPayment; use Tpay\OpenApi\Model\Objects\NotificationBody\BlikAliasRegister; @@ -35,9 +34,6 @@ class JWSVerifiedPaymentNotification extends Notification /** @var CertificateProvider */ private $certificateProvider; - /** @var ArrayObjectFactory */ - private $factory; - /** * @param string $merchantSecret string Merchant notification check secret * @param bool $productionMode true for prod or false for sandbox environment @@ -52,7 +48,6 @@ public function __construct( $this->merchantSecret = $merchantSecret; $this->requestParser = null === $requestParser ? new RequestParser() : $requestParser; $this->certificateProvider = $certificateProvider; - $this->factory = new ArrayObjectFactory(); parent::__construct(); } From 070ec41262c8c6b6c47cfcd65b041a2bc1143e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 16:53:30 +0100 Subject: [PATCH 22/24] fixer --- .../NotificationBody/BlikAlias/BlikAliasRegisterItem.php | 2 +- .../NotificationBody/BlikAlias/BlikAliasUnregisterItem.php | 2 +- src/Model/Objects/NotificationBody/BlikAliasRegister.php | 2 +- src/Model/Objects/NotificationBody/BlikAliasUnregister.php | 2 +- tests/Webhook/JWSVerifiedPaymentNotificationTest.php | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasRegisterItem.php b/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasRegisterItem.php index 0bcc8d0..dab83ea 100644 --- a/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasRegisterItem.php +++ b/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasRegisterItem.php @@ -41,4 +41,4 @@ public function toArray() 'expirationDate' => $this->expirationDate->getValue(), ]; } -} \ No newline at end of file +} diff --git a/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php b/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php index 2f76863..d2a6a42 100644 --- a/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php +++ b/src/Model/Objects/NotificationBody/BlikAlias/BlikAliasUnregisterItem.php @@ -34,4 +34,4 @@ public function toArray() 'type' => $this->type->getValue(), ]; } -} \ No newline at end of file +} diff --git a/src/Model/Objects/NotificationBody/BlikAliasRegister.php b/src/Model/Objects/NotificationBody/BlikAliasRegister.php index 1ca2733..6c4a7f7 100644 --- a/src/Model/Objects/NotificationBody/BlikAliasRegister.php +++ b/src/Model/Objects/NotificationBody/BlikAliasRegister.php @@ -23,7 +23,7 @@ class BlikAliasRegister extends Objects /** @var Event */ public $event; - /** @var BlikAliasRegisterItem[] */ + /** @var array */ public $msg_value; /** @var Md5sum */ diff --git a/src/Model/Objects/NotificationBody/BlikAliasUnregister.php b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php index 8cc1d43..347d354 100644 --- a/src/Model/Objects/NotificationBody/BlikAliasUnregister.php +++ b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php @@ -23,7 +23,7 @@ class BlikAliasUnregister extends Objects /** @var Event */ public $event; - /** @var BlikAliasUnregisterItem[] */ + /** @var array */ public $msg_value; /** @var Md5sum */ diff --git a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php index 45b0c82..113ff46 100644 --- a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php +++ b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php @@ -36,6 +36,7 @@ class JWSVerifiedPaymentNotificationTest extends TestCase * @param mixed $expectedClass * @param mixed $fieldName * @param mixed $fieldValue + * @param null|mixed $expectedItemClass */ public function testPositiveValidationCases($contentType, $data, $payload, $signature, $secret, $productionMode, $expectedClass, $fieldName, $fieldValue, $expectedItemClass = null) { @@ -232,7 +233,7 @@ public function positiveValidationProvider() $result[] = ['application/json', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'msg_value', ['value' => 'user_unique_alias_456', 'type' => 'UID'], BlikAliasUnregisterItem::class]; $payload = http_build_query($data); - $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'msg_value', ['value' => 'user_unique_alias_456', 'type' => 'UID',], BlikAliasUnregisterItem::class]; + $result[] = ['application/x-www-form-urlencoded', $data, $payload, $this->sign($payload, true), 'x', true, BlikAliasUnregister::class, 'msg_value', ['value' => 'user_unique_alias_456', 'type' => 'UID'], BlikAliasUnregisterItem::class]; return $result; } From b8cbd4d2be1cd985450defb46de41e66629b43cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 16:55:24 +0100 Subject: [PATCH 23/24] fixer --- .../JWSVerifiedPaymentNotificationTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php index 113ff46..89bcfd6 100644 --- a/tests/Webhook/JWSVerifiedPaymentNotificationTest.php +++ b/tests/Webhook/JWSVerifiedPaymentNotificationTest.php @@ -27,15 +27,15 @@ class JWSVerifiedPaymentNotificationTest extends TestCase /** * @dataProvider positiveValidationProvider * - * @param mixed $contentType - * @param mixed $data - * @param mixed $payload - * @param mixed $signature - * @param mixed $secret - * @param mixed $productionMode - * @param mixed $expectedClass - * @param mixed $fieldName - * @param mixed $fieldValue + * @param mixed $contentType + * @param mixed $data + * @param mixed $payload + * @param mixed $signature + * @param mixed $secret + * @param mixed $productionMode + * @param mixed $expectedClass + * @param mixed $fieldName + * @param mixed $fieldValue * @param null|mixed $expectedItemClass */ public function testPositiveValidationCases($contentType, $data, $payload, $signature, $secret, $productionMode, $expectedClass, $fieldName, $fieldValue, $expectedItemClass = null) From 1914fb7ab1382456993b651da485484a9228db04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksander=20K=C4=85kol?= Date: Fri, 6 Feb 2026 17:00:03 +0100 Subject: [PATCH 24/24] fixer --- src/Model/Objects/NotificationBody/BlikAliasRegister.php | 2 +- src/Model/Objects/NotificationBody/BlikAliasUnregister.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Model/Objects/NotificationBody/BlikAliasRegister.php b/src/Model/Objects/NotificationBody/BlikAliasRegister.php index 6c4a7f7..5269f11 100644 --- a/src/Model/Objects/NotificationBody/BlikAliasRegister.php +++ b/src/Model/Objects/NotificationBody/BlikAliasRegister.php @@ -23,7 +23,7 @@ class BlikAliasRegister extends Objects /** @var Event */ public $event; - /** @var array */ + /** @var BlikAliasRegisterItem */ public $msg_value; /** @var Md5sum */ diff --git a/src/Model/Objects/NotificationBody/BlikAliasUnregister.php b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php index 347d354..66b6659 100644 --- a/src/Model/Objects/NotificationBody/BlikAliasUnregister.php +++ b/src/Model/Objects/NotificationBody/BlikAliasUnregister.php @@ -23,7 +23,7 @@ class BlikAliasUnregister extends Objects /** @var Event */ public $event; - /** @var array */ + /** @var BlikAliasUnregisterItem */ public $msg_value; /** @var Md5sum */