PHP code example of gardi / dcb-kit

1. Go to this page and download the library: Download gardi/dcb-kit 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/ */

    

gardi / dcb-kit example snippets


use Gardi\DcbKit\Contracts\CarrierGateway;
use Gardi\DcbKit\Callbacks\{CallbackEvent, CallbackType};
use Gardi\DcbKit\Results\{ChargeResult, SubscriptionResult};
use Gardi\DcbKit\{Money, Support\Signature};

final class AcmeTelecom implements CarrierGateway
{
    public function __construct(private string $apiKey, private string $secret) {}

    public function name(): string { return 'acme'; }

    public function subscribe(string $msisdn, string $plan): SubscriptionResult { /* call carrier */ }

    public function charge(string $msisdn, Money $amount, string $reference): ChargeResult { /* ... */ }

    public function unsubscribe(string $msisdn, string $subscriptionId): void { /* ... */ }

    public function parseCallback(array $payload): CallbackEvent
    {
        $type = match ($payload['event']) {
            'SUB_OK'  => CallbackType::Subscribed,
            'BILL_OK' => CallbackType::Charged,
            'NO_FUND' => CallbackType::InsufficientBalance,
            default   => CallbackType::Unknown,
        };

        return new CallbackEvent($type, $payload['msisdn'], raw: $payload);
    }

    public function verifyCallback(string $rawBody, string $signature): bool
    {
        return Signature::verify($rawBody, $signature, $this->secret);
    }
}

use Gardi\DcbKit\{HttpCarrierGateway, CallbackUrl};
use Gardi\DcbKit\Callbacks\{StatusMap, CallbackType};
use Gardi\DcbKit\Contracts\Transport;
use Gardi\DcbKit\Auth\BearerAuth;
use Gardi\DcbKit\Verification\HmacVerifier;

// 1. The HTTP seam — wrap whatever client you use (Guzzle, Laravel Http, curl).
final class GuzzleTransport implements Transport
{
    public function request(string $method, string $url, array $payload, array $headers = []): array
    {
        // ...send it (with $headers) and return the decoded JSON response as an array
    }
}

// 2. Configure the carrier — no subclass needed.
$carriers->extend('acme', fn () => new HttpCarrierGateway(
    name: 'acme',
    baseUrl: $config['acme']['base_url'],            // <- your base URL
    transport: new GuzzleTransport(),
    statusMap: StatusMap::make([                      // <- this carrier's status codes
        'ACTIVATION' => CallbackType::Subscribed,
        'RENEWAL'    => CallbackType::Renewed,
        'BILL_OK'    => CallbackType::Charged,
        'NO_FUNDS'   => CallbackType::InsufficientBalance,
        'CANCEL'     => CallbackType::Unsubscribed,
    ]),
    verifier: new HmacVerifier($config['acme']['secret']), // <- how callbacks are signed
    auth: new BearerAuth($config['acme']['token']),        // <- how requests authenticate
    callbackUrl: CallbackUrl::for($config['webhook_base'], 'acme'),
    statusField: 'event',                             // <- which payload key holds the status
    msisdnField: 'phone',
    transactionIdField: 'data.txn.id',                // <- dot paths work for nested responses
));

use Gardi\DcbKit\CarrierManager;

$carriers = CarrierManager::fromArray([
    'acme' => [
        'base_url'  => 'https://api.acme.test',
        'auth'      => ['type' => 'bearer', 'token' => $config['acme']['token']],
        'verifier'  => ['type' => 'hmac', 'secret' => $config['acme']['secret']],
        'statuses'  => [
            'ACTIVATION' => 'subscribed',
            'BILL_OK'    => 'charged',
            'NO_FUNDS'   => 'insufficient_balance',
            'CANCEL'     => 'unsubscribed',
        ],
        'status_field'         => 'event',
        'msisdn_field'         => 'phone',
        'transaction_id_field' => 'data.txn.id',
    ],
    // 'mtn' => [ ... ], 'zain' => [ ... ]
], new GuzzleTransport());

$carriers->gateway('acme')->charge(/* ... */);

use Gardi\DcbKit\{CarrierManager, Money};

$carriers = new CarrierManager();
$carriers->extend('acme', fn () => new AcmeTelecom($apiKey, $secret)); // lazy

$gateway = $carriers->gateway('acme');

// $reference is your idempotency key — never charge the same one twice.
$result = $gateway->charge('9647501234567', Money::of(500, 'IQD'), 'order-42');

// In your webhook controller — verify the RAW body, then parse the decoded array:
if ($gateway->verifyCallback($rawBody, $signature)) {
    $event = $gateway->parseCallback($payload);   // $payload = json_decode($rawBody, true)
    if ($event->isSuccessful()) {
        // mark the subscription/charge as confirmed
    }
}

use Gardi\DcbKit\Transport\RetryingTransport;

$transport = new RetryingTransport(
    new GuzzleTransport(),
    maxAttempts: 3,
    baseDelayMs: 100,         // 100ms, then 200ms, then 400ms ... (exponential)
    retryOn: fn (\Throwable $e) => $e instanceof MyTimeoutException,  // optional: scope it
);

use Gardi\DcbKit\Idempotency\IdempotentGateway;

$gateway = new IdempotentGateway($carriers->gateway('acme'), new RedisIdempotencyStore());
$gateway->charge('9647501234567', Money::of(500, 'IQD'), 'order-42');  // safe to repeat

use Gardi\DcbKit\Webhooks\WebhookHandler;
use Gardi\DcbKit\Exceptions\InvalidCallbackSignatureException;

$handler = new WebhookHandler($carriers);

try {
    $event = $handler->handle($carrier, $request->getContent(), $request->header('X-Signature'));
    // ... act on $event, then 200
} catch (InvalidCallbackSignatureException) {
    // 403 — spoofed or misconfigured
}