I have a PHP array that outlines a parent-child relationships between objects, based on their ID. The array could potentially be infinitely deep, but the only rule is that "you may not add a child ID to a parent, where the child ID is a parent or grandparent (or great-grandparent etc etc) of said parent", in order to rule out recursive loops.
For example:
<?php
// Good relationship: 6 and 4 are children of 7, with 5 a child of 6 and so on
$good_relationship = [
'id' => 7,
'children' => [
[
'id' => 6,
'children' => [
[
'id' => 5,
'children' => [.. etc etc..]
]
]
],
[
'id' => 4,
'children' => []
]
]
];
// Badly-formed relationship: 6 is a child of 7, but someone added 7 as a child of 6.
$bad_relationship = [
'id' => 7,
'children' => [
[
'id' => 6,
'children' => [
[
'id' => 7,
'children' => [ ... 6, then 7 then 6 - feedback loop = bad ... ]
]
]
],
[
'id' => 4,
'children' => []
]
]
];
?>
I'm trying to write a function that checks for recursion issues when an ID is potentially added as a child to another ID. It would take in an ID ($candidate_id) and tries to add it as a child of another ID ($parent_id), and checks the existing array ($relationship) all the way back up the chain, and returns true if the candidate does not show up as a parent,grandparent,etc of $parent, and false if the candidate addition will cause a recursion issue by being added.
From the above $good_relationship, it would return true is I added ID 3 to ID 5, but false if I added ID 7 to ID 5.
Here's what I have so far, but I know it's way off - it's only checking for immediate grandparent of the candidate ID.
<?php
public function check_candidate($array, $candidate_id, $parent_id, &$grandparent_id = 0)
{
$reply_array = [];
foreach($array as $action)
{
// If $action['id'] is the same as the grandparent,
if($grandparent_id == $action['id'])
{
return false;
}
$grandparent_id = $action['id'];
if(isset($action['children']) && count($action['children']) >= 1)
{
$this->check_candidate($action['children'], $candidate_id, $parent_id, $grandparent_id);
}
}
return true;
}
?>
I've had a look at array_walk_recursive() in this case, but if $good_relationship has more than 1 element to it (which it always will), the callback will not know how 'deep' it is within the function, and it all becomes a bit of a nightmare.
Can anyone help me here?