PHPackages                             th3mouk/materialized-view - 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. th3mouk/materialized-view

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

th3mouk/materialized-view
=========================

Declarative, PostgreSQL-native management of materialized views: define views as versioned SQL, synchronise, rebuild, refresh (concurrently) and read them safely. Runs on Doctrine DBAL or a bare PDO connection.

v1.3.0(1mo ago)0864↓64.9%1Apache-2.0PHPPHP &gt;=8.4CI passing

Since Jun 5Pushed 1mo agoCompare

[ Source](https://github.com/Th3Mouk/materialized-view)[ Packagist](https://packagist.org/packages/th3mouk/materialized-view)[ RSS](/packages/th3mouk-materialized-view/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (14)Versions (6)Used By (1)

th3mouk/materialized-view
=========================

[](#th3moukmaterialized-view)

> Declarative, PostgreSQL-native management of **materialized views** — on Doctrine DBAL **or** a bare PDO connection.

Define a materialized view once, as a **versioned `.sql` file plus a small PHP definition**, and let the library create it, detect drift, rebuild it safely, refresh it (including `CONCURRENTLY`), and let your app read it without surprises. No ORM owns the DDL; PostgreSQL stays the source of truth for the physical object.

This is the **framework-agnostic core**. It talks to PostgreSQL through a tiny `Connection` port, so **Doctrine is optional**: run it on a plain **PDO** handle, or hand it a **Doctrine DBAL** connection to additionally get primary/replica routing, middlewares, profiling and read-only ORM mapping. For Symfony — autoconfiguration, console commands, the locked deploy lane and async refresh — use [`th3mouk/materialized-view-bundle`](../materialized-view-bundle).

Why this library exists
-----------------------

[](#why-this-library-exists)

A materialized view is a **physical PostgreSQL object with its own lifecycle**: `CREATE MATERIALIZED VIEW … AS …`, `REFRESH MATERIALIZED VIEW [CONCURRENTLY]`, no `CREATE OR REPLACE`, destructive redefinition, unique-index preconditions for concurrent refresh, dependency ordering. Doctrine ORM can *read* the rows as a read-only projection, but it cannot *express* any of that — and at the time of writing **no maintained, framework-agnostic PHP library** manages PostgreSQL materialized views. This library fills that gap — natively on Doctrine DBAL, or on a bare PDO connection when you don't run an ORM.

See [`docs/internals/design-rationale.md`](docs/internals/design-rationale.md) for the full reasoning and the competitive landscape.

Highlights
----------

[](#highlights)

- **Declarative**: SQL lives in `db/matviews/*.sql`; a tiny PHP class declares name, indexes, rebuild &amp; population policy.
- **Drift detection** via a canonical hash stored in `COMMENT ON MATERIALIZED VIEW` (travels with database clones).
- **Safe rebuilds**: `drop_create` and a low-lock `side_by_side` strategy, with **index and GRANT re-application**.
- **Refresh runtime**: `CONCURRENTLY` with precondition validation, primary/replica awareness (on the Doctrine backend), `lock_timeout`/`statement_timeout`, advisory locks, `ANALYZE`.
- **Catalog-derived dependency ordering** (`pg_depend`/`pg_rewrite`) — no hand-maintained graph, no drift.
- **Doctrine optional**: the engine runs on a bare `PDO` handle with zero extra Composer dependencies; a Doctrine DBAL connection is natively supported and adds primary/replica routing, middlewares, profiling and read-only ORM mapping. See [`docs/guide/connection-backends.md`](docs/guide/connection-backends.md).
- **Read-only ORM mapping** (optional, Doctrine ORM) with a write guard and an unpopulated-read readiness guard.

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

[](#installation)

```
composer require th3mouk/materialized-view
```

Requirements: **PHP ≥ 8.4**, **PostgreSQL** (12+; tested against 17), and one connection backend:

- **Doctrine DBAL ≥ 4.4** — `composer require doctrine/dbal`. Recommended: unlocks primary/replica routing, middlewares, profiling, and the optional read-only ORM mapping (`doctrine/orm` ≥ 3.6).
- **or the `pdo_pgsql` extension** — no extra Composer dependency; wire the manager with `MaterializedViewManager::forPdo()`.

The core itself depends only on `php` and `psr/log`; the backend is your choice.

60-second example (framework-agnostic)
--------------------------------------

[](#60-second-example-framework-agnostic)

Given a base table `orders (id bigint, category text, amount numeric, created_at timestamptz)`:

`db/matviews/sales_by_category.sql`

```
SELECT category, count(*) AS order_count, sum(amount) AS total_amount
FROM orders
GROUP BY category
```

```
use Th3Mouk\MaterializedView\Core\Definition\MaterializedViewDefinition;
use Th3Mouk\MaterializedView\Core\Definition\MaterializedViewIndex;
use Th3Mouk\MaterializedView\Core\Definition\SqlFileSource;
use Th3Mouk\MaterializedView\Core\Registry\MaterializedViewRegistry;

$definition = MaterializedViewDefinition::create('public.sales_by_category')
    ->fromSql(SqlFileSource::fromProjectPath('db/matviews/sales_by_category.sql'))
    ->withIndex(MaterializedViewIndex::unique(
        name: 'ux_sales_by_category_category',
        columns: ['category'],
    ));

$registry = MaterializedViewRegistry::fromDefinitions([$definition]);
```

Wire the manager onto your connection backend:

```
use Th3Mouk\MaterializedView\Core\MaterializedViewManager;

// With Doctrine DBAL (recommended — primary/replica routing, middlewares, profiling):
$manager = MaterializedViewManager::forConnection($dbalConnection);

// …or without Doctrine, on a bare PDO connection:
$manager = MaterializedViewManager::forPdo(new PDO($dsn, $user, $password));
```

```
$manager->syncAll($registry);          // create / rebuild on drift
$manager->refresh($definition);        // REFRESH MATERIALIZED VIEW (CONCURRENTLY when possible)
```

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

[](#documentation)

TierAudienceStart here**Getting started**Users — set it up fast[`docs/getting-started.md`](docs/getting-started.md)**Guide**Users — advanced concepts[`docs/guide/`](docs/guide/)**Internals**Maintainers — design &amp; upstream references[`docs/internals/`](docs/internals/)A full table of contents is in [`docs/README.md`](docs/README.md).

Compatibility
-------------

[](#compatibility)

This libraryPHPDoctrine DBAL *(optional)*Doctrine ORM *(optional)*PostgreSQL`^1.x`≥ 8.4^4.4^3.612 – 17The core needs only a PostgreSQL connection — **Doctrine DBAL or `pdo_pgsql`**. Doctrine is optional and natively supported; it adds primary/replica routing, middlewares, profiling and read-only ORM mapping. We track DBAL major versions deliberately and **do not pin a tight upper bound that would strand the library** (see [`docs/internals/compatibility-and-evolution.md`](docs/internals/compatibility-and-evolution.md)).

License
-------

[](#license)

[Apache-2.0](LICENSE) — Copyright © 2026 Jérémy Marodon (th3mouk). See [`NOTICE`](NOTICE).

If you use or redistribute this package, keep the [`NOTICE`](NOTICE) attribution — crediting **Jérémy Marodon (th3mouk)** and naming this library in your product's documentation or credits. Please [contribute](CONTRIBUTING.md) upstream rather than maintaining a public fork.

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance92

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity55

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 ~3 days

Total

4

Last Release

39d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5006899?v=4)[Jérémy](/maintainers/Th3Mouk)[@Th3Mouk](https://github.com/Th3Mouk)

---

Top Contributors

[![Th3Mouk](https://avatars.githubusercontent.com/u/5006899?v=4)](https://github.com/Th3Mouk "Th3Mouk (7 commits)")

---

Tags

doctrinepostgresqlpostgresdbalpdoreportinganalyticsprojectionrefreshread modelmaterialized viewmatview

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/th3mouk-materialized-view/health.svg)

```
[![Health](https://phpackages.com/badges/th3mouk-materialized-view/health.svg)](https://phpackages.com/packages/th3mouk-materialized-view)
```

###  Alternatives

[doctrine/dbal

Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.

9.7k605.0M7.0k](/packages/doctrine-dbal)[martin-georgiev/postgresql-for-doctrine

Extends Doctrine with native PostgreSQL support for arrays, JSONB, ranges, PostGIS geometries, text search, ltree, uuid, and 100+ PostgreSQL-specific functions.

4585.8M4](/packages/martin-georgiev-postgresql-for-doctrine)[scienta/doctrine-json-functions

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

58925.9M54](/packages/scienta-doctrine-json-functions)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

85036.3k](/packages/flow-php-flow)[cycle/database

DBAL, schema introspection, migration and pagination

71777.8k63](/packages/cycle-database)[patchlevel/event-sourcing

A lightweight but also all-inclusive event sourcing library with a focus on developer experience

211362.9k13](/packages/patchlevel-event-sourcing)

PHPackages © 2026

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