Example #1
0
 /**
  * Create a data tree of the selectable forms.  Deisgned to be fed into tree select
  * @param array $fields an ordered array E.g array('village+county','county','district,'region+country','country').
  * it is an "bottom up" array of string where strings are of the form "$form" or "$form+$link_field".  In the case of
  * the former type, then $link_field is assumed to be the next form.  So for example, "county" has link field "district".
  * If a "$form(+$link_field)" is surrounded by brackets [ ] , it is not displayed.
  * @param array $forms An unorderd array of form names whose values we allow to be selected
  * @param array $limits An array with keys form names and value limit data
  * @param array $orders An array with keys form names and values array of field orders for that form.  
  *                      If the form name has no orders, we use default ordering for that form based on its displayed firelds
  * @param int $show_hidden 0=non-hidden, 1=All, 2=hidden only.  Defaults to 0
  * @param array $report A report name to use for the query instead of building it from form cache or directly.
  * @return array
  */
 public static function buildDataTree($fields, $forms, $limits, $orders = array(), $show_hidden = 0, $report = null, $style = 'default')
 {
     //$forms = array(village, county) -- order does not matter.
     //$fields -- order matters.
     //Example0:
     //$fields == array('village','county','[district+cssc_region],'cssc_region+cssc_country','country')
     //Example1:
     //$fields == array('village+county','county','district,'region+country','country')  -- you could just as easily have used 'region'
     //Example2:
     //$fields == array('village','county');
     //build the tree top down.  top  = country in Example 0,1 and top = county in Example 2
     if (!is_array($forms) || !is_array($fields) || count($fields) == 0) {
         return array();
     }
     $data = array();
     $displayed = array();
     $last_form = false;
     $fields = array_reverse($fields);
     foreach ($fields as &$field) {
         //start0: $form = country $link_field = false   $last_form = false
         //next0: $form = cssc_region $link_field = country $last_form = country
         //start1: $form = country $link_field = false   $last_form = false
         //next0: $form = region $link_field = country $last_form = country
         //start2: $form = county $link_field = false   $last_form = false
         //next2: $form = village $link_field = county  $last_form = county
         if (!is_string($field)) {
             return array();
         }
         $len = strlen($field);
         if ($len >= 2 && $field[0] == '[' && $field[$len - 1] == ']') {
             $field = substr($field, 1, $len - 2);
             $display = false;
         } else {
             $display = true;
         }
         if (($pos = strpos($field, '+')) !== false) {
             list($form, $link_field) = explode('+', $field, 2);
             if ($last_form == false) {
                 //throw away junk linked field data on the top level form
                 $link_field = false;
             }
         } else {
             $form = $field;
             $link_field = false;
         }
         if (!$form) {
             return array();
         }
         if (!$link_field) {
             $link_field = $last_form;
         }
         $field = array($form, $link_field);
         $displayed[$form] = $display;
         $last_form = $form;
     }
     unset($field);
     $styles = array();
     $ff = I2CE_FormFactory::instance();
     if ($last_form) {
         $avail_styles = array($last_form => $style);
         $curr_style = $style;
         foreach (array_reverse($fields) as $formfield) {
             list($form, $link_field) = $formfield;
             if (!$form || !($formObj = $ff->createContainer($form)) instanceof I2CE_Form) {
                 break;
             }
             if (array_key_exists($form, $avail_styles) && is_string($avail_styles[$form])) {
                 $curr_style = $avail_styles[$form];
             } else {
                 $curr_style = 'default';
             }
             $styles["{$form}+{$link_field}"] = $curr_style;
             if (!$link_field || !($fieldObj = $formObj->getField($link_field)) instanceof I2CE_FormField) {
                 break;
             }
             $avail_styles = I2CE_List::getDisplayFieldStyles($form, $style);
         }
     }
     if (is_array($report)) {
         $results = self::buildReportTree($fields, $forms, $displayed, $limits, $orders, $show_hidden, $report);
         if (count($results) > 0) {
             return $results;
         } else {
             I2CE::raiseError("buildReportTree returned no results so defaulting to regular display.  If there is data then something went wrong so it should be fixed.");
         }
     }
     $use_cache = true;
     if (I2CE_ModuleFactory::instance()->isEnabled("CachedForms")) {
         $fs = I2CE_FormStorage::getMechanismByStorage("cached");
         if ($fs instanceof I2CE_FormStorage_cached) {
             try {
                 return $fs->buildDataTree($fields, $forms, $displayed, $limits, $orders, $show_hidden, $style);
             } catch (Exception $e) {
                 $use_cache = false;
                 I2CE::raiseError("Could not cache {$form}");
             }
         }
     }
     $phonebook = array();
     //indexed by "$form|$id" with values (by reference) the arrays at which contains the 'children' sub-array  for $form|$id node
     $parent_links = array();
     //indexed by "$form|$id" with values "$pform|$pid" which is the form/id that "$form|$id" is linked against
     $display_string = array();
     foreach ($fields as $formfield) {
         list($form, $link_field) = $formfield;
         if (array_key_exists("{$form}+{$link_field}", $limits)) {
             $limit = $limits["{$form}+{$link_field}"];
         } elseif (array_key_exists($form, $limits)) {
             $limit = $limits[$form];
         } else {
             $limit = array();
         }
         if (!($formObj = $ff->createContainer($form)) instanceof I2CE_Form) {
             continue;
         }
         $style = 'default';
         if (array_key_exists("{$form}+{$link_field}", $styles)) {
             $style = $styles["{$form}+{$link_field}"];
         }
         //if we dont show the hidden list memmber we need to include the limit where i2ce_disabled is false
         $limit = self::showHiddenLimit($limit, $show_hidden);
         $disp_fields = I2CE_List::getDisplayFields($form, $style);
         $disp_str = I2CE_List::getDisplayString($form, $style);
         //start0:  $form = country, $fields = (name)
         //next0:  $form = cssc_region, $fields = (name, cssc_country)
         //next0:  $form =  district $fields = (name, cssc_region)
         //next0: $form = county $field = (name,distrcit)
         //end0: $form = villate $field = (name,county)
         //start1:  $form = country, $fields = (name)
         //next1:  $form = region, $fields = (name, country)
         //next1:  $form =  district $fields = (name, region)
         //etc.
         if (array_key_exists($form, $orders)) {
             $order = $orders[$form];
         } else {
             $order = I2CE_List::getSortFields($form, $style);
         }
         ksort($order);
         if ($link_field) {
             $field_datas = I2CE_FormStorage::listFields($form, $link_field, false, $limit, $order, false, -1, $use_cache);
         } else {
             $field_datas = I2CE_FormStorage::listFields($form, 'id', false, $limit, $order, false, -1, $use_cache);
         }
         $display_datas = I2CE_FormStorage::listFields($form, $disp_fields, false, $limit, $order, false, -1, $use_cache);
         $link_id = false;
         $last_link = false;
         $selectable = in_array($form, $forms);
         foreach ($field_datas as $id => $field_data) {
             $formid = $form . '|' . $id;
             if (!$link_field) {
                 //this should only be the case for the top form
                 $parent =& $data;
             } else {
                 //we are not at the top.
                 $link = $field_data[$link_field];
                 unset($field_data[$link_field]);
                 if ($last_link != $link) {
                     if (!array_key_exists($link, $phonebook)) {
                         //don't know where to put this as a child of the previous one so skip it
                         continue;
                     }
                     $last_link = $link;
                     if (!array_key_exists('children', $phonebook[$link])) {
                         $phonebook[$link]['children'] = array();
                     }
                     $parent =& $phonebook[$link]['children'];
                     //example: $diplayed == array(country=>true, region=>false,  district=>true, county=>true village => true)
                     //we have $form = district, $formid = district|30, $parent_link= region|40
                     end($displayed);
                     $disp_form = key($displayed);
                     while ($disp_form !== false && $disp_form !== $form) {
                         prev($displayed);
                         $disp_form = key($displayed);
                     }
                     //we end here either before the beginning of the array or where $disp_form == $form.
                     prev($displayed);
                     //we are now at the one before the $form.  if the current form was district, we are now at region
                     $parent_link = $link;
                 } else {
                     if (!array_key_exists($link, $phonebook) || !$phonebook[$link]) {
                         //don't know where to put this as a child of the previous one so skip it
                         continue;
                     }
                 }
                 $parent_links[$formid] = $link;
             }
             if (!array_key_exists($id, $display_datas)) {
                 continue;
             }
             $disp_array = array();
             foreach ($disp_fields as $field) {
                 if (array_key_exists($field, $display_datas[$id]) && ($fieldObj = $formObj->getField($field)) instanceof I2CE_FormField) {
                     $fieldObj->setFromDB($display_datas[$id][$field]);
                     $disp_array[] = $fieldObj->getDisplayValue(false, $style);
                 } else {
                     $disp_array[] = '';
                 }
             }
             $display = vsprintf($disp_str, $disp_array);
             $child_data = array('display' => $display, 'show' => $displayed[$form]);
             if ($selectable) {
                 $child_data['value'] = $formid;
             }
             $parent[] = $child_data;
             end($parent);
             $phonebook[$formid] =& $parent[key($parent)];
         }
     }
     self::removeNotShownNodes($data);
     return $data;
 }
 /**
  * Build the data tree for the given list of fields 
  * and limits.  This is called by I2CE_List::buildDataTree.
  * See that for more details
  * @see I2CE_List::buildDataTree
  * @param array $fields The fields to build the tree
  * @param array $forms The selectable forms
  * @param array $displayed The displayed forms for the tree
  * @param array $limits The list of limits for each form.
  * @param array $orders The order fields for each given form
  * @param int $show_hidden 0=non-hidden, 1=All, 2=hidden only.  Defaults to 0
  * @return array The ordered list of all entries in the tree.
  */
 public function buildDataTree($fields, $forms, $displayed, $limits, $orders, $show_hidden = 0, $style = 'default')
 {
     $prev_form = false;
     $form_aliases = array();
     $selects = array();
     $displays = array();
     $all_orders = array();
     $formObjs = array();
     $skip_links = array();
     $skip_link_fields = array();
     $this->preserve_ids = true;
     $last_form = false;
     $styles = array();
     end($fields);
     $formfield = current($fields);
     if (is_array($formfield)) {
         list($last_form, $link_field) = $formfield;
     }
     if ($last_form) {
         $ff = I2CE_FormFactory::instance();
         $avail_styles = array($last_form => $style);
         $curr_style = $style;
         foreach (array_reverse($fields) as $formfield) {
             list($form, $link_field) = $formfield;
             if (!$form || !($formObj = $ff->createContainer($form)) instanceof I2CE_Form) {
                 break;
             }
             if (array_key_exists($form, $avail_styles) && is_string($avail_styles[$form])) {
                 $curr_style = $avail_styles[$form];
             } else {
                 $curr_style = 'default';
             }
             $styles["{$form}+{$link_field}"] = $curr_style;
             if (!$link_field || !($fieldObj = $formObj->getField($link_field)) instanceof I2CE_FormField) {
                 break;
             }
             $avail_styles = I2CE_List::getDisplayFieldStyles($form, $style);
         }
     }
     foreach ($fields as $formfield) {
         list($form, $link_field) = $formfield;
         $cachedForm = new I2CE_CachedForm($form);
         $cachedForm->generateCachedTable();
         unset($cachedForm);
         $alias_form = $form . ($link_field ? "+{$link_field}" : "");
         if (array_key_exists($alias_form, $limits)) {
             $limit = $limits[$alias_form];
         } elseif (array_key_exists($form, $limits)) {
             $limit = $limits[$form];
         } else {
             $limit = array();
         }
         self::addFormIdToLimit($form, $limit);
         $limit = I2CE_List::showHiddenLimit($limit, $show_hidden);
         $style = 'default';
         if (array_key_exists($form . '+' . $link_field, $styles)) {
             $style = $styles[$form . '+' . $link_field];
         }
         $disp_fields = I2CE_List::getDisplayFields($form, $style);
         $field_list = $disp_fields;
         $field_list[] = 'id';
         if ($link_field && !in_array($link_field, $field_list)) {
             $field_list[] = $link_field;
         }
         if (array_key_exists($form, $orders)) {
             $order = $orders[$form];
         } else {
             $order = I2CE_List::getSortFields($form, $style);
         }
         $sort_list = array();
         if (array_key_exists($form, $displayed) && $displayed[$form]) {
             $displays[$alias_form]['form'] = $form;
             $displays[$alias_form]['link_field'] = $link_field;
             foreach ($disp_fields as $disp) {
                 $displays[$alias_form]['fields'][$disp] = "{$alias_form}+{$disp}";
             }
             foreach ($order as $i => $ord) {
                 if (!is_string($ord)) {
                     unset($order[$i]);
                     continue;
                 }
                 if ($ord[0] == '-') {
                     $field = substr($ord, 1);
                     $all_orders[] = "`{$alias_form}`.`{$field}` DESC";
                 } else {
                     $field = $ord;
                     $all_orders[] = "`{$alias_form}`.`{$field}` ASC";
                 }
                 if (!in_array($field, $field_list)) {
                     $sort_list[] = $field;
                 }
             }
         } else {
             $skip_link_fields[$alias_form] = $link_field;
         }
         if (!array_key_exists($form, $formObjs)) {
             $formObjs[$form] = $this->getContainer($form);
             if (!$formObjs[$form] instanceof I2CE_Form) {
                 I2CE::raiseError("Could not instantiate {$form}");
                 return array();
             }
         }
         $where = false;
         if (is_array($limit) && count($limit) > 0) {
             $where = $formObjs[$form]->generateWhereClause($limit, array("I2CE_FormStorage_cached", "getSQLField"));
         }
         $query = $this->getRequiredFieldsQuery($form, array_merge($field_list, $sort_list), null, false, array("I2CE_FormStorage_cached", "getSQLField"));
         if (is_array($prev_form) && array_key_exists('form', $prev_form)) {
             if ($prev_form['form'] == $form) {
                 $froms[$alias_form] = " LEFT JOIN ";
             } else {
                 $froms[$alias_form] = " LEFT JOIN ";
             }
         } else {
             $froms[$alias_form] = "";
         }
         $froms[$alias_form] .= "({$query}" . ($where ? " WHERE " . $where : "") . ") AS `{$alias_form}`";
         if ($link_field) {
             $join_ons = array();
             $ff = $formObjs[$form]->getField($link_field);
             if ($ff instanceof I2CE_FormField_MAPPED) {
                 foreach ($ff->getSelectableForms() as $link_form) {
                     if (array_key_exists($link_form, $form_aliases)) {
                         foreach ($form_aliases[$link_form] as $link_alias) {
                             $join_ons[] = "`{$alias_form}`.`{$link_field}` = `{$link_alias}`.`id`";
                             if (!array_key_exists($link_alias, $displays) && array_key_exists($link_alias, $skip_link_fields)) {
                                 $skip_links[$alias_form . '+' . $link_field] = $link_alias . '+' . $skip_link_fields[$link_alias];
                             }
                         }
                     }
                 }
             } else {
                 I2CE::raiseMessage("Not sure what to link for {$form} {$link_field} so guessing.");
                 $join_ons[] = "`{$alias_form}`.`{$link_field}` = `" . $prev_form['alias'] . "`.`id`";
             }
             if (count($join_ons) > 0) {
                 $froms[$alias_form] .= " ON (" . implode(' OR ', $join_ons) . ") ";
             } else {
                 I2CE::raiseError("Don't know how to join on {$form} {$link_field}");
                 return array();
             }
         }
         foreach ($field_list as $field) {
             $selects[] = "`{$alias_form}`.`{$field}` AS `{$alias_form}+{$field}`";
         }
         $prev_form = array('form' => $form, 'alias' => $alias_form);
         $form_aliases[$form][] = $alias_form;
         $last_form = $form;
     }
     $or_wheres = array();
     foreach ($forms as $selectable) {
         if (array_key_exists($selectable, $form_aliases)) {
             foreach ($form_aliases[$selectable] as $required_form) {
                 $or_wheres[] = "`{$required_form}`.`id` IS NOT NULL";
             }
         }
     }
     $join_query = "SELECT " . implode(',', $selects) . " FROM " . implode('', $froms) . (count($or_wheres) > 0 ? " WHERE " . implode(' OR ', $or_wheres) : "") . (count($all_orders) > 0 ? " ORDER BY " . implode(',', $all_orders) : "");
     //I2CE::raiseMessage( $join_query );
     $res = $this->db->query($join_query);
     if (I2CE::pearError($res, "Bad query -- {$join_query}")) {
         return array();
     }
     $prev_ids = array();
     $results = array();
     $phonebook = array();
     $display_string = array();
     foreach ($displays as $fix_link_alias => &$fix_link_disp_data) {
         if (array_key_exists('link_field', $fix_link_disp_data) && $fix_link_disp_data['link_field'] != '') {
             $full_link_field = strtolower($fix_link_alias . "+" . $fix_link_disp_data['link_field']);
             while (array_key_exists($full_link_field, $skip_links)) {
                 $full_link_field = $skip_links[$full_link_field];
             }
             $fix_link_disp_data['link_field'] = $full_link_field;
         }
     }
     $display_copy = $displays;
     while ($data = $res->fetchRow()) {
         unset($prev_disp);
         foreach ($displays as $alias => $disp_data) {
             $id_field = strtolower($alias . "+id");
             if ($data->{$id_field} == null || array_key_exists($data->{$id_field}, $phonebook)) {
                 continue;
             }
             $curr = array();
             $add_this = false;
             if (in_array($disp_data['form'], $forms)) {
                 $curr['value'] = $data->{$id_field};
                 $add_this = true;
             }
             if (!$add_this) {
                 $check_ok = false;
                 foreach ($display_copy as $alias_copy => $disp_data_copy) {
                     if ($alias_copy == $alias) {
                         $check_ok = true;
                         continue;
                     }
                     if (!$check_ok) {
                         continue;
                     }
                     if (array_key_exists('link_field', $disp_data_copy) && $disp_data_copy['link_field'] != '') {
                         $link_field_copy = $disp_data_copy['link_field'];
                         if ($data->{$id_field} == $data->{$link_field_copy}) {
                             $add_this = true;
                             break;
                         }
                     }
                 }
             }
             if (!$add_this) {
                 continue;
             }
             $style = 'default';
             if (array_key_exists($disp_data['form'] . '+' . $disp_data['link_field'], $styles)) {
                 $style = $styles[$disp_data['form'] . '+' . $disp_data['link_field']];
             }
             if (!array_key_exists($disp_data['form'], $display_string)) {
                 $display_string[$disp_data['form']] = I2CE_List::getDisplayString($disp_data['form'], $style);
             }
             $disp_array = array();
             $disp_str = $display_string[$disp_data['form']];
             $disp_str_arr = explode("%s", $disp_str);
             $fo = $formObjs[$disp_data['form']];
             $disp_count = 0;
             foreach ($disp_data['fields'] as $field => $dbfield) {
                 $disp_count++;
                 if ($field == $disp_data['link_field']) {
                     // Don't include the data from the link field since it will already
                     // be in the tree above it.
                     if ($disp_count == 1) {
                         unset($disp_str_arr[$disp_count]);
                     } else {
                         unset($disp_str_arr[$disp_count - 1]);
                     }
                     continue;
                 }
                 $dbfield = strtolower($dbfield);
                 $fieldObj = $fo->getField($field);
                 if (!$fieldObj instanceof I2CE_FormField) {
                     I2CE::raiseError("Could not get field {$field}");
                     continue;
                 }
                 if (isset($data->{$dbfield})) {
                     $fieldObj->setFromDB($data->{$dbfield});
                     $disp_array[$field] = $fieldObj->getDisplayValue(false, $style);
                 } else {
                     $disp_array[$field] = null;
                 }
             }
             $disp_str = implode('%s', $disp_str_arr);
             $display = vsprintf($disp_str, $disp_array);
             //$display = $data->$disp_data['fields']['name'];
             $curr['display'] = $display;
             $phonebook[$data->{$id_field}] =& $curr;
             if ($disp_data['link_field'] != '') {
                 $link_field = $disp_data['link_field'];
                 if (array_key_exists($data->{$link_field}, $phonebook)) {
                     $add_to =& $phonebook[$data->{$link_field}];
                     if (!array_key_exists('children', $phonebook[$data->{$link_field}])) {
                         $phonebook[$data->{$link_field}]['children'] = array();
                     }
                     $phonebook[$data->{$link_field}]['children'][] =& $curr;
                 } else {
                     //I2CE::raiseMessage("Couldn't find $link_field " . $data->$link_field . " in phonebook");
                 }
             } else {
                 $results[] =& $curr;
             }
             unset($curr);
         }
     }
     $this->preserve_ids = false;
     return $results;
 }