Skip to content
Projets

tommyknocker/pdo-database-class

Voir sur GitHub

tommyknocker/pdo-database-class has 81 GitHub stars and 46 forks. GitHot measured 0 stars in 24 hours and 0 in 7 days. Last checked 2026-11-15 14:17 UTC. Last push 2026-11-02.

Comment ces chiffres sont mesurés

What you can do

  • Fluent query builder for select, insert, update, and delete
  • Filtering, joins, and aggregates, including subqueries
  • 80+ SQL helpers for strings, dates, math, JSON, and aggregates
  • Window functions: ROW_NUMBER, RANK, LAG, LEAD

Progression mesurée des étoiles

in 24h
0
in 7 days
0
in 15 days
Historique en cours
in 1 month
Historique en cours

Variations nettes sur des périodes qui se chevauchent, pas des totaux quotidiens. Les mesures absentes restent vides. Les étoiles indiquent l’intérêt, pas la qualité.

À propos

Framework-agnostic PHP database library with unified API for MySQL, MariaDB, PostgreSQL, SQLite, MSSQL, and Oracle. Query Builder, caching, sharding, window functions, CTEs, JSON, migrations, ActiveRecord, CLI tools, AI-powered analysis. Zero external dependencies.

Données

README.md

Original

PDOdb

PHP Version Latest Version Tests PHPStan Level 8 AI query advice Coverage License Downloads GitHub Stars

PDOdb is a PHP database library for MySQL, MariaDB, PostgreSQL, SQLite, SQL Server, and Oracle. You write queries once with a fluent builder. When a query is slow, one call sends the available execution plan, columns, and indexes to a provider you choose, so you can review a suggestion without pasting the schema into chat.

Built on PDO, with no framework dependency. The package requires three PSR interfaces: psr/log, psr/simple-cache, and psr/event-dispatcher.

To try it with SQLite, install PHP 8.4+ with pdo_sqlite, then run:

composer require tommyknocker/pdo-database-class
<?php
require 'vendor/autoload.php';

use tommyknocker\pdodb\PdoDb;

$db = new PdoDb('sqlite', ['path' => ':memory:']);
$db->rawQuery('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
$id = $db->find()->table('users')->insert(['name' => 'Alice']);
$user = $db->find()->from('users')->where('id', $id)->getOne();
if ($user !== false) {
    echo $user['name'];
}

Rows are associative arrays by default. asObject() returns stdClass objects instead:

// get() returns an array of objects (or an empty array if no rows match)
$users = $db->find()->from('users')->asObject()->get();
foreach ($users as $user) {
    echo $user->name;
}

// getOne() returns an object, or false if no row matches
$user = $db->find()->from('users')->where('id', $id)->asObject()->getOne();
if ($user !== false) {
    echo $user->name;
}

Why PDOdb

Compared with raw PDO. Queries are method calls, parameters are bound for you, and helpers cover dates, JSON, aggregates, and strings. The SQL that reaches the server still follows that database's dialect.

Compared with Eloquent or Doctrine. There is no framework to adopt and no ORM unless you want the optional ActiveRecord layer. You can drop to raw SQL. Two things those libraries do not include: query advice grounded in the database plan, and a terminal dashboard for a connection you have already configured.

Several databases in one project. The same builder calls target MySQL, MariaDB, PostgreSQL, SQLite, SQL Server, and Oracle. Where the SQL itself differs, the dialect guide says so.

Understand a slow query with your model

You already know which query is slow. The open question is whether to change a filter, a join, an index, or nothing. Start with the plan PDOdb can read. That call does not use a network.

$analysis = $db->find()
    ->from('orders')
    ->where('status', 'pending')
    ->orderBy('created_at', 'DESC')
    ->limit(50)
    ->explainAdvice();

foreach ($analysis->recommendations as $recommendation) {
    echo $recommendation->message . "\n";
}

A full scan plus a temporary sort suggests an index on the filter columns, then the sort columns. When that index already exists, the advice says a new one is not indicated. SQL Server does not expose a verified plan through PDO, and a parameterized Oracle EXPLAIN is unavailable. Those results say the plan is missing. They do not invent one.

When you want an explanation of that same query, send the collected plan to your model:

$advice = $db->find()
    ->from('orders')
    ->where('status', 'pending')
    ->orderBy('created_at', 'DESC')
    ->limit(50)
    ->explainAiAdvice();

echo $advice->aiAnalysis;

PDOdb collects the available plan, the columns, and the existing indexes, then makes one request to the provider configured for your application. You get an explanation and a hypothesis. PDOdb does not create the index or run the model's SQL. Details: query-advice limitations.

On the included SQLite fixture the plan before a matching index looked like this:

SCAN orders
USE TEMP B-TREE FOR ORDER BY

After the index was applied in that fixture, the same ordered page used the index:

SEARCH orders USING INDEX idx_orders_status_created (status=?)

The median SELECT on that synthetic database moved from 4.6860 ms to 0.0200 ms. That is a local measurement of the fixture, not a production promise. A third case in the same demo needs no new index: the existing one already matches the filter and the order. Walkthrough, setup, and the three cases: Understand and improve a query with AI.

In an application. Call explainAiAdvice() on the PdoDb instance you already use. Put the provider, key, and model in that process environment. Configuration reference.

Offline demo, no API key. A Composer installation places the package under vendor/tommyknocker/pdo-database-class/; it does not create examples/ in your project root. To run the demo from a repository checkout, use:

composer install
php examples/07-performance/05-ai-query-advice.php

The command builds 100,000 synthetic orders in memory, prints real SQLite plans, and checks that each reviewed index change preserves the result.

Capabilities

Each item below is implemented in the library and documented on its own page.

Queries

Writes and schema

Speed and scale

Application code

Tools

  • AI query advice from the PHP call, plus CLI reports
  • Optional MCP server so an editor can read the development schema
  • Terminal dashboard (pdodb ui) for a database configured for the CLI
  • CLI for migrations, seeds, outbox worker (work, status, list, retry, purge), dumps, users, models, and a SQL REPL

Work with JSON the same way on every database

The helper calls stay the same. Each dialect receives its own JSON SQL.

<?php
require 'vendor/autoload.php';

use tommyknocker\pdodb\helpers\Db;
use tommyknocker\pdodb\PdoDb;

$db = new PdoDb('sqlite', ['path' => ':memory:']);
$db->rawQuery('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, meta TEXT)');

$db->find()->table('users')->insert([
    'name' => 'John',
    'meta' => Db::jsonObject(['city' => 'NYC', 'age' => 30]),
]);

$users = $db->find()
    ->from('users')
    ->select([
        'name',
        'city' => Db::jsonGet('meta', ['city']),
    ])
    ->where(Db::jsonPath('meta', ['age'], '>', 25))
    ->get();

foreach ($users as $user) {
    echo $user['name'] . ' ' . $user['city'] . PHP_EOL;
}

More JSON operations: create and query JSON.

Requirements

  • PHP 8.4 or newer
  • mbstring and PDO, plus the extension for each database you connect to: pdo_mysql, pdo_pgsql, pdo_sqlite, pdo_sqlsrv (Microsoft ODBC Driver), or pdo_oci
  • Compatibility targets: MySQL 5.7+ / MariaDB 10.3+, PostgreSQL 9.4+, SQLite 3.38+, SQL Server 2019+ / Azure SQL, Oracle 12c+. Individual features may need a newer server. These targets are not a promise that every historical version is still covered or still supported by its vendor.

Database test coverage

CI runs the database suites against:

Database CI version
MySQL 8.0
MariaDB 11.2
PostgreSQL 16
SQLite Runner's bundled version
SQL Server 2022
Oracle XE 21

SQLite JSON support:

sqlite3 :memory: "SELECT json_valid('{}')"

1 means JSON is available.

Installation

composer require tommyknocker/pdo-database-class

vendor/bin/pdodb init writes a connection config (.env or config/db.php) and can create migration and model directories. Full option list: CLI tools. Connection arrays, pooling, and read/write splitting: configuration.

Documentation and examples

Start with the documentation index. Guides are grouped into getting started, the query builder, JSON, advanced features, errors, helpers, and the API reference. A short path for a first connection: installation, first connection, hello world.

Find methods in the API reference and database-specific behavior in dialect differences.

Coming from raw PDO or Eloquent: migration guide. Upgrading from 2.x: UPGRADE.md. Common failures: troubleshooting.

The examples are included under vendor/tommyknocker/pdo-database-class/examples/ in the Composer package and are also available in a repository checkout. Example catalog.

# From the repository root
php examples/01-basic/02-simple-crud.php

# MySQL (update examples/config.mysql.php with your credentials)
PDODB_DRIVER=mysql php examples/01-basic/02-simple-crud.php

To check all examples on the available databases, also from the repository root:

./scripts/test-examples.sh

Frequently Asked Questions

Is PDOdb an ORM? It is a query builder with an optional ActiveRecord layer.

Can I use raw SQL? Yes. Use rawQuery() or the raw SQL API.

Can I use it with a framework? Yes. PDOdb has no framework dependency and can be used in an existing PHP application.

Does it support transactions? Yes, including savepoints for nested transactions. See transactions.

Testing

./vendor/bin/phpunit
./vendor/bin/phpunit --testsuite "MySQL Tests"
./vendor/bin/phpunit --coverage-html coverage

MySQL and MariaDB expect a server on localhost:3306, PostgreSQL on 5432, SQL Server on 1433, and Oracle on 1521 (pdo_oci and Oracle Instant Client). SQLite uses :memory:.

Contributing

Open an issue before a new feature, follow PSR-12, and add tests. Dialect-specific behavior belongs in that dialect's test directory. See CONTRIBUTING.md.

Development and CI use composer install so PHPStan and the other development tools follow composer.lock. The lock file does not constrain applications that require PDOdb as a package. Update dependencies with composer update and include the lock file in that change.

License

MIT. See LICENSE.

Acknowledgments

Inspired by ThingEngineer/PHP-MySQLi-Database-Class and the Yii2 framework.