dorpmaster/dbal-amphp-postgres

PostgreSQL-only Doctrine DBAL driver backed by an AMPHP transport.

Maintainers

Package info

github.com/Dorpmaster/dbal-amphp-postgres

Homepage

Issues

pkg:composer/dorpmaster/dbal-amphp-postgres

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

1.2.0 2026-07-12 17:10 UTC

This package is auto-updated.

Last update: 2026-07-12 17:15:02 UTC


README

PostgreSQL-only Doctrine DBAL driver backed by an AMPHP transport.

The library keeps the Doctrine DBAL and Doctrine ORM programming model synchronous while moving database I/O to a fiber-compatible amphp/postgres transport. It targets applications that want PostgreSQL-specific behavior, Doctrine integration, and predictable transaction ownership without introducing an async-native ORM.

Key features

  • PostgreSQL-only driver with a real amphp/postgres transport
  • supported transport fixed to ext-pgsql
  • fiber-compatible I/O behind the standard Doctrine DBAL API
  • Doctrine ORM baseline support, including EntityManager, UnitOfWork, DQL, QueryBuilder, and validated lazy-loading scenarios
  • Doctrine Migrations-compatible PostgreSQL metadata introspection, including duplicate-column-alias handling
  • transaction pinning on one physical PostgreSQL connection
  • strict parameter conversion with DBAL-compatible safe scalar string support for INTEGER and BOOLEAN
  • explicit close and cleanup semantics for long-running processes
  • lightweight optional observability hooks

Quick start

Install the package with Composer:

composer config allow-plugins.cweagans/composer-patches true
composer require dorpmaster/dbal-amphp-postgres

The package declares a Composer Patches dependency patch for amphp/postgres. Composer plugins must stay enabled during install and update, otherwise the compatibility patch is not applied.

Supported transport: ext-pgsql.

The package intentionally does not support ext-pq / pecl-pq. The driver forces the ext-pgsql connector even if pq is installed in the PHP runtime.

Configure Doctrine DBAL with the custom driver and wrapper:

<?php

declare(strict_types=1);

use Dorpmaster\DbalAmpPostgres\Driver\AmpPgDbalConnection;
use Dorpmaster\DbalAmpPostgres\Driver\AmpPgDriver;
use Doctrine\DBAL\DriverManager;

$connection = DriverManager::getConnection([
    'host' => '127.0.0.1',
    'port' => 5432,
    'dbname' => 'app',
    'user' => 'app',
    'password' => 'secret',
    'driverClass' => AmpPgDriver::class,
    'wrapperClass' => AmpPgDbalConnection::class,
]);

AmpPgDbalConnection must be configured as wrapperClass for deterministic cleanup of driver resources and the underlying connection pool.

Connection params may safely contain spaces, equals signs, single quotes, and backslashes in credentials and application name. Pass them as structured params; do not manually interpolate credentials into a DSN string in user code.

Example usage

Doctrine ORM bootstrap

<?php

declare(strict_types=1);

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;

$ormConfig = ORMSetup::createAttributeMetadataConfig(
    paths: [__DIR__ . '/src/Entity'],
    isDevMode: false,
);

$entityManager = new EntityManager($connection, $ormConfig);

Simple query

<?php

declare(strict_types=1);

$rows = $connection->fetchAllAssociative(
    'SELECT id, email FROM users ORDER BY id'
);

Parameter conversion

Prepared statements remain the recommended path. The driver keeps parameter conversion strict, but accepts limited canonical scalar strings for DBAL compatibility:

<?php

declare(strict_types=1);

$statement = $connection->prepare('SELECT ?::int AS id, ?::bool AS active');
$statement->bindValue(1, '123', \Doctrine\DBAL\ParameterType::INTEGER);
$statement->bindValue(2, 'false', \Doctrine\DBAL\ParameterType::BOOLEAN);

INTEGER accepts integer literals such as "123", "-123", and "0". BOOLEAN accepts only bool, 0 / 1, and canonical "true" / "false" string forms. The driver does not use PHP loose casting, so ambiguous values fail explicitly.

Compatibility quoting

quote() is supported for Doctrine DBAL compatibility, but prepared statements remain the recommended path for passing values:

<?php

declare(strict_types=1);

$literal = $connection->quote("O'Reilly");

Under the hood, quote() performs a PostgreSQL round-trip through quote_literal(...), so avoid it in hot paths when a bound parameter would work.

Doctrine Migrations support

1.2.0 adds the metadata compatibility layer needed by Doctrine's PostgreSQL schema introspection path. The bundled amphp/postgres patch preserves:

  • positional rows for fetchNumeric()
  • ordered column names for getColumnName()
  • associative semantics for duplicate aliases

This closes the duplicate-alias regression behind errors such as Undefined array key 10 in Doctrine Migrations and related schema commands.

The package keeps a normal Composer semver constraint for amphp/postgres, applies the patch automatically through cweagans/composer-patches, and relies on fail-fast installation if upstream changes become incompatible with the patch context.

Once upstream exposes an equivalent public API, the compatibility patch will be removed.

Transaction

<?php

declare(strict_types=1);

$connection->beginTransaction();

try {
    $connection->executeStatement(
        'INSERT INTO audit_log (message) VALUES (?)',
        ['created user'],
    );

    $connection->commit();
} catch (\Throwable $e) {
    if ($connection->isTransactionActive()) {
        $connection->rollBack();
    }

    throw $e;
}

Known limitations

  • EntityManager is not concurrency-safe and must not be shared across parallel fibers
  • streaming results are not supported
  • the PostgreSQL type matrix is intentionally limited to the documented subset
  • installation and updates must allow the cweagans/composer-patches Composer plugin so the bundled amphp/postgres compatibility patch can be applied
  • root application Composer config must allow the plugin, for example:
{
    "config": {
        "allow-plugins": {
            "cweagans/composer-patches": true
        }
    }
}
  • only the ext-pgsql transport is supported; ext-pq / pecl-pq are outside the support contract
  • lastInsertId() is available only inside an active transaction on a pinned PostgreSQL connection
  • quote() is supported as a DBAL compatibility API, but it performs a PostgreSQL round-trip and should not replace prepared statements in hot paths
  • parameter conversion stays strict and does not use PHP loose casting; only safe integer literals and canonical boolean values are accepted for typed scalar parameters
  • after a SQL error inside a transaction, explicit rollback is required before more SQL can succeed on that connection

Documentation

Project status

The library is published as a public OSS package with a documented PostgreSQL-only 1.2.x support contract.

License

MIT