One-to-many iterator
Helper iterator and generator for one-to-many joins., (*1)
Overview
When you want to fetch a one-to-many relation, you're probably using
a JOIN
to avoid the [N+1 selects problem]0., (*2)
Though, it may be difficult to iterate over the result, especially when
you need the whole "many" part of the relation loaded for a process., (*3)
This is why I created this tiny library. It takes a Traversable
of arrays, having a common key to distinguish the "one" part of the
one-to-many relation, and sorted on this key (so it can yield items
in streaming, without loading the whole set in memory)., (*4)
It will then aggregate the "many" part of the relation in a configurable
key., (*5)
Installation
composer require val/one-to-many-iterator
Examples
Your database result iterator, once converted into an array, looks like
this (a typical JOIN
):, (*6)
<?php
[
['id' => 1, 'parent_column' => 'hello', 'child_column' => 'foo'],
['id' => 1, 'parent_column' => 'hello', 'child_column' => 'bar'],
['id' => 2, 'parent_column' => 'world', 'child_column' => 'baz'],
];
But you'd like to iterate over something like this:, (*7)
<?php
[
[
'id' => 1,
'parent_column' => 'hello',
'children' => [
['child_column' => 'foo'],
['child_column' => 'bar'],
],
],
[
'id' => 2,
'parent_column' => 'world',
'children' => [
['child_column' => 'baz'],
],
],
];
To achieve this, just pass your database result to
Val\Iterator\OneToManyIterator
or Val\Iterator\OneToManyGenerator
,
while configuring the common key (here, id
), and aggregate key (here,
children
)., (*8)
Assuming $result
contains the raw SQL result iterator:, (*9)
<?php
// With an iterator
$aggregated = new OneToManyIterator('id', 'children', $result);
// With a generator
$aggregated = new OneToManyGenerator('id', 'children', $result);
foreach ($aggregated as $i => $parent) {
$parent['id'];
$parent['parent_column'];
foreach ($parent['children'] as $child) {
$child['child_column'];
}
}
The difference between the iterator and the generator, is, well.. that
the former implements a raw PHP iterator while
the latter uses a PHP generator (available since
version 5.5)., (*10)
Bugs
- When using a
LEFT JOIN
instead of a JOIN
, thus not guaranteeing
the presence of at least one relation item, the aggregate field
will still contain one item of null
values.