pfilsx/postgresql-doctrine-bundle
Symfony bundle that integrates PostgreSQL-specific Doctrine DBAL types into your application, so you can map native Postgres data types in entities and queries while keeping standard Doctrine conventions. A small helper for projects running Doctrine on PostgreSQL.
Install (the bundle depends on doctrine/dbal, doctrine/doctrine-migrations-bundle — they will be pulled in if missing). Pin to ^0.2.2; earlier 0.2.x releases have a JSON type-registration bug and a DoctrineBundle compatibility break (see Gotchas):
composer require pfilsx/postgresql-doctrine-bundle:^0.2.2
Register the bundle. With Symfony Flex it is auto-enabled. Otherwise add it manually to config/bundles.php:
Pfilsx\PostgreSQLDoctrineBundle\PostgreSQLDoctrineBundle::class => ['all' => true],
If you are not on Symfony at all (e.g. Laravel with a Doctrine bridge), skip this step: the service wiring — including the ConnectionFactoryDecorator — is Symfony-only, so you must register the DBAL types yourself in your app's Doctrine config or via Type::addType() in a service provider.
Wire up the DBAL types in config/packages/doctrine.yaml (the bundle exposes PostgreSQL-specific types such as array, enum, hstore, JSONB variants — the exact list is in src/DBAL/Types/ after install):
doctrine:
dbal:
types:
text_array: Pfilsx\PostgreSQLDoctrineBundle\DBAL\Types\TextArrayType
integer_array: Pfilsx\PostgreSQLDoctrineBundle\DBAL\Types\IntegerArrayType
jsonb: Pfilsx\PostgreSQLDoctrineBundle\DBAL\Types\JsonbType
First use case: add a PostgreSQL text[] column to an entity, then rely on the bundle's migration base class to emit the DDL, since Doctrine's vanilla schema tool does not understand arrays/enums.
#[ORM\Column(type: 'text_array', nullable: true)]
private ?array $tags = [];
If you have never used it before, open the installed package under vendor/pfilsx/postgresql-doctrine-bundle/ and read src/DBAL/Types and src/Migrations first — the README is thin and the code is the real documentation.
Custom entities with PostgreSQL-native columns. Use the registered types (*_array, jsonb, hstore, etc.) directly on ORM columns. Convert at the PHP boundary — the DBAL type does the {...} array literal encoding/decoding for you, so your entities just see array/object.
Extended migration base class. Instead of Doctrine\Migrations\AbstractMigration, extend the bundle's base (in Pfilsx\PostgreSQLDoctrineBundle\Migrations) when a migration needs PostgreSQL-only syntax that the schema diff cannot generate:
use Pfilsx\PostgreSQLDoctrineBundle\Migrations\AbstractMigration;
final class Version20240101 extends AbstractMigration
{
public function up(Schema $schema): void
{
// create the native enum first
$this->addSql("CREATE TYPE status AS ENUM ('draft','live','archived')");
// then any helper the base class offers (array/enum column helpers)
$this->addSql("ALTER TABLE post ADD COLUMN state status NOT NULL DEFAULT 'draft'");
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE post DROP COLUMN state');
$this->addSql('DROP TYPE status');
}
}
Check the base class for convenience methods (addEnum, addArrayColumn, etc.) before writing raw SQL — they exist to keep migrations idempotent and diff-friendly.
Schema tool integration. Point doctrine.dbal.types at the bundle's types (see above) so doctrine:migrations:diff and doctrine:schema:validate understand the columns. Otherwise the schema tool will keep trying to drop or overwrite a column it cannot introspect.
Mix-and-match with vanilla Doctrine. The bundle does not replace the default Doctrine DBAL — you can use custom types only on the columns that need them and leave everything else standard. That is the safest adoption path: introduce one array column, verify migrations, then expand.
Testing. Use a real PostgreSQL instance (Testcontainers, docker compose, or a CI service). The custom types cannot be exercised by SQLite/MySQL, so tests against those drivers will silently diverge and are not a meaningful check.
^0.2.2, not ^0.2. v0.2.2 sets ConnectionFactoryDecorator's parent class to DoctrineBundle's ConnectionFactory for compatibility with current doctrine/doctrine-bundle. On older 0.2.x the decorator can blow up at container compile/boot on a modern DoctrineBundle — an upgrade that looks unrelated (a composer update) can take the app down. v0.2.2 is also the first release in a long gap, so check what your lockfile actually resolved to.json/jsonb type you had registered yourself once the bundle booted (or on a second kernel/connection). If you must stay on ≤0.2.1, assert after boot that Type::getType('json') is still your class — the failure mode is a silent change of serialization, not an exception.vendor/. Consider whether you could copy the 2–3 type classes you actually need into src/DBAL/Types and drop the dependency — the DBAL type interface is stable, and the bundle itself is tiny.composer.json constraint against your doctrine/dbal major version (2.x vs 3.x vs 4.x; the type registration API changed), and run composer why-not pfilsx/postgresql-doctrine-bundle 0.2.2 if install fails.CREATE TYPE first (or use ALTER TYPE ... ADD VALUE for appends only). Split type creation from table alteration if the DDL is large.CHECK constraints, and GENERATED columns often appear as "down" diffs. Always inspect doctrine:migrations:diff output before applying — never run it unchecked.config/bundles.php gives you "class not found" from the DBAL type registration, which is a confusing error. Confirm the bundle is loaded with bin/console debug:container --tag=doctrine.dbal.connection_factory or check bin/console about.config/packages/doctrine.yaml. If you are overriding migration behavior, extend the bundle's base class rather than the Doctrine one — otherwise you lose the PostgreSQL helpers on that specific migration.doctrine.yaml does not match the getName() of the class you registered. Dump the types config and grep the class for getName().How can I help you explore Laravel packages today?