PHPackages                             maatify/persistence - 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. maatify/persistence

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

maatify/persistence
===================

Standalone, framework-agnostic PDO ordering and pagination utilities for Maatify projects.

v1.1.0(1mo ago)1964↓75%MITPHPPHP &gt;=8.2CI passing

Since Jul 11Pushed 1mo agoCompare

[ Source](https://github.com/Maatify/persistence)[ Packagist](https://packagist.org/packages/maatify/persistence)[ Docs](https://github.com/Maatify/persistence)[ RSS](/packages/maatify-persistence/feed)WikiDiscussions main Synced 1w ago

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

Maatify Persistence
===================

[](#maatify-persistence)

[![Maatify.dev](https://camo.githubusercontent.com/bb8bf9ee079d7f823c9d5e94061d1d4c11dc0898e2b1b5cc9a8a7b04d8bfdd7d/68747470733a2f2f7777772e6d6161746966792e6465762f6173736574732f696d672f696d672f6d6161746966795f6c6f676f5f77686974652e737667)](https://camo.githubusercontent.com/bb8bf9ee079d7f823c9d5e94061d1d4c11dc0898e2b1b5cc9a8a7b04d8bfdd7d/68747470733a2f2f7777772e6d6161746966792e6465762f6173736574732f696d672f696d672f6d6161746966795f6c6f676f5f77686974652e737667)

**Package status:**
[![Latest Version](https://camo.githubusercontent.com/577e4a2b4b8c2ce7574fc179adb0304728427ed7d623756500cdd1272cdc9430/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d6161746966792f70657273697374656e63652e737667)](https://packagist.org/packages/maatify/persistence)[![PHP Version](https://camo.githubusercontent.com/6d0ffd2d69759538dd1354cb780164542c85a9fee6241a78c593a0e4756ab69d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6d6161746966792f70657273697374656e63652e737667)](https://packagist.org/packages/maatify/persistence)[![License: MIT](https://camo.githubusercontent.com/5d0c9352ab678cb25f1add35fb0590a1ec4b0c5e8d599012d1f28cc717539c8b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6d6161746966792f70657273697374656e63652e737667)](LICENSE)[![PHPStan: Level Max](https://camo.githubusercontent.com/b6d441ad4fe8332cb16c72aa27f22cc685181dfd74ae34964afc92c6c1146b3c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c2532306d61782d627269676874677265656e2e737667)](phpstan.neon)

**Documentation:**
[![Changelog](https://camo.githubusercontent.com/823f0865f88efc23894c06d92d2a141ebe8385c761b2ae1e34a40b958159a653/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4368616e67656c6f672d566965772d626c75652e737667)](CHANGELOG.md)[![Package Reference](https://camo.githubusercontent.com/e4a13cadb130f9f0f5af5f24632e95e70013a033eb76328d060ac907f8b7e05c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5265666572656e63652d526561642d626c75652e737667)](PERSISTENCE_PACKAGE_REFERENCE.md)[![Security Policy](https://camo.githubusercontent.com/3b9feb2066dbbe942adeafa8ed9d61c3763721f32609f314240571ed1c4e8862/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53656375726974792d506f6c6963792d626c75652e737667)](SECURITY.md)[![Contributing Guide](https://camo.githubusercontent.com/796cd1ae773d0577e7bd35df43a8b8eff55755f8925a6f1f7b3c006817e3a186/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6e747269627574696e672d47756964652d626c75652e737667)](CONTRIBUTING.md)

**Ecosystem and usage:**
[![Monthly Downloads](https://camo.githubusercontent.com/6612d4f086d94924d6b84a7855434fd03ed8822fd8c58db47da9816e1ea39251/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f6d6161746966792f70657273697374656e6365)](https://packagist.org/packages/maatify/persistence)[![Total Downloads](https://camo.githubusercontent.com/290d3df52db9752901b55edd326b39a6f8b4d6c9e624bec55ef3e1fc1da5d7ff/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d6161746966792f70657273697374656e6365)](https://packagist.org/packages/maatify/persistence)[![Maatify Ecosystem](https://camo.githubusercontent.com/e909123cad12b048a0b4441f2b9cfb19aebfb3986afe8e3631da84255281c12d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d6161746966792d45636f73797374656d2d626c756576696f6c6574)](https://github.com/Maatify)[![Install](https://camo.githubusercontent.com/2cd17a2f6cb7c21e007546cfbe3711bbebafb038d44bd1475d3cb64e56ea5859/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f496e7374616c6c2d636f6d706f736572253230726571756972652532306d61617469667925324670657273697374656e63652d626c7565)](https://packagist.org/packages/maatify/persistence)

*Standalone, framework-agnostic PDO utilities for Maatify projects, providing robust scoped and global ordering, and pagination tools. Designed and verified for MySQL environments.*

> **Note:** PDO Pagination is available starting with v1.1.0.

---

🚀 Key Features
--------------

[](#-key-features)

- **Global and Scoped Ordering**: Easily manage display order across an entire table or within a specific scope.
- **Transaction Ownership**: Handles its own transactions and locks the necessary scope reliably.
- **SQL Identifier Validation**: Ensures table and column configurations are safe and properly quoted.
- **Soft-Delete Filtering**: Optional support for ignoring soft-deleted rows in ordering calculations.
- **Scope Isolation**: Ensures only the affected range within the configured scope is updated.
- **PDO Pagination**: Deterministic offset pagination with strict normalization, bounds checking, and safe whitelist-based sorting.

⚙️ Requirements
---------------

[](#️-requirements)

**Runtime requirements:**

- PHP `>= 8.2`
- `ext-pdo`
- `maatify/exceptions ^1.0`

**Database behavior:**

- The package behavior is designed and verified against MySQL.

📦 Installation
--------------

[](#-installation)

```
composer require maatify/persistence
```

⚡ Quick Usage
-------------

[](#-quick-usage)

```
use Maatify\Persistence\Pdo\Ordering\ScopedOrderingConfig;
use Maatify\Persistence\Pdo\Ordering\ScopedOrderingManager;

// 1. Configure the ordering behavior for a table
$config = new ScopedOrderingConfig(
    table: 'maa_shipping_rates',
    scopeColumn: 'method_id', // Use null for global ordering
    idColumn: 'id',
    orderColumn: 'display_order',
    deletedAtColumn: 'deleted_at', // Use null if soft-deletes are not used
);

$ordering = new ScopedOrderingManager();

// 2. Get the next position for a new insert
$nextPosition = $ordering->getNextPosition(
    pdo: $pdo,
    config: $config,
    scopeValue: 2, // Use null for global ordering
);

// 3. Move an existing row within its scope
$success = $ordering->moveWithinScope(
    pdo: $pdo,
    config: $config,
    scopeValue: 2, // Use null for global ordering
    id: 15,
    newOrder: 4,
);
```

### PDO Pagination

[](#pdo-pagination)

```
use Maatify\Persistence\Pdo\Pagination\PaginationConfig;
use Maatify\Persistence\Pdo\Pagination\PageRequest;
use Maatify\Persistence\Pdo\Pagination\PdoPaginationQueryDescriptor;
use Maatify\Persistence\Pdo\Pagination\PdoPaginator;
use Maatify\Persistence\Pdo\Pagination\SortWhitelist;
use Maatify\Persistence\Pdo\Pagination\SortDirectionEnum;

$config = new PaginationConfig(
    defaultPerPage: 10,
    maxPerPage: 100,
    minPerPage: 1,
    sortWhitelist: new SortWhitelist([
        'id' => 'id',
        'created' => 'created_at',
        'name' => 'user_name',
    ]),
    defaultSortBy: 'created',
    defaultSortDirection: SortDirectionEnum::DESC,
    tieBreakerSortBy: 'id',
    tieBreakerDirection: SortDirectionEnum::DESC
);

$query = new PdoPaginationQueryDescriptor(
    totalSql: 'SELECT COUNT(*) FROM users',
    totalParams: [],
    filteredCountSql: 'SELECT COUNT(*) FROM users WHERE status = :status',
    filteredCountParams: ['status' => 'active'],
    dataSql: 'SELECT id, user_name, created_at FROM users WHERE status = :status',
    dataParams: ['status' => 'active']
);

$request = new PageRequest(page: 2, perPage: 15, sortBy: 'name', sortDirection: 'ASC');

$paginator = new PdoPaginator();
$result = $paginator->paginate(
    pdo: $pdo,
    query: $query,
    request: $request,
    config: $config,
    mapper: fn(array $row) => (object) $row
);
```

🧩 Public Runtime API
--------------------

[](#-public-runtime-api)

The package currently provides the following public classes for PDO ordering and pagination:

```
Maatify\Persistence\Pdo\Ordering\ScopedOrderingConfig;
Maatify\Persistence\Pdo\Ordering\ScopedOrderingManager;

Maatify\Persistence\Pdo\Pagination\PageRequest;
Maatify\Persistence\Pdo\Pagination\SortDirectionEnum;
Maatify\Persistence\Pdo\Pagination\SortWhitelist;
Maatify\Persistence\Pdo\Pagination\PaginationConfig;
Maatify\Persistence\Pdo\Pagination\PdoPaginationQueryDescriptor;
Maatify\Persistence\Pdo\Pagination\PageResult;
Maatify\Persistence\Pdo\Pagination\PdoPaginator;

// Exceptions
Maatify\Persistence\Exception\PersistenceException;
Maatify\Persistence\Exception\InvalidOrderingConfigurationException;
Maatify\Persistence\Exception\InvalidOrderingOperationException;
Maatify\Persistence\Exception\OrderingTransactionException;
Maatify\Persistence\Exception\InvalidPaginationConfigurationException;
Maatify\Persistence\Exception\InvalidPaginationQueryException;
Maatify\Persistence\Exception\PaginationExecutionException;
```

⚠️ Critical Runtime Behavior
----------------------------

[](#️-critical-runtime-behavior)

**`getNextPosition()`:**

- Does not start a transaction.
- Does not lock the applicable scope.
- For concurrent inserts, the host application must provide the transaction and locking mechanism required to serialize position allocation.

**`moveWithinScope()`:**

- Rejects inconsistent scope usage.
- Rejects `id
