PHP code example of revenexx / app-sdk

1. Go to this page and download the library: Download revenexx/app-sdk 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/ */

    

revenexx / app-sdk example snippets



// src/main.php
declare(strict_types=1);

use Acme\MyApp\Db;
use Revenexx\AppSdk\AdapterRegistry;
use Revenexx\AppSdk\Client;
use Revenexx\AppSdk\Router\App;
use Revenexx\AppSdk\Router\Crud;
use Revenexx\AppSdk\Router\RouteContext;
use Revenexx\AppSdk\Settings;

the identity of the
    // request it serves.
    $client = new Client(AdapterRegistry::create('runtime', ['context' => $context]), Db::entities());
    // If the manifest declares events the App fires itself, pass them too:
    // new Client($adapter, Db::entities(), Db::EMIT_FN, Db::declaredEvents())
    $app = new App(['name' => 'markets', 'settings' => $settings]);

    // GET/POST /markets, GET/PUT/DELETE /markets/{id}
    Crud::mount($app, $client, $client->entity('markets'), ['path' => '/markets']);

    $app->get('/markets/defaults', static fn (RouteContext $c) => $c->json([
        'auto_publish' => $c->settings()['auto_publish'],
    ]));

    return $app->handle($context);
};

$markets = $client->entity('markets');

$client->list($markets, ['where' => ['currency' => 'EUR'], 'order' => 'code.asc', 'limit' => 20]);
$client->page($markets, ['limit' => 20, 'offset' => 40]);   // ['items', 'total', 'limit', 'offset']
$client->get($markets, $id);                                 // the row, or null
$client->create($markets, ['code' => 'de', 'currency' => 'EUR']);
$client->update($markets, $id, ['currency' => 'CHF']);
$client->remove($markets, $id);

// Compare-and-set: writes only while the row still matches, in one write.
// Answers the updated row, or null when another writer got there first.
$client->updateIf($orders, $id, ['status' => 'placing'], ['status' => 'placed']);

function reserve(Client $client, Entity $budgets, string $id, int $amount): array
{
    for ($attempt = 0; $attempt < 5; $attempt++) {
        $budget = $client->get($budgets, $id) ?? throw HttpError::notFound('no such budget');
        if ($budget['available'] < $amount) {
            throw HttpError::conflict('not enough budget left');
        }
        $next = $client->updateIf(
            $budgets,
            $id,
            ['available' => $budget['available']],              // the value the decision was based on
            ['available' => $budget['available'] - $amount],
        );
        if ($next !== null) {
            return $next;                                       // our write won
        }
    }
    throw HttpError::conflict('the budget kept changing — try again');
}

AdapterRegistry::create('mock', ['seed' => ['markets' => [['id' => 'm1', 'code' => 'de', 'currency' => 'EUR']]]]);
AdapterRegistry::create('remote', ['endpoint' => 'https://…', 'token' => '…', 'tenant' => '…']);
AdapterRegistry::create('runtime', ['context' => $context]);

$app = new App(['name' => 'markets']);
$app->get('/markets/{id}', static fn (RouteContext $c) => $c->json($client->get($markets, $c->params['id'])));
$app->post('/markets/{id}/publish', $handler);
return $app->handle($context);

$refs = new GatewayCounter();
$trash = Trash::mount($app, $client, $client->entity('organizations'), [
    'path' => '/organizations',
    'children' => [['name' => 'contacts', 'entity' => $client->entity('contacts'), 'column' => 'organization_id']],
    'guard' => fn (array $org) => $org['is_default'] ? ['reason' => 'the default organization stays'] : null,
    'blockers' => fn (array $org, mixed $c) => [
        $refs->blocker($c, ['path' => '/v1/orders/open_orders', 'where' => ['organization_id' => $org['id']], 'reason' => 'open orders']),
    ],
]);

use Revenexx\AppSdk\HttpError;

throw HttpError::notFound('no such market');                  // 404 not_found
throw HttpError::badRequest('currency is flict
throw new HttpError(409, 'no active budget', ['id' => $id], 'no_active_budget');

use Revenexx\AppSdk\Refusal;

try {
    // … call another App through the revenexx platform client …
} catch (\Throwable $e) {
    $refusal = Refusal::of($e);   // status, code, message, details, app — or null
    if ($refusal?->code === 'no_active_budget') {
        throw new HttpError(409, $refusal->message, null, 'no_budget');
    }
    throw $e;                     // not a refusal: a crash, or the other side is down
}

$settings = new Settings([
    'app' => 'orders',
    'defaults' => ['auto_reserve' => true],   // used when nothing could be resolved
]);

$client->events()->emit('stock.low', ['sku' => $sku, 'available' => 3], [
    'topicId' => $sku,
    // A deterministic id makes a retry a no-op instead of a second event.
    'id' => "evt_low_{$sku}_" . date('Ymd'),
]);

use Revenexx\AppSdk\AdapterRegistry;
use Revenexx\AppSdk\Client;
use Revenexx\AppSdk\Router\App;
use Revenexx\AppSdk\Router\Crud;

$client = new Client(AdapterRegistry::create('mock', ['seed' => ['markets' => []]]), Db::entities());
$app = new App(['name' => 'markets']);
Crud::mount($app, $client, $client->entity('markets'), ['path' => '/markets']);

$context = (object) [
    'req' => (object) [
        'method' => 'POST',
        'path' => '/markets',
        'queryString' => '',
        'query' => [],
        'headers' => ['x-revenexx-tenant' => 'acme'],
        'bodyBinary' => '{"code":"de","currency":"EUR"}',
    ],
    'res' => new class () {
        public function send(string $body, int $status = 200, array $headers = []): array
        {
            return ['body' => $body, 'statusCode' => $status, 'headers' => $headers];
        }
    },
];

$answer = $app->handle($context);   // ['body' => '{"id":"…","code":"de",…}', 'statusCode' => 201, …]

new Settings(['app' => 'markets', 'transport' => fn () => ['status' => 200, 'body' => '{"settings":{"auto_publish":true}}']]);
bash
npx @revenexx/cli apps generate --target php --out ./src --namespace 'Acme\MyApp'