pfilsx/postgresql-doctrine
Adds PostgreSQL-specific types, functions, and platform support to Doctrine DBAL, enabling native arrays, JSON/JSONB, hstore, and other rich Postgres features in your entities. A lightweight bridge for projects needing more than Doctrine's built-in Postgres support.
This is a Doctrine DBAL/ORM/Migrations extension, not an Eloquent one. If your Laravel app is Eloquent-only, jsonb, text[], and enums already work through $casts and raw migrations — install this only when you actually speak Doctrine (via laravel-doctrine/orm, a standalone DriverManager connection, or doctrine/migrations for a bounded context).
composer require pfilsx/postgresql-doctrine
Register the types before anything touches metadata or the schema manager. With laravel-doctrine/orm, that means config/doctrine.php:
'custom_types' => [
'jsonb' => Pfilsx\PostgreSQLDoctrine\Types\JsonbType::class,
'text[]' => Pfilsx\PostgreSQLDoctrine\Types\TextArrayType::class,
'my_enum' => Pfilsx\PostgreSQLDoctrine\Types\EnumType::class,
],
For a plain DBAL connection (queue worker, reporting module, artisan command):
use Doctrine\DBAL\Types\Type;
Type::addType('jsonb', JsonbType::class);
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('jsonb', 'jsonb');
Where to look first: the package's src/Types/ directory (that's the real API surface — the README is thin for a 3-star package), then its tests, which show the exact registered type names and DQL function signatures. First use case: an entity or migration with a jsonb column plus a text[] tag column, then migrations:diff to confirm the platform emits JSONB and TEXT[] instead of falling back to JSON/TEXT.
Bounded-context Doctrine inside a Laravel app. Keep Eloquent for the app and wire this package into one reporting/analytics module with its own EntityManager. Boot the type registrations in a dedicated service provider's register() (not boot()) so they land before any console command or migration runs.
Type registration is two-sided. Type::addType() teaches DBAL to convert PHP ⇄ SQL; registerDoctrineTypeMapping() teaches the reverse — schema introspection. Miss the second and migrations:diff sees an unknown type and proposes dropping your column.
Enum migrations need hand-written SQL. Doctrine's diff won't emit CREATE TYPE. Use preUp() / addSql():
public function up(Schema $schema): void
{
$this->addSql("CREATE TYPE order_status AS ENUM ('pending','paid','shipped')");
$this->addSql("CREATE TABLE orders (id uuid PRIMARY KEY, status order_status NOT NULL)");
}
Down migrations must DROP TYPE order_status after the table.
DQL functions for aggregates. Register array_agg, string_agg, jsonb_agg, and PostgreSQL operators (ILIKE, @>, ?) on the ORM config so they're usable in DQL:
$config->addCustomStringFunction('array_agg', ArrayAgg::class);
Then SELECT array_agg(o.id) FROM Order o returns a real PHP array if the array type is registered — otherwise you get a raw {1,2,3} string.
Hybrid read models. A common fit: write with Eloquent, read with Doctrine + jsonb_agg for dashboards where you'd otherwise hand-roll DB::select with json_agg. You get typed hydration and no string SQL in the app layer.
Introspection safety net. If you use doctrine/dbal to diff a schema that Laravel migrations built, register all PG types the package provides (jsonb, json, arrays, inet, cidr) even if you don't use them — otherwise the diff will try to convert columns you never intended to touch.
EntityManager creation and before any schemaManager call. A Type::addType() inside a controller is too late; you'll get "Unknown column type" or a silently wrong diff.$casts = ['meta' => 'array'] and the Doctrine jsonb type share nothing. Don't expect one to configure the other.ADD VALUE can't run in a transaction on older PostgreSQL (<12). Doctrine migrations wrap everything in a transaction by default — set transactional: false on that migration or split enum extensions into their own file.varchar[] and text[] are different types; if the platform emits one and the DB has the other, every diff shows a phantom ALTER. Pin the exact type name and verify with \d+ table in psql.jsonb is mapped, a legacy json column introspects as unknown and the diff proposes a rewrite (with a table lock).jsonb_agg, jsonb_object_agg, and @> all assume a reasonably modern PostgreSQL. Check the package's composer.json constraints, then check your target server — this is the kind of package where the version matrix is implied by the test suite, not stated.composer.json and read the diff when you bump. martin-georgiev/postgresql-for-doctrine is the more established alternative if you hit a wall.jsonb mapping.$schemaManager->introspectTable('orders') and inspect each column's getType()->getName(). That tells you immediately whether the mapping (not your entity) is at fault.php artisan doctrine:migrations:diff --dry-run (or pipe SQL to --stdout) before applying. A wrong type mapping here produces destructive ALTER/DROP statements, not errors.How can I help you explore Laravel packages today?