nedarta/yii2-omnipay

An elegant Omnipay payment processing extension for the Yii 2 framework.

Maintainers

Package info

github.com/nedarta/yii2-omnipay

Type:yii2-extension

pkg:composer/nedarta/yii2-omnipay

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-05-27 11:43 UTC

This package is auto-updated.

Last update: 2026-05-27 12:17:53 UTC


README

Latest Stable Version Total Downloads License

A premium, elegant, and lightweight payment processing integration for the Yii 2 framework, built on top of the powerful Omnipay library. Configure payment gateways as standard Yii 2 components with clean, modern magic delegation.

Features

  • One Component, One Gateway: Simple, modular architecture that integrates seamlessly into Yii 2's dependency injection container.
  • 💳 Clean Magic Delegation: Call gateway methods (like purchase, completePurchase, etc.) directly on the component.
  • 🛡️ Strict & Safe: Safe lazy-initialization guards and robust type validation to prevent runtime errors.
  • ⚙️ Immutable Config & Reinitialization: Built to support reactive changes in dynamic execution contexts (e.g. CLI, tests).
  • 🧪 Test-Driven: Structured to work seamlessly with PHPUnit.

Installation

Install the package via Composer:

composer require nedarta/yii2-omnipay

To use specific gateways, you should also require their respective Omnipay drivers:

# For Stripe
composer require omnipay/stripe

# For PayPal
composer require omnipay/paypal

Configuration

Add the gateway components directly to your application configuration file (usually config/web.php or common/config/main.php):

return [
    'components' => [
        'stripe' => [
            'class' => 'nedarta\omnipay\OmniPayComponent',
            'gateway' => 'Stripe',
            'parameters' => [
                'apiKey' => 'sk_test_51Px...your_stripe_secret_key...',
            ],
        ],
        'paypal' => [
            'class' => 'nedarta\omnipay\OmniPayComponent',
            'gateway' => 'PayPal_Express',
            'parameters' => [
                'username' => 'paypal-developer_api1.example.com',
                'password' => 'ABC123XYZ456',
                'signature' => 'AFcWxV21C7fd0xs3bSMuz153.4VeA1F-34zQv1F.c7',
            ],
            'testMode' => true, // Optional global shortcut
        ],
    ],
];

Usage Examples

1. Stripe Checkout

Because of magic-method delegation, you can call all underlying gateway methods directly on the Yii 2 component (Yii::$app->stripe).

namespace app\controllers;

use Yii;
use yii\web\Controller;
use yii\web\BadRequestHttpException;

class PaymentController extends Controller
{
    /**
     * Process a direct credit card charge via Stripe
     */
    public function actionStripeCharge()
    {
        $request = Yii::$app->request;
        
        // Stripe token generated on the frontend by Stripe.js Elements
        $token = $request->post('stripeToken');
        $amount = 29.99; // Amount in USD
        
        if (!$token) {
            throw new BadRequestHttpException('Missing stripe payment token.');
        }

        try {
            // Direct call to Stripe gateway purchase() via magic method delegation
            $response = Yii::$app->stripe->purchase([
                'amount' => $amount,
                'currency' => 'USD',
                'token' => $token,
                'description' => 'Order #1042 Payment',
            ])->send();

            if ($response->isSuccessful()) {
                $transactionReference = $response->getTransactionReference();
                Yii::$app->session->setFlash('success', "Payment successful! Ref: {$transactionReference}");
                return $this->redirect(['site/success']);
            } elseif ($response->isRedirect()) {
                // Redirect to 3D Secure / off-site authentication if required
                return $response->redirect();
            } else {
                $errorMessage = $response->getMessage();
                Yii::$app->session->setFlash('error', "Payment failed: {$errorMessage}");
            }
        } catch (\Exception $e) {
            Yii::$app->session->setFlash('error', "An error occurred: " . $e->getMessage());
        }

        return $this->redirect(['site/checkout']);
    }
}

2. PayPal Express Checkout Workflow

PayPal Express requires a redirection to PayPal's checkout page and a secondary step to capture the payment on return.

Step A: Initiate the PayPal Purchase

namespace app\controllers;

use Yii;
use yii\web\Controller;
use yii\helpers\Url;

class PaypalController extends Controller
{
    /**
     * Start the PayPal Express Checkout flow
     */
    public function actionCheckout()
    {
        $amount = 99.00;

        try {
            // Direct call to purchase() via magic method delegation on the paypal component
            $response = Yii::$app->paypal->purchase([
                'amount' => $amount,
                'currency' => 'USD',
                'description' => 'Premium Subscription - Annual Plan',
                'returnUrl' => Url::to(['paypal/success'], true),
                'cancelUrl' => Url::to(['paypal/cancel'], true),
            ])->send();

            if ($response->isRedirect()) {
                // Redirect to PayPal checkout page
                return $response->redirect();
            } else {
                Yii::$app->session->setFlash('error', $response->getMessage());
            }
        } catch (\Exception $e) {
            Yii::$app->session->setFlash('error', "Could not initiate payment: " . $e->getMessage());
        }

        return $this->redirect(['site/checkout']);
    }
}

Step B: Capture and Complete the Purchase

    /**
     * Complete the PayPal payment after successful return
     */
    public function actionSuccess()
    {
        $request = Yii::$app->request;
        
        $token = $request->get('token');
        $payerId = $request->get('PayerID');

        try {
            // Direct call to completePurchase() via magic method delegation
            $response = Yii::$app->paypal->completePurchase([
                'amount' => 99.00,
                'currency' => 'USD',
                'transactionReference' => $token,
                'payerId' => $payerId,
            ])->send();

            if ($response->isSuccessful()) {
                $data = $response->getData();
                $transactionId = $data['PAYMENTINFO_0_TRANSACTIONID'] ?? 'Unknown';

                Yii::$app->session->setFlash('success', "PayPal payment completed successfully! Transaction ID: {$transactionId}");
                return $this->redirect(['site/success']);
            } else {
                Yii::$app->session->setFlash('error', "Transaction completion failed: " . $response->getMessage());
            }
        } catch (\Exception $e) {
            Yii::$app->session->setFlash('error', "An error occurred during verification: " . $e->getMessage());
        }

        return $this->redirect(['site/checkout']);
    }

    /**
     * Handle user cancellation
     */
    public function actionCancel()
    {
        Yii::$app->session->setFlash('info', 'You have cancelled the PayPal payment checkout process.');
        return $this->redirect(['site/checkout']);
    }

Advanced Usage: Dynamic Reinitialization

In multi-tenant setups, SaaS environments, or instances where merchant credentials must be loaded dynamically from a database at runtime, you can reconfigure components on the fly.

1. Update Parameters Dynamically

To update configuration parameters for the current gateway:

Yii::$app->stripe->setParameters([
    'apiKey' => 'sk_test_dynamic_merchant_key...',
]);

2. Complete Gateway Rebuilding

To reconfigure the entire component dynamically (e.g., swapping gateway drivers, updating test mode flags, and resetting parameters all at once):

Yii::$app->stripe->reinitialize([
    'gateway' => 'PayPal_Express',
    'testMode' => true,
    'parameters' => [
        'username' => 'merchant-dynamic_api1.example.com',
        'password' => 'SECRET_PWD_123',
        'signature' => 'SIG_XYZ...',
    ],
]);

Note

The reinitialize() method uses strict safety validation. Attempting to assign unknown or read-only properties will throw a yii\base\InvalidConfigException immediately to prevent silent typos or configuration bugs in production.

Webhooks & CSRF Validation

When integrating payment gateways, they will send asynchronous payment update notifications via webhooks (e.g. Stripe webhooks or PayPal IPN notifications) as standard HTTP POST requests.

By default, Yii 2 validates CSRF tokens on all POST requests, which will block incoming gateway webhooks with an HTTP 400 Bad Request error. To resolve this, disable CSRF validation for your webhook action inside your payment controller:

namespace app\controllers;

use Yii;
use yii\web\Controller;

class WebhookController extends Controller
{
    /**
     * @inheritdoc
     */
    public function beforeAction($action)
    {
        if ($action->id === 'stripe-webhook' || $action->id === 'paypal-ipn') {
            $this->enableCsrfValidation = false;
        }

        return parent::beforeAction($action);
    }

    public function actionStripeWebhook()
    {
        // Process Stripe webhook signature and handle notification
    }
}

Running Tests

This library includes automated unit tests written in PHPUnit. To run tests, use the following command:

composer test

Tests are located in the /tests/ directory.

License

This project is licensed under the MIT License - see the LICENCE.md file for details.

Developed with ❤️ by Edgars Karlsons.