I have an HMVC webapplication developed in PHP.
In my controller and in my view, I need to iterate over multiple arrays. Between the iterations I need to use/echo some values out of the array. The problem is that my code is a mess and I was wondering if there are better best practices to do this kind of loops.
For the following examples: $header
has 15 values and $groups
has 1000 values.
I have the following (simplified) example of code in my view:
<? foreach($headers as $header) { ?>
<div class="header"><?= $header->number ?></div>
<? $i = 0; ?>
<? foreach($groups as $group) { ?>
<? $part_letter = $group->part->letter ?>
<? if ($group->number !== $header->number) { continue; } ?>
<? $i++; ?>
<? if ($i === 1) { $first_group = true; } else { $first_group = false; } ?>
<div class="<?= $first_group ? 'colored' : ''>
<?= echo $group->name ?>
<?= echo $part_letter ?>
</div>
<? } ?>
<? } ?>
I have the following (simplified) example of code in my controller:
foreach($headers as $header) {
$pdf[] = $header->number;
$i = 0;
foreach($groups as $group) {
$part_letter = $group->part->letter;
if ($group->number !== $header->number) { continue; }
$i++;
if ($i === 1) { $first_group = true; } else { $first_group = false; }
$pdf['first_group'] = $first_group;
$pdf['group_name'] = $group->name;
$pdf['part_letter'] = $part_letter;
}
}
My thoughts
$headers
and $groups
, but what would be the output? In the view I need some array values between HTML code and in the controller I need to save them in the $pdf
array.My second thought was to create a separate function to iterate over both arrays to create a 3rd and 4th array with all significant values in it. That 3rd and 4th array would look something like this:
$header_values[$id] = $number;
$group_values[$id] = array($part_letter, $group_equals_header_number, $is_first_group);
Then my controller would look like this:
foreach($header_values as $header_value) {
$pdf[] = $header_value;
foreach($group_values as $group_value) {
if (!$group_value['group_equals_header_number']) { continue; }
$pdf['first_group'] = $group_value['is_first_group'];
$pdf['group_name'] = $group_value['group_name'];
$pdf['part_letter'] = $group_value['part_letter'];
}
}
And my view would look like this:
<? if (!$group_value['group_equals_header_number']) { continue; } ?>
<div class="<?= $group_value['is_first_group'] ? 'colored' : ''>
<?= echo $group_value['group_name'] ?>
<?= echo $group_value['part_letter'] ?>
</div>
It looks a bit better, the downside is that I need an extra iteration.
What is best practice with this kind of repeating loops / repeating code, while keeping my code DRY?
sorry for my too quick comment, i don't have seen that the "group loop" is not a children of $header
then in this case, you can waste time if you have lots of headers and lots of groups in differents headers
you can try this code, it will use a little more time for the first task but it will spare more time for the second task
<?php
////////////////////////////////////////////////////
// *** first task : grouping "groups" by header
$listHeaders = [];
// searching all the headers numbers
foreach ($headers as $header)) {
$listHeaders[$header->number] = $header;
}
// associating groups with header
foreach ($groups as $group) {
$headerNumber = $group->number;
if (!isset($listHeaders[$headerNumber])) {
continue;
}
if (!isset($listHeaders[$headerNumber]->listGroups)) {
$listHeaders[$headerNumber]->listGroups = [];
}
$listHeaders[$headerNumber]->listGroups[] = $group;
}
////////////////////////////////////////////////////
// *** second task : display
foreach ($listHeaders as $headerNumber => $header) {
?>
<div class="header">
<?php echo $headerNumber;?>
</div>
<?php
foreach ($header->listGroups as $index => $group) {
?>
<div class="<?php echo (0 !== $index) ? "" : "colored";?>">
<?php echo $group->name;?>
<?php echo $group->part->letter;?>
</div>
<?php
} // END foreach ($header->listGroups as $index => $group) {
} // END foreach ($listHeaders as $headerNumber => $header) {
just do benchmarks to choose wich code take less time with your datas