Search by

Accord's merge core for PHP: hybrid logical clocks, operations, lww, counter, set and conflict.

v0.3.0 2026-10-07 11:57 UTC

This package is auto-updated.

Last update: 2026-10-07 16:34:34 UTC


README

Accord's merge core for PHP: hybrid logical clocks, operations and the four merge strategies.

Pure PHP, no I/O. Most apps use accordsync/server or its Laravel and Symfony packages, which depend on it. PHP 8.3+.

composer require accordsync/core
Strategy Merges by
Schema::lww() Highest hybrid logical clock wins.
Schema::counter() Sum of every increment; none is ever lost.
Schema::set() Add-wins set: a remove only removes what its writer had seen.
Schema::conflict() Concurrent values are all kept and the field is flagged; a resolution supersedes exactly the values its writer saw.
use Accord\Core\{Json, LocalWriter, Schema};

$schema = Schema::define(['dossier' => ['visits' => Schema::counter(), 'status' => Schema::conflict()]]);
$now = fn () => (int) (microtime(true) * 1000);
$a = new LocalWriter($schema, 'phone-a', $now);
$b = new LocalWriter($schema, 'phone-b', $now);

// Each device writes offline...
$fromA = [$a->inc('dossier:1', 'visits', 1), $a->assign('dossier:1', 'status', 'approved')];
$fromB = [$b->inc('dossier:1', 'visits', 2), $b->assign('dossier:1', 'status', 'rejected')];

// ...then they exchange ops, in any order, as often as the network repeats them.
foreach ([...$fromB, ...$fromB] as $op) {
    $a->receive($op);
}
foreach (array_reverse($fromA) as $op) {
    $b->receive($op);
}

echo Json::canonical($a->replica()->read('dossier:1'));
// {"status":{"conflicted":[{"opId":"phone-a:2","value":"approved"},{"opId":"phone-b:2","value":"rejected"}]},"visits":3}
var_dump($a->replica()->snapshot() === $b->replica()->snapshot()); // bool(true)

Objects in values are Accord\Core\JsonObject (PHP arrays cannot tell {} from []), and Json::canonical() writes the same canonical JSON as the TypeScript core.

It merges byte for byte like @accordsync/core: the test suite runs the shared golden vectors in every delivery order, and random scenarios generated by the TypeScript core must produce identical snapshots here.

Docs: accord.benhattab.pro/docs/schema · Source: crossben/accordsync-php · Licence: Apache-2.0