Installation
composer require akyos/payment-bundle
Add the bundle to config/bundles.php:
return [
// ...
Akyos\PaymentBundle\AkyosPaymentBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console config:dump-reference Akyos\PaymentBundle\DependencyInjection\Configuration
Configure Stripe keys in .env:
STRIPE_SECRET_KEY=your_secret_key
STRIPE_PUBLISHABLE_KEY=your_publishable_key
First Use Case: Creating a Payment Intent
Inject the PaymentService in a controller:
use Akyos\PaymentBundle\Service\PaymentService;
class CheckoutController extends AbstractController
{
public function __construct(private PaymentService $paymentService) {}
public function createIntent(Request $request): JsonResponse
{
$intent = $this->paymentService->createPaymentIntent(
$request->request->get('amount'),
$request->request->get('currency', 'usd')
);
return $this->json($intent);
}
}
Frontend Integration Use the publishable key in your frontend (e.g., React/Vue) to initialize Stripe.js:
const stripe = Stripe(process.env.STRIPE_PUBLISHABLE_KEY);
Payment Creation
Use PaymentService for server-side payment logic:
$intent = $paymentService->createPaymentIntent(1000, 'usd'); // $10.00
$intent = $paymentService->createPaymentIntent(1000, 'usd', ['metadata' => ['order_id' => 123]]);
Webhook Handling Register a controller to handle Stripe webhooks:
#[Route('/stripe/webhook', name: 'stripe_webhook', methods: ['POST'])]
public function handleWebhook(Request $request, PaymentService $paymentService): Response
{
$event = $paymentService->handleWebhook($request->getContent());
// Process event (e.g., update order status)
return new Response('OK');
}
Subscription Management Create/subscribe customers:
$customer = $paymentService->createCustomer('[email protected]', 'card_123');
$subscription = $paymentService->createSubscription($customer->id, 'price_123');
Refunds and Disputes Handle refunds via:
$paymentService->createRefund('pi_123', ['amount' => 500]); // Refund $5.00
Dependency Injection
Prefer constructor injection for PaymentService in controllers/services:
public function __construct(private PaymentService $paymentService) {}
Event Listeners Extend functionality by listening to Stripe events:
#[AsEventListener(event: KernelEvents::TERMINATE)]
public function onKernelTerminate(Request $request, PaymentService $paymentService)
{
if ($request->getPathInfo() === '/stripe/webhook') {
$paymentService->handleWebhook($request->getContent());
}
}
Testing
Use Stripe test keys (pk_test_..., sk_test_...) and mock the service in tests:
$this->paymentService = $this->createMock(PaymentService::class);
$this->paymentService->method('createPaymentIntent')
->willReturn(['client_secret' => 'test_secret']);
Configuration Overrides
Override default config in config/packages/akyos_payment.yaml:
akyos_payment:
stripe:
webhook_secret: 'whsec_...' # Optional: Validate webhook signatures
Webhook Validation
webhook_secret in config, webhook events will not be validated. Always set it in production:
akyos_payment:
stripe:
webhook_secret: '%env(STRIPE_WEBHOOK_SECRET)%'
Amount Handling
$amountInCents = $amountInDollars * 100;
Customer ID Persistence
customer IDs in your database (e.g., users table) to avoid recreating customers on every payment.Idempotency Keys
$intent = $paymentService->createPaymentIntent(1000, 'usd', [], 'unique_key_123');
Error Handling
Stripe\Exception\BaseException globally or per-operation:
try {
$intent = $paymentService->createPaymentIntent(1000, 'usd');
} catch (Stripe\Exception\CardException $e) {
// Handle card errors
}
Log Stripe Events
Enable logging in config/packages/akyos_payment.yaml:
akyos_payment:
debug: true # Logs all Stripe API calls/responses
Stripe CLI Use the Stripe CLI to test webhooks locally:
stripe listen --forward-to localhost:8000/stripe/webhook
Test Mode Quirks
4242 4242 4242 4242) work in test mode but fail in live mode.stripe test helpers to simulate 3D Secure or failed payments.Custom Services
Extend PaymentService to add domain-specific logic:
class CustomPaymentService extends PaymentService
{
public function createOrderPayment(int $orderId, float $amount): array
{
$intent = parent::createPaymentIntent($amount * 100, 'usd');
// Add order metadata
$intent['metadata']['order_id'] = $orderId;
return $intent;
}
}
Event Dispatching Dispatch Symfony events after payment operations:
$paymentService->createPaymentIntent(1000, 'usd', [], null, function ($intent) {
$this->eventDispatcher->dispatch(new PaymentIntentCreatedEvent($intent));
});
Custom Webhook Handlers Override the default webhook handler:
$paymentService->setWebhookHandler(function ($event) {
// Custom logic for specific event types
if ($event->type === 'payment_intent.succeeded') {
// Update order status
}
});
Rector for Upgrades The bundle includes Rector for PHP 8.1+ migrations. Run it during upgrades:
vendor/bin/rector process src --dry-run
How can I help you explore Laravel packages today?