Define the strategy interface:
interface PaymentGatewayInterface
{
public function processPayment(array $paymentDetails): bool;
}
Implement concrete strategies:
class StripePayment implements PaymentGatewayInterface
{
public function processPayment(array $paymentDetails): bool
{
// Stripe-specific implementation
}
}
class PayPalPayment implements PaymentGatewayInterface
{
public function processPayment(array $paymentDetails): bool
{
// PayPal-specific implementation
}
}
Create a context class:
class PaymentProcessor
{
private $gateway;
public function __construct(PaymentGatewayInterface $gateway)
{
$this->gateway = $gateway;
}
public function pay(array $paymentDetails): bool
{
return $this->gateway->processPayment($paymentDetails);
}
}
Install required packages:
composer require stripe/stripe-php
composer require paypal/rest-api-sdk-php
Create service providers:
php artisan make:provider StripeServiceProvider
php artisan make:provider PayPalServiceProvider
Implement service providers:
// app/Providers/StripeServiceProvider.php
public function register()
{
$this->app->bind(PaymentGatewayInterface::class, function ($app) {
return new StripePayment(config('services.stripe.secret'));
});
}
// app/Providers/PayPalServiceProvider.php
public function register()
{
$this->app->bind(PaymentGatewayInterface::class, function ($app) {
return new PayPalPayment(config('services.paypal.client_id'), config('services.paypal.secret'));
});
}
Update config/app.php:
The choice between these providers is typically made in the config/app.php file or through environment variables. You would enable one provider and comment out or remove the other:
'providers' => [
// ...
App\Providers\StripeServiceProvider::class,
// App\Providers\PayPalServiceProvider::class,
],
Use in controller:
class PaymentController extends Controller
{
private $paymentProcessor;
public function __construct(PaymentProcessor $paymentProcessor)
{
$this->paymentProcessor = $paymentProcessor;
}
public function processPayment(Request $request)
{
$paymentDetails = $request->validated();
$result = $this->paymentProcessor->pay($paymentDetails);
return $result ? response()->json(['status' => 'success']) : response()->json(['status' => 'failure'], 400);
}
}
This implementation allows easy switching between payment gateways and the addition of new gateways without modifying existing code.
The payment method is sent from the front end as 'payment_method'.
The controller retrieves this value using $request->input('payment_method').
// In your controller
public function processPayment(Request $request)
{
$gatewayName = $request->input('payment_method');
$paymentDetails = $request->input('payment_details');
try {
$gateway = PaymentGatewayFactory::create($gatewayName);
$result = $gateway->processPayment($paymentDetails);
// Handle successful payment
} catch (\Exception $e) {
// Handle errors
}
}
The PaymentGatewayFactory creates the appropriate gateway object based on the payment method.
// PaymentGatewayFactory.php
class PaymentGatewayFactory
{
public static function create($gatewayName)
{
switch ($gatewayName) {
case 'paypal':
return new PayPalGateway();
case 'stripe':
return new StripeGateway();
default:
throw new \Exception("Unsupported gateway");
}
}
}
The controller then uses this gateway object to process the payment.
This approach allows you to easily add new payment gateways by creating new classes that implement the PaymentGatewayInterface and adding them to the factory method.