<?php
declare(strict_types=1);
namespace App\Infrastructure\PaymentGateway\IbanXS;
use Http\Message\MessageFactory;
use Payum\Core\Exception\Http\HttpException;
use Payum\Core\Exception\LogicException;
use Payum\Core\HttpClientInterface;
use Payum\Core\Request\Generic;
use App\Domain\Payment\Model\Payment as DomainPayment;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Types\Types;
class Api
{
// production
// public const AUTH_URL = 'https://cronosauth.bankxs.eu/auth/realms/GatewayRealm/protocol/openid-connect/token';
// public const API_URL = 'https://cronos.bankxs.eu/api/v1';
private string $clientId;
private string $clientSecret;
private HttpClientInterface $client;
private MessageFactory $messageFactory;
public function __construct(array $options, HttpClientInterface $client, MessageFactory $messageFactory, string $ibanxsAuthTokenUrl, string $ibanxsApiBaseUrlV1)
{
if (true === empty($options['client_id'])) {
throw new \InvalidArgumentException('The client_id option must be set.');
}
if (true === empty($options['client_secret'])) {
throw new \InvalidArgumentException('The client_secret option must be set.');
}
$this->clientId = $options['client_id'];
$this->clientSecret = $options['client_secret'];
$this->client = $client;
$this->messageFactory = $messageFactory;
$this->authUrl = $ibanxsAuthTokenUrl;
$this->apiUrl = $ibanxsApiBaseUrlV1;
}
public function createHostedFlow(array $data, $paymentId = null): array
{
return $this->doRequest($data, 'hostedflows', $paymentId);
}
private function getToken(): string
{
$request = $this->messageFactory->createRequest(
'POST',
$this->authUrl,
[
'Content-Type' => 'application/x-www-form-urlencoded',
],
http_build_query([
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'grant_type' => 'client_credentials',
])
);
$response = $this->client->send($request);
if (false === ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) {
throw HttpException::factory($request, $response);
}
$result = json_decode($response->getBody()->getContents(), true);
if (null === $result) {
throw new LogicException("Response content is not valid json: \n\n{$response->getBody()->getContents()}");
}
return $result['access_token'];
}
private function doRequest(array $data, string $path, $paymentId): array
{
$token = $this->getToken();
// Move fields from params to the root level if present
if (isset($data['params'])) {
if (!empty($data['params']['countryCode'])) {
$data['countryId'] = $data['params']['countryCode'];
unset($data['params']['countryCode']);
}
if (!empty($data['params']['bankId'])) {
$data['bankId'] = $data['params']['bankId'];
unset($data['params']['bankId']);
}
}
$request = $this->messageFactory->createRequest(
'POST',
$this->apiUrl . $path,
[
'accept' => 'application/json',
'Content-Type' => 'application/json',
'authorization' => sprintf('Bearer %s', $token),
],
json_encode($data)
);
$request = $this->messageFactory->createRequest(
'POST',
$this->apiUrl . $path,
[
'accept' => 'application/json',
'Content-Type' => 'application/json',
'authorization' => sprintf('Bearer %s', $token),
],
json_encode($data)
);
$response = $this->client->send($request);
if (false === ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) {
$statusCode = $response->getStatusCode();
$logs = [
'title' => 'Failed to redirect to PISP',
'details' => (string) $response->getBody()
];
try {
$logsJson = json_encode(
$logs,
JSON_THROW_ON_ERROR
| JSON_UNESCAPED_UNICODE
| JSON_UNESCAPED_SLASHES
| JSON_PRESERVE_ZERO_FRACTION
);
$conn = \Doctrine\DBAL\DriverManager::getConnection([
'url' => $_ENV['DATABASE_URL'] ?? 'mysql://user:pass@127.0.0.1:3306/your_db?charset=utf8mb4',
]);
$conn->insert(
'payment_logs',
[
'payment_id' => $paymentId,
'status_code' => $statusCode,
'logs' => $logsJson,
],
[
'payment_id' => is_numeric($paymentId) ? ParameterType::INTEGER : ParameterType::STRING,
'status_code' => ParameterType::INTEGER,
'logs' => Types::JSON,
]
);
} catch (\Throwable $e) {
}
throw HttpException::factory($request, $response);
}
$result = json_decode($response->getBody()->getContents(), true);
if (null === $result) {
throw new LogicException("Response content is not valid json: \n\n{$response->getBody()->getContents()}");
}
return $result;
}
}