PHP Client
Official SDK
v0.1.0
PHP 8.0+
Getting Started
Installation
Using Composer:
composer require solidb/php-client
In composer.json:
"require": {
"solidb/php-client": "^0.1.0"
}
Requirements: PHP 8.0 or higher. The client requires either the msgpack PHP extension or the rybakit/msgpack library for binary serialization.
Quick Start
<?php
use SoliDB\Client;
// Create client instance
$client = new Client('127.0.0.1', 6745);
// Connect to server (auto-connects if not called)
$client->connect();
// Authenticate
$client->auth('_system', 'admin', 'password');
// Set database context (required for sub-clients)
$client->useDatabase('mydb');
// Basic CRUD operations
$doc = $client->insert('mydb', 'users', ['name' => 'Alice', 'age' => 30]);
echo "Created: " . $doc['_key'] . "\n";
$user = $client->get('mydb', 'users', $doc['_key']);
echo "Retrieved: " . $user['name'] . "\n";
$client->update('mydb', 'users', $doc['_key'], ['age' => 31]);
// Query with SDBQL
$results = $client->query('mydb', 'FOR u IN users FILTER u.age > @min RETURN u', ['min' => 25]);
echo "Found " . count($results) . " users\n";
// Use management sub-clients
$scripts = $client->scripts()->list();
$triggers = $client->triggers()->list();
// Clean up
$client->close();
Connection Management
// Initialize with host and port
$client = new Client('127.0.0.1', 6745);
// Connect (establishes TCP socket with binary protocol)
$client->connect();
// Check connection latency (returns ms)
$latency = $client->ping();
echo "Latency: " . round($latency, 2) . "ms\n";
// Close connection when done
$client->close();
| Method | Returns | Description |
|---|---|---|
new Client($host, $port) | Client | Create client instance |
connect() | void | Establish TCP connection |
ping() | float | Latency in milliseconds |
close() | void | Close connection |
useDatabase($name) | self | Set database context for sub-clients |
getDatabase() | ?string | Get current database context |
Authentication
// Authenticate with database, username, and password
$client->auth('_system', 'admin', 'password');
// Authentication is required for most operations
// The session remains authenticated until disconnected
// Authenticate to a specific database
$client->auth('mydb', 'myuser', 'userpassword');
Core Operations
Database Operations
// List all databases
$databases = $client->listDatabases();
// => ["_system", "mydb", "testdb"]
// Create a new database
$client->createDatabase('analytics');
// Delete a database
$client->deleteDatabase('old_db');
| Method | Returns | Description |
|---|---|---|
listDatabases() | array | List all database names |
createDatabase($name) | void | Create new database |
deleteDatabase($name) | void | Delete database |
Collection Operations
// List collections in a database
$collections = $client->listCollections('mydb');
// => [["name" => "users", "type" => "document"], ...]
// Create a document collection
$client->createCollection('mydb', 'products');
// Create an edge collection (for graphs)
$client->createCollection('mydb', 'relationships', 'edge');
// Get collection statistics
$stats = $client->collectionStats('mydb', 'users');
// => ["count" => 1523, "size" => 245760, ...]
// Delete a collection
$client->deleteCollection('mydb', 'old_collection');
| Method | Returns | Description |
|---|---|---|
listCollections($db) | array | List collections in database |
createCollection($db, $name, $type = null) | void | Create collection (type: document/edge) |
collectionStats($db, $name) | array | Get collection statistics |
deleteCollection($db, $name) | void | Delete collection |
Document Operations (CRUD)
// INSERT - Create a new document
$doc = $client->insert('mydb', 'users', [
'name' => 'Alice',
'email' => '[email protected]',
'age' => 30
]);
echo $doc['_key']; // Auto-generated key
// INSERT with custom key
$doc = $client->insert('mydb', 'users', ['name' => 'Bob'], 'custom-key-123');
// GET - Retrieve a document by key
$user = $client->get('mydb', 'users', 'custom-key-123');
// => ["_key" => "custom-key-123", "name" => "Bob", ...]
// UPDATE - Modify a document (merge by default)
$client->update('mydb', 'users', 'custom-key-123', ['age' => 25]);
// UPDATE - Replace entire document (merge = false)
$client->update('mydb', 'users', 'custom-key-123', ['name' => 'Robert'], false);
// DELETE - Remove a document
$client->delete('mydb', 'users', 'custom-key-123');
| Method | Returns | Description |
|---|---|---|
insert($db, $col, $doc, $key = null) | array | Insert document, returns doc with _key |
get($db, $col, $key) | ?array | Get document by key |
update($db, $col, $key, $doc, $merge = true) | void | Update document (merge or replace) |
delete($db, $col, $key) | void | Delete document |
SDBQL Queries
// Simple query
$users = $client->query('mydb', 'FOR u IN users RETURN u');
// Query with bind variables (recommended for security)
$results = $client->query('mydb', '
FOR u IN users
FILTER u.age >= @min_age AND u.status == @status
SORT u.created_at DESC
LIMIT @limit
RETURN { name: u.name, email: u.email }
', [
'min_age' => 18,
'status' => 'active',
'limit' => 100
]);
// Aggregation query
$stats = $client->query('mydb', '
FOR u IN users
COLLECT status = u.status WITH COUNT INTO count
RETURN { status, count }
');
// Join query
$orders = $client->query('mydb', '
FOR o IN orders
FOR u IN users FILTER u._key == o.user_id
RETURN { order: o, user: u.name }
');
// Explain query plan (for optimization)
$plan = $client->explain('mydb', 'FOR u IN users FILTER u.age > 25 RETURN u');
ACID Transactions
// Begin a transaction
$txId = $client->beginTransaction('mydb', 'read_committed');
// Isolation levels: read_uncommitted, read_committed, repeatable_read, serializable
try {
// Perform operations within transaction
$client->insert('mydb', 'accounts', ['id' => 1, 'balance' => 1000]);
$client->insert('mydb', 'accounts', ['id' => 2, 'balance' => 500]);
// Commit if all operations succeed
$client->commitTransaction($txId);
echo "Transaction committed\n";
} catch (Exception $e) {
// Rollback on any error
$client->rollbackTransaction($txId);
echo "Transaction rolled back: " . $e->getMessage() . "\n";
}
| Method | Returns | Description |
|---|---|---|
beginTransaction($db, $isolation) | string | Start transaction, returns tx_id |
commitTransaction($txId) | void | Commit transaction |
rollbackTransaction($txId) | void | Rollback transaction |
Index Management
// Create an index
$client->createIndex('mydb', 'users', 'idx_email', ['email'], true, false);
// $db $col $name $fields $unique $sparse
// List indexes on a collection
$indexes = $client->listIndexes('mydb', 'users');
// Delete an index
$client->deleteIndex('mydb', 'users', 'idx_email');
Management Sub-Clients
Sub-clients provide namespaced access to management APIs.
Important: Call useDatabase($name) first to set the database context.
scripts()
jobs()
cron()
triggers()
env()
roles()
users()
apiKeys()
cluster()
collectionsOps()
indexesOps()
geo()
vector()
ttl()
columnar()
$client->scripts()
Lua Script Endpoints$client->useDatabase('mydb');
// Create a Lua script endpoint
$script = $client->scripts()->create(
'hello', // name
'/api/hello', // path
['GET', 'POST'], // methods
'return { message = "Hello, " .. (req.params.name or "World") }', // code
'Greeting endpoint', // description (optional)
null // collection (optional: restrict to collection)
);
echo "Created script: " . $script['_key'] . "\n";
// List all scripts
$scripts = $client->scripts()->list();
foreach ($scripts as $s) {
echo $s['name'] . " -> " . $s['path'] . "\n";
}
// Get a specific script
$script = $client->scripts()->get('script_key');
// Update script code
$client->scripts()->update('script_key', [
'code' => 'return { message = "Updated!" }',
'methods' => ['GET']
]);
// Delete a script
$client->scripts()->delete('script_key');
// Get execution statistics
$stats = $client->scripts()->getStats();
echo "Total calls: " . $stats['total_calls'] . "\n";
| Method | Parameters | Description |
|---|---|---|
create() | $name, $path, $methods, $code, $description, $collection | Create Lua endpoint |
list() | - | List all scripts |
get($scriptId) | $scriptId | Get script details |
update($scriptId, $updates) | $scriptId, array | Update script properties |
delete($scriptId) | $scriptId | Delete script |
getStats() | - | Execution statistics |
$client->jobs() & $client->cron()
Background Processing$client->useDatabase('mydb');
// === JOBS ===
// List all queues
$queues = $client->jobs()->listQueues();
// => [["name" => "default", "pending" => 5, "running" => 2], ...]
// List jobs in a queue with filters
$jobs = $client->jobs()->listJobs('default', 'pending', 50, 0);
// $queueName, $status, $limit, $offset
// Enqueue a new job
$job = $client->jobs()->enqueue(
'default', // queue name
'/scripts/process-order', // script path
['order_id' => 12345], // params (optional)
10, // priority (optional: higher = more urgent)
null // run_at (optional: ISO8601 for delayed execution)
);
echo "Job ID: " . $job['_key'] . "\n";
// Get job details
$job = $client->jobs()->get('job_id');
echo "Status: " . $job['status'] . "\n";
// Cancel a pending job
$client->jobs()->cancel('job_id');
// === CRON ===
// List scheduled jobs
$crons = $client->cron()->list();
// Create a cron job
$cron = $client->cron()->create(
'daily-cleanup', // name
'0 2 * * *', // schedule (cron expression)
'/scripts/cleanup', // script path
['days_old' => 30], // params (optional)
true, // enabled (optional)
'Remove old records' // description (optional)
);
// Get cron job details
$cron = $client->cron()->get('cron_id');
// Update cron schedule
$client->cron()->update('cron_id', ['schedule' => '0 3 * * *']);
// Toggle cron job on/off
$client->cron()->toggle('cron_id', false); // disable
$client->cron()->toggle('cron_id', true); // enable
// Delete cron job
$client->cron()->delete('cron_id');
$client->triggers()
Database Triggers$client->useDatabase('mydb');
// List all triggers
$triggers = $client->triggers()->list();
// List triggers for a specific collection
$triggers = $client->triggers()->listByCollection('users');
// Create a trigger
$trigger = $client->triggers()->create(
'on_user_created', // name
'users', // collection
'insert', // event: insert, update, delete
'after', // timing: before, after
'/scripts/on-user-create', // script path
true // enabled (optional)
);
// Get trigger details
$trigger = $client->triggers()->get('trigger_id');
// Update trigger
$client->triggers()->update('trigger_id', [
'script_path' => '/scripts/new-handler',
'enabled' => false
]);
// Toggle trigger on/off
$client->triggers()->toggle('trigger_id', true); // enable
$client->triggers()->toggle('trigger_id', false); // disable
// Delete trigger
$client->triggers()->delete('trigger_id');
| Event | Timing | Description |
|---|---|---|
insert | before / after | Fires on document creation |
update | before / after | Fires on document modification |
delete | before / after | Fires on document removal |
$client->roles() & $client->users()
Role-Based Access Control// === ROLES ===
// List all roles
$roles = $client->roles()->list();
// Create a role with permissions
$role = $client->roles()->create(
'editor', // name
[ // permissions
['action' => 'read', 'scope' => 'database', 'database' => 'mydb'],
['action' => 'write', 'scope' => 'collection', 'database' => 'mydb', 'collection' => 'articles'],
['action' => 'execute', 'scope' => 'script', 'database' => 'mydb']
],
'Content editor role' // description (optional)
);
// Get role details
$role = $client->roles()->get('editor');
// Update role permissions
$client->roles()->update('editor', [
['action' => 'read', 'scope' => 'database', 'database' => 'mydb'],
['action' => 'write', 'scope' => 'database', 'database' => 'mydb']
]);
// Delete role
$client->roles()->delete('editor');
// === USERS ===
// List all users
$users = $client->users()->list();
// Create a user
$user = $client->users()->create(
'john', // username
'secure_password', // password
['editor', 'viewer'] // roles (optional)
);
// Get user details
$user = $client->users()->get('john');
// Get user's assigned roles
$roles = $client->users()->getRoles('john');
// Assign a role to user
$client->users()->assignRole('john', 'admin', 'mydb');
// Revoke a role from user
$client->users()->revokeRole('john', 'admin', 'mydb');
// Get current authenticated user
$me = $client->users()->me();
// Get current user's permissions
$permissions = $client->users()->myPermissions();
// Change password
$client->users()->changePassword('john', 'old_password', 'new_password');
// Delete user
$client->users()->delete('john');
| Action | Scopes | Description |
|---|---|---|
read | database, collection | Read documents and query |
write | database, collection | Create, update, delete documents |
admin | database, collection | Manage indexes, schema, etc. |
execute | script | Execute Lua scripts |
$client->apiKeys()
API Key Management// List all API keys
$apiKeys = $client->apiKeys()->list();
// Create an API key
$apiKey = $client->apiKeys()->create(
'my-app-key', // name
[ // permissions
['action' => 'read', 'scope' => 'database', 'database' => 'mydb']
],
'2025-12-31T23:59:59Z' // expires_at (optional)
);
echo "API Key: " . $apiKey['key'] . "\n"; // Store this securely!
// Get API key details
$key = $client->apiKeys()->get('key_id');
// Regenerate an API key
$newKey = $client->apiKeys()->regenerate('key_id');
// Delete an API key
$client->apiKeys()->delete('key_id');
Advanced Features
$client->vector()
Vector Search & AI$client->useDatabase('mydb');
// Create a vector index
$index = $client->vector()->createIndex(
'products', // collection
'product_embeddings', // name
'embedding', // field
1536, // dimensions
'cosine', // metric: cosine, euclidean, dot_product
[] // options (optional)
);
// Search by vector (semantic search)
$embedding = getEmbedding("wireless headphones"); // Your embedding function
$results = $client->vector()->search(
'products', // collection
$embedding, // vector
10, // limit
['category' => 'electronics'] // filter (optional)
);
foreach ($results as $result) {
echo $result['doc']['name'] . " - Score: " . $result['score'] . "\n";
}
// Search by existing document (find similar)
$similar = $client->vector()->searchByDocument(
'products', // collection
'product-123', // doc_key
'embedding', // field
5, // limit
null // filter (optional)
);
// Quantize index (reduce memory usage)
$client->vector()->quantize('products', 'product_embeddings', 'binary');
// Dequantize (restore full precision)
$client->vector()->dequantize('products', 'product_embeddings');
// Get index info
$info = $client->vector()->getIndexInfo('products', 'product_embeddings');
// List vector indexes
$indexes = $client->vector()->listIndexes('products');
// Delete index
$client->vector()->deleteIndex('products', 'product_embeddings');
$client->geo()
Geospatial Queries$client->useDatabase('mydb');
// Create a geo index
$client->geo()->createIndex(
'stores', // collection
'location_idx', // name
['location'], // fields containing [lat, lon] or GeoJSON
true // geoJson (optional: true if using GeoJSON format)
);
// Find nearby locations (radius search)
$nearby = $client->geo()->near(
'stores', // collection
48.8566, // latitude
2.3522, // longitude
5000, // radius (meters)
20 // limit (optional)
);
foreach ($nearby as $result) {
echo $result['doc']['name'] . " - " . $result['distance'] . "m away\n";
}
// Find within polygon
$polygon = [
'type' => 'Polygon',
'coordinates' => [[[2.3, 48.8], [2.4, 48.8], [2.4, 48.9], [2.3, 48.9], [2.3, 48.8]]]
];
$within = $client->geo()->within('stores', $polygon);
// Find intersecting geometries
$intersects = $client->geo()->intersects('zones', $polygon);
// Calculate distance between two points
$distance = $client->geo()->distance(48.8566, 2.3522, 51.5074, -0.1278);
echo "Paris to London: " . ($distance / 1000) . "km\n";
// List geo indexes
$indexes = $client->geo()->listIndexes('stores');
// Delete index
$client->geo()->deleteIndex('stores', 'location_idx');
$client->ttl()
Time-To-Live Indexes$client->useDatabase('mydb');
// Create TTL index (auto-expire documents)
$client->ttl()->createIndex(
'sessions', // collection
'session_ttl', // name
'created_at', // field (DateTime field to check)
3600 // expire_after_seconds (1 hour)
);
// Update expiration time
$client->ttl()->updateExpiration('sessions', 'session_ttl', 7200); // 2 hours
// Get index info
$info = $client->ttl()->getIndexInfo('sessions', 'session_ttl');
echo "Expires after: " . $info['expire_after_seconds'] . "s\n";
// Manually trigger cleanup (normally runs automatically)
$result = $client->ttl()->runCleanup('sessions');
echo "Deleted " . $result['deleted'] . " expired documents\n";
// List TTL indexes
$indexes = $client->ttl()->listIndexes('sessions');
// Delete TTL index
$client->ttl()->deleteIndex('sessions', 'session_ttl');
$client->columnar()
Columnar/Analytics Storage$client->useDatabase('mydb');
// Create a columnar table (optimized for analytics)
$table = $client->columnar()->create('metrics', [
['name' => 'timestamp', 'type' => 'datetime'],
['name' => 'metric_name', 'type' => 'string'],
['name' => 'value', 'type' => 'float'],
['name' => 'tags', 'type' => 'string']
]);
// Insert rows (batch insert is efficient)
$client->columnar()->insert('metrics', [
['timestamp' => '2024-01-15T10:00:00Z', 'metric_name' => 'cpu_usage', 'value' => 45.2, 'tags' => 'server1'],
['timestamp' => '2024-01-15T10:01:00Z', 'metric_name' => 'cpu_usage', 'value' => 47.8, 'tags' => 'server1'],
['timestamp' => '2024-01-15T10:00:00Z', 'metric_name' => 'memory', 'value' => 72.1, 'tags' => 'server1']
]);
// Query with SQL-like syntax
$results = $client->columnar()->query(
'metrics',
'SELECT * FROM metrics WHERE value > @min ORDER BY timestamp DESC LIMIT 100',
['min' => 40.0]
);
// Aggregation
$agg = $client->columnar()->aggregate('metrics', [
'group_by' => ['metric_name', 'tags'],
'metrics' => [
['column' => 'value', 'function' => 'avg'],
['column' => 'value', 'function' => 'max'],
['column' => 'value', 'function' => 'min'],
['column' => 'value', 'function' => 'count']
],
'filters' => ['metric_name' => 'cpu_usage'] // optional
]);
// Get table statistics
$stats = $client->columnar()->stats('metrics');
echo "Row count: " . $stats['row_count'] . ", Size: " . $stats['size_bytes'] . "\n";
// Add a column
$client->columnar()->addColumn('metrics', 'host', 'string', 'unknown');
// Drop a column
$client->columnar()->dropColumn('metrics', 'host');
// Create index on columnar table
$client->columnar()->createIndex('metrics', 'idx_timestamp', 'timestamp', 'btree');
// List indexes
$indexes = $client->columnar()->listIndexes('metrics');
// Delete index
$client->columnar()->deleteIndex('metrics', 'idx_timestamp');
// List all columnar tables
$tables = $client->columnar()->list();
// Get table info
$table = $client->columnar()->get('metrics');
// Delete table
$client->columnar()->delete('metrics');
$client->cluster()
Cluster Management// Get cluster status
$status = $client->cluster()->status();
echo "Mode: " . $status['mode'] . "\n"; // standalone, cluster
echo "Nodes: " . $status['node_count'] . "\n";
// Get detailed cluster info
$info = $client->cluster()->info();
// Get all nodes
$nodes = $client->cluster()->getNodes();
foreach ($nodes as $node) {
echo $node['id'] . ": " . $node['address'] . " (" . $node['status'] . ")\n";
}
// Get shard distribution
$shards = $client->cluster()->getShards();
// Remove a node from cluster
$client->cluster()->removeNode('node-id-to-remove');
// Trigger data rebalancing
$client->cluster()->rebalance();
// Cleanup orphaned data
$client->cluster()->cleanup();
// Reshard cluster
$client->cluster()->reshard(16); // new number of shards
$client->collectionsOps()
Advanced Collection Operations$client->useDatabase('mydb');
// Truncate collection (delete all documents)
$client->collectionsOps()->truncate('logs');
// Compact collection (reclaim disk space)
$client->collectionsOps()->compact('users');
// Repair collection (fix inconsistencies)
$result = $client->collectionsOps()->repair('orders');
// Get collection statistics
$stats = $client->collectionsOps()->stats('users');
// Prune old documents
$result = $client->collectionsOps()->prune('logs', '2024-01-01T00:00:00Z', 'created_at');
// Recount documents
$result = $client->collectionsOps()->recount('users');
// Set JSON schema validation
$client->collectionsOps()->setSchema('users', [
'type' => 'object',
'required' => ['name', 'email'],
'properties' => [
'name' => ['type' => 'string', 'minLength' => 1],
'email' => ['type' => 'string', 'format' => 'email'],
'age' => ['type' => 'integer', 'minimum' => 0]
]
]);
// Get current schema
$schema = $client->collectionsOps()->getSchema('users');
// Remove schema validation
$client->collectionsOps()->deleteSchema('users');
// Export collection
$data = $client->collectionsOps()->export('users', 'json'); // json, csv, msgpack
// Import data
$client->collectionsOps()->import('users_backup', $data, 'json');
// Get sharding configuration
$sharding = $client->collectionsOps()->getSharding('orders');
// Configure sharding
$client->collectionsOps()->setSharding('orders', [
'num_shards' => 8,
'shard_key' => 'user_id'
]);
$client->indexesOps()
Advanced Index Operations$client->useDatabase('mydb');
// Rebuild a specific index
$client->indexesOps()->rebuild('users', 'idx_email');
// Rebuild all indexes on a collection
$client->indexesOps()->rebuildAll('users');
// Hybrid search (combine vector + keyword search)
$results = $client->indexesOps()->hybridSearch('products', [
'vector' => $embedding,
'text' => 'wireless headphones',
'vector_field' => 'embedding',
'text_field' => 'description',
'limit' => 10
]);
// Analyze index performance
$analysis = $client->indexesOps()->analyze('users', 'idx_email');
// Get index usage statistics
$stats = $client->indexesOps()->getUsageStats('users');
$client->env()
Environment Variables$client->useDatabase('mydb');
// List environment variables (for Lua scripts)
$vars = $client->env()->list();
// Get a specific variable
$value = $client->env()->get('API_KEY');
// Set an environment variable
$client->env()->set('API_KEY', 'sk-xxx-your-api-key');
$client->env()->set('WEBHOOK_URL', 'https://example.com/webhook');
// Set multiple variables at once
$client->env()->setBulk([
'API_KEY' => 'sk-xxx-key',
'API_SECRET' => 'secret123',
'DEBUG' => 'false'
]);
// Delete an environment variable
$client->env()->delete('OLD_VAR');
Error Handling
<?php
use SoliDB\Client;
use SoliDB\Exception\DriverException;
try {
$client = new Client('127.0.0.1', 6745);
$client->connect();
$client->auth('mydb', 'user', 'password');
$doc = $client->get('mydb', 'users', 'nonexistent-key');
} catch (DriverException $e) {
// All SoliDB errors extend DriverException
echo "Error: " . $e->getMessage() . "\n";
echo "Error Type: " . $e->getErrorType() . "\n";
switch ($e->getErrorType()) {
case 'connection_error':
// Network/connection issues
echo "Connection failed - check server availability\n";
break;
case 'server_error':
// Server-side errors (not found, validation, permissions)
echo "Server error - check request parameters\n";
break;
case 'serialization_error':
// Protocol/serialization errors
echo "Protocol error - possible version mismatch\n";
break;
case 'protocol_error':
// Response too large, invalid format
echo "Protocol error - response format issue\n";
break;
}
} finally {
if (isset($client)) {
$client->close();
}
}
connection_error
Network failures, connection refused, timeouts, disconnections
server_error
Document not found, permission denied, validation errors
serialization_error
MessagePack encoding/decoding failures
protocol_error
Response too large, invalid message format