Skip to content

Quick start

This page builds a small application end to end: connect, create a schema, write, read, and handle errors. It assumes the extension is installed and a node is reachable. See installation if it is not.

1. Connect

php
<?php

declare(strict_types=1);

$cluster = Cassandra::cluster()
    ->withContactPoints('127.0.0.1')
    ->withPort(9042)
    ->build();

$session = $cluster->connect();

Cassandra::cluster() returns a Cassandra\Cluster\Builder. Every with*() method returns the same builder, so calls chain. build() produces an immutable Cassandra\Cluster. connect() opens the connection pool and returns a Cassandra\Session.

One session per process

Building a cluster is cheap. Connecting is not: it opens sockets to every node and reads the schema. Create the session once and share it. See performance.

2. Create a keyspace and a table

php
$session->execute(
    "CREATE KEYSPACE IF NOT EXISTS shop
     WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1}"
);

$session->execute(
    'CREATE TABLE IF NOT EXISTS shop.users (
        id uuid PRIMARY KEY,
        email text,
        created_at timestamp,
        login_count bigint
    )'
);

execute() accepts a plain CQL string. The driver wraps it in a Cassandra\SimpleStatement for you.

3. Select the keyspace

Connect with a keyspace to avoid writing it in every query:

php
$session = $cluster->connect('shop');

An existing session can switch with USE, but a per-keyspace session is clearer.

4. Write with a prepared statement

php
$insert = $session->prepare(
    'INSERT INTO users (id, email, created_at, login_count) VALUES (?, ?, ?, ?)'
);

$id = new Cassandra\Uuid();   // random version 4 UUID

$session->execute($insert, [
    'arguments' => [
        $id,
        'ada@example.com',
        new Cassandra\Timestamp(time()),
        new Cassandra\Bigint(0),
    ],
]);

Two rules to remember:

  • Bind values with the arguments key. Never build CQL by string concatenation.
  • A bigint column needs a Cassandra\Bigint, not a PHP int. A plain int marshals as a 4-byte value and the server rejects it. The full table is in data types.

5. Read

php
$rows = $session->execute('SELECT id, email, login_count FROM users');

echo count($rows), " rows\n";

foreach ($rows as $row) {
    printf(
        "%s  %-24s logins=%s\n",
        $row['id'],          // Cassandra\Uuid
        $row['email'],       // string
        $row['login_count'], // Cassandra\Bigint
    );
}

Each row is an associative array keyed by column name. Values arrive as PHP scalars or as driver value objects. See results and paging.

6. Bind by name

Named markers work as well, and they do not depend on argument order:

php
$byId = $session->prepare('SELECT email, login_count FROM users WHERE id = :id');

$rows = $session->execute($byId, [
    'arguments' => ['id' => $id],
]);

$first = $rows->first();   // null when the result is empty

7. Handle errors

Every driver error implements Cassandra\Exception. Catch the specific class you can act on, and the interface for everything else.

php
use Cassandra\Exception\InvalidQueryException;
use Cassandra\Exception\ReadTimeoutException;

try {
    $rows = $session->execute($select, ['timeout' => 2.5]);
} catch (ReadTimeoutException $e) {
    // Not enough replicas answered in time. Safe to retry a read.
    error_log('read timeout: ' . $e->getMessage());
} catch (InvalidQueryException $e) {
    // The table or column does not exist. Retrying will not help.
    throw $e;
} catch (Cassandra\Exception $e) {
    error_log('driver error: ' . $e->getMessage());
}

The full hierarchy is in error handling.

8. Close

php
$session->close();

The session closes on script shutdown as well. Call close() when you want the sockets released at a known point, for example in a long running worker between jobs.

The complete example

php
<?php

declare(strict_types=1);

$session = Cassandra::cluster()
    ->withContactPoints('127.0.0.1')
    ->withPort(9042)
    ->withDefaultConsistency(Cassandra::CONSISTENCY_LOCAL_QUORUM)
    ->withTokenAwareRouting(true)
    ->build()
    ->connect('shop');

$insert = $session->prepare(
    'INSERT INTO users (id, email, created_at, login_count) VALUES (?, ?, ?, ?)'
);

$id = new Cassandra\Uuid();

$session->execute($insert, [
    'arguments' => [$id, 'ada@example.com', new Cassandra\Timestamp(time()), new Cassandra\Bigint(0)],
]);

$select = $session->prepare('SELECT email, login_count FROM users WHERE id = ?');
$row = $session->execute($select, ['arguments' => [$id]])->first();

printf("%s has %s logins\n", $row['email'], $row['login_count']);

$session->close();

Next steps

Version 1.4. Released under the Apache License 2.0.