vankosoft/payment-bundle
Vankosoft Payment Bundle is a PHP payment processing bundle for Vankosoft e-commerce applications, offering payment gateway integrations, transaction handling, and an extensible payment method architecture for building flexible checkout flows.
This is a small, low-traffic Symfony bundle (1 star, 0 dependents), so treat the source as the documentation. Budget an hour to read it before wiring anything into an app.
Install and register
composer require vankosoft/payment-bundle
Symfony Flex probably won't have a recipe for it, so register the bundle manually in config/bundles.php:
return [
// ...
Vankosoft\PaymentBundle\VankosoftPaymentBundle::class => ['all' => true],
];
Then check DependencyInjection/Configuration.php and DependencyInjection/VankosoftPaymentExtension.php first — they are the authoritative list of config keys, service IDs, and constructor arguments. Everything else (entities, forms, controllers) hangs off that.
Where to look first, in order
DependencyInjection/Configuration.php — required config (gateway credentials, table prefixes, currency, factory names).Resources/config/services.*.yaml — the public/aliased service IDs you'll actually inject.Entity/ or Model/ — the persistence model (payment, payment method, gateway config).Form/ and Controller/ — the reference UI flow you can copy or override.README.md — often thin; cross-check with the tests/ folder if present.First use case
Get one sandbox gateway working end-to-end before touching anything else:
bin/console config:dump-reference vankosoft_payment # confirm the root key
bin/console doctrine:migrations:diff # entities ship with the bundle
bin/console doctrine:migrations:migrate
Then hit the payment form route in dev with a sandbox credential set. If the bundle exposes a route prefix, verify it with bin/console debug:router | grep -i pay.
Inject the bundle's services, don't reimplement them. The bundle almost certainly exposes a manager/factory pair (something like ...Manager and ...Factory) plus a gateway registry. Prefer constructor injection of the aliased service ID over $container->get():
public function __construct(
private PaymentManagerInterface $paymentManager,
private GatewayRegistry $gateways,
) {}
Create payments through the factory, not new. Entities in bundles like this usually carry lifecycle callbacks (UUIDs, timestamps, initial state, details JSON). Bypassing the factory gives you half-initialized records that fail later in the flow.
Treat gateway selection as data, not code. Register additional gateways via the config map rather than branching in your controllers; the bundle's registry exists precisely so you can iterate $gateways->all() in a template or a checkout step. When adding a custom gateway, extend the bundle's abstract gateway class and tag the service — check Resources/config/services.yaml for the tag name the compiler pass consumes.
Wrap the flow in your own domain service. Bundles this small tend to change service IDs between minor versions. Put one CheckoutService in your app that owns the bundle's API surface, so an upgrade touches one file:
final class CheckoutService
{
public function start(Order $order, string $gatewayCode): Payment
{
$method = $this->gateways->get($gatewayCode);
$payment = $this->paymentManager->createFor($order, $method);
return $this->paymentManager->transition($payment, PaymentState::PENDING);
}
}
Handle callbacks in your own controller. Webhook/IPN routes shipped by third-party bundles are frequently either too opinionated or too generic. Point the gateway's notify URL at your controller, verify the signature yourself, then call the bundle's manager to mark the payment captured — and make the handler idempotent by keying on the gateway's transaction ID.
Override templates, don't fork controllers. Use the standard Symfony mechanism (templates/bundles/VankosoftPaymentBundle/...) and confirm the bundle's Twig namespace from getPath() in the bundle class.
Listen to events rather than editing the bundle. Check Event/ or EventDispatcher usage in the source; a payment.completed-style event is the cleanest hook for order fulfillment, email, and ledger writes.
Maintenance risk is the headline issue. One star and zero dependents means no community to absorb breakage. Pin the version exactly ("vankosoft/payment-bundle": "1.2.*" or a commit hash for dev-main), commit composer.lock, and be prepared to vendor the bundle ("type": "path" with a local fork) if upstream goes quiet. Read the last-commit date before committing to it.
Entity mapping collisions. Bundles that ship Entity/ classes with their own mappings frequently clash with your app's naming strategy or table prefix. Run bin/console doctrine:mapping:info immediately after install and check for duplicate table names before generating migrations — and never run doctrine:schema:update --force on an existing database.
Money as integers, always. Verify how the bundle stores amounts. If it uses floats or a decimal string, normalize at your boundary — pick a currency with a fixed exponent (or store minor units) and convert exactly once, in your own service. Currency-in-amount bugs are the most expensive kind to find in payment code.
Config key naming is not guessable. The root key may be vankosoft_payment, vs_payment, or derived from the extension alias. Use config:dump-reference and debug:container --parameter= rather than copying keys from a README — several of these small bundles have READMEs that predate a config restructure.
Service visibility. Symfony's default is private, and older bundles still call $this->get() in controllers. If you get "service not found," check debug:container for the alias and confirm the bundle still ships a public: true alias — otherwise wrap it.
Sandbox detection. Look for an explicit sandbox/test_mode flag and assert it in a boot-time check for the prod env. Silently hitting production endpoints during integration testing is the classic failure here.
Extension points to lean on: compiler passes (to register your own gateway), the gateway registry (to add methods without touching bundle code), form types (to add fields you need), and event subscribers (for post-payment work). If the bundle offers none of these for your use case, that's your signal to keep the integration behind your own façade rather than spreading it through the codebase.
Log the raw gateway response. Store the unmodified request/response payload on the payment record (a details JSON column is the usual pattern). When a payment fails in production six weeks from now, this is the only thing that will save you.
How can I help you explore Laravel packages today?