Installation
composer require bellashaye/paypal-bundle
Add to config/bundles.php:
BellaShaye\PaypalBundle\BellaShayePaypalBundle::class => ['all' => true],
Configuration Publish the default config:
php bin/console config:dump-reference BellaShayePaypalBundle
Update config/packages/bella_shaye_paypal.yaml with your PayPal credentials:
bella_shaye_paypal:
client_id: 'YOUR_CLIENT_ID'
secret: 'YOUR_SECRET'
mode: 'sandbox' # or 'live'
First Use Case: Create a Payment Inject the service in a controller:
use BellaShaye\PaypalBundle\Service\PaypalService;
class PaymentController extends AbstractController
{
public function createPayment(PaypalService $paypalService): Response
{
$payment = $paypalService->createPayment(
10.00, // amount
'USD', // currency
'customer@example.com', // payer email
'Order #123' // description
);
return $this->redirect($payment->getApprovalLink());
}
}
Order Creation & Approval Flow
// 1. Create payment intent
$payment = $paypalService->createPayment(100.00, 'USD', 'user@example.com', 'Order #123');
// 2. Redirect user to PayPal for approval
return $this->redirect($payment->getApprovalLink());
// 3. Handle PayPal callback (webhook)
public function handlePaypalWebhook(Request $request, PaypalService $paypalService)
{
$paypalService->processWebhook($request->getContent());
// Validate and update order status
}
Subscription Management
// Create subscription
$subscription = $paypalService->createSubscription(
'user@example.com',
'premium-plan',
9.99,
'USD',
['start_date' => '2023-12-01T00:00:00Z']
);
// Cancel subscription
$paypalService->cancelSubscription($subscription->getId());
Refunds & Captures
// Capture payment (authorize + capture)
$paypalService->capturePayment($paymentId, 100.00);
// Refund
$paypalService->refundPayment($paymentId, 50.00);
Symfony Forms Integration
Use the PaypalType form field for pre-filled payment forms:
$builder->add('paypal', PaypalType::class, [
'amount' => 10.00,
'currency' => 'USD',
'description' => 'Order #123',
]);
Event Listeners Subscribe to PayPal events for real-time updates:
# config/services.yaml
BellaShaye\PaypalBundle\EventListener\PaypalWebhookListener:
tags:
- { name: kernel.event_listener, event: paypal.webhook, method: onWebhook }
Testing
Use the sandbox mode and mock the PayPal API:
$this->getContainer()->get('bella_shaye_paypal.service')->setMockMode(true);
Webhook Verification
$isValid = $paypalService->verifyWebhook($request->getContent(), $request->headers->get('PAYPAL-SIGNATURE'));
if (!$isValid) throw new \RuntimeException('Invalid webhook signature');
Currency & Locale Mismatches
currency matches PayPal’s supported currencies (e.g., USD, EUR). Locale settings may affect decimal formatting.Idempotency Keys
idempotency_key for duplicate requests (e.g., retries) to avoid duplicate charges:
$paypalService->createPayment(..., null, 'unique-key-123');
Sandbox vs. Live Mode
sandbox mode. Live mode requires real credentials and may have rate limits.Enable Logging Configure Monolog to log PayPal API calls:
# config/packages/monolog.yaml
handlers:
paypal:
type: stream
path: "%kernel.logs_dir%/paypal.log"
level: debug
channels: ["paypal"]
API Response Inspection
Use getLastResponse() to debug failed requests:
try {
$payment = $paypalService->createPayment(...);
} catch (\Exception $e) {
$response = $paypalService->getLastResponse();
error_log($response->getContent());
}
Custom PayPal API Calls Extend the service to support unsupported endpoints:
class CustomPaypalService extends PaypalService
{
public function customApiCall(string $endpoint, array $data)
{
return $this->client->post("/v1/$endpoint", $data);
}
}
Payment Status Handlers Override the default webhook handler:
$paypalService->setWebhookHandler(function (array $event) {
// Custom logic for payment.completed, payment.failed, etc.
});
Payment Data Transformers Modify how payment data is formatted before sending to PayPal:
$paypalService->setPaymentTransformer(function (array $data) {
$data['invoice_number'] = 'INV-' . uniqid();
return $data;
});
How can I help you explore Laravel packages today?