Jump to content
Larry Ullman's Book Forums

Recommended Posts

Hi,

 

I am trying to use similar recursive logic to Larry's in chapter 1.  I have modified my code to enable you to mark tasks as completed and that works just fine.  Now I am trying to use the recursive approach to list out the completed tasks in the same manner as 'live' tasks get listed.

 

I create a two-dimensional array of completed tasks and then try to use the recursive logic to list out those tasks.  It works only partially in that, say, a completed task has a parent, then that prints out OK. But, the logic in the display_completed_tasks recursive function does not 'pop back up' to the next highest level after (correctly) printing out part of the array.

 

Maybe it is because the key of the first array passed is not necessarily zero - you can see that I save the first key in the list_completed_tasks function.

 

I have printed out the arrays and they look OK.  Here's my code:

function list_completed_tasks()

 {

  global $dbc, $completed_tasks;

  $first_time_through = TRUE;

  $qa = 'SELECT task_id, parent_id, task FROM tasks WHERE date_completed IS NOT NULL ORDER BY parent_id, date_added ASC';

  $ra = mysqli_query($dbc, $qa);

  $completed_tasks = array();  // Initialize the storage array:

  while (list($task_id, $parent_id, $task) = mysqli_fetch_row($ra))

     { // Add to the array:

    $completed_tasks[$parent_id][$task_id] =  $task;

    if ($first_time_through)

     {

      $first_key = $parent_id;

      $first_time_through = FALSE; 

     }

    }

  echo '<h3>Completed Tasks Array Details</h3><pre>' . print_r($completed_tasks, 1) . '</pre>';  // For debugging and general interest

  display_completed_tasks($completed_tasks[$first_key]);

  

 } // end list_completed_tasks function
function display_completed_tasks($complete_tasks)

 {

  // note: the value passed is an array

  echo '<p>Coming into display_completed_tasks: <pre>' .  print_r($complete_tasks, 1) . '</pre>';

  global $completed_tasks; 

  // Start an ordered list:

  echo '<ol>';

 

  // Loop through each subarray:

  foreach ($complete_tasks as $task_id => $done)

    { 

   // Display the item:

   echo <<<EOT

<li><input type="checkbox" name="marked_tasks[$task_id]" value="$done" /> $done

EOT;

   // Note that the above creates an array of task_ids, even if only one checkbox is selected

   // The array is later accessed through the super-global $_POST['marked_tasks']

   // Check for subtasks:

   if (isset($completed_tasks[$task_id]))

    {   // isset checks the variables from left to right

       // in this instance, the isset is looking to see if the current sub-array element's task_id

        // is a parent_id in the multi-dimensional array $completed_tasks

        // Call this function recursively:

        // echo '<p>About to call the function recursively - calling it with: <pre>' .  print_r($completed_tasks[$task_id], 1) . '</pre>';  // For debugging and general interest

     display_completed_tasks($completed_tasks[$task_id]);  // note that $completed_tasks[$task_id] is an array in its own right (a sub-array of $completed_tasks)

     }

   // Complete the list item:

   echo '</li>';

  } // End of FOREACH loop.

  

  // Close the ordered list:

  echo '</ol>';
 } // End of display_completed_tasks() function.

Any advice will be appreciated and thank you in anticipation.

Link to comment
Share on other sites

If I understand you correctly, it sounds like you have a flat DB structure that you want to turn into a hierarchical structure with parent ID data in the DB.

 

Could you please provide more info about your DB structure as well as the intended structure you're looking for?

Thanks.

Link to comment
Share on other sites

Hi HartleySan,

 

As always, thanks for getting back to me.  I am trying to use the logic in view_tasks.php as per the book page 18-23 but adjusted to recursively list out tasks marked as completed rather than 'live' tasks (the 'live' tasks part of my script works just fine).  The DB structure is as per page 9 except that I used 'DATETIME' instead of 'TIMESTAMP'.  Thus I check for NULL rather than a zeroed TIMESTAMP.

 

The problem that I am getting is that the recursive function does not 'pop out' at the end of processing a subordinate task array to go back to processing a higher-level task array.

 

I have been looking at my code 'till I am blue in the face' but am obviously missing something - it should function exactly as per the logic in Larry's view_tasks.php script.

 

Again, any advice will be most appreciated.

 

Cheers from Oz.

Link to comment
Share on other sites

Mmmm - I think that I can see what the issue is.  When listing 'live' tasks, the initial array passed has all the tasks with no parents, i.e., all tasks with parent-id of zero.  Thus when a lower-level task processing has been completed, the recursion 'pops-up' to the next element in the highest-level array.

 

When I try and use this logic for completed tasks, the only array element that initially gets passed to the recursive routine is the first array element. The logic correctly 'pops back' to the higher level when a lower-level completed task has been listed, but as the initial array only had one element there is nothing for the recursive logic to process and thus the function finishes its processing. 

 

I will have to try and think of another way to list completed tasks.  This was in the spirit of a 'review and pursue' challenge!

 

Cheers, Necuima.

Link to comment
Share on other sites

The whole point of recursion is that you call a function within itself, but the argument you send that function each time is different, thus allowing you to do things like advance through the hierarchy of a multidimensional array, regardless of how deep or complex it is.

 

To that end, make sure you're passing the recursively called function the right argument each call. Here's a simply example:

function list_array($arr) {
  foreach ($arr as $val) {
    if (is_array($val)) {
      list_array($val);
    } else {
      echo "$val<br>";
    }
  }
}
Link to comment
Share on other sites

Yes, you are quite correct. 

 

FYI I 'manipulated' the array of completed tasks so that the recursive routine would display the completed tasks correctly.  I must admit that it took a while to get the 'manipulation' code to work correctly but I got there in the end.

 

There were two key issues - firstly for completed tasks, as they may have only been sub-tasks, the highest-level primary key in the completed tasks array is not necessarily zero.  So the first task was to save that highest-level value for possible subsequent use.

 

The second issue, again arising from the fact that completed tasks may have been sub-tasks, was to identify tasks where there was no link to a higher-level task in the completed-tasks array, and in that case to substitute the saved value from the paragraph above.

 

Once this was done, everything worked OK. There was nothing wrong with the 'display_completed_tasks' recursive function!

 

Thanks again for your input and suggestions.

 

Cheers, Necuima.

Link to comment
Share on other sites

 Share

×
×
  • Create New...