Jump to content
Larry Ullman's Book Forums
banacan

Recursive Function - One Record Missing

Recommended Posts

I'm using Script 1.3 to display an indented listing of all "pages" of my website. I say "pages" because each page is a record in a table. The problem is that one page, the home page, is always missing from the list and I can't figure out why. The SQL is correct and returns all records, including the home page record, when I run the SQL in phpmyadmin, but it never shows up in the script. Can anyone help me understand why not?

 

Here is the modified recursive function:

 

// Function for displaying a list.
// Receives one argument: an array.
function make_list ($parent) {
// Need the main $tasks array:
global $pagelist;
// Start an ordered list:
echo '<ul id="pagelist">';

// Loop through each subarray:
foreach ($parent as $pid=>$item) {

// Display the item:
?>
<li class="pglist <?php if (isset($pagelist[$pid])) { echo 'haschild'; } else { echo ''; } ?>">
 <table class="pgdisp">
 <tr>
 <td class="pgname "><?php echo $item['pgname']; ?></td>
 <td class="hdline"><?php echo $item['hdline']; ?></td>
 <td class="deck"><?php echo $item['deck']; ?></td>
 <td class="order"><?php echo $item['ordr']; ?></td>
 <td class="edit"><a class="cnav" href="admin.php?content=Webtext%2ftextEdit&page_id=<?php echo $item['pgid']; ?>">EDIT</a></td>
 <td class="delete"><a class="cnav" href="admin.php?content=Webtext%2ftextDelete&page_id=<?php echo $item['pgid']; ?>">DELETE</a></td>
 </tr>
 </table>
<?php

// Check for subtasks:
if (isset($pagelist[$pid])) {

// Call this function:
make_list($pagelist[$pid]);

}

// Complete the list item:
echo '</li>';

} // End of FOREACH loop.

// Close the ordered list:
echo '</ul>';

} // End of make_list() function.
// Initialize the storage array:
$pagelist = array();
while (list($page_id, $pid, $page_name, $headline, $deck, $ordr ) = mysql_fetch_array($getText, MYSQL_BOTH)) {
// Add to the array:
$pagelist[$pid][$page_id] = array('pgid'=>$page_id,'pid'=>$pid, 'pgname'=>$page_name,'hdline'=>$headline,'deck'=>$deck,'ordr'=>$ordr );

}
// For debugging:
//echo '<pre>' . print_r($pagelist,1) . '</pre>';
// Send the first array element
// to the make_list() function:
make_list($pagelist[1]);

 

Here is my SQL:

 

mysql_select_db($database_siteadmin, $siteadmin);
$query_getText = "SELECT page_id, pid, page_name, headline, deck, ordr FROM webtext WHERE page_id != '1' ORDER BY pid, ordr LIMIT $offset,$recsperpage";
$getText = mysql_query($query_getText, $siteadmin) or die(mysql_error());
$row_getText = mysql_fetch_assoc($getText);
$totalRows_getText = mysql_num_rows($getText);

 

Interestingly, I had the same problem with my nested navigation menu

that was based on this recursive function. I was able to work around it so it wasn't a problem then, but it is now.

 

Any ideas?

Share this post


Link to post
Share on other sites

One easy miss here. PHP arrays start the count on zero, (0) while MySQL starts at 1. Try printing out the number inside the loop, and see if the first is repeated or the last is missing. Adjust accordingly.

 

This might not be your problem, but it's at least a very easy check.

Share this post


Link to post
Share on other sites

Hi Antonio,

 

Thanks for your reply. I'm not sure how this affected things, but I changed my SQL to this:

 

SELECT page_id, pid, page_name, headline, deck, ordr FROM webtext ORDER BY pid, ordr LIMIT $offset,$recsperpage

 

By eliminating this:

 

WHERE page_id != '1'

 

from the SQL, it works as expected. The record which has page_id = 1 is a special record that establishes main, category pages (those that have a pid = 1). I guess by filtering out that record I was actually making the first record that was NOT page_id = 1, the first array element, and therefore it was not displaying. I guess I don't really understand exactly how that happens in this function, but I'm glad I figured it out, so now I can move forward.

 

Thanks for your help.

  • Upvote 1

Share this post


Link to post
Share on other sites

Hi Larry,

 

I have run into another issue that I hope you can help with. I have a standard paging function that limits the number of records displayed per screen. When the paging function is used in conjunction with the recursive function, the top-level records (those with pid=1) display and page correctly. However, child records no longer display with their parent, and when the paging function reaches a page with children, it produces an error: "Undefined offset: 1". Is there a way to maintain paging while using the recursion function?

 

Thanks.

Share this post


Link to post
Share on other sites

I believe you need to write a more advanced query then. It's a little bit tricky to understand the problem without some example results, but I believe you need to add a where clause here. It could be something along the lines of :

 

WHERE page_id = $page_id OR parent_id = $page_id

 

That might not even be close to a solution for you, but it will help with your thought process. Think about what kind of records you need, check that all variables have correct values, and check number of recursions to make sure you get everything. Use a combination of print_r(), echo and similar to get this info.

Share this post


Link to post
Share on other sites

I solved my problem by using array_slice and setting the offset and records per page within the function. Here is what I did:

 

// Set page display limit
$bunch = array_slice($parent, $offset, $recsperpage, TRUE);

// Loop through each subarray:
foreach ($bunch as $pid=>$item) {

[ echo items here ]

 

This fix actually had I great side effect. What I discovered is that limiting the number of array elements per page using array_slice, limited the number of top-level items only. That means that each parent item contained all of its decendents, and paging results returned X parent items with all of their decendents "attached". Therefore I don't get a page break between sub-items, which would make relationships more difficult to understand. Unless and until my sub-items become too numerous, this will work great. It just means uneven page lengths for display, depending on how many decendents are attached. That's a small price to pay for the clarity and comfort this provides.

 

The other thing I had to do was to change one SQL from counting the number of records to counting the number of top-level records, and using that number in my calculations for total pages and records per page.

 

I must say Larry, I am getting alot of mileage out of your Script. Thanks again for including it in you book.

Share this post


Link to post
Share on other sites

banacan, glad it's all working.

Just as a side note, if you use some sort of loop structure, then you're code is no longer recursive, but iterative.

 

Also, keep in mind that loops are good when you know the number of items, but recursion can be better when you don't know the number of items.

Share this post


Link to post
Share on other sites

HartleySan,

 

Just as a side note, if you use some sort of loop structure, then you're code is no longer recursive, but iterative.

 

Is this a distinction without a difference?

 

Thanks for taking the time to reply.

Share this post


Link to post
Share on other sites

It's a semantic difference used to express two different approaches to looping through items.

I mentioned it because this topic was about recursion, but at the end of the day, you used an iterative loop structure to solve your problem, which seemed to go against the whole theme of the topic (which is why I mentioned it).

 

There are definite pros and cons to both iterative looping (e.g., for loops) and recursion, meaning that one is definitely better than the other in some cases.

Share this post


Link to post
Share on other sites

Actually, PHP is rumored to have bad recursion support. I can't prove that in a scientifically correct manner, but it holds true from personal experience and some unconfirmed sources on google. Generally, if you have ever done recursion in Java, C or anything like that, PHP will not perform comparably to them. I generally stay away from recursion in PHP because of this, although I would not generally recommend anyone from using it neither. Maybe Larry knows more about the recursion support?

 

Recursion is a function that calls itself btw. Generally, recursion has a lot of overhead. You should almost always replace recursion with iterative calls if possible, but that is sometimes not convenient. All kinds of programming tricks has it usage.

 

Btw. This is more of an informative/non-sense post than actual help. I'm speaking in general terms here...

Share this post


Link to post
Share on other sites

Yes, Antonio, you are right.

I remember doing recursion in C++ in high school to solve the Tower of Hanoi problem and having the computer quickly crash 'cause it ran out of memory.

I've also heard that PHP recursion is not optimized well, and it should be avoided in general.

With that said, I think recursion still has its uses (like when you want to go through a directory structure or an XML structure of indeterminate length and depth). I do tend to use recursion sparingly though.

Share this post


Link to post
Share on other sites

Thanks to both of you for your comments. I did a search for "iterative vs recursive" and found a wonderful explanation of the two, and when which is appropriate. Without going into too much depth - that is done beautifully in the article - the main take-away for me was at the end of the article when the author stated:

 

In the case of tree traversals (e.g. file systems), recursion is clearly the best

approach. In fact, any time the depth or breadth of a structure is unknown, using

recursion makes much more sense than using iteration.

 

So when I look at what I'm trying to do (I started two separate posts addressing different parts of the same problem), I need to use both recursive and iterative functions. I need the recursive to traverse the tree to whatever depth is there, keeping track of the hierarchical relationship, and I need the iterative to display the results in a paged way.

 

Thanks again to you both for sharing your knowledge and for helping to illuminate some important concepts.

Share this post


Link to post
Share on other sites

Just to emphasize a previous thing I said, which you, banacan, responded to with, "Is this a distinction without a difference?":

 

Also, keep in mind that loops are good when you know the number of items, but recursion can be better when you don't know the number of items.

Share this post


Link to post
Share on other sites

HartleySan,

 

It seems we were both posting about the same time. Yes, after reading the article, I realized the significance. BTW, I wasn't being flip, I just wasn't clear on the subtleties. I now have a much better understanding. Thanks for your input.

Share this post


Link to post
Share on other sites

Yeah, no, it's okay. I realize that I probably came off as a bit snippy in my previous post.

I was being more sarcastic than anything, although it probably didn't come across that way in text form.

Sorry for the bad joke, I suppose.

Share this post


Link to post
Share on other sites

HartleySan,

 

No, I did not take your reply as snippy or sarcastic. You and Antonio are way more advanced in your programming skills and understanding than I am, and I like to take advantage of that knowledge whenever possible. As Antonio said in one post, he may not have the solution, but he can help my thought process. By you mentioning the iterative vs recursive, it got me thinking, and that led me to a search, which resulted in finding a very helpful article, that ended in better understanding. All of this was very important and helpful, which is why I'm so grateful to you and Antonio and of course Larry.

 

Best wishes.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...