PHPackages                             blackcube/active-record - 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. blackcube/active-record

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

blackcube/active-record
=======================

Scoped queries, elastic dynamic attributes, Hazeltree nested sets — a toolkit for ActiveRecord

1.0.0(1mo ago)03↓100%3BSD-3-ClausePHPPHP ^8.0

Since Mar 21Pushed 1mo agoCompare

[ Source](https://github.com/blackcubeio/active-record)[ Packagist](https://packagist.org/packages/blackcube/active-record)[ Docs](https://github.com/blackcubeio/active-record)[ RSS](/packages/blackcube-active-record/feed)WikiDiscussions devel Synced 1mo ago

READMEChangelogDependencies (18)Versions (3)Used By (3)

Blackcube ActiveRecord
======================

[](#blackcube-activerecord)

Scoped queries, elastic dynamic attributes, Hazeltree nested sets — a toolkit for ActiveRecord.

[![License](https://camo.githubusercontent.com/6cb285b57819f8de0acfb34923298f4f569f962544e8fe35331da2d163f4e485/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4253442d2d332d2d436c617573652d626c75652e737667)](LICENSE.md)[![Packagist Version](https://camo.githubusercontent.com/4f87eb16fdaf2a23c4e9114bbee1e12e7d9d156e849e12c05a879b7cde292bde/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f626c61636b637562652f6163746976652d7265636f72642e737667)](https://packagist.org/packages/blackcube/active-record)

Quickstart
----------

[](#quickstart)

```
composer require blackcube/active-record
```

```
// Scoped queries
$products = Product::query()->active()->language(languageId: 'fr')->all();

// Elastic — dynamic attributes from JSON Schema
$article->author = 'Philippe';
$article->rating = 5;
$article->save();
$found = Article::query()->where(['author' => 'Philippe'])->all();

// Hazeltree — nested sets
$child = new Menu();
$child->name = 'About';
$child->saveInto($homepage);
$breadcrumb = $child->relativeQuery()->parent()->includeAncestors()->includeSelf()->all();
```

Three building blocks
---------------------

[](#three-building-blocks)

### Scoped queries

[](#scoped-queries)

Named, composable filters. PHP 8 named arguments flow through `__call` into typed parameters.

```
class ProductQuery extends ActiveQuery implements ScopableQueryInterface
{
    use ScopableTrait;
    use QualifyColumnTrait;
}

$products = Product::query()
    ->active(active: false)
    ->language(languageId: 'fr')
    ->andWhere(['like', 'title', 'laptop'])
    ->all();
```

`QualifyColumnTrait` auto-prefixes column names with the table qualifier. Scopes write simple names, qualification is transparent. No ambiguous column errors in JOINs.

### Elastic — Dynamic JSON Schema attributes

[](#elastic--dynamic-json-schema-attributes)

JSON column + JSON Schema = dynamic attributes without EAV.

```
class Article extends ActiveRecord implements ElasticInterface
{
    use ElasticTrait;  // handles __get/__set dispatch, no MagicCompose needed
}

// Properties come from JSON Schema, not PHP class definition
$article->author = 'Philippe';     // stored in _extras JSON column
$article->rating = 5;
$article->save();

// Query virtual columns — automatically converted to JSON_VALUE()
$top = Article::query()->where(['>', 'rating', 3])->orderBy(['rating' => SORT_DESC])->all();

// Validation from JSON Schema
$resolver = new ElasticRuleResolver();
$rules = $resolver->resolve($article);
```

### Hazeltree — Nested sets with rational numbers

[](#hazeltree--nested-sets-with-rational-numbers)

Tree structure in RDBMS. Read branches in one query. Write without global renumbering.

Based on [Dan Hazel's research (2008)](https://arxiv.org/abs/0806.3115).

```
class Menu extends ActiveRecord implements HazeltreeInterface
{
    use HazeltreeTrait;  // handles __get/__set dispatch, no MagicCompose needed
}

// Write
$home = new Menu(); $home->name = 'Home'; $home->save();           // path: 1
$about = new Menu(); $about->name = 'About'; $about->saveInto($home); // path: 1.1
$blog = new Menu(); $blog->name = 'Blog'; $blog->saveAfter($about);  // path: 1.2

// Read — one query each
$children   = $home->relativeQuery()->children()->all();
$breadcrumb = $about->relativeQuery()->parent()->includeAncestors()->includeSelf()->all();
$siblings   = $about->relativeQuery()->siblings()->next()->all();
$roots      = Menu::query()->roots()->all();
```

### Combined — Elastic + Hazeltree

[](#combined--elastic--hazeltree)

For models that need both dynamic attributes and tree structure:

```
class Content extends ActiveRecord implements ElasticInterface, HazeltreeInterface
{
    use HazeltreeElasticTrait;  // dispatches to both, resolves all collisions
}
```

Trait architecture
------------------

[](#trait-architecture)

Three layers, zero collision:

LayerPurposeExample**Base traits**Prefixed methods, `protected`, no collision`BaseElasticTrait`, `BaseHazeltreeTrait`**Composite traits**`__get`/`__set` dispatch, one per model`ElasticTrait`, `HazeltreeTrait`, `HazeltreeElasticTrait`**Abstract classes**Convenience, just `use Trait``AbstractElasticActiveRecord`, `AbstractHazeltreeElasticQuery`Base traits use `tryElasticGet()` / `tryHazeltreeGet()` returning `bool`. Composite traits chain: elastic, then hazeltree, then `parent::`. No `insteadof`, no MagicCompose needed.

Tests
-----

[](#tests)

```
vendor/bin/codecept run
```

500 tests, 2726 assertions across 17 suites.

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

[](#documentation)

- [Overview &amp; prerequisites](docs/index.md)
- [Installation](docs/installation.md)
- [API — Scopes &amp; Qualification](docs/api.md)
- [API — Elastic](docs/elastic.md)
- [API — Hazeltree](docs/hazeltree.md)
- [Integration](docs/integration.md)

License
-------

[](#license)

BSD-3-Clause. See [LICENSE.md](LICENSE.md).

Author
------

[](#author)

Philippe Gaultier

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance97

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity39

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

Unknown

Total

1

Last Release

48d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/545714?v=4)[pgaultier](/maintainers/pgaultier)[@pgaultier](https://github.com/pgaultier)

---

Top Contributors

[![pgaultier](https://avatars.githubusercontent.com/u/545714?v=4)](https://github.com/pgaultier "pgaultier (3 commits)")

---

Tags

json-schemaelastictreeactive-recordyiinested-setscopehierarchicalactive-querynamed-parametersquery scopedynamic-attributesvirtual-columnsdynamic-scopecolumn-qualification

###  Code Quality

TestsCodeception

### Embed Badge

![Health badge](/badges/blackcube-active-record/health.svg)

```
[![Health](https://phpackages.com/badges/blackcube-active-record/health.svg)](https://phpackages.com/packages/blackcube-active-record)
```

###  Alternatives

[typicms/nestablecollection

A Laravel Package that extends Collection to handle unlimited nested items following adjacency list model.

88327.2k19](/packages/typicms-nestablecollection)[yiiext/activerecord-relation-behavior

Inspired by and put together the awesomeness of many yii extensions that aim to improve saving of related records. Comes with 100% test coverage and well structured and clean code so it can savely be used in enterprise production enviroment.

9336.5k](/packages/yiiext-activerecord-relation-behavior)[baril/bonsai

An implementation of the Closure Tables pattern for Eloquent.

3593.5k](/packages/baril-bonsai)[stefano/stefano-tree

Nested Set(MPTT) implementation for PHP

2788.5k](/packages/stefano-stefano-tree)[arogachev/yii2-tree

Database tree structures management for Yii 2 framework

222.1k](/packages/arogachev-yii2-tree)

PHPackages © 2026

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