ttpryg / database-migrator
Framework-agnostic PDO schema migration runner with tracking and rollback for PHP 8.1+.
Requires
- php: ^8.1
- ext-pdo: *
Requires (Dev)
- laravel/pint: ^1.20
- phpstan/phpstan: ^2.3
- phpunit/phpunit: ^10.0
- rector/rector: ^2.6
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-20 13:28:05 UTC
README
A framework-agnostic PDO schema migration runner for PHP 8.1+ with migration tracking and rollback. It has no framework dependencies and works with any module that owns its own tables and migration files.
โจ Features
- PDO Only: Works with MySQL, MariaDB, SQLite, and any PDO driver.
- Banker Tracked: Records applied migrations in a tracker table so
migrate()can be run repeatedly and safely. - Rollback Support: Reverts the most recent migrations through each
migration's
down()method. - Configurable: Migration directory and tracker table name are supplied by the caller, so multiple modules can share one database without collisions.
- Baseline Friendly:
markAllAsMigrated()records migrations without executing them, useful when a schema snapshot already reflects the latest schema. - Framework Agnostic: No Laravel, Symfony, or other framework dependency.
๐ฆ Installation
composer require ttpryg/database-migrator
Requirements: PHP 8.1+,
ext-pdo, and a configured PDO connection.
๐ Usage
1. Create a Migration
Each migration file must return an instance of Migration. Files are executed
in filename (alphabetical) order, so use a sortable prefix:
<?php // database/migrations/202610200001_create_audit_logs.php declare(strict_types=1); use Ttpryg\DatabaseMigrator\Migration; return new class extends Migration { public function up(PDO $pdo): void { $pdo->exec('CREATE TABLE audit_logs (id INTEGER PRIMARY KEY, event_name VARCHAR(100))'); } public function down(PDO $pdo): void { $pdo->exec('DROP TABLE audit_logs'); } };
Migrations that cannot be reverted safely may omit down(). The default
implementation throws MigrationException, so rollback() fails loudly
instead of pretending the change was undone.
2. Run Migrations
use Ttpryg\DatabaseMigrator\MigrationRunner; $runner = new MigrationRunner( $pdo, __DIR__.'/database/migrations', 'audit_engine_migrations' ); $executed = $runner->migrate(); $applied = $runner->appliedMigrations();
3. Roll Back
$rolledBack = $runner->rollback(); // revert the latest migration $rolledBack = $runner->rollback(3); // revert the latest three migrations
4. Baseline an Existing Schema
When a schema snapshot already reflects the latest schema, record the migrations as applied without executing them:
$runner->markAllAsMigrated();
5. Renamed Migrations
If a migration file was renamed in a deployed environment, declare the old name so it is not executed twice:
public function previouslyRecordedAs(): array { return ['001_create_audit_logs']; }
๐๏ธ Tracker Table
The runner creates the tracker table automatically by default:
CREATE TABLE IF NOT EXISTS <tracker_table> ( migration VARCHAR(191) NOT NULL PRIMARY KEY, applied_at TIMESTAMP NULL );
Choose a module-specific tracker name (for example
audit_engine_migrations) when several modules share a database.
Disabling Automatic Tracker Table Creation
In environments with restricted permissions where CREATE TABLE is not
permitted for the application database user, pass autoCreateTrackerTable: false:
$runner = new MigrationRunner( $pdo, __DIR__.'/database/migrations', 'audit_engine_migrations', autoCreateTrackerTable: false );
You can explicitly create the tracker table during installation or deployment via:
$runner->ensureTrackerTable();
MySQL/MariaDB note: DDL statements are auto-commit. A failure in the middle of a migration file cannot be rolled back automatically, so write migrations to be idempotent where practical (for example
CREATE TABLE IF NOT EXISTS).
๐งช Development
composer install
composer test
composer analyse
composer fix:check
๐ License
MIT License.