Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Postgres Types Bundle Laravel Package

garak/doctrine-postgres-types-bundle

Symfony bundle that registers PostgreSQL-specific Doctrine DBAL types, so you can map Postgres arrays, JSONB, and similar column types directly to PHP values in your entities without writing custom type classes.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require garak/doctrine-postgres-types-bundle

Enable it (Flex usually does this for you):

// config/bundles.php
return [
    // ...
    Garak\DoctrinePostgresTypesBundle\GarakDoctrinePostgresTypesBundle::class => ['all' => true],
];

Where to look first:

  1. The bundle's DI extension (DependencyInjection/*Extension.php) and any CompilerPass — this is where the bundle typically calls Type::addType() / registerDoctrineTypeMapping(). That tells you which type names exist and whether registration is automatic.
  2. The DBAL/Types (or Doctrine/DBAL/Types) directory — one class per Postgres type. Read convertToDatabaseValue, convertToPHPValue, and getSQLDeclaration to learn the PHP <-> Postgres contract precisely.
  3. The README mapping table, if present — quickest way to see the supported set (typically inet, cidr, macaddr, hstore, jsonb, uuid, range types, tsvector, array types, etc.).

Sanity-check boot and registration:

php bin/console doctrine:query:sql "SELECT 1::inet"
php -r 'require "vendor/autoload.php"; Doctrine\DBAL\Types\Type::hasType("inet") ?: exit(1);'

First use case — a column Doctrine doesn't ship a type for, say INET:

#[ORM\Entity]
class Login
{
    #[ORM\Column(type: 'inet', nullable: true)]
    private ?string $remoteIp = null;
}

Then run doctrine:schema:validate / inspect the generated SQL in a migration. If INET shows up, the bundle is wired correctly and you can start mapping the rest of your Postgres-native columns.

Implementation Patterns

Rely on bundle registration, override only when needed. The bundle is meant to make the type name (inet, hstore, …) usable directly in #[ORM\Column(type: ...)]. Only fall back to an explicit doctrine.yaml entry if the type isn't registered:

# config/packages/doctrine.yaml
doctrine:
    dbal:
        types:
            inet: Garak\DoctrinePostgresTypesBundle\DBAL\Types\InetType

(Confirm the class path from the bundle source before copying — aliasing here shadows the bundle and is easy to get wrong.)

Pick the right mapping for the shape you need. A common decision is JSONB vs Postgres array:

  • jsonb — heterogeneous/nested data, want @> containment queries and GIN indexes.
  • native array (text[], int[]) — homogeneous lists you'll query with = ANY(...), @>, &&, and index with GIN.
  • hstore — legacy key/value; prefer jsonb for new work unless you need hstore operators.

Migrations. Doctrine's schema tool understands a custom type only if getSQLDeclaration() is correct. Inside a migration, pass the type name and expect the DBAL platform to render it:

public function up(Schema $schema): void
{
    $this->addSql('ALTER TABLE login ADD remote_ip INET DEFAULT NULL');
}

For diff-heavy flows, prefer writing the raw ALTER for these columns rather than relying on auto-diff (see gotchas).

Query with native SQL for type-specific operators. Custom DBAL types do not add DQL functions, so use NativeQuery + ResultSetMapping when you need <<, @>, ?, ~, or range operators:

$rsm = new ResultSetMappingBuilder($em);
$rsm->addRootEntityFromClassMetadata(Login::class, 'l');
$query = $em->createNativeQuery(
    'SELECT l.* FROM login l WHERE l.remote_ip << :net',
    $rsm
);
$query->setParameter('net', '10.0.0.0/8');

Value-object wrapping. Many of these types round-trip as strings/arrays. If you want a VO (e.g. IpAddress), write a small Type that delegates to the bundle's class and casts in convertToPHPValue. This keeps your domain clean while reusing the SQL declaration and database-value conversion.

Test against a real Postgres. SQLite/MySQL will not exercise these types; INET, HSTORE, ranges, etc. don't exist there. Wire a Dockerized Postgres in CI and run functional tests that round-trip each mapped type.

Gotchas and Tips

  • Schema diffs lie about custom types. Doctrine's comparator often produces perpetual ALTER diffs for custom types unless the type implements requiresSQLCommentHint() (DBAL 3) and your getSQLDeclaration() matches what Postgres reports back. If you see "column already exists" style churn, that's why — a common fix is a comment hint or dropping the column from diff scope in migrations.
  • DBAL 2 vs 3 API drift. Type::getName() was dropped in DBAL 3 in favour of name constants, and getSQLDeclaration()'s signature changed (array &$column). Check the doctrine/dbal version constraint in the bundle's composer.json before upgrading your own DBAL — this package is small and may lag.
  • Only Postgres platforms. The SQL declarations assume Postgres. Running against another driver (e.g. in a test environment) yields invalid SQL. Guard with platform instanceof PostgreSQLPlatform checks or a dedicated test env pinned to Postgres.
  • Type-name collisions. Names like jsonb, uuid, and array are registered by other bundles and by application code. Whichever Type::addType() runs last wins. If you have a custom uuid type, verify it isn't being shadowed — inspect Type::getTypes() in a console command.
  • Null vs empty is not the same. For hstore/arrays/JSON, convertToPHPValue(null) must be handled separately from '[]' / '{}'. Test both; a lot of subtle bugs live here.
  • DQL doesn't know your types. WHERE x = :y works, but type-specific operators and functions require NativeQuery or a custom DQL function. Don't expect ANY() or @> to be available out of the box.
  • Migrations + addColumn. Do not let the schema diff author these columns. Write the DDL yourself (INET, HSTORE, INT4RANGE, …) so you control defaults, indexes (GIN/USING gist), and operator classes.
  • Extension point. Everything is a plain Doctrine Type. Subclass the bundle's class, override convertToPHPValue/convertToDatabaseValue for a VO, and register it under a new name — that's the cleanest way to customize without forking.
  • Maintenance risk. With ~3 stars and 0 known dependents, treat this as vendorable code: read the type classes (there aren't many), copy the ones you use into your app's src/Doctrine/DBAL/Types/, and drop the dependency if you want to decouple from the bundle's release cadence and DBAL version pins. LGPL-3.0 permits this within a larger application, but check your legal guidance for redistribution scenarios.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels