CDO
CDO (Connection Data Object) is an extended PDO wrapper for PHP. It gives you
safe, parameterised DML — insert, update, delete, upsert and their batch
variants — a type-aware binder that picks the right PDO::PARAM_* for every
value, and Qb, a composable query builder that produces injection-safe
WHERE fragments. It speaks PostgreSQL, MySQL/MariaDB and Oracle, and adapts
its SQL to each.
Philosophy
- Parameterised by default — every value goes through a named placeholder and a typed bind. There is no string interpolation of values anywhere in the DML path, so injection is not a risk you have to remember to avoid.
- Driver-aware, not driver-locked — CDO detects PostgreSQL, MySQL, MariaDB and
Oracle at connect time and rewrites
RETURNING,ON CONFLICTvsON DUPLICATE KEY UPDATE, and timezone handling for you. - Thin over PDO —
CDO extends PDO, so every method you already know (query,prepare,fetchAll, transactions) is still there. The wrapper only adds convenience on top; it never takes PDO away.
Core concepts
CDO— the connection. ExtendsPDOand addsinsert,insertGroup,upsert,upsertGroup,update,delete.Qb— an immutable query builder. Static factories (Qb::eq,Qb::and, …) return composable fragments, each carrying its own bound values.CDOBind— a name + value pair. Auto-created byQb; you build one by hand to name a placeholder or reuse it across conditions.- Config classes — extend
PgDbConfig/MySqlDbConfig(or use the inlinePgDbCall/MySqlDbCall/DbCall) to describe a connection. ConnectionPool— a process-level registry that instantiates each config once and hands back a readyCDO.
Key features
- Full CRUD + upsert — single-row and chunked batch inserts and upserts, with
automatic primary-key return where the driver supports
RETURNING. - Composable
Qb— comparison,NULL, set, pattern, range, logical,CASEand raw operators, all combinable withand/or/xor/clip. - Type-aware binding —
null,bool,int,array(JSON), objects (JsonSerializable,Stringable,DateTimeInterface,BackedEnum) are each bound with the correct PDO type. - Health checks —
ping()andpingDetail()(status + latency) on every config, plus lazyconnect/disconnect/reconnect. - PSR-3 logging — attach any
LoggerInterface; every generated query is logged at debug level.
Good fit for
Application data access where you want parameterised safety and batch throughput without the weight of a full ORM — services, workers, importers, and anywhere you already reach for PDO but keep re-writing the same insert/upsert plumbing.
Requirements
- PHP ≥ 8.3
ext-pdoand the driver extension for your database (pdo_pgsql,pdo_mysql, orpdo_oci)psr/log^3.0
See Installation & requirements for the full list.
Install
composer require flytachi/winter-cdoQuick taste
Get a connection, insert a row, read the generated id:
use Flytachi\Winter\Cdo\ConnectionPool;
use Flytachi\Winter\Cdo\Qb;
$cdo = ConnectionPool::db(AppDb::class);
$id = $cdo->insert('users', ['name' => 'Alice', 'email' => 'alice@example.com']);
$cdo->update('users', ['name' => 'Alice Smith'], Qb::eq('id', $id));Walk through it end to end in the Quickstart.
Source & links
- GitHub — github.com/flytachi/winter-cdo
- Packagist — packagist.org/packages/flytachi/winter-cdo
Continue with Installation & requirements, the Quickstart, and the Mental model.