Skip to content

feat: make Doctrine DBAL optional via a Connection port (DBAL + PDO adapters) - #2

Merged
Th3Mouk merged 1 commit into
mainfrom
feat/optional-dbal-pdo
Jun 15, 2026
Merged

feat: make Doctrine DBAL optional via a Connection port (DBAL + PDO adapters)#2
Th3Mouk merged 1 commit into
mainfrom
feat/optional-dbal-pdo

Conversation

@Th3Mouk

@Th3Mouk Th3Mouk commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Why

The core engine only needs to run statements, fetch rows and open a transaction — a tiny surface. Expressing that as a port frees Core from any database library, so a project without Doctrine can drive PostgreSQL materialized views over a bare PDO connection, while Doctrine stays the recommended, natively-supported backend.

What

  • Core\Database portConnection (5 methods), ParameterType (enum), DatabaseException (carries the SQLSTATE, so 42P01/3F000 missing-dependency handling stays backend-agnostic). The whole synchronous engine runs on this; Core no longer depends on Doctrine.
  • Two adapters
    • Dbal\DbalConnection — wraps a Doctrine DBAL connection; keeps primary/replica routing, middlewares and profiling; maps DBAL\ExceptionDatabaseException.
    • Pdo\PdoConnection — wraps a bare PDO handle (pdo_pgsql); no extra Composer dependency.
  • Manager factories — new forDriver(Connection) and forPdo(\PDO); forConnection(DBAL\Connection) is unchanged and now wraps the connection in DbalConnection internally.
  • IdentifierQuoter is PostgreSQL-native (no DBAL platform), byte-identical output.
  • composer.jsondoctrine/dbal moves requirerequire-dev + suggest; the core requires only php and psr/log. ext-pdo_pgsql is suggested for the PDO path.

Backward compatibility

Fully BC. forConnection(), MaterializedViewMigrationSql, RefreshTargetResolver (still returns a DBAL Connection) and AsyncRefreshRequest are unchanged, so existing Doctrine code and the Symfony bundle need no changes. The DBAL type names that remain in Core (the forConnection convenience and the async-refresh resolver contract) are never loaded on the PDO path.

Validation

All CI gates green, plus the new PDO adapter exercised against a real PostgreSQL:

Gate Result
cs:check 0 issues
stan No errors
test:unit 552 tests
test:pg 12 tests (incl. PdoConnectionTest against a live PostgreSQL)

New tests: tests/Unit/Dbal/DbalConnectionTest (delegation, ParameterType mapping, exception→SQLSTATE, primary/replica routing) and tests/Integration/Pdo/PdoConnectionTest (queries, typed params, transactional commit/rollback, SQLSTATE).

Docs

README, getting-started, architecture, design-rationale (decision #1 reframed), a refresh/locking note, a new docs/guide/connection-backends.md, and CHANGELOG [1.2.0].

The core engine now talks to PostgreSQL through a small
Core\Database\Connection port instead of Doctrine DBAL directly, so the
library runs on Doctrine DBAL or a bare PDO connection. Doctrine is
optional and natively supported.

- Core\Database: Connection (port), ParameterType (enum) and
  DatabaseException, which carries the SQLSTATE so missing-dependency
  handling stays backend-agnostic.
- Dbal\DbalConnection: adapter over Doctrine DBAL — keeps primary/replica
  routing, middlewares and profiling.
- Pdo\PdoConnection: adapter over a bare PDO handle (pdo_pgsql), with no
  extra Composer dependency.
- MaterializedViewManager gains forDriver(Connection) and forPdo(\PDO);
  forConnection(DBAL\Connection) is unchanged and now wraps the connection
  in DbalConnection internally.
- IdentifierQuoter is PostgreSQL-native (no DBAL platform) with
  byte-identical output.
- doctrine/dbal moves from require to require-dev + suggest; the core
  requires only php and psr/log.

Fully backward compatible: existing Doctrine code and the Symfony bundle
need no changes — forConnection, MaterializedViewMigrationSql,
RefreshTargetResolver and AsyncRefreshRequest are unchanged.
@Th3Mouk
Th3Mouk force-pushed the feat/optional-dbal-pdo branch from 2cc334a to 9e0338a Compare June 13, 2026 12:05
@Th3Mouk
Th3Mouk merged commit 41482cd into main Jun 15, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant