PHPackages                             bumpcore/panorama - 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. bumpcore/panorama

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

bumpcore/panorama
=================

Query-backed Eloquent models for Laravel.

v0.1.1(1mo ago)00MITPHPPHP ^8.2CI passing

Since Jun 1Pushed 1mo agoCompare

[ Source](https://github.com/bumpcore/panorama)[ Packagist](https://packagist.org/packages/bumpcore/panorama)[ RSS](/packages/bumpcore-panorama/feed)WikiDiscussions 0.x Synced 1w ago

READMEChangelog (2)Dependencies (8)Versions (4)Used By (0)

Bumpcore Panorama
=================

[](#bumpcore-panorama)

Bumpcore Panorama is a Laravel package for building Eloquent models from query sources. It lets a model behave like a normal read model while its rows come from a subquery, aggregate, CTE, or custom query builder source.

Use it when you need query-backed models for reports, projections, aggregate tables, read-only relation targets, or custom database features without giving up Eloquent relations and builder chaining.

Table Of Contents
-----------------

[](#table-of-contents)

- [Version Table](#version-table)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [HasSource](#hassource)
    - [Defining a Source](#defining-a-source)
    - [Passing Source Params](#passing-source-params)
    - [Changing the Source Alias](#changing-the-source-alias)
- [Eloquent Compatibility](#eloquent-compatibility)
- [Exceptions](#exceptions)
- [Testing](#testing)
- [Contribution](#contribution)
- [Changelog](#changelog)
- [Credits](#credits)
- [License](#license)

Version Table
-------------

[](#version-table)

Bumpcore PanoramaLaravelPHP0.x^12.0^8.20.x^13.0^8.3Installation
------------

[](#installation)

Install the package with Composer:

```
composer require bumpcore/panorama
```

Quick Start
-----------

[](#quick-start)

Add the `HasSource` trait to an Eloquent model and define `newSource()`.

```
use Bumpcore\Panorama\HasSource;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;

class CustomerBalance extends Model
{
    use HasSource;

    protected $primaryKey = 'customer_id';

    public function newSource(int $customer_id): Builder
    {
        return DB::table('invoices')
            ->selectRaw('customer_id, sum(amount) as balance')
            ->where('customer_id', $customer_id)
            ->groupBy('customer_id');
    }
}

$balances = CustomerBalance::query()
    ->where('balance', '>', 0)
    ->withParams(customer_id: $customer->getKey())
    ->get();
```

The model is still queried through Eloquent. Panorama only replaces the model's `from` clause with the source query when the builder is executed.

HasSource
---------

[](#hassource)

`HasSource` registers a global scope and a local `withParams()` scope on the model. The global scope wraps the model query in the source returned by `newSource()`.

### Defining a Source

[](#defining-a-source)

`newSource()` may return an Eloquent builder or a base query builder.

```
use Bumpcore\Panorama\HasSource;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class OpenInvoiceTotal extends Model
{
    use HasSource;

    public function newSource(): Builder
    {
        return Invoice::query()
            ->selectRaw('customer_id, sum(amount) as open_total')
            ->where('status', 'open')
            ->groupBy('customer_id');
    }
}
```

The source is not expected to hit a real table with the model name. It becomes the derived table Panorama queries from.

### Passing Source Params

[](#passing-source-params)

Use `withParams()` to pass named arguments to `newSource()`.

```
$balance = CustomerBalance::query()
    ->withParams(customer_id: 1, status: 'open')
    ->first();
```

Array params are also supported:

```
$balance = CustomerBalance::query()
    ->withParams([
        'customer_id' => 1,
        'status' => 'open',
    ])
    ->first();
```

Params must use string keys because they are passed as named arguments. Later calls replace earlier values, just like normal builder state.

### Changing the Source Alias

[](#changing-the-source-alias)

By default, Panorama uses the model table name as the SQL alias for the wrapped source. Override `querySourceAlias()` when the source should use a different alias.

```
class CustomerBalance extends Model
{
    use HasSource;

    public function querySourceAlias(): string
    {
        return 'customer_balances';
    }
}
```

The alias must not be an empty string.

Eloquent Compatibility
----------------------

[](#eloquent-compatibility)

Panorama keeps the consumer-facing Eloquent builder intact. You can still use:

- normal Eloquent builder methods;
- local scopes;
- relations and eager loading;
- `whereHas()` against query-backed relation models;
- custom Eloquent builders;
- external query builder extensions.

The test suite includes compatibility coverage for:

- `staudenmeir/laravel-cte`
- `tpetry/laravel-postgresql-enhanced`
- consumer-defined custom Eloquent builders

Exceptions
----------

[](#exceptions)

All package-specific failures extend:

```
Bumpcore\Panorama\Exceptions\PanoramaException
```

More specific exceptions are available:

- `InvalidQuerySourceException`
- `MissingQuerySourceException`

`InvalidQuerySourceException` is thrown when a model does not use the required trait, when `newSource()` returns an unsupported value, or when the source alias is empty.

`MissingQuerySourceException` is thrown when a model uses `HasSource` without overriding `newSource()`.

Testing
-------

[](#testing)

Install development dependencies:

```
composer install
```

Run the test suite:

```
composer test
```

Run static analysis:

```
composer analyse
```

Check code style:

```
composer cs:check
```

Run the 100% coverage gate:

```
composer test:coverage
```

Coverage requires PCOV, Xdebug, or phpdbg.

Contribution
------------

[](#contribution)

Contributions are welcome. If you find a bug or have a suggestion for improvement, please open an issue or create a pull request.

Please include tests for behavioral changes and run the quality checks before submitting a pull request:

```
composer cs:check
composer analyse
composer test
```

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) for version history.

Credits
-------

[](#credits)

- [Abdulkadir Cemiloglu](https://github.com/megastive19)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance90

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

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

Total

3

Last Release

52d ago

### Community

Maintainers

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

---

Top Contributors

[![megasteve19](https://avatars.githubusercontent.com/u/32229751?v=4)](https://github.com/megasteve19 "megasteve19 (11 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/bumpcore-panorama/health.svg)

```
[![Health](https://phpackages.com/badges/bumpcore-panorama/health.svg)](https://phpackages.com/packages/bumpcore-panorama)
```

###  Alternatives

[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k8.4M98](/packages/mongodb-laravel-mongodb)[kirschbaum-development/eloquent-power-joins

The Laravel magic applied to joins.

1.6k32.6M46](/packages/kirschbaum-development-eloquent-power-joins)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8793.2M25](/packages/yajra-laravel-oci8)[bavix/laravel-wallet

It's easy to work with a virtual wallet.

1.3k1.3M19](/packages/bavix-laravel-wallet)[glushkovds/phpclickhouse-laravel

Adapter of the most popular library https://github.com/smi2/phpClickHouse to Laravel

2051.5M2](/packages/glushkovds-phpclickhouse-laravel)[laravel-liberu/laravel-gedcom

A package that converts gedcom files to Eloquent models

782.5k1](/packages/laravel-liberu-laravel-gedcom)

PHPackages © 2026

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