PHPackages                             fahara02/udb-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. fahara02/udb-laravel

ActiveLibrary[API Development](/categories/api)

fahara02/udb-laravel
====================

Laravel SDK for UDB (Universal Data Broker) — gRPC client, ServiceProvider, Facade, request-context middleware, and tenant-aware request injection.

v0.4.0(2w ago)00MITPHPPHP ^8.1

Since May 31Pushed 1w agoCompare

[ Source](https://github.com/fahara02/udb-laravel)[ Packagist](https://packagist.org/packages/fahara02/udb-laravel)[ Docs](https://github.com/fahara02/udb)[ RSS](/packages/fahara02-udb-laravel/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (40)Versions (12)Used By (0)

UDB Laravel SDK
===============

[](#udb-laravel-sdk)

 [![UDB logo](../../docs/assets/udb_logo.svg)](../../docs/assets/udb_logo.svg)

 **UDB :: Universal Data Broker**
 gRPC data plane | native control plane | tenant/project scope guard
crate v0.4.13 | protocol v1.0.0

[![Packagist](https://camo.githubusercontent.com/412a6292fad9312dfcf053e002062796bbb1be2efcea87d999c804e5bd543cb7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f66616861726130322f7564622d6c61726176656c2e737667)](https://packagist.org/packages/fahara02/udb-laravel)[![PHP Version](https://camo.githubusercontent.com/acffb6ae1962992d26e4466782832787e79504a6250f80d732c4283458b9f497/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e312d626c75652e737667)](https://www.php.net/)[![Laravel](https://camo.githubusercontent.com/2e8f7955348c3ea73a4d31c15311535852a8092d070a9fcb38a6aaf1c15efc54/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d3130253230253743253230313125323025374325323031322d7265642e737667)](https://laravel.com/)

Laravel client for [UDB](https://github.com/fahara02/udb), a service that lets your app read and write data through one broker instead of connecting directly to every database or storage backend.

Install this package when a Laravel app needs to call a running UDB broker. It gives you a Laravel `ServiceProvider`, a `Udb` facade, generated PHP protobuf classes, request middleware, and clear exceptions for gRPC errors.

---

What is UDB?
------------

[](#what-is-udb)

UDB stands for Universal Data Broker. Think of it as a data API that sits between your Laravel app and the systems where the data actually lives.

A Laravel app sends a request such as "select patients", "upsert this invoice", or "delete this object". UDB decides where that data lives, applies the broker rules, talks to the right backend, and returns a typed response.

That means the Laravel app does not need to know whether the data is in Postgres, MySQL, SQLite, MongoDB, S3, Redis, Qdrant, or another supported backend. The app only needs the UDB endpoint and the request it wants to send.

What This Package Does
----------------------

[](#what-this-package-does)

This package makes UDB feel natural inside Laravel:

- `composer require fahara02/udb-laravel:^0.4.13`
- set `UDB_ENDPOINT` in `.env`
- call `Udb::select()`, `Udb::upsert()`, or `Udb::delete()`
- use typed generated PHP classes for requests and responses
- let middleware attach tenant, user, and correlation context automatically
- catch Laravel-friendly exceptions instead of handling raw gRPC status arrays everywhere

---

Requirements
------------

[](#requirements)

- **PHP 8.1+**
- **`grpc` PECL extension** — `pecl install grpc` then add `extension=grpc.so` to `php.ini`. The generated stubs extend `\Grpc\BaseStub`; there is no fallback transport.
- **Laravel 10, 11, or 12** (Illuminate Container + HTTP + Routing)
- A running UDB broker reachable from the app

---

Installation
------------

[](#installation)

```
composer require fahara02/udb-laravel:^0.4.13
```

The service provider is auto-discovered by Laravel. The `Udb` facade is registered automatically. By default, the package also adds middleware to the `web` and `api` route groups so each request can carry tenant and user context into UDB.

The package also installs a version-matched CLI launcher at `vendor/bin/udb`. Use it from your Laravel project when you need UDB's shared annotation protos:

```
vendor/bin/udb proto export --fmt
```

After that, your app-owned `.proto` files can import:

```
import "udb/core/common/v1/db.proto";
```

Run `vendor/bin/udb proto fmt` after export or schema edits to keep long UDB field annotations on one line for easier review.

Publish the config file when you need to override defaults:

```
php artisan vendor:publish --tag=udb-config
```

This drops a documented `config/udb.php` into your app.

---

Configuration
-------------

[](#configuration)

For local development, the only required value is usually:

```
UDB_ENDPOINT=127.0.0.1:50051
```

For production, you will normally set TLS, service identity, project, and timeout values too:

```
UDB_ENDPOINT=udb.prod.svc.cluster.local:50051

# TLS
UDB_TLS_ENABLED=true
UDB_TLS_ROOT_CERTS=/etc/ssl/certs/udb-ca.pem
UDB_TLS_TARGET=udb.prod.svc.cluster.local

# Static metadata (per-request values come from middleware)
UDB_SERVICE_IDENTITY=acme.api
UDB_PROJECT_ID=acme
UDB_DEFAULT_PURPOSE=web.request
UDB_DEFAULT_SCOPES=udb:read,udb:write
UDB_CLIENT_CATALOG_VERSION=1.0.0

# Timeouts / channel tuning
UDB_DEADLINE_MS=30000
UDB_GRPC_KEEPALIVE_MS=30000
UDB_GRPC_MAX_RECV_BYTES=16777216

# Middleware
UDB_MIDDLEWARE_AUTO=true
```

The full reference lives in [`config/udb.php`](config/udb.php).

`UDB_ENDPOINT` accepts either a `host:port` value or a **Unix-domain-socket**target (`unix:///var/run/udb.sock`) for a co-located broker sidecar — see [Performance](#performance) below.

---

Performance
-----------

[](#performance)

PHP-FPM is **shared-nothing**: it tears down the worker after every request, so a normal PHP UDB client opens a **new gRPC channel per request** and re-pays the TCP + TLS + HTTP/2 handshake every time ([grpc#15426](https://github.com/grpc/grpc/issues/15426)). That re-handshake is the dominant PHP latency against a gRPC broker.

The fix is to hold a **warm channel** in a persistent-worker runtime (OpenSwoole / RoadRunner / FrankenPHP) that builds the client **once** and reuses it across requests, and/or to run a **local UDB sidecar** reached over a Unix domain socket. See:

- **Guide:** [`docs/php-perf.md`](../../docs/php-perf.md) — why PHP-FPM can't pool a channel, per-runtime setup recipes, keepalive args, and the local sidecar / UDS pattern (incl. the required broker-side UDS bind, a maintainer follow-up).
- **Runnable example:** [`examples/persistent-worker/`](examples/persistent-worker/)— a worker that constructs the client once and serves requests on the warm channel (OpenSwoole + RoadRunner + a plain-CLI fallback).

Worker keepalive env (set these for a persistent-worker deployment so the warm channel isn't dropped to IDLE and re-handshaked):

```
UDB_GRPC_KEEPALIVE_MS=30000
UDB_GRPC_KEEPALIVE_TIMEOUT_MS=10000
# co-located sidecar over a Unix domain socket (needs the broker to bind it):
UDB_ENDPOINT=unix:///var/run/udb.sock
```

---

Usage
-----

[](#usage)

### Read Data

[](#read-data)

```
use Udb\Entity\V1\SelectRequest;
use Fahara02\UdbLaravel\Facades\Udb;

$req = (new SelectRequest())
    ->setMessageType('acme.healthcare.v1.Patient')
    ->setLimit(50);

$records = Udb::select($req);

foreach ($records->getRecords() as $record) {
    // $record is a typed protobuf object.
}
```

If the call happens during an HTTP request, the middleware will try to attach the current tenant, user, and correlation ID automatically.

### Write Data

[](#write-data)

```
use Udb\Entity\V1\UpsertRequest;
use Fahara02\UdbLaravel\Facades\Udb;

$response = Udb::upsert($upsertRequest);
```

`upsert()` returns a `MutationResponse`.

### Delete Data

[](#delete-data)

```
use Udb\Entity\V1\DeleteRequest;
use Fahara02\UdbLaravel\Facades\Udb;

$response = Udb::delete($deleteRequest);
```

`delete()` also returns a `MutationResponse`.

### Idempotency Replay And Read-Your-Writes

[](#idempotency-replay-and-read-your-writes)

A keyed replay-safe mutation the broker deduplicated reports `was_duplicate`; the write receipt on the response fences a follow-up read (full contract: [docs/native-services.md](../../docs/native-services.md)).

```
use Fahara02\UdbLaravel\UdbMetadata;
use Fahara02\UdbLaravel\WriteReceipt;
use function Fahara02\UdbLaravel\wasReplay;

$response = Udb::upsert($upsertRequest); // request carries an idempotency_key

if (wasReplay($response)) {
    // durable-idempotency replay — no new side effect occurred
}

// Read-your-writes: fence the next read on the write's receipt.
$receipt = WriteReceipt::fromJson($response->getWriteReceiptJson());
$meta = UdbMetadata::fromContext(/* ... */)->afterWrite($receipt);
```

Retry contract: a replay-safe mutation is retried on transient errors **only when the request carries a non-empty idempotency key** — keyless mutations fail closed rather than risk a double apply.

### Queue Jobs And Scheduled Commands

[](#queue-jobs-and-scheduled-commands)

Jobs, commands, and schedulers do not have an HTTP request, so pass metadata explicitly:

```
use Fahara02\UdbLaravel\UdbMetadata;

$meta = UdbMetadata::fromContext(
    tenantId: 'acme',
    userId: 'system',
    correlationId: 'nightly-billing-' . now()->timestamp,
    purpose: 'scheduled.billing',
    scopes: ['udb:read', 'udb:billing'],
);

$response = Udb::upsert($req, $meta);
```

### Storage (upload &amp; download)

[](#storage-upload--download)

The framework-agnostic `UdbProject` exposes a `storage()` facade over the generated `StorageService`. Build it with `createUdb()` (or `UdbProject::connect()`), then use the convenience wrappers:

```
use function Fahara02\UdbLaravel\createUdb;

$udb = createUdb([
    'target'    => '127.0.0.1:50051',
    'tenantId'  => 't_acme',
    'projectId' => 'default',
    'purpose'   => 'web.request',
    'scopes'    => ['udb:read', 'udb:write'],
]);

$storage = $udb->storage();

// One-call upload: RegisterUpload -> presigned PUT -> FinalizeUpload.
$file = $storage->uploadFile('report.pdf', $bytes, [
    'contentType'   => 'application/pdf',
    'fileType'      => 'report',
    'referenceType' => 'invoice',
    'referenceId'   => 'inv_42',
]);
$fileId = $file->getFileId();
```

**Download — happy path (presigned URL).** `downloadFile()` emits exactly one `GetDownloadUrl` RPC and returns the typed `GetDownloadUrlResponse`; the bytes never transit the broker. Hand the URL to the client / browser:

```
$dl  = $storage->downloadFile($fileId, ['expiresInMinutes' => 15]);
$url = $dl->getDownloadUrl();
// `getDownloadUrl($fileId, $expiresInMinutes)` is the un-aliased equivalent.
```

**Download — streaming fallback (new in 0.3.6).** When the client cannot reach the object store over HTTP (no egress, corporate proxy), pull the raw bytes through the broker with the server-streaming `DownloadFile` RPC. `downloadFileBytes()` opens one server-stream and reassembles each `DownloadFileChunk.data` run in order:

```
// BLOCKING: PHP ext-grpc has no async API, so this returns only after the
// final chunk lands (or the deadline trips) and buffers the body in memory.
// Prefer the presigned URL above for large objects.
$bytes = $storage->downloadFileBytes($fileId);            // server default chunk size
$bytes = $storage->downloadFileBytes($fileId, 1 client()`. A runnable end-to-end upload-then-download script lives at [`examples/storage-download.php`](examples/storage-download.php).

### Raw gRPC Stub

[](#raw-grpc-stub)

For broker RPCs that do not have a convenience method yet, use the generated gRPC stub:

```
$stub = Udb::stub();
$call = $stub->BeginTx($request, Udb::context()->toGrpcMetadata());
[$response, $status] = $call->wait();
```

### Platform Services (Vault, Metering, Scheduler, …)

[](#platform-services-vault-metering-scheduler-)

Vault, Metering, Scheduler, Search, Webhook, Workflow, Lock, LiveQuery, Config, Backup, and Embedding have no convenience wrappers yet — reach their buf-generated stubs through the generated client's per-service accessors (`VaultServiceStub()`, `MeteringServiceStub()`, …), which share one channel, metadata, and TLS configuration:

```
use Fahara02\UdbLaravel\Generated\GeneratedClient;
use Udb\Core\Vault\Services\V1\EncryptRequest;

$gen = new GeneratedClient(config('udb'));
$stub = $gen->VaultServiceStub();
[$response, $status] = $stub->Encrypt(
    (new EncryptRequest())->setTenantId($tenant)->setKeyName('docs')->setPlaintext('secret'),
    Udb::context()->toGrpcMetadata(),
)->wait();
```

The per-RPC retry class and idempotency contract are listed in [docs/generated/udb-native-contract.json](../../docs/generated/udb-native-contract.json).

### Error handling

[](#error-handling)

```
use Fahara02\UdbLaravel\Exceptions\UdbRpcException;
use Fahara02\UdbLaravel\Exceptions\UdbConfigurationException;
use Fahara02\UdbLaravel\Exceptions\UdbException;

try {
    Udb::select($req);
} catch (UdbRpcException $e) {
    // UDB returned a gRPC error. $e->status holds the \Grpc\STATUS_* code.
    if ($e->status === \Grpc\STATUS_NOT_FOUND) { /* ... */ }
} catch (UdbConfigurationException $e) {
    // Missing endpoint, invalid TLS config, or similar app setup problem.
} catch (UdbException $e) {
    // Base exception for this package.
}
```

---

Per-request context
-------------------

[](#per-request-context)

The shipped `UdbContextMiddleware` resolves three values from each incoming HTTP request and binds them to the singleton client so subsequent RPC calls inherit them:

ValueDefault resolverHeader fallback`tenant_id``$request->user()->tenant_id``X-Tenant-Id``user_id``$request->user()->getAuthIdentifier()``X-User-Id``correlation_id``X-Correlation-Id` headerfreshly generated v4 UUIDOverride the resolvers by binding the same container keys in your `AppServiceProvider`:

```
$this->app->bind('udb.tenant_resolver', function () {
    return function (Request $request): ?string {
        return $request->attributes->get('resolved_tenant_id');
    };
});
```

---

Testing
-------

[](#testing)

The SDK ships with Pest tests + an Orchestra Testbench base class. For your own app's tests, swap the `UdbClient` binding for a fake:

```
use Fahara02\UdbLaravel\UdbClient;

$this->app->instance(UdbClient::class, $fakeClient = Mockery::mock(UdbClient::class));
$fakeClient->shouldReceive('select')->andReturn(new \Udb\Entity\V1\RecordSet());
```

Run the SDK's own tests:

```
composer install
composer test          # vendor/bin/pest
composer analyse       # vendor/bin/phpstan
```

---

Versioning &amp; compatibility
------------------------------

[](#versioning--compatibility)

This SDK follows the UDB wire-protocol version — see `UDB_PROTOCOL_VERSION` in the parent `sdk/` directory. Major SDK versions track major broker versions; minor SDK versions add convenience methods and Laravel-idiomatic helpers.

The current wire protocol is **1.0.0**.

---

License
-------

[](#license)

MIT © fahara02

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance98

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

11

Last Release

15d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/104659967?v=4)[faruk hannan](/maintainers/fahara02)[@fahara02](https://github.com/fahara02)

---

Top Contributors

[![fahara02](https://avatars.githubusercontent.com/u/104659967?v=4)](https://github.com/fahara02 "fahara02 (59 commits)")

---

Tags

laravelgRPCtenantmulti-tenantudbuniversal-data-brokerdata-broker

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/fahara02-udb-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/fahara02-udb-laravel/health.svg)](https://phpackages.com/packages/fahara02-udb-laravel)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M246](/packages/laravel-ai)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

813336.8k3](/packages/defstudio-telegraph)[moonshine/moonshine

Laravel administration panel

1.3k253.1k86](/packages/moonshine-moonshine)[clarifai/clarifai-php-grpc

Clarifai PHP gRPC client

1229.7k](/packages/clarifai-clarifai-php-grpc)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
