payplug / unified-plugin-core
Core foundations shared library for Payplug e-commerce plugins.
Requires
- php: >=7.4
- giggsey/libphonenumber-for-php: 8.13.45
- giggsey/locale: 1.9
- symfony/polyfill-mbstring: 1.28.0
Requires (Dev)
- captainhook/captainhook: ^5.0
- friendsofphp/php-cs-fixer: 3.60.0
- mockery/mockery: ^1.6
- phpstan/phpstan: ^2.2
- phpstan/phpstan-mockery: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^9.5
This package is auto-updated.
Last update: 2026-07-17 09:09:51 UTC
README
Core foundations shared library for Payplug e-commerce plugins (e.g. PrestaShop).
Requirements
- Docker (the only local requirement — PHP and Composer run inside a container)
composer.json'srequire.phpis>=7.4— this matches the build-tooling floor of the PrestaShop/WooCommerce plugins that depend on this package via Composer, not the runtime the shipped code executes on.- Regardless, code under
src/andtests/must not use any PHP syntax newer than 7.1 (no typed properties, arrow functions, constructor property promotion,match, orenum). This library ends up bundled directly into a plugin ZIP distributed on marketplaces, without a livevendor/install on the merchant's server — and that server can be running PrestaShop 1.7.0 on PHP 7.1.
Getting started
make install
This builds the dev Docker image (PHP 7.4-cli + Composer — the actual dev/CI tooling baseline)
and runs composer install inside it, including the CaptainHook git hooks setup.
Other targets:
make test— run the PHPUnit suitemake coverage— run the PHPUnit suite with a Clover coverage report atbuild/logs/clover.xmlmake stan— PHPStan level 8 static analysismake cs-lint— PHP-CS-Fixer dry-run diffmake cs-fix— PHP-CS-Fixer, applies fixesmake quality—cs-lint+stan+test(mirrors the CIqualityjob)make shell— interactive shell in the dev container, e.g. to run a single test:vendor/bin/phpunit tests/ScaffoldingTest.phpmake verify-71— proves the PHP 7.1 runtime floor actually holds (see Compatibility below)
Compatibility
PHP 7.1 compatibility is enforced two ways:
- A CI job lints
src/andtests/directly withphp -lacross PHP 7.1, 7.4, 8.0, 8.1, and 8.2 interpreters — a parser-level check independent of Composer's own PHP version gate (which would otherwise reject installing this package on anything below 7.4). make verify-71goes further: it builds a--no-devvendor tree (what actually ships to merchants) and boots it under a realphp:7.1-cliinterpreter, then runs a small smoke script exercisingPhoneHelper/AmountHelperend to end. This is what actually caught that a caret version range ongiggsey/libphonenumber-for-phphad silently drifted past the PHP 7.1 floor — run it after touching any dependency version.
Composer's own platform-check (the runtime guard baked into vendor/composer/platform_check.php)
is disabled in composer.json ("config": {"platform-check": false}), since it would otherwise
enforce this repo's own require.php (>=7.4, a build-tooling floor, not a runtime one) against
the merchant's actual PHP version. make verify-71 is the real replacement check.
Contracts
src/Contracts/ holds the 6 interfaces that define the boundary between this library and each
consuming CMS plugin (first real consumer: UHF/Sylius) — designed around what a CMS needs to
provide, not the not-yet-built Unified API's shape. Each ships with a docblock sketching a Sylius
and a WooCommerce implementation; this library itself contains no concrete implementations.
ILogger— structured logging sink (debug/info/error), decoupled from any CMS's native logger.IConfigurationRepository— OAuth2 client credentials and Hosted Fields public key material, sourced from each CMS's own settings storage.IPaymentRepository— persistsOperationDataand tracks webhook processing state for idempotency.IOrderStateMutator— applies aPaymentOutcometo the CMS-native order, identified by order ID (not a CMS-native object, since Sylius and WooCommerce orders share no common type).ILock— per-operation mutex preventing a retried webhook from being processed concurrently with itself.ITokenCache— caches the OAuth2 JWT this library will use against the future Unified API.
Exceptions
PayplugUnifiedCore\Exceptions\PayplugException is the base type for every exception this
library throws — catch it instead of a generic \Exception to handle any error raised by this
package. Six domain-specific subtypes let callers catch more precisely:
RefundAmountExceptionPaymentNotFoundExceptionInvalidPhoneNumberExceptionCardOperationExceptionApiExceptionInvalidOperationDataException
Each behaves like a standard PHP exception: new SomeException($message, $code, $previous).
Models
PayplugUnifiedCore\Models\PaymentOutcome expresses UPC's payment result intent to the CMS,
decoupled from any CMS's native order-status vocabulary — a set of class constants (a PHP 7.1
stand-in for a PHP 8.1 enum):
use PayplugUnifiedCore\Models\PaymentOutcome; PaymentOutcome::PAID; // 'paid' PaymentOutcome::AUTHORIZED; // 'authorized' PaymentOutcome::CAPTURE_REQUIRED; // 'capture_required' PaymentOutcome::THREE_DS_PENDING; // 'three_ds_pending' PaymentOutcome::REFUNDED; // 'refunded' PaymentOutcome::FAILED; // 'failed' PaymentOutcome::isValid('paid'); // true PaymentOutcome::isValid('bogus'); // false
PayplugUnifiedCore\Models\OperationData is the persistence value object built from a Payplug API
response or webhook payload — its constructor is this library's validation boundary for that data,
throwing InvalidOperationDataException on an empty operationId/execCode/orderId, a negative
amount, or an outcome that isn't a PaymentOutcome constant:
use PayplugUnifiedCore\Models\OperationData; use PayplugUnifiedCore\Models\PaymentOutcome; $operation = new OperationData('op_123', '4001', PaymentOutcome::PAID, 4999, 'order_456'); $operation->operationId; // 'op_123' $operation->execCode; // '4001' $operation->outcome; // 'paid' $operation->amount; // 4999 (cents) $operation->orderId; // 'order_456'
Utilities
PayplugUnifiedCore\Utilities\Helpers\AmountHelper converts amounts between a major-unit float
(e.g. a plugin's cart or order total) and the integer number of cents the Payplug API expects:
use PayplugUnifiedCore\Utilities\Helpers\AmountHelper; AmountHelper::toCents(49.99); // 4999 AmountHelper::fromCents(4999); // 49.99
toCents() corrects the classic floating-point imprecision (19.99 * 100 evaluates to
1998.9999999999998 in raw PHP) by rounding before casting to int.
For CMS platforms where the merchant can configure their own rounding algorithm (e.g.
PrestaShop's PS_ROUND_MODE), pass the resolved mode explicitly — it only changes the result for
amounts landing exactly on a half-cent boundary:
AmountHelper::toCents(19.995, PHP_ROUND_HALF_EVEN); // 2000 AmountHelper::toCents(19.995, PHP_ROUND_HALF_DOWN); // 1999
PayplugUnifiedCore\Utilities\Helpers\PhoneHelper normalizes a customer-entered phone number to
E.164 (the format the Payplug API expects) and determines whether it's a mobile line, backed by
giggsey/libphonenumber-for-php:
use PayplugUnifiedCore\Utilities\Helpers\PhoneHelper; PhoneHelper::toE164('06 12 34 56 78', 'FR'); // "+33612345678" PhoneHelper::isMobile('06 12 34 56 78', 'FR'); // true
$countryCode is a 2-letter ISO 3166-1 alpha-2 region code (the UK's is GB, not UK). Invalid
or unparseable input throws InvalidPhoneNumberException from both methods.
License
MIT