Skip to content
docsv0.2.4

SqliteRepository

SQLite document-store {@see RepositoryInterface}: the same six-method contract as {@see FileRepository}, over a real database file — and still zero migrations, because the table is not a schema. Each entity class gets one table of two payload columns — `id TEXT` plus `doc TEXT` holding the entity's `toArray()` as JSON — created lazily with `CREATE TABLE IF NOT EXISTS` on first use. The `toArray()`/`fromArray()` pair IS the schema: adding a field to an entity never touches the database. The table name derives from the entity class: snake_case of the short class name plus a crc32 suffix of the fully-qualified name — `App\Blog\Post` becomes `post_2f1f1893`. The suffix is what lets two classes with the same short name share one database file without silently sharing a table. Ids live in the `id TEXT` column through their string form, so — as with the PHP array keys backing {@see FileRepository} — `1` and `'1'` name the same row; the typed id survives inside the JSON document. Insertion order of {@see self::all()} rides an internal `seq INTEGER PRIMARY KEY AUTOINCREMENT` column; re-saving an existing id updates its row in place, so `seq` — and with it the entity's position — never moves. Concurrency is SQLite's own locking, the way `flock` is {@see FileRepository}'s: every save runs inside an immediate transaction held across id assignment and the write, so concurrent processes can neither mint the same fresh id nor lose each other's rows. Needs `ext-pdo_sqlite` (suggested, not required, by the package — the other backends need no extension). A missing extension, or a database path that cannot be created or opened, fails with an error that says what broke, why it matters, and how to fix it.

SqliteRepository::__construct()

public function __construct(string $dbPath, string $entityClass):

Parameters

Parameters of __construct()
NameTypeDescription
$dbPathstringpath to the SQLite database file; the file — and its directory — are created on first use if missing
$entityClassclass-string<T>the entity class rows are rehydrated into via `fromArray()`

SqliteRepository::find()

public function find(string|int $id): ?Milpa\Data\EntityInterface

The entity stored under `$id`, or `null` when no entity is stored under it.

Parameters

Parameters of find()
NameTypeDescription
$idstring|int

SqliteRepository::save()

public function save(Milpa\Data\EntityInterface $entity): string|int

Persists `$entity` as one JSON document row, inside an immediate transaction held across id assignment and the write — so a concurrent saver against the same file can neither mint the same fresh id nor be overwritten. When `$entity->id()` is `null`, a fresh id is assigned via {@see self::nextId()}. Re-saving an existing id updates its row in place, keeping the entity's insertion position in {@see self::all()}. The stored document always carries the id actually used under the key `'id'`, regardless of what `$entity->toArray()` returned for it.

Parameters

Parameters of save()
NameTypeDescription
$entityT

SqliteRepository::delete()

public function delete(string|int $id): void

Removes the row stored under `$id`. A no-op when no entity is stored under it.

Parameters

Parameters of delete()
NameTypeDescription
$idstring|int

SqliteRepository::all()

public function all(): array

Every stored entity, in insertion order — rows come back ordered by the internal autoincrement `seq` column, which records the order ids were first saved regardless of the ids themselves.

SqliteRepository::nextId()

public function nextId(): int

The id to assign to the next entity saved without one of its own — one past the highest integer id currently stored, or `1` when the store holds no integer id. Ids live in a TEXT column, so the maximum is computed in PHP over the fetched ids, exactly like `FileRepository` does over its array keys — a stored `'42'` counts as the integer it names, `'custom-id'` does not.

SqliteRepository::query()

public function query(array $criteria): array

Stored entities matching every `$criteria` pair by strict equality. Deliberately filtered in PHP after fetching every row — not pushed into SQL — so equality semantics stay exactly {@see FileRepository}'s (`===` over the decoded `toArray()` values, JSON types intact), at the cost of reading the whole table. For the collection sizes this backend targets that is the right trade; a SQL-side filter could come later without touching the contract.

Parameters

Parameters of query()
NameTypeDescription
$criteriaarray<string, mixed>