mediaarea/kj-payment-stripe-bundle
Stripe payment bundle for the KJ PHP framework from mediaarea. Adds Stripe checkout and payment processing to KJ applications so you can accept card payments with minimal setup. A small, low-adoption package, so review the source and documentation carefully before relying on it in production.
Read the compatibility surface before anything else. This is a Symfony bundle (Bundle subclass, DependencyInjection/, Resources/config/services.yml), not a Laravel package. There is no service provider, no config/*.php to publish, and no facade. If you are working in a Laravel app, you cannot composer require it and expect it to boot — you would be pulling in Symfony DI machinery for a dependency you would then wire by hand. Treat the decision as: use the bundle only inside Symfony; otherwise use stripe/stripe-php directly.
With that caveat, the minimal path in a Symfony app:
composer require mediaarea/kj-payment-stripe-bundle — open its composer.json first and check the symfony/* and stripe/stripe-php constraints against your app. The Stripe SDK constraint is the real compatibility story here; it dictates which API version and which objects (Charge vs PaymentIntent) the bundle's internals actually speak.config/bundles.php.config/packages/kj_payment_stripe.yaml with your secret/publishable keys sourced from env vars. Do not guess the key names — open vendor/mediaarea/kj-payment-stripe-bundle/DependencyInjection/Configuration.php, which is the authoritative schema, then run bin/console debug:config kj_payment_stripe to confirm what loaded.bin/console debug:container | grep -i stripe to find the service IDs the bundle registers. That list, plus Resources/config/services.yml, is the only real documentation you have.First use case: a single one-off PaymentIntent. Server-side, create the intent through whatever gateway/manager service the bundle exposes and return the client_secret to a Stripe.js form; confirm client-side; handle the redirect/requires_action return in the same controller. Get this end-to-end in test mode before touching subscriptions, refunds, or webhooks — the bundle is thin enough that you'll likely be reaching for the underlying Stripe SDK for anything beyond intent creation anyway.
Treat the bundle as an adapter, not a framework. The healthy pattern is to define your own narrow interface (StripeGateway with createIntent(), refund(), verifyWebhook()) and register an implementation that delegates to the bundle's service. Because this package has 0 stars and 0 dependents, the realistic mid-term outcome is replacing it with direct stripe/stripe-php calls; an interface you own makes that a one-class change instead of a grep across the codebase.
Configure per environment, inject by service ID. Keep sk_ keys in .env.local / your secret manager and reference them as %env(STRIPE_SECRET_KEY)% in the bundle config. Then constructor-inject the bundle service into your own gateway class rather than reaching for Container::get() in a controller — Symfony's compiled container won't catch typos in stringly-typed lookups, and this bundle gives you nothing to compensate for that.
Persist the Stripe object ID, not the transaction. Whatever the bundle returns, the durable record is the pi_... (or ch_...) identifier plus status. Store it on your order, and pass an idempotency key derived from your own order ID on every create call. This is what makes retries — from your code, from a queued job, from a user double-clicking — safe.
Webhook handling belongs in your app, not the bundle. Register a controller at a dedicated route, read the raw request body (not the parsed payload — signature verification breaks otherwise), and verify with \Stripe\Webhook::constructEvent() using the endpoint secret. Dispatch to handlers keyed on type, and wrap each handler in DB-transaction-plus-idempotency-check on event.id. Stripe will redeliver; assume at-least-once semantics everywhere.
Test with the Stripe CLI, which forwards real events to your local webhook route (stripe listen --forward-to). Use 4242 4242 4242 4242 for the happy path and 4000 0025 0000 3155 to exercise SCA/3DS — if the bundle predates PaymentIntents, that card will fail and that failure is your signal that you need to bypass the bundle for anything European.
stripe/stripe-php — Laravel already ships Cashier for subscriptions and a clean path for one-off intents. Installing a Symfony bundle to get a Stripe API client is a lot of container for very little client.DependencyInjection/, a gateway class, and a client wrapper. That reading is expected to take minutes, not days.composer.json locks you to a specific one. Old versions lose access to newer objects and behaviors, and Stripe eventually sunsets them. Check how far behind the pin is before committing.$amount = 1000 is €10.00, except for zero-decimal currencies (JPY, KRW) where 1000 is ¥1000. If the bundle has a currency-conversion helper, verify it rather than assume.Charge-based rather than PaymentIntent-based, it predates the European regulatory shift and will fail on cards that require authentication. Confirm which object model it wraps before designing around it.bin/console debug:config kj_payment_stripe for the merged config, debug:container kj_payment for service IDs and constructor arguments, debug:router for anything it auto-registers. In Symfony, a stale config cache is the usual cause of "my key isn't being picked up" — cache:clear after touching the bundle config.services.yaml, or use a service decorator to wrap the bundle's gateway. There is unlikely to be anything resembling a plugin or event system, so plan on decoration if you need to change behavior.How can I help you explore Laravel packages today?