Reputation: 5104
I'm having trouble getting started with the following:
I'm trying to create a multi-level tree visualization of the entire relationship path without knowing the number of levels. How would I best do this?
Here is an example of the data array (simplififed):
array(
1 => array( //this key is the answer id
question_id = 1,
answers = array(
0 => answer_opens_question__id = 2,
1 => answer_opens_question__id = 3,
2 => answer_opens_question__id = 5
)
),
2 => array(
question_id = 2,
answers = array(
0 => answer_opens_question__id = 1,
1 => answer_opens_question__id = 5
)
),
5 => array(
question_id = 3,
answers = array(
0 => answer_opens_question__id = 2
)
)
)
In theory, this could go on forever and end up in an infinite loop - it's highly unlikely that this will ever happen though, since this data is user generated and not dynamically created.
I'm only looking for a way to recursively display a path like question > answer>>question > answer>>question > answer>>question> ...
- the output will be in HTML with nested ul-li
.
Any ideas on how I could do this? Thanks a lot for input of any kind.
EDIT/Solution:
Thanks to DaveRandom, I got it: write a function that loops through each answer and calls itself for each.
function recursiveTree($id) {
global $data; //an array like the one above
if(array_key_exists($id, $data)) {
echo '<ul><li>';
echo $data[$id]['question_name']; //question
if(is_array($data[$id]['answers']) && !empty($data[$id]['answers'])) {
foreach($data[$id]['answers'] as $answer) {
echo '<ul><li class="answer"><div>'.$answer['text'].' opens </div>';
recursiveTree($answer['answer_opens_question__id']); //call this very function for this answer's question - that's the trick
echo '</li></ul>';
}
}
echo '<li></ul>';
}
}//recursiveTree()
recursiveTree(1); //where 1 is the first question's id
I'm not keeping track of questions yet like Dave is in this code (please check out the accepted answer below) - that will be added. It works like this already though (because I don't have any loops in my test data), but I agree with everybody that it's advisable to take care of possible infinite loops.
With some padding and some borders around li.answer
, the above output is even readable :)
Thanks again DaveRandom.
Upvotes: 0
Views: 339
Reputation: 88657
Maybe this will give you a prod in the right direction? (Slightly fixed)
function recursive_tree ($startQuestionId, $alreadyDisplayed = array()) {
// Make sure we only display each question once
$alreadyDisplayed[] = $startQuestionId;
// Replace this with a sensible query to get the answers for question id $startQuestionId
$answers = $db->query("SELECT answers.answerId, answers.opensQuestionId FROM questions, answers WHERE questions.questionId = '$startQuestionId' AND answers.questionId = questions.questionId");
// Echo a header for the question
echo "<div id='question$startQuestionId'>Question $startQuestionId\n<ul>\n";
while ($row = $db->fetch()) {
// Loop through the answers to this question
echo "<li>\nAnswer id {$row['answerId']} opens question id {$row['opensQuestionId']}\n";
if (!in_array($row['opensQuestionId'],$alreadyDisplayed)) {
// The linked question hasn't been displayed, show it here
$alreadyDisplayed = array_merge($alreadyDisplayed,recursive_tree($row['opensQuestionId'],$alreadyDisplayed));
} else {
// The linked question has already been displayed
echo "(<a href='#question{$row['opensQuestionId']}'>Already displayed</a>)\n";
}
echo "</li>\n";
}
// Close everything off
echo "</ul>\n</div>\n";
return $alreadyDisplayed;
}
// And call it like this
$questionToStartAt = 1;
recursive_tree($questionToStartAt);
Upvotes: 1
Reputation: 360702
You do have a loop in that data. Question #1 has an answer pointing at question #2, and question #2 has an answer pointing at question #1. Ditto for #5 and #2.
If you want to prevent an infinite loop, you'll just have to build up a parallel breadcrumb array as you recurse down the tree. if you come to question #2 and see that it's pointing at question #1 - well, the breadcrumb array indicates that #1's been output already, so you skip recursing down that particular branch, and no loop occurs.
Upvotes: 2