darvinstudio/darvin-payment-bundle
Installation
composer require darvinstudio/darvin-payment-bundle
php bin/console darvin:payment:install
Darvin\PaymentBundle\DarvinPaymentBundle is enabled in config/bundles.php.Configure Gateway
Edit config/packages/darvin_payment.yaml to define your Omnipay gateway (e.g., Stripe, PayPal):
darvin_payment:
gateway: stripe
stripe:
secret: '%env(STRIPE_SECRET_KEY)%'
publishable: '%env(STRIPE_PUBLISHABLE_KEY)%'
First Use Case: Create a Payment
Inject PaymentFactoryInterface and create a payment for an order:
use Darvin\PaymentBundle\Payment\Factory\PaymentFactoryInterface;
use Darvin\PaymentBundle\Payment\PaidOrder;
use Darvin\PaymentBundle\Payment\Client;
$payment = $paymentFactory->createPayment(
new PaidOrder($orderId, Order::class, $orderNumber),
$order->getTotal(),
new Client($userId, User::class, $user->getEmail()),
'USD'
);
Trigger Purchase Use the Twig helper to generate a purchase link:
<a href="{{ payment_purchase_urls(payment)['stripe'] }}">Pay with Stripe</a>
Payment Creation & State Management
PaymentFactoryInterface to create payments tied to orders/users.created → approved → paid).$payment->approve(); // Transitions state via workflow
$payment->purchase(); // Executes Omnipay purchase
Webhooks & Notifications
darvin_payment.yaml to enable email notifications:
darvin_payment:
notifications:
enabled: true
from_email: 'payments@example.com'
PaymentEventListener to customize email templates or logic.Multi-Gateway Support
darvin_payment:
gateways:
stripe: ~
paypal:
username: '%env(PAYPAL_USERNAME)%'
password: '%env(PAYPAL_PASSWORD)%'
{{ payment_purchase_widget(order) }} {# Renders buttons for all configured gateways #}
Refunds/Cancellations
PaymentInterface methods:
$payment->refund($amount); // Partial/refund-all
$payment->cancel(); // Void the payment
PaymentEvent (e.g., payment.paid) to update order status:
use Darvin\PaymentBundle\Event\PaymentEvent;
$eventDispatcher->addListener(PaymentEvent::PAID, function (PaymentEvent $event) {
$order = $event->getPayment()->getPaidOrder();
$order->markAsPaid();
});
ReceiptInterface to attach receipts to payments:
$payment->addReceipt(new FileReceipt('/path/to/receipt.pdf'));
PaymentFactory with mock gateways (e.g., Omnipay’s MockGateway) in PHPUnit.Workflow Misconfigurations
config/packages/workflow.yaml includes the payment workflow:
payment_workflow:
type: 'state_machine'
supports:
- Darvin\PaymentBundle\Entity\Payment
initial_marking: created
transitions:
approve: { from: created, to: approved }
purchase: { from: approved, to: paid }
php bin/console debug:workflow payment_workflow to inspect states.Gateway-Specific Quirks
publishable_key is set for frontend integration.sandbox mode in development:
paypal:
environment: sandbox
try {
$payment->purchase();
} catch (\Omnipay\Common\Exception\InvalidRequestException $e) {
// Log and retry or notify user
}
Event Dispatching
payment.created are dispatched after the payment entity is persisted. Avoid relying on event data for immediate DB operations.Currency/Amount Precision
$amountInCents = (int)round($order->getTotal() * 100);
config/packages/monolog.yaml:
handlers:
payment:
type: stream
path: var/log/payment.log
level: debug
php bin/console debug:workflow payment_workflow
\Omnipay\Common\CreditCard::setValidationMode(\Omnipay\Common\CreditCard::VALIDATE_MODE_NONE);
Custom States/Transitions
config/packages/workflow.yaml:
transitions:
authorize: { from: approved, to: authorized }
PaymentStateMachine service to override logic.Custom Receipts
ReceiptInterface for PDF/email receipts:
class EmailReceipt implements ReceiptInterface {
public function generate(PaymentInterface $payment): string {
return $this->twig->render('payment/receipt_email.html.twig', [...]);
}
}
Gateway-Specific Logic
PaymentGatewayFactory to inject custom gateways:
services:
Darvin\PaymentBundle\Payment\Gateway\PaymentGatewayFactory:
arguments:
$gateways: ['@custom_stripe_gateway']
Testing
PaymentFactory and PaymentGateway in tests:
$paymentFactory = $this->createMock(PaymentFactoryInterface::class);
$paymentFactory->method('createPayment')->willReturn($mockPayment);
How can I help you explore Laravel packages today?