Installation
composer require draw/draw-payment-bundle
Add to config/app.php under providers:
Draw\PaymentBundle\DrawPaymentBundle::class,
Publish the config:
php artisan vendor:publish --provider="Draw\PaymentBundle\DrawPaymentBundle" --tag="config"
Configuration
Edit .env with your API credentials:
DRAW_PAYMENT_API_KEY=your_api_key
DRAW_PAYMENT_BASE_URL=https://api.example.com
First Use Case: Making a Payment
Inject the DrawPaymentService into a controller or service:
use Draw\PaymentBundle\Services\DrawPaymentService;
public function __construct(private DrawPaymentService $paymentService) {}
public function processPayment(Request $request) {
$response = $this->paymentService->createPayment([
'amount' => 100.00,
'currency' => 'EUR',
'description' => 'Order #12345',
'customer_email' => 'user@example.com',
]);
return response()->json($response);
}
Key Files to Review
config/draw_payment.php (API endpoints, default settings)src/Services/DrawPaymentService.php (core logic)src/Exceptions/ (custom exceptions)// Create a payment
$payment = $paymentService->createPayment($paymentData);
// Retrieve a payment
$payment = $paymentService->getPayment($paymentId);
Extend the DrawPaymentWebhookHandler to process events:
use Draw\PaymentBundle\Services\DrawPaymentWebhookHandler;
class CustomWebhookHandler extends DrawPaymentWebhookHandler {
public function handlePaymentSucceeded(array $payload) {
// Custom logic for successful payments
}
}
Register in config/draw_payment.php:
'webhook_handler' => \App\Services\CustomWebhookHandler::class,
Use the DrawPaymentClient directly for custom retry logic:
$client = app(DrawPaymentClient::class);
$response = $client->post('/payments', $data, ['retry' => 3]);
Use the DrawPaymentService with a mock client:
$mockClient = Mockery::mock(DrawPaymentClient::class);
$mockClient->shouldReceive('post')->andReturn(['success' => true]);
$service = new DrawPaymentService($mockClient);
Laravel Events
Bind to payment.created or payment.failed events in EventServiceProvider:
protected $listen = [
'Draw\PaymentBundle\Events\PaymentCreated' => [
\App\Listeners\LogPayment::class,
],
];
Middleware for API Key Validation Add middleware to validate API keys in incoming requests:
public function handle($request, Closure $next) {
if (!$request->hasValidApiKey()) {
abort(403);
}
return $next($request);
}
Queue Jobs for Async Processing
Dispatch ProcessPaymentJob for background processing:
ProcessPaymentJob::dispatch($paymentData);
API Rate Limits
GuzzleHttp\Middleware::retry:
$client->setDefaultOption('handler', HandlerStack::create([
Middleware::retry(new RetryDecorator([
'max_retries' => 3,
'delay' => 100,
'retry_conditions' => function ($result) {
return $result->hasResponse() &&
$result->getResponse()->getStatusCode() === 429;
},
])),
]));
Idempotency
$paymentService->createPayment($data, ['idempotency_key' => 'unique_key']);
Webhook Verification
verifyWebhook method but requires manual setup:
$isValid = $paymentService->verifyWebhook($payload, $signature);
Deprecated Methods
@deprecated tags in DrawPaymentService. Example:
// Avoid this (deprecated)
$paymentService->oldMethod();
// Use this instead
$paymentService->newMethod();
Enable Debug Logging
Set debug to true in config/draw_payment.php:
'debug' => env('APP_DEBUG', false),
Logs will appear in storage/logs/laravel.log.
HTTP Client Debugging Use Guzzle’s debug handler:
$client = new DrawPaymentClient();
$client->setDefaultOption('debug', true);
Common Exceptions Catch specific exceptions for better error handling:
try {
$paymentService->createPayment($data);
} catch (\Draw\PaymentBundle\Exceptions\InvalidAmountException $e) {
// Handle invalid amount
} catch (\Draw\PaymentBundle\Exceptions\ApiConnectionException $e) {
// Handle connection issues
}
Custom API Clients
Extend DrawPaymentClient to add custom logic:
class CustomPaymentClient extends DrawPaymentClient {
public function customEndpoint($endpoint, $data) {
return $this->post("/custom/{$endpoint}", $data);
}
}
Bind it in AppServiceProvider:
$this->app->bind(DrawPaymentClient::class, function ($app) {
return new CustomPaymentClient();
});
Payment Gateways
Add support for additional payment methods by extending DrawPaymentService:
class ExtendedPaymentService extends DrawPaymentService {
public function createSEPAPayment(array $data) {
return $this->client->post('/sepa', $data);
}
}
Database Models
Create a Payment model to persist payment data:
class Payment extends Model {
protected $fillable = ['draw_payment_id', 'amount', 'status'];
}
Use the payment.created event to sync data:
public function handle(PaymentCreated $event) {
Payment::create([
'draw_payment_id' => $event->payment->id,
'amount' => $event->payment->amount,
'status' => $event->payment->status,
]);
}
Testing Helpers Create a trait for testing:
trait PaymentTests {
protected function createTestPayment() {
return $this->paymentService->createPayment([
'amount' => 50.00,
'currency' => 'EUR',
'description' => 'Test Payment',
]);
}
}
How can I help you explore Laravel packages today?