/** * Create a data tree from a report of the selectable forms. Deisgned to be fed into tree select * @param array $fields * @param array $forms An unorderd array of form names whose values we allow to be selected * @param array $displayed The displayed forms for the tree * @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 string $report A report name to use for the query instead of building it from form cache or directly. * @return array */ public static function buildReportTree($fields, $forms, $displayed, $limits, $orders = array(), $show_hidden = 0, $report = null) { if (!is_array($report) || !array_key_exists('report', $report)) { return array(); } $report_table = I2CE_CustomReport::getCachedTableName($report['report']); if (!$report_table) { return array(); } $map = array(); if (array_key_exists('map', $report)) { $map = $report['map']; } $where = array(); $displays = array(); $report_alias = array(); $formObjs = array(); $use_link = ''; foreach ($fields as $formfield) { list($form, $link_field) = $formfield; $ff = $form . ($link_field ? "+{$link_field}" : ""); if (array_key_exists($ff, $map)) { $report_alias[$ff] = $map[$ff]; } elseif (array_key_exists($form, $map)) { $report_alias[$form] = $map[$form]; $report_alias[$ff] = $map[$form]; } else { $report_alias[$form] = $form; $report_alias[$ff] = $form; } //if ( array_key_exists( $ff, $limits ) ) { //$limit = $limits[$ff]; //} else if (array_key_exists($report_alias[$ff], $limits)) { $limit = $limits[$report_alias[$ff]]; } elseif (array_key_exists($form, $limits)) { $limit = $limits[$form]; } else { $limit = array(); } self::addFormIdToLimit($form, $limit); $limit = self::showHiddenLimit($limit, $show_hidden); /* if ( !$show_hidden ) { $hidden = $report_alias[$ff] . '+i2ce_hidden'; $where[] = "( `$hidden` = 0 OR ISNULL( `$hidden` ) )"; } */ $disp_fields = I2CE_List::getDisplayFields($form); if (array_key_exists($form, $orders)) { $order = $orders[$form]; } else { $order = I2CE_List::getSortFields($form); } $sort_list = array(); //if ( array_key_exists( $form, $displayed ) && $displayed[$form] ) { if (array_key_exists($form, $displayed)) { $alias_form = $report_alias[$ff]; if ($displayed[$form]) { $displays[$alias_form]['form'] = $form; if ($use_link == '') { $displays[$alias_form]['link_field'] = $link_field == '' ? $link_field : "{$alias_form}+{$link_field}"; } else { $displays[$alias_form]['link_field'] = $use_link; $use_link = ''; } 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"; } } } elseif ($use_link == '') { $use_link = $link_field == '' ? $link_field : "{$alias_form}+{$link_field}"; } } if (!array_key_exists($form, $formObjs)) { $formObjs[$form] = I2CE_FormFactory::instance()->createContainer($form); if (!$formObjs[$form] instanceof I2CE_Form) { I2CE::raiseError("Could not instantiate {$form}"); return array(); } } self::$curr_alias = $report_alias[$ff]; $where[] = $formObjs[$form]->generateWhereClause($limit, array("I2CE_DataTree", "getSQLField")); } $where_clause = ""; $order_by = ""; if (count($where) > 0) { $where_clause = " WHERE " . implode(' AND ', $where); } if (count($all_orders) > 0) { $order_by = " ORDER BY " . implode(',', $all_orders); } $qry = "SELECT * FROM {$report_table} {$where_clause} {$order_by}"; $db = MDB2::singleton(); I2CE::raiseMessage($qry); $res = $db->query($qry); if (I2CE::pearError($res, "Invalid report data tree query: ")) { return array(); } $phonebook = array(); $results = array(); $display_string = array(); $display_copy = $displays; while ($data = $res->fetchRow()) { 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; } if (!array_key_exists($disp_data['form'], $display_string)) { $display_string[$disp_data['form']] = I2CE_List::getDisplayString($disp_data['form']); } $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 ($dbfield == $disp_data['link_field']) { // Don't include the data from the link field since it will already be there. 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(); } else { $disp_array[$field] = null; } } $disp_str = implode('%s', $disp_str_arr); $display = vsprintf($disp_str, $disp_array); $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); } } return $results; }
/** * Perform any actions * * @return boolean true on sucess */ protected function action() { /* * XX lists/form/position/facility+location/county/district?district%2Bregion=region|1 * XX lists/field/person_position+facility/default/?? * lists/LIST/[FORM[+FIELD]/[STYLE]]?[limit={JSON}&FORM[+FIELD]=VALUE * lists/district/position+facility?country=country|TF * lists/facility?facility+location=country|TF */ $list = array_shift($this->request_remainder); $is_public = false; I2CE::getConfig()->setIfIsSet($is_public, "/modules/forms/forms/{$list}/meta/list/is_public"); if (!$is_public) { $task = "can_view_database_list_{$list}"; if (!$this->hasPermission("task({$task})")) { $this->setError('noaccess_page'); return false; } } $listObj = I2CE_FormFactory::instance()->createContainer($list); if (!$listObj instanceof I2CE_List) { $this->setError('invalid_list', array($list)); } $style = 'default'; $fields = array(); $forms = array($list); $where = array(); $get = $this->request(); if (array_key_exists('limit', $get)) { $where = json_decode($get['limit']); unset($get['limit']); } $enclose_array = false; if (array_key_exists('array', $get)) { if ($get['array']) { $enclose_array = true; } unset($get['array']); } if (count($this->request_remainder) > 0) { $formfield = array_shift($this->request_remainder); if (strpos($formfield, '+') === false) { $form = $formfield; $field = $list; } else { list($form, $field) = explode('+', $formfield, 2); } $formObj = I2CE_FormFactory::instance()->createContainer($form); if (!$formObj instanceof I2CE_Form) { $this->setError('invalid_form', array($form)); } if (!$formObj->hasField($field)) { $this->setError('invalid_field', array($field, $form)); return true; } $fieldObj = $formObj->getField($field); if (!$fieldObj instanceof I2CE_FormField_MAPPED) { $this->setError('invalid_field', array($field, $form)); } if (count($this->request_remainder) > 0) { $style = array_shift($this->request_remainder); } $form_limits = $fieldObj->getFormLimits($style); $form_fields = $fieldObj->getDisplayedFields($style); $form_limits = $this->getCurrentListLimits($form_limits, $list, $form_fields); array_walk($form_fields, 'self::removeHidden'); $add_where = array(); foreach ($get as $formfield => $limit) { if (($form_key = array_search($formfield, $form_fields)) !== false) { if (!is_array($limit)) { $limit = array('equals' => $limit); } unset($get[$formfield]); if ($form_key == 0) { if (strpos($formfield, '+') !== false) { list($form, $field) = self::explodeLimitField($formfield); foreach ($limit as $limit_style => $value) { self::addOrCombineFieldLimit($add_where, $form, $field, $value, $limit_style); } } } else { $prev_key = $form_key - 1; $prev_form = $form_fields[$prev_key]; $curr_form = $form_fields[$form_key]; $new_limit = array(); if (strpos($prev_form, '+') === false) { if (($curr_pos = strpos($curr_form, '+')) !== false) { $curr_form = substr($curr_form, 0, $curr_pos); } foreach ($limit as $limit_style => $value) { self::addOrCombineFieldLimit($add_where, $prev_form, $curr_form, $value, $limit_style); } } else { list($form, $field) = self::explodeLimitField($prev_form); foreach ($limit as $limit_style => $value) { self::addOrCombineFieldLimit($add_where, $form, $field, $value, $limit_style); } } } } } $form_limits = self::combineFormLimits($form_limits, $add_where); if (!array_key_exists($list, $form_limits)) { $skip = true; foreach ($form_fields as $ff) { if (($pluspos = strpos($ff, '+')) !== false) { $ff_form = substr($ff, 0, $pluspos); } else { $ff_form = $ff; } $ff = str_replace('[', '', str_replace(']', '', $ff)); if ($ff_form == $list) { $skip = false; } if ($skip) { continue; } $fields[] = $ff; if (array_key_exists($ff_form, $form_limits)) { break; } } } else { $fields[] = $list; } $where = self::combineFormLimits($where, $form_limits); } else { $fields[] = $list; } if (count($get) > 0) { $add_where = array(); foreach ($get as $formfield => $limit) { if (!is_array($limit)) { $limit = array('equals' => $limit); } if (strpos($formfield, '+') !== false) { list($form, $field) = self::explodeLimitField($formfield); foreach ($limit as $limit_limit_style => $value) { self::addOrCombineFieldLimit($add_where, $form, $field, $value, $limit_style); } } } $where = self::combineFormLimits($where, $add_where); } foreach ($where as $w_form => $w_limits) { if (!in_array($w_form, $fields)) { unset($where[$w_form]); } } $this->data = array('list' => $list); //$this->data['data'] = I2CE_List::listOptions( $list ); //$results = I2CE_DataTree::flattenDataTree( I2CE_DataTree::buildDataTree( array( 'position', 'facility+location', 'county', 'district' ), array( 'position' ), $where ), true ); //I2CE::raiseMessage("building tree for " . print_r($fields,true).print_r($forms,true).print_r($where,true)); $results = I2CE_DataTree::flattenDataTree(I2CE_DataTree::buildDataTree($fields, $forms, $where, array(), 0, null, $style), true); $this->data['length'] = count($results); $this->data['data'] = $results; if ($enclose_array) { $this->data = array($this->data); } return true; }
/** * Internal method to search all the ids for forms that are below * the given matched form id. * @param string $match The form id to match at the top. * @param array $fields The getDisplayedFields() for the field object. * @param array $forms The getSelectableFroms() for the field object. * @param array $displayed A list of forms that should be included in the results. * @param int $show_hidden 0=non-hidden, 1=All, 2=hidden only. * @return array */ protected static function _searchLowerMatches($match_form, $match_ids, $fields, $forms, $displayed, $show_hidden) { $formfield = array_shift($fields); if (!is_array($formfield)) { return array(); } list($form, $link_field) = $formfield; $limit = array('operator' => 'FIELD_LIMIT', 'field' => $link_field, 'style' => 'in', 'data' => array('value' => $match_ids)); $limit = I2CE_DataTree::showHiddenLimit($limit, $show_hidden); $order = I2CE_List::getSortFields($form); $field_datas = I2CE_FormStorage::listFields($form, 'id', false, $limit, $order); $matched = array(); foreach (array_keys($field_datas) as $matched_id) { $matched[] = $form . "|" . $matched_id; } if ($displayed[$form]) { return array_merge($matched, self::_searchLowerMatches($form, $matched, $fields, $forms, $displayed, $show_hidden)); } else { return self::_searchLowerMatches($form, $matched, $fields, $forms, $displayed, $show_hidden); } }
/** *@returns array where keys are ids, values are arrays with the following keys 'value', 'display' */ public function getMapOptions($type = 'default', $show_hidden = 0, $flat = true, $add_limits = array()) { $forms = $this->getSelectableForms(); $fields = $this->getDisplayedFields($type); $limits = $this->getFormLimits($type); $report = $this->getDisplayReport($type); if (is_array($add_limits) && count($add_limits) > 0) { if (!is_array($limits) || count($limits) > 0) { $limits = $add_limits; } else { //need to go through each form and possibly merge limits foreach ($add_limits as $form => $formLimits) { if (!array_key_exists($form, $limits) || !is_array($limits[$form]) || count($limits[$form]) == 0) { $limits[$form] = $formLimits; } else { $limits[$form] = array('operator' => 'AND', 'operand' => array(0 => $limits[$form], 1 => $formLimits)); } } } } $orders = $this->getFormOrders($type); //echo "For " . ($this->getContainer() instanceof I2CE_Form ? $this->getContainer()->getName() . " + " : "" ) . $this->getName() . " using " . $report . "\n"; //I2CE::raiseError( "For " . ($this->getContainer() instanceof I2CE_Form ? $this->getContainer()->getName() . " + " : "" ) . $this->getName() . " using " . print_r($limits,true) ); $data = I2CE_DataTree::buildDataTree($fields, $forms, $limits, $orders, $show_hidden, $report); if (!$data) { //I2CE::raiseError("Could not build data tree for " .implode(',',$fields) . " and " . implode(",",$forms)); return array(); } if ($flat) { $data = I2CE_DataTree::flattenDataTree($data); } return $data; }