Download the PHP package adaiasmagdiel/pdo-restify without Composer
On this page you can find all versions of the php package adaiasmagdiel/pdo-restify. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download adaiasmagdiel/pdo-restify
More information about adaiasmagdiel/pdo-restify
Files in adaiasmagdiel/pdo-restify
Package pdo-restify
Short Description A framework-agnostic REST API layer on top of PDO, for MySQL, MariaDB and SQLite.
License LGPL-3.0-or-later
Informations about the package pdo-restify
pdo-restify
A small, framework-agnostic REST API layer on top of PDO. It exposes whitelisted database tables as CRUD endpoints — inspired by PostgREST — but works with plain PDO, so it runs on MySQL, MariaDB and SQLite, and can be plugged into any PHP application: Slim, Laravel, CakePHP, Erlenmeyer, or a plain script.
Early, minimal first version. The scope is intentionally small — see Roadmap.
📚 Full documentation — guides for connections, resources & the security model, querying, framework integration, error handling, tips, and a complete API reference. The sections below are a quick overview; the docs go deeper on every one of them.
🟨 JS/TS client — a typed, dependency-free
fetch-based client for consuming a pdo-restify API from JS/TS (browser,
Node, or edge), published as @adaiasmagdiel/pdo-restify.
Install
Quick start
Api::handle() takes and returns plain data — it does no I/O by itself. Your
app (or a thin bridge, see examples/erlenmeyer-bridge.php)
is responsible for turning the real HTTP request into a Request and writing
the resulting Response back out. This is what makes pdo-restify pluggable
into any router or framework.
Security model
PostgreSQL has Row-Level Security to scope what each request can see or change. PDO has nothing like that built in, and pdo-restify doesn't try to fake it either — it gives you the pieces and leaves the decision to you:
- Deny by default, at the table level. A table is only reachable if
registered as a
Resourcewith an explicit column whitelist, and each operation (Operation::Select,Insert,Update,Delete) must be explicitly enabled withallow(). Anything you don't register stays unreachable. - Row-level scoping is optional, not imposed — and it's real SQL. The
policy closure passed to
allow()returns aRawCondition: a raw SQL boolean expression plus its bound params, always enforced for that operation —OR,IN (...), whatever yourWHEREclause can express, not a fixed condition DSL. For insert/update it doubles as aWITH CHECK, re-validated against the written row, rolling back on violation. Skip the closure ($posts->allow(Operation::Select)) and that operation is wide open, no scoping at all. Some APIs genuinely don't need per-row scoping (public read-only data, an admin tool behind its own auth layer, a single-tenant app), and pdo-restify won't force a no-op policy on you just for ceremony — but skipping one does mean every caller sees every row for that operation, so make that trade-off deliberately. - Every query is parameterized. Table, column and operator names are validated against a whitelist before they ever reach a SQL string; values are always bound as parameters, never interpolated.
See Resources & security model for the full guide, including a ready-made "public read, admin-only write" recipe plus multi-tenant and role-based policy examples.
Query string
| Param | Example | Meaning |
|---|---|---|
<column> |
age=gt.18 |
Filter, operator.value |
select |
select=id,title |
Which whitelisted columns to return |
order |
order=created_at.desc |
Sort column and direction |
limit / offset |
limit=20&offset=40 |
Pagination, limit is capped server-side |
Supported filter operators: eq, ne, gt, gte, lt, lte, like
(* is the wildcard), in (comma-separated values). Full details,
including how AND/pagination/limits interact, in
Querying.
select= can also embed related rows — select=id,title,comments(id,body)
— declared with ->hasMany()/->belongsTo() on a Resource, scoped by the
related resource's own policy just like a direct request to it. See
Relationships.
Routes
Api::handle() dispatches based on Request::$path and Request::$method:
| Method | Path | Action |
|---|---|---|
| GET | /{table} |
List rows (filters apply) |
| GET | /{table}/{id} |
Fetch a single row |
| POST | /{table} |
Insert a row, or bulk-insert if the body is a list of objects |
| PATCH | /{table}/{id} |
Update a row |
| PATCH | /{table} |
Bulk-update rows (each object must include the primary key) |
| DELETE | /{table}/{id} |
Delete a row |
| DELETE | /{table} |
Bulk-delete rows (body is a list of ids) |
POST/PATCH/DELETE bulk requests run in a single transaction — one bad
row rolls back the whole batch. See Bulk operations.
Testing
The suite runs on Pest against an in-memory SQLite database:
Coverage requires Xdebug or PCOV (composer test:coverage, enforced at
95%+ in CI). Locally, with Xdebug installed:
MySQL and MariaDB compatibility is checked separately, against real service containers, by the Integration workflow on GitHub Actions. Those tests skip themselves locally and only run in CI.
Roadmap
- Nested embeds (
comments(replies(*))), many-to-many/hasOnerelations, and filter/order/pagination on embedded relations - Per-row results for partially-failed bulk requests
- Pluggable authentication helpers
- RPC-style calls to stored procedures/functions
License
LGPL-3.0-or-later.
All versions of pdo-restify with dependencies
ext-pdo Version *