PHPackages                             obernard/property-indexer - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. obernard/property-indexer

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

obernard/property-indexer
=========================

Object property manipulation tools based on symfony/property-access

v1.1(4y ago)013.0k↓50%MITPHPPHP &gt;=8.0

Since Jan 24Pushed 4y ago1 watchersCompare

[ Source](https://github.com/pytoccaz/php-property-indexer)[ Packagist](https://packagist.org/packages/obernard/property-indexer)[ RSS](/packages/obernard-property-indexer/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (2)Versions (10)Used By (0)

🖇 Porperty Indexer &amp; Tree builder
=====================================

[](#-porperty-indexer--tree-builder)

- A `PorpertyIndexer` indexes objects/arrays properties inside a key-value map.
- A `PorpertyTree` builds a Tree structure from a collection of objects.

`PorpertyIndexer` and `PropertyTree` are iterables.

Index *key* and *value* values one case, nodes and leaves in the other are retreived from objects or arrays via [symfony/property-access](https://symfony.com/doc/current/components/property_access.html#usage) component.

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

[](#installation)

```
# from packagist
composer require obernard/property-indexer

# or from github
git clone git@github.com:pytoccaz/php-property-indexer.git
```

Porperty Indexer
----------------

[](#porperty-indexer)

A `PorpertyIndexer` indexes objects/arrays properties inside a key-value map.

Choose :

- a string|int property to provide keys
- a mixed property or the objects|arrays themselves to provide values

### Index objects properties

[](#index-objects-properties)

Say you have objects with properties `id` and `value`:

```
$obj1->id == "id1";
$obj1->value == "value1";

$obj2->id == "id2";
$obj2->value == "value2";
```

Create an indexer for *id&amp;value* objects :

```
$indexer = new Obernard\PropertyIndexer\PropertyIndexer('id', 'value');
```

Add objects:

```
$indexer->add($obj1)->add($obj2);
```

Retreive indexed values via their key:

```
$index->get('id1') //  returns "value1"
$index->get('id2') //  returns "value2"
```

Or directly via a reference to an indexed object:

```
$index->get($obj2) //  returns "value2"
```

### Index array properties

[](#index-array-properties)

Say you have array maps with `id` and `value` keys:

```
$array1= ["id" => "id1", "value" => "value1"];

$array2 = ["id" => "id2", "value" => "value2"];
```

Create an indexer for *id&amp;value* arrays (note the use of brakets for array property path):

```
$indexer = new Obernard\PropertyIndexer\PropertyIndexer('[id]', '[value]');
```

Add arrays:

```
$indexer->add($array1)->add($array2);
```

Retreive indexed values via their key:

```
$index->get('id1') //  returns "value1"
$index->get('id2') //  returns "value2"
```

### Bulk Load collections

[](#bulk-load-collections)

Use the `load` method:

```
$indexer = new Obernard\PropertyIndexer\PropertyIndexer('[id]', '[value]');
$collection = [
            ["id" => "id1", "value" => "value1"],
            ["id" => "id2", "value" => "value2"]
]
$indexer = $indexer->load($collection);
$index->get('id1') //  returns value1
$index->get('id2') //  returns value2
```

Or invoke `PropertyIndexer` with a third argument:

```
$indexer = new Obernard\PropertyIndexer\PropertyIndexer('[id]', '[value]', $collection);
```

### Index Objects or Arrays (not their properties)

[](#index-objects-or-arrays-not-their-properties)

Don't specify the value path or set it to null when invoking `PropertyIndexer`:

```
$objectIndexer = new Obernard\PropertyIndexer\PropertyIndexer('id');
$arrayIndexer = new Obernard\PropertyIndexer\PropertyIndexer('[id]', null);
```

Porperty Tree Builder
---------------------

[](#porperty-tree-builder)

A `PorpertyTree` builds a Tree structure from a collection of objects.

Leaves path and values are picked from the items of the processed collection.

### Porperty Tree basics

[](#porperty-tree-basics)

Say you have objects with properties `id`, `value` and `date`:

```
$obj1->id == "id1";
$obj1->value == "value1";
$obj1->date == "today";

$obj2->id == "id2";
$obj2->value == "value2";
$obj2->date == "today";

// first arg is the collection of objects
// second arg is the "leaves" value
// third arg is a groupBy-like definition of the tree levels
$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], 'value', ['id', 'date']);
//   ["tree":"Obernard\PropertyIndexer\PropertyTree":private]=>
//   array(2) {
//     ["id1"]=>
//     array(1) {
//       ["today"]=>
//       string(6) "value1"
//     }
//     ["id2"]=>
//     array(1) {
//       ["today"]=>
//       string(6) "value2"
//     }
//   }

$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], 'value', ['date', 'id']);
//   ["tree":"Obernard\PropertyIndexer\PropertyTree":private]=>
//   array(1) {
//     ["today"]=>
//     array(2) {
//       ["id1"]=>
//       string(6) "value1"
//       ["id2"]=>
//       string(6) "value2"
//     }
//   }
```

### Porperty Tree mode ARRAY\_LEAF

[](#porperty-tree-mode-array_leaf)

Mind the possible colisions between objects sharing the "same" properties path:

```
$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], 'value', ['date']);
//   ["tree":"Obernard\PropertyIndexer\PropertyTree":private]=>
//   array(1) {
//     ["today"]=>
//     string(6) "value2"
//   }
```

To avoid possible colisions, switch to array-type leaves:

```
$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], 'value', ['date'], PropertyTree::ARRAY_LEAF);
//   ["tree":"Obernard\PropertyIndexer\PropertyTree":private]=>
//   array(1) {
//     ["today"]=>
//     array(2) {
//       [0]=>
//       string(6) "value1"
//       [1]=>
//       string(6) "value2"
//     }
//   }
```

### Porperty Tree advanced features

[](#porperty-tree-advanced-features)

### Closure as valuePath

[](#closure-as-valuepath)

`$valuePath` 2nd arg accepts a one-arg Closure (that must return int|string). While iterating the object|array collection, PorpertyTree will bind the arg with the current object|array item to extract a value.

To retrieve the object items themselves, you may use an Identity Closure ( or better set `valuePath` to `null` :P ) :

```
// Use an Idendity Closure to retrieve Objects themselves:
$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], function($item):string {return $item;}, ['id']);
  ["tree":"Obernard\PropertyIndexer\PropertyTree":private]=>
//   array(2) {
//     ["id1"]=>
//     object(stdClass)#106 (3) {
//       ["id"]=>
//       string(3) "id1"
//       ["value"]=>
//       string(6) "value1"
//       ["date"]=>
//       string(5) "today"
//     }
//     ["id2"]=>
//     object(stdClass)#83 (3) {
//       ["id"]=>
//       string(3) "id2"
//       ["value"]=>
//       string(6) "value2"
//       ["date"]=>
//       string(5) "today"
//     }
//   }

// Or a simple way :
$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], null, ['id']);
```

### Closure as groupByproperties

[](#closure-as-groupbyproperties)

array `$groupByproperties` 3nd arg accepts one-arg Closures (that must return int|string). While iterating the object|array collection, PorpertyTree will bind the arg with the current object|array item to extract a tree-path node :

```
$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], null, [function($item):string {return $item->id;}]);

// is a complicated way to get the same resulting tree as :
$tree = new Obernard\PropertyIndexer\PropertyTree([$obj1, $obj2], null, ['id']);
```

Those 2 examples are dumb-ones. Closures are for performing complex tasks (to retrieve path or leaves) that objects properties do not provide natively.

Tests
-----

[](#tests)

Run `composer test`.

Contributing
------------

[](#contributing)

Feel free to submit pull requests.

Licence
-------

[](#licence)

MIT

Copyright (c) 2022 Olivier BERNARD

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity23

Limited adoption so far

Community4

Small or concentrated contributor base

Maturity60

Established project with proven stability

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

Total

9

Last Release

1527d ago

Major Versions

v0.x-dev → v1.02022-03-03

### Community

Maintainers

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

---

Tags

collectionindexpropertytreeaccessorgroupBy

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/obernard-property-indexer/health.svg)

```
[![Health](https://phpackages.com/badges/obernard-property-indexer/health.svg)](https://phpackages.com/packages/obernard-property-indexer)
```

###  Alternatives

[symfony/property-access

Provides functions to read and write from/to an object or array using a simple string notation

2.8k295.3M2.5k](/packages/symfony-property-access)[knplabs/knp-menu

An object oriented menu library

1.4k55.8M285](/packages/knplabs-knp-menu)[cuyz/valinor

Dependency free PHP library that helps to map any input into a strongly-typed structure.

1.5k9.2M108](/packages/cuyz-valinor)[chdemko/sorted-collections

Sorted Collections for PHP &gt;= 8.2

222.5M3](/packages/chdemko-sorted-collections)

PHPackages © 2026

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