This commit is contained in:
2026-02-02 15:18:51 +01:00
parent 7a26dd69a5
commit ae0ee002ec
170 changed files with 7446 additions and 1519 deletions

View File

@@ -357,13 +357,17 @@ class PaynowAdminFormHelper
'id_option' => Paynow\Model\PaymentMethods\Type::CARD,
'name' => $this->module->getPaymentMethodTitle(Paynow\Model\PaymentMethods\Type::CARD)
],
[
'id_option' => 'DIGITAL_WALLETS',
'name' => $this->translations['Digital wallets']
],
[
'id_option' => Paynow\Model\PaymentMethods\Type::PAYPO,
'name' => $this->module->getPaymentMethodTitle(Paynow\Model\PaymentMethods\Type::PAYPO)
],
[
'id_option' => Paynow\Model\PaymentMethods\Type::GOOGLE_PAY,
'name' => $this->module->getPaymentMethodTitle(Paynow\Model\PaymentMethods\Type::GOOGLE_PAY)
],
[
'id_option' => Paynow\Model\PaymentMethods\Type::APPLE_PAY,
'name' => $this->module->getPaymentMethodTitle(Paynow\Model\PaymentMethods\Type::APPLE_PAY)
'id_option' => Paynow\Model\PaymentMethods\Type::CLICK_TO_PAY,
'name' => $this->module->getPaymentMethodTitle(Paynow\Model\PaymentMethods\Type::CLICK_TO_PAY)
]
],
'id' => 'id_option',

View File

@@ -63,16 +63,17 @@ class PaynowFrontController extends ModuleFrontControllerCore
);
}
protected function getPaymentStatus($paymentId)
protected function getPaymentStatus($paymentId, $external_id)
{
PaynowLogger::info('Retrieving payment status {paymentId={}}', [$paymentId]);
PaynowLogger::info('Retrieving payment status {paymentId={}, externalId={}}', [$paymentId, $external_id]);
$idempotencyKey = PaynowKeysGenerator::generateIdempotencyKey($external_id);
try {
$status = (new Paynow\Service\Payment($this->module->getPaynowClient()))->status($paymentId)->getStatus();
$status = (new Paynow\Service\Payment($this->module->getPaynowClient()))->status($paymentId, $idempotencyKey)->getStatus();
PaynowLogger::info('Retrieved payment status {paymentId={}, status={}}', [$paymentId, $status]);
return $status;
} catch (PaynowException $exception) {
PaynowLogger::error($exception->getMessage() . ' {paymentId={}}', [$paymentId]);
PaynowLogger::error($exception->getMessage() . ' {paymentId={}, idempotencyKey={}}', [$paymentId, $idempotencyKey]);
}
return false;

View File

@@ -18,6 +18,11 @@ use Paynow\Exception\PaynowException;
*/
class PaynowGDPRHelper
{
// in seconds
private const OPTION_VALIDITY_TIME = 86400;
private $cart;
/**
* @var Client
*/
@@ -25,10 +30,12 @@ class PaynowGDPRHelper
/**
* @param Client $client
* @param $cart
*/
public function __construct(Client $client)
public function __construct(Client $client, $cart)
{
$this->client = $client;
$this->cart = $cart;
}
/**
@@ -38,10 +45,10 @@ class PaynowGDPRHelper
*/
public function getNotices(?string $locale)
{
$configurationId = 'PAYNOW_'.$this->isSandbox() ? 'SANDBOX_' : ''.'GDPR_' . $this->cleanLocale($locale);
$configurationId = 'PAYNOW_' . ( $this->isSandbox() ? 'SANDBOX_' : '') .'GDPR_' . $this->cleanLocale($locale);
$configurationOption = Configuration::get($configurationId);
if (! $configurationOption) {
if ( !$configurationOption || !$this->isValid( $locale ) ) {
$gdpr_notices = $this->retrieve($locale);
if ($gdpr_notices) {
@@ -54,6 +61,7 @@ class PaynowGDPRHelper
]);
}
Configuration::updateValue($configurationId, serialize($notices));
Configuration::updateValue($this->getOptionValidityKey($locale), time() + self::OPTION_VALIDITY_TIME);
$configurationOption = Configuration::get($configurationId);
}
}
@@ -77,7 +85,8 @@ class PaynowGDPRHelper
{
try {
PaynowLogger::info("Retrieving GDPR notices");
return (new Paynow\Service\DataProcessing($this->client))->getNotices($locale)->getAll();
$idempotencyKey = PaynowKeysGenerator::generateIdempotencyKey(PaynowKeysGenerator::generateExternalIdByCart($this->cart));
return (new Paynow\Service\DataProcessing($this->client))->getNotices($locale, $idempotencyKey)->getAll();
} catch (PaynowException $exception) {
PaynowLogger::error(
'An error occurred during GDPR notices retrieve {code={}, message={}}',
@@ -100,4 +109,20 @@ class PaynowGDPRHelper
{
return Tools::strtoupper(str_replace('-', '_', $locale));
}
private function isValid( ?string $locale ): bool
{
$optionValidity = Configuration::get($this->getOptionValidityKey($locale));
if ( empty( $optionValidity ) ) {
return false;
}
return time() < (int) $optionValidity;
}
private function getOptionValidityKey( ?string $locale ): string
{
return 'PAYNOW_'.( $this->isSandbox() ? 'SANDBOX_' : '' ).'GDPR_VALIDITY_' . $this->cleanLocale($locale);
}
}

View File

@@ -226,7 +226,7 @@ class PaynowOrderStateProcessor
$data['paymentId'],
$data['externalId']
);
$this->addOrderPayment($order, $data['paymentId']);
$this->addOrderPayment($order, $data['paymentId'], $payment->total);
break;
case Paynow\Model\Payment\Status::STATUS_ERROR:
$this->changeState(
@@ -358,16 +358,49 @@ class PaynowOrderStateProcessor
return $previous_status_exists && $is_change_possible;
}
/**
* @param $order
* @param $id_payment
*/
private function addOrderPayment($order, $id_payment)
/**
* @param $order
* @param $id_payment
* @param $total
*/
private function addOrderPayment($order, $id_payment, $total)
{
$payments = $order->getOrderPaymentCollection()->getResults();
if (count($payments) > 0) {
$payments[0]->transaction_id = $id_payment;
$payments[0]->update();
} else {
try {
$currentOrder = new Order($order->id);
// in case when order payment was not created
$result = $currentOrder->addOrderPayment(
$total,
$this->module->displayName,
$id_payment
);
if (!$result) {
PaynowLogger::error(
'Cannot create order payment entry',
[
$currentOrder->id,
$currentOrder->reference,
$id_payment
]
);
}
} catch (Throwable $t) {
PaynowLogger::error(
'Cannot create order payment entry due to exception: ',
[
$t->getMessage(),
$t->getLine(),
$order->id,
$order->reference,
$id_payment
]
);
}
}
}

View File

@@ -12,6 +12,7 @@
class PaynowPaymentDataBuilder
{
private const MAX_ORDER_ITEM_NAME_LENGTH = 120;
private $context;
/**
@@ -94,6 +95,7 @@ class PaynowPaymentDataBuilder
): array {
$currency = Currency::getCurrency($id_currency);
$customer = new Customer((int)$id_customer);
$paymentMethodId = Tools::getValue('paymentMethodId');
$request = [
'amount' => number_format($total_to_paid * 100, 0, '', ''),
@@ -114,8 +116,68 @@ class PaynowPaymentDataBuilder
)
];
if (! empty(Tools::getValue('paymentMethodId'))) {
$request['paymentMethodId'] = (int)Tools::getValue('paymentMethodId');
try {
$address = new Address($this->context->cart->id_address_delivery);
$invoiceAddress = new Address($this->context->cart->id_address_invoice);
try {
$state = new State($address->id_state);
} catch (Throwable $e) {
$state = null;
}
try {
$invoiceState = new State($invoiceAddress->id_state);
} catch (Throwable $e) {
$invoiceState = null;
}
try {
$country = Country::getIsoById($address->id_country);
} catch (Throwable $e) {
$country = null;
}
try {
$invoiceCountry = Country::getIsoById($invoiceAddress->id_country);
} catch (Throwable $e) {
$invoiceCountry = null;
}
$request['buyer']['address'] = [
'billing' => [
'street' => $invoiceAddress->address1,
'houseNumber' => $invoiceAddress->address2,
'apartmentNumber' => '',
'zipcode' => $invoiceAddress->postcode,
'city' => $invoiceAddress->city,
'county' => $invoiceState ? $invoiceState->name : '',
'country' => $invoiceCountry ?: '',
],
'shipping' => [
'street' => $address->address1,
'houseNumber' => $address->address2,
'apartmentNumber' => '',
'zipcode' => $address->postcode,
'city' => $address->city,
'county' => $state ? $state->name : '',
'country' => $country ?: '',
]
];
} catch (Throwable $exception) {
PaynowLogger::error('Cannot add addresses to payment data', ['msg' => $exception->getMessage()]);
}
if (!empty($id_customer) && $this->context->customer){
if (method_exists($this->context->customer, 'isGuest') && !$this->context->customer->isGuest()) {
$request['buyer']['externalId'] = PaynowKeysGenerator::generateBuyerExternalId($id_customer, $this->module);
} elseif ($this->context->customer->is_guest === '0') {
$request['buyer']['externalId'] = PaynowKeysGenerator::generateBuyerExternalId($id_customer, $this->module);
}
}
if (! empty($paymentMethodId)) {
$request['paymentMethodId'] = (int)$paymentMethodId;
}
if (Configuration::get('PAYNOW_PAYMENT_VALIDITY_TIME_ENABLED')) {
@@ -126,12 +188,20 @@ class PaynowPaymentDataBuilder
$request['authorizationCode'] = (int)preg_replace('/\s+/', '', Tools::getValue('blikCode'));
}
if (!empty(Tools::getValue('paymentMethodToken'))) {
$request['paymentMethodToken'] = Tools::getValue('paymentMethodToken');
}
if (! empty(Tools::getValue('paymentMethodFingerprint'))) {
$request['buyer']['deviceFingerprint'] = Tools::getValue('paymentMethodFingerprint');
}
if (Configuration::get('PAYNOW_SEND_ORDER_ITEMS')) {
$products = $this->context->cart->getProducts(true);
$order_items = [];
foreach ($products as $product) {
$order_items[] = [
'name' => $product['name'],
'name' => self::truncateOrderItemName($product['name']),
'category' => $this->getCategoriesNames($product['id_category_default']),
'quantity' => $product['quantity'],
'price' => number_format($product['price'] * 100, 0, '', '')
@@ -161,4 +231,15 @@ class PaynowPaymentDataBuilder
}
return implode(", ", $categoriesNames);
}
public static function truncateOrderItemName(string $name): string
{
$name = trim($name);
if(strlen($name) <= self::MAX_ORDER_ITEM_NAME_LENGTH) {
return $name;
}
return substr($name, 0, self::MAX_ORDER_ITEM_NAME_LENGTH - 3) . '...';
}
}

View File

@@ -39,20 +39,36 @@ class PaynowPaymentMethodsHelper
/**
* @param $currency_iso_code
* @param $total
* @param $context
* @param $module
*
* @return PaymentMethods|null
*/
public function getAvailable($currency_iso_code, $total): ?PaymentMethods
public function getAvailable($currency_iso_code, $total, $context, $module): ?PaymentMethods
{
$applePayEnabled = htmlspecialchars($_COOKIE['applePayEnabled'] ?? '0') === '1';
$idempotencyKey = PaynowKeysGenerator::generateIdempotencyKey(PaynowKeysGenerator::generateExternalIdByCart($context->cart));
$buyerExternalId = null;
if ($context->customer && $context->customer->isLogged()) {
$buyerExternalId = PaynowKeysGenerator::generateBuyerExternalId($context->cart->id_customer, $module);
}
try {
$applePayEnabled = htmlspecialchars($_COOKIE['applePayEnabled'] ?? '0') === '1';
return $this->payment_client->getPaymentMethods($currency_iso_code, $total, $applePayEnabled);
return $this->payment_client->getPaymentMethods($currency_iso_code, $total, $applePayEnabled, $idempotencyKey, $buyerExternalId);
} catch (PaynowException $exception) {
PaynowLogger::error(
'An error occurred during payment methods retrieve {code={}, message={}}',
'An error occurred during payment methods retrieve {currency={}, total={}, applePayEnabled={}, idempotencyKey={}, buyerExternalId={}, code={}, message={}, errors={}, m={}}',
[
$currency_iso_code,
$total,
$applePayEnabled,
$idempotencyKey,
$buyerExternalId,
$exception->getCode(),
$exception->getPrevious()->getMessage()
$exception->getPrevious()->getMessage(),
$exception->getErrors(),
$exception->getMessage()
]
);
}

View File

@@ -57,11 +57,16 @@ class PaynowPaymentOptions
];
}
$payment_options = [];
$digital_wallets = [
Paynow\Model\PaymentMethods\Type::CLICK_TO_PAY => null,
Paynow\Model\PaymentMethods\Type::GOOGLE_PAY => null,
Paynow\Model\PaymentMethods\Type::APPLE_PAY => null,
];
$this->context->smarty->assign([
'action' => PaynowLinkHelper::getPaymentUrl(),
'data_processing_notices' => $this->data_processing_notices
'data_processing_notices' => $this->data_processing_notices,
'data_paynow_plugin_version' => $this->module->version,
]);
$isAnyPblEnabled = false;
@@ -74,20 +79,25 @@ class PaynowPaymentOptions
}
$hiddenPaymentTypes = explode(',', Configuration::get('PAYNOW_HIDE_PAYMENT_TYPES'));
$digitalWalletsHidden = in_array('DIGITAL_WALLETS', $hiddenPaymentTypes);
$list = [];
$payment_options = [];
/** @var PaymentMethod $payment_method */
foreach ($this->payment_methods->getAll() as $payment_method) {
if (isset($list[$payment_method->getType()])) {
continue;
}
if (in_array($payment_method->getType(), $hiddenPaymentTypes)) {
continue;
}
if (Paynow\Model\PaymentMethods\Type::PBL == $payment_method->getType()) {
if (!$isAnyPblEnabled) {
continue;
}
$this->context->smarty->assign([
'paynowPbls' => $this->payment_methods->getOnlyPbls(),
]);
@@ -97,23 +107,45 @@ class PaynowPaymentOptions
PaynowLinkHelper::getPaymentUrl(),
'module:paynow/views/templates/front/1.7/payment_form.tpl'
);
} elseif (array_key_exists($payment_method->getType(), $digital_wallets)) {
if (!$payment_method->isEnabled() || $digitalWalletsHidden) {
continue;
}
$digital_wallets[$payment_method->getType()] = $payment_method;
} else {
if (!$payment_method->isEnabled()) {
continue;
}
$this->setUpAdditionalTemplateVariables($payment_method);
$payment_options[] = $this->getPaymentOption(
$this->module->getPaymentMethodTitle($payment_method->getType()),
$payment_method->getImage(),
PaynowLinkHelper::getPaymentUrl([
'paymentMethodId' => $payment_method->getId()
'paymentMethodId' => $payment_method->getId(),
]),
$this->getForm($payment_method)
);
}
$list[$payment_method->getType()] = $payment_method->getId();
}
$digital_wallets = array_values(array_filter($digital_wallets));
if (!empty($digital_wallets)) {
$this->context->smarty->assign([
'paynowDigitalWalletsPayments' => $digital_wallets,
]);
$payment_options[] = $this->getPaymentOption(
$this->module->getPaymentMethodTitle('DIGITAL_WALLETS'),
$this->module->getDigitalWalletsLogo($digital_wallets),
PaynowLinkHelper::getPaymentUrl(),
'module:paynow/views/templates/front/1.7/payment_method_digital_wallets_form.tpl'
);
}
return $payment_options;
}
@@ -131,10 +163,29 @@ class PaynowPaymentOptions
'action_token' => Tools::encrypt($this->context->customer->secure_key ?? ''),
'action_token_refresh' => Context::getContext()->link->getModuleLink('paynow', 'customerToken'),
'error_message' => $this->getMessage('An error occurred during the payment process'),
'terms_message' => $this->getMessage('You have to accept terms and conditions'),
'terms_message' => $this->getMessage('First accept the terms of service, then click pay.'),
'blik_autofocus' => Configuration::get('PAYNOW_BLIK_AUTOFOCUS_ENABLED') === '0' ? '0' : '1',
]);
}
} elseif (Paynow\Model\PaymentMethods\Type::CARD == $payment_method->getType()) {
$this->context->smarty->assign([
'action_card' => PaynowLinkHelper::getPaymentUrl([
'paymentMethodId' => $payment_method->getId()
]),
'action_remove_saved_instrument' => Context::getContext()->link->getModuleLink(
'paynow',
'removeSavedInstrument'
),
'action_remove_saved_instrument_token' => Tools::encrypt($this->context->customer->secure_key ?? ''),
'default_card_image' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->module->name . '/views/img/card-default.svg'),
'paynow_card_instruments' => $payment_method->getSavedInstruments(),
]);
} elseif (Paynow\Model\PaymentMethods\Type::PAYPO == $payment_method->getType()) {
$this->context->smarty->assign([
'action_paypo' => PaynowLinkHelper::getPaymentUrl([
'paymentMethodId' => $payment_method->getId()
]),
]);
}
}
private function getForm($payment_method): ?string
@@ -143,6 +194,14 @@ class PaynowPaymentOptions
return 'module:paynow/views/templates/front/1.7/payment_method_blik_form.tpl';
}
if (Paynow\Model\PaymentMethods\Type::CARD === $payment_method->getType()) {
return 'module:paynow/views/templates/front/1.7/payment_method_card_form.tpl';
}
if (Paynow\Model\PaymentMethods\Type::PAYPO === $payment_method->getType()) {
return 'module:paynow/views/templates/front/1.7/payment_method_paypo_form.tpl';
}
return null;
}

View File

@@ -128,9 +128,16 @@ class PaynowPaymentProcessor
$order->reference
]
);
$idempotency_key = $this->generateIdempotencyKey($external_id);
$idempotency_key = PaynowKeysGenerator::generateIdempotencyKey($external_id);
$payment_request_data = $this->paymentDataBuilder->fromOrder($order);
if ( !PaynowPaymentLockData::checkIsCartLocked($order->id_cart, $order->id) ) {
throw new PaynowPaymentAuthorizeException(
'Cannot create another payment transaction',
$external_id
);
}
return $this->sendPaymentRequest($payment_request_data, $idempotency_key);
}
@@ -146,15 +153,17 @@ class PaynowPaymentProcessor
$external_id
]
);
$idempotency_key = $this->generateIdempotencyKey($external_id);
$idempotency_key = PaynowKeysGenerator::generateIdempotencyKey($external_id);
$payment_request_data = $this->paymentDataBuilder->fromCart($cart, $external_id);
return $this->sendPaymentRequest($payment_request_data, $idempotency_key);
}
if ( !PaynowPaymentLockData::checkIsCartLocked($cart->id) ) {
throw new PaynowPaymentAuthorizeException(
'Cannot create another payment transaction',
$external_id
);
}
private function generateIdempotencyKey($external_id): string
{
return substr(uniqid($external_id . '_', true), 0, 45);
return $this->sendPaymentRequest($payment_request_data, $idempotency_key);
}
/**
@@ -165,11 +174,11 @@ class PaynowPaymentProcessor
if (PaynowConfigurationHelper::CREATE_ORDER_BEFORE_PAYMENT === (int)Configuration::get('PAYNOW_CREATE_ORDER_STATE') && ! empty($this->module->currentOrder)) {
$order = new Order($this->module->currentOrder);
$this->externalId = $order->reference;
$this->externalId = PaynowKeysGenerator::generateExternalIdByOrder($order);
} else {
$cart = $this->context->cart;
$this->externalId = uniqid($cart->id . '_', false);
$this->externalId = PaynowKeysGenerator::generateExternalIdByCart($cart);
}
}

View File

@@ -1,47 +1,54 @@
{
"name": "pay-now/paynow-prestashop",
"description": "Paynow gateway module for PrestaShop",
"license": "MIT",
"authors": [
{
"name": "mElements S.A.",
"email": "kontakt@paynow.pl"
}
],
"require": {
"php": ">=7.1",
"ext-json": "*",
"pay-now/paynow-php-sdk": "^2.2",
"nyholm/psr7": "^1.2",
"php-http/curl-client": "^2.1"
},
"require-dev": {
"prestashop/autoindex": "^1.0",
"friendsofphp/php-cs-fixer": "^2.18",
"squizlabs/php_codesniffer": "^3.6"
},
"config": {
"platform": {
"php": "7.1"
},
"prepend-autoloader": false,
"optimize-autoloader": true
},
"type": "prestashop-module",
"minimum-stability": "stable",
"scripts": {
"cs": [
"vendor/bin/phpcs --standard=PSR2 --ignore=*/vendor/*,*/Test/* ."
"name": "pay-now/paynow-prestashop",
"description": "Paynow gateway module for PrestaShop",
"license": "MIT",
"authors": [
{
"name": "mElements S.A.",
"email": "kontakt@paynow.pl"
}
],
"cs-fix": [
"php vendor/bin/phpcbf --standard=PSR2 --ignore=*/vendor/* ."
]
},
"extra": {
"hooks": {
"pre-commit": [
"php vendor/bin/phpcbf --standard=PSR2 --ignore=*/vendor/* ."
]
"require": {
"php": ">=7.2",
"ext-json": "*",
"pay-now/paynow-php-sdk": "2.4.4",
"nyholm/psr7": "^1.2",
"php-http/curl-client": "^2.1",
"cweagans/composer-patches": "^1.7"
},
"require-dev": {
"prestashop/autoindex": "^1.0",
"friendsofphp/php-cs-fixer": "^2.18",
"squizlabs/php_codesniffer": "^3.6",
"symfony/var-dumper": "^4.4",
"symplify/vendor-patches": "^11.4"
},
"config": {
"platform": {
"php": "7.2"
},
"prepend-autoloader": false,
"optimize-autoloader": true,
"allow-plugins": {
"php-http/discovery": true,
"cweagans/composer-patches": true
}
},
"type": "prestashop-module",
"minimum-stability": "stable",
"scripts": {
"cs": [
"vendor/bin/phpcs --standard=PSR2 --ignore=*/vendor/*,*/Test/* ."
],
"cs-fix": [
"php vendor/bin/phpcbf --standard=PSR2 --ignore=*/vendor/* ."
]
},
"extra": {
"hooks": {
"pre-commit": [
"php vendor/bin/phpcbf --standard=PSR2 --ignore=*/vendor/* ."
]
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
<module>
<name>paynow</name>
<displayName><![CDATA[Zapłać z paynow.pl]]></displayName>
<version><![CDATA[1.6.35]]></version>
<version><![CDATA[1.7.11]]></version>
<description><![CDATA[Akceptuj płatności internetowe przez paynow.pl]]></description>
<author><![CDATA[mElements S.A.]]></author>
<tab><![CDATA[payments_gateways]]></tab>

View File

@@ -28,7 +28,7 @@ class PaynowConfirmBlikModuleFrontController extends PaynowFrontController
}
$this->order = new Order($this->payment->id_order);
$payment_status_from_api = $this->getPaymentStatus($this->payment->id_payment);
$payment_status_from_api = $this->getPaymentStatus($this->payment->id_payment, $external_id);
$statusToProcess = [
'status' => $payment_status_from_api,
'externalId' => $this->payment->external_id,

View File

@@ -50,7 +50,7 @@ class PaynowReturnModuleFrontController extends PaynowFrontController
}
if (Tools::getValue('paymentId')) {
$payment_status_from_api = $this->getPaymentStatus($this->payment->id_payment);
$payment_status_from_api = $this->getPaymentStatus($this->payment->id_payment, $this->payment->external_id);
$statusToProcess = [
'status' => $payment_status_from_api,
'externalId' => $this->payment->external_id,

View File

@@ -34,7 +34,7 @@ class PaynowStatusModuleFrontController extends PaynowFrontController
$payment = PaynowPaymentData::findLastByExternalId($external_id);
$payment_status = $payment->status;
if (Status::STATUS_CONFIRMED !== $payment->status) {
$payment_status_from_api = $this->getPaymentStatus($payment->id_payment);
$payment_status_from_api = $this->getPaymentStatus($payment->id_payment, $payment->external_id);
$statusToProcess = [
'status' => $payment_status_from_api,
'externalId' => $payment->external_id,

View File

@@ -0,0 +1,133 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
class PaynowPaymentLockData extends ObjectModel
{
const TABLE = 'paynow_payment_locks';
const PRIMARY_KEY = 'id';
const COUNTER_LIMIT = 6;
public $id;
public $id_order;
public $id_cart;
public $counter;
public $created_at;
public $modified_at;
public static $definition = [
'table' => self::TABLE,
'primary' => self::PRIMARY_KEY,
'fields' => [
self::PRIMARY_KEY => ['type' => self::TYPE_INT],
'id_order' => ['type' => self::TYPE_INT, 'required' => false],
'id_cart' => ['type' => self::TYPE_INT, 'required' => true],
'counter' => ['type' => self::TYPE_INT, 'required' => false],
'created_at' => ['type' => self::TYPE_DATE, 'required' => true],
'modified_at' => ['type' => self::TYPE_DATE, 'required' => true]
]
];
public static function create(
$id_order,
$id_cart
) {
$now = (new DateTime('now', new DateTimeZone(Configuration::get('PS_TIMEZONE'))))->format('Y-m-d H:i:s');
$model = new PaynowPaymentLockData();
$model->id_order = $id_order;
$model->id_cart = $id_cart;
$model->counter = 1;
$model->created_at = $now;
$model->modified_at = $now;
try {
$result = $model->save(false, false);
if (!$result) {
throw new Exception('Locks Model-save() returned false.');
}
} catch (Exception $e) {
PaynowLogger::debug(
'Can\'t create paynow lock entry',
[
'model' => (array)$model,
'exception' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getline(),
'DB error' => Db::getInstance()->getMsgError(),
]
);
throw $e;
}
}
/**
* @param $order_id
*
* @return PrestaShopCollection
* @throws PrestaShopException
*/
public static function findByOrderId($order_id)
{
Db::getInstance(_PS_USE_SQL_SLAVE_)->disableCache();
$queryBuilder = new PrestaShopCollection(self::class);
return $queryBuilder
->where('id_order', '=', $order_id)
->setPageSize(1)
->getFirst();
}
/**
* @param $cart_id
*
* @return PrestaShopCollection
* @throws PrestaShopException
*/
public static function findByCartId($cart_id)
{
Db::getInstance(_PS_USE_SQL_SLAVE_)->disableCache();
$queryBuilder = new PrestaShopCollection(self::class);
return $queryBuilder
->where('id_cart', '=', $cart_id)
->setPageSize(1)
->getFirst();
}
public static function checkIsCartLocked($id_cart, $id_order = 0): bool
{
Db::getInstance(_PS_USE_SQL_SLAVE_)->disableCache();
$data = PaynowPaymentLockData::findByCartId($id_cart);
if ($data) {
if ($data->counter >= self::COUNTER_LIMIT) {
return false;
}
$data->counter++;
$data->update();
return true;
} else {
self::create($id_order, $id_cart);
return true;
}
}
}

View File

@@ -18,6 +18,7 @@ include_once(dirname(__FILE__) . '/vendor/autoload.php');
include_once(dirname(__FILE__) . '/classes/PaynowFrontController.php');
include_once(dirname(__FILE__) . '/classes/PaynowLogger.php');
include_once(dirname(__FILE__) . '/classes/PaynowHelper.php');
include_once(dirname(__FILE__) . '/classes/PaynowKeysGenerator.php');
include_once(dirname(__FILE__) . '/classes/PaynowNotificationRetryProcessing.php');
include_once(dirname(__FILE__) . '/classes/PaynowNotificationStopProcessing.php');
include_once(dirname(__FILE__) . '/classes/PaynowConfigurationHelper.php');
@@ -31,11 +32,13 @@ include_once(dirname(__FILE__) . '/classes/PaynowAdminFormHelper.php');
include_once(dirname(__FILE__) . '/classes/PaynowOrderCreateProcessor.php');
include_once(dirname(__FILE__) . '/classes/PaynowOrderStateProcessor.php');
include_once(dirname(__FILE__) . '/models/PaynowPaymentData.php');
include_once(dirname(__FILE__) . '/models/PaynowPaymentLockData.php');
include_once(dirname(__FILE__) . '/classes/PaynowFrontController.php');
include_once(dirname(__FILE__) . '/classes/PaynowPaymentProcessor.php');
include_once(dirname(__FILE__) . '/classes/PaynowPaymentDataBuilder.php');
include_once(dirname(__FILE__) . '/classes/PaynowGithubClient.php');
include_once(dirname(__FILE__) . '/classes/PaynowLockingHelper.php');
include_once(dirname(__FILE__) . '/classes/PaynowSavedInstrumentHelper.php');
class Paynow extends PaymentModule
{
@@ -47,7 +50,7 @@ class Paynow extends PaymentModule
{
$this->name = 'paynow';
$this->tab = 'payments_gateways';
$this->version = '1.6.35';
$this->version = '1.7.12';
$this->ps_versions_compliancy = ['min' => '1.6.0', 'max' => _PS_VERSION_];
$this->author = 'mElements S.A.';
$this->is_eu_compatible = 1;
@@ -77,12 +80,14 @@ class Paynow extends PaymentModule
public function install()
{
if (!parent::install() ||
if (!parent::install() ||
!$this->createDbTables() ||
!$this->createModuleSettings() ||
!$this->registerHooks()) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_UPDATED);
return true;
}
@@ -91,29 +96,62 @@ class Paynow extends PaymentModule
if (!$this->unregisterHooks() || !$this->deleteModuleSettings() || !parent::uninstall()) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_UNINSTALLED);
return true;
}
public function enable($force_all = false)
{
if (!parent::enable($force_all)) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_ENABLED);
return true;
}
public function disable($force_all = false)
{
if (!parent::disable($force_all)) {
return false;
}
$this->saveShopPluginStatus(Paynow\Service\ShopConfiguration::STATUS_DISABLED);
return true;
}
private function createDbTables()
{
return Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'paynow_payments` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`id_order` INT(10) UNSIGNED NOT NULL,
`id_cart` INT(10) UNSIGNED NOT NULL,
`id_payment` varchar(30) NOT NULL,
`order_reference` varchar(9) NOT NULL,
`external_id` varchar(50) NOT NULL,
`status` varchar(64) NOT NULL,
`total` DECIMAL(20,6) NOT NULL DEFAULT \'0.000000\',
`locked` TINYINT(1) NOT NULL DEFAULT 0,
`active` tinyint(1) NOT NULL DEFAULT 0,
`counter` tinyint(1) NOT NULL DEFAULT 0,
`sent_at` datetime DEFAULT NULL,
`created_at` datetime,
`modified_at` datetime,
UNIQUE (`id_payment`, `status`),
INDEX `index_order_cart_payment_reference` (`id_order`, `id_cart`, `id_payment`, `order_reference`)
)');
$result = Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'paynow_payments` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`id_order` INT(10) UNSIGNED NOT NULL,
`id_cart` INT(10) UNSIGNED NOT NULL,
`id_payment` varchar(30) NOT NULL,
`order_reference` varchar(9) NOT NULL,
`external_id` varchar(50) NOT NULL,
`status` varchar(64) NOT NULL,
`total` DECIMAL(20,6) NOT NULL DEFAULT \'0.000000\',
`locked` TINYINT(1) NOT NULL DEFAULT 0,
`active` tinyint(1) NOT NULL DEFAULT 0,
`counter` tinyint(1) NOT NULL DEFAULT 0,
`sent_at` datetime DEFAULT NULL,
`created_at` datetime,
`modified_at` datetime,
UNIQUE (`id_payment`, `status`),
INDEX `index_order_cart_payment_reference` (`id_order`, `id_cart`, `id_payment`, `order_reference`)
)');
return $result && Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'paynow_payment_locks` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`id_order` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`id_cart` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`counter` tinyint(1) NOT NULL DEFAULT 0,
`created_at` datetime,
`modified_at` datetime,
INDEX `index_payment_cart_reference` (`id_cart`),
INDEX `index_payment_order_reference` (`id_order`)
)');
}
private function registerHooks()
@@ -378,6 +416,12 @@ class Paynow extends PaymentModule
return $this->l('Pay by Google Pay');
case \Paynow\Model\PaymentMethods\Type::APPLE_PAY:
return $this->l('Pay by Apple Pay');
case 'DIGITAL_WALLETS':
return $this->l('Pay by digital wallets');
case \Paynow\Model\PaymentMethods\Type::PAYPO:
return $this->l('PayPo - buy now, pay later');
case \Paynow\Model\PaymentMethods\Type::CLICK_TO_PAY:
return $this->l('Click To Pay - pay with pre-saved card');
}
}
@@ -389,13 +433,13 @@ class Paynow extends PaymentModule
{
$total = number_format($this->context->cart->getOrderTotal() * 100, 0, '', '');
$currency = new Currency($this->context->cart->id_currency);
return (new PaynowPaymentMethodsHelper($this->getPaynowClient()))->getAvailable($currency->iso_code, $total);
return (new PaynowPaymentMethodsHelper($this->getPaynowClient()))->getAvailable($currency->iso_code, $total, $this->context, $this);
}
private function getGDPRNotices(): array
{
$locale = $this->context->language->locale ?? $this->context->language->language_code;
return (new PaynowGDPRHelper($this->getPaynowClient()))->getNotices($locale);
return (new PaynowGDPRHelper($this->getPaynowClient(), $this->context->cart))->getNotices($locale);
}
/** Returns is possible to show payment option
@@ -436,14 +480,22 @@ class Paynow extends PaymentModule
'cta_text' => $this->getCallToActionText(),
'logo' => $this->getLogo(),
'paynow_url' => PaynowLinkHelper::getPaymentUrl(),
'data_processing_notices' => $gdpr_notices ?? null
'data_processing_notices' => $gdpr_notices ?? null,
'data_paynow_plugin_version' => $this->version,
]);
$payment_options = [];
if ((int)Configuration::get('PAYNOW_SEPARATE_PAYMENT_METHODS') === 1) {
$payment_methods = $this->getPaymentMethods();
if (!empty($payment_methods)) {
$digital_wallets = [
Paynow\Model\PaymentMethods\Type::CLICK_TO_PAY => null,
Paynow\Model\PaymentMethods\Type::GOOGLE_PAY => null,
Paynow\Model\PaymentMethods\Type::APPLE_PAY => null,
];
$list = [];
$payment_options = [];
foreach ($payment_methods->getAll() as $payment_method) {
if (!isset($list[$payment_method->getType()])) {
if (Paynow\Model\PaymentMethods\Type::PBL == $payment_method->getType()) {
@@ -454,7 +506,13 @@ class Paynow extends PaymentModule
'authorization' => $payment_method->getAuthorizationType(),
'pbls' => $payment_methods->getOnlyPbls()
]);
} else {
} elseif (array_key_exists($payment_method->getType(), $digital_wallets)) {
if (!$payment_method->isEnabled()) {
continue;
}
$digital_wallets[$payment_method->getType()] = $payment_method;
} else {
if (Paynow\Model\PaymentMethods\Type::BLIK == $payment_method->getType()) {
$this->context->smarty->assign([
'action_blik' => Context::getContext()->link->getModuleLink(
@@ -467,22 +525,52 @@ class Paynow extends PaymentModule
'action_token' => Tools::encrypt($this->context->customer->secure_key),
'action_token_refresh' => Context::getContext()->link->getModuleLink('paynow', 'customerToken'),
'error_message' => $this->getTranslationsArray()['An error occurred during the payment process'],
'terms_message' => $this->getTranslationsArray()['You have to accept terms and conditions'],
'terms_message' => $this->getTranslationsArray()['First accept the terms of service, then click pay.'],
'blik_autofocus' => Configuration::get('PAYNOW_BLIK_AUTOFOCUS_ENABLED') === '0' ? '0' : '1',
]);
}
array_push($payment_options, [
$payment_option = [
'name' => $this->getPaymentMethodTitle($payment_method->getType()),
'image' => $payment_method->getImage(),
'id' => $payment_method->getId(),
'enabled' => $payment_method->isEnabled(),
'type' => $payment_method->getType(),
'authorization' => $payment_method->getAuthorizationType(),
]);
];
if (Paynow\Model\PaymentMethods\Type::CARD == $payment_method->getType()) {
$payment_option = array_merge($payment_option, [
'action_card' => PaynowLinkHelper::getPaymentUrl([
'paymentMethodId' => $payment_method->getId()
]),
'action_remove_saved_instrument' => Context::getContext()->link->getModuleLink(
'paynow',
'removeSavedInstrument'
),
'action_token' => Tools::encrypt($this->context->customer->secure_key),
'default_card_image' => Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/card-default.svg'),
'instruments' => $payment_method->getSavedInstruments(),
]);
}
array_push($payment_options, $payment_option);
}
$list[$payment_method->getType()] = $payment_method->getId();
}
}
$digital_wallets = array_values(array_filter($digital_wallets));
if (!empty($digital_wallets)) {
$payment_options[] = [
'name' => $this->getPaymentMethodTitle('DIGITAL_WALLETS'),
'image' => $this->getDigitalWalletsLogo($digital_wallets),
'type' => 'DIGITAL_WALLETS',
'authorization' => '',
'pbls' => $digital_wallets
];
}
$this->context->smarty->assign([
'payment_options' => $payment_options
]);
@@ -535,8 +623,11 @@ class Paynow extends PaymentModule
*/
public function hookActionOrderSlipAdd($params)
{
if ((int)Configuration::get('PAYNOW_REFUNDS_ENABLED') === 1 && Tools::isSubmit('makeRefundViaPaynow') &&
$this->name == $params['order']->module) {
if ((int)Configuration::get('PAYNOW_REFUNDS_ENABLED') === 1
&& Tools::isSubmit('makeRefundViaPaynow')
&& $this->name == $params['order']->module
)
{
(new PaynowRefundProcessor($this->getPaynowClient(), $this->displayName))
->processFromOrderSlip($params['order']);
}
@@ -609,6 +700,8 @@ class Paynow extends PaymentModule
return $this->fetchTemplate('/views/templates/admin/_partials/upgrade.tpl');
}
$this->sendShopPluginStatus();
return null;
}
@@ -641,6 +734,22 @@ class Paynow extends PaymentModule
return false;
}
public function getDigitalWalletsLogo(array $wallets): string
{
if(count($wallets) === 1) {
return $wallets[0]->getImage();
}
$types = array_map(function($dw) {
return strtolower(substr($dw->getType(), 0, 1));
}, $wallets);
sort($types);
$types = implode('', $types);
return Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/digital-wallets-' . $types . '.svg');
}
public function getLogo()
{
return Media::getMediaPath(_PS_MODULE_DIR_ . $this->name . '/views/img/logo-paynow.png');
@@ -743,6 +852,60 @@ class Paynow extends PaymentModule
}
}
private function saveShopPluginStatus($status)
{
$statuses = Configuration::get('PAYNOW_PLUGIN_STATUSES');
if (empty($statuses)) {
$statuses = [];
} else {
$statuses = json_decode($statuses, true);
}
date_default_timezone_set('UTC');
$statuses[] = [
'status' => $status,
'timestamp' => date('Y-m-d\TH:i:s.v\Z'),
];
Configuration::updateValue('PAYNOW_PLUGIN_STATUSES', json_encode($statuses));
}
private function sendShopPluginStatus()
{
if ( empty( $this->getApiKey() ) ) {
return;
}
$statuses = Configuration::get('PAYNOW_PLUGIN_STATUSES');
Configuration::updateValue('PAYNOW_PLUGIN_STATUSES', json_encode([]));
if (empty($statuses)) {
return;
} else {
$statuses = json_decode($statuses, true);
}
if (empty($statuses)) {
return;
}
$shop_configuration = new Paynow\Service\ShopConfiguration($this->getPaynowClient());
try {
$shop_configuration->status($statuses);
} catch (Paynow\Exception\PaynowException $exception) {
PaynowLogger::error(
'An error occurred during shop plugin status send {code={}, message={}}',
[
$exception->getCode(),
$exception->getPrevious()->getMessage()
]
);
foreach ($exception->getErrors() as $error) {
PaynowLogger::error('Error', ['mes' => $error->getMessage()]);
}
}
}
public function getContent()
{
if (Tools::isSubmit('submit' . $this->name)) {
@@ -819,7 +982,6 @@ class Paynow extends PaymentModule
'Wrong BLIK code' => $this->l('Wrong BLIK code'),
'BLIK code has expired' => $this->l('BLIK code has expired'),
'BLIK code already used' => $this->l('BLIK code already used'),
'You have to accept terms and conditions' => $this->l('You have to accept terms and conditions'),
'Moment of creating order' => $this->l('Moment of creating order'),
'On clicking the Place order' => $this->l('On clicking the Place order'),
'After the successful Paynow payment' => $this->l('After the successful Paynow payment'),
@@ -828,6 +990,9 @@ class Paynow extends PaymentModule
'Show retry payment button on selected statuses' => $this->l('Show retry payment button on selected statuses'),
'BLIK field autofocus' => $this->l('BLIK field autofocus'),
'Autofocus on checkout form field: BLIK code. Enabled by default. Disabling may be helpful when checkout page is visualy long (e.g. single-page checkout).' => $this->l('Autofocus on checkout form field: BLIK code. Enabled by default. Disabling may be helpful when checkout page is visualy long (e.g. single-page checkout).'),
'An error occurred while deleting the saved card.' => $this->l('An error occurred while deleting the saved card.'),
'First accept the terms of service, then click pay.' => $this->l('First accept the terms of service, then click pay.'),
'Digital wallets' => $this->l('Digital wallets'),
];
}
}

View File

@@ -13,10 +13,17 @@ $_MODULE['<{paynow}prestashop>paynow_cc21116ce900f38c0691823ab193b9a3'] = 'Płat
$_MODULE['<{paynow}prestashop>paynow_961d23fcb6c49cee1150dba52beb04ca'] = 'Płatność szybkim przelewem';
$_MODULE['<{paynow}prestashop>paynow_2a34963732b2fea04f1417120be393ae'] = 'Płatność Google Pay';
$_MODULE['<{paynow}prestashop>paynow_111999b13ca63380771744ea02c4906b'] = 'Płatność Apple Pay';
$_MODULE['<{paynow}prestashop>paynow_80f5e0ec61eb764d2c250d5c1c96da57'] = 'Płatność portfelami cyfrowymi';
$_MODULE['<{paynow}prestashop>paynow_6b46e5850b6a6bf8af7118c5f21cd916'] = 'PayPo - kup teraz, zapłać później';
$_MODULE['<{paynow}prestashop>paynow_1557d8cc30061fe149e267e1e196c4dc'] = 'Click To Pay - zapłać zapisaną kartą';
$_MODULE['<{paynow}prestashop>paynow_428a1abd50e8dadb4fdc0f3861dbe04b'] = 'Zleć zwrot środków przez paynow.pl';
$_MODULE['<{paynow}prestashop>paynow_dc34c9c3d4e62630ad62b58828cae5d8'] = 'Musisz wprowadzić klucze integracyjne';
$_MODULE['<{paynow}prestashop>paynow_aaca790b3b211a66ee5ddb51b817cbf2'] = 'Czas ważności płatności musi być większy niż 60 i mniejszy niż 86400 sekund.';
$_MODULE['<{paynow}prestashop>paynow_02436b9306ccb6eeb1e435a6109bf6ca'] = 'Czas ważności płatności musi być liczbą całkowitą';
$_MODULE['<{paynow}prestashop>paynow_9e900430ecef9d66cd31784b325c89e1'] = 'Niepoprawny format klucza dostępu do API (sandbox)';
$_MODULE['<{paynow}prestashop>paynow_28a67914858c1ad4333046e878cdaff2'] = 'Niepoprawny format klucza obliczania podpisu (sandbox)';
$_MODULE['<{paynow}prestashop>paynow_93b851b08ee6b549ccbed93252ba3e3c'] = 'Niepoprawny format klucza dostępu do API (produkcja)';
$_MODULE['<{paynow}prestashop>paynow_f78db1f0dc7be32221b1e5a18f23ef8d'] = 'Niepoprawny format klucza obliczania podpisu (produkcja)';
$_MODULE['<{paynow}prestashop>paynow_20015706a8cbd457cbb6ea3e7d5dc9b3'] = 'Konfiguracja zapisana';
$_MODULE['<{paynow}prestashop>paynow_f27165ecfba5364104162ba4eef9568b'] = 'Błędna konfiguracja kluczy dostępowych do API';
$_MODULE['<{paynow}prestashop>paynow_c9b759157090f6e673fc780ca46ee3e1'] = 'Odpowiedź z API: ';
@@ -45,9 +52,7 @@ $_MODULE['<{paynow}prestashop>paynow_80c85fada5bbc57f4ca99ba8c1634b50'] = 'na st
$_MODULE['<{paynow}prestashop>paynow_baa5053eacdd3b516c60cbcc9695c12a'] = 'Zwracaj koszty przesyłki';
$_MODULE['<{paynow}prestashop>paynow_e128ece85361c066ea30a503fb868121'] = 'Dodatkowo ustawienia';
$_MODULE['<{paynow}prestashop>paynow_5c2c5c1ab84b763f09cd2ab6bd5720a3'] = 'Pozwól wybrać metody płatności';
$_MODULE['<{paynow}prestashop>paynow_ecd133189898f0bb5c22929d945b5a16'] = 'Pokaż przycisk ponów płatność';
$_MODULE['<{paynow}prestashop>paynow_f80582610895a112b5bd6be72a44b0eb'] = 'Przycisk pokazywany jest na ekranie szczegółów zamówienia.';
$_MODULE['<{paynow}prestashop>paynow_f073bd1fb850d58894658439ac926d45'] = 'Pokaż przycisk ponów płatność dla wybranych statusów';
$_MODULE['<{paynow}prestashop>paynow_95a791ac35811c3805b6e51b9899638a'] = 'Ukryj metody płatności';
$_MODULE['<{paynow}prestashop>paynow_b5c4d3273e029a1ab33c3ef315a00916'] = 'Użyj strony potwierdzenie-zamówienia jako strony powrotu do sklepu';
$_MODULE['<{paynow}prestashop>paynow_a6cd1dd6e1c5c70b936136dc687f793e'] = 'Po płatności kupujący zostanie przekierowany do klasycznej strony potwierdzenia zamówienia.';
$_MODULE['<{paynow}prestashop>paynow_33d2b4361184679164c34a538c362744'] = 'Wysyłaj informację o produktach';
@@ -64,14 +69,31 @@ $_MODULE['<{paynow}prestashop>paynow_eed0e5c8805353597a14d1bf8723b6c9'] = 'Potwi
$_MODULE['<{paynow}prestashop>paynow_1027fdee59a948aa52827bcb3cbf8f50'] = 'Błędny kod BLIK';
$_MODULE['<{paynow}prestashop>paynow_d91754b07a6dea16490d2411b0b167bb'] = 'Kod jest nieaktualny';
$_MODULE['<{paynow}prestashop>paynow_04da3af7560536b3731ac6a478e71c0d'] = 'Kod był wcześniej wykorzystany';
$_MODULE['<{paynow}prestashop>paynow_ed9bfacc48621ce7a789eb48ef273d51'] = 'Zaakceptuj warunki świadczenia usługi';
$_MODULE['<{paynow}prestashop>paynow_2d7b427e37231031e942756d082bf03f'] = 'Tworzenie zamówienia';
$_MODULE['<{paynow}prestashop>paynow_247421e49992417c813b035ca3256a01'] = 'Po kliknięciu przycisku Złóż zamówienie';
$_MODULE['<{paynow}prestashop>paynow_8d857bed9bc986ff7295ba154b7a99d1'] = 'Po udanej płatności Paynow';
$_MODULE['<{paynow}prestashop>paynow_ecd133189898f0bb5c22929d945b5a16'] = 'Pokaż przycisk ponów płatność';
$_MODULE['<{paynow}prestashop>paynow_f80582610895a112b5bd6be72a44b0eb'] = 'Przycisk pokazywany jest na ekranie szczegółów zamówienia.';
$_MODULE['<{paynow}prestashop>paynow_f073bd1fb850d58894658439ac926d45'] = 'Pokaż przycisk ponów płatność dla wybranych statusów';
$_MODULE['<{paynow}prestashop>paynow_18089cf8fe24bbd8110951a7419cdc24'] = 'Autofocus dla pola BLIK';
$_MODULE['<{paynow}prestashop>paynow_2075cf7a7fc00b561fb19947f3141226'] = 'Autofocus dla pola BLIK na ekrakanie koszyka przy wyborze płatności. Domyślnie włączone. Wyłączenie może być przydatne, jeśli strona kosztyka jest długa (np. jeśli zastosowano moduł pojedynczej strony koszyka)';
$_MODULE['<{paynow}prestashop>paynow_98725517a57057b6652ac5ac1717688a'] = 'Wystąpił błąd podczas usuwania zapisanej karty.';
$_MODULE['<{paynow}prestashop>paynow_5df39de6796a1b94e70aeabb30c6f441'] = 'Najpierw zaakceptuj warunki świadczenia usługi, potem kliknij zapłać.';
$_MODULE['<{paynow}prestashop>paynow_e2c9b039841eebbab5e62a14cdc9ec6b'] = 'Portfele cyfrowe';
$_MODULE['<{paynow}prestashop>paynowadminformhelper_6adf97f83acf6453d4a6a4b1070f3754'] = 'Żadne';
$_MODULE['<{paynow}prestashop>order_details_d43f2c65af8fb54fa71636c3e5308cf3'] = 'Ponów płatność przez paynow.pl';
$_MODULE['<{paynow}prestashop>payment_data_processing_info_43340e6cc4e88197d57f8d6d5ea50a46'] = 'Czytaj więcej';
$_MODULE['<{paynow}prestashop>payment_method_blik_form_ea37f7c5bc6b5b74ea529c3d21a468d1'] = 'Podaj kod BLIK';
$_MODULE['<{paynow}prestashop>payment_method_blik_form_99938b17c91170dfb0c2f3f8bc9f2a85'] = 'Zapłać';
$_MODULE['<{paynow}prestashop>payment_data_processing_info_43340e6cc4e88197d57f8d6d5ea50a46'] = 'Czytaj więcej';
$_MODULE['<{paynow}prestashop>payment_method_card_form_de03c9a7273f2eb642e921592abb2907'] = 'Wybierz zapisaną kartę lub wprowadź dane nowej:';
$_MODULE['<{paynow}prestashop>payment_method_card_form_623990b71104bea810bac8c9ebc08471'] = 'Karta:';
$_MODULE['<{paynow}prestashop>payment_method_card_form_76fd25c5c62f184483aea1dce80902ce'] = 'Wygasła:';
$_MODULE['<{paynow}prestashop>payment_method_card_form_7896bdb62c4e9bd3baa9f8d56ffaa031'] = 'Wygasa:';
$_MODULE['<{paynow}prestashop>payment_method_card_form_0f6969d7052da9261e31ddb6e88c136e'] = 'usuń';
$_MODULE['<{paynow}prestashop>payment_method_card_form_98725517a57057b6652ac5ac1717688a'] = 'Wystąpił błąd podczas usuwania zapisanej karty.';
$_MODULE['<{paynow}prestashop>payment_method_card_form_3f9742a5b058d0a3f1b7ffa4eed8b9cc'] = 'Usuń kartę';
$_MODULE['<{paynow}prestashop>payment_method_card_form_20d44104dfc61a9c2de2814c26208c2b'] = 'Wprowadź dane nowej karty';
$_MODULE['<{paynow}prestashop>payment_method_card_form_f21bac71884b2f861ed0b5479e5607f3'] = 'Możesz ją zapisać w następnym kroku';
$_MODULE['<{paynow}prestashop>return_3eea8b36c11f4bdf099b22d3f8788cff'] = 'Zapłać przelewem online lub BLIK';
$_MODULE['<{paynow}prestashop>return_f403ac95a07ddae169d88c4833ace3ce'] = 'Dziękujemy za złożenie zamówienia!';
$_MODULE['<{paynow}prestashop>return_163136ea55fe3c7b78c2334bd1133a9c'] = 'Numer Twojego zamówienia:';
@@ -85,6 +107,7 @@ $_MODULE['<{paynow}prestashop>confirm_blik_eed0e5c8805353597a14d1bf8723b6c9'] =
$_MODULE['<{paynow}prestashop>confirm_blik_1e554f863a6a8e8ec5deca559c6a7408'] = 'Potwierdź płatność BLIKIEM';
$_MODULE['<{paynow}prestashop>confirm_blik_163136ea55fe3c7b78c2334bd1133a9c'] = 'Numer Twojego zamówienia:';
$_MODULE['<{paynow}prestashop>confirm_blik_2a32cf6f2fa4e898ac64c8015a27e27e'] = 'Status zamówienia:';
$_MODULE['<{paynow}prestashop>payment_method_digital_wallets_form_d13efc31eb6f59b1508f2552b507fa4c'] = 'Wybierz portfel:';
$_MODULE['<{paynow}prestashop>payment_form_427ee560f858d9e02e102b0060d1973e'] = 'Wybierz bank:';
$_MODULE['<{paynow}prestashop>upgrade_7fa519ae904624b16cc755ea761546c1'] = 'Dostępna jest nowa wersja modułu Płacę z paynow.pl';
$_MODULE['<{paynow}prestashop>upgrade_6af7b7a01de0b0b0954a237def7349ef'] = 'Pobierz';
@@ -97,12 +120,3 @@ $_MODULE['<{paynow}prestashop>account_2652eec977dcb2a5aea85f5bec235b05'] = 'z te
$_MODULE['<{paynow}prestashop>account_e900e40bc91d3f9f7f0a99fed68a2e96'] = 'środowiska';
$_MODULE['<{paynow}prestashop>account_be11de1ab431efc5d058e52e68667abb'] = 'Klucze uwierzytelniające dostępne są w zakładce Paynow -> Ustawienia -> Sklepy i punkty płatności -> Dane uwierzytelniające w bankowości internetowej mBanku.';
$_MODULE['<{paynow}prestashop>info_37050ea474edaaacb565cbec9d64bea3'] = 'Moduł umożliwia dokonywanie automatycznego zwrotu środków z salda dla płatności zrealizowanych przez paynow.pl. Aby skorzystać z tej opcji musisz wybrać dzienną częstotliwość wypłat w panelu paynow. Aby to zrobić wejdź w `Ustawienia / Harmonogram wypłat` a następnie wybierz ustawienie dla odpowiedniego sklepu.';
$_MODULE['<{paynow}prestashop>paynow_18089cf8fe24bbd8110951a7419cdc24'] = 'Autofocus dla pola BLIK';
$_MODULE['<{paynow}prestashop>paynow_2075cf7a7fc00b561fb19947f3141226'] = 'Autofocus dla pola BLIK na ekrakanie koszyka przy wyborze płatności. Domyślnie włączone. Wyłączenie może być przydatne, jeśli strona kosztyka jest długa (np. jeśli zastosowano moduł pojedynczej strony koszyka)';
$_MODULE['<{paynow}prestashop>paynow_95a791ac35811c3805b6e51b9899638a'] = 'Ukryj metody płatności';
$_MODULE['<{paynow}prestashop>paynow_9e900430ecef9d66cd31784b325c89e1'] = 'Niepoprawny format klucza dostępu do API (sandbox)';
$_MODULE['<{paynow}prestashop>paynow_28a67914858c1ad4333046e878cdaff2'] = 'Niepoprawny format klucza obliczania podpisu (sandbox)';
$_MODULE['<{paynow}prestashop>paynow_93b851b08ee6b549ccbed93252ba3e3c'] = 'Niepoprawny format klucza dostępu do API (produkcja)';
$_MODULE['<{paynow}prestashop>paynow_f78db1f0dc7be32221b1e5a18f23ef8d'] = 'Niepoprawny format klucza obliczania podpisu (produkcja)';
$_MODULE['<{paynow}prestashop>paynow_6adf97f83acf6453d4a6a4b1070f3754'] = 'Nie ukrywaj';

View File

@@ -0,0 +1,53 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
if (!defined('_PS_VERSION_')) {
exit;
}
/**
* @throws PrestaShopDatabaseException
*/
function upgrade_module_1_7_11($module)
{
try {
if (Db::getInstance()->executeS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "external_id"') == false) {
Db::getInstance()->execute('ALTER TABLE ' . _DB_PREFIX_ . 'paynow_payments ADD external_id VARCHAR(50) NOT NULL AFTER `order_reference`');
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "total"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `total` DECIMAL(20,6) NOT NULL DEFAULT '0.000000' AFTER `status`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "locked"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `locked` TINYINT(1) NOT NULL DEFAULT 0 AFTER `total`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "counter"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `counter` TINYINT(1) NOT NULL DEFAULT 0 AFTER `locked`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "active"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `active` TINYINT(1) NOT NULL DEFAULT 0 AFTER `counter`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "sent_at"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `sent_at` datetime NULL AFTER `active`;");
}
} catch (PrestaShopDatabaseException $exception) {
PaynowLogger::error('Fatal error on upgrade: ' . $exception->getMessage() . ' ' . $exception->getTraceAsString());
}
return true;
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License (MIT)
* that is bundled with this package in the file LICENSE.md.
*
* @author mElements S.A.
* @copyright mElements S.A.
* @license MIT License
*/
if (!defined('_PS_VERSION_')) {
exit;
}
/**
* @throws PrestaShopDatabaseException
*/
function upgrade_module_1_7_12($module)
{
try {
if (Db::getInstance()->executeS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "external_id"') == false) {
Db::getInstance()->execute('ALTER TABLE ' . _DB_PREFIX_ . 'paynow_payments ADD external_id VARCHAR(50) NOT NULL AFTER `order_reference`');
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "total"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `total` DECIMAL(20,6) NOT NULL DEFAULT '0.000000' AFTER `status`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "locked"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `locked` TINYINT(1) NOT NULL DEFAULT 0 AFTER `total`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "counter"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `counter` TINYINT(1) NOT NULL DEFAULT 0 AFTER `locked`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "active"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `active` TINYINT(1) NOT NULL DEFAULT 0 AFTER `counter`;");
}
if (Db::getInstance()->ExecuteS('SHOW COLUMNS FROM ' . _DB_PREFIX_ . 'paynow_payments LIKE "sent_at"') == false) {
Db::getInstance()->Execute("ALTER TABLE `" . _DB_PREFIX_ . "paynow_payments` ADD `sent_at` datetime NULL AFTER `active`;");
}
Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'paynow_payment_locks` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`id_order` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`id_cart` INT(10) UNSIGNED NOT NULL DEFAULT 0,
`counter` tinyint(1) NOT NULL DEFAULT 0,
`created_at` datetime,
`modified_at` datetime,
INDEX `index_payment_cart_reference` (`id_cart`),
INDEX `index_payment_order_reference` (`id_order`)
)');
} catch (PrestaShopDatabaseException $exception) {
PaynowLogger::error('Fatal error on upgrade: ' . $exception->getMessage() . ' ' . $exception->getTraceAsString());
}
return true;
}

10
modules/paynow/vendor/.htaccess vendored Normal file
View File

@@ -0,0 +1,10 @@
# Apache 2.2
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
Require all denied
</IfModule>

View File

@@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInita3df77b4b522885b715a8fd38a5db444::getLoader();
return ComposerAutoloaderInit93238e2dd576a8d3792c34ad274d581f::getLoader();

View File

@@ -2,7 +2,7 @@
"name": "clue/stream-filter",
"description": "A simple and modern approach to stream filtering in PHP",
"keywords": ["stream", "callback", "filter", "php_user_filter", "stream_filter_append", "stream_filter_register", "bucket brigade"],
"homepage": "https://github.com/clue/php-stream-filter",
"homepage": "https://github.com/clue/stream-filter",
"license": "MIT",
"authors": [
{
@@ -14,13 +14,19 @@
"php": ">=5.3"
},
"require-dev": {
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
},
"autoload": {
"psr-4": { "Clue\\StreamFilter\\": "src/" },
"files": [ "src/functions_include.php" ]
"psr-4": {
"Clue\\StreamFilter\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"autoload-dev": {
"psr-4": { "Clue\\Tests\\StreamFilter\\": "tests/" }
"psr-4": {
"Clue\\Tests\\StreamFilter\\": "tests/"
}
}
}

View File

@@ -104,13 +104,27 @@ namespace Clue\StreamFilter;
*/
function append($stream, $callback, $read_write = STREAM_FILTER_ALL)
{
$ret = @\stream_filter_append($stream, register(), $read_write, $callback);
$errstr = '';
\set_error_handler(function ($_, $error) use (&$errstr) {
// Match errstr from PHP's warning message.
// stream_filter_append() expects parameter 1 to be resource,...
$errstr = $error; // @codeCoverageIgnore
});
try {
$ret = \stream_filter_append($stream, register(), $read_write, $callback);
} catch (\TypeError $e) { // @codeCoverageIgnoreStart
// Throws TypeError on PHP 8.0+
\restore_error_handler();
throw $e;
} // @codeCoverageIgnoreEnd
\restore_error_handler();
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
// @codeCoverageIgnoreStart
if ($ret === false) {
$error = \error_get_last() + array('message' => '');
throw new \RuntimeException('Unable to append filter: ' . $error['message']);
throw new \RuntimeException('Unable to append filter: ' . $errstr);
}
// @codeCoverageIgnoreEnd
@@ -147,13 +161,27 @@ function append($stream, $callback, $read_write = STREAM_FILTER_ALL)
*/
function prepend($stream, $callback, $read_write = STREAM_FILTER_ALL)
{
$ret = @\stream_filter_prepend($stream, register(), $read_write, $callback);
$errstr = '';
\set_error_handler(function ($_, $error) use (&$errstr) {
// Match errstr from PHP's warning message.
// stream_filter_prepend() expects parameter 1 to be resource,...
$errstr = $error; // @codeCoverageIgnore
});
try {
$ret = \stream_filter_prepend($stream, register(), $read_write, $callback);
} catch (\TypeError $e) { // @codeCoverageIgnoreStart
// Throws TypeError on PHP 8.0+
\restore_error_handler();
throw $e;
} // @codeCoverageIgnoreEnd
\restore_error_handler();
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
// @codeCoverageIgnoreStart
if ($ret === false) {
$error = \error_get_last() + array('message' => '');
throw new \RuntimeException('Unable to prepend filter: ' . $error['message']);
throw new \RuntimeException('Unable to prepend filter: ' . $errstr);
}
// @codeCoverageIgnoreEnd
@@ -242,16 +270,25 @@ function prepend($stream, $callback, $read_write = STREAM_FILTER_ALL)
function fun($filter, $parameters = null)
{
$fp = \fopen('php://memory', 'w');
$errstr = '';
\set_error_handler(function ($_, $error) use (&$errstr) {
// Match errstr from PHP's warning message.
// stream_filter_append() expects parameter 1 to be resource,...
$errstr = $error;
});
if (\func_num_args() === 1) {
$filter = @\stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE);
$filter = \stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE);
} else {
$filter = @\stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE, $parameters);
$filter = \stream_filter_append($fp, $filter, \STREAM_FILTER_WRITE, $parameters);
}
\restore_error_handler();
if ($filter === false) {
\fclose($fp);
$error = \error_get_last() + array('message' => '');
throw new \RuntimeException('Unable to access built-in filter: ' . $error['message']);
throw new \RuntimeException('Unable to access built-in filter: ' . $errstr);
}
// append filter function which buffers internally
@@ -301,10 +338,26 @@ function fun($filter, $parameters = null)
*/
function remove($filter)
{
if (@\stream_filter_remove($filter) === false) {
$errstr = '';
\set_error_handler(function ($_, $error) use (&$errstr) {
// Match errstr from PHP's warning message.
// stream_filter_remove() expects parameter 1 to be resource,...
$errstr = $error;
});
try {
$ret = \stream_filter_remove($filter);
} catch (\TypeError $e) { // @codeCoverageIgnoreStart
// Throws TypeError on PHP 8.0+
\restore_error_handler();
throw $e;
} // @codeCoverageIgnoreEnd
\restore_error_handler();
if ($ret === false) {
// PHP 8 throws above on type errors, older PHP and memory issues can throw here
$error = \error_get_last();
throw new \RuntimeException('Unable to remove filter: ' . $error['message']);
throw new \RuntimeException('Unable to remove filter: ' . $errstr);
}
}

View File

@@ -1,6 +1,9 @@
<?php
namespace Clue\StreamFilter;
// @codeCoverageIgnoreStart
if (!\function_exists('Clue\\StreamFilter\\append')) {
if (!\function_exists(__NAMESPACE__ . '\\append')) {
require __DIR__ . '/functions.php';
}
// @codeCoverageIgnoreEnd

View File

@@ -6,6 +6,7 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Clue\\StreamFilter\\CallbackFilter' => $vendorDir . '/clue/stream-filter/src/CallbackFilter.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Http\\Client\\Curl\\Client' => $vendorDir . '/php-http/curl-client/src/Client.php',
@@ -110,6 +111,7 @@ return array(
'Nyholm\\Psr7\\Response' => $vendorDir . '/nyholm/psr7/src/Response.php',
'Nyholm\\Psr7\\ServerRequest' => $vendorDir . '/nyholm/psr7/src/ServerRequest.php',
'Nyholm\\Psr7\\Stream' => $vendorDir . '/nyholm/psr7/src/Stream.php',
'Nyholm\\Psr7\\StreamTrait' => $vendorDir . '/nyholm/psr7/src/StreamTrait.php',
'Nyholm\\Psr7\\UploadedFile' => $vendorDir . '/nyholm/psr7/src/UploadedFile.php',
'Nyholm\\Psr7\\Uri' => $vendorDir . '/nyholm/psr7/src/Uri.php',
'Paynow\\Client' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Client.php',
@@ -127,6 +129,8 @@ return array(
'Paynow\\Model\\DataProcessing\\Notice' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/DataProcessing/Notice.php',
'Paynow\\Model\\PaymentMethods\\AuthorizationType' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/AuthorizationType.php',
'Paynow\\Model\\PaymentMethods\\PaymentMethod' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/PaymentMethod.php',
'Paynow\\Model\\PaymentMethods\\SavedInstrument' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/SavedInstrument.php',
'Paynow\\Model\\PaymentMethods\\SavedInstrument\\Status' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/SavedInstrument/Status.php',
'Paynow\\Model\\PaymentMethods\\Status' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/Status.php',
'Paynow\\Model\\PaymentMethods\\Type' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/Type.php',
'Paynow\\Model\\Payment\\Status' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Model/Payment/Status.php',
@@ -150,8 +154,11 @@ return array(
'Paynow\\Tests\\Service\\ShopConfigurationTest' => $vendorDir . '/pay-now/paynow-php-sdk/tests/Service/ShopConfigurationTest.php',
'Paynow\\Tests\\TestCase' => $vendorDir . '/pay-now/paynow-php-sdk/tests/TestCase.php',
'Paynow\\Tests\\TestHttpClient' => $vendorDir . '/pay-now/paynow-php-sdk/tests/TestHttpClient.php',
'Paynow\\Tests\\Util\\SavedInstrumentTest' => $vendorDir . '/pay-now/paynow-php-sdk/tests/Util/SavedInstrumentTest.php',
'Paynow\\Tests\\Util\\SignatureCalculatorTest' => $vendorDir . '/pay-now/paynow-php-sdk/tests/Util/SignatureCalculatorTest.php',
'Paynow\\Util\\ClientExternalIdCalculator' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Util/ClientExternalIdCalculator.php',
'Paynow\\Util\\SignatureCalculator' => $vendorDir . '/pay-now/paynow-php-sdk/src/Paynow/Util/SignatureCalculator.php',
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Psr\\Http\\Client\\ClientExceptionInterface' => $vendorDir . '/psr/http-client/src/ClientExceptionInterface.php',
'Psr\\Http\\Client\\ClientInterface' => $vendorDir . '/psr/http-client/src/ClientInterface.php',
'Psr\\Http\\Client\\NetworkExceptionInterface' => $vendorDir . '/psr/http-client/src/NetworkExceptionInterface.php',
@@ -169,6 +176,7 @@ return array(
'Psr\\Http\\Message\\UploadedFileInterface' => $vendorDir . '/psr/http-message/src/UploadedFileInterface.php',
'Psr\\Http\\Message\\UriFactoryInterface' => $vendorDir . '/psr/http-factory/src/UriFactoryInterface.php',
'Psr\\Http\\Message\\UriInterface' => $vendorDir . '/psr/http-message/src/UriInterface.php',
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => $vendorDir . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php',
'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => $vendorDir . '/symfony/options-resolver/Exception/AccessException.php',
'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/options-resolver/Exception/ExceptionInterface.php',
@@ -181,4 +189,11 @@ return array(
'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',
'Symfony\\Component\\OptionsResolver\\Options' => $vendorDir . '/symfony/options-resolver/Options.php',
'Symfony\\Component\\OptionsResolver\\OptionsResolver' => $vendorDir . '/symfony/options-resolver/OptionsResolver.php',
'Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php',
'Symfony\\Polyfill\\Php80\\PhpToken' => $vendorDir . '/symfony/polyfill-php80/PhpToken.php',
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'cweagans\\Composer\\PatchEvent' => $vendorDir . '/cweagans/composer-patches/src/PatchEvent.php',
'cweagans\\Composer\\PatchEvents' => $vendorDir . '/cweagans/composer-patches/src/PatchEvents.php',
'cweagans\\Composer\\Patches' => $vendorDir . '/cweagans/composer-patches/src/Patches.php',
);

View File

@@ -7,5 +7,6 @@ $baseDir = dirname($vendorDir);
return array(
'9c67151ae59aff4788964ce8eb2a0f43' => $vendorDir . '/clue/stream-filter/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php',
);

View File

@@ -6,6 +6,8 @@ $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'cweagans\\Composer\\' => array($vendorDir . '/cweagans/composer-patches/src'),
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInita3df77b4b522885b715a8fd38a5db444
class ComposerAutoloaderInit93238e2dd576a8d3792c34ad274d581f
{
private static $loader;
@@ -24,16 +24,16 @@ class ComposerAutoloaderInita3df77b4b522885b715a8fd38a5db444
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInita3df77b4b522885b715a8fd38a5db444', 'loadClassLoader'), true, false);
spl_autoload_register(array('ComposerAutoloaderInit93238e2dd576a8d3792c34ad274d581f', 'loadClassLoader'), true, false);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInita3df77b4b522885b715a8fd38a5db444', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit93238e2dd576a8d3792c34ad274d581f', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInita3df77b4b522885b715a8fd38a5db444::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInit93238e2dd576a8d3792c34ad274d581f::getInitializer($loader));
$loader->register(false);
$filesToLoad = \Composer\Autoload\ComposerStaticInita3df77b4b522885b715a8fd38a5db444::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInit93238e2dd576a8d3792c34ad274d581f::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@@ -4,16 +4,22 @@
namespace Composer\Autoload;
class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
class ComposerStaticInit93238e2dd576a8d3792c34ad274d581f
{
public static $files = array (
'9c67151ae59aff4788964ce8eb2a0f43' => __DIR__ . '/..' . '/clue/stream-filter/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'8cff32064859f4559445b89279f3199c' => __DIR__ . '/..' . '/php-http/message/src/filters.php',
);
public static $prefixLengthsPsr4 = array (
'c' =>
array (
'cweagans\\Composer\\' => 18,
),
'S' =>
array (
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Component\\OptionsResolver\\' => 34,
),
'P' =>
@@ -42,6 +48,14 @@ class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
);
public static $prefixDirsPsr4 = array (
'cweagans\\Composer\\' =>
array (
0 => __DIR__ . '/..' . '/cweagans/composer-patches/src',
),
'Symfony\\Polyfill\\Php80\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
),
'Symfony\\Component\\OptionsResolver\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/options-resolver',
@@ -95,6 +109,7 @@ class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
);
public static $classMap = array (
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
'Clue\\StreamFilter\\CallbackFilter' => __DIR__ . '/..' . '/clue/stream-filter/src/CallbackFilter.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Http\\Client\\Curl\\Client' => __DIR__ . '/..' . '/php-http/curl-client/src/Client.php',
@@ -199,6 +214,7 @@ class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
'Nyholm\\Psr7\\Response' => __DIR__ . '/..' . '/nyholm/psr7/src/Response.php',
'Nyholm\\Psr7\\ServerRequest' => __DIR__ . '/..' . '/nyholm/psr7/src/ServerRequest.php',
'Nyholm\\Psr7\\Stream' => __DIR__ . '/..' . '/nyholm/psr7/src/Stream.php',
'Nyholm\\Psr7\\StreamTrait' => __DIR__ . '/..' . '/nyholm/psr7/src/StreamTrait.php',
'Nyholm\\Psr7\\UploadedFile' => __DIR__ . '/..' . '/nyholm/psr7/src/UploadedFile.php',
'Nyholm\\Psr7\\Uri' => __DIR__ . '/..' . '/nyholm/psr7/src/Uri.php',
'Paynow\\Client' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Client.php',
@@ -216,6 +232,8 @@ class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
'Paynow\\Model\\DataProcessing\\Notice' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/DataProcessing/Notice.php',
'Paynow\\Model\\PaymentMethods\\AuthorizationType' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/AuthorizationType.php',
'Paynow\\Model\\PaymentMethods\\PaymentMethod' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/PaymentMethod.php',
'Paynow\\Model\\PaymentMethods\\SavedInstrument' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/SavedInstrument.php',
'Paynow\\Model\\PaymentMethods\\SavedInstrument\\Status' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/SavedInstrument/Status.php',
'Paynow\\Model\\PaymentMethods\\Status' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/Status.php',
'Paynow\\Model\\PaymentMethods\\Type' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/PaymentMethods/Type.php',
'Paynow\\Model\\Payment\\Status' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Model/Payment/Status.php',
@@ -239,8 +257,11 @@ class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
'Paynow\\Tests\\Service\\ShopConfigurationTest' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/tests/Service/ShopConfigurationTest.php',
'Paynow\\Tests\\TestCase' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/tests/TestCase.php',
'Paynow\\Tests\\TestHttpClient' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/tests/TestHttpClient.php',
'Paynow\\Tests\\Util\\SavedInstrumentTest' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/tests/Util/SavedInstrumentTest.php',
'Paynow\\Tests\\Util\\SignatureCalculatorTest' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/tests/Util/SignatureCalculatorTest.php',
'Paynow\\Util\\ClientExternalIdCalculator' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Util/ClientExternalIdCalculator.php',
'Paynow\\Util\\SignatureCalculator' => __DIR__ . '/..' . '/pay-now/paynow-php-sdk/src/Paynow/Util/SignatureCalculator.php',
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
'Psr\\Http\\Client\\ClientExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/ClientExceptionInterface.php',
'Psr\\Http\\Client\\ClientInterface' => __DIR__ . '/..' . '/psr/http-client/src/ClientInterface.php',
'Psr\\Http\\Client\\NetworkExceptionInterface' => __DIR__ . '/..' . '/psr/http-client/src/NetworkExceptionInterface.php',
@@ -258,6 +279,7 @@ class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
'Psr\\Http\\Message\\UploadedFileInterface' => __DIR__ . '/..' . '/psr/http-message/src/UploadedFileInterface.php',
'Psr\\Http\\Message\\UriFactoryInterface' => __DIR__ . '/..' . '/psr/http-factory/src/UriFactoryInterface.php',
'Psr\\Http\\Message\\UriInterface' => __DIR__ . '/..' . '/psr/http-message/src/UriInterface.php',
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
'Symfony\\Component\\OptionsResolver\\Debug\\OptionsResolverIntrospector' => __DIR__ . '/..' . '/symfony/options-resolver/Debug/OptionsResolverIntrospector.php',
'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/AccessException.php',
'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/ExceptionInterface.php',
@@ -270,14 +292,21 @@ class ComposerStaticInita3df77b4b522885b715a8fd38a5db444
'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',
'Symfony\\Component\\OptionsResolver\\Options' => __DIR__ . '/..' . '/symfony/options-resolver/Options.php',
'Symfony\\Component\\OptionsResolver\\OptionsResolver' => __DIR__ . '/..' . '/symfony/options-resolver/OptionsResolver.php',
'Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php',
'Symfony\\Polyfill\\Php80\\PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/PhpToken.php',
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
'cweagans\\Composer\\PatchEvent' => __DIR__ . '/..' . '/cweagans/composer-patches/src/PatchEvent.php',
'cweagans\\Composer\\PatchEvents' => __DIR__ . '/..' . '/cweagans/composer-patches/src/PatchEvents.php',
'cweagans\\Composer\\Patches' => __DIR__ . '/..' . '/cweagans/composer-patches/src/Patches.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInita3df77b4b522885b715a8fd38a5db444::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInita3df77b4b522885b715a8fd38a5db444::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInita3df77b4b522885b715a8fd38a5db444::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit93238e2dd576a8d3792c34ad274d581f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit93238e2dd576a8d3792c34ad274d581f::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit93238e2dd576a8d3792c34ad274d581f::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -2,26 +2,26 @@
"packages": [
{
"name": "clue/stream-filter",
"version": "v1.6.0",
"version_normalized": "1.6.0.0",
"version": "v1.7.0",
"version_normalized": "1.7.0.0",
"source": {
"type": "git",
"url": "https://github.com/clue/stream-filter.git",
"reference": "d6169430c7731d8509da7aecd0af756a5747b78e"
"reference": "049509fef80032cb3f051595029ab75b49a3c2f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/clue/stream-filter/zipball/d6169430c7731d8509da7aecd0af756a5747b78e",
"reference": "d6169430c7731d8509da7aecd0af756a5747b78e",
"url": "https://api.github.com/repos/clue/stream-filter/zipball/049509fef80032cb3f051595029ab75b49a3c2f7",
"reference": "049509fef80032cb3f051595029ab75b49a3c2f7",
"shasum": ""
},
"require": {
"php": ">=5.3"
},
"require-dev": {
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
},
"time": "2022-02-21T13:15:14+00:00",
"time": "2023-12-20T15:40:13+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -43,7 +43,7 @@
}
],
"description": "A simple and modern approach to stream filtering in PHP",
"homepage": "https://github.com/clue/php-stream-filter",
"homepage": "https://github.com/clue/stream-filter",
"keywords": [
"bucket brigade",
"callback",
@@ -55,7 +55,7 @@
],
"support": {
"issues": "https://github.com/clue/stream-filter/issues",
"source": "https://github.com/clue/stream-filter/tree/v1.6.0"
"source": "https://github.com/clue/stream-filter/tree/v1.7.0"
},
"funding": [
{
@@ -70,25 +70,75 @@
"install-path": "../clue/stream-filter"
},
{
"name": "nyholm/psr7",
"version": "1.6.1",
"version_normalized": "1.6.1.0",
"name": "cweagans/composer-patches",
"version": "1.7.3",
"version_normalized": "1.7.3.0",
"source": {
"type": "git",
"url": "https://github.com/Nyholm/psr7.git",
"reference": "e874c8c4286a1e010fb4f385f3a55ac56a05cc93"
"url": "https://github.com/cweagans/composer-patches.git",
"reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/e874c8c4286a1e010fb4f385f3a55ac56a05cc93",
"reference": "e874c8c4286a1e010fb4f385f3a55ac56a05cc93",
"url": "https://api.github.com/repos/cweagans/composer-patches/zipball/e190d4466fe2b103a55467dfa83fc2fecfcaf2db",
"reference": "e190d4466fe2b103a55467dfa83fc2fecfcaf2db",
"shasum": ""
},
"require": {
"php": ">=7.1",
"php-http/message-factory": "^1.0",
"composer-plugin-api": "^1.0 || ^2.0",
"php": ">=5.3.0"
},
"require-dev": {
"composer/composer": "~1.0 || ~2.0",
"phpunit/phpunit": "~4.6"
},
"time": "2022-12-20T22:53:13+00:00",
"type": "composer-plugin",
"extra": {
"class": "cweagans\\Composer\\Patches"
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"cweagans\\Composer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Cameron Eagans",
"email": "me@cweagans.net"
}
],
"description": "Provides a way to patch Composer packages.",
"support": {
"issues": "https://github.com/cweagans/composer-patches/issues",
"source": "https://github.com/cweagans/composer-patches/tree/1.7.3"
},
"install-path": "../cweagans/composer-patches"
},
{
"name": "nyholm/psr7",
"version": "1.8.2",
"version_normalized": "1.8.2.0",
"source": {
"type": "git",
"url": "https://github.com/Nyholm/psr7.git",
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
"shasum": ""
},
"require": {
"php": ">=7.2",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0"
"psr/http-message": "^1.1 || ^2.0"
},
"provide": {
"php-http/message-factory-implementation": "1.0",
@@ -97,15 +147,16 @@
},
"require-dev": {
"http-interop/http-factory-tests": "^0.9",
"php-http/message-factory": "^1.0",
"php-http/psr7-integration-tests": "^1.0",
"phpunit/phpunit": "^7.5 || 8.5 || 9.4",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"symfony/error-handler": "^4.4"
},
"time": "2023-04-17T16:03:48+00:00",
"time": "2024-09-09T07:06:30+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6-dev"
"dev-master": "1.8-dev"
}
},
"installation-source": "dist",
@@ -136,7 +187,7 @@
],
"support": {
"issues": "https://github.com/Nyholm/psr7/issues",
"source": "https://github.com/Nyholm/psr7/tree/1.6.1"
"source": "https://github.com/Nyholm/psr7/tree/1.8.2"
},
"funding": [
{
@@ -152,21 +203,21 @@
},
{
"name": "pay-now/paynow-php-sdk",
"version": "2.2.2",
"version_normalized": "2.2.2.0",
"version": "2.4.4",
"version_normalized": "2.4.4.0",
"source": {
"type": "git",
"url": "https://github.com/pay-now/paynow-php-sdk.git",
"reference": "33432ca177e937f3f5c6abb9f36c7f979baec67d"
"reference": "0b300739620fc6c838d9af14be50c561c27f50c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pay-now/paynow-php-sdk/zipball/33432ca177e937f3f5c6abb9f36c7f979baec67d",
"reference": "33432ca177e937f3f5c6abb9f36c7f979baec67d",
"url": "https://api.github.com/repos/pay-now/paynow-php-sdk/zipball/0b300739620fc6c838d9af14be50c561c27f50c9",
"reference": "0b300739620fc6c838d9af14be50c561c27f50c9",
"shasum": ""
},
"require": {
"php": ">=7.1",
"php": ">=7.2",
"php-http/client-implementation": "^1.0 || ^2.0",
"php-http/discovery": "^1.12",
"php-http/httplug": "^2.2",
@@ -181,14 +232,14 @@
"php-http/guzzle6-adapter": "^2.0",
"php-http/mock-client": "^1.3",
"phpcompatibility/php-compatibility": "^9.3",
"phpunit/phpunit": "^7.0",
"phpunit/phpunit": "^8.5.36",
"squizlabs/php_codesniffer": "^3.4"
},
"suggest": {
"nyholm/psr7": "A super lightweight PSR-7 implementation",
"php-http/curl-client": "PSR-18 and HTTPlug Async client with cURL"
},
"time": "2023-11-03T14:26:59+00:00",
"time": "2025-05-14T11:25:10+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -217,23 +268,23 @@
],
"support": {
"issues": "https://github.com/pay-now/paynow-php-sdk/issues",
"source": "https://github.com/pay-now/paynow-php-sdk/tree/v2.2.2"
"source": "https://github.com/pay-now/paynow-php-sdk/tree/v2.4.4"
},
"install-path": "../pay-now/paynow-php-sdk"
},
{
"name": "php-http/curl-client",
"version": "2.3.0",
"version_normalized": "2.3.0.0",
"version": "2.3.1",
"version_normalized": "2.3.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/curl-client.git",
"reference": "f7352c0796549949900d28fe991e19c90572386a"
"reference": "085570be588f7cbdc4601e78886eea5b7051ad71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/curl-client/zipball/f7352c0796549949900d28fe991e19c90572386a",
"reference": "f7352c0796549949900d28fe991e19c90572386a",
"url": "https://api.github.com/repos/php-http/curl-client/zipball/085570be588f7cbdc4601e78886eea5b7051ad71",
"reference": "085570be588f7cbdc4601e78886eea5b7051ad71",
"shasum": ""
},
"require": {
@@ -244,7 +295,7 @@
"php-http/message": "^1.2",
"psr/http-client": "^1.0",
"psr/http-factory-implementation": "^1.0",
"symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0"
"symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"provide": {
"php-http/async-client-implementation": "1.0",
@@ -255,9 +306,10 @@
"guzzlehttp/psr7": "^1.0",
"laminas/laminas-diactoros": "^2.0",
"php-http/client-integration-tests": "^3.0",
"php-http/message-factory": "^1.1",
"phpunit/phpunit": "^7.5 || ^9.4"
},
"time": "2023-04-28T14:56:41+00:00",
"time": "2023-11-03T15:32:00+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -284,23 +336,23 @@
],
"support": {
"issues": "https://github.com/php-http/curl-client/issues",
"source": "https://github.com/php-http/curl-client/tree/2.3.0"
"source": "https://github.com/php-http/curl-client/tree/2.3.1"
},
"install-path": "../php-http/curl-client"
},
{
"name": "php-http/discovery",
"version": "1.19.1",
"version_normalized": "1.19.1.0",
"version": "1.20.0",
"version_normalized": "1.20.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/discovery.git",
"reference": "57f3de01d32085fea20865f9b16fb0e69347c39e"
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/discovery/zipball/57f3de01d32085fea20865f9b16fb0e69347c39e",
"reference": "57f3de01d32085fea20865f9b16fb0e69347c39e",
"url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d",
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d",
"shasum": ""
},
"require": {
@@ -324,9 +376,10 @@
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message-factory": "^1.0",
"phpspec/phpspec": "^5.1 || ^6.1 || ^7.3",
"symfony/phpunit-bridge": "^6.2"
"sebastian/comparator": "^3.0.5 || ^4.0.8",
"symfony/phpunit-bridge": "^6.4.4 || ^7.0.1"
},
"time": "2023-07-11T07:02:26+00:00",
"time": "2024-10-02T11:20:13+00:00",
"type": "composer-plugin",
"extra": {
"class": "Http\\Discovery\\Composer\\Plugin",
@@ -365,23 +418,23 @@
],
"support": {
"issues": "https://github.com/php-http/discovery/issues",
"source": "https://github.com/php-http/discovery/tree/1.19.1"
"source": "https://github.com/php-http/discovery/tree/1.20.0"
},
"install-path": "../php-http/discovery"
},
{
"name": "php-http/httplug",
"version": "2.4.0",
"version_normalized": "2.4.0.0",
"version": "2.4.1",
"version_normalized": "2.4.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/httplug.git",
"reference": "625ad742c360c8ac580fcc647a1541d29e257f67"
"reference": "5cad731844891a4c282f3f3e1b582c46839d22f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67",
"reference": "625ad742c360c8ac580fcc647a1541d29e257f67",
"url": "https://api.github.com/repos/php-http/httplug/zipball/5cad731844891a4c282f3f3e1b582c46839d22f4",
"reference": "5cad731844891a4c282f3f3e1b582c46839d22f4",
"shasum": ""
},
"require": {
@@ -394,7 +447,7 @@
"friends-of-phpspec/phpspec-code-coverage": "^4.1 || ^5.0 || ^6.0",
"phpspec/phpspec": "^5.1 || ^6.0 || ^7.0"
},
"time": "2023-04-14T15:10:03+00:00",
"time": "2024-09-23T11:39:58+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -425,30 +478,29 @@
],
"support": {
"issues": "https://github.com/php-http/httplug/issues",
"source": "https://github.com/php-http/httplug/tree/2.4.0"
"source": "https://github.com/php-http/httplug/tree/2.4.1"
},
"install-path": "../php-http/httplug"
},
{
"name": "php-http/message",
"version": "1.14.0",
"version_normalized": "1.14.0.0",
"version": "1.16.2",
"version_normalized": "1.16.2.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/message.git",
"reference": "2ccee04a28c3d98eb3f2b85ce1e2fcff70c0e63b"
"reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/message/zipball/2ccee04a28c3d98eb3f2b85ce1e2fcff70c0e63b",
"reference": "2ccee04a28c3d98eb3f2b85ce1e2fcff70c0e63b",
"url": "https://api.github.com/repos/php-http/message/zipball/06dd5e8562f84e641bf929bfe699ee0f5ce8080a",
"reference": "06dd5e8562f84e641bf929bfe699ee0f5ce8080a",
"shasum": ""
},
"require": {
"clue/stream-filter": "^1.5",
"php": "^7.1 || ^8.0",
"php-http/message-factory": "^1.0.2",
"psr/http-message": "^1.0 || ^2.0"
"php": "^7.2 || ^8.0",
"psr/http-message": "^1.1 || ^2.0"
},
"provide": {
"php-http/message-factory-implementation": "1.0"
@@ -456,8 +508,9 @@
"require-dev": {
"ergebnis/composer-normalize": "^2.6",
"ext-zlib": "*",
"guzzlehttp/psr7": "^1.0",
"laminas/laminas-diactoros": "^2.0",
"guzzlehttp/psr7": "^1.0 || ^2.0",
"laminas/laminas-diactoros": "^2.0 || ^3.0",
"php-http/message-factory": "^1.0.2",
"phpspec/phpspec": "^5.1 || ^6.3 || ^7.1",
"slim/slim": "^3.0"
},
@@ -467,7 +520,7 @@
"laminas/laminas-diactoros": "Used with Diactoros Factories",
"slim/slim": "Used with Slim Framework PSR-7 implementation"
},
"time": "2023-04-14T14:26:18+00:00",
"time": "2024-10-02T11:34:13+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -497,7 +550,7 @@
],
"support": {
"issues": "https://github.com/php-http/message/issues",
"source": "https://github.com/php-http/message/tree/1.14.0"
"source": "https://github.com/php-http/message/tree/1.16.2"
},
"install-path": "../php-http/message"
},
@@ -561,17 +614,17 @@
},
{
"name": "php-http/promise",
"version": "1.2.0",
"version_normalized": "1.2.0.0",
"version": "1.3.1",
"version_normalized": "1.3.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/promise.git",
"reference": "ef4905bfb492ff389eb7f12e26925a0f20073050"
"reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/promise/zipball/ef4905bfb492ff389eb7f12e26925a0f20073050",
"reference": "ef4905bfb492ff389eb7f12e26925a0f20073050",
"url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83",
"reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83",
"shasum": ""
},
"require": {
@@ -581,7 +634,7 @@
"friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3",
"phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4"
},
"time": "2023-10-24T09:20:26+00:00",
"time": "2024-03-15T13:55:21+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -610,7 +663,7 @@
],
"support": {
"issues": "https://github.com/php-http/promise/issues",
"source": "https://github.com/php-http/promise/tree/1.2.0"
"source": "https://github.com/php-http/promise/tree/1.3.1"
},
"install-path": "../php-http/promise"
},
@@ -671,24 +724,24 @@
},
{
"name": "psr/http-factory",
"version": "1.0.2",
"version_normalized": "1.0.2.0",
"version": "1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "e616d01114759c4c489f93b099585439f795fe35"
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
"reference": "e616d01114759c4c489f93b099585439f795fe35",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"time": "2023-04-10T20:10:41+00:00",
"time": "2024-04-15T12:06:14+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -711,7 +764,7 @@
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
@@ -723,33 +776,33 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
"source": "https://github.com/php-fig/http-factory"
},
"install-path": "../psr/http-factory"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"version": "2.0",
"version_normalized": "2.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": "^7.2 || ^8.0"
},
"time": "2016-08-06T14:39:51+00:00",
"time": "2023-04-04T09:54:51+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "2.0.x-dev"
}
},
"installation-source": "dist",
@@ -765,7 +818,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
@@ -779,29 +832,30 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
"source": "https://github.com/php-fig/http-message/tree/2.0"
},
"install-path": "../psr/http-message"
},
{
"name": "symfony/options-resolver",
"version": "v3.4.47",
"version_normalized": "3.4.47.0",
"version": "v4.4.44",
"version_normalized": "4.4.44.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "c7efc97a47b2ebaabc19d5b6c6b50f5c37c92744"
"reference": "583f56160f716dd435f1cd721fd14b548f4bb510"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/c7efc97a47b2ebaabc19d5b6c6b50f5c37c92744",
"reference": "c7efc97a47b2ebaabc19d5b6c6b50f5c37c92744",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/583f56160f716dd435f1cd721fd14b548f4bb510",
"reference": "583f56160f716dd435f1cd721fd14b548f4bb510",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8"
"php": ">=7.1.3",
"symfony/polyfill-php80": "^1.16"
},
"time": "2020-10-24T10:57:07+00:00",
"time": "2022-07-20T09:59:04+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -826,7 +880,7 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony OptionsResolver Component",
"description": "Provides an improved replacement for the array_replace PHP function",
"homepage": "https://symfony.com",
"keywords": [
"config",
@@ -834,7 +888,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v3.4.47"
"source": "https://github.com/symfony/options-resolver/tree/v4.4.44"
},
"funding": [
{
@@ -851,6 +905,89 @@
}
],
"install-path": "../symfony/options-resolver"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.32.0",
"version_normalized": "1.32.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"time": "2025-01-02T08:10:11+00:00",
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/polyfill-php80"
}
],
"dev": false,

View File

@@ -3,7 +3,7 @@
'name' => 'pay-now/paynow-prestashop',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'ae162451919441e986928aafb1996fab693c0159',
'reference' => 'd907e1ebe7f0e3da69122c3391fd802221b9226d',
'type' => 'prestashop-module',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -11,27 +11,36 @@
),
'versions' => array(
'clue/stream-filter' => array(
'pretty_version' => 'v1.6.0',
'version' => '1.6.0.0',
'reference' => 'd6169430c7731d8509da7aecd0af756a5747b78e',
'pretty_version' => 'v1.7.0',
'version' => '1.7.0.0',
'reference' => '049509fef80032cb3f051595029ab75b49a3c2f7',
'type' => 'library',
'install_path' => __DIR__ . '/../clue/stream-filter',
'aliases' => array(),
'dev_requirement' => false,
),
'cweagans/composer-patches' => array(
'pretty_version' => '1.7.3',
'version' => '1.7.3.0',
'reference' => 'e190d4466fe2b103a55467dfa83fc2fecfcaf2db',
'type' => 'composer-plugin',
'install_path' => __DIR__ . '/../cweagans/composer-patches',
'aliases' => array(),
'dev_requirement' => false,
),
'nyholm/psr7' => array(
'pretty_version' => '1.6.1',
'version' => '1.6.1.0',
'reference' => 'e874c8c4286a1e010fb4f385f3a55ac56a05cc93',
'pretty_version' => '1.8.2',
'version' => '1.8.2.0',
'reference' => 'a71f2b11690f4b24d099d6b16690a90ae14fc6f3',
'type' => 'library',
'install_path' => __DIR__ . '/../nyholm/psr7',
'aliases' => array(),
'dev_requirement' => false,
),
'pay-now/paynow-php-sdk' => array(
'pretty_version' => '2.2.2',
'version' => '2.2.2.0',
'reference' => '33432ca177e937f3f5c6abb9f36c7f979baec67d',
'pretty_version' => '2.4.4',
'version' => '2.4.4.0',
'reference' => '0b300739620fc6c838d9af14be50c561c27f50c9',
'type' => 'library',
'install_path' => __DIR__ . '/../pay-now/paynow-php-sdk',
'aliases' => array(),
@@ -40,7 +49,7 @@
'pay-now/paynow-prestashop' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => 'ae162451919441e986928aafb1996fab693c0159',
'reference' => 'd907e1ebe7f0e3da69122c3391fd802221b9226d',
'type' => 'prestashop-module',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -61,36 +70,36 @@
),
),
'php-http/curl-client' => array(
'pretty_version' => '2.3.0',
'version' => '2.3.0.0',
'reference' => 'f7352c0796549949900d28fe991e19c90572386a',
'pretty_version' => '2.3.1',
'version' => '2.3.1.0',
'reference' => '085570be588f7cbdc4601e78886eea5b7051ad71',
'type' => 'library',
'install_path' => __DIR__ . '/../php-http/curl-client',
'aliases' => array(),
'dev_requirement' => false,
),
'php-http/discovery' => array(
'pretty_version' => '1.19.1',
'version' => '1.19.1.0',
'reference' => '57f3de01d32085fea20865f9b16fb0e69347c39e',
'pretty_version' => '1.20.0',
'version' => '1.20.0.0',
'reference' => '82fe4c73ef3363caed49ff8dd1539ba06044910d',
'type' => 'composer-plugin',
'install_path' => __DIR__ . '/../php-http/discovery',
'aliases' => array(),
'dev_requirement' => false,
),
'php-http/httplug' => array(
'pretty_version' => '2.4.0',
'version' => '2.4.0.0',
'reference' => '625ad742c360c8ac580fcc647a1541d29e257f67',
'pretty_version' => '2.4.1',
'version' => '2.4.1.0',
'reference' => '5cad731844891a4c282f3f3e1b582c46839d22f4',
'type' => 'library',
'install_path' => __DIR__ . '/../php-http/httplug',
'aliases' => array(),
'dev_requirement' => false,
),
'php-http/message' => array(
'pretty_version' => '1.14.0',
'version' => '1.14.0.0',
'reference' => '2ccee04a28c3d98eb3f2b85ce1e2fcff70c0e63b',
'pretty_version' => '1.16.2',
'version' => '1.16.2.0',
'reference' => '06dd5e8562f84e641bf929bfe699ee0f5ce8080a',
'type' => 'library',
'install_path' => __DIR__ . '/../php-http/message',
'aliases' => array(),
@@ -112,9 +121,9 @@
),
),
'php-http/promise' => array(
'pretty_version' => '1.2.0',
'version' => '1.2.0.0',
'reference' => 'ef4905bfb492ff389eb7f12e26925a0f20073050',
'pretty_version' => '1.3.1',
'version' => '1.3.1.0',
'reference' => 'fc85b1fba37c169a69a07ef0d5a8075770cc1f83',
'type' => 'library',
'install_path' => __DIR__ . '/../php-http/promise',
'aliases' => array(),
@@ -137,9 +146,9 @@
),
),
'psr/http-factory' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'reference' => 'e616d01114759c4c489f93b099585439f795fe35',
'pretty_version' => '1.1.0',
'version' => '1.1.0.0',
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(),
@@ -153,9 +162,9 @@
),
),
'psr/http-message' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'pretty_version' => '2.0',
'version' => '2.0.0.0',
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
@@ -169,13 +178,22 @@
),
),
'symfony/options-resolver' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'c7efc97a47b2ebaabc19d5b6c6b50f5c37c92744',
'pretty_version' => 'v4.4.44',
'version' => '4.4.44.0',
'reference' => '583f56160f716dd435f1cd721fd14b548f4bb510',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/options-resolver',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/polyfill-php80' => array(
'pretty_version' => 'v1.32.0',
'version' => '1.32.0.0',
'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

View File

@@ -4,8 +4,8 @@
$issues = array();
if (!(PHP_VERSION_ID >= 70100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.';
if (!(PHP_VERSION_ID >= 70200)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {

View File

@@ -0,0 +1,30 @@
{
"name": "cweagans/composer-patches",
"description": "Provides a way to patch Composer packages.",
"minimum-stability": "dev",
"license": "BSD-3-Clause",
"type": "composer-plugin",
"extra": {
"class": "cweagans\\Composer\\Patches"
},
"authors": [
{
"name": "Cameron Eagans",
"email": "me@cweagans.net"
}
],
"require": {
"php": ">=5.3.0",
"composer-plugin-api": "^1.0 || ^2.0"
},
"require-dev": {
"composer/composer": "~1.0 || ~2.0",
"phpunit/phpunit": "~4.6"
},
"autoload": {
"psr-4": {"cweagans\\Composer\\": "src"}
},
"autoload-dev": {
"psr-4": {"cweagans\\Composer\\Tests\\": "tests"}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,18 @@
<!--?xml version="1.0" encoding="UTF-8"?-->
<phpunit colors="true" bootstrap="vendor/autoload.php">
<testsuites>
<testsuite name="composer-patches">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<!-- Filter for coverage reports. -->
<filter>
<whitelist>
<directory>src/</directory>
</whitelist>
<blacklist>
<directory>vendor/</directory>
</blacklist>
</filter>
</phpunit>

View File

@@ -0,0 +1,70 @@
<?php
/**
* @file
* Dispatch events when patches are applied.
*/
namespace cweagans\Composer;
use Composer\EventDispatcher\Event;
use Composer\Package\PackageInterface;
class PatchEvent extends Event {
/**
* @var PackageInterface $package
*/
protected $package;
/**
* @var string $url
*/
protected $url;
/**
* @var string $description
*/
protected $description;
/**
* Constructs a PatchEvent object.
*
* @param string $eventName
* @param PackageInterface $package
* @param string $url
* @param string $description
*/
public function __construct($eventName, PackageInterface $package, $url, $description) {
parent::__construct($eventName);
$this->package = $package;
$this->url = $url;
$this->description = $description;
}
/**
* Returns the package that is patched.
*
* @return PackageInterface
*/
public function getPackage() {
return $this->package;
}
/**
* Returns the url of the patch.
*
* @return string
*/
public function getUrl() {
return $this->url;
}
/**
* Returns the description of the patch.
*
* @return string
*/
public function getDescription() {
return $this->description;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* @file
* Dispatch events when patches are applied.
*/
namespace cweagans\Composer;
class PatchEvents {
/**
* The PRE_PATCH_APPLY event occurs before a patch is applied.
*
* The event listener method receives a cweagans\Composer\PatchEvent instance.
*
* @var string
*/
const PRE_PATCH_APPLY = 'pre-patch-apply';
/**
* The POST_PATCH_APPLY event occurs after a patch is applied.
*
* The event listener method receives a cweagans\Composer\PatchEvent instance.
*
* @var string
*/
const POST_PATCH_APPLY = 'post-patch-apply';
}

View File

@@ -0,0 +1,599 @@
<?php
/**
* @file
* Provides a way to patch Composer packages after installation.
*/
namespace cweagans\Composer;
use Composer\Composer;
use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\DependencyResolver\Operation\UninstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Package\AliasPackage;
use Composer\Package\PackageInterface;
use Composer\Plugin\PluginInterface;
use Composer\Installer\PackageEvents;
use Composer\Script\Event;
use Composer\Script\ScriptEvents;
use Composer\Installer\PackageEvent;
use Composer\Util\ProcessExecutor;
use Composer\Util\RemoteFilesystem;
use Symfony\Component\Process\Process;
class Patches implements PluginInterface, EventSubscriberInterface {
/**
* @var Composer $composer
*/
protected $composer;
/**
* @var IOInterface $io
*/
protected $io;
/**
* @var EventDispatcher $eventDispatcher
*/
protected $eventDispatcher;
/**
* @var ProcessExecutor $executor
*/
protected $executor;
/**
* @var array $patches
*/
protected $patches;
/**
* @var array $installedPatches
*/
protected $installedPatches;
/**
* Apply plugin modifications to composer
*
* @param Composer $composer
* @param IOInterface $io
*/
public function activate(Composer $composer, IOInterface $io) {
$this->composer = $composer;
$this->io = $io;
$this->eventDispatcher = $composer->getEventDispatcher();
$this->executor = new ProcessExecutor($this->io);
$this->patches = array();
$this->installedPatches = array();
}
/**
* Returns an array of event names this subscriber wants to listen to.
*/
public static function getSubscribedEvents() {
return array(
ScriptEvents::PRE_INSTALL_CMD => array('checkPatches'),
ScriptEvents::PRE_UPDATE_CMD => array('checkPatches'),
PackageEvents::PRE_PACKAGE_INSTALL => array('gatherPatches'),
PackageEvents::PRE_PACKAGE_UPDATE => array('gatherPatches'),
// The following is a higher weight for compatibility with
// https://github.com/AydinHassan/magento-core-composer-installer and more generally for compatibility with
// every Composer plugin which deploys downloaded packages to other locations.
// In such cases you want that those plugins deploy patched files so they have to run after
// the "composer-patches" plugin.
// @see: https://github.com/cweagans/composer-patches/pull/153
PackageEvents::POST_PACKAGE_INSTALL => array('postInstall', 10),
PackageEvents::POST_PACKAGE_UPDATE => array('postInstall', 10),
);
}
/**
* Before running composer install,
* @param Event $event
*/
public function checkPatches(Event $event) {
if (!$this->isPatchingEnabled()) {
return;
}
try {
$repositoryManager = $this->composer->getRepositoryManager();
$localRepository = $repositoryManager->getLocalRepository();
$installationManager = $this->composer->getInstallationManager();
$packages = $localRepository->getPackages();
$extra = $this->composer->getPackage()->getExtra();
$patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array();
$tmp_patches = $this->grabPatches();
foreach ($packages as $package) {
$extra = $package->getExtra();
if (isset($extra['patches'])) {
if (isset($patches_ignore[$package->getName()])) {
foreach ($patches_ignore[$package->getName()] as $package_name => $patches) {
if (isset($extra['patches'][$package_name])) {
$extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches);
}
}
}
$this->installedPatches[$package->getName()] = $extra['patches'];
}
$patches = isset($extra['patches']) ? $extra['patches'] : array();
$tmp_patches = $this->arrayMergeRecursiveDistinct($tmp_patches, $patches);
}
if ($tmp_patches == FALSE) {
$this->io->write('<info>No patches supplied.</info>');
return;
}
// Remove packages for which the patch set has changed.
$promises = array();
foreach ($packages as $package) {
if (!($package instanceof AliasPackage)) {
$package_name = $package->getName();
$extra = $package->getExtra();
$has_patches = isset($tmp_patches[$package_name]);
$has_applied_patches = isset($extra['patches_applied']) && count($extra['patches_applied']) > 0;
if (($has_patches && !$has_applied_patches)
|| (!$has_patches && $has_applied_patches)
|| ($has_patches && $has_applied_patches && $tmp_patches[$package_name] !== $extra['patches_applied'])) {
$uninstallOperation = new UninstallOperation($package, 'Removing package so it can be re-installed and re-patched.');
$this->io->write('<info>Removing package ' . $package_name . ' so that it can be re-installed and re-patched.</info>');
$promises[] = $installationManager->uninstall($localRepository, $uninstallOperation);
}
}
}
$promises = array_filter($promises);
if ($promises) {
$this->composer->getLoop()->wait($promises);
}
}
// If the Locker isn't available, then we don't need to do this.
// It's the first time packages have been installed.
catch (\LogicException $e) {
return;
}
}
/**
* Gather patches from dependencies and store them for later use.
*
* @param PackageEvent $event
*/
public function gatherPatches(PackageEvent $event) {
// If we've already done this, then don't do it again.
if (isset($this->patches['_patchesGathered'])) {
$this->io->write('<info>Patches already gathered. Skipping</info>', TRUE, IOInterface::VERBOSE);
return;
}
// If patching has been disabled, bail out here.
elseif (!$this->isPatchingEnabled()) {
$this->io->write('<info>Patching is disabled. Skipping.</info>', TRUE, IOInterface::VERBOSE);
return;
}
$this->patches = $this->grabPatches();
if (empty($this->patches)) {
$this->io->write('<info>No patches supplied.</info>');
}
$extra = $this->composer->getPackage()->getExtra();
$patches_ignore = isset($extra['patches-ignore']) ? $extra['patches-ignore'] : array();
// Now add all the patches from dependencies that will be installed.
$operations = $event->getOperations();
$this->io->write('<info>Gathering patches for dependencies. This might take a minute.</info>');
foreach ($operations as $operation) {
if ($operation instanceof InstallOperation || $operation instanceof UpdateOperation) {
$package = $this->getPackageFromOperation($operation);
$extra = $package->getExtra();
if (isset($extra['patches'])) {
if (isset($patches_ignore[$package->getName()])) {
foreach ($patches_ignore[$package->getName()] as $package_name => $patches) {
if (isset($extra['patches'][$package_name])) {
$extra['patches'][$package_name] = array_diff($extra['patches'][$package_name], $patches);
}
}
}
$this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $extra['patches']);
}
// Unset installed patches for this package
if(isset($this->installedPatches[$package->getName()])) {
unset($this->installedPatches[$package->getName()]);
}
}
}
// Merge installed patches from dependencies that did not receive an update.
foreach ($this->installedPatches as $patches) {
$this->patches = $this->arrayMergeRecursiveDistinct($this->patches, $patches);
}
// If we're in verbose mode, list the projects we're going to patch.
if ($this->io->isVerbose()) {
foreach ($this->patches as $package => $patches) {
$number = count($patches);
$this->io->write('<info>Found ' . $number . ' patches for ' . $package . '.</info>');
}
}
// Make sure we don't gather patches again. Extra keys in $this->patches
// won't hurt anything, so we'll just stash it there.
$this->patches['_patchesGathered'] = TRUE;
}
/**
* Get the patches from root composer or external file
* @return Patches
* @throws \Exception
*/
public function grabPatches() {
// First, try to get the patches from the root composer.json.
$extra = $this->composer->getPackage()->getExtra();
if (isset($extra['patches'])) {
$this->io->write('<info>Gathering patches for root package.</info>');
$patches = $extra['patches'];
return $patches;
}
// If it's not specified there, look for a patches-file definition.
elseif (isset($extra['patches-file'])) {
$this->io->write('<info>Gathering patches from patch file.</info>');
$patches = file_get_contents($extra['patches-file']);
$patches = json_decode($patches, TRUE);
$error = json_last_error();
if ($error != 0) {
switch ($error) {
case JSON_ERROR_DEPTH:
$msg = ' - Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = ' - Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = ' - Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$msg = ' - Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$msg = ' - Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$msg = ' - Unknown error';
break;
}
throw new \Exception('There was an error in the supplied patches file:' . $msg);
}
if (isset($patches['patches'])) {
$patches = $patches['patches'];
return $patches;
}
elseif(!$patches) {
throw new \Exception('There was an error in the supplied patch file');
}
}
else {
return array();
}
}
/**
* @param PackageEvent $event
* @throws \Exception
*/
public function postInstall(PackageEvent $event) {
// Check if we should exit in failure.
$extra = $this->composer->getPackage()->getExtra();
$exitOnFailure = getenv('COMPOSER_EXIT_ON_PATCH_FAILURE') || !empty($extra['composer-exit-on-patch-failure']);
$skipReporting = getenv('COMPOSER_PATCHES_SKIP_REPORTING') || !empty($extra['composer-patches-skip-reporting']);
// Get the package object for the current operation.
$operation = $event->getOperation();
/** @var PackageInterface $package */
$package = $this->getPackageFromOperation($operation);
$package_name = $package->getName();
if (!isset($this->patches[$package_name])) {
if ($this->io->isVerbose()) {
$this->io->write('<info>No patches found for ' . $package_name . '.</info>');
}
return;
}
$this->io->write(' - Applying patches for <info>' . $package_name . '</info>');
// Get the install path from the package object.
$manager = $event->getComposer()->getInstallationManager();
$install_path = $manager->getInstaller($package->getType())->getInstallPath($package);
// Set up a downloader.
$downloader = new RemoteFilesystem($this->io, $this->composer->getConfig());
// Track applied patches in the package info in installed.json
$localRepository = $this->composer->getRepositoryManager()->getLocalRepository();
$localPackage = $localRepository->findPackage($package_name, $package->getVersion());
$extra = $localPackage->getExtra();
$extra['patches_applied'] = array();
foreach ($this->patches[$package_name] as $description => $url) {
$this->io->write(' <info>' . $url . '</info> (<comment>' . $description. '</comment>)');
try {
$this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::PRE_PATCH_APPLY, $package, $url, $description));
$this->getAndApplyPatch($downloader, $install_path, $url, $package);
$this->eventDispatcher->dispatch(NULL, new PatchEvent(PatchEvents::POST_PATCH_APPLY, $package, $url, $description));
$extra['patches_applied'][$description] = $url;
}
catch (\Exception $e) {
$this->io->write(' <error>Could not apply patch! Skipping. The error was: ' . $e->getMessage() . '</error>');
if ($exitOnFailure) {
throw new \Exception("Cannot apply patch $description ($url)!");
}
}
}
$localPackage->setExtra($extra);
$this->io->write('');
if (true !== $skipReporting) {
$this->writePatchReport($this->patches[$package_name], $install_path);
}
}
/**
* Get a Package object from an OperationInterface object.
*
* @param OperationInterface $operation
* @return PackageInterface
* @throws \Exception
*/
protected function getPackageFromOperation(OperationInterface $operation) {
if ($operation instanceof InstallOperation) {
$package = $operation->getPackage();
}
elseif ($operation instanceof UpdateOperation) {
$package = $operation->getTargetPackage();
}
else {
throw new \Exception('Unknown operation: ' . get_class($operation));
}
return $package;
}
/**
* Apply a patch on code in the specified directory.
*
* @param RemoteFilesystem $downloader
* @param $install_path
* @param $patch_url
* @param PackageInterface $package
* @throws \Exception
*/
protected function getAndApplyPatch(RemoteFilesystem $downloader, $install_path, $patch_url, PackageInterface $package) {
// Local patch file.
if (file_exists($patch_url)) {
$filename = realpath($patch_url);
}
else {
// Generate random (but not cryptographically so) filename.
$filename = uniqid(sys_get_temp_dir().'/') . ".patch";
// Download file from remote filesystem to this location.
$hostname = parse_url($patch_url, PHP_URL_HOST);
try {
$downloader->copy($hostname, $patch_url, $filename, false);
} catch (\Exception $e) {
// In case of an exception, retry once as the download might
// have failed due to intermittent network issues.
$downloader->copy($hostname, $patch_url, $filename, false);
}
}
// The order here is intentional. p1 is most likely to apply with git apply.
// p0 is next likely. p2 is extremely unlikely, but for some special cases,
// it might be useful. p4 is useful for Magento 2 patches
$patch_levels = array('-p1', '-p0', '-p2', '-p4');
// Check for specified patch level for this package.
$extra = $this->composer->getPackage()->getExtra();
if (!empty($extra['patchLevel'][$package->getName()])){
$patch_levels = array($extra['patchLevel'][$package->getName()]);
}
// Attempt to apply with git apply.
$patched = $this->applyPatchWithGit($install_path, $patch_levels, $filename);
// In some rare cases, git will fail to apply a patch, fallback to using
// the 'patch' command.
if (!$patched) {
foreach ($patch_levels as $patch_level) {
// --no-backup-if-mismatch here is a hack that fixes some
// differences between how patch works on windows and unix.
if ($patched = $this->executeCommand("patch %s --no-backup-if-mismatch -d %s < %s", $patch_level, $install_path, $filename)) {
break;
}
}
}
// Clean up the temporary patch file.
if (isset($hostname)) {
unlink($filename);
}
// If the patch *still* isn't applied, then give up and throw an Exception.
// Otherwise, let the user know it worked.
if (!$patched) {
throw new \Exception("Cannot apply patch $patch_url");
}
}
/**
* Checks if the root package enables patching.
*
* @return bool
* Whether patching is enabled. Defaults to TRUE.
*/
protected function isPatchingEnabled() {
$extra = $this->composer->getPackage()->getExtra();
if (empty($extra['patches']) && empty($extra['patches-ignore']) && !isset($extra['patches-file'])) {
// The root package has no patches of its own, so only allow patching if
// it has specifically opted in.
return isset($extra['enable-patching']) ? $extra['enable-patching'] : FALSE;
}
else {
return TRUE;
}
}
/**
* Writes a patch report to the target directory.
*
* @param array $patches
* @param string $directory
*/
protected function writePatchReport($patches, $directory) {
$output = "This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)\n";
$output .= "Patches applied to this directory:\n\n";
foreach ($patches as $description => $url) {
$output .= $description . "\n";
$output .= 'Source: ' . $url . "\n\n\n";
}
file_put_contents($directory . "/PATCHES.txt", $output);
}
/**
* Executes a shell command with escaping.
*
* @param string $cmd
* @return bool
*/
protected function executeCommand($cmd) {
// Shell-escape all arguments except the command.
$args = func_get_args();
foreach ($args as $index => $arg) {
if ($index !== 0) {
$args[$index] = escapeshellarg($arg);
}
}
// And replace the arguments.
$command = call_user_func_array('sprintf', $args);
$output = '';
if ($this->io->isVerbose()) {
$this->io->write('<comment>' . $command . '</comment>');
$io = $this->io;
$output = function ($type, $data) use ($io) {
if ($type == Process::ERR) {
$io->write('<error>' . $data . '</error>');
}
else {
$io->write('<comment>' . $data . '</comment>');
}
};
}
return ($this->executor->execute($command, $output) == 0);
}
/**
* Recursively merge arrays without changing data types of values.
*
* Does not change the data types of the values in the arrays. Matching keys'
* values in the second array overwrite those in the first array, as is the
* case with array_merge.
*
* @param array $array1
* The first array.
* @param array $array2
* The second array.
* @return array
* The merged array.
*
* @see http://php.net/manual/en/function.array-merge-recursive.php#92195
*/
protected function arrayMergeRecursiveDistinct(array $array1, array $array2) {
$merged = $array1;
foreach ($array2 as $key => &$value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
}
else {
$merged[$key] = $value;
}
}
return $merged;
}
/**
* Attempts to apply a patch with git apply.
*
* @param $install_path
* @param $patch_levels
* @param $filename
*
* @return bool
* TRUE if patch was applied, FALSE otherwise.
*/
protected function applyPatchWithGit($install_path, $patch_levels, $filename) {
// Do not use git apply unless the install path is itself a git repo
// @see https://stackoverflow.com/a/27283285
if (!is_dir($install_path . '/.git')) {
return FALSE;
}
$patched = FALSE;
foreach ($patch_levels as $patch_level) {
if ($this->io->isVerbose()) {
$comment = 'Testing ability to patch with git apply.';
$comment .= ' This command may produce errors that can be safely ignored.';
$this->io->write('<comment>' . $comment . '</comment>');
}
$checked = $this->executeCommand('git -C %s apply --check -v %s %s', $install_path, $patch_level, $filename);
$output = $this->executor->getErrorOutput();
if (substr($output, 0, 7) == 'Skipped') {
// Git will indicate success but silently skip patches in some scenarios.
//
// @see https://github.com/cweagans/composer-patches/pull/165
$checked = FALSE;
}
if ($checked) {
// Apply the first successful style.
$patched = $this->executeCommand('git -C %s apply %s %s', $install_path, $patch_level, $filename);
break;
}
}
return $patched;
}
/**
* Indicates if a package has been patched.
*
* @param \Composer\Package\PackageInterface $package
* The package to check.
*
* @return bool
* TRUE if the package has been patched.
*/
public static function isPackagePatched(PackageInterface $package) {
return array_key_exists('patches_applied', $package->getExtra());
}
/**
* {@inheritDoc}
*/
public function deactivate(Composer $composer, IOInterface $io)
{
}
/**
* {@inheritDoc}
*/
public function uninstall(Composer $composer, IOInterface $io)
{
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,39 @@
<?php
/**
* @file
* Tests event dispatching.
*/
namespace cweagans\Composer\Tests;
use cweagans\Composer\PatchEvent;
use cweagans\Composer\PatchEvents;
use Composer\Package\PackageInterface;
class PatchEventTest extends \PHPUnit_Framework_TestCase {
/**
* Tests all the getters.
*
* @dataProvider patchEventDataProvider
*/
public function testGetters($event_name, PackageInterface $package, $url, $description) {
$patch_event = new PatchEvent($event_name, $package, $url, $description);
$this->assertEquals($event_name, $patch_event->getName());
$this->assertEquals($package, $patch_event->getPackage());
$this->assertEquals($url, $patch_event->getUrl());
$this->assertEquals($description, $patch_event->getDescription());
}
public function patchEventDataProvider() {
$prophecy = $this->prophesize('Composer\Package\PackageInterface');
$package = $prophecy->reveal();
return array(
array(PatchEvents::PRE_PATCH_APPLY, $package, 'https://www.drupal.org', 'A test patch'),
array(PatchEvents::POST_PATCH_APPLY, $package, 'https://www.drupal.org', 'A test patch'),
);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -15,13 +15,13 @@
}
],
"require": {
"php": ">=7.1",
"psr/http-message": "^1.0",
"php-http/message-factory": "^1.0",
"php": ">=7.2",
"psr/http-message": "^1.1 || ^2.0",
"psr/http-factory": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || 8.5 || 9.4",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"php-http/message-factory": "^1.0",
"php-http/psr7-integration-tests": "^1.0",
"http-interop/http-factory-tests": "^0.9",
"symfony/error-handler": "^4.4"
@@ -43,7 +43,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.6-dev"
"dev-master": "1.8-dev"
}
}
}

View File

@@ -11,11 +11,19 @@ use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
if (!\interface_exists(MessageFactory::class)) {
throw new \LogicException('You cannot use "Nyholm\Psr7\Factory\HttplugFactory" as the "php-http/message-factory" package is not installed. Try running "composer require php-http/message-factory". Note that this package is deprecated, use "psr/http-factory" instead');
}
@\trigger_error('Class "Nyholm\Psr7\Factory\HttplugFactory" is deprecated since version 1.8, use "Nyholm\Psr7\Factory\Psr17Factory" instead.', \E_USER_DEPRECATED);
/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
* @author Martijn van der Ven <martijn@vanderven.se>
*
* @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md
*
* @deprecated since version 1.8, use Psr17Factory instead
*/
class HttplugFactory implements MessageFactory, StreamFactory, UriFactory
{

View File

@@ -57,7 +57,7 @@ class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface,
return Stream::create($resource);
}
public function createUploadedFile(StreamInterface $stream, int $size = null, int $error = \UPLOAD_ERR_OK, string $clientFilename = null, string $clientMediaType = null): UploadedFileInterface
public function createUploadedFile(StreamInterface $stream, ?int $size = null, int $error = \UPLOAD_ERR_OK, ?string $clientFilename = null, ?string $clientMediaType = null): UploadedFileInterface
{
if (null === $size) {
$size = $stream->getSize();

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Nyholm\Psr7;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;
/**
@@ -34,7 +35,10 @@ trait MessageTrait
return $this->protocol;
}
public function withProtocolVersion($version): self
/**
* @return static
*/
public function withProtocolVersion($version): MessageInterface
{
if (!\is_scalar($version)) {
throw new \InvalidArgumentException('Protocol version must be a string');
@@ -81,7 +85,10 @@ trait MessageTrait
return \implode(', ', $this->getHeader($header));
}
public function withHeader($header, $value): self
/**
* @return static
*/
public function withHeader($header, $value): MessageInterface
{
$value = $this->validateAndTrimHeader($header, $value);
$normalized = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
@@ -96,7 +103,10 @@ trait MessageTrait
return $new;
}
public function withAddedHeader($header, $value): self
/**
* @return static
*/
public function withAddedHeader($header, $value): MessageInterface
{
if (!\is_string($header) || '' === $header) {
throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string');
@@ -108,7 +118,10 @@ trait MessageTrait
return $new;
}
public function withoutHeader($header): self
/**
* @return static
*/
public function withoutHeader($header): MessageInterface
{
if (!\is_string($header)) {
throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string');
@@ -135,7 +148,10 @@ trait MessageTrait
return $this->stream;
}
public function withBody(StreamInterface $body): self
/**
* @return static
*/
public function withBody(StreamInterface $body): MessageInterface
{
if ($body === $this->stream) {
return $this;

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Nyholm\Psr7;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;
/**
@@ -40,7 +41,10 @@ trait RequestTrait
return $target;
}
public function withRequestTarget($requestTarget): self
/**
* @return static
*/
public function withRequestTarget($requestTarget): RequestInterface
{
if (!\is_string($requestTarget)) {
throw new \InvalidArgumentException('Request target must be a string');
@@ -61,7 +65,10 @@ trait RequestTrait
return $this->method;
}
public function withMethod($method): self
/**
* @return static
*/
public function withMethod($method): RequestInterface
{
if (!\is_string($method)) {
throw new \InvalidArgumentException('Method must be a string');
@@ -78,7 +85,10 @@ trait RequestTrait
return $this->uri;
}
public function withUri(UriInterface $uri, $preserveHost = false): self
/**
* @return static
*/
public function withUri(UriInterface $uri, $preserveHost = false): RequestInterface
{
if ($uri === $this->uri) {
return $this;

View File

@@ -39,7 +39,7 @@ class Response implements ResponseInterface
* @param string $version Protocol version
* @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
*/
public function __construct(int $status = 200, array $headers = [], $body = null, string $version = '1.1', string $reason = null)
public function __construct(int $status = 200, array $headers = [], $body = null, string $version = '1.1', ?string $reason = null)
{
// If we got no body, defer initialization of the stream until Response::getBody()
if ('' !== $body && null !== $body) {
@@ -67,7 +67,10 @@ class Response implements ResponseInterface
return $this->reasonPhrase;
}
public function withStatus($code, $reasonPhrase = ''): self
/**
* @return static
*/
public function withStatus($code, $reasonPhrase = ''): ResponseInterface
{
if (!\is_int($code) && !\is_string($code)) {
throw new \InvalidArgumentException('Status code has to be an integer');

View File

@@ -81,7 +81,7 @@ class ServerRequest implements ServerRequestInterface
/**
* @return static
*/
public function withUploadedFiles(array $uploadedFiles)
public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface
{
$new = clone $this;
$new->uploadedFiles = $uploadedFiles;
@@ -97,7 +97,7 @@ class ServerRequest implements ServerRequestInterface
/**
* @return static
*/
public function withCookieParams(array $cookies)
public function withCookieParams(array $cookies): ServerRequestInterface
{
$new = clone $this;
$new->cookieParams = $cookies;
@@ -113,7 +113,7 @@ class ServerRequest implements ServerRequestInterface
/**
* @return static
*/
public function withQueryParams(array $query)
public function withQueryParams(array $query): ServerRequestInterface
{
$new = clone $this;
$new->queryParams = $query;
@@ -132,7 +132,7 @@ class ServerRequest implements ServerRequestInterface
/**
* @return static
*/
public function withParsedBody($data)
public function withParsedBody($data): ServerRequestInterface
{
if (!\is_array($data) && !\is_object($data) && null !== $data) {
throw new \InvalidArgumentException('First parameter to withParsedBody MUST be object, array or null');
@@ -165,7 +165,10 @@ class ServerRequest implements ServerRequestInterface
return $this->attributes[$attribute];
}
public function withAttribute($attribute, $value): self
/**
* @return static
*/
public function withAttribute($attribute, $value): ServerRequestInterface
{
if (!\is_string($attribute)) {
throw new \InvalidArgumentException('Attribute name must be a string');
@@ -177,7 +180,10 @@ class ServerRequest implements ServerRequestInterface
return $new;
}
public function withoutAttribute($attribute): self
/**
* @return static
*/
public function withoutAttribute($attribute): ServerRequestInterface
{
if (!\is_string($attribute)) {
throw new \InvalidArgumentException('Attribute name must be a string');

View File

@@ -5,8 +5,6 @@ declare(strict_types=1);
namespace Nyholm\Psr7;
use Psr\Http\Message\StreamInterface;
use Symfony\Component\Debug\ErrorHandler as SymfonyLegacyErrorHandler;
use Symfony\Component\ErrorHandler\ErrorHandler as SymfonyErrorHandler;
/**
* @author Michael Dowling and contributors to guzzlehttp/psr7
@@ -17,6 +15,8 @@ use Symfony\Component\ErrorHandler\ErrorHandler as SymfonyErrorHandler;
*/
class Stream implements StreamInterface
{
use StreamTrait;
/** @var resource|null A resource reference */
private $stream;
@@ -81,10 +81,14 @@ class Stream implements StreamInterface
}
if (\is_string($body)) {
$resource = \fopen('php://temp', 'rw+');
\fwrite($resource, $body);
\fseek($resource, 0);
$body = $resource;
if (200000 <= \strlen($body)) {
$body = self::openZvalStream($body);
} else {
$resource = \fopen('php://memory', 'r+');
\fwrite($resource, $body);
\fseek($resource, 0);
$body = $resource;
}
}
if (!\is_resource($body)) {
@@ -102,35 +106,6 @@ class Stream implements StreamInterface
$this->close();
}
/**
* @return string
*/
public function __toString()
{
try {
if ($this->isSeekable()) {
$this->seek(0);
}
return $this->getContents();
} catch (\Throwable $e) {
if (\PHP_VERSION_ID >= 70400) {
throw $e;
}
if (\is_array($errorHandler = \set_error_handler('var_dump'))) {
$errorHandler = $errorHandler[0] ?? null;
}
\restore_error_handler();
if ($e instanceof \Error || $errorHandler instanceof SymfonyErrorHandler || $errorHandler instanceof SymfonyLegacyErrorHandler) {
return \trigger_error((string) $e, \E_USER_ERROR);
}
return '';
}
}
public function close(): void
{
if (isset($this->stream)) {
@@ -285,11 +260,19 @@ class Stream implements StreamInterface
throw new \RuntimeException('Stream is detached');
}
if (false === $contents = @\stream_get_contents($this->stream)) {
throw new \RuntimeException('Unable to read stream contents: ' . (\error_get_last()['message'] ?? ''));
}
$exception = null;
return $contents;
\set_error_handler(static function ($type, $message) use (&$exception) {
throw $exception = new \RuntimeException('Unable to read stream contents: ' . $message);
});
try {
return \stream_get_contents($this->stream);
} catch (\Throwable $e) {
throw $e === $exception ? $e : new \RuntimeException('Unable to read stream contents: ' . $e->getMessage(), 0, $e);
} finally {
\restore_error_handler();
}
}
/**
@@ -313,4 +296,104 @@ class Stream implements StreamInterface
return $meta[$key] ?? null;
}
private static function openZvalStream(string $body)
{
static $wrapper;
$wrapper ?? \stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper = \get_class(new class() {
public $context;
private $data;
private $position = 0;
public function stream_open(): bool
{
$this->data = \stream_context_get_options($this->context)['Nyholm-Psr7-Zval']['data'];
\stream_context_set_option($this->context, 'Nyholm-Psr7-Zval', 'data', null);
return true;
}
public function stream_read(int $count): string
{
$result = \substr($this->data, $this->position, $count);
$this->position += \strlen($result);
return $result;
}
public function stream_write(string $data): int
{
$this->data = \substr_replace($this->data, $data, $this->position, \strlen($data));
$this->position += \strlen($data);
return \strlen($data);
}
public function stream_tell(): int
{
return $this->position;
}
public function stream_eof(): bool
{
return \strlen($this->data) <= $this->position;
}
public function stream_stat(): array
{
return [
'mode' => 33206, // POSIX_S_IFREG | 0666
'nlink' => 1,
'rdev' => -1,
'size' => \strlen($this->data),
'blksize' => -1,
'blocks' => -1,
];
}
public function stream_seek(int $offset, int $whence): bool
{
if (\SEEK_SET === $whence && (0 <= $offset && \strlen($this->data) >= $offset)) {
$this->position = $offset;
} elseif (\SEEK_CUR === $whence && 0 <= $offset) {
$this->position += $offset;
} elseif (\SEEK_END === $whence && (0 > $offset && 0 <= $offset = \strlen($this->data) + $offset)) {
$this->position = $offset;
} else {
return false;
}
return true;
}
public function stream_set_option(): bool
{
return true;
}
public function stream_truncate(int $new_size): bool
{
if ($new_size) {
$this->data = \substr($this->data, 0, $new_size);
$this->position = \min($this->position, $new_size);
} else {
$this->data = '';
$this->position = 0;
}
return true;
}
}));
$context = \stream_context_create(['Nyholm-Psr7-Zval' => ['data' => $body]]);
if (!$stream = @\fopen('Nyholm-Psr7-Zval://', 'r+', false, $context)) {
\stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper);
$stream = \fopen('Nyholm-Psr7-Zval://', 'r+', false, $context);
}
return $stream;
}
}

View File

@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Nyholm\Psr7;
use Psr\Http\Message\StreamInterface;
use Symfony\Component\Debug\ErrorHandler as SymfonyLegacyErrorHandler;
use Symfony\Component\ErrorHandler\ErrorHandler as SymfonyErrorHandler;
if (\PHP_VERSION_ID >= 70400 || (new \ReflectionMethod(StreamInterface::class, '__toString'))->hasReturnType()) {
/**
* @internal
*/
trait StreamTrait
{
public function __toString(): string
{
if ($this->isSeekable()) {
$this->seek(0);
}
return $this->getContents();
}
}
} else {
/**
* @internal
*/
trait StreamTrait
{
/**
* @return string
*/
public function __toString()
{
try {
if ($this->isSeekable()) {
$this->seek(0);
}
return $this->getContents();
} catch (\Throwable $e) {
if (\is_array($errorHandler = \set_error_handler('var_dump'))) {
$errorHandler = $errorHandler[0] ?? null;
}
\restore_error_handler();
if ($e instanceof \Error || $errorHandler instanceof SymfonyErrorHandler || $errorHandler instanceof SymfonyLegacyErrorHandler) {
return \trigger_error((string) $e, \E_USER_ERROR);
}
return '';
}
}
}
}

View File

@@ -140,7 +140,10 @@ class Uri implements UriInterface
return $this->fragment;
}
public function withScheme($scheme): self
/**
* @return static
*/
public function withScheme($scheme): UriInterface
{
if (!\is_string($scheme)) {
throw new \InvalidArgumentException('Scheme must be a string');
@@ -157,7 +160,10 @@ class Uri implements UriInterface
return $new;
}
public function withUserInfo($user, $password = null): self
/**
* @return static
*/
public function withUserInfo($user, $password = null): UriInterface
{
if (!\is_string($user)) {
throw new \InvalidArgumentException('User must be a string');
@@ -182,7 +188,10 @@ class Uri implements UriInterface
return $new;
}
public function withHost($host): self
/**
* @return static
*/
public function withHost($host): UriInterface
{
if (!\is_string($host)) {
throw new \InvalidArgumentException('Host must be a string');
@@ -198,7 +207,10 @@ class Uri implements UriInterface
return $new;
}
public function withPort($port): self
/**
* @return static
*/
public function withPort($port): UriInterface
{
if ($this->port === $port = $this->filterPort($port)) {
return $this;
@@ -210,7 +222,10 @@ class Uri implements UriInterface
return $new;
}
public function withPath($path): self
/**
* @return static
*/
public function withPath($path): UriInterface
{
if ($this->path === $path = $this->filterPath($path)) {
return $this;
@@ -222,7 +237,10 @@ class Uri implements UriInterface
return $new;
}
public function withQuery($query): self
/**
* @return static
*/
public function withQuery($query): UriInterface
{
if ($this->query === $query = $this->filterQueryAndFragment($query)) {
return $this;
@@ -234,7 +252,10 @@ class Uri implements UriInterface
return $new;
}
public function withFragment($fragment): self
/**
* @return static
*/
public function withFragment($fragment): UriInterface
{
if ($this->fragment === $fragment = $this->filterQueryAndFragment($fragment)) {
return $this;

View File

@@ -1,7 +1,7 @@
{
"name": "pay-now/paynow-php-sdk",
"description": "PHP client library for accessing Paynow API",
"version": "2.2.2",
"version": "2.4.4",
"keywords": [
"paynow",
"mbank",
@@ -20,7 +20,7 @@
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=7.1",
"php": ">=7.2",
"psr/http-message": "^1.0 || ^2.0",
"php-http/client-implementation": "^1.0 || ^2.0",
"php-http/message-factory": "^1.0 || ^2.0",
@@ -28,7 +28,7 @@
"php-http/httplug": "^2.2"
},
"require-dev": {
"phpunit/phpunit": "^7.0",
"phpunit/phpunit": "^8.5.36",
"php-http/mock-client": "^1.3",
"squizlabs/php_codesniffer": "^3.4",
"friendsofphp/php-cs-fixer": "^2.15",
@@ -52,5 +52,11 @@
"test": "vendor/bin/phpunit",
"cs-check": "php-cs-fixer fix --no-interaction --dry-run --diff",
"cs-fix": "php-cs-fixer fix -v --diff"
},
"config": {
"allow-plugins": {
"php-http/discovery": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View File

@@ -6,6 +6,8 @@ class Configuration implements ConfigurationInterface
{
public const API_VERSION = 'v1';
public const API_VERSION_V2 = 'v2';
public const API_VERSION_V3 = 'v3';
public const API_PRODUCTION_URL = 'https://api.paynow.pl';
public const API_SANDBOX_URL = 'https://api.sandbox.paynow.pl';
public const USER_AGENT = 'paynow-php-sdk';
@@ -32,7 +34,7 @@ class Configuration implements ConfigurationInterface
*/
private function get($key)
{
return isset($this->data[$key]) ? $this->data[$key] : null;
return $this->data[$key] ?? null;
}
/**

View File

@@ -13,11 +13,11 @@ class PaynowException extends Exception
/**
* PaynowException constructor.
* @param string $message
* @param int $code
* @param int|null $code
* @param string|null $body
* @param Throwable|null $previous
*/
public function __construct(string $message, int $code = 0, ?string $body = null, Throwable $previous = null)
public function __construct(string $message, ?int $code = 0, ?string $body = null, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);

View File

@@ -3,13 +3,14 @@
namespace Paynow\HttpClient;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
class ApiResponse
{
/**
* Body content
*
* @var string
* @var StreamInterface
*/
public $body;

View File

@@ -43,7 +43,7 @@ class HttpClient implements HttpClientInterface
} catch (NotFoundException $exception) {
$this->client = HttpClientDiscovery::find();
}
$this->url = Psr17FactoryDiscovery::findUrlFactory()->createUri((string)$config->getUrl());
$this->url = Psr17FactoryDiscovery::findUriFactory()->createUri((string)$config->getUrl());
}
/**
@@ -60,8 +60,8 @@ class HttpClient implements HttpClientInterface
/**
* @param RequestInterface $request
* @throws HttpClientException
* @return ApiResponse
* @throws HttpClientException
*/
private function send(RequestInterface $request): ApiResponse
{
@@ -76,16 +76,17 @@ class HttpClient implements HttpClientInterface
* @param string $url
* @param array $data
* @param string|null $idempotencyKey
* @throws HttpClientException
* @return ApiResponse
* @throws HttpClientException
*/
public function post(string $url, array $data, ?string $idempotencyKey = null): ApiResponse
{
$headers = $this->prepareHeaders($data);
$isv3 = strpos($url, Configuration::API_VERSION_V3) !== false;
$headers = $this->prepareHeaders($data, [], $idempotencyKey, $isv3);
if ($idempotencyKey) {
$headers['Idempotency-Key'] = $idempotencyKey;
}
if ($idempotencyKey && !$isv3) {
$headers['Idempotency-Key'] = $idempotencyKey;
}
$request = $this->messageFactory->createRequest(
'POST',
@@ -104,12 +105,13 @@ class HttpClient implements HttpClientInterface
/**
* @param string $url
* @param array $data
* @throws HttpClientException
* @param string|null $idempotencyKey
* @return ApiResponse
* @throws HttpClientException
*/
public function patch(string $url, array $data): ApiResponse
public function patch(string $url, array $data, ?string $idempotencyKey = null): ApiResponse
{
$headers = $this->prepareHeaders($data);
$headers = $this->prepareHeaders($data, [], $idempotencyKey, strpos($url, Configuration::API_VERSION_V3) !== false);
$request = $this->messageFactory->createRequest(
'PATCH',
$this->url->withPath($url)
@@ -127,17 +129,49 @@ class HttpClient implements HttpClientInterface
/**
* @param string $url
* @param string|null $query
* @throws HttpClientException
* @param string|null $idempotencyKey
* @return ApiResponse
* @throws HttpClientException
*/
public function get(string $url, string $query = null): ApiResponse
public function get(string $url, ?string $query = null, ?string $idempotencyKey = null): ApiResponse
{
$request = $this->messageFactory->createRequest(
'GET',
$query ? $this->url->withPath($url)->withQuery($query) : $this->url->withPath($url)
);
foreach ($this->prepareHeaders() as $name => $value) {
$parameters = [];
if ($query) {
parse_str(urldecode($query), $parameters);
}
foreach ($this->prepareHeaders(null, $parameters, $idempotencyKey, strpos($url, Configuration::API_VERSION_V3) !== false) as $name => $value) {
$request = $request->withHeader($name, $value);
}
return $this->send($request);
}
/**
* @param string $url
* @param string $idempotencyKey
* @param string|null $query
* @return ApiResponse
* @throws HttpClientException
*/
public function delete(string $url, string $idempotencyKey, ?string $query = null): ApiResponse
{
$request = $this->messageFactory->createRequest(
'DELETE',
$query ? $this->url->withPath($url)->withQuery($query) : $this->url->withPath($url)
);
$parameters = [];
if ($query) {
parse_str(urldecode($query), $parameters);
}
foreach ($this->prepareHeaders(null, $parameters, $idempotencyKey, strpos($url, Configuration::API_VERSION_V3) !== false) as $name => $value) {
$request = $request->withHeader($name, $value);
}
@@ -150,24 +184,40 @@ class HttpClient implements HttpClientInterface
*/
private function arrayAsJson(array $data): string
{
return json_encode($data);
return json_encode($data, JSON_UNESCAPED_SLASHES);
}
/**
* @param null|array $data
* @param array|null $body
* @param array $query
* @param string|null $idempotencyKey
* @param bool $isv3
* @return array
*/
private function prepareHeaders(?array $data = null)
private function prepareHeaders(?array $body = null, array $query = [], ?string $idempotencyKey = '', bool $isv3 = true): array
{
$headers = [
'Api-Key' => $this->config->getApiKey(),
'User-Agent' => $this->getUserAgent(),
'Accept' => 'application/json'
'Accept' => 'application/json',
];
if ($data) {
if ($isv3) {
$headers['Idempotency-Key'] = $idempotencyKey;
$headers['Signature'] = SignatureCalculator::generateV3(
$this->config->getApiKey(),
$this->config->getSignatureKey(),
$idempotencyKey,
$body ? json_encode($body, JSON_UNESCAPED_SLASHES) : '',
$query
);
}
if (!is_null($body)) {
$headers['Content-Type'] = 'application/json';
$headers['Signature'] = (string)new SignatureCalculator($this->config->getSignatureKey(), json_encode($data));
if (!$isv3) {
$headers['Signature'] = SignatureCalculator::generate($this->config->getSignatureKey(), json_encode($body, JSON_UNESCAPED_SLASHES));
}
}
return $headers;

View File

@@ -6,7 +6,9 @@ interface HttpClientInterface
{
public function post(string $url, array $data, ?string $idempotencyKey = null): ApiResponse;
public function patch(string $url, array $data): ApiResponse;
public function patch(string $url, array $data, ?string $idempotencyKey = null): ApiResponse;
public function get(string $url, ?string $query = null): ApiResponse;
public function get(string $url, ?string $query = null, ?string $idempotencyKey = null): ApiResponse;
public function delete(string $url, string $idempotencyKey, ?string $query = null): ApiResponse;
}

View File

@@ -11,8 +11,12 @@ class PaymentMethod
private $image;
private $status;
private $authorizationType;
/**
* @var SavedInstrument[]
*/
private $savedInstruments = [];
public function __construct($id, $type, $name, $description, $image, $status, $authorizationType)
public function __construct($id, $type, $name, $description, $image, $status, $authorizationType, $savedInstruments = [])
{
$this->id = $id;
$this->type = $type;
@@ -21,6 +25,18 @@ class PaymentMethod
$this->image = $image;
$this->status = $status;
$this->authorizationType = $authorizationType;
if (!empty($savedInstruments)) {
foreach ($savedInstruments as $savedInstrument) {
$this->savedInstruments[] = new SavedInstrument(
$savedInstrument->name,
$savedInstrument->expirationDate,
$savedInstrument->brand,
$savedInstrument->image,
$savedInstrument->token,
$savedInstrument->status
);
}
}
}
public function getId()
@@ -65,4 +81,12 @@ class PaymentMethod
{
return $this->authorizationType;
}
/**
* @return SavedInstrument[]
*/
public function getSavedInstruments()
{
return $this->savedInstruments;
}
}

View File

@@ -9,4 +9,6 @@ class Type
public const GOOGLE_PAY = 'GOOGLE_PAY';
public const APPLE_PAY = 'APPLE_PAY';
public const PBL = 'PBL';
public const PAYPO = 'PAYPO';
public const CLICK_TO_PAY = 'CLICK_TO_PAY';
}

View File

@@ -10,7 +10,7 @@ class PaymentMethods
/**
* @var PaymentMethod[]
*/
private $list;
private $list = [];
public function __construct($body)
{
@@ -25,7 +25,8 @@ class PaymentMethods
$item->description,
$item->image,
$item->status,
$item->authorizationType ?? null
$item->authorizationType ?? null,
$item->savedInstruments ?? []
);
}
}

View File

@@ -13,25 +13,30 @@ class DataProcessing extends Service
* Retrieve data processing notice
*
* @param string|null $locale
*
* @throws PaynowException
* @param string|null $idempotencyKey
* @return Notices
* @throws PaynowException
*/
public function getNotices(?string $locale): Notices
public function getNotices(?string $locale, ?string $idempotencyKey = null): Notices
{
$parameters = [];
if (! empty($locale)) {
if (!empty($locale)) {
$parameters['locale'] = $locale;
}
try {
if (empty($idempotencyKey)) {
$idempotencyKey = md5(($locale ?? '') . '_' . $this->getClient()->getConfiguration()->getApiKey());
}
$decodedApiResponse = $this->getClient()
->getHttpClient()
->get(
Configuration::API_VERSION . "/payments/dataprocessing/notices",
http_build_query($parameters, '', '&')
)
->decode();
->getHttpClient()
->get(
Configuration::API_VERSION_V3 . "/payments/dataprocessing/notices",
http_build_query($parameters, '', '&'),
$idempotencyKey
)
->decode();
return new Notices($decodedApiResponse);
} catch (HttpClientException $exception) {

View File

@@ -16,25 +16,29 @@ class Payment extends Service
*
* @param array $data
* @param string|null $idempotencyKey
* @throws PaynowException
* @return Authorize
* @throws PaynowException
*/
public function authorize(array $data, ?string $idempotencyKey = null): Authorize
{
try {
if (empty($idempotencyKey)) {
$idempotencyKey = ($data['externalId'] ?? null) ? md5($data['externalId']) : md5('_' . $this->getClient()->getConfiguration()->getApiKey());
}
$decodedApiResponse = $this->getClient()
->getHttpClient()
->post(
'/' . Configuration::API_VERSION . '/payments',
'/' . Configuration::API_VERSION_V3 . '/payments',
$data,
$idempotencyKey ?? $data['externalId']
$idempotencyKey
)
->decode();
return new Authorize(
$decodedApiResponse->paymentId,
$decodedApiResponse->status,
! empty($decodedApiResponse->redirectUrl) ? $decodedApiResponse->redirectUrl : null
!empty($decodedApiResponse->redirectUrl) ? $decodedApiResponse->redirectUrl : null
);
} catch (HttpClientException $exception) {
throw new PaynowException(
@@ -52,30 +56,42 @@ class Payment extends Service
* @param string|null $currency
* @param int|null $amount
* @param bool $applePayEnabled
* @param string|null $idempotencyKey
* @param string|null $buyerExternalId
* @return PaymentMethods
* @throws PaynowException
*/
public function getPaymentMethods(?string $currency = null, ?int $amount = 0, bool $applePayEnabled = true): PaymentMethods
public function getPaymentMethods(?string $currency = null, ?int $amount = 0, bool $applePayEnabled = true, ?string $idempotencyKey = null, ?string $buyerExternalId = null): PaymentMethods
{
$parameters = [
'applePayEnabled' => $applePayEnabled,
];
if (! empty($currency)) {
$parameters['currency'] = $currency;
}
$parameters = [];
if ($amount > 0) {
$parameters['amount'] = $amount;
}
$parameters['applePayEnabled'] = $applePayEnabled;
if (!empty($currency)) {
$parameters['currency'] = $currency;
}
if (!empty($buyerExternalId)) {
$parameters['externalBuyerId'] = $buyerExternalId;
}
try {
if (empty($idempotencyKey)) {
$idempotencyKey = md5($currency . '_' . $amount . '_' . $this->getClient()->getConfiguration()->getApiKey());
}
$decodedApiResponse = $this->getClient()
->getHttpClient()
->get(
Configuration::API_VERSION_V2 . '/payments/paymentmethods',
http_build_query($parameters, '', '&')
)
->decode();
->getHttpClient()
->get(
Configuration::API_VERSION_V3 . '/payments/paymentmethods',
http_build_query($parameters, '', '&'),
$idempotencyKey
)
->decode();
return new PaymentMethods($decodedApiResponse);
} catch (HttpClientException $exception) {
throw new PaynowException(
@@ -87,19 +103,59 @@ class Payment extends Service
}
}
/**
* @param string $externalBuyerId
* @param string $token
* @param string $idempotencyKey
* @throws PaynowException
*/
public function removeSavedInstrument(string $externalBuyerId, string $token, string $idempotencyKey): void
{
$parameters = [
'externalBuyerId' => $externalBuyerId,
'token' => $token,
];
try {
$this->getClient()
->getHttpClient()
->delete(
Configuration::API_VERSION_V3 . '/payments/paymentmethods/saved',
$idempotencyKey,
http_build_query($parameters, '', '&')
);
} catch (HttpClientException $exception) {
throw new PaynowException(
$exception->getMessage(),
$exception->getStatus(),
$exception->getBody(),
$exception
);
}
}
/**
* Retrieve payment status
*
* @param string $paymentId
* @throws PaynowException
* @param string|null $idempotencyKey
* @return Status
* @throws PaynowException
*/
public function status(string $paymentId): Status
public function status(string $paymentId, ?string $idempotencyKey = null): Status
{
try {
if (empty($idempotencyKey)) {
$idempotencyKey = md5($paymentId);
}
$decodedApiResponse = $this->getClient()
->getHttpClient()
->get(Configuration::API_VERSION . "/payments/$paymentId/status")
->get(
Configuration::API_VERSION_V3 . "/payments/$paymentId/status",
null,
$idempotencyKey
)
->decode();
return new Status($decodedApiResponse->paymentId, $decodedApiResponse->status);

View File

@@ -16,8 +16,8 @@ class Refund extends Service
* @param string $idempotencyKey
* @param int $amount
* @param null $reason
* @throws PaynowException
* @return Status
* @throws PaynowException
*/
public function create(string $paymentId, string $idempotencyKey, int $amount, $reason = null): Status
{
@@ -25,7 +25,7 @@ class Refund extends Service
$decodedApiResponse = $this->getClient()
->getHttpClient()
->post(
'/' . Configuration::API_VERSION . '/payments/' . $paymentId . '/refunds',
'/' . Configuration::API_VERSION_V3 . '/payments/' . $paymentId . '/refunds',
[
'amount' => $amount,
'reason' => $reason
@@ -45,17 +45,25 @@ class Refund extends Service
}
/**
* Retrieve refund status
* @param $refundId
* @throws PaynowException
* @param string|null $idempotencyKey
* @return Status
* @throws PaynowException
*/
public function status($refundId): Status
public function status($refundId, ?string $idempotencyKey = null): Status
{
try {
if (empty($idempotencyKey)) {
$idempotencyKey = md5($refundId);
}
$decodedApiResponse = $this->getClient()
->getHttpClient()
->get(Configuration::API_VERSION . "/refunds/$refundId/status")
->get(
Configuration::API_VERSION_V3 . "/refunds/$refundId/status",
null,
$idempotencyKey
)
->decode();
return new Status($decodedApiResponse->refundId, $decodedApiResponse->status);

View File

@@ -9,24 +9,35 @@ use Paynow\HttpClient\HttpClientException;
class ShopConfiguration extends Service
{
/**
* @param string $continueUrl
* @param string $notificationUrl
* @throws PaynowException
* @return ApiResponse
*/
public function changeUrls(string $continueUrl, string $notificationUrl)
public const STATUS_ENABLED = 'ENABLED';
public const STATUS_DISABLED = 'DISABLED';
public const STATUS_UNINSTALLED = 'UNINSTALLED';
public const STATUS_UPDATED = 'UPDATED';
/**
* @param string $continueUrl
* @param string $notificationUrl
* @param string|null $idempotencyKey
* @return ApiResponse
* @throws PaynowException
*/
public function changeUrls(string $continueUrl, string $notificationUrl, ?string $idempotencyKey = null): ApiResponse
{
$data = [
'continueUrl' => $continueUrl,
'notificationUrl' => $notificationUrl,
];
try {
if (empty($idempotencyKey)) {
$idempotencyKey = md5($this->getClient()->getConfiguration()->getApiKey());
}
return $this->getClient()
->getHttpClient()
->patch(
'/' . Configuration::API_VERSION.'/configuration/shop/urls',
$data
'/' . Configuration::API_VERSION_V3 . '/configuration/shop/urls',
$data,
$idempotencyKey
);
} catch (HttpClientException $exception) {
throw new PaynowException(
@@ -37,4 +48,31 @@ class ShopConfiguration extends Service
);
}
}
/**
* @param array $statuses
* @return ApiResponse
* @throws PaynowException
*/
public function status(array $statuses): ApiResponse
{
try {
$idempotencyKey = md5($this->getClient()->getConfiguration()->getApiKey());
return $this->getClient()
->getHttpClient()
->post(
'/' . Configuration::API_VERSION_V3 . '/configuration/shop/plugin/status',
$statuses,
$idempotencyKey
);
} catch (HttpClientException $exception) {
throw new PaynowException(
$exception->getMessage(),
$exception->getStatus(),
$exception->getBody(),
$exception
);
}
}
}

View File

@@ -15,6 +15,56 @@ class SignatureCalculator
* @throws InvalidArgumentException
*/
public function __construct(string $signatureKey, string $data)
{
$this->hash = self::generate($signatureKey, $data);
}
/**
* @param string $apiKey
* @param string $signatureKey
* @param string $idempotencyKey
* @param string $data
* @param array $parameters
* @return string
*/
public static function generateV3(string $apiKey, string $signatureKey, string $idempotencyKey, string $data = '', array $parameters = []): string
{
if (empty($apiKey)) {
throw new InvalidArgumentException('You did not provide a api key');
}
if (empty($signatureKey)) {
throw new InvalidArgumentException('You did not provide a Signature key');
}
if (empty($idempotencyKey)) {
throw new InvalidArgumentException('You did not provide a idempotency key');
}
$parsedParameters = [];
foreach ($parameters as $key => $value) {
$parsedParameters[$key] = is_array($value) ? $value : [$value];
}
$signatureBody = [
'headers' => [
'Api-Key' => $apiKey,
'Idempotency-Key' => $idempotencyKey,
],
'parameters' => $parsedParameters ?: new \stdClass(),
'body' => $data,
];
return base64_encode(hash_hmac('sha256', json_encode($signatureBody, JSON_UNESCAPED_SLASHES), $signatureKey, true));
}
/**
* @param string $signatureKey
* @param string $data
* @return string
*/
public static function generate(string $signatureKey, string $data): string
{
if (empty($signatureKey)) {
throw new InvalidArgumentException('You did not provide a Signature key');
@@ -23,7 +73,8 @@ class SignatureCalculator
if (empty($data)) {
throw new InvalidArgumentException('You did not provide any data');
}
$this->hash = base64_encode(hash_hmac('sha256', $data, $signatureKey, true));
return base64_encode(hash_hmac('sha256', $data, $signatureKey, true));
}
/**

View File

@@ -13,6 +13,7 @@ class NotificationTest extends TestCase
* @param $payload
* @param $headers
* @throws SignatureVerificationException
* @suppress PhanNoopNew
*/
public function testVerifyPayloadSuccessfully($payload, $headers)
{
@@ -40,6 +41,11 @@ class NotificationTest extends TestCase
];
}
/**
* @return void
* @throws SignatureVerificationException
* @suppress PhanNoopNew
*/
public function testShouldThrowExceptionOnIncorrectSignature()
{
// given
@@ -53,12 +59,14 @@ class NotificationTest extends TestCase
// then
}
/**
* @suppress PhanNoopNew
* @return void
*/
public function testShouldThrowExceptionOnMissingPayload()
{
// given
$this->expectException(InvalidArgumentException::class);
$payload = null;
$headers = [];
// when
new Notification('s3ecret-k3y', null, null);
@@ -66,12 +74,16 @@ class NotificationTest extends TestCase
// then
}
/**
* @return void
* @throws SignatureVerificationException
* @suppress PhanNoopNew
*/
public function testShouldThrowExceptionOnMissingPayloadHeaders()
{
// given
$this->expectException(InvalidArgumentException::class);
$payload = $this->loadData('notification.json', true);
$headers = null;
// when
new Notification('s3ecret-k3y', $payload, null);

View File

@@ -12,6 +12,9 @@ class TestCase extends BaseTestCase
protected $client;
/**
* @suppress PhanAccessMethodInternal
*/
public function __construct($name = null, array $data = [], $dataName = '')
{
$this->client = new Client(

View File

@@ -22,13 +22,14 @@
"php-http/message": "^1.2",
"psr/http-client": "^1.0",
"psr/http-factory-implementation": "^1.0",
"symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0"
"symfony/options-resolver": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"require-dev": {
"guzzlehttp/psr7": "^1.0",
"php-http/client-integration-tests": "^3.0",
"phpunit/phpunit": "^7.5 || ^9.4",
"laminas/laminas-diactoros": "^2.0"
"laminas/laminas-diactoros": "^2.0",
"php-http/message-factory": "^1.1"
},
"autoload": {
"psr-4": {
@@ -48,5 +49,10 @@
"scripts": {
"test": "vendor/bin/phpunit",
"test-ci": "vendor/bin/phpunit --coverage-clover build/coverage.xml"
},
"config": {
"allow-plugins": {
"php-http/discovery": false
}
}
}

View File

@@ -28,7 +28,8 @@
"php-http/httplug": "^1.0 || ^2.0",
"php-http/message-factory": "^1.0",
"phpspec/phpspec": "^5.1 || ^6.1 || ^7.3",
"symfony/phpunit-bridge": "^6.2"
"symfony/phpunit-bridge": "^6.4.4 || ^7.0.1",
"sebastian/comparator": "^3.0.5 || ^4.0.8"
},
"autoload": {
"psr-4": {

View File

@@ -452,12 +452,21 @@ EOPHP
private function updateComposerLock(Composer $composer, IOInterface $io)
{
if (false === $composer->getConfig()->get('lock')) {
return;
}
$lock = substr(Factory::getComposerFile(), 0, -4).'lock';
$composerJson = file_get_contents(Factory::getComposerFile());
$lockFile = new JsonFile($lock, null, $io);
$locker = ClassDiscovery::safeClassExists(RepositorySet::class)
? new Locker($io, $lockFile, $composer->getInstallationManager(), $composerJson)
: new Locker($io, $lockFile, $composer->getRepositoryManager(), $composer->getInstallationManager(), $composerJson);
if (!$locker->isLocked()) {
return;
}
$lockData = $locker->getLockData();
$lockData['content-hash'] = Locker::getContentHash($composerJson);
$lockFile->write($lockData);

View File

@@ -2,6 +2,8 @@
namespace Http\Discovery;
use Http\Discovery\Exception\NotFoundException as RealNotFoundException;
/**
* Thrown when a discovery does not find any matches.
*
@@ -9,6 +11,6 @@ namespace Http\Discovery;
*
* @deprecated since since version 1.0, and will be removed in 2.0. Use {@link \Http\Discovery\Exception\NotFoundException} instead.
*/
final class NotFoundException extends \Http\Discovery\Exception\NotFoundException
final class NotFoundException extends RealNotFoundException
{
}

View File

@@ -49,12 +49,12 @@ class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface,
private $uriFactory;
public function __construct(
RequestFactoryInterface $requestFactory = null,
ResponseFactoryInterface $responseFactory = null,
ServerRequestFactoryInterface $serverRequestFactory = null,
StreamFactoryInterface $streamFactory = null,
UploadedFileFactoryInterface $uploadedFileFactory = null,
UriFactoryInterface $uriFactory = null
?RequestFactoryInterface $requestFactory = null,
?ResponseFactoryInterface $responseFactory = null,
?ServerRequestFactoryInterface $serverRequestFactory = null,
?StreamFactoryInterface $streamFactory = null,
?UploadedFileFactoryInterface $uploadedFileFactory = null,
?UriFactoryInterface $uriFactory = null
) {
$this->requestFactory = $requestFactory;
$this->responseFactory = $responseFactory;
@@ -98,7 +98,7 @@ class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface,
return $factory->createServerRequest(...\func_get_args());
}
public function createServerRequestFromGlobals(array $server = null, array $get = null, array $post = null, array $cookie = null, array $files = null, StreamInterface $body = null): ServerRequestInterface
public function createServerRequestFromGlobals(?array $server = null, ?array $get = null, ?array $post = null, ?array $cookie = null, ?array $files = null, ?StreamInterface $body = null): ServerRequestInterface
{
$server = $server ?? $_SERVER;
$request = $this->createServerRequest($server['REQUEST_METHOD'] ?? 'GET', $this->createUriFromGlobals($server), $server);
@@ -134,7 +134,7 @@ class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface,
return $factory->createStreamFromResource($resource);
}
public function createUploadedFile(StreamInterface $stream, int $size = null, int $error = \UPLOAD_ERR_OK, string $clientFilename = null, string $clientMediaType = null): UploadedFileInterface
public function createUploadedFile(StreamInterface $stream, ?int $size = null, int $error = \UPLOAD_ERR_OK, ?string $clientFilename = null, ?string $clientMediaType = null): UploadedFileInterface
{
$factory = $this->uploadedFileFactory ?? $this->setFactory(Psr17FactoryDiscovery::findUploadedFileFactory());
@@ -148,7 +148,7 @@ class Psr17Factory implements RequestFactoryInterface, ResponseFactoryInterface,
return $factory->createUri(...\func_get_args());
}
public function createUriFromGlobals(array $server = null): UriInterface
public function createUriFromGlobals(?array $server = null): UriInterface
{
return $this->buildUriFromGlobals($this->createUri(''), $server ?? $_SERVER);
}

View File

@@ -3,6 +3,7 @@
namespace Http\Discovery;
use Http\Discovery\Exception\DiscoveryFailedException;
use Http\Discovery\Exception\NotFoundException as RealNotFoundException;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ServerRequestFactoryInterface;
@@ -19,7 +20,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
{
private static function createException($type, Exception $e)
{
return new \Http\Discovery\Exception\NotFoundException(
return new RealNotFoundException(
'No PSR-17 '.$type.' found. Install a package from this list: https://packagist.org/providers/psr/http-factory-implementation',
0,
$e
@@ -29,7 +30,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
/**
* @return RequestFactoryInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*/
public static function findRequestFactory()
{
@@ -45,7 +46,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
/**
* @return ResponseFactoryInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*/
public static function findResponseFactory()
{
@@ -61,7 +62,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
/**
* @return ServerRequestFactoryInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*/
public static function findServerRequestFactory()
{
@@ -77,7 +78,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
/**
* @return StreamFactoryInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*/
public static function findStreamFactory()
{
@@ -93,7 +94,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
/**
* @return UploadedFileFactoryInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*/
public static function findUploadedFileFactory()
{
@@ -109,7 +110,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
/**
* @return UriFactoryInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*/
public static function findUriFactory()
{
@@ -125,7 +126,7 @@ final class Psr17FactoryDiscovery extends ClassDiscovery
/**
* @return UriFactoryInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*
* @deprecated This will be removed in 2.0. Consider using the findUriFactory() method.
*/

View File

@@ -25,14 +25,21 @@ class Psr18Client extends Psr17Factory implements ClientInterface
private $client;
public function __construct(
ClientInterface $client = null,
RequestFactoryInterface $requestFactory = null,
ResponseFactoryInterface $responseFactory = null,
ServerRequestFactoryInterface $serverRequestFactory = null,
StreamFactoryInterface $streamFactory = null,
UploadedFileFactoryInterface $uploadedFileFactory = null,
UriFactoryInterface $uriFactory = null
?ClientInterface $client = null,
?RequestFactoryInterface $requestFactory = null,
?ResponseFactoryInterface $responseFactory = null,
?ServerRequestFactoryInterface $serverRequestFactory = null,
?StreamFactoryInterface $streamFactory = null,
?UploadedFileFactoryInterface $uploadedFileFactory = null,
?UriFactoryInterface $uriFactory = null
) {
$requestFactory ?? $requestFactory = $client instanceof RequestFactoryInterface ? $client : null;
$responseFactory ?? $responseFactory = $client instanceof ResponseFactoryInterface ? $client : null;
$serverRequestFactory ?? $serverRequestFactory = $client instanceof ServerRequestFactoryInterface ? $client : null;
$streamFactory ?? $streamFactory = $client instanceof StreamFactoryInterface ? $client : null;
$uploadedFileFactory ?? $uploadedFileFactory = $client instanceof UploadedFileFactoryInterface ? $client : null;
$uriFactory ?? $uriFactory = $client instanceof UriFactoryInterface ? $client : null;
parent::__construct($requestFactory, $responseFactory, $serverRequestFactory, $streamFactory, $uploadedFileFactory, $uriFactory);
$this->client = $client ?? Psr18ClientDiscovery::find();

View File

@@ -3,6 +3,7 @@
namespace Http\Discovery;
use Http\Discovery\Exception\DiscoveryFailedException;
use Http\Discovery\Exception\NotFoundException as RealNotFoundException;
use Psr\Http\Client\ClientInterface;
/**
@@ -17,14 +18,14 @@ final class Psr18ClientDiscovery extends ClassDiscovery
*
* @return ClientInterface
*
* @throws Exception\NotFoundException
* @throws RealNotFoundException
*/
public static function find()
{
try {
$client = static::findOneByType(ClientInterface::class);
} catch (DiscoveryFailedException $e) {
throw new \Http\Discovery\Exception\NotFoundException('No PSR-18 clients found. Make sure to install a package providing "psr/http-client-implementation". Example: "php-http/guzzle7-adapter".', 0, $e);
throw new RealNotFoundException('No PSR-18 clients found. Make sure to install a package providing "psr/http-client-implementation". Example: "php-http/guzzle7-adapter".', 0, $e);
}
return static::instantiateClass($client);

View File

@@ -78,7 +78,7 @@ final class CommonClassesStrategy implements DiscoveryStrategy
['class' => React::class, 'condition' => React::class],
],
HttpClient::class => [
['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, [self::class, 'isPsr17FactoryInstalled']]],
['class' => SymfonyHttplug::class, 'condition' => [SymfonyHttplug::class, [self::class, 'isPsr17FactoryInstalled'], [self::class, 'isSymfonyImplementingHttpClient']]],
['class' => Guzzle7::class, 'condition' => Guzzle7::class],
['class' => Guzzle6::class, 'condition' => Guzzle6::class],
['class' => Guzzle5::class, 'condition' => Guzzle5::class],
@@ -158,6 +158,11 @@ final class CommonClassesStrategy implements DiscoveryStrategy
return defined('GuzzleHttp\ClientInterface::MAJOR_VERSION');
}
public static function isSymfonyImplementingHttpClient()
{
return is_subclass_of(SymfonyHttplug::class, HttpClient::class);
}
/**
* Can be used as a condition.
*

View File

@@ -26,7 +26,7 @@ class HttpException extends RequestException
$message,
RequestInterface $request,
ResponseInterface $response,
\Exception $previous = null
?\Exception $previous = null
) {
parent::__construct($message, $request, $previous);
@@ -50,7 +50,7 @@ class HttpException extends RequestException
public static function create(
RequestInterface $request,
ResponseInterface $response,
\Exception $previous = null
?\Exception $previous = null
) {
$message = sprintf(
'[url] %s [http method] %s [status code] %s [reason phrase] %s',

View File

@@ -19,7 +19,7 @@ class NetworkException extends TransferException implements PsrNetworkException
/**
* @param string $message
*/
public function __construct($message, RequestInterface $request, \Exception $previous = null)
public function __construct($message, RequestInterface $request, ?\Exception $previous = null)
{
$this->setRequest($request);

View File

@@ -16,9 +16,6 @@ trait RequestAwareTrait
$this->request = $request;
}
/**
* {@inheritdoc}
*/
public function getRequest(): RequestInterface
{
return $this->request;

View File

@@ -20,7 +20,7 @@ class RequestException extends TransferException implements PsrRequestException
/**
* @param string $message
*/
public function __construct($message, RequestInterface $request, \Exception $previous = null)
public function __construct($message, RequestInterface $request, ?\Exception $previous = null)
{
$this->setRequest($request);

View File

@@ -18,10 +18,7 @@ final class HttpFulfilledPromise implements Promise
$this->response = $response;
}
/**
* {@inheritdoc}
*/
public function then(callable $onFulfilled = null, callable $onRejected = null)
public function then(?callable $onFulfilled = null, ?callable $onRejected = null)
{
if (null === $onFulfilled) {
return $this;
@@ -34,17 +31,11 @@ final class HttpFulfilledPromise implements Promise
}
}
/**
* {@inheritdoc}
*/
public function getState()
{
return Promise::FULFILLED;
}
/**
* {@inheritdoc}
*/
public function wait($unwrap = true)
{
if ($unwrap) {

View File

@@ -17,10 +17,7 @@ final class HttpRejectedPromise implements Promise
$this->exception = $exception;
}
/**
* {@inheritdoc}
*/
public function then(callable $onFulfilled = null, callable $onRejected = null)
public function then(?callable $onFulfilled = null, ?callable $onRejected = null)
{
if (null === $onRejected) {
return $this;
@@ -38,17 +35,11 @@ final class HttpRejectedPromise implements Promise
}
}
/**
* {@inheritdoc}
*/
public function getState()
{
return Promise::REJECTED;
}
/**
* {@inheritdoc}
*/
public function wait($unwrap = true)
{
if ($unwrap) {

View File

@@ -15,10 +15,9 @@
}
],
"require": {
"php": "^7.1 || ^8.0",
"php": "^7.2 || ^8.0",
"clue/stream-filter": "^1.5",
"php-http/message-factory": "^1.0.2",
"psr/http-message": "^1.0 || ^2.0"
"psr/http-message": "^1.1 || ^2.0"
},
"provide": {
"php-http/message-factory-implementation": "1.0"
@@ -26,10 +25,11 @@
"require-dev": {
"ext-zlib": "*",
"ergebnis/composer-normalize": "^2.6",
"guzzlehttp/psr7": "^1.0",
"guzzlehttp/psr7": "^1.0 || ^2.0",
"php-http/message-factory": "^1.0.2",
"phpspec/phpspec": "^5.1 || ^6.3 || ^7.1",
"slim/slim": "^3.0",
"laminas/laminas-diactoros": "^2.0"
"laminas/laminas-diactoros": "^2.0 || ^3.0"
},
"suggest": {
"ext-zlib": "Used with compressor/decompressor streams",

View File

@@ -27,9 +27,6 @@ final class AutoBasicAuth implements Authentication
$this->shouldRemoveUserInfo = (bool) $shouldRremoveUserInfo;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
$uri = $request->getUri();

View File

@@ -32,9 +32,6 @@ final class BasicAuth implements Authentication
$this->password = $password;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
$header = sprintf('Basic %s', base64_encode(sprintf('%s:%s', $this->username, $this->password)));

View File

@@ -25,9 +25,6 @@ final class Bearer implements Authentication
$this->token = $token;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
$header = sprintf('Bearer %s', $this->token);

View File

@@ -33,9 +33,6 @@ final class Chain implements Authentication
$this->authenticationChain = $authenticationChain;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
foreach ($this->authenticationChain as $authentication) {

View File

@@ -26,9 +26,6 @@ class Header implements Authentication
$this->value = $value;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
return $request->withHeader($this->name, $this->value);

View File

@@ -27,7 +27,7 @@ final class Matching implements Authentication
*/
private $matcher;
public function __construct(Authentication $authentication, callable $matcher = null)
public function __construct(Authentication $authentication, ?callable $matcher = null)
{
if (is_null($matcher)) {
$matcher = function () {
@@ -39,9 +39,6 @@ final class Matching implements Authentication
$this->matcher = new CallbackRequestMatcher($matcher);
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
if ($this->matcher->matches($request)) {

View File

@@ -25,9 +25,6 @@ final class QueryParam implements Authentication
$this->params = $params;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
$uri = $request->getUri();

View File

@@ -29,9 +29,6 @@ final class RequestConditional implements Authentication
$this->authentication = $authentication;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
if ($this->requestMatcher->matches($request)) {

View File

@@ -42,9 +42,6 @@ final class Wsse implements Authentication
$this->hashAlgorithm = $hashAlgorithm;
}
/**
* {@inheritdoc}
*/
public function authenticate(RequestInterface $request)
{
$nonce = substr(md5(uniqid(uniqid().'_', true)), 0, 16);

View File

@@ -73,7 +73,7 @@ final class Cookie
$path = null,
$secure = false,
$httpOnly = false,
\DateTime $expires = null
?\DateTime $expires = null
) {
$this->validateName($name);
$this->validateValue($value);
@@ -109,7 +109,7 @@ final class Cookie
$path = null,
$secure = false,
$httpOnly = false,
\DateTime $expires = null
?\DateTime $expires = null
) {
$cookie = new self('name', null, null, $domain, $path, $secure, $httpOnly, $expires);
$cookie->name = $name;
@@ -228,7 +228,7 @@ final class Cookie
*
* @return Cookie
*/
public function withExpires(\DateTime $expires = null)
public function withExpires(?\DateTime $expires = null)
{
$new = clone $this;
$new->expires = $expires;
@@ -511,7 +511,9 @@ final class Cookie
*/
private function normalizePath($path)
{
$path = rtrim($path, '/');
if (null !== $path) {
$path = rtrim($path, '/');
}
if (empty($path) or '/' !== substr($path, 0, 1)) {
$path = '/';

View File

@@ -192,18 +192,12 @@ final class CookieJar implements \Countable, \IteratorAggregate
$this->cookies = new \SplObjectStorage();
}
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function count()
{
return $this->cookies->count();
}
/**
* {@inheritdoc}
*/
#[\ReturnTypeWillChange]
public function getIterator()
{

View File

@@ -20,26 +20,18 @@ trait MessageDecorator
*
* Since the underlying Message is immutable as well
* exposing it is not an issue, because it's state cannot be altered
*
* @return MessageInterface
*/
public function getMessage()
public function getMessage(): MessageInterface
{
return $this->message;
}
/**
* {@inheritdoc}
*/
public function getProtocolVersion()
public function getProtocolVersion(): string
{
return $this->message->getProtocolVersion();
}
/**
* {@inheritdoc}
*/
public function withProtocolVersion($version)
public function withProtocolVersion(string $version): MessageInterface
{
$new = clone $this;
$new->message = $this->message->withProtocolVersion($version);
@@ -47,42 +39,27 @@ trait MessageDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function getHeaders()
public function getHeaders(): array
{
return $this->message->getHeaders();
}
/**
* {@inheritdoc}
*/
public function hasHeader($header)
public function hasHeader(string $header): bool
{
return $this->message->hasHeader($header);
}
/**
* {@inheritdoc}
*/
public function getHeader($header)
public function getHeader(string $header): array
{
return $this->message->getHeader($header);
}
/**
* {@inheritdoc}
*/
public function getHeaderLine($header)
public function getHeaderLine(string $header): string
{
return $this->message->getHeaderLine($header);
}
/**
* {@inheritdoc}
*/
public function withHeader($header, $value)
public function withHeader(string $header, $value): MessageInterface
{
$new = clone $this;
$new->message = $this->message->withHeader($header, $value);
@@ -90,10 +67,7 @@ trait MessageDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function withAddedHeader($header, $value)
public function withAddedHeader(string $header, $value): MessageInterface
{
$new = clone $this;
$new->message = $this->message->withAddedHeader($header, $value);
@@ -101,10 +75,7 @@ trait MessageDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function withoutHeader($header)
public function withoutHeader(string $header): MessageInterface
{
$new = clone $this;
$new->message = $this->message->withoutHeader($header);
@@ -112,18 +83,12 @@ trait MessageDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function getBody()
public function getBody(): StreamInterface
{
return $this->message->getBody();
}
/**
* {@inheritdoc}
*/
public function withBody(StreamInterface $body)
public function withBody(StreamInterface $body): MessageInterface
{
$new = clone $this;
$new->message = $this->message->withBody($body);

View File

@@ -16,10 +16,8 @@ trait RequestDecorator
/**
* Exchanges the underlying request with another.
*
* @return self
*/
public function withRequest(RequestInterface $request)
public function withRequest(RequestInterface $request): RequestInterface
{
$new = clone $this;
$new->message = $request;
@@ -27,18 +25,12 @@ trait RequestDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function getRequestTarget()
public function getRequestTarget(): string
{
return $this->message->getRequestTarget();
}
/**
* {@inheritdoc}
*/
public function withRequestTarget($requestTarget)
public function withRequestTarget(string $requestTarget): RequestInterface
{
$new = clone $this;
$new->message = $this->message->withRequestTarget($requestTarget);
@@ -46,18 +38,12 @@ trait RequestDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function getMethod()
public function getMethod(): string
{
return $this->message->getMethod();
}
/**
* {@inheritdoc}
*/
public function withMethod($method)
public function withMethod(string $method): RequestInterface
{
$new = clone $this;
$new->message = $this->message->withMethod($method);
@@ -65,18 +51,12 @@ trait RequestDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function getUri()
public function getUri(): UriInterface
{
return $this->message->getUri();
}
/**
* {@inheritdoc}
*/
public function withUri(UriInterface $uri, $preserveHost = false)
public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface
{
$new = clone $this;
$new->message = $this->message->withUri($uri, $preserveHost);

View File

@@ -15,10 +15,8 @@ trait ResponseDecorator
/**
* Exchanges the underlying response with another.
*
* @return self
*/
public function withResponse(ResponseInterface $response)
public function withResponse(ResponseInterface $response): ResponseInterface
{
$new = clone $this;
$new->message = $response;
@@ -26,18 +24,12 @@ trait ResponseDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function getStatusCode()
public function getStatusCode(): int
{
return $this->message->getStatusCode();
}
/**
* {@inheritdoc}
*/
public function withStatus($code, $reasonPhrase = '')
public function withStatus(int $code, string $reasonPhrase = ''): ResponseInterface
{
$new = clone $this;
$new->message = $this->message->withStatus($code, $reasonPhrase);
@@ -45,10 +37,7 @@ trait ResponseDecorator
return $new;
}
/**
* {@inheritdoc}
*/
public function getReasonPhrase()
public function getReasonPhrase(): string
{
return $this->message->getReasonPhrase();
}

View File

@@ -16,122 +16,77 @@ trait StreamDecorator
*/
protected $stream;
/**
* {@inheritdoc}
*/
public function __toString()
public function __toString(): string
{
return $this->stream->__toString();
}
/**
* {@inheritdoc}
*/
public function close()
public function close(): void
{
$this->stream->close();
}
/**
* {@inheritdoc}
*/
public function detach()
{
return $this->stream->detach();
}
/**
* {@inheritdoc}
*/
public function getSize()
public function getSize(): ?int
{
return $this->stream->getSize();
}
/**
* {@inheritdoc}
*/
public function tell()
public function tell(): int
{
return $this->stream->tell();
}
/**
* {@inheritdoc}
*/
public function eof()
public function eof(): bool
{
return $this->stream->eof();
}
/**
* {@inheritdoc}
*/
public function isSeekable()
public function isSeekable(): bool
{
return $this->stream->isSeekable();
}
/**
* {@inheritdoc}
*/
public function seek($offset, $whence = SEEK_SET)
public function seek(int $offset, int $whence = SEEK_SET): void
{
$this->stream->seek($offset, $whence);
}
/**
* {@inheritdoc}
*/
public function rewind()
public function rewind(): void
{
$this->stream->rewind();
}
/**
* {@inheritdoc}
*/
public function isWritable()
public function isWritable(): bool
{
return $this->stream->isWritable();
}
/**
* {@inheritdoc}
*/
public function write($string)
public function write(string $string): int
{
return $this->stream->write($string);
}
/**
* {@inheritdoc}
*/
public function isReadable()
public function isReadable(): bool
{
return $this->stream->isReadable();
}
/**
* {@inheritdoc}
*/
public function read($length)
public function read(int $length): string
{
return $this->stream->read($length);
}
/**
* {@inheritdoc}
*/
public function getContents()
public function getContents(): string
{
return $this->stream->getContents();
}
/**
* {@inheritdoc}
*/
public function getMetadata($key = null)
public function getMetadata(?string $key = null)
{
return $this->stream->getMetadata($key);
}

Some files were not shown because too many files have changed in this diff Show More