PHP code example of ceibacore / ceiba-ase

1. Go to this page and download the library: Download ceibacore/ceiba-ase library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

ceibacore / ceiba-ase example snippets


use CeibaAse\AseManager;

// Register Stripe
AseManager::registerGateway('stripe', [
    'publishable_key'  => 'pk_live_...',  // For client-side checkout
    'secret_key'       => 'sk_live_...',  // For server-side API
    'webhook_secret'   => 'whsec_...',    // For webhook validation
    'test_mode'        => false
]);

// Register PayPal
AseManager::registerGateway('paypal', [
    'client_id'     => 'xxx',
    'client_secret' => 'yyy',
    'webhook_id'    => 'zzz',
    'sandbox'       => false
]);

// Create plan
$plan = AseManager::createPlan('pro', 'Professional Plan', 'Full features', true);

// Add price: $99.99 per month with 7-day trial
$price = AseManager::createPlanPrice(
    $plan['id'],
    'recurring',          // or 'one_time'
    99.99,
    'USD',
    'month',              // interval: day|month|quarter|year
    1,                    // interval count
    7                     // trial days
);

// List available gateways
$gateways = AseManager::getEnabledGateways();
// Returns: [
//   ['id' => 'gw1', 'provider' => 'stripe'],
//   ['id' => 'gw2', 'provider' => 'paypal']
// ]

// User selects a gateway
$selectedGatewayId = $gateways[0]['id'];

// Create checkout
$checkoutUrl = AseManager::createCheckoutSession(
    $clientId,
    $priceId,
    $selectedGatewayId,
    'https://your-domain.com/success?session_id={CHECKOUT_SESSION_ID}', // {CHECKOUT_SESSION_ID} is supported by Stripe
    'https://your-domain.com/cancel'
);

// Redirect user
header("Location: $checkoutUrl");

// Stripe webhook endpoint
Route::post('/ase/webhooks/stripe/{gatewayId}', function($gatewayId) {
    $rawBody = file_get_contents('php://input');
    $headers = getallheaders();
    
    AseManager::handleWebhook($gatewayId, $rawBody, $headers);
    
    return response('OK', 200);
});

// ASE handles:
// ✅ Signature validation (HMAC-SHA256)
// ✅ Event parsing & normalization
// ✅ Subscription creation
// ✅ Invoice generation
// ✅ Idempotency checking

use CeibaAse\AseManager;

// Grant course access when a subscription starts or renews
AseManager::listen('subscription.created', function($subscription) {
    MyLmsAccessService::grant($subscription->externalClientId());
});

// Revoke access when canceled or unpaid
AseManager::listen('subscription.canceled', function($subscription) {
    MyLmsAccessService::revoke($subscription->externalClientId());
});

// Sync invoices with accounting software
AseManager::listen('invoice.paid', function($invoice) {
    AccountingApi::syncInvoice($invoice);
});

// Get all ENABLED gateways (active payment methods)
$gateways = AseManager::getEnabledGateways();
// Returns: [['id' => 'uuid1', 'provider' => 'stripe'], ...]

// Get ALL gateways (including disabled)
$all = AseManager::getAllGateways();
// Returns: [['id' => 'uuid1', 'provider' => 'stripe', 'is_active' => true], ...]

// Get specific gateway by ID
$gateway = AseManager::getGatewayById($gatewayId);
// Returns: ['id' => '...', 'provider' => '...', 'is_active' => true] or null

// Get first enabled gateway of a provider type
$stripe = AseManager::getGatewayByProvider('stripe');
// Returns: ['id' => '...', 'provider' => 'stripe'] or null

// Create plan
$plan = AseManager::createPlan('pro', 'Pro Plan', 'Full features', true);
// Returns: ['id', 'slug', 'name', 'description', 'is_active']

// Update plan
$updated = AseManager::updatePlan($planId, 'Pro Plan v2', null, true);

// Add price to plan
$price = AseManager::createPlanPrice(
    $planId,
    'recurring',      // 'one_time' or 'recurring'
    99.99,
    'USD',
    'month',          // day|month|quarter|year
    1,                // interval count (e.g., every 3 months)
    7                 // trial days
);

// Register payment gateway
$gateway = AseManager::registerGateway('stripe', [
    'publishable_key'  => '...',
    'secret_key'       => '...',
    'webhook_secret'   => '...',
    'test_mode'        => false
]);

// Create checkout session (client-side)
$checkoutUrl = AseManager::createCheckoutSession(
    $clientId,
    $planPriceId,
    $gatewayId  // from getEnabledGateways()
);

// Get active subscription
$sub = AseManager::getClientActiveSubscription($clientId);
// Returns: ['id', 'status', 'current_period_end', 'external_subscription_id', ...]

// Check access (

// Handle incoming webhook (Stripe/PayPal)
AseManager::handleWebhook(
    $gatewayId,
    file_get_contents('php://input'),  // raw body (for signature validation)
    getallheaders()                     // HTTP headers
);

// ASE automatically:
// ✅ Validates webhook signature (HMAC-SHA256 or RSA-SHA256)
// ✅ Prevents replay attacks (5-minute window)
// ✅ Parses event & normalizes across gateway differences
// ✅ Creates subscription with trial status if applicable
// ✅ Handles state transitions (trialing → active)
// ✅ Processes refunds & updates subscription status

// Admin initiates refund
$refund = AseManager::issueRefund(
    $transactionId,
    $refundAmount,
    'Customer requested cancellation'
);
// Returns: ['status' => 'success'|'failed', 'refund_id' => '...', 'error' => ?string]

// Webhook processes gateway refund confirmation
// ASE automatically updates:
// ├── ase_transactions_log (status: 'refunded')
// ├── ase_subscriptions (status: 'canceled' if full refund)
// └── ase_invoices (status: 'refunded')

// Gateway credentials stored as encrypted JSON in ase_gateways table
$credentials = [
    'publishable_key'  => '...', // Visible to frontend for checkout
    'secret_key'       => '...', // Server-only, never leaked
    'webhook_secret'   => '...', // Encrypted at rest
    'test_mode'        => false
];

// Extracted via GatewayRepository::findById()
// Never logged or exposed in error messages

// Invoice created during trial has:
$invoice = [
    'amount'  => 0,        // No charge during trial
    'status'  => 'draft',  // Not yet issued
    'reason'  => 'trial'
];

// After trial ends or first renewal:
// → amount is populated with plan price
// → status changes to 'pending' or 'paid'

// Monthly billing
BillingPeriodCalculator::calculate($planPrice, $now)
// Returns: $now.modify('+1 month')

// Quarterly (every 3 months)
$planPrice->interval = 'month';
$planPrice->intervalCount = 3;

// Yearly
$planPrice->interval = 'year';
$planPrice->intervalCount = 1;

// Daily
$planPrice->interval = 'day';
$planPrice->intervalCount = 30;  // Every 30 days

// Handles:
// ✅ Leap years
// ✅ DST transitions
// ✅ Month-end edge cases (Feb 29 → March 1)

// migrations/php/20260505000000_add_payment_method_column.php

use CeibaAse\Migration\AseBaseMigration;
use CeibaAse\Migration\AseSchemaBuilder;

class Migration_20260505000000_AddPaymentMethodColumn extends AseBaseMigration
{
    public const VERSION = '20260505000000';
    public const DESCRIPTION = 'add_payment_method_column';

    public function up(): void
    {
        AseSchemaBuilder::alterTable('ase_subscriptions', function($table) {
            $table->addColumn('payment_method', 'string', 50)->after('status');
        });
    }

    public function down(): void
    {
        AseSchemaBuilder::alterTable('ase_subscriptions', function($table) {
            $table->dropColumn('payment_method');
        });
    }
}

class PostgreSQLDialect implements AseDialectInterface
{
    public function jsonType(): string { /* return 'JSONB'; */ }
    public function booleanType(): string { /* return 'BOOLEAN'; */ }
    public function autoIncrementPk(): string { /* return 'BIGSERIAL PRIMARY KEY'; */ }
    // ... (10 more methods)
}

// In your service provider
use CeibaAse\Ase;

class AseServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // Initialize ASE with Laravel's DB connection
        Ase::boot([
            'db' => [
                'driver'   => 'mysql',
                'host'     => config('database.connections.mysql.host'),
                'database' => config('database.connections.mysql.database'),
                'username' => config('database.connections.mysql.username'),
                'password' => config('database.connections.mysql.password'),
            ]
        ]);
    }
}

// In your service
use CeibaAse\Ase;

class SubscriptionService
{
    public function __construct(private Connection $db)
    {
        Ase::boot([
            'db' => [
                'pdo' => $this->db->getWrappedConnection()
            ]
        ]);
    }
}

// In your plugin bootstrap
use CeibaAse\Ase;

add_action('plugins_loaded', function() {
    global $wpdb;
    
    Ase::boot([
        'db' => [
            'pdo' => $wpdb->dbh // Use WordPress DB connection
        ]
    ]);
});

// Verify gateway is registered and enabled
$gateways = AseManager::getEnabledGateways();
if (empty($gateways)) {
    echo "ERROR: No enabled gateways. Register one first.";
}

// Verify webhook secret matches
// Ensure raw body (not parsed JSON) is passed to handleWebhook()
$rawBody = file_get_contents('php://input');
// NOT: $rawBody = json_encode($_POST);

$plan = AseManager::createPlan(
    'enterprise',
    'Enterprise Plan',
    'Full-featured plan for large orgs',
    true,
    [
        'is_recommended' => true,
        'billing_type'   => 'annual',
        'max_users'      => 500,
        'support_level'  => 'premium',
        'features'       => ['api', 'webhooks', 'sso', 'advanced_reporting'],
        'custom_sla'     => '99.95%'
    ]
);

// Returns:
// [
//     'id'          => 'uuid',
//     'slug'        => 'enterprise',
//     'name'        => 'Enterprise Plan',
//     'description' => '...',
//     'is_active'   => true,
//     'metadata'    => ['is_recommended' => true, ...]
// ]

// After retrieving a plan via repository
$planRepo = new CeibaPlanRepository();
$plan = $planRepo->findBySlug('enterprise');

// Get entire metadata
$meta = $plan->metadata();

// Get specific attribute with optional default
$maxUsers = $plan->getMetadata('max_users', 10);  // defaults to 10 if not set
$isRecommended = $plan->getMetadata('is_recommended', false);

// Check if key exists (null values return false)
if ($plan->hasMetadata('features')) {
    $features = $plan->getMetadata('features');
}

// MySQL: Get all recommended plans
$db = CeibaInstance::get();
$recommended = $db->query('ase_plans')
    ->where([
        'is_active' => 1
    ])
    ->get();

// Filter in PHP (CeibaDB does not support JSON_EXTRACT in WHERE yet)
$recommended = array_filter($recommended, function($row) {
    $metadata = json_decode($row['metadata'] ?? '{}', true);
    return $metadata['is_recommended'] ?? false;
});
bash
cd ceiba-ase
php bin/ase-migrate migrate
bash
GATEWAY_ENCRYPTION_KEY=        # 32-byte base64 key (generate: php -r "echo base64_encode(random_bytes(32));")
GATEWAY_CSRF_SECRET=            # HMAC secret (falls back to GATEWAY_SERVICE_SECRET)
bash
# Applied automatically during schema setup
php bin/ase-migrate migrate

# You can verify it exists:
php bin/ase-migrate status