PHPackages                             sad\_spirit/pg\_gateway - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. sad\_spirit/pg\_gateway

ActiveLibrary[Database &amp; ORM](/categories/database)

sad\_spirit/pg\_gateway
=======================

Table Data Gateway for Postgres - auto-converts types, allows raw SQL, supports joins between gateways

v0.10.0(9mo ago)146BSD-2-ClausePHPPHP ^8.2CI passing

Since Sep 13Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/sad-spirit/pg-gateway)[ Packagist](https://packagist.org/packages/sad_spirit/pg_gateway)[ Docs](https://github.com/sad-spirit/pg-gateway/)[ RSS](/packages/sad-spirit-pg-gateway/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (8)Dependencies (6)Versions (11)Used By (0)

sad\_spirit/pg\_gateway
=======================

[](#sad_spiritpg_gateway)

[![Continuous Integration](https://github.com/sad-spirit/pg-gateway/actions/workflows/continuous-integration.yml/badge.svg?branch=master)](https://github.com/sad-spirit/pg-gateway/actions/workflows/continuous-integration.yml)[![Static Analysis](https://github.com/sad-spirit/pg-gateway/actions/workflows/static-analysis.yml/badge.svg?branch=master)](https://github.com/sad-spirit/pg-gateway/actions/workflows/static-analysis.yml)

This is a [Table Data Gateway](https://martinfowler.com/eaaCatalog/tableDataGateway.html) implementation built upon [pg\_wrapper](https://github.com/sad-spirit/pg-wrapper) and [pg\_builder](https://github.com/sad-spirit/pg-builder) packages.

Using those packages immediately allows

- Transparent conversion of PHP types to Postgres types and back;
- Writing parts of the query as SQL strings while later processing those parts as Nodes in the Abstract Syntax Tree.

Installation
------------

[](#installation)

Require the package with composer:

```
composer require sad_spirit/pg_gateway

```

Design goals
------------

[](#design-goals)

- Code generation is not necessary, default gateway implementations are useful as-is.
- Gateways are aware of the table metadata: columns, primary key, foreign keys.
- It is possible to cache the generated SQL, skipping the whole parsing/building process.
- API encourages building parametrized queries.
- Queries built by several Gateways can be combined via joins / `EXISTS()` / etc.

Usage example
-------------

[](#usage-example)

Assuming the following database schema

```
create schema example;

create table example.users (
    id integer not null generated by default as identity,
    login text not null,
    password_hash text not null,

    constraint users_pkey primary key (id)
);

create table example.roles (
    id integer not null generated by default as identity,
    name text not null,
    description text,

    constraint roles_pkey primary key (id)
);

create table example.users_roles (
    user_id integer not null,
    role_id integer not null,
    valid_from date,
    valid_to date,

    constraint users_roles_pkey primary key (user_id, role_id),
    constraint roles_users_fkey foreign key (user_id)
        references example.users (id)
        on delete cascade on update restrict,
    constraint users_roles_fkey foreign key (role_id)
        references example.roles (id)
        on delete cascade on update restrict
);
```

we can use default gateways and default builders to perform a non-trivial query to the above tables

```
use sad_spirit\pg_gateway\{
    TableLocator,
    builders\FluentBuilder
};
use sad_spirit\pg_wrapper\Connection;

$connection = new Connection('...');
$locator    = new TableLocator($connection);

$adminRoles = $locator->select('example.roles', fn(FluentBuilder $builder) => $builder
    ->operatorCondition('name', '~*', 'admin')
    ->returningColumns()
        ->except(['description'])
        ->replace('/^/', 'role_'));

$activeAdminRoles = $locator->select('example.users_roles', fn(FluentBuilder $builder) => $builder
    ->sqlCondition("current_date between coalesce(self.valid_from, 'yesterday') and coalesce(self.valid_to, 'tomorrow')")
    ->join($adminRoles) // defaults to joining on foreign key
    ->returningColumns(['valid_from', 'valid_to']));

$activeAdminUsers = $locator->select('example.users', fn(FluentBuilder $builder) => $builder
    ->returningColumns()
        ->except(['password_hash'])
        ->replace('/^/', 'user_')
    ->join($activeAdminRoles) // defaults to joining on foreign key
    ->orderBy('user_login, role_name')
    ->limit(5));

// Let's assume we want to output that list with pagination
echo "Total users with active admin roles: " . $activeAdminUsers->executeCount() . "\n\n";

foreach ($activeAdminUsers as $row) {
    print_r($row);
}

echo $activeAdminUsers->createSelectCountStatement()->getSql() . ";\n\n";
echo $activeAdminUsers->createSelectStatement()->getSql() . ';';
```

where the last two `echo` statements will output something similar to

```
select count(self.*)
from example.users as self, example.users_roles as gw_1, example.roles as gw_2
where gw_2."name" ~* $1::"text"
    and gw_1.role_id = gw_2.id
    and current_date between coalesce(gw_1.valid_from, 'yesterday') and coalesce(gw_1.valid_to, 'tomorrow')
    and gw_1.user_id = self.id;

select gw_2.id as role_id, gw_2."name" as role_name, gw_1.valid_from, gw_1.valid_to, self.id as user_id,
    self.login as user_login
from example.users as self, example.users_roles as gw_1, example.roles as gw_2
where gw_2."name" ~* $1::"text"
    and gw_1.role_id = gw_2.id
    and current_date between coalesce(gw_1.valid_from, 'yesterday') and coalesce(gw_1.valid_to, 'tomorrow')
    and gw_1.user_id = self.id
order by user_login, role_name
limit $2;
```

Documentation
-------------

[](#documentation)

For in-depth description of package features, visit [pg\_gateway manual](https://pg-gateway.readthedocs.io/).

Requirements
------------

[](#requirements)

`pg_gateway` requires at least PHP 8.2 with native [pgsql extension](https://php.net/manual/en/book.pgsql.php).

Minimum supported PostgreSQL version is 12.

It is highly recommended to use [PSR-6 compatible](https://www.php-fig.org/psr/psr-6/) cache in production, both for metadata lookup and for generated queries.

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance66

Regular maintenance activity

Popularity11

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~91 days

Recently: every ~72 days

Total

10

Last Release

152d ago

Major Versions

v0.10.0 → v1.0.0-beta2025-12-09

PHP version history (2 changes)v0.1.0PHP &gt;=7.4.0

v0.9.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/4b43550745afa89d33e4b93f8535fc31c93ac0a712d264c13cb8f8c62d9198c1?d=identicon)[sad-spirit](/maintainers/sad-spirit)

---

Top Contributors

[![sad-spirit](https://avatars.githubusercontent.com/u/4820288?v=4)](https://github.com/sad-spirit "sad-spirit (199 commits)")

---

Tags

ormphppostgrespostgresqlsqltable-data-gatewaydataormpostgresqlpostgressqlgatewaytable

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/sad-spirit-pg-gateway/health.svg)

```
[![Health](https://phpackages.com/badges/sad-spirit-pg-gateway/health.svg)](https://phpackages.com/packages/sad-spirit-pg-gateway)
```

###  Alternatives

[scienta/doctrine-json-functions

A set of extensions to Doctrine that add support for json query functions.

58523.9M36](/packages/scienta-doctrine-json-functions)[cycle/orm

PHP DataMapper ORM and Data Modelling Engine

1.3k835.4k65](/packages/cycle-orm)[aura/sqlquery

Object-oriented query builders for MySQL, Postgres, SQLite, and SQLServer; can be used with any database connection library.

4572.9M34](/packages/aura-sqlquery)[atlas/orm

An ORM for your persistence model (not your domain model).

429139.8k12](/packages/atlas-orm)[cycle/database

DBAL, schema introspection, migration and pagination

64690.9k31](/packages/cycle-database)[atlas/query

Object-oriented query builders and performers for MySQL, Postgres, SQLite, and SQLServer.

41249.0k7](/packages/atlas-query)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
