hivellm/nexus-php

Official PHP client library for Nexus, a high-performance Neo4j-compatible graph database

Maintainers

Package info

github.com/hivellm/nexus-php

pkg:composer/hivellm/nexus-php

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-07-21 12:26 UTC

This package is auto-updated.

Last update: 2026-07-21 12:28:53 UTC


README

Official PHP client library for Nexus, a high-performance Neo4j-compatible graph database.

Compatibility: SDK 2.5.0 ↔ nexus-server 2.5.0. SDK and server move in lockstep on the same X.Y.Z train. See docs/COMPATIBILITY_MATRIX.md.

Features

  • Binary RPC by default — connects over nexus://127.0.0.1:15475 using length-prefixed MessagePack; 3–10× lower latency and 40–60% smaller payloads than the legacy HTTP path.
  • HTTP fallback in one line — pass an http://… URL or set Config::$transport = TransportMode::Http to use the REST transport.
  • Complete Cypher Support - Execute any Cypher query with parameters
  • CRUD Operations - Simplified methods for nodes and relationships
  • Batch Operations - Create multiple nodes/relationships efficiently
  • Transaction Support - Full ACID transaction management
  • Schema Management - Indexes, labels, and relationship types
  • Authentication - API keys and bearer tokens
  • Modern PHP - PHP 8.1+ with strict types and readonly properties
  • PSR Compliant - Follows PSR-4, PSR-12, and uses PSR-18 HTTP client
  • Type Safe - Full type hints and return types

Requirements

  • PHP 8.1 or higher
  • Composer
  • Nexus server 1.0.0 or higher

Installation

composer require hivellm/nexus-php

Quick Start (RPC — default)

<?php

require 'vendor/autoload.php';

use Nexus\SDK\Config;
use Nexus\SDK\NexusClient;

// Defaults to nexus://127.0.0.1:15475 (binary RPC).
$config = new Config(
    baseUrl: 'nexus://127.0.0.1:15475',
    apiKey: 'your-api-key', // Optional
    timeout: 30
);

$client = new NexusClient($config);

// Check connection
$client->ping();

// Execute Cypher query
$result = $client->executeCypher(
    'MATCH (n:Person) WHERE n.age > $minAge RETURN n.name, n.age ORDER BY n.age DESC',
    ['minAge' => 25]
);

// Process results
foreach ($result->rows as $row) {
    echo "Name: {$row['n.name']}, Age: {$row['n.age']}\n";
}

echo "Query took {$result->stats?->executionTimeMs}ms\n";

Usage Examples

Creating Nodes

// Create a single node
$node = $client->createNode(
    labels: ['Person'],
    properties: [
        'name' => 'John Doe',
        'age' => 30,
        'email' => 'john@example.com'
    ]
);

echo "Created node with ID: {$node->id}\n";

// Batch create multiple nodes
$nodes = $client->batchCreateNodes([
    [
        'labels' => ['Person'],
        'properties' => ['name' => 'Alice', 'age' => 28]
    ],
    [
        'labels' => ['Person'],
        'properties' => ['name' => 'Bob', 'age' => 32]
    ]
]);

echo "Created " . count($nodes) . " nodes\n";

External IDs

Nodes can carry a caller-supplied external id in prefixed string form. Supported variants: sha256:<64-hex>, blake3:<64-hex>, sha512:<128-hex>, uuid:<canonical>, str:<utf8 ≤256 B>, bytes:<hex ≤128 chars>.

$client = new NexusClient(new Config(baseUrl: 'http://localhost:15474'));

// Create via Cypher with an external id
$result = $client->executeCypher(
    "CREATE (n:Document {_id: 'str:doc-phase10', title: 'Phase 10 spec'}) RETURN n._id"
);
echo $result->rows[0][0] . "\n"; // str:doc-phase10

// Retrieve by external id
$resp = $client->getNodeByExternalId('str:doc-phase10');
if ($resp['node'] !== null) {
    echo "Node id: " . $resp['node']['id'] . "\n";
}

// Conflict policies via Cypher ON CONFLICT
$client->executeCypher(
    "CREATE (n:Document {_id: 'str:doc-phase10', title: 'Updated'}) ON CONFLICT REPLACE RETURN n._id"
);

Run the live test suite (requires a running server):

NEXUS_LIVE_HOST=http://localhost:15474 vendor/bin/phpunit --group live

Creating Relationships

// Create a relationship
$rel = $client->createRelationship(
    startNode: $node1->id,
    endNode: $node2->id,
    type: 'KNOWS',
    properties: [
        'since' => '2020',
        'strength' => 0.8
    ]
);

echo "Created relationship: {$rel->type}\n";

// Batch create relationships
$rels = $client->batchCreateRelationships([
    [
        'start_node' => '1',
        'end_node' => '2',
        'type' => 'KNOWS',
        'properties' => ['since' => '2020']
    ],
    [
        'start_node' => '2',
        'end_node' => '3',
        'type' => 'WORKS_WITH',
        'properties' => ['project' => 'GraphDB']
    ]
]);

Reading and Updating Data

// Get node by ID
$node = $client->getNode('1');
echo "Node: {$node->properties['name']}\n";

// Update node properties
$updated = $client->updateNode('1', [
    'age' => 31,
    'updated_at' => time()
]);

// Get relationship
$rel = $client->getRelationship('r1');

// Delete node
$client->deleteNode('1');

// Delete relationship
$client->deleteRelationship('r1');

Transactions

// Begin transaction
$tx = $client->beginTransaction();

try {
    // Execute queries in transaction
    $tx->executeCypher("CREATE (n:Person {name: \$name})", ['name' => 'Transaction User']);
    $tx->executeCypher("CREATE (n:Person {name: \$name})", ['name' => 'Another User']);

    // Commit transaction
    $tx->commit();
    echo "Transaction committed successfully\n";
} catch (Exception $e) {
    // Rollback on error
    $tx->rollback();
    echo "Transaction rolled back: {$e->getMessage()}\n";
}

Schema Management

// List all labels. Each entry is ['name' => '...', 'id' => N] —
// `id` is the catalog id allocated by the engine, not a count.
// (Renamed from a JSON tuple ['Person', 0] in nexus-server 1.15+,
// see https://github.com/hivellm/nexus/issues/2.)
$labels = $client->listLabels();
foreach ($labels as $label) {
    echo "  {$label['name']} (id={$label['id']})\n";
}

// List all relationship types — same shape as labels.
$types = $client->listRelationshipTypes();
foreach ($types as $relType) {
    echo "  {$relType['name']} (id={$relType['id']})\n";
}

// Create index
$client->createIndex('person_name_idx', 'Person', ['name']);

// List indexes
$indexes = $client->listIndexes();
foreach ($indexes as $idx) {
    echo "Index: {$idx->name} on {$idx->label}(" . implode(', ', $idx->properties) . ")\n";
}

// Delete index
$client->deleteIndex('person_name_idx');

Error Handling

use Nexus\SDK\NexusApiException;
use Nexus\SDK\NexusException;

try {
    $result = $client->executeCypher('INVALID QUERY');
} catch (NexusApiException $e) {
    echo "HTTP {$e->statusCode}: {$e->responseBody}\n";

    match ($e->statusCode) {
        400 => echo "Bad request - check your query syntax\n",
        401 => echo "Unauthorized - check your API key\n",
        404 => echo "Not found\n",
        500 => echo "Server error\n",
        default => echo "Unknown error\n"
    };
} catch (NexusException $e) {
    echo "Nexus SDK error: {$e->getMessage()}\n";
} catch (Exception $e) {
    echo "Unexpected error: {$e->getMessage()}\n";
}

Authentication

API Key

$config = new Config(
    baseUrl: 'nexus://127.0.0.1:15475',
    apiKey: 'your-api-key'
);
$client = new NexusClient($config);

Username/Password

$config = new Config(
    baseUrl: 'nexus://127.0.0.1:15475',
    username: 'admin',
    password: 'password'
);
$client = new NexusClient($config);

Bearer Token

$config = new Config(baseUrl: 'nexus://127.0.0.1:15475');
$client = new NexusClient($config);

// Set token manually after authentication
$client->setToken('your-jwt-token');

Configuration

class Config
{
    public function __construct(
        public string $baseUrl = 'nexus://127.0.0.1:15475',
        public ?string $apiKey = null,
        public ?string $username = null,
        public ?string $password = null,
        public int $timeout = 30,
        public ?\Nexus\SDK\Transport\TransportMode $transport = null,
        public ?int $rpcPort = null,
        public ?int $resp3Port = null,
    ) {}
}

Models

Node

class Node
{
    public string $id;                // Unique identifier
    public array $labels;             // Node labels
    public array $properties;         // Node properties
}

Relationship

class Relationship
{
    public string $id;                // Unique identifier
    public string $type;              // Relationship type
    public string $startNode;         // Start node ID
    public string $endNode;           // End node ID
    public array $properties;         // Relationship properties
}

QueryResult

class QueryResult
{
    public array $columns;            // Column names
    public array $rows;               // Result rows
    public ?QueryStats $stats;        // Execution statistics
}

class QueryStats
{
    public int $nodesCreated;
    public int $nodesDeleted;
    public int $relationshipsCreated;
    public int $relationshipsDeleted;
    public int $propertiesSet;
    public float $executionTimeMs;
}

Testing

Run tests with PHPUnit:

composer test

Run static analysis:

composer phpstan

Check code style:

composer cs-check

Fix code style:

composer cs-fix

Examples

See the examples directory for complete working examples:

  • basic_usage.php - Basic CRUD operations
  • transactions.php - Transaction management
  • batch_operations.php - Batch node/relationship creation
  • schema_management.php - Working with indexes and schema

Performance Tips

  1. Use Batch Operations - For creating multiple nodes/relationships
  2. Reuse Client - Create one client instance and reuse it
  3. Parameterized Queries - Always use parameters instead of string concatenation
  4. Transactions - Group related operations for consistency and performance
  5. Connection Timeout - Set appropriate timeout for your use case

License

Apache License 2.0 - see LICENSE file for details

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Support

Related