You are here

function party_hat_get_tree in Party 7

Same name and namespace in other branches
  1. 8.2 modules/party_hat/party_hat.module \party_hat_get_tree()

Build a hierarchical representation of hats.

Parameters

$parent: (optional) A $hat entity. If set, the subtree of this hat is returned.

Return value

An array of PartyHat entities that are children of $parent, in depth-first order. The hat objects are augmented with the following properties:

  • 'depth': the depth relative to the $parent
  • 'parents': an array of the hat's parents.
3 calls to party_hat_get_tree()
party_hat_build_hat_options in modules/party_hat/party_hat.module
Build a set of hats for EntityMetadataWrapper::optionsList().
party_hat_form in modules/party_hat/party_hat.admin.inc
Entity form for party hats.
party_user_settings_form in modules/party_user/party_user.admin.inc
User integration settings form.

File

modules/party_hat/party_hat.module, line 359
party_hat.module Provides an extensible access system for parties.

Code

function party_hat_get_tree($parent = '', $max_depth = NULL) {
  $children =& drupal_static(__FUNCTION__, array());
  $parents =& drupal_static(__FUNCTION__ . ':parents', array());
  $hats =& drupal_static(__FUNCTION__ . ':hats', array());

  // We cache trees, so it's not CPU-intensive to call get_tree() on a term
  // and its children, too.
  if (empty($children)) {
    $children = array();
    $parents = array();
    $hats = array();
    $hats = party_hat_get_all_hats();
    foreach ($hats as $hat) {

      // If the parent is empty, fill it with an empty string. This helps us
      // search from the very top of the tree and gets removed later.
      if (empty($hat->parent)) {
        $hat->parent = '';
      }
      $children[$hat->parent][] = $hat->name;
      $parents[$hat->name][] = $hat->parent;
    }
  }
  $max_depth = !isset($max_depth) ? count($children) : $max_depth;
  $tree = array();

  // Keeps track of the parents we have to process, the last entry is used
  // for the next processing step.
  $process_parents = array();
  $process_parents[] = is_object($parent) ? $parent->name : $parent;

  // Loops over the parent terms and adds its children to the tree array.
  // Uses a loop instead of a recursion, because it's more efficient.
  while (count($process_parents)) {
    $parent = array_pop($process_parents);

    // The number of parents determines the current depth.
    $depth = count($process_parents);
    if ($max_depth > $depth && !empty($children[$parent])) {
      $has_children = FALSE;
      $child = current($children[$parent]);
      do {
        if (empty($child)) {
          break;
        }
        $hat = $hats[$child];
        if (isset($parents[$hat->name])) {

          // Clone the term so that the depth attribute remains correct
          // in the event of multiple parents.
          // @todo Remove IF we're not allowing multiple parents.
          $hat = clone $hat;
        }
        $hat->depth = $depth;
        unset($hat->parent);

        // Filter out the empty string parents.
        $hat->parents = array_filter($parents[$hat->name]);
        $tree[$hat->name] = $hat;
        if (!empty($children[$hat->name])) {
          $has_children = TRUE;

          // We have to continue with this parent later.
          $process_parents[] = $parent;

          // Use the current hat as parent for the next iteration.
          $process_parents[] = $hat->name;

          // Reset pointers for child lists because we step in there more often
          // with multi parents.
          reset($children[$hat->name]);

          // Move pointer so that we get the correct hat the next time.
          next($children[$parent]);
          break;
        }
      } while ($child = next($children[$parent]));
      if (!$has_children) {

        // We processed all terms in this hierarchy-level, reset pointer
        // so that this function works the next time it gets called.
        reset($children[$parent]);
      }
    }
  }
  return $tree;
}