PHPackages                             austinw/laravel-union-paginator - 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. austinw/laravel-union-paginator

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

austinw/laravel-union-paginator
===============================

Combines data from multiple models into a single unified query using SQL unions, allowing for consistent pagination and customization across diverse data sources.

v2.2.4(10mo ago)7839.7k↑49%7[1 PRs](https://github.com/AustinW/laravel-union-paginator/pulls)MITPHPPHP ^8.2CI passing

Since Dec 7Pushed 10mo ago2 watchersCompare

[ Source](https://github.com/AustinW/laravel-union-paginator)[ Packagist](https://packagist.org/packages/austinw/laravel-union-paginator)[ Docs](https://github.com/austinw/laravel-union-paginator)[ RSS](/packages/austinw-laravel-union-paginator/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (7)Dependencies (10)Versions (11)Used By (0)

UnionPaginator Documentation
============================

[](#unionpaginator-documentation)

[![Tests](https://github.com/AustinW/laravel-union-paginator/actions/workflows/run-tests.yml/badge.svg)](https://github.com/AustinW/laravel-union-paginator/actions/workflows/run-tests.yml)[![Linter](https://github.com/AustinW/laravel-union-paginator/actions/workflows/run-linter.yml/badge.svg)](https://github.com/AustinW/laravel-union-paginator/actions/workflows/run-linter.yml)[![Total Downloads](https://camo.githubusercontent.com/5a506b12d771cae4cd5e7c0037b7999b74f8f5b290f45220dad8c66a783d3af9/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f61757374696e772f6c61726176656c2d756e696f6e2d706167696e61746f72)](https://packagist.org/packages/austinw/laravel-union-paginator)[![Latest Stable Version](https://camo.githubusercontent.com/f4d3147ddbc0d1d4922a30e95a9bbdad66ad9b8b3494b54389768d46fa35b1a6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f61757374696e772f6c61726176656c2d756e696f6e2d706167696e61746f72)](https://packagist.org/packages/austinw/laravel-union-paginator)[![License](https://camo.githubusercontent.com/d780e6ea5bf4c05644994f5f86061a16e81f122d7ef3e114a7f29527c51d2150/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f61757374696e772f6c61726176656c2d756e696f6e2d706167696e61746f72)](https://packagist.org/packages/austinw/laravel-union-paginator)

Introduction
------------

[](#introduction)

The `UnionPaginator` package enables you to paginate and unify results from multiple Eloquent models into a single dataset. By merging multiple model queries, it allows for straightforward pagination and sorting of data drawn from various sources.

**Key Features:**

- Unite and paginate multiple Eloquent model results in one go.
- Apply per-model filters (scopes) before the union.
- Choose between retrieving actual Eloquent models or working with raw database records.
- Mitigate N+1 queries by loading models in bulk.
- Customize selected columns for each model type.

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

[](#installation)

Install via Composer:

```
composer require austinw/laravel-union-paginator
```

Migration Guide
---------------

[](#migration-guide)

If you are upgrading from an earlier version of `UnionPaginator`, please refer to the [Migration Guide](MIGRATION.md) for detailed instructions on updating your code to take advantage of the latest features and improvements.

Getting Started
---------------

[](#getting-started)

### Initializing the UnionPaginator

[](#initializing-the-unionpaginator)

Specify which Eloquent models you want to combine:

```
use AustinW\UnionPaginator\UnionPaginator;

$paginator = UnionPaginator::forModels([User::class, Post::class]);
```

All provided classes must be subclasses of `Illuminate\Database\Eloquent\Model`.

### Paginating Data

[](#paginating-data)

Call `paginate` to get paginated results:

```
$results = $paginator->paginate(15);
```

This returns a `LengthAwarePaginator` instance, seamlessly integrating with Laravel’s pagination utilities.

### Applying Scopes to Individual Models

[](#applying-scopes-to-individual-models)

You can apply specific query conditions to a single model type before creating the union:

```
$paginator->applyScope(User::class, fn($query) => $query->where('active', true));
```

### Customizing Mass Model Retrieval

[](#customizing-mass-model-retrieval)

The UnionPaginator class allows you to customize how models are retrieved during pagination. This can be useful if you need to apply specific logic or optimizations when fetching models from the database.

#### Registering a Custom Retrieval Callback

[](#registering-a-custom-retrieval-callback)

You can register a custom callback for retrieving models by type using the fetchModelsUsing method. This method allows you to define how models should be fetched for a specific model type.

Now only active users are included in the final union.

```
use AustinW\UnionPaginator\UnionPaginator;
use App\Models\Post;
use App\Models\Comment;

// Create a new UnionPaginator instance for the specified models
$paginator = new UnionPaginator([Post::class, Comment::class]);

// Register a custom retrieval callback for the Post model
$paginator->fetchModelsUsing(Post::class, function (array $ids) {
    // Custom logic to retrieve Post models
    return Post::with('author')->findMany($ids);
});

// Register a custom retrieval callback for the Comment model
$paginator->fetchModelsUsing(Comment::class, function (array $ids) {
    // Custom logic to retrieve Comment models
    return Comment::with('post')->findMany($ids);
});

// Use the paginator as usual
$paginatedResults = $paginator->paginate();
```

#### Important Considerations

[](#important-considerations)

- Model Type Registration: Ensure that the model type you are registering a callback for has been added to the UnionPaginator instance using the constructor or addModelType method.
- Callback Signature: The callback should accept an array of IDs and return a collection of models. You can use Eloquent's findMany method or any other custom logic to retrieve the models.
- Default Behavior: If no custom callback is registered for a model type, the UnionPaginator will use the default retrieval logic, which is to call findMany on the model type.

By using custom retrieval callbacks, you can optimize and tailor the model fetching process to suit your application's specific needs.

### Transforming Results

[](#transforming-results)

Use `transformResultsFor` to alter records for a particular model type:

```
$paginator->transformResultsFor(User::class, fn($user) => [
    'id' => $user->id,
    'uppercase_name' => strtoupper($user->name),
]);
```

If model retrieval is active, `$user` is an Eloquent model. If you call `preventModelRetrieval()`, `$user` is a raw database record (`stdClass`).

### Preventing Model Retrieval

[](#preventing-model-retrieval)

If you don’t need Eloquent models and prefer raw records:

```
$paginator->preventModelRetrieval()->paginate();
```

Transformations still apply, but are run on raw records.

### Selecting Columns

[](#selecting-columns)

Choose specific columns for each model type to reduce overhead:

```
$paginator->setSelectedColumns(User::class, ['id', 'email', DB::raw("'User' as type")]);
```

### Soft Deletes

[](#soft-deletes)

Models using `SoftDeletes` are automatically filtered so that soft-deleted records do not appear.

Methods
-------

[](#methods)

- **forModels(array $modelTypes): self**
    Set the models to combine. Throws an exception if a non-model class is provided.
- **applyScope(string $modelType, Closure $callable): self**
    Modify queries for an individual model type.
- **transformResultsFor(string $modelType, Closure $callable): self**
    Apply transformations to either models or raw records of a particular model type.
- **preventModelRetrieval(): self**
    Skip loading actual models. Return raw database rows instead.
- **setSelectedColumns(string $modelType, array $columns): self**
    Specify which columns to fetch for each model type.
- **paginate($perPage = 15, $columns = \['\*'\], $pageName = 'page', $page = null): LengthAwarePaginator**
    Execute the union query, apply scopes and transformations, and return a paginator.
- **\_\_call($method, $parameters)**
    Forward method calls to the underlying union query builder, enabling sorting and other query modifications.

Example Usage
-------------

[](#example-usage)

```
use AustinW\UnionPaginator\UnionPaginator;

$paginator = UnionPaginator::forModels([User::class, Post::class])
    ->applyScope(User::class, fn($query) => $query->where('active', true))
    ->transformResultsFor(User::class, fn($user) => ['id' => $user->id, 'name' => strtoupper($user->name)])
    ->transformResultsFor(Post::class, fn($post) => ['title' => $post->title, 'date' => $post->created_at->toDateString()])
    ->paginate(10);

foreach ($paginator->items() as $item) {
    // Each $item could be a transformed array or a raw record, depending on your configuration.
}
```

Advanced Usage
--------------

[](#advanced-usage)

### Ordering and Complex Queries

[](#ordering-and-complex-queries)

You can chain Eloquent methods before `paginate()`:

```
$paginator->latest()->paginate();
```

or

```
$paginator->orderBy('created_at', 'desc')->paginate();
```

### Multiple Transformations for the Same Model

[](#multiple-transformations-for-the-same-model)

Applying multiple transformations for the same model type overwrites earlier ones:

```
$paginator->transformResultsFor(User::class, fn($user) => ['transformed' => true])
          ->transformResultsFor(User::class, fn($user) => ['overridden' => true]);
```

The latter transformation takes precedence.

### Handling Empty Results

[](#handling-empty-results)

If no matching records are found, the paginator returns an empty result set without errors.

Testing
-------

[](#testing)

`UnionPaginator` is well-tested across various scenarios, including:

- Multiple model unions.
- Soft deletes handling.
- Both raw and model-based transformations.
- Large datasets and edge cases.

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance54

Moderate activity, may be stable

Popularity45

Moderate usage in the ecosystem

Community14

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 91.7% 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 ~24 days

Recently: every ~54 days

Total

10

Last Release

308d ago

Major Versions

1.0.1 → v2.0.02024-12-10

### Community

Maintainers

![](https://www.gravatar.com/avatar/9444ae0906d85682c4700758c9ac0b7903e693557da4b6a876c11eff026bbcdc?d=identicon)[AustinW](/maintainers/AustinW)

---

Top Contributors

[![AustinW](https://avatars.githubusercontent.com/u/333398?v=4)](https://github.com/AustinW "AustinW (22 commits)")[![alexandre-tobia](https://avatars.githubusercontent.com/u/5537783?v=4)](https://github.com/alexandre-tobia "alexandre-tobia (1 commits)")[![mxp100](https://avatars.githubusercontent.com/u/8124083?v=4)](https://github.com/mxp100 "mxp100 (1 commits)")

---

Tags

paginationmultipleunionlaravel-union-paginatoraustinw

###  Code Quality

TestsPest

Static AnalysisPHPStan

### Embed Badge

![Health badge](/badges/austinw-laravel-union-paginator/health.svg)

```
[![Health](https://phpackages.com/badges/austinw-laravel-union-paginator/health.svg)](https://phpackages.com/packages/austinw-laravel-union-paginator)
```

###  Alternatives

[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[laravel-doctrine/orm

An integration library for Laravel and Doctrine ORM

8425.3M87](/packages/laravel-doctrine-orm)[watson/validating

Eloquent model validating trait.

9723.3M47](/packages/watson-validating)[yajra/laravel-oci8

Oracle DB driver for Laravel via OCI8

8703.0M17](/packages/yajra-laravel-oci8)[dyrynda/laravel-model-uuid

This package allows you to easily work with UUIDs in your Laravel models.

4802.8M8](/packages/dyrynda-laravel-model-uuid)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

423715.4k1](/packages/clickbar-laravel-magellan)

PHPackages © 2026

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