PHPackages                             somnambulist/read-models - 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. somnambulist/read-models

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

somnambulist/read-models
========================

A stripped down active-record'ish query layer for fetching data from your database.

4.1.1(1y ago)123.2k↓20%[1 issues](https://github.com/somnambulist-tech/read-models/issues)3MITPHPPHP &gt;=8.1CI failing

Since Jul 14Pushed 1y ago5 watchersCompare

[ Source](https://github.com/somnambulist-tech/read-models)[ Packagist](https://packagist.org/packages/somnambulist/read-models)[ RSS](/packages/somnambulist-read-models/feed)WikiDiscussions master Synced 2d ago

READMEChangelog (10)Dependencies (19)Versions (46)Used By (3)

Read-Models
===========

[](#read-models)

[![GitHub Actions Build Status](https://camo.githubusercontent.com/3df89505ce4b1a36b4e03ce4c15c8c1a204f7b3c5e2c768fb509730d8b8a0bc8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f736f6d6e616d62756c6973742d746563682f726561642d6d6f64656c732f74657374732e796d6c3f6c6f676f3d676974687562266272616e63683d6d6173746572)](https://github.com/somnambulist-tech/read-models/actions?query=workflow%3Atests)[![Issues](https://camo.githubusercontent.com/cf71b8bca2dc17e325cc43e61a128ae3ab3097be7cbfc9a5a4b77ad8d8e2acc2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f736f6d6e616d62756c6973742d746563682f726561642d6d6f64656c733f6c6f676f3d676974687562)](https://github.com/somnambulist-tech/read-models/issues)[![License](https://camo.githubusercontent.com/6935f3b16eee3f79e4efc4a42e30815955679962cc3eff72931e3e9474831b04/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f736f6d6e616d62756c6973742d746563682f726561642d6d6f64656c733f6c6f676f3d676974687562)](https://github.com/somnambulist-tech/read-models/blob/master/LICENSE)[![PHP Version](https://camo.githubusercontent.com/566332ada4c4fea58496a4aea9cfbd5198802fa81c9332fbe8f20c29c7e967c6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f736f6d6e616d62756c6973742f726561642d6d6f64656c733f6c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/somnambulist/read-models)[![Current Version](https://camo.githubusercontent.com/afe330f4d88491a3dce9eb196a6803c10a809274697bc1df5837b601ab5fc6dc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736f6d6e616d62756c6973742f726561642d6d6f64656c733f6c6f676f3d7061636b6167697374266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/somnambulist/read-models)

Read-Models are a companion resource to a Doctrine ORM entity based project. They provide an active-record style data access layer, designed for presentational purposes only. This allows your domain objects to remain completely focused on managing your data and not getting sidelined with presentational concerns.

To further highlight this tight integration, read-models uses DBAL and the DBAL type system under-the-hood. Any registered types will be used during model hydration and even embeddables can be reused.

Note that unlike standard active-record packages, there is no write support at all nor will this be added. This package is purely focused on reading and querying data with objects / query builders for use in the presentation layer.

A lot of the internal arrangement is heavily inspired by Laravels Eloquent and other active-record projects including GranadaORM (IdiORM), PHP ActiveRecord and others.

### Supported Features

[](#supported-features)

- active-record query model
- read-only - no ability to change your db through the built-in methods
- read-only models - no mutation methods, models are immutable once loaded
- support for attribute casting
- support for embedded objects via attribute casting
- support for exporting as JSON / Array data (configurable)
- eager loading of relationships including batch loading
- relationships (1:1, 1:m, m:m, 1:m reversed)
- identity map
- pluggable attribute casting / cast to value-objects

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

[](#requirements)

- PHP 8.1+
- mb\_string
- doctrine/dbal
- somnambulist/collection

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

[](#installation)

Install using composer, or checkout / pull the files from github.com.

- composer require somnambulist/read-models
- instantiate `Manager` with your connection mappings and any attribute casters
- add models extending the `Model` class, being sure to set the table name property
- load some data: `::find()`

For example:

```
use Doctrine\DBAL\DriverManager;
use Somnambulist\Components\ReadModels\Manager;
use Somnambulist\Components\ReadModels\TypeCasters\DoctrineTypeCaster;

new Manager(
[
    User::class => $conn = DriverManager::getConnection(['url' => 'sqlite://db.sqlite']),
    'default'   => $conn,
],
[
    new DoctrineTypeCaster($conn),
]
);
```

Usage
-----

[](#usage)

Extend `Somnambulist\Components\ReadModels\Model` and add casts, define relationships, exports etc.

```
class User extends Model
{
    protected string $table = 'users';
}
```

You can add a default table alias by setting the property: `$tableAlias`. Other defaults can be overridden by defining the property:

```
class User extends Model
{
    protected string $table = 'tbl_users';
    protected ?string $tableAlias = 'u';
    protected string $primaryKey = 'uuid';
}
```

**Note:** properties are defined with types and must follow those defined in the base class.

To load a record:

```
$model = User::find(1);

$results = User::query()->whereColumn('name', 'like', '%bob%')->orderBy('created_at', 'desc')->limit(5)->fetch();
```

Access properties directly or via method calls:

```
$model = User::find(1);

$model->id;
$model->id();
$model->created_at;
$model->createdAt();
```

You cannot set, unset, or change the returned models.

You can define attribute mutators in the same way as Laravels Eloquent:

```
class User extends Model
{
    protected function getUsernameAttribute($username)
    {
        return Str::capitalize($username);
    }
}

// user:{username: bob was here} -> returns Bob Was Here

User::find(1)->username();
```

**Note:** these methods should be `protected` as they expect the current value to be passed from the loaded model attributes.

Or create virtual properties, that exist at run time:

```
class User extends Model
{
    protected function getAnniversayDayAttribute()
    {
        return $this->created_at->format('l');
    }
}

// user:{created_at: '2019-07-15 14:23:21'} -> "Monday"

User::find(1)->anniversay_day;
User::find(1)->anniversayDay();
```

Or for micro-optimizations, add the method directly:

```
class User extends Model
{
    public function anniversayDay()
    {
        return $this->created_at->format('l');
    }
}

// user:{created_at: '2019-07-15 14:23:21'} -> "Monday"

User::find(1)->anniversayDay();
```

**Note:** to access properties via the magic \_\_get/call the property name must be a valid PHP property/method name. Keys that start with numbers (for example), will not work. Any virtual methods / properties should be documented using `@property-read` tags on the class level docblock comment. Additionally: virtual methods can be tagged using `@method`.

**Note:** to get a raw attribute value, use `->getRawAttribute()`. This will return null if the attribute is not found, but could also return null for the specified key.

When returning sets of Model objects, the returned set can be customised per model to allow for specific filters on the collection or other behaviour. Override the `collectionClass` property with the class name to use. This class must implement the Collection contract from the somnambulist/collection project and must have `extract()` and `add()` methods.

More Reading
------------

[](#more-reading)

- [Upgrading from 1.X to 2.0](docs/upgrading_1.X_to_2.0.md)
- [Upgrading from 2.X to 3.0](docs/upgrading_2.X_to_3.0.md)
- [Upgrading from 3.X to 4.0](docs/upgrading_3.X_to_4.0.md)
- [Setting up Symfony](docs/setup_symfony.md)
- [Querying Data](docs/querying.md)
- [Casting Attributes](docs/casting.md)
- [Relationships](docs/relationships.md)
- [Identity Map](docs/identity_map.md)
- [Exporting Models](docs/exporting.md)

[Auto-generated API docs](docs/api-read-models.md) are available in the docs folder.

Profiling
---------

[](#profiling)

If you use Symfony; using the standard Doctrine DBAL connection from your entity manager will automatically ensure that *ALL* SQL queries are added to the profiler without having to do anything else! You get full insight into the query that was executed, the data bound etc. For further insights consider using an application profiler such as:

- [Tideways](https://tideways.io)
- [BlackFire](https://blackfire.io)

For other frameworks; as DBAL is used, hook into the Configuration object and add an SQL logger instance that can report to your frameworks profiler.

Test Suite
----------

[](#test-suite)

The test suite uses an SQlite database file named "users.db" that simulates a possible User setup with Roles, Permissions, Contacts and Addresses. Before running the test suite, be sure to generate some test data using: `tests/resources/seed.php`. This console app has a couple of commands:

- `db:create` - builds the table structure
- `db:seed` - generate base records and `--records=XX` random records
- `db:destroy` - deletes all test data and tables

For the test suite to run and be able to test various relationships / eager loading etc a reasonable number of test records are needed. The suite was built against a random sample of 150 records.

The `DataGenerator` attempts some amount of random allocation of addresses, contacts and roles to each user; however data integrity was not the goal, merely usable data.

To run the tests: `vendor/bin/phpunit`.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance37

Infrequent updates — may be unmaintained

Popularity26

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity80

Battle-tested with a long release history

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

Recently: every ~241 days

Total

45

Last Release

532d ago

Major Versions

1.4.1 → 2.0.02020-09-07

1.4.2 → 2.1.22020-09-23

1.4.3 → 2.1.32020-09-23

2.2.0 → 3.0.02021-01-21

3.x-dev → 4.0.02023-01-19

PHP version history (5 changes)0.1.0PHP &gt;=7.2

1.3.0PHP &gt;=7.3

2.0.0PHP &gt;=7.4

3.0.0PHP &gt;=8.0

4.0.0PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/c0e439bf91b68c2e81e0250c752d3a552e78752c91acdf00c72a1f93aeb1ceca?d=identicon)[dredfern](/maintainers/dredfern)

---

Top Contributors

[![dave-redfern](https://avatars.githubusercontent.com/u/1477147?v=4)](https://github.com/dave-redfern "dave-redfern (116 commits)")

---

Tags

activerecorddoctrinephpread-only

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/somnambulist-read-models/health.svg)

```
[![Health](https://phpackages.com/badges/somnambulist-read-models/health.svg)](https://phpackages.com/packages/somnambulist-read-models)
```

###  Alternatives

[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M651](/packages/sylius-sylius)[damienharper/auditor-bundle

Integrate auditor library in your Symfony projects.

4542.8M](/packages/damienharper-auditor-bundle)[sonata-project/entity-audit-bundle

Audit for Doctrine Entities

644989.8k1](/packages/sonata-project-entity-audit-bundle)[overtrue/laravel-versionable

Make Laravel model versionable.

585308.0k5](/packages/overtrue-laravel-versionable)[bolt/core

🧿 Bolt Core

585142.5k54](/packages/bolt-core)[netgen/layouts-core

Netgen Layouts enables you to build and manage complex web pages in a simpler way and with less coding. This is the core of Netgen Layouts, its heart and soul.

3689.4k10](/packages/netgen-layouts-core)

PHPackages © 2026

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