Download the PHP package revenexx/app-sdk without Composer

On this page you can find all versions of the php package revenexx/app-sdk. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package app-sdk

revenexx App SDK for PHP

Packagist

Build revenexx Apps in PHP. The SDK gives an App function everything it needs to answer requests on the revenexx platform:

It is the PHP counterpart of the JavaScript SDK @revenexx/app-sdk. The two behave the same way, call for call.

Requirements

Install

How an App is put together

An App declares its data in two files, and the CLI turns them into a typed client:

File Declares
schema.json the App's entities and their columns
manifest.json what the App may do with them (read, create, update, delete), its events and its settings

This writes src/Db.php. It holds one typed repository and one row class per entity, plus Db::entities(), which lists the entities for the SDK. Regenerate it whenever schema.json or manifest.json changes; never edit it by hand.

Quick start: a function

The runtime loads your entrypoint once per process and calls the function it returns for every request.

Answer through $c->json(), not $context->res->json(). The runtime's own json() encodes every list as an object ({"0": …}). The router writes JSON itself for that reason.

The data client

Client reaches the App's records. The generated Db wraps the same calls with typed repositories ($db->markets->list(...)); Client takes an Entity and works with plain arrays.

A guard on a number gives an atomic decrement. Read, compute, write only if nobody wrote in between, and retry when the answer is null:

Two concurrent reservations cannot both spend the same amount. The second one's condition no longer holds, so it gets null, reads again and decides again.

Only the operations the manifest grants are available. Any other call fails with a 403 and the code not_permitted, naming the method.

Queries

Every read takes the same shape: where, select, order, limit, offset.

where entry Matches
['status' => 'published'] equal to the value
['locale' => ['en', 'de']] any of the values
['total' => ['op' => 'gte', 'value' => 100]] the comparison: eq neq gt gte lt lte like ilike in is
['deleted_at' => null] is null

All entries must hold. An order without a direction sorts ascending ('code' is 'code.asc').

Adapters

Adapter Use it for
mock unit tests: in-memory rows, no network, no setup
remote trying your code against a development tenant
runtime production: configured from the request the function serves

The mock fills in column defaults and generated keys. It also refuses a filter on a column the entity does not have, as the platform does. It does not imitate tenant isolation, unique constraints or foreign keys, so try your App against a development tenant once before you ship it.

The router

RouteContext gives a handler the following:

$c->params path parameters
$c->query the query string, decoded
$c->body the parsed JSON body
$c->tenant the tenant the request is for
$c->header($name) any request header
$c->actor who is acting
$c->settings() the App's settings for this request
$c->json($data, $status) the answer
$c->log($message) the function log

Routing rules:

One-line CRUD

Crud::mount mounts the five standard routes for an entity:

Route Answer
GET /markets { items, page: { limit, offset, total, returned, hasMore }, filter }
POST /markets the created row, 201
GET /markets/{id} the row, or 404
PUT /markets/{id} the updated row
DELETE /markets/{id} { deleted: true, id }

Options:

List filters. A caller filters the list by exact value: ?currency=EUR. limit, offset and order page and sort it. Anything the list cannot apply is refused with a 400, never silently ignored:

Refusal code
a key that is not a column and not declared in queryParams unknown_filter
a value carrying an operator, e.g. ?sku=in.(a,b) unsupported_filter_operator
a filter on a JSON column that is not a whole JSON document invalid_value

The trash in one call

An entity with trash: true in schema.json gets the routes a trash needs from Trash::mount, the same as mountTrash in the JavaScript SDK:

A check that throws, and a cross-app count the gateway does not answer, block.

Errors

Throw an HttpError to refuse a request. The router answers it with its status, and the caller sees only what is safe to show:

Branch on code, never on the message. A code is stable across versions; a message may be reworded. message and type repeat error and code under the names the revenexx platform client reads.

Anything else a handler throws answers 500 {"error": "internal error", "code": "internal_error"}. Its message goes to the function log and never reaches the caller.

The data client raises HttpErrors itself:

Situation Status code
an operation the manifest does not grant 403 not_permitted
an update with nothing to update 400 empty_update
updateIf without a condition 400 empty_condition
an update whose row is gone 404 not_found
a duplicate value 409 unique_violation
a referenced record that does not exist 400 foreign_key_violation
a record still referenced by others, on delete 409 foreign_key_violation
a required value missing / a check failed 400 not_null_violation / check_violation
a value in the wrong format 400 invalid_value
the data plane unavailable 500 data_error

No table, column or constraint name ever appears in an answer. The full diagnosis is on $e->serverDetail and in the function log.

Reading another App's refusal

When your App calls another App and is refused, Refusal::of() reads what it said:

Settings

$c->settings() returns the App's settings for the tenant and market of the request, resolved by the platform: a market value, else the tenant's value, else the default from your settings declaration.

Who is acting

$c->actor reads the identity the platform forwarded with the request:

user, email the person, when one is known
contact, organization the customer contact and organization the call is for
permissions, holds('orders.approve') what that person may do
trust authenticated, asserted or none
plane contact, operator or system

Check trust before enforcing a per-person rule. A contact named by a storefront server is asserted, not proven: authenticated() answers true only for a person the platform verified itself. Today the platform verifies no person itself, so treat every contact as asserted.

The App's own events

An App declares the events it fires itself in its manifest, for facts with no row behind them:

With the generated client, the same call is $db->events()->emit(…). A Client built by hand needs Db::EMIT_FN and Db::declaredEvents() passed to its constructor (see the quick start). An event the manifest does not declare is refused before anything is sent. On the mock adapter nothing is published; $client->events()->emitted() lists what the App fired, so a test can assert it.

Testing an App

Build the same routes on the mock adapter and run requests through $app->handle(), with a small stand-in for the runtime's context:

Keep the route setup in one function that both main.php and your tests call, so the tests run the routes production runs. For Settings, pass a transport callable to answer without a network:

Not included

Versioning

The SDK follows semantic versioning. The public classes and methods, the answers of the routes it mounts, and the status and code of every refusal are bound: changing any of them needs a new major version. A message may be reworded in a minor version. See CHANGELOG.md.

Working on the SDK itself

A few tests check the SDK against cases it shares with the JavaScript SDK. Those cases are not part of this package, so these tests are skipped here.

This repository is published from the SDK's main repository and is replaced on every release, so pull requests opened here cannot be merged. Report problems to revenexx.

License

MIT — see LICENSE.


All versions of app-sdk with dependencies

PHP Build Version
Package Version
Requires php Version >=8.2
ext-curl Version *
ext-json Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package revenexx/app-sdk contains the following files

Loading the files please wait ...