Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Riak Laravel Package

basho/riak

Official PHP client for Riak, Basho's distributed NoSQL database. Provides a simple API for storing, retrieving, and querying data across a Riak cluster, with support for buckets, keys, links, MapReduce, and connection handling.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and orient yourself in 5 minutes

composer require basho/riak

The client speaks Riak KV's HTTP interface (default port 8098), not the Protocol Buffers port (8087). You need a reachable Riak 2.x node — in practice the basho/riak-kv Docker image or an existing cluster.

use Basho\Riak;
use Basho\Riak\Node;

$node = (new Node\Builder())
    ->atHost('127.0.0.1')
    ->onPort(8098)
    ->build();

$riak = new Riak($node);

$ping = (new Riak\Command\Builder\Ping($riak))->build()->execute();
var_dump($ping->isSuccess()); // sanity check the connection before anything else

Where to look first. The package is archived and Basho's documentation site is gone, so the source is the documentation. Read these in order:

  1. vendor/basho/riak/README.md — the last surviving tutorial.
  2. vendor/basho/riak/src/Basho/Riak/Command/Builder/ — one class per operation; grep here before guessing a method name.
  3. vendor/basho/riak/src/Basho/Riak/Command/Response/ — tells you what isSuccess() / isNotFound() / getObject() return.

First real use case. A key/value store behind a cache or session layer — one bucket, one object per key, no queries:

$store = (new Riak\Command\Builder\StoreObject($riak))
    ->buildLocation('user:42', 'app_sessions', 'app_bucket_type')
    ->withData(json_encode(['cart' => [1, 2, 3]]))
    ->withContentType('application/json')
    ->build()
    ->execute();

$fetch = (new Riak\Command\Builder\FetchObject($riak))
    ->buildLocation('user:42', 'app_sessions', 'app_bucket_type')
    ->build()
    ->execute();

if ($fetch->isNotFound()) {
    // cold cache
} elseif ($fetch->isSuccess()) {
    $data = $fetch->getObject()->getData(); // already json_decode()'d
}

The three-argument buildLocation($key, $bucketName, $bucketType) is the pattern you'll type a hundred times. Riak 2.x is bucket-type first; there is no "just a bucket" any more.

Implementation Patterns

Register one client per node in the container. Basho\Riak holds a Node and an HTTP API instance; constructing it per request is wasteful but harmless, while constructing it per call is a code smell. Bind it as a singleton and inject it. If you run a multi-node cluster, either put a load balancer in front and point at that, or keep an array of Node\Builder results and pick one per request.

Builder → Command → Response is the universal shape. Every operation is:

$response = (new Riak\Command\Builder\FetchObject($riak))
    ->buildLocation($key, $bucket, $type)
    ->build()          // returns a Command
    ->execute();       // returns a Response

Keep the two-step build/execute in mind when you wrap operations in repository classes: build the command in one method, execute in another, and your unit tests can assert on the command's parameters without a live node.

Use CRDTs instead of read-modify-write. This is the single biggest architectural win available with this client. A naive fetch → mutate → store loop loses writes under concurrency unless you carry the vclock back:

$fetch = (new Riak\Command\Builder\FetchObject($riak))
    ->buildLocation($key, $bucket, $type)->build()->execute();

$store = (new Riak\Command\Builder\StoreObject($riak))
    ->buildLocation($key, $bucket, $type)
    ->withData($newData)
    ->withVClock($fetch->getVClock())   // CAS guard
    ->build()->execute();

For counters, sets, and maps, skip that entirely:

$response = (new Riak\Command\Builder\UpdateCounter($riak))
    ->buildBucket('page_views', 'counters')
    ->increment(1)
    ->build()->execute();

$response->getCounter();         // new value
$response->getPreviousCounter(); // value before the update

Same builder family exists for UpdateSet / FetchSet and UpdateMap / FetchMap. Offload anything monotonically increasing or set-like to these and you delete an entire class of race conditions.

Model your access patterns before your data. Riak has no joins and key listing is expensive. Decide up front whether a lookup goes through:

  • Direct key — cheapest, use it for everything you can.
  • Secondary indexes (2i) — build a FetchKeys/ListKeys command with an index and value; the index field must be registered (index on the bucket type).
  • Solr search — Command\Builder\Search\FetchObjects with withIndexName() / withQuery() for range or full-text predicates.

If none of those fit, Riak is the wrong store for that entity.

Push aggregation to the server with MapReduce — sparingly. Command\Builder\MapReduce lets you chain JS map/reduce phases over a bucket. It's genuinely useful for backfills and one-off reporting, but MapReduce is deprecated in Riak 2.x and removed from the surrounding ecosystem; don't build product features on it. Keep phases in resources/ as .js files, load them with file_get_contents(), and version them alongside your code.

Handle siblings explicitly if you enable allow_mult. With multi-value buckets, concurrent writes leave siblings; getObject()->getData() gives you one and hides the rest. For anything where losing a write matters, inspect the sibling list from the response and merge (last-write-wins by timestamp, or a set union) before writing back with the combined vclock. Decide this at bucket-type creation time — flipping allow_mult later is a cluster operation.

Test against a real node, cheaply. There's no useful in-memory fake. Run docker run -d -p 8098:8098 basho/riak-kv in CI, wait for /ping to return OK, create your bucket types in a fixture, and truncate by deleting/recreating the bucket between tests. For unit tests, the Api layer is swappable — inject a stub HTTP client so you can assert on the generated request (method, path, headers) without a socket.

Health and readiness endpoints. Ping for liveness, Command\Builder\Stats for a richer readiness probe. Cache the result for a few seconds; hitting the node on every request is noise.

Gotchas and Tips

The project is dead — budget for that. Basho Technologies shut down in 2017; this repo is archived and its last release is from April 2017. There will be no security fixes, no TLS/library updates, and no PHP-version work. Its practical lifespan is the lifespan of the Riak cluster you already own. If you're greenfielding, this package is a reason to pick a different store, not a reason to pick Riak.

Composer on modern PHP is the first fight. The package predates PHP 7 type declarations and pins an old Guzzle range. On PHP 8 you'll get deprecation notices (implicit nullable parameters, dynamic properties) and Guzzle 5 will not run at all — force guzzlehttp/guzzle:^6 or ^7 in your root composer.json and let the conflict resolver tell you the truth. If you must run it long-term, fork it into your own VCS namespace and patch it there; don't rely on composer update ever touching it again.

Bucket types must pre-exist. riak-admin bucket-type create app_bucket_type '{"props":{"allow_mult":true}}' then riak-admin bucket-type activate app_bucket_type. The default type always exists, which is why tutorials "just work" and your code then fails in production. Treat bucket-type creation as a migration step, checked into your deploy scripts.

JSON is encoded and decoded for you — sometimes twice. With Content-Type: application/json, getData() returns an array, not a string. If you json_decode() it again you'll get null. Conversely, if you setData() an array with a non-JSON content type, the client will stringify it in ways you didn't intend. Pick one convention (store JSON, always) and assert on getObject()->getContentType() in tests.

isSuccess() is not enough. Distinguish isNotFound() from a 500 from a connection failure. A node that's down throws from Guzzle inside execute(); a node that's up but has no surviving primaries returns 503. Wrap execute() in a try/catch and check status — retries belong in a Guzzle middleware, not in a loop around the builder.

Never list keys to paginate a UI. ListKeys on a large bucket is O(n) over the whole keyspace and will eventually take down your node's HTTP listener. If you need paging, you needed 2i or Solr in the design phase. There is no LIMIT/OFFSET.

Counters can't be set. UpdateCounter only increments or decrements. There's no "reset to zero" other than writing a new counter object at the same key (which resets and can produce siblings). If your feature needs "set the counter," it's a map field, not a counter.

MapReduce is deprecated. It still works on most 2.x releases but is on the way out and has a reputation for timing out on large buckets. Cap it, run it from a queue worker, and don't let a web request block on it.

Extension points worth knowing. Node\Builder exposes TLS configuration (certificate, CA file, verify-peer) and auth, which is how you go from localhost to a secured cluster. Api\Http accepts an injected Guzzle client — that's your hook for request logging, tracing headers, and retry/backoff middleware. For raw operations the builders don't cover, drop to Command\Builder\FetchObject-style commands with a custom path, or implement Api yourself against the PB protocol if HTTP overhead becomes the bottleneck.

Debugging tip. Set a Guzzle middleware that dumps X-Riak-Vclock and X-Riak-Sibling-Count on every response. Nine out of ten "the data disappeared" reports are sibling resolution or a lost vclock, and those two headers tell you which within seconds.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource