Installation:
composer require ekyna/payment-bundle
Add the bundle to config/bundles.php (Symfony 4+):
Ekyna\PaymentBundle\EkynaPaymentBundle::class => ['all' => true],
Publish Config:
php artisan vendor:publish --provider="Ekyna\PaymentBundle\EkynaPaymentBundle" --tag=config
This generates config/payment.php with default gateways (e.g., PayPal, Stripe).
First Use Case: Define a payment method in your controller:
use Ekyna\PaymentBundle\Payment\PaymentGatewayInterface;
public function processPayment(Request $request, PaymentGatewayInterface $gateway)
{
$payment = $gateway->createPayment([
'amount' => 100.00,
'currency' => 'USD',
'description' => 'Order #12345',
'method' => 'paypal', // Configured in payment.php
]);
return $payment->execute();
}
Gateway Integration:
config/payment.php:
'gateways' => [
'paypal' => [
'class' => 'Ekyna\PaymentBundle\Payment\Gateway\PayPalGateway',
'options' => [
'api_username' => env('PAYPAL_API_USERNAME'),
// ... other PayPal credentials
],
],
],
PaymentGatewayInterface into services/controllers for flexibility.Payment Lifecycle:
$gateway->createPayment($data) → Returns a Payment object.$payment->execute() → Triggers the gateway’s logic.$payment->refund($amount) → If supported by the gateway.Event-Driven Extensions:
payment.created, payment.succeeded, or payment.failed events:
// In a service provider
$this->app->booted(function () {
event(new PaymentCreated($payment));
});
Form Integration:
payment_form Twig helper to generate gateway-specific forms:
{{ payment_form('paypal', payment) }}
Custom Gateways:
Implement PaymentGatewayInterface and register it in config/payment.php:
'custom_gateway' => [
'class' => 'App\Payment\CustomGateway',
'options' => [...],
],
Payment Models:
Extend Ekyna\PaymentBundle\Model\Payment to add domain-specific fields:
class OrderPayment extends Payment
{
protected $orderId;
}
Webhook Handling:
Use the PaymentWebhookListener to process gateway callbacks:
$listener = new PaymentWebhookListener($gateway);
$listener->handle($request->getContent());
Deprecated Package:
Configuration Quirks:
TODO in README: Assume config/payment.php requires manual setup (no defaults for credentials).config/services.php:
PaymentGatewayInterface::class => \Ekyna\PaymentBundle\Payment\Gateway\PayPalGateway::class,
Event System:
src/Event/ for available events (e.g., PaymentEvent).Database Schema:
payments table. Run migrations manually if not auto-generated:
php artisan vendor:publish --provider="Ekyna\PaymentBundle\EkynaPaymentBundle" --tag=migrations
Gateway Failures:
Enable debug mode in config/payment.php:
'debug' => env('APP_DEBUG', false),
Logs will appear in storage/logs/laravel.log.
Webhook Testing:
Use the PaymentWebhookListener with a test payload:
$listener->handle(json_encode([
'ipn_track_id' => '123', // PayPal example
'mc_gross' => '100.00',
]));
Override Payment Model:
Bind your custom model in config/payment.php:
'model' => App\Models\OrderPayment::class,
Add Custom Fields:
Extend the Payment entity and update the migration:
class OrderPayment extends Payment
{
protected $userId;
}
Gateway-Specific Logic:
Override gateway methods (e.g., execute()) by creating a decorator:
class CustomPayPalGateway extends PayPalGateway
{
public function execute(Payment $payment)
{
// Add custom logic
return parent::execute($payment);
}
}
Register it in config/payment.php.
Testing:
Use the PaymentGatewayInterface mock in PHPUnit:
$mockGateway = $this->createMock(PaymentGatewayInterface::class);
$mockGateway->method('createPayment')->willReturn(new Payment());
How can I help you explore Laravel packages today?