/** * Log a change * * @access private * @param string $ps_change_type 'I', 'U' or 'D', meaning INSERT, UPDATE or DELETE * @param int $pn_user_id user identifier, defaults to null */ protected function logChange($ps_change_type, $pn_user_id = null) { if (defined('__CA_DONT_LOG_CHANGES__')) { return null; } if (!$this->logChanges()) { return null; } $vb_is_metadata = $vb_is_metadata_value = false; if ($this->tableName() == 'ca_attributes') { $vb_log_changes_to_self = false; $va_subject_config = null; $vb_is_metadata = true; } elseif ($this->tableName() == 'ca_attribute_values') { $vb_log_changes_to_self = false; $va_subject_config = null; $vb_is_metadata_value = true; } else { $vb_log_changes_to_self = $this->getProperty('LOG_CHANGES_TO_SELF'); $va_subject_config = $this->getProperty('LOG_CHANGES_USING_AS_SUBJECT'); } global $AUTH_CURRENT_USER_ID; if (!$pn_user_id) { $pn_user_id = $AUTH_CURRENT_USER_ID; } if (!$pn_user_id) { $pn_user_id = null; } if (!in_array($ps_change_type, array('I', 'U', 'D'))) { return false; } // invalid change type (shouldn't happen) if (!($vn_row_id = $this->getPrimaryKey())) { return false; } // no logging without primary key value // get unit id (if set) global $g_change_log_unit_id; $vn_unit_id = $g_change_log_unit_id; if (!$vn_unit_id) { $vn_unit_id = null; } // get subject ids $va_subjects = array(); if ($vb_is_metadata) { // special case for logging attribute changes if (($vn_id = $this->get('row_id')) > 0) { $va_subjects[$this->get('table_num')][] = $vn_id; } } elseif ($vb_is_metadata_value) { // special case for logging metadata changes $t_attr = new ca_attributes($this->get('attribute_id')); if (($vn_id = $t_attr->get('row_id')) > 0) { $va_subjects[$t_attr->get('table_num')][] = $vn_id; } } else { if (is_array($va_subject_config)) { if (is_array($va_subject_config['FOREIGN_KEYS'])) { foreach ($va_subject_config['FOREIGN_KEYS'] as $vs_field) { $va_relationships = $this->_DATAMODEL->getManyToOneRelations($this->tableName(), $vs_field); if ($va_relationships['one_table']) { $vn_table_num = $this->_DATAMODEL->getTableNum($va_relationships['one_table']); if (!isset($va_subjects[$vn_table_num]) || !is_array($va_subjects[$vn_table_num])) { $va_subjects[$vn_table_num] = array(); } if (($vn_id = $this->get($vs_field)) > 0) { $va_subjects[$vn_table_num][] = $vn_id; } } } } if (is_array($va_subject_config['RELATED_TABLES'])) { $o_db = $this->getDb(); if (!isset($o_db) || !$o_db) { $o_db = new Db(); $o_db->dieOnError(false); } foreach ($va_subject_config['RELATED_TABLES'] as $vs_dest_table => $va_path_to_dest) { $t_dest = $this->_DATAMODEL->getTableInstance($vs_dest_table); if (!$t_dest) { continue; } $vn_dest_table_num = $t_dest->tableNum(); $vs_dest_primary_key = $t_dest->primaryKey(); $va_path_to_dest[] = $vs_dest_table; $vs_cur_table = $this->tableName(); $vs_sql = "SELECT " . $vs_dest_table . "." . $vs_dest_primary_key . " FROM " . $this->tableName() . "\n"; foreach ($va_path_to_dest as $vs_ltable) { $va_relations = $this->_DATAMODEL->getRelationships($vs_cur_table, $vs_ltable); $vs_sql .= "INNER JOIN {$vs_ltable} ON {$vs_cur_table}." . $va_relations[$vs_cur_table][$vs_ltable][0][0] . " = {$vs_ltable}." . $va_relations[$vs_cur_table][$vs_ltable][0][1] . "\n"; $vs_cur_table = $vs_ltable; } $vs_sql .= "WHERE " . $this->tableName() . "." . $this->primaryKey() . " = " . $this->getPrimaryKey(); if ($qr_subjects = $o_db->query($vs_sql)) { if (!isset($va_subjects[$vn_dest_table_num]) || !is_array($va_subjects[$vn_dest_table_num])) { $va_subjects[$vn_dest_table_num] = array(); } while ($qr_subjects->nextRow()) { if (($vn_id = $qr_subjects->get($vs_dest_primary_key)) > 0) { $va_subjects[$vn_dest_table_num][] = $vn_id; } } } else { print "<hr>Error in subject logging: "; print "<br>{$vs_sql}<hr>\n"; } } } else { if (($vn_id = $this->get('row_id')) > 0) { // At a minimum always log self as subject $va_subjects[$this->get('table_num')][] = $vn_id; } } } } if (!sizeof($va_subjects) && !$vb_log_changes_to_self) { return true; } if (!$this->opqs_change_log) { $o_db = $this->getDb(); $o_db->dieOnError(false); $vs_change_log_database = ''; if ($vs_change_log_database = $this->_CONFIG->get("change_log_database")) { $vs_change_log_database .= "."; } if (!($this->opqs_change_log = $o_db->prepare("\n\t\t\t\tINSERT INTO " . $vs_change_log_database . "ca_change_log\n\t\t\t\t(\n\t\t\t\t\tlog_datetime, user_id, unit_id, changetype,\n\t\t\t\t\tlogged_table_num, logged_row_id, batch_id\n\t\t\t\t)\n\t\t\t\tVALUES\n\t\t\t\t(?, ?, ?, ?, ?, ?, ?)\n\t\t\t"))) { // prepare failed - shouldn't happen return false; } if (!($this->opqs_change_log_snapshot = $o_db->prepare("\n\t\t\t\tINSERT IGNORE INTO " . $vs_change_log_database . "ca_change_log_snapshots\n\t\t\t\t(\n\t\t\t\t\tlog_id, snapshot\n\t\t\t\t)\n\t\t\t\tVALUES\n\t\t\t\t(?, ?)\n\t\t\t"))) { // prepare failed - shouldn't happen return false; } if (!($this->opqs_change_log_subjects = $o_db->prepare("\n\t\t\t\tINSERT IGNORE INTO " . $vs_change_log_database . "ca_change_log_subjects\n\t\t\t\t(\n\t\t\t\t\tlog_id, subject_table_num, subject_row_id\n\t\t\t\t)\n\t\t\t\tVALUES\n\t\t\t\t(?, ?, ?)\n\t\t\t"))) { // prepare failed - shouldn't happen return false; } } // get snapshot of changes made to record $va_snapshot = $this->getSnapshot($ps_change_type === 'U' ? true : false); $vs_snapshot = caSerializeForDatabase($va_snapshot, true); if (!($ps_change_type == 'U' && !sizeof($va_snapshot))) { // Create primary log entry global $g_change_log_batch_id; // Log batch_id as set in global by ca_batch_log model (app/models/ca_batch_log.php) $this->opqs_change_log->execute(time(), $pn_user_id, $vn_unit_id, $ps_change_type, $this->tableNum(), $vn_row_id, (int) $g_change_log_batch_id ? (int) $g_change_log_batch_id : null); $vn_log_id = $this->opqs_change_log->getLastInsertID(); $this->opqs_change_log_snapshot->execute($vn_log_id, $vs_snapshot); global $g_change_log_delegate; if ($g_change_log_delegate && method_exists($g_change_log_delegate, "onLogChange")) { call_user_func(array($g_change_log_delegate, 'onLogChange'), $this->tableNum(), $vn_row_id, $vn_log_id); } foreach ($va_subjects as $vn_subject_table_num => $va_subject_ids) { foreach ($va_subject_ids as $vn_subject_row_id) { $this->opqs_change_log_subjects->execute($vn_log_id, $vn_subject_table_num, $vn_subject_row_id); } } } return true; }
/** * */ public function delete($pb_delete_related = false, $pa_options = null, $pa_fields = null, $pa_table_list = null) { //$t_element = new ca_metadata_elements($this->get('element_id')); $t_element = ca_attributes::getElementInstance($this->get('element_id')); switch ($vn_data_type = $t_element->get('datatype')) { case 15: // FT_FILE $this->useBlobAsFileField(true); // force value_blob field to be treated as FT_FILE field by BaseModel break; case 16: // FT_MEDIA $this->useBlobAsMediaField(true); // force value_blob field to be treated as FT_MEDIA field by BaseModel break; default: // Reset value_blob field to default (FT_TEXT) – should already be that but we reset it just in case $this->useBlobAsMediaField(false); break; } return parent::delete($pb_delete_related, $pa_options, $pa_fields, $pa_table_list); }
/** * */ private function _getChangeLogFromRawData($pa_data, $pn_table_num, $pa_options = null) { //print "<pre>".print_r($pa_data, true)."</pre>\n"; $va_log_output = array(); $vs_blank_placeholder = '<' . _t('BLANK') . '>'; if (!$pa_options) { $pa_options = array(); } if (sizeof($pa_data)) { // // Init // $o_datamodel = Datamodel::load(); $va_change_types = array('I' => _t('Added'), 'U' => _t('Edited'), 'D' => _t('Deleted')); $vs_label_table_name = $vs_label_display_name = ''; $t_item = $o_datamodel->getInstanceByTableNum($pn_table_num, true); $vs_label_table_name = $vn_label_table_num = $vs_label_display_name = null; if (method_exists($t_item, 'getLabelTableName')) { $t_item_label = $t_item->getLabelTableInstance(); $vs_label_table_name = $t_item->getLabelTableName(); $vn_label_table_num = $t_item_label->tableNum(); $vs_label_display_name = $t_item_label->getProperty('NAME_SINGULAR'); } // // Group data by unit // $va_grouped_data = array(); foreach ($pa_data as $va_log_entry) { $va_grouped_data[$va_log_entry['unit_id']]['ca_table_num_' . $va_log_entry['logged_table_num']][] = $va_log_entry; } // // Process units // $va_attributes = array(); foreach ($va_grouped_data as $vn_unit_id => $va_log_entries_by_table) { foreach ($va_log_entries_by_table as $vs_table_key => $va_log_entries) { foreach ($va_log_entries as $va_log_entry) { $va_changes = array(); if (!is_array($va_log_entry['snapshot'])) { $va_log_entry['snapshot'] = array(); } // // Get date/time stamp for display // $vs_datetime = date("n/d/Y@g:i:sa T", $va_log_entry['log_datetime']); // // Get user name // $vs_user = $va_log_entry['fname'] . ' ' . $va_log_entry['lname']; $vs_email = $va_log_entry['email']; // The "logged" table/row is the row to which the change was actually applied // The "subject" table/row is the row to which the change is considered to have been made for workflow purposes. // // For example: if an entity is related to an object, strictly speaking the logging occurs on the ca_objects_x_entities // row (ca_objects_x_entities is the "logged" table), but the subject is ca_objects since it's only in the context of the // object (and probably the ca_entities row as well) that you can about the change. // $t_obj = $o_datamodel->getInstanceByTableNum($va_log_entry['logged_table_num'], true); // get instance for logged table if (!$t_obj) { continue; } $vs_subject_display_name = '???'; $vn_subject_row_id = null; $vn_subject_table_num = null; if (isset($pa_options['return_item_names']) && $pa_options['return_item_names']) { if (!($vn_subject_table_num = $va_log_entry['subject_table_num'])) { $vn_subject_table_num = $va_log_entry['logged_table_num']; $vn_subject_row_id = $va_log_entry['logged_row_id']; } else { $vn_subject_row_id = $va_log_entry['subject_row_id']; } if ($t_subject = $o_datamodel->getInstanceByTableNum($vn_subject_table_num, true)) { if ($t_subject->load($vn_subject_row_id)) { if (method_exists($t_subject, 'getLabelForDisplay')) { $vs_subject_display_name = $t_subject->getLabelForDisplay(false); } else { if ($vs_idno_field = $t_subject->getProperty('ID_NUMBERING_ID_FIELD')) { $vs_subject_display_name = $t_subject->getProperty('NAME_SINGULAR') . ' [' . $t_subject->get($vs_idno_field) . ']'; } else { $vs_subject_display_name = $t_subject->getProperty('NAME_SINGULAR') . ' [' . $vn_subject_row_id . ']'; } } } } } // // Get item changes // // --------------------------------------------------------------- // is this an intrinsic field? if ($pn_table_num == $va_log_entry['logged_table_num']) { foreach ($va_log_entry['snapshot'] as $vs_field => $vs_value) { $va_field_info = $t_obj->getFieldInfo($vs_field); if (isset($va_field_info['IDENTITY']) && $va_field_info['IDENTITY']) { continue; } if (isset($va_field_info['DISPLAY_TYPE']) && $va_field_info['DISPLAY_TYPE'] == DT_OMIT) { continue; } if (isset($va_field_info['DISPLAY_FIELD']) && is_array($va_field_info['DISPLAY_FIELD']) && ($va_disp_fields = $va_field_info['DISPLAY_FIELD'])) { // // Lookup value in related table // if (!$vs_value) { continue; } if (sizeof($va_disp_fields)) { $va_rel = $o_datamodel->getManyToOneRelations($t_obj->tableName(), $vs_field); $va_rel_values = array(); if ($t_rel_obj = $o_datamodel->getTableInstance($va_rel['one_table'], true)) { $t_rel_obj->load($vs_value); foreach ($va_disp_fields as $vs_display_field) { $va_tmp = explode('.', $vs_display_field); if (($vs_tmp = $t_rel_obj->get($va_tmp[1])) !== '') { $va_rel_values[] = $vs_tmp; } } } $vs_proc_val = join(', ', $va_rel_values); } } else { // Is field a foreign key? $va_keys = $o_datamodel->getManyToOneRelations($t_obj->tableName(), $vs_field); if (sizeof($va_keys)) { // yep, it's a foreign key $va_rel_values = array(); if ($t_rel_obj = $o_datamodel->getTableInstance($va_keys['one_table'], true)) { if ($t_rel_obj->load($vs_value)) { if (method_exists($t_rel_obj, 'getLabelForDisplay')) { $vs_proc_val = $t_rel_obj->getLabelForDisplay(false); } else { $va_disp_fields = $t_rel_obj->getProperty('LIST_FIELDS'); foreach ($va_disp_fields as $vs_display_field) { if (($vs_tmp = $t_rel_obj->get($vs_display_field)) !== '') { $va_rel_values[] = $vs_tmp; } } $vs_proc_val = join(' ', $va_rel_values); } if (!$vs_proc_val) { $vs_proc_val = '???'; } } else { $vs_proc_val = _t("Not set"); } } else { $vs_proc_val = _t('Non-existent'); } } else { // Adjust display of value for different field types switch ($va_field_info['FIELD_TYPE']) { case FT_BIT: $vs_proc_val = $vs_value ? 'Yes' : 'No'; break; default: $vs_proc_val = $vs_value; break; } // Adjust display of value for lists if ($va_field_info['LIST']) { $t_list = new ca_lists(); if ($t_list->load(array('list_code' => $va_field_info['LIST']))) { $vn_list_id = $t_list->getPrimaryKey(); $t_list_item = new ca_list_items(); if ($t_list_item->load(array('list_id' => $vn_list_id, 'item_value' => $vs_value))) { $vs_proc_val = $t_list_item->getLabelForDisplay(); } } } else { if ($va_field_info['BOUNDS_CHOICE_LIST']) { // TODO } } } } $va_changes[] = array('label' => $va_field_info['LABEL'], 'description' => strlen((string) $vs_proc_val) ? $vs_proc_val : $vs_blank_placeholder, 'value' => $vs_value); } } // --------------------------------------------------------------- // is this a label row? if ($va_log_entry['logged_table_num'] == $vn_label_table_num) { foreach ($va_log_entry['snapshot'] as $vs_field => $vs_value) { $va_changes[] = array('label' => $t_item_label->getFieldInfo($vs_field, 'LABEL'), 'description' => $vs_value); } } // --------------------------------------------------------------- // is this an attribute? if ($va_log_entry['logged_table_num'] == 3) { // attribute_values if ($t_element = ca_attributes::getElementInstance($va_log_entry['snapshot']['element_id'])) { if ($o_attr_val = Attribute::getValueInstance($t_element->get('datatype'))) { $o_attr_val->loadValueFromRow($va_log_entry['snapshot']); $vs_attr_val = $o_attr_val->getDisplayValue(); } else { $vs_attr_val = '?'; } // Convert list-based attributes to text if ($vn_list_id = $t_element->get('list_id')) { $t_list = new ca_lists(); $vs_attr_val = $t_list->getItemFromListForDisplayByItemID($vn_list_id, $vs_attr_val, true); } if (!$vs_attr_val) { $vs_attr_val = $vs_blank_placeholder; } $vs_label = $t_element->getLabelForDisplay(); $va_attributes[$va_log_entry['snapshot']['attribute_id']]['values'][] = array('label' => $vs_label, 'value' => $vs_attr_val); $va_changes[] = array('label' => $vs_label, 'description' => $vs_attr_val); } } // --------------------------------------------------------------- // is this a related (many-many) row? $va_keys = $o_datamodel->getOneToManyRelations($t_item->tableName(), $t_obj->tableName()); if (sizeof($va_keys) > 0) { if (method_exists($t_obj, 'getLeftTableNum')) { if ($t_obj->getLeftTableNum() == $t_item->tableNum()) { // other side of rel is on right $t_related_table = $o_datamodel->getInstanceByTableNum($t_obj->getRightTableNum(), true); $t_related_table->load($va_log_entry['snapshot'][$t_obj->getRightTableFieldName()]); } else { // other side of rel is on left $t_related_table = $o_datamodel->getInstanceByTableNum($t_obj->getLeftTableNum(), true); $t_related_table->load($va_log_entry['snapshot'][$t_obj->getLeftTableFieldName()]); } $t_rel = $o_datamodel->getInstanceByTableNum($t_obj->tableNum(), true); $va_changes[] = array('label' => caUcFirstUTF8Safe($t_related_table->getProperty('NAME_SINGULAR')), 'idno' => ($vs_idno_field = $t_related_table->getProperty('ID_NUMBERING_ID_FIELD')) ? $t_related_table->get($vs_idno_field) : null, 'description' => $t_related_table->getLabelForDisplay(), 'table_name' => $t_related_table->tableName(), 'table_num' => $t_related_table->tableNum(), 'row_id' => $t_related_table->getPrimaryKey(), 'rel_type_id' => $va_log_entry['snapshot']['type_id'], 'rel_typename' => $t_rel->getRelationshipTypename('ltor', $va_log_entry['snapshot']['type_id'])); } } // --------------------------------------------------------------- // record log line if (sizeof($va_changes)) { $va_log_output[$vn_unit_id][] = array('datetime' => $vs_datetime, 'user_fullname' => $vs_user, 'user_email' => $vs_email, 'user' => $vs_user . ' (' . $vs_email . ')', 'changetype_display' => $va_change_types[$va_log_entry['changetype']], 'changetype' => $va_log_entry['changetype'], 'changes' => $va_changes, 'subject' => $vs_subject_display_name, 'subject_id' => $vn_subject_row_id, 'subject_table_num' => $vn_subject_table_num, 'logged_table_num' => $va_log_entry['logged_table_num'], 'logged_table' => $t_obj->tableName(), 'logged_row_id' => $va_log_entry['logged_row_id']); } } } } } return $va_log_output; }
/** * Indexes single row in a table; this is the public call when one needs to index content. * indexRow() will analyze the dependencies of the row being indexed and automatically * apply the indexing of the row to all dependent rows in other tables. (Note that while I call this * a "public" call in fact you shouldn't need to call this directly. BaseModel.php does this for you * during insert() and update().) * * For example, if you are indexing a row in table 'entities', then indexRow() * will automatically apply the indexing not just to the entities record, but also * to all objects, place_names, occurrences, lots, etc. that reference the entity. * The dependencies are configured in the search_indices.conf configuration file. * * "subject" tablenum/row_id refer to the row **to which the indexing is being applied**. This may be the row being indexed * or it may be a dependent row. The "content" tablenum/fieldnum/row_id parameters define the specific row and field being indexed. * This is always the actual row being indexed. $pm_content is the content to be indexed and $pa_options is an optional associative * array of indexing options passed through from the search_indices.conf (no options are defined yet - but will be soon) */ public function indexRow($pn_subject_tablenum, $pn_subject_row_id, $pa_field_data, $pb_reindex_mode = false, $pa_exclusion_list = null, $pa_changed_fields = null, $pa_old_values = null, $pa_options = null) { $vb_initial_reindex_mode = $pb_reindex_mode; if (!$pb_reindex_mode && is_array($pa_changed_fields) && !sizeof($pa_changed_fields)) { return; } // don't bother indexing if there are no changed fields $vs_subject_tablename = $this->opo_datamodel->getTableName($pn_subject_tablenum); $t_subject = $this->opo_datamodel->getInstanceByTableName($vs_subject_tablename, true); $t_subject->setDb($this->getDb()); // force the subject instance to use the same db connection as the indexer, in case we're operating in a transaction // Prevent endless recursive reindexing if (is_array($pa_exclusion_list[$pn_subject_tablenum]) && isset($pa_exclusion_list[$pn_subject_tablenum][$pn_subject_row_id])) { return; } $pb_is_new_row = (int) caGetOption('isNewRow', $pa_options, false); $vb_reindex_children = false; $vs_subject_pk = $t_subject->primaryKey(); if (!is_array($pa_changed_fields)) { $pa_changed_fields = array(); } foreach ($pa_changed_fields as $vs_k => $vb_bool) { if (!isset($pa_field_data[$vs_k])) { $pa_field_data[$vs_k] = null; } } $vb_can_do_incremental_indexing = $this->opo_engine->can('incremental_reindexing') ? true : false; // can the engine do incremental indexing? Or do we need to reindex the entire row every time? if (!$pa_exclusion_list) { $pa_exclusion_list = array(); } $pa_exclusion_list[$pn_subject_tablenum][$pn_subject_row_id] = true; // // index fields in subject table itself // $va_fields_to_index = $this->getFieldsToIndex($pn_subject_tablenum); if (is_array($va_fields_to_index)) { foreach ($va_fields_to_index as $vs_k => $va_data) { if (preg_match('!^ca_attribute_(.*)$!', $vs_k, $va_matches)) { unset($va_fields_to_index[$vs_k]); if ($va_data['DONT_INDEX']) { // remove attribute from indexing list unset($va_fields_to_index['_ca_attribute_' . $va_matches[1]]); } else { if ($vn_element_id = $this->_getElementID($va_matches[1])) { $va_fields_to_index['_ca_attribute_' . $vn_element_id] = $va_data; } } } } // always index type id if applicable if (method_exists($t_subject, 'getTypeFieldName') && ($vs_type_field = $t_subject->getTypeFieldName()) && !isset($va_fields_to_index[$vs_type_field])) { $va_fields_to_index[$vs_type_field] = array('STORE', 'DONT_TOKENIZE'); } } // // If location in hierarchy has changed we need to reindex this record and all of its children // if ($t_subject->isHierarchical() && isset($pa_changed_fields['parent_id']) && $pa_changed_fields['parent_id'] && method_exists($t_subject, "makeSearchResult")) { $pb_reindex_mode = true; $vb_reindex_children = true; } $vb_started_indexing = false; if (is_array($va_fields_to_index)) { $this->opo_engine->startRowIndexing($pn_subject_tablenum, $pn_subject_row_id); $vb_started_indexing = true; foreach ($va_fields_to_index as $vs_field => $va_data) { if (substr($vs_field, 0, 14) === '_ca_attribute_') { // // Is attribute // if (!preg_match('!^_ca_attribute_(.*)$!', $vs_field, $va_matches)) { continue; } if ($vb_can_do_incremental_indexing && !$pb_is_new_row && !$pb_reindex_mode && (!isset($pa_changed_fields[$vs_field]) || !$pa_changed_fields[$vs_field])) { continue; // skip unchanged attribute value } if ($va_data['DONT_INDEX'] && is_array($va_data['DONT_INDEX'])) { $vb_cont = false; foreach ($va_data["DONT_INDEX"] as $vs_exclude_type) { if ($this->_getElementID($vs_exclude_type) == intval($va_matches[1])) { $vb_cont = true; break; } } if ($vb_cont) { continue; } // skip excluded attribute type } $va_data['datatype'] = (int) $this->_getElementDataType($va_matches[1]); $this->_indexAttribute($t_subject, $pn_subject_row_id, $va_matches[1], $va_data); } else { // // Plain old field // if ($vb_can_do_incremental_indexing && !$pb_is_new_row && !$pb_reindex_mode && !isset($pa_changed_fields[$vs_field]) && $vs_field != $vs_subject_pk) { // skip unchanged continue; } if (!($vn_fld_num = $t_subject->fieldNum($vs_field))) { continue; } // // Hierarchical indexing in primary table // if (isset($va_data['INDEX_ANCESTORS']) && $va_data['INDEX_ANCESTORS'] || in_array('INDEX_ANCESTORS', $va_data)) { if ($t_subject && $t_subject->isHierarchical()) { $vn_fld_num = $t_subject->fieldNum($vs_field); if ($va_hier_values = $this->_genHierarchicalPath($pn_subject_row_id, $vs_field, $t_subject, $va_data)) { $this->opo_engine->indexField($pn_subject_tablenum, 'I' . $vn_fld_num, $pn_subject_row_id, join(" ", $va_hier_values['values']), $va_data); if (caGetOption('INDEX_ANCESTORS_AS_PATH_WITH_DELIMITER', $va_data, false) !== false) { $this->opo_engine->indexField($pn_subject_tablenum, 'I' . $vn_fld_num, $pn_subject_row_id, $va_hier_values['path'], array_merge($va_data, array('DONT_TOKENIZE' => 1))); } } $va_children_ids = $t_subject->getHierarchyAsList($pn_subject_row_id, array('idsOnly' => true)); if (!$pb_reindex_mode && is_array($va_children_ids) && sizeof($va_children_ids) > 0) { // trigger reindexing of children $o_indexer = new SearchIndexer($this->opo_db); $qr_children_res = $t_subject->makeSearchResult($vs_subject_tablename, $va_children_ids, array('db' => $this->getDb())); while ($qr_children_res->nextHit()) { $o_indexer->indexRow($pn_subject_tablenum, $qr_children_res->get($vs_subject_pk), array('parent_id' => $qr_children_res->get('parent_id'), $vs_field => $qr_children_res->get($vs_field)), false, $pa_exclusion_list, array($vs_field => true), null); } } continue; } } // specialized identifier (idno) processing; used IDNumbering plugin to generate searchable permutations of identifier if ((isset($va_data['INDEX_AS_IDNO']) && $va_data['INDEX_AS_IDNO'] || in_array('INDEX_AS_IDNO', $va_data)) && method_exists($t_subject, "getIDNoPlugInInstance") && ($o_idno = $t_subject->getIDNoPlugInInstance())) { $va_values = $o_idno->getIndexValues($pa_field_data[$vs_field]); $vn_fld_num = $t_subject->fieldNum($vs_field); $this->opo_engine->indexField($pn_subject_tablenum, 'I' . $vn_fld_num, $pn_subject_row_id, join(" ", $va_values), $va_data); continue; } $va_field_list = $t_subject->getFieldsArray(); if (in_array($va_field_list[$vs_field]['FIELD_TYPE'], array(FT_DATERANGE, FT_HISTORIC_DATERANGE))) { // if the field is a daterange type get content from start and end fields $start_field = $va_field_list[$vs_field]['START']; $end_field = $va_field_list[$vs_field]['END']; if (!$pa_field_data[$start_field] || !$pa_field_data[$start_field]) { continue; } $pn_content = $pa_field_data[$start_field] . " - " . $pa_field_data[$end_field]; } else { $va_content = array(); if (isset($va_field_list[$vs_field]['LIST_CODE']) && $va_field_list[$vs_field]['LIST_CODE']) { // Is reference to list item so index preferred label values $t_item = new ca_list_items((int) $pa_field_data[$vs_field]); $va_labels = $t_item->getPreferredDisplayLabelsForIDs(array((int) $pa_field_data[$vs_field]), array('returnAllLocales' => true)); foreach ($va_labels as $vn_label_row_id => $va_labels_per_row) { foreach ($va_labels_per_row as $vn_locale_id => $va_label_list) { foreach ($va_label_list as $vs_label) { $va_content[$vs_label] = true; } } } $va_content[$t_item->get('idno')] = true; } else { // is this field related to something? if (is_array($va_rels = $this->opo_datamodel->getManyToOneRelations($vs_subject_tablename)) && $va_rels[$vs_field]) { if (isset($va_rels[$vs_field])) { if ($pa_changed_fields[$vs_field]) { $pb_reindex_mode = true; // trigger full reindex of record so it reflects text of related item (if so indexed) } } $this->opo_engine->indexField($pn_subject_tablenum, 'I' . $vn_fld_num, $pn_subject_row_id, $pn_content, $va_data); } } $va_content[$pa_field_data[$vs_field]] = true; $this->opo_engine->indexField($pn_subject_tablenum, 'I' . $vn_fld_num, $pn_subject_row_id, join(" ", array_keys($va_content)), $va_data); continue; } $this->opo_engine->indexField($pn_subject_tablenum, 'I' . $vn_fld_num, $pn_subject_row_id, $pn_content, $va_data); } } } // ------------------------------------- // // index related fields // // Here's where we generate indexing on the subject from content in related rows (data stored externally to the subject row) // If the underlying engine doesn't support incremental indexing (if it can't change existing indexing for a row in-place, in other words) // then we need to do this every time we update the indexing for a row; if the engine *does* support incremental indexing then // we can just update the existing indexing with content from the changed fields. // // We also do this indexing if we're in "reindexing" mode. When reindexing is indicated it means that we need to act as if // we're indexing this row for the first time, and all indexing should be performed. if (!$vb_can_do_incremental_indexing || $pb_reindex_mode) { if (is_array($va_related_tables = $this->getRelatedIndexingTables($pn_subject_tablenum))) { if (!$vb_started_indexing) { $this->opo_engine->startRowIndexing($pn_subject_tablenum, $pn_subject_row_id); $vb_started_indexing = true; } // Needs self-indexing? $va_self_info = $this->getTableIndexingInfo($vs_subject_tablename, $vs_subject_tablename); if (is_array($va_self_info['related']['fields']) && sizeof($va_self_info['related']['fields'])) { $va_related_tables[] = $vs_subject_tablename; } foreach ($va_related_tables as $vs_related_table) { $va_queries = array(); $vn_related_tablenum = $this->opo_datamodel->getTableNum($vs_related_table); $vs_related_pk = $this->opo_datamodel->getTablePrimaryKeyName($vn_related_tablenum); $t_rel = $this->opo_datamodel->getInstanceByTableNum($vn_related_tablenum, true); $t_rel->setDb($this->getDb()); $va_params = null; if ($vs_subject_tablename == $vs_related_table) { // self-relation if (!($vs_self_rel_table_name = $t_rel->getSelfRelationTableName())) { continue; } $t_self_rel = $this->opo_datamodel->getInstanceByTableName($vs_self_rel_table_name, true); $va_proc_field_list = array(); $va_fields_to_index = $va_self_info['related']['fields']; $va_field_list = array_keys($va_fields_to_index); $vn_field_list_count = sizeof($va_field_list); for ($vn_i = 0; $vn_i < $vn_field_list_count; $vn_i++) { if ($va_field_list[$vn_i] == '_count') { continue; } if (substr($va_field_list[$vn_i], 0, 14) === '_ca_attribute_') { continue; } if (!trim($va_field_list[$vn_i])) { continue; } $va_proc_field_list[$vn_i] = $vs_related_table . '.' . $va_field_list[$vn_i]; } $va_proc_field_list[] = $vs_related_table . '.' . $vs_related_pk; if ($vs_self_rel_table_name) { $va_proc_field_list[] = $vs_self_rel_table_name . '.type_id rel_type_id'; } $vs_sql = "\n\t\t\t\t\t\tSELECT " . join(",", $va_proc_field_list) . "\n\t\t\t\t\t\tFROM {$vs_related_table}\n\t\t\t\t\t\tINNER JOIN {$vs_self_rel_table_name} ON {$vs_self_rel_table_name}." . $t_self_rel->getLeftTableFieldName() . " = {$vs_related_table}.{$vs_related_pk}\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t(" . $vs_self_rel_table_name . '.' . $t_self_rel->getRightTableFieldName() . ' = ?) UNION SELECT ' . join(",", $va_proc_field_list) . "\n\t\t\t\t\t\tFROM {$vs_related_table}\n\t\t\t\t\t\tINNER JOIN {$vs_self_rel_table_name} ON {$vs_self_rel_table_name}." . $t_self_rel->getRightTableFieldName() . " = {$vs_related_table}.{$vs_related_pk}\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t(" . $vs_self_rel_table_name . '.' . $t_self_rel->getLeftTableFieldName() . ' = ?) '; $va_params = array($pn_subject_row_id, $pn_subject_row_id); $va_queries[] = array('sql' => $vs_sql, 'params' => $va_params); } else { // related table $va_fields_to_index = $this->getFieldsToIndex($vs_subject_tablename, $vs_related_table); $va_table_info = $this->getTableIndexingInfo($vs_subject_tablename, $vs_related_table); $va_field_list = array_keys($va_fields_to_index); $va_table_list_list = $va_table_key_list = array(); if (isset($va_table_info['key']) && $va_table_info['key']) { $va_table_list_list = array('key' => array($vs_related_table)); $va_table_key_list = array(); } else { if ($pb_reindex_mode || !$vb_can_do_incremental_indexing) { $va_table_list_list = isset($va_table_info['tables']) ? $va_table_info['tables'] : null; $va_table_key_list = isset($va_table_info['keys']) ? $va_table_info['keys'] : null; } } if (!is_array($va_table_list_list) || !sizeof($va_table_list_list)) { continue; } foreach ($va_table_list_list as $vs_list_name => $va_linking_tables) { array_push($va_linking_tables, $vs_related_table); $vs_left_table = $vs_subject_tablename; $va_joins = array(); $vs_rel_type_id_fld = null; foreach ($va_linking_tables as $vs_right_table) { if (is_array($va_table_key_list) && (isset($va_table_key_list[$vs_list_name][$vs_right_table][$vs_left_table]) || isset($va_table_key_list[$vs_list_name][$vs_left_table][$vs_right_table]))) { // are the keys for this join specified in the indexing config? if (isset($va_table_key_list[$vs_list_name][$vs_left_table][$vs_right_table])) { $va_key_spec = $va_table_key_list[$vs_list_name][$vs_left_table][$vs_right_table]; $vs_join = 'INNER JOIN ' . $vs_right_table . ' ON (' . $vs_right_table . '.' . $va_key_spec['right_key'] . ' = ' . $vs_left_table . '.' . $va_key_spec['left_key']; if ($va_key_spec['left_table_num'] || $va_key_spec['right_table_num']) { if ($va_key_spec['right_table_num']) { $vs_join .= ' AND ' . $vs_right_table . '.' . $va_key_spec['right_table_num'] . ' = ' . $this->opo_datamodel->getTableNum($vs_left_table); } else { $vs_join .= ' AND ' . $vs_left_table . '.' . $va_key_spec['left_table_num'] . ' = ' . $this->opo_datamodel->getTableNum($vs_right_table); } } $vs_join .= ")"; } else { $va_key_spec = $va_table_key_list[$vs_list_name][$vs_right_table][$vs_left_table]; $vs_join = 'INNER JOIN ' . $vs_right_table . ' ON (' . $vs_right_table . '.' . $va_key_spec['left_key'] . ' = ' . $vs_left_table . '.' . $va_key_spec['right_key']; if ($va_key_spec['left_table_num'] || $va_key_spec['right_table_num']) { if ($va_key_spec['right_table_num']) { $vs_join .= ' AND ' . $vs_left_table . '.' . $va_key_spec['right_table_num'] . ' = ' . $this->opo_datamodel->getTableNum($vs_right_table); } else { $vs_join .= ' AND ' . $vs_right_table . '.' . $va_key_spec['left_table_num'] . ' = ' . $this->opo_datamodel->getTableNum($vs_left_table); } } $vs_join .= ")"; } if (($t_rel_instance = $this->opo_datamodel->getInstanceByTableName($vs_right_table, true)) && method_exists($t_rel_instance, "isRelationship") && $t_rel_instance->isRelationship() && $t_rel_instance->hasField('type_id')) { $vs_rel_type_id_fld = "{$vs_right_table}.type_id"; } $va_joins[] = $vs_join; } else { if ($va_rel = $this->opo_datamodel->getOneToManyRelations($vs_left_table, $vs_right_table)) { $va_joins[] = 'INNER JOIN ' . $va_rel['many_table'] . ' ON ' . $va_rel['one_table'] . '.' . $va_rel['one_table_field'] . ' = ' . $va_rel['many_table'] . '.' . $va_rel['many_table_field']; if (($t_rel_instance = $this->opo_datamodel->getInstanceByTableName($va_rel['many_table'], true)) && method_exists($t_rel_instance, "isRelationship") && $t_rel_instance->isRelationship() && $t_rel_instance->hasField('type_id')) { $vs_rel_type_id_fld = "{$vs_right_table}.type_id"; } } else { if ($va_rel = $this->opo_datamodel->getOneToManyRelations($vs_right_table, $vs_left_table)) { $va_joins[] = 'INNER JOIN ' . $va_rel['one_table'] . ' ON ' . $va_rel['one_table'] . '.' . $va_rel['one_table_field'] . ' = ' . $va_rel['many_table'] . '.' . $va_rel['many_table_field']; if (($t_rel_instance = $this->opo_datamodel->getInstanceByTableName($va_rel['one_table'], true)) && method_exists($t_rel_instance, "isRelationship") && $t_rel_instance->isRelationship() && $t_rel_instance->hasField('type_id')) { $vs_rel_type_id_fld = "{$vs_right_table}.type_id"; } } } } $vs_left_table = $vs_right_table; } $va_proc_field_list = array(); $vn_field_list_count = sizeof($va_field_list); for ($vn_i = 0; $vn_i < $vn_field_list_count; $vn_i++) { if ($va_field_list[$vn_i] == '_count') { continue; } if (substr($va_field_list[$vn_i], 0, 14) === '_ca_attribute_') { continue; } if (!trim($va_field_list[$vn_i])) { continue; } $va_proc_field_list[$vn_i] = $vs_related_table . '.' . $va_field_list[$vn_i]; } $va_proc_field_list[] = $vs_related_table . '.' . $vs_related_pk; if ($vs_rel_type_id_fld) { $va_proc_field_list[] = $vs_rel_type_id_fld . ' rel_type_id'; } if (isset($va_rel['many_table']) && $va_rel['many_table']) { $va_proc_field_list[] = $va_rel['many_table'] . '.' . $va_rel['many_table_field']; } $vs_sql = "\n\t\t\t\t\t\t\tSELECT " . join(",", $va_proc_field_list) . "\n\t\t\t\t\t\t\tFROM " . $vs_subject_tablename . "\n\t\t\t\t\t\t\t" . join("\n", $va_joins) . "\n\t\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\t\t(" . $vs_subject_tablename . '.' . $vs_subject_pk . ' = ?) '; $va_params = array($pn_subject_row_id); $va_queries[] = array('sql' => $vs_sql, 'params' => $va_params); } } foreach ($va_queries as $va_query) { $vs_sql = $va_query['sql']; $va_params = $va_query['params']; $qr_res = $this->opo_db->query($vs_sql, $va_params); if ($this->opo_db->numErrors()) { // Shouldn't ever happen throw new Exception(_t("SQL error while getting content for index of related fields: %1; SQL was %2", $this->opo_db->getErrors(), $vs_sql)); } if (method_exists($t_rel, "getApplicableElementCodes")) { if (is_array($va_element_ids = array_keys($t_rel->getApplicableElementCodes(null, false, false))) && sizeof($va_element_ids)) { $va_rel_row_ids = $qr_res->getAllFieldValues($vs_related_pk); if (sizeof($va_rel_row_ids) > 0) { ca_attributes::prefetchAttributes($this->opo_db, $vn_related_tablenum, $va_rel_row_ids, $va_element_ids); } } } if (!$qr_res->seek(0)) { $qr_res = $this->opo_db->query($vs_sql, $va_params); } while ($qr_res->nextRow()) { $va_field_data = $qr_res->getRow(); $vn_row_id = $qr_res->get($vs_related_pk); $vn_rel_type_id = $qr_res->get('rel_type_id'); foreach ($va_fields_to_index as $vs_rel_field => $va_rel_field_info) { // // BEGIN: Index attributes in related tables // $vb_is_attr = false; if (substr($vs_rel_field, 0, 14) === '_ca_attribute_') { if (!preg_match('!^_ca_attribute_(.*)$!', $vs_rel_field, $va_matches)) { continue; } if ($va_rel_field_info['DONT_INDEX'] && is_array($va_rel_field_info['DONT_INDEX'])) { $vb_cont = false; foreach ($va_rel_field_info["DONT_INDEX"] as $vs_exclude_type) { if ($this->_getElementID($vs_exclude_type) == intval($va_matches[1])) { $vb_cont = true; break; } } if ($vb_cont) { continue; } // skip excluded attribute type } $vb_is_attr = true; $va_rel_field_info['datatype'] = (int) $this->_getElementDataType($va_matches[1]); $this->_indexAttribute($t_rel, $vn_row_id, $va_matches[1], array_merge($va_rel_field_info, array('relationship_type_id' => $vn_rel_type_id))); } $vs_fld_data = trim($va_field_data[$vs_rel_field]); // // Hierarchical indexing in related tables // if (isset($va_rel_field_info['INDEX_ANCESTORS']) && $va_rel_field_info['INDEX_ANCESTORS'] || in_array('INDEX_ANCESTORS', $va_rel_field_info)) { // is this current field a label? $t_hier_rel = $t_rel; $vn_fld_num = $t_rel->fieldNum($vs_rel_field); $vn_id = $vn_row_id; if ($t_hier_rel && ($t_hier_rel->isHierarchical() || is_subclass_of($t_hier_rel, "BaseLabel"))) { // get hierarchy if ($va_hier_values = $this->_genHierarchicalPath($vn_id, $vs_rel_field, $t_hier_rel, $va_rel_field_info)) { $this->opo_engine->indexField($vn_related_tablenum, 'I' . $vn_fld_num, $vn_id, $vs_fld_data . ' ' . join(" ", $va_hier_values['values']), array_merge($va_rel_field_info, array('relationship_type_id' => $vn_rel_type_id))); if (caGetOption('INDEX_ANCESTORS_AS_PATH_WITH_DELIMITER', $va_rel_field_info, false) !== false) { $this->opo_engine->indexField($vn_related_tablenum, 'I' . $vn_fld_num, $vn_id, $va_hier_values['path'], array_merge($va_rel_field_info, array('DONT_TOKENIZE' => 1, 'relationship_type_id' => $vn_rel_type_id))); } } continue; } } switch ($vs_rel_field) { case '_count': // noop break; default: if ($vb_is_attr) { $this->opo_engine->indexField($vn_related_tablenum, 'A' . $va_matches[1], $qr_res->get($vs_related_pk), $vs_fld_data, array_merge($va_rel_field_info, array('relationship_type_id' => $vn_rel_type_id))); } else { if ((isset($va_rel_field_info['INDEX_AS_IDNO']) && $va_rel_field_info['INDEX_AS_IDNO'] || in_array('INDEX_AS_IDNO', $va_rel_field_info)) && method_exists($t_rel, "getIDNoPlugInInstance") && ($o_idno = $t_rel->getIDNoPlugInInstance())) { // specialized identifier (idno) processing; used IDNumbering plugin to generate searchable permutations of identifier $va_values = $o_idno->getIndexValues($vs_fld_data); $this->opo_engine->indexField($vn_related_tablenum, 'I' . $this->opo_datamodel->getFieldNum($vs_related_table, $vs_rel_field), $qr_res->get($vs_related_pk), join(" ", $va_values), array_merge($va_rel_field_info, array('relationship_type_id' => $vn_rel_type_id))); } else { // regular intrinsic $this->opo_engine->indexField($vn_related_tablenum, 'I' . $this->opo_datamodel->getFieldNum($vs_related_table, $vs_rel_field), $qr_res->get($vs_related_pk), $vs_fld_data, array_merge($va_rel_field_info, array('relationship_type_id' => $vn_rel_type_id))); } } break; } // // END: Index attributes in related tables // } } // index label for self-relation? if ($vs_subject_tablename == $vs_related_table) { if ($t_label = $t_rel->getLabelTableInstance()) { $t_label->setDb($this->getDb()); $va_label_info = $this->getTableIndexingInfo($vs_subject_tablename, $t_label->tableName()); if (is_array($va_label_info['related']['fields']) && sizeof($va_label_info['related']['fields'])) { $vn_label_table_num = $t_label->tableNum(); if (is_array($va_labels = $t_rel->getPreferredLabels(null, false, array('row_id' => $vn_row_id)))) { foreach ($va_labels as $vn_label_id => $va_labels_by_locale) { foreach ($va_labels_by_locale as $vn_locale_id => $va_label_list) { foreach ($va_label_list as $va_label) { foreach ($va_label_info['related']['fields'] as $vs_label_field => $va_config) { $this->opo_engine->indexField($vn_label_table_num, 'I' . $this->opo_datamodel->getFieldNum($vn_label_table_num, $vs_label_field), $vn_row_id, $va_label[$vs_label_field], array_merge($va_config, array('relationship_type_id' => $vn_rel_type_id))); } } } } } } } } } } } } } // save indexing on subject if ($vb_started_indexing) { $this->opo_engine->commitRowIndexing(); } if (!$vb_initial_reindex_mode && sizeof($pa_changed_fields) > 0) { // // When not reindexing then we consider the effect of the change on this row upon related rows that use it // in their indexing. This means figuring out which related tables have indexing that depend upon the subject row. // // We deal with this by pulling up a dependency map generated from the search_indexing.conf file and then reindexing // those rows // $va_deps = $this->getDependencies($vs_subject_tablename); $va_changed_field_nums = array(); foreach (array_keys($pa_changed_fields) as $vs_f) { if ($t_subject->hasField($vs_f)) { $va_changed_field_nums[$vs_f] = 'I' . $t_subject->fieldNum($vs_f); } else { if (preg_match('!^_ca_attribute_([\\d]+)$!', $vs_f, $va_matches)) { $va_changed_field_nums[$vs_f] = 'A' . $this->_getElementListCode($va_matches[1]); } } } // // reindex rows in dependent tables that use the subject_row_id // $va_rows_to_reindex = $this->_getDependentRowsForSubject($pn_subject_tablenum, $pn_subject_row_id, $va_deps, $va_changed_field_nums); if ($vb_can_do_incremental_indexing) { $va_rows_to_reindex_by_row_id = array(); $va_row_ids_to_reindex_by_table = array(); foreach ($va_rows_to_reindex as $vs_key => $va_row_to_reindex) { foreach ($va_row_to_reindex['field_nums'] as $vs_fld_name => $vn_fld_num) { $vs_new_key = $va_row_to_reindex['table_num'] . '/' . $va_row_to_reindex['field_table_num'] . '/' . $vn_fld_num . '/' . $va_row_to_reindex['field_row_id']; if (!isset($va_rows_to_reindex_by_row_id[$vs_new_key])) { $va_rows_to_reindex_by_row_id[$vs_new_key] = array('table_num' => $va_row_to_reindex['table_num'], 'row_ids' => array(), 'field_table_num' => $va_row_to_reindex['field_table_num'], 'field_num' => $vn_fld_num, 'field_name' => $vs_fld_name, 'field_row_id' => $va_row_to_reindex['field_row_id'], 'field_values' => $va_row_to_reindex['field_values'], 'relationship_type_id' => $va_row_to_reindex['relationship_type_id'], 'indexing_info' => $va_row_to_reindex['indexing_info'][$vs_fld_name]); } $va_rows_to_reindex_by_row_id[$vs_new_key]['row_ids'][] = $va_row_to_reindex['row_id']; $va_row_ids_to_reindex_by_table[$va_row_to_reindex['field_table_num']][] = $va_row_to_reindex['field_row_id']; } } foreach ($va_row_ids_to_reindex_by_table as $vn_rel_tablenum => $va_rel_row_ids) { $va_rel_row_ids = array_unique($va_rel_row_ids); if ($t_rel = $this->opo_datamodel->getInstanceByTableNum($vn_rel_tablenum, true)) { $t_rel->setDb($this->getDb()); if (method_exists($t_rel, "getApplicableElementCodes")) { if (is_array($va_element_ids = array_keys($t_rel->getApplicableElementCodes(null, false, false))) && sizeof($va_element_ids)) { ca_attributes::prefetchAttributes($this->opo_db, $vn_rel_tablenum, $va_rel_row_ids, $va_element_ids); } } } } $o_indexer = new SearchIndexer($this->opo_db); foreach ($va_rows_to_reindex_by_row_id as $va_row_to_reindex) { $vn_rel_type_id = $va_row_to_reindex['relationship_type_id']; $t_rel = $this->opo_datamodel->getInstanceByTableNum($va_row_to_reindex['field_table_num'], true); $t_rel->setDb($this->getDb()); if (substr($va_row_to_reindex['field_name'], 0, 14) == '_ca_attribute_') { // is attribute $va_row_to_reindex['indexing_info']['datatype'] = $this->_getElementDataType(substr($va_row_to_reindex['field_name'], 14)); } if (isset($va_row_to_reindex['indexing_info']['INDEX_ANCESTORS']) && $va_row_to_reindex['indexing_info']['INDEX_ANCESTORS'] || in_array('INDEX_ANCESTORS', $va_row_to_reindex['indexing_info'])) { if (!is_array($va_row_to_reindex['row_ids'])) { continue; } $t_label = $this->opo_datamodel->getInstanceByTableNum($va_row_to_reindex['field_table_num'], true); $t_label->setDb($this->getDb()); foreach ($va_row_to_reindex['row_ids'] as $vn_row_id) { $va_content = $this->_genHierarchicalPath($va_row_to_reindex['field_row_id'], $va_row_to_reindex['field_name'], $t_label, $va_row_to_reindex['indexing_info']); $vs_content = is_array($va_content['values']) ? join(" ", $va_content['values']) : ""; $this->opo_engine->updateIndexingInPlace($va_row_to_reindex['table_num'], array($vn_row_id), $va_row_to_reindex['field_table_num'], $va_row_to_reindex['field_num'], $va_row_to_reindex['field_row_id'], $vs_content, array_merge($va_row_to_reindex['indexing_info'], array('relationship_type_id' => $vn_rel_type_id, 'literalContent' => $va_content['path']))); } } else { $vs_element_code = substr($va_row_to_reindex['field_name'], 14); if (isset($va_row_to_reindex['indexing_info']['datatype'])) { $vs_v = ''; switch ($va_row_to_reindex['indexing_info']['datatype']) { case __CA_ATTRIBUTE_VALUE_CONTAINER__: // container // index components of complex multi-value attributes foreach ($va_row_to_reindex['row_ids'] as $vn_rel_row_id) { $this->opo_engine->startRowIndexing($va_row_to_reindex['table_num'], $vn_rel_row_id); $va_attributes = $t_rel->getAttributesByElement($vs_element_code, array('row_id' => $va_row_to_reindex['field_row_id'])); if (sizeof($va_attributes)) { foreach ($va_attributes as $vo_attribute) { foreach ($vo_attribute->getValues() as $vo_value) { $vn_list_id = $this->_getElementListID($vo_value->getElementID()); $vs_value_to_index = $vo_value->getDisplayValue($vn_list_id); $va_additional_indexing = $vo_value->getDataForSearchIndexing(); if (is_array($va_additional_indexing) && sizeof($va_additional_indexing) > 0) { foreach ($va_additional_indexing as $vs_additional_value) { $vs_value_to_index .= " ; " . $vs_additional_value; } } $this->opo_engine->indexField($va_row_to_reindex['table_num'], 'A' . $vo_value->getElementID(), $va_row_to_reindex['field_row_id'], $vs_value_to_index, array_merge($va_row_to_reindex['indexing_info'], array('relationship_type_id' => $vn_rel_type_id))); } } } else { // we are deleting a container so cleanup existing sub-values $va_sub_elements = $this->opo_metadata_element->getElementsInSet($vs_element_code); foreach ($va_sub_elements as $vn_i => $va_element_info) { $this->opo_engine->indexField($va_row_to_reindex['table_num'], 'A' . $va_element_info['element_id'], $va_row_to_reindex['field_row_id'], '', array_merge($va_row_to_reindex['indexing_info'], array('relationship_type_id' => $vn_rel_type_id))); } } $this->opo_engine->commitRowIndexing(); } break; case __CA_ATTRIBUTE_VALUE_LIST__: // list $va_tmp = array(); if (is_array($va_attributes = $t_rel->getAttributesByElement($vs_element_code, array('row_id' => $va_row_to_reindex['field_row_id'])))) { foreach ($va_attributes as $vo_attribute) { foreach ($vo_attribute->getValues() as $vo_value) { $va_tmp[$vo_attribute->getAttributeID()] = $vo_value->getDisplayValue(); } } } $va_new_values = array(); $t_item = new ca_list_items(); $va_labels = $t_item->getPreferredDisplayLabelsForIDs($va_tmp, array('returnAllLocales' => true)); foreach ($va_labels as $vn_label_row_id => $va_labels_per_row) { foreach ($va_labels_per_row as $vn_locale_id => $va_label_list) { foreach ($va_label_list as $vs_label) { $va_new_values[$vn_label_row_id][$vs_label] = true; } } } foreach ($va_tmp as $vn_attribute_id => $vn_item_id) { if (!$vn_item_id) { continue; } if (!isset($va_new_values[$vn_item_id]) || !is_array($va_new_values[$vn_item_id])) { continue; } $vs_v = join(' ; ', array_merge(array($vn_item_id), array_keys($va_new_values[$vn_item_id]))); } $this->opo_engine->updateIndexingInPlace($va_row_to_reindex['table_num'], $va_row_to_reindex['row_ids'], $va_row_to_reindex['field_table_num'], $va_row_to_reindex['field_num'], $va_row_to_reindex['field_row_id'], $vs_v, array_merge($va_row_to_reindex['indexing_info'], array('relationship_type_id' => $vn_rel_type_id))); break; default: $va_tmp = array(); if (is_array($va_attributes = $t_rel->getAttributesByElement($vs_element_code, array('row_id' => $va_row_to_reindex['field_row_id'])))) { foreach ($va_attributes as $vo_attribute) { foreach ($vo_attribute->getValues() as $vo_value) { $vs_value_to_index = $vo_value->getDisplayValue($vn_list_id); $va_additional_indexing = $vo_value->getDataForSearchIndexing(); if (is_array($va_additional_indexing) && sizeof($va_additional_indexing) > 0) { foreach ($va_additional_indexing as $vs_additional_value) { $vs_value_to_index .= " ; " . $vs_additional_value; } } $va_tmp[$vo_attribute->getAttributeID()] = $vs_value_to_index; } } } foreach ($va_tmp as $vn_attribute_id => $vn_item_id) { if (!$vn_item_id) { continue; } $vs_v = join(' ; ', $va_tmp); } $this->opo_engine->updateIndexingInPlace($va_row_to_reindex['table_num'], $va_row_to_reindex['row_ids'], $va_row_to_reindex['field_table_num'], $va_row_to_reindex['field_num'], $va_row_to_reindex['field_row_id'], $vs_v, array_merge($va_row_to_reindex['indexing_info'], array('relationship_type_id' => $vn_rel_type_id))); break; } } else { $this->opo_engine->updateIndexingInPlace($va_row_to_reindex['table_num'], $va_row_to_reindex['row_ids'], $va_row_to_reindex['field_table_num'], $va_row_to_reindex['field_num'], $va_row_to_reindex['field_row_id'], $va_row_to_reindex['field_values'][$va_row_to_reindex['field_name']], array_merge($va_row_to_reindex['indexing_info'], array('relationship_type_id' => $vn_rel_type_id))); } } } } else { // // If the underlying engine doesn't support incremental indexing then // we fall back to reindexing each dependenting row completely and independently. // This can be *really* slow for subjects with many dependent rows (for example, a ca_list_item value used as a type for many ca_objects rows) // and we need to think about how to optimize this for such engines; ultimately since no matter how you slice it in such // engines you're going to have a lot of reindexing going on, we may just have to construct a facility to handle large // indexing tasks in a separate process when the number of dependent rows exceeds a certain threshold // $o_indexer = new SearchIndexer($this->opo_db); $t_dep = null; $va_rows_seen = array(); foreach ($va_rows_to_reindex as $va_row_to_reindex) { if (isset($va_rows_seen[$va_row_to_reindex['table_num']][$va_row_to_reindex['row_id']])) { continue; } if (!$t_dep || $t_dep->tableNum() != $va_row_to_reindex['table_num']) { $t_dep = $this->opo_datamodel->getInstanceByTableNum($va_row_to_reindex['table_num']); } $vb_support_attributes = is_subclass_of($t_dep, 'BaseModelWithAttributes') ? true : false; if (is_array($pa_exclusion_list[$va_row_to_reindex['table_num']]) && isset($pa_exclusion_list[$va_row_to_reindex['table_num']][$va_row_to_reindex['row_id']])) { continue; } // trigger reindexing $this->opo_engine->removeRowIndexing($va_row_to_reindex['table_num'], $va_row_to_reindex['row_id']); if ($vb_support_attributes) { if ($t_dep->load($va_row_to_reindex['row_id'])) { // $o_indexer->indexRow($va_row_to_reindex['table_num'], $va_row_to_reindex['row_id'], $t_dep->getFieldValuesArray(), true, $pa_exclusion_list); } } else { $o_indexer->indexRow($va_row_to_reindex['table_num'], $va_row_to_reindex['row_id'], $va_row_to_reindex['field_values'], true, $pa_exclusion_list); } $va_rows_seen[$va_row_to_reindex['table_num']][$va_row_to_reindex['row_id']] = true; } $o_indexer = null; } } if ($vb_reindex_children && method_exists($t_subject, "makeSearchResult")) { // // Force reindexing of children of this record, typically because the record has shifted location in the hierarchy and is hierarchically indexed // $va_children_ids = $t_subject->getHierarchyAsList($pn_subject_row_id, array('idsOnly' => true)); if (is_array($va_children_ids) && sizeof($va_children_ids) > 0) { // trigger reindexing of children $o_indexer = new SearchIndexer($this->opo_db); $qr_children_res = $t_subject->makeSearchResult($vs_subject_tablename, $va_children_ids, array('db' => $this->getDb())); while ($qr_children_res->nextHit()) { $o_indexer->indexRow($pn_subject_tablenum, $vn_id = $qr_children_res->get($vs_subject_pk), array($vs_subject_pk => $vn_id, 'parent_id' => $qr_children_res->get('parent_id')), true, $pa_exclusion_list, array(), null); } } } }
/** * Implementation of core get() logic * * @param string $ps_field bundle specifier * @param null|array $pa_options options array * @return array|null|string */ private function _get($ps_field, $pa_options = null) { if (!is_array($pa_options)) { $pa_options = array(); } $vb_return_as_array = isset($pa_options['returnAsArray']) ? (bool) $pa_options['returnAsArray'] : false; $vb_return_all_locales = isset($pa_options['returnAllLocales']) ? (bool) $pa_options['returnAllLocales'] : false; $vb_return_with_structure = isset($pa_options['returnWithStructure']) ? (bool) $pa_options['returnWithStructure'] : false; if ($vb_return_with_structure) { $pa_options['returnAsArray'] = $vb_return_as_array = true; } // returnWithStructure implies returnAsArray $vs_delimiter = isset($pa_options['delimiter']) ? $pa_options['delimiter'] : ';'; $vb_unserialize = isset($pa_options['unserialize']) ? (bool) $pa_options['unserialize'] : false; $vb_return_url = isset($pa_options['returnURL']) ? (bool) $pa_options['returnURL'] : false; $vb_return_path = isset($pa_options['returnPath']) ? (bool) $pa_options['returnPAth'] : false; $vb_convert_codes_to_display_text = isset($pa_options['convertCodesToDisplayText']) ? (bool) $pa_options['convertCodesToDisplayText'] : false; $vb_convert_codes_to_idno = isset($pa_options['convertCodesToIdno']) ? (bool) $pa_options['convertCodesToIdno'] : false; $vb_use_locale_codes = isset($pa_options['useLocaleCodes']) ? (bool) $pa_options['useLocaleCodes'] : false; if (!($vs_output = isset($pa_options['output']) ? (string) $pa_options['output'] : null)) { if ($vb_convert_codes_to_display_text) { $vs_output = "text"; } if (!$vs_output && $vb_convert_codes_to_idno) { $vs_output = "idno"; } } if (!in_array($vs_output, array('text', 'idno', 'value'))) { $vs_output = 'value'; } $pa_options['output'] = $vs_output; if (!($vb_return_as_link = isset($pa_options['makeLink']) ? (bool) $pa_options['makeLink'] : false)) { $vb_return_as_link = isset($pa_options['returnAsLink']) ? (bool) $pa_options['returnAsLink'] : false; } $pa_options['makeLink'] = $vb_return_as_link; $vn_max_levels_from_top = isset($pa_options['maxLevelsFromTop']) ? (int) $pa_options['maxLevelsFromTop'] : null; $vn_max_levels_from_bottom = isset($pa_options['maxLevelsFromBottom']) ? (int) $pa_options['maxLevelsFromBottom'] : null; $vn_remove_first_items = isset($pa_options['removeFirstItems']) ? (int) $pa_options['removeFirstItems'] : 0; $va_check_access = isset($pa_options['checkAccess']) ? is_array($pa_options['checkAccess']) ? $pa_options['checkAccess'] : array($pa_options['checkAccess']) : null; $vs_template = isset($pa_options['template']) ? (string) $pa_options['template'] : null; $va_path_components = isset(SearchResult::$s_parsed_field_component_cache[$this->ops_table_name . '/' . $ps_field]) ? SearchResult::$s_parsed_field_component_cache[$this->ops_table_name . '/' . $ps_field] : $this->parseFieldPathComponents($ps_field); $va_val_opts = array_merge($pa_options, array('returnAsArray' => $vb_return_as_array, 'returnAllLocales' => $vb_return_all_locales, 'returnWithStructure' => $vb_return_with_structure, 'pathComponents' => $va_path_components, 'delimiter' => $vs_delimiter, 'makeLink' => $vb_return_as_link, 'returnURL' => $vb_return_url, 'returnPath' => $vb_return_path, 'unserialize' => $vb_unserialize, 'convertCodesToDisplayText' => $vb_convert_codes_to_display_text, 'convertCodesToIdno' => $vb_convert_codes_to_idno, 'checkAccess' => $va_check_access, 'template' => $vs_template, 'useLocaleCodes' => $vb_use_locale_codes)); if ($va_path_components['table_name'] != $this->ops_table_name) { $vs_access_chk_key = $va_path_components['table_name'] . ($va_path_components['field_name'] ? '.' . $va_path_components['field_name'] : ''); } else { $vs_access_chk_key = $va_path_components['field_name']; } if ($va_path_components['field_name'] !== 'access' && caGetBundleAccessLevel($va_path_components['table_name'], $vs_access_chk_key) == __CA_BUNDLE_ACCESS_NONE__) { return null; } if (!(($vs_value = $this->opo_engine_result->get($ps_field, $pa_options)) === false)) { if ($vb_return_as_array) { if ($vb_return_all_locales) { return array(1 => $vs_value); } else { return array($vs_value); } } else { return $vs_value; } } if (!($t_instance = SearchResult::$s_instance_cache[$va_path_components['table_name']])) { $t_instance = SearchResult::$s_instance_cache[$va_path_components['table_name']] = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true); } if (!$t_instance) { return null; } // Bad table $vn_row_id = $this->opo_engine_result->get($this->ops_table_pk); $va_val_opts['primaryKey'] = $t_instance->primaryKey(); if ($va_path_components['hierarchical_modifier']) { if (in_array($va_path_components['field_name'], array('preferred_labels', 'nonpreferred_labels')) && !$va_path_components['subfield_name']) { $va_path_components['subfield_name'] = $va_path_components['components'][2] = $t_instance->getLabelDisplayField(); } switch ($va_path_components['hierarchical_modifier']) { case 'parent': if ($va_path_components['related']) { // [RELATED TABLE PARENT] if (!isset(SearchResult::$opa_hierarchy_parent_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']])) { $this->prefetchHierarchyParents($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_ids = SearchResult::$opa_hierarchy_parent_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']]; } else { // [PRIMARY TABLE PARENT] if (!isset(SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_row_id])) { $this->prefetchHierarchyParents($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_ids = array($vn_row_id); } if (!sizeof($va_ids)) { return $pa_options['returnAsArray'] ? array() : null; } $va_hiers = array(); foreach ($va_ids as $vn_id) { $va_parent_ids = array(); if (isset(SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_id]) && is_array(SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_id])) { if (!is_array($va_parent_ids = SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_id])) { return $pa_options['returnAsArray'] ? array() : null; } } $va_parent_ids = array_slice($va_parent_ids, 0, 1); if (!($qr_hier = $t_instance->makeSearchResult($va_path_components['table_name'], $va_parent_ids))) { return $pa_options['returnAsArray'] ? array() : null; } $va_tmp = array($va_path_components['table_name']); if ($va_path_components['field_name']) { $va_tmp[] = $va_path_components['field_name']; } if ($va_path_components['subfield_name']) { $va_tmp[] = $va_path_components['subfield_name']; } $vs_hier_fld_name = join(".", $va_tmp); $vs_pk = $t_instance->primaryKey(); $vm_val = null; if ($qr_hier->nextHit()) { $vm_val = $qr_hier->get($vs_hier_fld_name, $pa_options); } if ($vm_val) { $va_hiers[] = $vb_return_as_array ? array_shift($vm_val) : $vm_val; } } return $vb_return_as_array ? $va_hiers : join($vs_delimiter, $va_hiers); break; case 'hierarchy': // generate the hierarchy if ($va_path_components['related']) { // [RELATED TABLE HIERARCHY] if (!isset(SearchResult::$opa_hierarchy_parent_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']])) { $this->prefetchHierarchyParents($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } // ids of related items $va_ids = array_values(SearchResult::$opa_hierarchy_parent_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']]); } else { // [PRIMARY TABLE HIERARCHY] if (!isset(SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_row_id])) { $this->prefetchHierarchyParents($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_ids = array($vn_row_id); } if (!sizeof($va_ids)) { return $pa_options['returnAsArray'] ? array() : null; } $vs_hier_pk_fld = $t_instance->primaryKey(); $va_hiers = $va_hier_ids = array(); $vs_hierarchy_direction = isset($pa_options['hierarchyDirection']) ? strtolower($pa_options['hierarchyDirection']) : 'asc'; if ($t_instance->isHierarchical()) { if ($va_path_components['field_name'] === $vs_hier_pk_fld) { if ($va_path_components['related']) { foreach ($va_ids as $vn_id) { if (is_array(SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_id])) { $va_hier_id_list = array_merge(array($vn_id), SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_id]); $va_hier_id_list = array_filter($va_hier_id_list, function ($v) { return $v > 0; }); if ($vs_hierarchy_direction === 'asc') { $va_hier_id_list = array_reverse($va_hier_id_list); } if (!is_null($vn_max_levels_from_top)) { $va_hier_id_list = array_slice($va_hier_id_list, 0, $vn_max_levels_from_top, true); } elseif (!is_null($vn_max_levels_from_bottom)) { if (($vn_start = sizeof($va_hier_id_list) - $vn_max_levels_from_bottom) < 0) { $vn_start = 0; } $va_hier_id_list = array_slice($va_hier_id_list, $vn_start, $vn_max_levels_from_bottom, true); } $va_hier_ids[] = $va_hier_id_list; } } } else { // Return ids from hierarchy in order if (is_array(SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_row_id])) { $va_hier_ids = array_merge(array($vn_row_id), SearchResult::$opa_hierarchy_parent_prefetch_cache[$va_path_components['table_name']][$vn_row_id]); } else { $va_hier_ids = array($vn_row_id); } if (!is_null($vn_max_levels_from_top)) { $va_hier_ids = array_slice($va_hier_ids, 0, $vn_max_levels_from_top, true); } elseif (!is_null($vn_max_levels_from_bottom)) { if (($vn_start = sizeof($va_hier_ids) - $vn_max_levels_from_bottom) < 0) { $vn_start = 0; } $va_hier_ids = array_slice($va_hier_ids, $vn_start, $vn_max_levels_from_bottom, true); } if ($vs_hierarchy_direction === 'asc') { $va_hier_ids = array_reverse($va_hier_ids); } } return $vb_return_as_array ? $va_hier_ids : join($vs_delimiter, $va_hier_ids); } else { $vs_field_spec = join('.', array_values($va_path_components['components'])); $va_ancestor_id_list = $this->get($va_path_components['table_name'] . '.hierarchy.' . $vs_hier_pk_fld, array_merge($pa_options, array('returnAsArray' => true, 'returnAsLink' => false, 'returnAllLocales' => false))); if (!is_array($va_ancestor_id_list)) { return $vb_return_as_array ? array() : null; } if (!$va_path_components['related']) { $va_ancestor_id_list = array($va_ancestor_id_list); } $va_hier_list = array(); foreach ($va_ancestor_id_list as $va_ancestor_ids) { if ($vn_remove_first_items > 0) { $va_ancestor_ids = array_slice($va_ancestor_ids, $vn_remove_first_items); } $va_hier_item = array(); if ($qr_hier = caMakeSearchResult($va_path_components['table_name'], $va_ancestor_ids)) { while ($qr_hier->nextHit()) { $va_hier_item += $qr_hier->get($vs_field_spec, array('returnWithStructure' => true, 'returnAllLocales' => true, 'useLocaleCodes' => $pa_options['useLocaleCodes'])); } if (!is_null($vn_max_levels_from_top)) { $va_hier_item = array_slice($va_hier_item, 0, $vn_max_levels_from_top, true); } elseif (!is_null($vn_max_levels_from_bottom)) { if (($vn_start = sizeof($va_hier_item) - $vn_max_levels_from_bottom) < 0) { $vn_start = 0; } $va_hier_item = array_slice($va_hier_item, $vn_start, $vn_max_levels_from_bottom, true); } $va_hier_list[] = $va_hier_item; } } } } $va_acc = array(); foreach ($va_hier_list as $vn_h => $va_hier_item) { if (!$vb_return_all_locales) { $va_hier_item = caExtractValuesByUserLocale($va_hier_item); } if ($vb_return_with_structure) { $va_acc[] = $va_hier_item; } else { $va_acc = $this->_flattenArray($va_hier_item, $pa_options); } } return $pa_options['returnAsArray'] ? $va_acc : join($vs_delimiter, $va_acc); break; case 'children': // grab children if ($va_path_components['related']) { // [RELATED TABLE CHILDREN] if (!isset(SearchResult::$opa_hierarchy_children_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']])) { $this->prefetchHierarchyChildren($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_ids = SearchResult::$opa_hierarchy_children_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']]; } else { // [PRIMARY TABLE CHILDREN] if (!isset(SearchResult::$opa_hierarchy_children_prefetch_cache[$this->ops_table_name][$vn_row_id])) { $this->prefetchHierarchyChildren($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_ids = array($vn_row_id); } $va_hier_list = array(); foreach ($va_ids as $vn_id) { if (!is_array(SearchResult::$opa_hierarchy_children_prefetch_cache[$va_path_components['table_name']][$vn_id]) || !sizeof(SearchResult::$opa_hierarchy_children_prefetch_cache[$va_path_components['table_name']][$vn_id])) { continue; } $qr_hier = $t_instance->makeSearchResult($va_path_components['table_name'], SearchResult::$opa_hierarchy_children_prefetch_cache[$va_path_components['table_name']][$vn_id]); $va_tmp = array($va_path_components['table_name']); if ($va_path_components['field_name']) { $va_tmp[] = $va_path_components['field_name']; } if ($va_path_components['subfield_name']) { $va_tmp[] = $va_path_components['subfield_name']; } $vs_hier_fld_name = join(".", $va_tmp); $vs_pk = $t_instance->primaryKey(); while ($qr_hier->nextHit()) { $vm_val = $qr_hier->get($vs_hier_fld_name, $pa_options); $va_hier_list[$qr_hier->get($va_path_components['table_name'] . '.' . $vs_pk)] = $vb_return_as_array ? array_shift($vm_val) : $vm_val; } } if (!$vb_return_as_array) { return join($vs_delimiter, $va_hier_list); } return $va_hier_list; break; case 'siblings': // grab siblings if ($va_path_components['related']) { // [RELATED TABLE SIBLINGS] if (!isset(SearchResult::$opa_hierarchy_siblings_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']])) { $this->prefetchHierarchySiblings($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_ids = SearchResult::$opa_hierarchy_siblings_prefetch_cache_index[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']]; } else { // [PRIMARY TABLE SIBLINGS] if (!isset(SearchResult::$opa_hierarchy_siblings_prefetch_cache[$this->ops_table_name][$vn_row_id])) { $this->prefetchHierarchySiblings($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_ids = array($vn_row_id); } $va_hier_list = array(); foreach ($va_ids as $vn_id) { if (!is_array(SearchResult::$opa_hierarchy_siblings_prefetch_cache[$va_path_components['table_name']][$vn_id]) || !sizeof(SearchResult::$opa_hierarchy_siblings_prefetch_cache[$va_path_components['table_name']][$vn_id])) { continue; } $qr_hier = $t_instance->makeSearchResult($va_path_components['table_name'], SearchResult::$opa_hierarchy_siblings_prefetch_cache[$va_path_components['table_name']][$vn_id]); $va_tmp = array($va_path_components['table_name']); if ($va_path_components['field_name']) { $va_tmp[] = $va_path_components['field_name']; } if ($va_path_components['subfield_name']) { $va_tmp[] = $va_path_components['subfield_name']; } $vs_hier_fld_name = join(".", $va_tmp); $vs_pk = $t_instance->primaryKey(); while ($qr_hier->nextHit()) { $vm_val = $qr_hier->get($vs_hier_fld_name, $pa_options); $va_hier_list[$qr_hier->get($va_path_components['table_name'] . '.' . $vs_pk)] = $vb_return_as_array ? array_shift($vm_val) : $vm_val; } } if (!$vb_return_as_array) { return join($vs_delimiter, $va_hier_list); } return $va_hier_list; break; } return; } if ($va_path_components['related']) { // // [RELATED TABLE] // $vs_opt_md5 = caMakeCacheKeyFromOptions(array_merge($pa_options, array('dontReturnLabels' => false))); if (!isset(self::$s_rel_prefetch_cache[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']][$vs_opt_md5])) { $this->prefetchRelated($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), array_merge($pa_options, array('dontReturnLabels' => false))); } $va_related_items = self::$s_rel_prefetch_cache[$this->ops_table_name][$vn_row_id][$va_path_components['table_name']][$vs_opt_md5]; if (!is_array($va_related_items)) { return $vb_return_with_structure || $vb_return_as_array ? array() : null; } return $this->_getRelatedValue($va_related_items, $va_val_opts); } else { if (!$va_path_components['hierarchical_modifier']) { // // [PRIMARY TABLE] Created on // if ($va_path_components['field_name'] == 'created') { if (!isset(self::$s_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id])) { $this->prefetchChangeLogData($this->ops_table_name, $this->opo_engine_result->currentRow(), $this->getOption('prefetch')); } if ($vb_return_as_array) { return self::$s_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id]; } else { $vs_subfield = $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : 'timestamp'; $vm_val = self::$s_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id][$vs_subfield]; if ($vs_subfield == 'timestamp') { $this->opo_tep->init(); $this->opo_tep->setUnixTimestamps($vm_val, $vm_val); $vm_val = $this->opo_tep->getText($pa_options); } return $vm_val; } } // // [PRIMARY TABLE] Last modified on // if ($va_path_components['field_name'] == 'lastModified') { if (!isset(self::$s_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id])) { $this->prefetchChangeLogData($this->ops_table_name, $this->opo_engine_result->currentRow(), $this->getOption('prefetch')); } if ($vb_return_as_array) { return self::$s_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id]; } else { $vs_subfield = $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : 'timestamp'; $vm_val = self::$s_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id][$vs_subfield]; if ($vs_subfield == 'timestamp') { $this->opo_tep->init(); $this->opo_tep->setUnixTimestamps($vm_val, $vm_val); $vm_val = $this->opo_tep->getText($pa_options); } return $vm_val; } } $vs_opt_md5 = caMakeCacheKeyFromOptions($pa_options); // // [PRIMARY TABLE] Preferred/nonpreferred labels // if (in_array($va_path_components['field_name'], array('preferred_labels', 'nonpreferred_labels')) && $t_instance instanceof LabelableBaseModelWithAttributes) { $vs_label_table_name = $t_instance->getLabelTableName(); if (!isset(self::$s_prefetch_cache[$vs_label_table_name][$vn_row_id][$vs_opt_md5])) { $this->prefetchLabels($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } return $this->_getLabelValue(self::$s_prefetch_cache[$vs_label_table_name][$vn_row_id][$vs_opt_md5], $t_instance, $va_val_opts); } if ($t_instance->hasField($va_path_components['field_name'])) { $va_val_opts['fieldInfo'] = $t_instance->getFieldInfo($va_path_components['field_name']); // // [PRIMARY TABLE] Plain old intrinsic // if (!isset(self::$s_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) { $this->prefetch($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } return $this->_getIntrinsicValue(self::$s_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5], $t_instance, $va_val_opts); } elseif (method_exists($t_instance, 'isValidBundle') && !$t_instance->hasElement($va_path_components['field_name']) && $t_instance->isValidBundle($va_path_components['field_name'])) { // // [PRIMARY TABLE] Special bundle // return $t_instance->renderBundleForDisplay($va_path_components['field_name'], $vn_row_id, self::$s_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5], $va_val_opts); } else { // // [PRIMARY TABLE] Metadata attribute // if ($t_instance instanceof BaseModelWithAttributes && isset($va_path_components['field_name']) && $va_path_components['field_name'] && ($t_element = $t_instance->_getElementInstance($va_path_components['field_name']))) { $vn_element_id = $t_element->getPrimaryKey(); } else { return $pa_options['returnAsArray'] ? array() : null; } if (!isset(ca_attributes::$s_get_attributes_cache[(int) $this->opn_table_num . '/' . (int) $vn_row_id][(int) $vn_element_id])) { ca_attributes::prefetchAttributes($this->opo_subject_instance->getDb(), $this->opn_table_num, $this->getRowIDsToPrefetch($this->opo_engine_result->currentRow(), $this->getOption('prefetch')), $vn_element_id ? array($vn_element_id) : null, array('dontFetchAlreadyCachedValues' => true)); } $va_attributes = ca_attributes::getAttributes($this->opo_subject_instance->getDb(), $this->opn_table_num, $vn_row_id, array($vn_element_id), array()); return $this->_getAttributeValue($va_attributes[$vn_element_id], $t_instance, $va_val_opts); } } } return null; }
/** * Retrieves attribute value for a list of rows * * @return array Array of values indexed on row_id, then locale_id and finally an index (to accommodate repeating values) */ public static function getAttributeValueForIDs($po_db, $pn_table_num, $pa_row_ids, $pn_element_id, $pa_options = null) { $vb_is_cached = true; foreach ($pa_row_ids as $vn_row_id) { if (!is_array(ca_attributes::$s_get_attributes_cache[$pn_table_num . '/' . $vn_row_id][$pn_element_id])) { $vb_is_cached = false; break; } } if (!$vb_is_cached) { if (!ca_attributes::prefetchAttributes($po_db, $pn_table_num, $pa_row_ids, array($pn_element_id))) { return null; } } $va_values = array(); foreach ($pa_row_ids as $vn_i => $vn_row_id) { foreach (ca_attributes::$s_get_attributes_cache[$pn_table_num . '/' . $vn_row_id] as $va_elements) { foreach ($va_elements as $vn_j => $o_attr) { if ((int) $o_attr->getElementID() === (int) $pn_element_id) { $va_attr_values = $o_attr->getValues(); $vn_locale_id = $o_attr->getLocaleID(); foreach ($va_attr_values as $va_attr_value) { $va_values[$vn_row_id][$vn_locale_id][] = $va_attr_value->getDisplayValue(); } } } } } return $va_values; }
/** * Processes single exporter item for a given record * * @param int $pn_item_id Primary of exporter item * @param int $pn_table_num Table num of item to export * @param int $pn_record_id Primary key value of item to export * @param array $pa_options * ignoreContext = don't switch context even though context may be set for current item * relationship_type_id, relationship_type_code, relationship_typename = * if this export is a sub-export (context-switch), we have no way of knowing the relationship * to the 'parent' element in the export, so there has to be a means to pass it down to make it accessible * attribute_id = signals that this is an export relative to a specific attribute instance * this triggers special behavior that allows getting container values in a kind of sub-export * it's really only useful for Containers but in theory can be any attribute * logger = KLogger instance to use for logging. This option is mandatory! * @return array Item info */ public function processExporterItem($pn_item_id, $pn_table_num, $pn_record_id, $pa_options = array()) { $o_log = caGetOption('logger', $pa_options); // always set by exportRecord() $vb_ignore_context = caGetOption('ignoreContext', $pa_options); $vn_attribute_id = caGetOption('attribute_id', $pa_options); $o_log->logInfo(_t("Export mapping processor called with parameters [exporter_item_id:%1 table_num:%2 record_id:%3]", $pn_item_id, $pn_table_num, $pn_record_id)); $t_exporter_item = ca_data_exporters::loadExporterItemByID($pn_item_id); $t_instance = ca_data_exporters::loadInstanceByID($pn_record_id, $pn_table_num); // switch context to a different set of records if necessary and repeat current exporter item for all those selected records // (e.g. hierarchy children or related items in another table, restricted by types or relationship types) if (!$vb_ignore_context && ($vs_context = $t_exporter_item->getSetting('context'))) { $va_restrict_to_types = $t_exporter_item->getSetting('restrictToTypes'); $va_restrict_to_rel_types = $t_exporter_item->getSetting('restrictToRelationshipTypes'); $va_restrict_to_bundle_vals = $t_exporter_item->getSetting('restrictToBundleValues'); $va_check_access = $t_exporter_item->getSetting('checkAccess'); $va_sort = $t_exporter_item->getSetting('sort'); $vn_new_table_num = $this->getAppDatamodel()->getTableNum($vs_context); $vb_context_is_related_table = false; $va_related = null; if ($vn_new_table_num) { // switch to new table $vs_key = $this->getAppDatamodel()->getTablePrimaryKeyName($vs_context); } else { // this table, i.e. hierarchy context switch $vs_key = $t_instance->primaryKey(); } $o_log->logInfo(_t("Initiating context switch to '%1' for mapping ID %2 and record ID %3. The processor now tries to find matching records for the switch and calls itself for each of those items.", $vs_context, $pn_item_id, $pn_record_id)); switch ($vs_context) { case 'children': $va_related = $t_instance->getHierarchyChildren(); break; case 'parent': $va_related = array(); if ($vs_parent_id_fld = $t_instance->getProperty("HIERARCHY_PARENT_ID_FLD")) { $va_related[] = array($vs_key => $t_instance->get($vs_parent_id_fld)); } break; case 'ancestors': $va_parents = $t_instance->getHierarchyAncestors(null, array('idsOnly' => true)); $va_related = array(); foreach (array_unique($va_parents) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; case 'ca_sets': $t_set = new ca_sets(); $va_set_options = array(); if (isset($va_restrict_to_types[0])) { // the utility used below doesn't support passing multiple types so we just pass the first. // this should be enough for 99.99% of the actual use cases anyway $va_set_options['setType'] = $va_restrict_to_types[0]; } $va_set_options['checkAccess'] = $va_check_access; $va_set_options['setIDsOnly'] = true; $va_set_ids = $t_set->getSetsForItem($pn_table_num, $t_instance->getPrimaryKey(), $va_set_options); $va_related = array(); foreach (array_unique($va_set_ids) as $vn_pk) { $va_related[] = array($vs_key => intval($vn_pk)); } break; case 'ca_list_items.firstLevel': if ($t_instance->tableName() == 'ca_lists') { $o_dm = Datamodel::load(); $va_related = array(); $va_items_legacy_format = $t_instance->getListItemsAsHierarchy(null, array('maxLevels' => 1, 'dontIncludeRoot' => true)); $vn_new_table_num = $o_dm->getTableNum('ca_list_items'); $vs_key = 'item_id'; foreach ($va_items_legacy_format as $va_item_legacy_format) { $va_related[$va_item_legacy_format['NODE']['item_id']] = $va_item_legacy_format['NODE']; } break; } else { return array(); } break; default: if ($vn_new_table_num) { $va_options = array('restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_rel_types, 'restrictToBundleValues' => $va_restrict_to_bundle_vals, 'checkAccess' => $va_check_access, 'sort' => $va_sort); $o_log->logDebug(_t("Calling getRelatedItems with options: %1.", print_r($va_options, true))); $va_related = $t_instance->getRelatedItems($vs_context, $va_options); $vb_context_is_related_table = true; } else { // container or invalid context $va_context_tmp = explode('.', $vs_context); if (sizeof($va_context_tmp) != 2) { $o_log->logError(_t("Invalid context %1. Ignoring this mapping.", $vs_context)); return array(); } $va_attrs = $t_instance->getAttributesByElement($va_context_tmp[1]); $va_info = array(); if (is_array($va_attrs) && sizeof($va_attrs) > 0) { $o_log->logInfo(_t("Switching context for element code: %1.", $va_context_tmp[1])); $o_log->logDebug(_t("Raw attribute value array is as follows. The mapping will now be repeated for each (outer) attribute. %1", print_r($va_attrs, true))); foreach ($va_attrs as $vo_attr) { $va_attribute_export = $this->processExporterItem($pn_item_id, $pn_table_num, $pn_record_id, array_merge(array('ignoreContext' => true, 'attribute_id' => $vo_attr->getAttributeID()), $pa_options)); $va_info = array_merge($va_info, $va_attribute_export); } } else { $o_log->logInfo(_t("Switching context for element code %1 failed. Either there is no attribute with that code attached to the current row or the code is invalid. Mapping is ignored for current row.", $va_context_tmp[1])); } return $va_info; } break; } $va_info = array(); if (is_array($va_related)) { $o_log->logDebug(_t("The current mapping will now be repreated for these items: %1", print_r($va_related, true))); if (!$vn_new_table_num) { $vn_new_table_num = $pn_table_num; } foreach ($va_related as $va_rel) { // if we're dealing with a related table, pass on some info the relationship type to the context-switched invocation of processExporterItem(), // because we can't access that information from the related item simply because we don't exactly know where the call originated if ($vb_context_is_related_table) { $pa_options['relationship_typename'] = $va_rel['relationship_typename']; $pa_options['relationship_type_code'] = $va_rel['relationship_type_code']; $pa_options['relationship_type_id'] = $va_rel['relationship_type_id']; } $va_rel_export = $this->processExporterItem($pn_item_id, $vn_new_table_num, $va_rel[$vs_key], array_merge(array('ignoreContext' => true), $pa_options)); $va_info = array_merge($va_info, $va_rel_export); } } else { $o_log->logDebug(_t("No matching related items found for last context switch")); } return $va_info; } // end switch context // Don't prevent context switches for children of context-switched exporter items. This way you can // build cascades for jobs like exporting objects related to the creator of the record in question. unset($pa_options['ignoreContext']); $va_item_info = array(); $vs_source = $t_exporter_item->get('source'); $vs_element = $t_exporter_item->get('element'); $vb_repeat = $t_exporter_item->getSetting('repeat_element_for_multiple_values'); // if omitIfEmpty is set and get() returns nothing, we ignore this exporter item and all children if ($vs_omit_if_empty = $t_exporter_item->getSetting('omitIfEmpty')) { if (!(strlen($t_instance->get($vs_omit_if_empty)) > 0)) { return array(); } } // if omitIfNotEmpty is set and get() returns a value, we ignore this exporter item and all children if ($vs_omit_if_not_empty = $t_exporter_item->getSetting('omitIfNotEmpty')) { if (strlen($t_instance->get($vs_omit_if_not_empty)) > 0) { return array(); } } // always return URL for export, not an HTML tag $va_get_options = array('returnURL' => true); if ($vs_delimiter = $t_exporter_item->getSetting("delimiter")) { $va_get_options['delimiter'] = $vs_delimiter; } if ($vs_template = $t_exporter_item->getSetting('template')) { $va_get_options['template'] = $vs_template; } if ($vs_locale = $t_exporter_item->getSetting('locale')) { // the global UI locale for some reason has a higher priority // than the locale setting in BaseModelWithAttributes::get // which is why we unset it here and restore it later global $g_ui_locale; $vs_old_ui_locale = $g_ui_locale; $g_ui_locale = null; $va_get_options['locale'] = $vs_locale; } // AttributeValue settings that are simply passed through by the exporter if ($t_exporter_item->getSetting('convertCodesToDisplayText')) { $va_get_options['convertCodesToDisplayText'] = true; // try to return text suitable for display for system lists stored in intrinsics (ex. ca_objects.access, ca_objects.status, ca_objects.source_id) // this does not affect list attributes } else { $va_get_options['convertCodesToIdno'] = true; // if display text is not requested try to return list item idno's... since underlying integer ca_list_items.item_id values are unlikely to be useful in an export context } if ($t_exporter_item->getSetting('returnIdno')) { $va_get_options['returnIdno'] = true; } if ($t_exporter_item->getSetting('start_as_iso8601')) { $va_get_options['start_as_iso8601'] = true; } if ($t_exporter_item->getSetting('end_as_iso8601')) { $va_get_options['end_as_iso8601'] = true; } if ($t_exporter_item->getSetting('dontReturnValueIfOnSameDayAsStart')) { $va_get_options['dontReturnValueIfOnSameDayAsStart'] = true; } if ($vs_date_format = $t_exporter_item->getSetting('dateFormat')) { $va_get_options['dateFormat'] = $vs_date_format; } // context was switched to attribute if ($vn_attribute_id) { $o_log->logInfo(_t("Processing mapping in attribute mode for attribute_id = %1.", $vn_attribute_id)); if ($vs_source) { // trying to find the source only makes sense if the source is set $t_attr = new ca_attributes($vn_attribute_id); $va_values = $t_attr->getAttributeValues(); $va_src_tmp = explode('.', $vs_source); if (sizeof($va_src_tmp) == 2) { $o_dm = Datamodel::load(); if ($t_attr->get('table_num') == $o_dm->getTableNum($va_src_tmp[0])) { $vs_source = $va_src_tmp[1]; } } $o_log->logDebug(_t("Trying to find code %1 in value array for the current attribute.", $vs_source)); $o_log->logDebug(_t("Value array is %1.", print_r($va_values, true))); foreach ($va_values as $vo_val) { $va_display_val_options = array(); if ($vo_val instanceof ListAttributeValue) { // figure out list_id -- without it we can't pull display values $t_element = new ca_metadata_elements($vo_val->getElementID()); $va_display_val_options = array('list_id' => $t_element->get('list_id')); if ($t_exporter_item->getSetting('returnIdno') || $t_exporter_item->getSetting('convertCodesToIdno')) { $va_display_val_options['output'] = 'idno'; } elseif ($t_exporter_item->getSetting('convertCodesToDisplayText')) { $va_display_val_options['output'] = 'text'; } } $o_log->logDebug(_t("Trying to match code from array %1 and the code we're looking for %2.", $vo_val->getElementCode(), $vs_source)); if ($vo_val->getElementCode() == $vs_source) { $vs_display_value = $vo_val->getDisplayValue($va_display_val_options); $o_log->logDebug(_t("Found value %1.", $vs_display_value)); $va_item_info[] = array('text' => $vs_display_value, 'element' => $vs_element); } } } else { // no source in attribute context probably means this is some form of wrapper, e.g. a MARC field $va_item_info[] = array('element' => $vs_element); } } else { if ($vs_source) { $o_log->logDebug(_t("Source for current mapping is %1", $vs_source)); $va_matches = array(); // CONSTANT value if (preg_match("/^_CONSTANT_:(.*)\$/", $vs_source, $va_matches)) { $o_log->logDebug(_t("This is a constant. Value for this mapping is '%1'", trim($va_matches[1]))); $va_item_info[] = array('text' => trim($va_matches[1]), 'element' => $vs_element); } else { if (in_array($vs_source, array("relationship_type_id", "relationship_type_code", "relationship_typename"))) { if (isset($pa_options[$vs_source]) && strlen($pa_options[$vs_source]) > 0) { $o_log->logDebug(_t("Source refers to releationship type information. Value for this mapping is '%1'", $pa_options[$vs_source])); $va_item_info[] = array('text' => $pa_options[$vs_source], 'element' => $vs_element); } } else { if (!$vb_repeat) { $vs_get = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a simple get() for some bundle. Value for this mapping is '%1'", $vs_get)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_item_info[] = array('text' => $vs_get, 'element' => $vs_element); } else { // user wants current element repeated in case of multiple returned values $va_get_options['delimiter'] = ';#;'; $vs_values = $t_instance->get($vs_source, $va_get_options); $o_log->logDebug(_t("Source is a get() that should be repeated for multiple values. Value for this mapping is '%1'. It includes the custom delimiter ';#;' that is later used to split the value into multiple values.", $vs_values)); $o_log->logDebug(_t("get() options are: %1", print_r($va_get_options, true))); $va_tmp = explode(";#;", $vs_values); foreach ($va_tmp as $vs_text) { $va_item_info[] = array('element' => $vs_element, 'text' => $vs_text); } } } } } else { if ($vs_template) { // templates without source are probably just static text, but you never know // -> run them through processor anyways $vs_proc_template = caProcessTemplateForIDs($vs_template, $pn_table_num, array($pn_record_id), array()); $o_log->logDebug(_t("Current mapping has no source but a template '%1'. Value from extracted via template processor is '%2'", $vs_template, $vs_proc_template)); $va_item_info[] = array('element' => $vs_element, 'text' => $vs_proc_template); } else { // no source, no template -> probably wrapper $o_log->logDebug(_t("Current mapping has no source and no template and is probably an XML/MARC wrapper element")); $va_item_info[] = array('element' => $vs_element); } } } // reset UI locale if we unset it if ($vs_locale) { $g_ui_locale = $vs_old_ui_locale; } $o_log->logDebug(_t("We're now processing other settings like default, prefix, suffix, skipIfExpression, filterByRegExp, maxLength, plugins and replacements for this mapping")); $o_log->logDebug(_t("Local data before processing is: %1", print_r($va_item_info, true))); // handle other settings and plugin hooks $vs_default = $t_exporter_item->getSetting('default'); $vs_prefix = $t_exporter_item->getSetting('prefix'); $vs_suffix = $t_exporter_item->getSetting('suffix'); //$vs_regexp = $t_exporter_item->getSetting('filterByRegExp'); // Deprecated -- remove? $vn_max_length = $t_exporter_item->getSetting('maxLength'); $vs_skip_if_expr = $t_exporter_item->getSetting('skipIfExpression'); $vs_original_values = $t_exporter_item->getSetting('original_values'); $vs_replacement_values = $t_exporter_item->getSetting('replacement_values'); $va_replacements = ca_data_exporter_items::getReplacementArray($vs_original_values, $vs_replacement_values); foreach ($va_item_info as $vn_key => &$va_item) { $this->opo_app_plugin_manager->hookExportItemBeforeSettings(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => &$va_item)); // handle dontReturnValueIfOnSameDayAsStart if (caGetOption('dontReturnValueIfOnSameDayAsStart', $va_get_options, false)) { if (strlen($va_item['text']) < 1) { unset($va_item_info[$vn_key]); } } // handle skipIfExpression setting if ($vs_skip_if_expr) { // Add current value as variable "value", accessible in expressions as ^value $va_vars = array_merge(array('value' => $va_item['text']), ca_data_exporters::$s_variables); if (ExpressionParser::evaluate($vs_skip_if_expr, $va_vars)) { unset($va_item_info[$vn_key]); continue; } } // filter by regex (deprecated since you can do the same thing and more with skipIfExpression) -- remove? //if((strlen($va_item['text'])>0) && $vs_regexp) { // if(!preg_match("!".$vs_regexp."!i", $va_item['text'])) { // unset($va_item_info[$vn_key]); // continue; // } //} // do replacements $va_item['text'] = ca_data_exporter_items::replaceText($va_item['text'], $va_replacements); // if text is empty, fill in default // if text isn't empty, respect prefix and suffix if (strlen($va_item['text']) == 0) { if ($vs_default) { $va_item['text'] = $vs_default; } } else { if (strlen($vs_prefix) > 0 || strlen($vs_suffix) > 0) { $va_item['text'] = $vs_prefix . $va_item['text'] . $vs_suffix; } } if ($vn_max_length && strlen($va_item['text']) > $vn_max_length) { $va_item['text'] = substr($va_item['text'], 0, $vn_max_length) . " ..."; } // if this is a variable, set the value and delete it from the export tree $va_matches = array(); if (preg_match("/^_VARIABLE_:(.*)\$/", $va_item['element'], $va_matches)) { ca_data_exporters::$s_variables[$va_matches[1]] = $va_item['text']; unset($va_item_info[$vn_key]); continue; } // if returned value is null then we skip the item $this->opo_app_plugin_manager->hookExportItem(array('instance' => $t_instance, 'exporter_item_instance' => $t_exporter_item, 'export_item' => &$va_item)); } $o_log->logInfo(_t("Extracted data for this mapping is as follows:")); foreach ($va_item_info as $va_tmp) { $o_log->logInfo(sprintf(" element:%-20s value: %-10s", $va_tmp['element'], $va_tmp['text'])); } $va_children = $t_exporter_item->getHierarchyChildren(); if (is_array($va_children) && sizeof($va_children) > 0) { $o_log->logInfo(_t("Now proceeding to process %1 direct children in the mapping hierarchy", sizeof($va_children))); foreach ($va_children as $va_child) { foreach ($va_item_info as &$va_info) { $va_child_export = $this->processExporterItem($va_child['item_id'], $pn_table_num, $pn_record_id, $pa_options); $va_info['children'] = array_merge((array) $va_info['children'], $va_child_export); } } } return $va_item_info; }
/** * */ public static function check_media_fixity($po_opts = null) { require_once __CA_LIB_DIR__ . "/core/Db.php"; require_once __CA_MODELS_DIR__ . "/ca_object_representations.php"; $ps_file_path = strtolower((string) $po_opts->getOption('file')); $ps_format = strtolower((string) $po_opts->getOption('format')); if (!in_array($ps_format, array('text', 'tab', 'csv'))) { $ps_format = 'text'; } $o_db = new Db(); $o_dm = Datamodel::load(); $t_rep = new ca_object_representations(); $vs_report_output = join($ps_format == 'tab' ? "\t" : ",", array(_t('Type'), _t('Error'), _t('Name'), _t('ID'), _t('Version'), _t('File path'), _t('Expected MD5'), _t('Actual MD5'))) . "\n"; // Verify object representations $qr_reps = $o_db->query("SELECT representation_id, idno, media FROM ca_object_representations WHERE deleted = 0"); print CLIProgressBar::start($vn_rep_count = $qr_reps->numRows(), _t('Checking object representations')) . "\n"; $vn_errors = 0; while ($qr_reps->nextRow()) { $vn_representation_id = $qr_reps->get('representation_id'); print CLIProgressBar::next(1, _t("Checking representation media %1", $vn_representation_id)); $va_media_versions = $qr_reps->getMediaVersions('media'); foreach ($va_media_versions as $vs_version) { $vs_path = $qr_reps->getMediaPath('media', $vs_version); $vs_database_md5 = $qr_reps->getMediaInfo('media', $vs_version, 'MD5'); $vs_file_md5 = md5_file($vs_path); if ($vs_database_md5 !== $vs_file_md5) { $t_rep->load($vn_representation_id); $vs_message = _t("[Object representation][MD5 mismatch] %1; version %2 [%3]", $t_rep->get("ca_objects.preferred_labels.name") . " (" . $t_rep->get("ca_objects.idno") . "); representation_id={$vn_representation_id}", $vs_version, $vs_path); switch ($ps_format) { case 'text': default: $vs_report_output .= "{$vs_message}\n"; break; case 'tab': case 'csv': $va_log = array(_t('Object representation'), "MD5 mismatch", caEscapeForDelimitedOutput($t_rep->get("ca_objects.preferred_labels.name") . " (" . $t_rep->get("ca_objects.idno") . ")"), $vn_representation_id, $vs_version, $vs_path, $vs_database_md5, $vs_file_md5); $vs_report_output .= join($ps_format == 'tab' ? "\t" : ",", $va_log) . "\n"; break; } CLIUtils::addError($vs_message); $vn_errors++; } } } print CLIProgressBar::finish(); CLIUtils::addMessage(_t('%1 errors for %2 representations', $vn_errors, $vn_rep_count)); // get all Media elements $va_elements = ca_metadata_elements::getElementsAsList(false, null, null, true, false, true, array(16)); // 16=media if (is_array($va_elements) && sizeof($va_elements)) { if (is_array($va_element_ids = caExtractValuesFromArrayList($va_elements, 'element_id', array('preserveKeys' => false))) && sizeof($va_element_ids)) { $qr_c = $o_db->query("\n\t\t\t\t\t\tSELECT count(*) c\n\t\t\t\t\t\tFROM ca_attribute_values\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\telement_id in (?)\n\t\t\t\t\t", array($va_element_ids)); if ($qr_c->nextRow()) { $vn_count = $qr_c->get('c'); } else { $vn_count = 0; } print CLIProgressBar::start($vn_count, _t('Checking attribute media')); $vn_errors = 0; foreach ($va_elements as $vs_element_code => $va_element_info) { $qr_vals = $o_db->query("SELECT value_id FROM ca_attribute_values WHERE element_id = ?", (int) $va_element_info['element_id']); $va_vals = $qr_vals->getAllFieldValues('value_id'); foreach ($va_vals as $vn_value_id) { $t_attr_val = new ca_attribute_values($vn_value_id); if ($t_attr_val->getPrimaryKey()) { $t_attr_val->setMode(ACCESS_WRITE); $t_attr_val->useBlobAsMediaField(true); print CLIProgressBar::next(1, _t("Checking attribute media %1", $vn_value_id)); $va_media_versions = $t_attr_val->getMediaVersions('value_blob'); foreach ($va_media_versions as $vs_version) { $vs_path = $t_attr_val->getMediaPath('value_blob', $vs_version); $vs_database_md5 = $t_attr_val->getMediaInfo('value_blob', $vs_version, 'MD5'); $vs_file_md5 = md5_file($vs_path); if ($vs_database_md5 !== $vs_file_md5) { $t_attr = new ca_attributes($vn_attribute_id = $t_attr_val->get('attribute_id')); $vs_label = "attribute_id={$vn_attribute_id}; value_id={$vn_value_id}"; if ($t_instance = $o_dm->getInstanceByTableNum($t_attr->get('table_num'), true)) { if ($t_instance->load($t_attr->get('row_id'))) { $vs_label = $t_instance->get($t_instance->tableName() . '.preferred_labels'); if ($vs_idno = $t_instance->get($t_instance->getProperty('ID_NUMBERING_ID_FIELD'))) { $vs_label .= " ({$vs_label})"; } } } $vs_message = _t("[Media attribute][MD5 mismatch] %1; value_id=%2; version %3 [%4]", $vs_label, $vn_value_id, $vs_version, $vs_path); switch ($ps_format) { case 'text': default: $vs_report_output .= "{$vs_message}\n"; break; case 'tab': case 'csv': $va_log = array(_t('Media attribute'), _t("MD5 mismatch"), caEscapeForDelimitedOutput($vs_label), $vn_value_id, $vs_version, $vs_path, $vs_database_md5, $vs_file_md5); $vs_report_output .= join($ps_format == 'tab' ? "\t" : ",", $va_log); break; } CLIUtils::addError($vs_message); $vn_errors++; } } } } } print CLIProgressBar::finish(); CLIUtils::addMessage(_t('%1 errors for %2 attributes', $vn_errors, $vn_rep_count)); } } // get all File elements $va_elements = ca_metadata_elements::getElementsAsList(false, null, null, true, false, true, array(15)); // 15=file if (is_array($va_elements) && sizeof($va_elements)) { if (is_array($va_element_ids = caExtractValuesFromArrayList($va_elements, 'element_id', array('preserveKeys' => false))) && sizeof($va_element_ids)) { $qr_c = $o_db->query("\n\t\t\t\t\t\tSELECT count(*) c\n\t\t\t\t\t\tFROM ca_attribute_values\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\telement_id in (?)\n\t\t\t\t\t", array($va_element_ids)); if ($qr_c->nextRow()) { $vn_count = $qr_c->get('c'); } else { $vn_count = 0; } print CLIProgressBar::start($vn_count, _t('Checking attribute files')); $vn_errors = 0; foreach ($va_elements as $vs_element_code => $va_element_info) { $qr_vals = $o_db->query("SELECT value_id FROM ca_attribute_values WHERE element_id = ?", (int) $va_element_info['element_id']); $va_vals = $qr_vals->getAllFieldValues('value_id'); foreach ($va_vals as $vn_value_id) { $t_attr_val = new ca_attribute_values($vn_value_id); if ($t_attr_val->getPrimaryKey()) { $t_attr_val->setMode(ACCESS_WRITE); $t_attr_val->useBlobAsFileField(true); print CLIProgressBar::next(1, _t("Checking attribute file %1", $vn_value_id)); $vs_path = $t_attr_val->getFilePath('value_blob'); $vs_database_md5 = $t_attr_val->getFileInfo('value_blob', 'MD5'); $vs_file_md5 = md5_file($vs_path); if ($vs_database_md5 !== $vs_file_md5) { $t_attr = new ca_attributes($vn_attribute_id = $t_attr_val->get('attribute_id')); $vs_label = "attribute_id={$vn_attribute_id}; value_id={$vn_value_id}"; if ($t_instance = $o_dm->getInstanceByTableNum($t_attr->get('table_num'), true)) { if ($t_instance->load($t_attr->get('row_id'))) { $vs_label = $t_instance->get($t_instance->tableName() . '.preferred_labels'); if ($vs_idno = $t_instance->get($t_instance->getProperty('ID_NUMBERING_ID_FIELD'))) { $vs_label .= " ({$vs_label})"; } } } $vs_message = _t("[File attribute][MD5 mismatch] %1; value_id=%2; version %3 [%4]", $vs_label, $vn_value_id, $vs_version, $vs_path); switch ($ps_format) { case 'text': default: $vs_report_output .= "{$vs_message}\n"; break; case 'tab': case 'csv': $va_log = array(_t('File attribute'), _t("MD5 mismatch"), caEscapeForDelimitedOutput($vs_label), $vn_value_id, $vs_version, $vs_path, $vs_database_md5, $vs_file_md5); $vs_report_output .= join($ps_format == 'tab' ? "\t" : ",", $va_log); break; } CLIUtils::addError($vs_message); $vn_errors++; } } } } print CLIProgressBar::finish(); CLIUtils::addMessage(_t('%1 errors for %2 attributes', $vn_errors, $vn_rep_count)); } } if ($ps_file_path) { file_put_contents($ps_file_path, $vs_report_output); } return true; }
/** * */ public function getRawAttributeValuesForIDs($pm_element_code_or_id, $pa_ids, $pa_options = null) { if (!($vn_element_id = $this->_getElementID($pm_element_code_or_id))) { return null; } return ca_attributes::getRawAttributeValuesForIDs($this->getDb(), $this->tableNum(), $pa_ids, $vn_element_id, $pa_options); }
$vn_c = 0; $qr_res->seek($vn_start); $va_ids = array(); while ($qr_res->nextHit() && $vn_c < $vn_hits_per_block) { $va_ids[] = $qr_res->get("{$vs_table}.{$vs_pk}"); $vn_c++; } $qr_res->seek($vn_start); $vn_c = 0; if ($vs_table != 'ca_objects') { $va_images = caGetDisplayImagesForAuthorityItems($vs_table, $va_ids, array('version' => 'small', 'relationshipTypes' => caGetOption('selectMediaUsingRelationshipTypes', $va_options, null), 'checkAccess' => $va_access_values)); } else { $va_images = null; } $va_element_ids = array_keys($t_instance->getApplicableElementCodes(null, false, false)); ca_attributes::prefetchAttributes($t_instance->getDb(), $t_instance->tableNum(), $va_ids, $va_element_ids); $vs_add_to_lightbox_msg = addslashes(_t('Add to lightbox')); $t_list_item = new ca_list_items(); $va_locality_cache = $va_taxonomy_cache = array(); while ($qr_res->nextHit() && $vn_c < $vn_hits_per_block) { $vn_id = $qr_res->get("{$vs_table}.{$vs_pk}"); $vs_idno = $qr_res->get('ca_objects.idno'); $vn_type_id = $qr_res->get('ca_objects.type_id'); $vs_image = $vs_table === 'ca_objects' ? $qr_res->getMediaTag("ca_object_representations.media", 'small', array("checkAccess" => $va_access_values)) : $va_images[$vn_id]; if (!$vs_image && !in_array($vn_type_id, $va_vertebrate_type_ids)) { $vs_image = $vs_placeholder_tag; } if ($vs_image) { $vs_rep_detail_link = caDetailLink($this->request, $vs_image, '', $vs_table, $vn_id, array("subsite" => $this->request->session->getVar("coloradoSubSite"))); } print "<div class='bResultListItemCol col-xs-12 col-sm-12 col-md-12'>";
/** * Fetch details on an item from a remote data source and output results of the 'display' key in the response. * */ public function GetDetail() { $pn_element_id = $this->request->getParameter('element_id', pInteger); $t_element = new ca_metadata_elements($pn_element_id); $va_data = array(); if (!$t_element->getPrimaryKey()) { // error $va_items['error'] = array('label' => _t('ERROR: Invalid element_id'), 'idno' => ''); } else { $vs_service = $t_element->getSetting('service'); $va_settings = $t_element->getSettings(); $pn_attribute_id = $this->request->getParameter('id', pInteger); $t_attr_val = new ca_attribute_values(); if ($t_attr_val->load(array('attribute_id' => $pn_attribute_id, 'element_id' => $pn_element_id))) { $t_attr = new ca_attributes(); if ($t_attr->load($pn_attribute_id)) { if (!caCanRead($this->request->getUserID(), $t_attr->get('table_num'), $t_attr->get('row_id'), $t_element->get('element_code'))) { $va_items['error'] = array('label' => _t('ERROR: You do not have access to this item'), 'idno' => ''); } else { $vs_url = $t_attr_val->get('value_longtext2'); if (!($o_plugin = InformationServiceManager::getInformationServiceInstance($vs_service))) { $va_items['error'] = array('label' => _t('ERROR: Invalid service'), 'idno' => ''); } else { $vs_cache_key = md5(print_r($va_settings, true) . $vs_url); if (CompositeCache::contains($vs_cache_key, 'InformationServiceExtendedInfo')) { $va_data = CompositeCache::fetch($vs_cache_key, 'InformationServiceExtendedInfo'); } else { $va_data = $o_plugin->getExtendedInformation($va_settings, $vs_url); CompositeCache::save($vs_cache_key, $va_data, 'InformationServiceExtendedInfo'); } } } } } } $this->view->setVar('detail', $va_data); return $this->render('ajax_information_service_detail_html.php'); }
/** * Initiates user download of media stored in a media attribute, returning file in response to request. * Adds download output to response directly. No view is used. * * @param array $pa_options Array of options passed through to _initView */ public function DownloadAttributeMedia($pa_options = null) { if (!($pn_value_id = $this->request->getParameter('value_id', pInteger))) { return; } $t_attr_val = new ca_attribute_values($pn_value_id); if (!$t_attr_val->getPrimaryKey()) { return; } $t_attr = new ca_attributes($t_attr_val->get('attribute_id')); $vn_table_num = $this->opo_datamodel->getTableNum($this->ops_table_name); if ($t_attr->get('table_num') != $vn_table_num) { $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath())); return; } $t_element = new ca_metadata_elements($t_attr->get('element_id')); $this->request->setParameter($this->opo_datamodel->getTablePrimaryKeyName($vn_table_num), $t_attr->get('row_id')); list($vn_subject_id, $t_subject) = $this->_initView($pa_options); $ps_version = $this->request->getParameter('version', pString); if (!$this->_checkAccess($t_subject)) { return false; } // // Does user have access to bundle? // if ($this->request->user->getBundleAccessLevel($this->ops_table_name, $t_element->get('element_code')) < __CA_BUNDLE_ACCESS_READONLY__) { $this->response->setRedirect($this->request->config->get('error_display_url') . '/n/2580?r=' . urlencode($this->request->getFullUrlPath())); return; } $t_attr_val->useBlobAsMediaField(true); if (!in_array($ps_version, $t_attr_val->getMediaVersions('value_blob'))) { $ps_version = 'original'; } $o_view = new View($this->request, $this->request->getViewsDirectoryPath() . '/bundles/'); // get value $t_element = new ca_metadata_elements($t_attr_val->get('element_id')); // check that value is a media attribute if ($t_element->get('datatype') != 16) { // 16=media return; } $vs_path = $t_attr_val->getMediaPath('value_blob', $ps_version); $vs_path_ext = pathinfo($vs_path, PATHINFO_EXTENSION); if ($vs_name = trim($t_attr_val->get('value_longtext2'))) { $vs_file_name = pathinfo($vs_name, PATHINFO_FILENAME); $vs_name = "{$vs_file_name}.{$vs_path_ext}"; } else { $vs_name = _t("downloaded_file.%1", $vs_path_ext); } $o_view->setVar('file_path', $vs_path); $o_view->setVar('file_name', $vs_name); // send download $this->response->addContent($o_view->render('ca_attributes_download_media.php')); }
/** * Implementation of primary get() functionality */ private function _get($ps_field, $pa_options = null) { if (!is_array($pa_options)) { $pa_options = array(); } if (isset($pa_options['restrictToType']) && (!isset($pa_options['restrict_to_type']) || !$pa_options['restrict_to_type'])) { $pa_options['restrict_to_type'] = $pa_options['restrictToType']; } if (isset($pa_options['restrictToTypes']) && (!isset($pa_options['restrict_to_types']) || !$pa_options['restrict_to_types'])) { $pa_options['restrict_to_types'] = $pa_options['restrictToTypes']; } if (isset($pa_options['restrictToRelationshipTypes']) && (!isset($pa_options['restrict_to_relationship_types']) || !$pa_options['restrict_to_relationship_types'])) { $pa_options['restrict_to_relationship_types'] = $pa_options['restrictToRelationshipTypes']; } if (isset($pa_options['excludeType']) && (!isset($pa_options['exclude_type']) || !$pa_options['exclude_type'])) { $pa_options['exclude_type'] = $pa_options['excludeType']; } if (isset($pa_options['excludeTypes']) && (!isset($pa_options['exclude_types']) || !$pa_options['exclude_types'])) { $pa_options['exclude_types'] = $pa_options['excludeTypes']; } if (isset($pa_options['excludeRelationshipTypes']) && (!isset($pa_options['exclude_relationship_types']) || !$pa_options['exclude_relationship_types'])) { $pa_options['exclude_relationship_types'] = $pa_options['excludeRelationshipTypes']; } $vb_return_as_array = caGetOption('returnAsArray', $pa_options, false, array('castTo' => 'bool')); $vb_return_all_locales = caGetOption('returnAllLocales', $pa_options, false, array('castTo' => 'bool')); $vb_return_as_link = caGetOption('returnAsLink', $pa_options, false, array('castTo' => 'bool')); $vs_return_as_link_text = caGetOption('returnAsLinkText', $pa_options, ''); $vs_return_as_link_target = caGetOption('returnAsLinkTarget', $pa_options, ''); $vs_return_as_link_attributes = caGetOption('returnAsLinkAttributes', $pa_options, array(), array('castTo' => 'array')); $va_original_path_components = $va_path_components = $this->getFieldPathComponents($ps_field); if ($va_path_components['table_name'] != $this->ops_table_name) { $vs_access_chk_key = $va_path_components['table_name'] . ($va_path_components['field_name'] ? '.' . $va_path_components['field_name'] : ''); } else { $vs_access_chk_key = $va_path_components['field_name']; } if (caGetBundleAccessLevel($this->ops_table_name, $vs_access_chk_key) == __CA_BUNDLE_ACCESS_NONE__) { return null; } $vo_request = caGetOption('request', $pa_options, null); unset($pa_options['request']); // first see if the search engine can provide the field value directly (fastest) if (!(($vs_value = $this->opo_engine_result->get($ps_field, $pa_options)) === false)) { if ($vb_return_as_array) { if ($vb_return_all_locales) { return array(1 => $vs_value); } else { return array($vs_value); } } else { return $vs_value; } } $vs_template = caGetOption('template', $pa_options, null); $vs_delimiter = caGetOption('delimiter', $pa_options, ' '); $vs_hierarchical_delimiter = caGetOption('hierarchicalDelimiter', $pa_options, ' '); if ($vb_return_all_locales && !$vb_return_as_array) { $vb_return_as_array = true; } if (isset($pa_options['sort']) && !is_array($pa_options['sort'])) { $pa_options['sort'] = array($pa_options['sort']); } if (is_array($va_sort_fields = isset($pa_options['sort']) && is_array($pa_options['sort']) ? $pa_options['sort'] : null)) { foreach ($va_sort_fields as $vn_i => $vs_sort_fld) { if (!trim($vs_sort_fld)) { unset($va_sort_fields[$vn_i]); } } } $vn_row_id = $this->opo_engine_result->get($this->ops_table_pk); // try to lazy load (slower)... // // Are we getting timestamp (created on or last modified) info? // if ($va_path_components['table_name'] == $this->ops_table_name && $va_path_components['field_name'] == 'created') { if (!isset($this->opa_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id])) { $this->prefetchChangeLogData($this->ops_table_name, $this->opo_engine_result->currentRow(), $this->getOption('prefetch')); } if ($vb_return_as_array) { return $this->opa_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id]; } else { $vs_subfield = $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : 'timestamp'; $vm_val = $this->opa_timestamp_cache['created_on'][$this->ops_table_name][$vn_row_id][$vs_subfield]; if ($vs_subfield == 'timestamp') { $o_tep = new TimeExpressionParser(); $o_tep->setUnixTimestamps($vm_val, $vm_val); $vm_val = $o_tep->getText($pa_options); } return $vm_val; } } if ($va_path_components['table_name'] == $this->ops_table_name && $va_path_components['field_name'] == 'lastModified') { if (!isset($this->opa_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id])) { $this->prefetchChangeLogData($this->ops_table_name, $this->opo_engine_result->currentRow(), $this->getOption('prefetch')); } if ($vb_return_as_array) { return $this->opa_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id]; } else { $vs_subfield = $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : 'timestamp'; $vm_val = $this->opa_timestamp_cache['last_changed'][$this->ops_table_name][$vn_row_id][$vs_subfield]; if ($vs_subfield == 'timestamp') { $o_tep = new TimeExpressionParser(); $o_tep->setUnixTimestamps($vm_val, $vm_val); $vm_val = $o_tep->getText($pa_options); } return $vm_val; } } if (!($t_instance = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true))) { return null; } // Bad table $t_original_instance = $t_instance; // $t_original_instance will always be the as-called subject; optimizations may results in $t_instance being transformed into a different model // // Simple related table get: // <table> // <table>.related // <table>.hierarchy // <table>.related.hierarchy // if ($va_path_components['num_components'] == 1 && $va_path_components['table_name'] !== $this->ops_table_name || $va_path_components['num_components'] == 2 && $va_path_components['field_name'] == 'related' || $va_path_components['num_components'] == 2 && $va_path_components['field_name'] == 'hierarchy' || $va_path_components['num_components'] == 3 && $va_path_components['field_name'] == 'related' && $va_path_components['subfield_name'] == 'hierarchy') { if (!($t_table = $this->opo_datamodel->getInstanceByTableName($this->ops_table_name, true))) { return null; } $vb_show_hierarachy = (bool) ($va_path_components['field_name'] == 'hierarchy' && $t_instance->isHierarchical()); if ($va_path_components['num_components'] == 2) { $va_path_components['num_components'] = 1; $va_path_components['field_name'] = null; } $vs_opt_md5 = caMakeCacheKeyFromOptions($pa_options); if (!isset($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) { $this->prefetchRelated($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_related_items = $this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5]; if (!is_array($va_related_items)) { return null; } if (is_array($va_sort_fields) && sizeof($va_sort_fields)) { $va_related_items = caSortArrayByKeyInValue($va_related_items, $va_sort_fields); } // Return as array if ($vs_template) { return caProcessTemplateForIDs($vs_template, $this->opo_subject_instance->tableName(), array($vn_row_id), array_merge($pa_options, array('placeholderPrefix' => $va_path_components['field_name']))); } if ($vb_return_as_array || $vb_return_all_locales) { if ($vb_return_all_locales) { $va_related_tmp = array(); foreach ($va_related_items as $vn_i => $va_related_item) { $va_related_tmp[$vn_i][$va_related_item['locale_id']] = $va_related_item; } return $va_related_tmp; } else { if (!$vs_template && !$va_path_components['field_name']) { return $va_related_items; } $vs_pk = $t_instance->primaryKey(); $va_links = array(); foreach ($va_related_items as $vn_relation_id => $va_relation_info) { $va_relation_info['labels'] = caExtractValuesByUserLocale(array(0 => $va_relation_info['labels'])); if ($vb_return_as_link) { $va_template_opts = array(); $va_template_opts['relationshipValues'][$va_relation_info[$vs_pk]][$va_relation_info['relation_id']]['relationship_typename'] = $va_relation_info['relationship_typename']; $vs_text = $vs_template ? caProcessTemplateForIDs($vs_template, $t_instance->tableName(), array($va_relation_info[$vs_pk]), $va_template_opts) : join("; ", $va_relation_info['labels']); $va_link = caCreateLinksFromText(array($vs_text), $va_original_path_components['table_name'], array($va_relation_info[$vs_pk]), $vs_return_as_link_class, $vs_return_as_link_target); $va_links[$vn_relation_id] = array_pop($va_link); } else { $va_related_items[$vn_relation_id]['labels'] = $va_relation_info['labels']; } } if ($vb_return_as_link) { return $va_links; } return $va_related_items; } } else { // Return scalar $va_proc_labels = array(); $va_row_ids = array(); $vs_rel_pk = $t_instance->primaryKey(); $va_relationship_values = array(); foreach ($va_related_items as $vn_relation_id => $va_relation_info) { $va_row_ids[] = $va_relation_info[$vs_rel_pk]; $va_relationship_values[$va_relation_info[$vs_rel_pk]][$vn_relation_id] = array('relationship_typename' => $va_relation_info['relationship_typename'], 'relationship_type_id' => $va_relation_info['relationship_type_id'], 'relationship_type_code' => $va_relation_info['relationship_type_code'], 'relationship_typecode' => $va_relation_info['relationship_type_code'], 'label' => $va_relation_info['label']); } if (!sizeof($va_row_ids)) { return ''; } if (!$vs_template) { $vs_template = "^label"; } $va_template_opts = $pa_options; unset($va_template_opts['request']); unset($va_template_opts['template']); $va_template_opts['returnAsLink'] = false; $va_template_opts['returnAsArray'] = true; $va_text = caProcessTemplateForIDs($vs_template, $t_instance->tableNum(), $va_row_ids, array_merge($va_template_opts, array('relationshipValues' => $va_relationship_values, 'showHierarchicalLabels' => $vb_show_hierarachy))); if ($vb_return_as_link) { $va_links = caCreateLinksFromText($va_text, $va_original_path_components['table_name'], $va_row_ids, $vs_return_as_link_class, $vs_return_as_link_target); return join($vs_delimiter, $va_links); } return join($vs_delimiter, $va_text); } } $vb_need_parent = false; $vb_need_children = false; // // Transform "preferred_labels" into tables for pre-fetching // $vb_is_get_for_labels = $vb_return_all_label_values = $vb_get_preferred_labels_only = $vb_get_nonpreferred_labels_only = false; if (in_array($va_path_components['field_name'], array('preferred_labels', 'nonpreferred_labels'))) { if ($t_instance->getProperty('LABEL_TABLE_NAME')) { $vb_get_preferred_labels_only = $va_path_components['field_name'] == 'preferred_labels' ? true : false; $vb_get_nonpreferred_labels_only = $va_path_components['field_name'] == 'nonpreferred_labels' ? true : false; if ($va_path_components['num_components'] == 2) { // if it's just <table_name>.preferred_labels then return an array of fields from the label table $vb_return_all_label_values = true; } $va_path_components['table_name'] = $t_instance->getLabelTableName(); $t_label_instance = $t_instance->getLabelTableInstance(); if (!$va_path_components['subfield_name'] || !$t_label_instance->hasField($va_path_components['subfield_name'])) { $va_path_components['field_name'] = $t_instance->getLabelDisplayField(); } else { $va_path_components['field_name'] = $va_path_components['subfield_name']; } $va_path_components['subfield_name'] = null; $va_path_components = $this->getFieldPathComponents($va_path_components['table_name'] . '.' . $va_path_components['field_name']); // Ok, convert the table instance to the label table since that's the table we'll be grabbing data from $t_instance = $t_label_instance; $vb_is_get_for_labels = true; } } // // Handle modifiers (parent, children, related, hierarchy) with and without fields // if ($va_path_components['num_components'] >= 2) { switch ($va_path_components['field_name']) { case 'parent': if ($t_instance->isHierarchical() && ($vn_parent_id = $this->get($va_path_components['table_name'] . '.' . $t_instance->getProperty('HIERARCHY_PARENT_ID_FLD')))) { // // TODO: support some kind of prefetching of parents? // unset($va_path_components['components'][1]); if ($t_instance->load($vn_parent_id)) { return $t_instance->get(join('.', array_values($va_path_components['components'])), $pa_options); } return null; } break; case 'children': if ($t_instance->isHierarchical()) { //unset($va_path_components['components'][1]); // remove 'children' from field path $vs_field_spec = join('.', array_values($va_path_components['components'])); if ($vn_id = $this->get($va_path_components['table_name'] . '.' . $t_instance->primaryKey(), array('returnAsArray' => false))) { if ($t_instance->load($vn_id)) { return $t_instance->get($vs_field_spec, $pa_options); } } return null; } break; case 'related': // Regular related table call if ($va_path_components['table_name'] != $this->ops_table_name) { // just remove "related" from name and be on our way $va_tmp = $va_path_components['components']; array_splice($va_tmp, 1, 1); return $this->get(join('.', $va_tmp), $pa_options); } // Self-relations need special handling $vs_opt_md5 = caMakeCacheKeyFromOptions($pa_options); if (!isset($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) { $this->prefetchRelated($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } $va_related_items = $this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5]; if (!($t_table = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true))) { return null; } $va_ids = array(); foreach ($va_related_items as $vn_relation_id => $va_item) { $va_ids[] = $va_item[$t_table->primaryKey()]; } $va_vals = array(); if ($qr_res = $t_table->makeSearchResult($va_path_components['table_name'], $va_ids)) { $va_tmp = $va_path_components['components']; unset($va_tmp[1]); $vs_rel_field = join('.', $va_tmp); while ($qr_res->nextHit()) { if ($vb_return_as_array) { $va_vals = array_merge($va_vals, $qr_res->get($vs_rel_field, $pa_options)); } else { $va_vals[] = $qr_res->get($vs_rel_field, $pa_options); } } } //if (is_array($va_sort_fields) && sizeof($va_sort_fields)) { // $va_vals = caSortArrayByKeyInValue($va_vals, $va_sort_fields); //} if ($vb_return_as_link) { if (!$vb_return_all_locales) { $va_vals = caCreateLinksFromText($va_vals, $va_original_path_components['table_name'], $va_ids, $vs_return_as_link_class, $vs_return_as_link_target); } } if ($vb_return_as_array) { return $va_vals; } else { return join($vs_delimiter, $va_vals); } break; case 'hierarchy': $vn_max_levels_from_bottom = caGetOption('maxLevelsFromBottom', $pa_options, caGetOption('maxLevels', $pa_options, null)); $vn_max_levels_from_top = caGetOption('maxLevelsFromTop', $pa_options, null); if ($t_instance->isHierarchical()) { $vs_field_spec = join('.', array_values($va_path_components['components'])); $vs_hier_pk_fld = $t_instance->primaryKey(); if ($va_ids = $this->get($va_path_components['table_name'] . '.' . $vs_hier_pk_fld, array_merge($pa_options, array('returnAsArray' => true, 'returnAsLink' => false, 'returnAllLocales' => false)))) { $va_vals = array(); if ($va_path_components['subfield_name'] == $vs_hier_pk_fld) { foreach ($va_ids as $vn_id) { // TODO: This is too slow if ($t_instance->load($vn_id)) { $va_vals = array_merge($va_vals, $t_instance->get($va_path_components['table_name'] . ".hierarchy." . $vs_hier_pk_fld, array_merge($pa_options, array('returnAsArray' => true)))); } } } else { foreach ($va_ids as $vn_id) { // TODO: This is too slow if ($t_instance->load($vn_id)) { $va_vals = $t_instance->get($vs_field_spec, array_merge($pa_options, array('returnAsArray' => true))); if (is_array($va_vals)) { $va_vals = array_reverse($va_vals); } // Add/replace hierarchy name if ($t_instance->getProperty('HIERARCHY_TYPE') == __CA_HIER_TYPE_MULTI_MONO__ && $t_instance->getHierarchyName()) { $vn_first_key = array_shift(array_keys($va_vals)); if ($vb_return_all_locales) { $va_vals[$vn_first_key] = array(0 => array($t_instance->getHierarchyName())); } else { $va_vals[$vn_first_key] = $t_instance->getHierarchyName(); } } if ($vn_max_levels_from_bottom > 0) { if (($vn_start = sizeof($va_vals) - $vn_max_levels_from_bottom) < 0) { $vn_start = 0; } $va_vals = array_slice($va_vals, $vn_start, $vn_max_levels_from_bottom, true); } elseif ($vn_max_levels_from_top > 0) { $va_vals = array_slice($va_vals, 0, $vn_max_levels_from_top, true); } } } } if ($vb_return_as_array) { return $va_vals; } else { return join($vs_hierarchical_delimiter, $va_vals); } } return null; } break; } } // If the requested table was not added to the query via SearchEngine::addTable() // then auto-add it here. It's better to explicitly add it with addTables() as that call // gives you precise control over which fields are autoloaded and also lets you specify limiting criteria // for selection of related field data; and it also lets you explicitly define the tables used to join the // related table. Autoloading guesses and usually does what you want, but not always. if (!isset($this->opa_tables[$va_path_components['table_name']]) || !$this->opa_tables[$va_path_components['table_name']]) { $va_join_tables = $this->opo_datamodel->getPath($this->ops_table_name, $va_path_components['table_name']); array_shift($va_join_tables); // remove subject table array_pop($va_join_tables); // remove content table (we only need linking tables here) $va_join_criteria = array(); if (is_array($va_primary_ids)) { foreach ($va_primary_ids as $vs_t => $va_t_ids) { if (isset($va_join_tables[$vs_t]) && sizeof($va_t_ids) > 0) { $vs_t_pk = $this->opo_datamodel->getTablePrimaryKeyName($vs_t); $va_join_criteria[] = "{$vs_t}.{$vs_t_pk} NOT IN (" . join(",", $va_t_ids) . ")"; } } } $this->opa_tables[$va_path_components['table_name']] = array('fieldList' => array($va_path_components['table_name'] . '.*'), 'joinTables' => array_keys($va_join_tables), 'criteria' => $va_join_criteria); } if ($va_path_components['table_name'] === $this->ops_table_name && !$t_instance->hasField($va_path_components['field_name']) && method_exists($t_instance, 'getAttributes')) { // // Return attribute values for primary table // if ($va_path_components['field_name'] && ($t_element = $t_instance->_getElementInstance($va_path_components['field_name']))) { $vn_element_id = $t_element->getPrimaryKey(); } else { $vn_element_id = null; } if (!isset(ca_attributes::$s_get_attributes_cache[$this->opn_table_num . '/' . $vn_row_id][$vn_element_id])) { ca_attributes::prefetchAttributes($this->opo_db, $this->opn_table_num, $this->getRowIDsToPrefetch($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch')), $vn_element_id ? array($vn_element_id) : null, array('dontFetchAlreadyCachedValues' => true)); } if (!$vb_return_as_array && !$vb_return_all_locales) { // return scalar // // Handle "hierarchy" modifier on list elements // if ($va_hier = $this->_getElementHierarchy($t_instance, $va_path_components)) { return join($vs_hierarchical_delimiter, $va_hier); } if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && $va_path_components['field_name']) { $vs_template = null; if ($va_path_components['subfield_name']) { $va_values = $t_instance->getAttributeDisplayValues($va_path_components['field_name'], $vn_row_id, $pa_options); $va_value_list = array(); foreach ($va_values as $vn_id => $va_attr_val_list) { foreach ($va_attr_val_list as $vn_value_id => $va_value_array) { $va_value_list[] = $va_value_array[$va_path_components['subfield_name']]; } } return join(" ", $va_value_list); } else { if (isset($pa_options['template'])) { $vs_template = $pa_options['template']; } } unset($pa_options['template']); if (!$vs_template) { $vs_template = "^" . $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : $va_path_components['field_name']; } return $t_instance->getAttributesForDisplay($va_path_components['field_name'], $vs_template, array_merge(array('row_id' => $vn_row_id), $pa_options)); } if ($t_element && !$va_path_components['subfield_name'] && $t_element->get('datatype') == 0) { return $t_instance->getAttributesForDisplay($va_path_components['field_name'], $vs_template, array_merge($pa_options, array('row_id' => $vn_row_id))); } else { if (!$vs_template) { return $t_instance->getRawValue($vn_row_id, $va_path_components['field_name'], $va_path_components['subfield_name'], ',', $pa_options); } else { return caProcessTemplateForIDs($vs_template, $va_path_components['table_name'], array($vn_row_id), array()); } } } else { // return array // // Handle "hierarchy" modifier on list elements // if ($va_hier = $this->_getElementHierarchy($t_instance, $va_path_components)) { return $va_hier; } $va_values = $t_instance->getAttributeDisplayValues($va_path_components['field_name'], $vn_row_id, $pa_options); if ($vs_template && !$vb_return_all_locales) { $va_values_tmp = array(); foreach ($va_values as $vn_i => $va_value_list) { foreach ($va_value_list as $vn_attr_id => $va_attr_data) { $va_values_tmp[] = caProcessTemplateForIDs($vs_template, $va_path_components['table_name'], array($vn_row_id), array_merge($pa_options, array('placeholderPrefix' => $va_path_components['field_name']))); } } $va_values = $va_values_tmp; } else { if ($va_path_components['subfield_name']) { if ($vb_return_all_locales) { foreach ($va_values as $vn_row_id => $va_values_by_locale) { foreach ($va_values_by_locale as $vn_locale_id => $va_value_list) { foreach ($va_value_list as $vn_attr_id => $va_attr_data) { $va_values[$vn_row_id][$vn_locale_id][$vn_attr_id] = $va_attr_data[$va_path_components['subfield_name']]; } } } } else { $va_processed_value_list = array(); foreach ($va_values as $vn_row_id => $va_value_list) { foreach ($va_value_list as $vn_attr_id => $va_attr_data) { $va_processed_value_list[$vn_attr_id] = $va_attr_data[$va_path_components['subfield_name']]; } } $va_values = $va_processed_value_list; } } else { if (!$vb_return_all_locales) { $va_values = array_shift($va_values); } } } return $va_values; } } else { // Prefetch intrinsic fields in primary and related tables if (!isset($this->opa_prefetch_cache[$va_path_components['table_name']][$vn_row_id])) { $this->prefetch($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); // try to prefetch ahead (usually doesn't hurt and very often helps performance) } } $va_return_values = array(); if ($va_path_components['table_name'] !== $this->ops_table_name && $va_path_components['field_name'] !== 'relationship_typename' && !$t_instance->hasField($va_path_components['field_name']) && method_exists($t_instance, 'getAttributes')) { // // Return metadata attributes in a related table // $vs_pk = $t_instance->primaryKey(); $vb_is_related = $this->ops_table_name !== $va_path_components['table_name']; $va_ids = array(); $vs_opt_md5 = caMakeCacheKeyFromOptions($pa_options); if (!isset($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) { $this->prefetchRelated($va_path_components['table_name'], $this->opo_engine_result->currentRow(), $this->getOption('prefetch'), $pa_options); } if (is_array($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5])) { foreach ($this->opa_rel_prefetch_cache[$va_path_components['table_name']][$vn_row_id][$vs_opt_md5] as $vn_i => $va_values) { //$vn_locale_id => $va_values_by_locale) { $va_ids[] = $va_values[$vs_pk]; if (!$vb_return_as_array) { $vs_val = $t_instance->getAttributesForDisplay($va_path_components['field_name'], $vs_template, array_merge(array('row_id' => $va_values[$vs_pk]), $pa_options)); } else { $vs_val = $t_instance->getAttributeDisplayValues($va_path_components['field_name'], $va_values[$vs_pk], $pa_options); } if ($vs_val) { if ($vb_return_as_array) { if (!$vb_return_all_locales) { foreach ($vs_val as $vn_i => $va_values_list) { foreach ($va_values_list as $vn_j => $va_values) { $va_return_values[] = $va_values; } } } else { foreach ($vs_val as $vn_i => $va_values_list) { $va_return_values[] = $va_values_list; } } } else { $va_return_values[] = $vs_val; } } } } if ($vb_return_as_array || $vb_return_all_locales) { // return array if ($vb_return_as_link && $vb_is_related) { $vs_table_name = $t_instance->tableName(); $vs_fld_key = $va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : $va_path_components['field_name']; if (!$vb_return_all_locales) { $va_return_values_tmp = array(); foreach ($va_return_values as $vn_i => $va_value) { if ($vs_template) { $vs_value = caProcessTemplateForIDs($vs_template, $va_path_components['table_name'], array($va_ids[$vn_i][$vs_pk]), array('returnAsArray' => false)); } else { $vs_value = $va_value[$vs_fld_key]; } if ($vb_return_as_link) { $va_return_values_tmp[$vn_i] = array_pop(caCreateLinksFromText(array($vs_value), $va_original_path_components['table_name'], array($va_ids[$vn_i]), $vs_return_as_link_class, $vs_return_as_link_target)); } else { $va_return_values_tmp[$vn_i] = $vs_value; } } $va_return_values = $va_return_values_tmp; } } return $va_return_values; } else { // return scalar if ($vb_return_as_link && $vb_is_related) { $va_return_values = caCreateLinksFromText($va_return_values, $va_original_path_components['table_name'], $va_ids, $vs_return_as_link_class, $vs_return_as_link_target); } if (isset($pa_options['convertLineBreaks']) && $pa_options['convertLineBreaks']) { return caConvertLineBreaks(join($vs_delimiter, $va_return_values)); } else { return join($vs_delimiter, $va_return_values); } } } else { if ($vs_template) { return caProcessTemplateForIDs($vs_template, $this->opo_subject_instance->tableName(), array($vn_row_id), array_merge($pa_options, array('placeholderPrefix' => $va_path_components['field_name']))); } // // Return fields (intrinsics, labels) in primary or related table // $t_list = $this->opo_datamodel->getInstanceByTableName('ca_lists', true); $va_value_list = array($vn_row_id => $this->opa_prefetch_cache[$va_path_components['table_name']][$vn_row_id]); // Restrict to relationship types (related) if (isset($pa_options['restrict_to_relationship_types']) && $pa_options['restrict_to_relationship_types']) { if (!is_array($pa_options['restrict_to_relationship_types'])) { $pa_options['restrict_to_relationship_types'] = array($pa_options['restrict_to_relationship_types']); } if (sizeof($pa_options['restrict_to_relationship_types'])) { $t_rel_type = $this->opo_datamodel->getInstanceByTableName('ca_relationship_types', true); $va_rel_types = array(); $va_rel_path = array_keys($this->opo_datamodel->getPath($this->ops_table_name, $va_path_components['table_name'])); foreach ($pa_options['restrict_to_relationship_types'] as $vm_type) { if (!$vm_type) { continue; } if ($vn_type_id = $t_rel_type->getRelationshipTypeID($va_rel_path[1], $vm_type)) { $va_rel_types[] = $vn_type_id; if (is_array($va_children = $t_rel_type->getHierarchyChildren($vn_type_id, array('idsOnly' => true)))) { $va_rel_types = array_merge($va_rel_types, $va_children); } } } if (sizeof($va_rel_types)) { $va_tmp = array(); foreach ($va_value_list as $vn_id => $va_by_locale) { foreach ($va_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { if (!$va_value['rel_type_id'] || in_array($va_value['rel_type_id'], $va_rel_types)) { $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value; } } } } $va_value_list = $va_tmp; } } } // Exclude relationship types (related) if (isset($pa_options['exclude_relationship_types']) && $pa_options['exclude_relationship_types']) { if (!is_array($pa_options['exclude_relationship_types'])) { $pa_options['exclude_relationship_types'] = array($pa_options['exclude_relationship_types']); } if (sizeof($pa_options['exclude_relationship_types'])) { $t_rel_type = $this->opo_datamodel->getInstanceByTableName('ca_relationship_types', true); $va_rel_types = array(); $va_rel_path = array_keys($this->opo_datamodel->getPath($this->ops_table_name, $va_path_components['table_name'])); foreach ($pa_options['exclude_relationship_types'] as $vm_type) { if ($vn_type_id = $t_rel_type->getRelationshipTypeID($va_rel_path[1], $vm_type)) { $va_rel_types[] = $vn_type_id; if (is_array($va_children = $t_rel_type->getHierarchyChildren($vn_type_id, array('idsOnly' => true)))) { $va_rel_types = array_merge($va_rel_types, $va_children); } } } if (sizeof($va_rel_types)) { $va_tmp = array(); foreach ($va_value_list as $vn_id => $va_by_locale) { foreach ($va_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { if (!in_array($va_value['rel_type_id'], $va_rel_types)) { $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value; } } } } $va_value_list = $va_tmp; } } } // Restrict to types (related) $va_type_ids = $vs_type_fld = null; if (method_exists($t_instance, "getTypeFieldName")) { $va_type_ids = caMergeTypeRestrictionLists($t_instance, $pa_options); $vs_type_fld = $t_instance->getTypeFieldName(); } else { if (method_exists($t_instance, "getSubjectTableInstance")) { $t_label_subj_instance = $t_instance->getSubjectTableInstance(); if (method_exists($t_label_subj_instance, "getTypeFieldName")) { $va_type_ids = caMergeTypeRestrictionLists($t_label_subj_instance, $pa_options); $vs_type_fld = 'item_type_id'; } } } if (is_array($va_type_ids) && sizeof($va_type_ids)) { $va_tmp = array(); foreach ($va_value_list as $vn_id => $va_by_locale) { foreach ($va_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { if (!$va_value[$vs_type_fld ? $vs_type_fld : 'item_type_id'] || in_array($va_value[$vs_type_fld ? $vs_type_fld : 'item_type_id'], $va_type_ids)) { $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value; } } } } $va_value_list = $va_tmp; } // Restrict to sources (related) $va_source_ids = $vs_source_id_fld = null; if (method_exists($t_instance, "getSourceFieldName")) { $va_source_ids = caMergeSourceRestrictionLists($t_instance, $pa_options); $vs_source_id_fld = $t_instance->getSourceFieldName(); } else { if (method_exists($t_instance, "getSubjectTableInstance")) { $t_label_subj_instance = $t_instance->getSubjectTableInstance(); if (method_exists($t_label_subj_instance, "getSourceFieldName")) { $va_source_ids = caMergeSourceRestrictionLists($t_label_subj_instance, $pa_options); $vs_source_id_fld = 'item_source_id'; } } } if (is_array($va_source_ids) && sizeof($va_source_ids)) { $va_tmp = array(); foreach ($va_value_list as $vn_id => $va_by_locale) { foreach ($va_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { if (!$va_value[$vs_source_id_fld ? $vs_source_id_fld : 'item_source_id'] || in_array($va_value[$vs_source_id_fld ? $vs_source_id_fld : 'item_source_id'], $va_source_ids)) { $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value; } } } } $va_value_list = $va_tmp; } // Exclude types (related) if (isset($pa_options['exclude_type']) && $pa_options['exclude_type']) { if (!isset($pa_options['exclude_types']) || !is_array($pa_options['exclude_types'])) { $pa_options['exclude_types'] = array(); } $pa_options['exclude_types'][] = $pa_options['exclude_type']; } if (isset($pa_options['exclude_types']) && is_array($pa_options['exclude_types'])) { $va_ids = caMakeTypeIDList($va_path_components['table_name'], $pa_options['exclude_types']); if (is_array($va_ids) && sizeof($va_ids) > 0) { $va_tmp = array(); foreach ($va_value_list as $vn_id => $va_by_locale) { foreach ($va_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { if (!in_array($va_value[$vs_type_fld ? $vs_type_fld : 'item_type_id'], $va_type_ids)) { $va_tmp[$vn_id][$vn_locale_id][$vn_i] = $va_value; } } } } $va_value_list = $va_tmp; } } // Handle 'relationship_typename' (related) $vb_get_relationship_typename = false; if ($va_path_components['field_name'] == 'relationship_typename') { $va_path_components['field_name'] = 'rel_type_id'; $vb_get_relationship_typename = true; } if ($vb_return_as_array) { // return array (intrinsics or labels in primary or related table) if ($t_instance->hasField($va_path_components['field_name']) && $va_path_components['table_name'] === $t_instance->tableName()) { // Intrinsic $va_field_info = $t_instance->getFieldInfo($va_path_components['field_name']); $vs_pk = $t_original_instance->primaryKey(); // Handle specific intrinsic types switch ($va_field_info['FIELD_TYPE']) { case FT_DATERANGE: case FT_HISTORIC_DATERANGE: foreach ($va_value_list as $vn_id => $va_values_by_locale) { foreach ($va_values_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { $va_ids[] = $va_value[$vs_pk]; if (caGetOption('GET_DIRECT_DATE', $pa_options, false) || caGetOption('getDirectDate', $pa_options, false)) { if (caGetOption('sortable', $pa_options, false)) { $vs_prop = $va_value[$va_field_info['START']] . '/' . $va_value[$va_field_info['END']]; } else { $vs_prop = $va_value[$va_field_info['START']]; } } else { $this->opo_tep->init(); if ($va_field_info['FIELD_TYPE'] == FT_DATERANGE) { $this->opo_tep->setUnixTimestamps($va_value[$va_field_info['START']], $va_value[$va_field_info['END']]); } else { $this->opo_tep->setHistoricTimestamps($va_value[$va_field_info['START']], $va_value[$va_field_info['END']]); } $vs_prop = $this->opo_tep->getText($pa_options); } if ($vb_return_all_locales) { $va_return_values[$vn_row_id][$vn_locale_id][] = $vs_prop; } else { $va_return_values[] = $vs_prop; } } } } break; case FT_MEDIA: if (!($vs_version = $va_path_components['subfield_name'])) { $vs_version = "largeicon"; } foreach ($va_value_list as $vn_id => $va_values_by_locale) { foreach ($va_values_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { $va_ids[] = $va_value[$vs_pk]; if (isset($pa_options['unserialize']) && $pa_options['unserialize']) { $vs_prop = caUnserializeForDatabase($va_value[$va_path_components['field_name']]); if ($vb_return_all_locales) { $va_return_values[$vn_row_id][$vn_locale_id][] = $vs_prop; } else { $va_return_values[] = $vs_prop; } } else { $o_media_settings = new MediaProcessingSettings($va_path_components['table_name'], $va_path_components['field_name']); $va_versions = $o_media_settings->getMediaTypeVersions('*'); if (!isset($va_versions[$vs_version])) { $va_tmp = array_keys($va_versions); $vs_version = array_shift($va_tmp); } // See if an info element was passed, eg. ca_object_representations.media.icon.width should return the width of the media rather than a tag or url to the media $vs_info_element = $va_path_components['num_components'] == 4 ? $va_path_components['components'][3] : null; if ($vb_return_all_locales) { if ($vs_info_element) { $va_return_values[$vn_row_id][$vn_locale_id][] = $this->getMediaInfo($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $vs_info_element, $pa_options); } elseif (isset($pa_options['returnURL']) && $pa_options['returnURL']) { $va_return_values[$vn_row_id][$vn_locale_id][] = $this->getMediaUrl($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $pa_options); } else { $va_return_values[$vn_row_id][$vn_locale_id][] = $this->getMediaTag($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $pa_options); } } else { if ($vs_info_element) { $va_return_values[] = $this->getMediaInfo($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $vs_info_element, $pa_options); } elseif (isset($pa_options['returnURL']) && $pa_options['returnURL']) { $va_return_values[] = $this->getMediaUrl($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $pa_options); } else { $va_return_values[] = $this->getMediaTag($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $pa_options); } } } } } } break; default: // is intrinsic field in primary table $vb_supports_preferred = (bool) $t_instance->hasField('is_preferred'); foreach ($va_value_list as $vn_id => $va_values_by_locale) { foreach ($va_values_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { $va_ids[] = $vn_id = $va_value[$vs_pk]; if ($vb_get_preferred_labels_only && $vb_supports_preferred && !$va_value['is_preferred']) { continue; } if ($vb_get_nonpreferred_labels_only && $vb_supports_preferred && $va_value['is_preferred']) { continue; } $vs_prop = $va_value[$va_path_components['field_name']]; if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'], "LIST_CODE"))) { $vs_prop = $t_list->getItemFromListForDisplayByItemID($vs_list_code, $vs_prop); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'], "LIST"))) { $vs_prop = $t_list->getItemFromListForDisplayByItemValue($vs_list_code, $vs_prop); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && $va_path_components['field_name'] === 'locale_id' && (int) $vs_prop > 0) { $t_locale = new ca_locales($vs_prop); $vs_prop = $t_locale->getName(); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && is_array($va_list = $t_instance->getFieldInfo($va_path_components['field_name'], "BOUNDS_CHOICE_LIST"))) { foreach ($va_list as $vs_option => $vs_value) { if ($vs_value == $vs_prop) { $vs_prop = $vs_option; break; } } } } } } if ($vb_return_all_locales) { $va_return_values[$vn_id][$vn_locale_id][] = $vs_prop; } else { $va_return_values[$vn_id][$vn_locale_id] = $vs_prop; } } } } if (!$vb_return_all_locales) { $va_return_values = array_values(caExtractValuesByUserLocale($va_return_values)); } break; } } else { // Attributes $vs_pk = $t_original_instance->primaryKey(); $vb_is_related = $this->ops_table_name !== $va_path_components['table_name']; $va_ids = array(); $t_instance = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true); foreach ($va_value_list as $vn_i => $va_values_by_locale) { foreach ($va_values_by_locale as $vn_locale_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { if ($vb_is_related) { $va_ids[] = $va_value[$vs_pk]; } if ($vb_get_preferred_labels_only && !$va_value['is_preferred']) { continue; } if ($vb_get_nonpreferred_labels_only && $va_value['is_preferred']) { continue; } // do we need to translate foreign key and choice list codes to display text? $vs_prop = $vb_return_all_label_values && !$vb_return_as_link ? $va_value : $va_value[$va_path_components['field_name']]; if ($vb_get_relationship_typename) { if (!$t_rel_type) { $t_rel_type = $this->opo_datamodel->getInstanceByTableName('ca_relationship_types', true); } if (is_array($va_labels = $t_rel_type->getDisplayLabels(false, array('row_id' => (int) $vs_prop)))) { $va_label = array_shift($va_labels); $vs_prop = $va_label[0]['typename']; } else { $vs_prop = "?"; } } else { // Decode list items to text if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'], "LIST_CODE"))) { $vs_prop = $t_list->getItemFromListForDisplayByItemID($vs_list_code, $vs_prop); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'], "LIST"))) { $vs_prop = $t_list->getItemFromListForDisplayByItemValue($vs_list_code, $vs_prop); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && $va_path_components['field_name'] === 'locale_id' && (int) $vs_prop > 0) { $t_locale = new ca_locales($vs_prop); $vs_prop = $t_locale->getName(); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && is_array($va_list = $t_instance->getFieldInfo($va_path_components['field_name'], "BOUNDS_CHOICE_LIST"))) { foreach ($va_list as $vs_option => $vs_value) { if ($vs_value == $vs_prop) { $vs_prop = $vs_option; break; } } } } } } } if ($vb_return_all_locales) { $va_return_values[$vn_row_id][$vn_locale_id][] = $vs_prop; } else { if ($vb_get_nonpreferred_labels_only && is_array($vs_prop)) { // non-preferred labels are lists of lists because they can repeat $va_return_values[][] = $vs_prop; } else { $va_return_values[] = $vs_prop; } } } } } } if ($vb_return_as_link) { if (!$vb_return_all_locales) { $va_return_values = caCreateLinksFromText($va_return_values, $va_original_path_components['table_name'], $va_ids, $vs_return_as_link_class, $vs_return_as_link_target); } } return $va_return_values; } else { // Return scalar (intrinsics or labels in primary or related table) if ($vb_get_preferred_labels_only || $vb_get_nonpreferred_labels_only) { // We have to distinguish between preferred and non-preferred labels here // so that only appropriate labels are passed for output. $va_filtered_values = array(); foreach ($va_value_list as $vn_label_id => $va_labels_by_locale) { foreach ($va_labels_by_locale as $vn_locale_id => $va_labels) { foreach ($va_labels as $vn_i => $va_label) { if ($vb_get_preferred_labels_only && (!isset($va_label['is_preferred']) || $va_label['is_preferred']) || $vb_get_nonpreferred_labels_only && !$va_label['is_preferred']) { $va_filtered_values[$vn_label_id][$vn_locale_id][] = $va_label; } } } } $va_value_list = $va_filtered_values; } $va_value_list = caExtractValuesByUserLocale($va_value_list); // do we need to translate foreign key and choice list codes to display text? $t_instance = $this->opo_datamodel->getInstanceByTableName($va_path_components['table_name'], true); $va_field_info = $t_instance->getFieldInfo($va_path_components['field_name']); $vs_pk = $t_instance->primaryKey(); $vb_is_related = $this->ops_table_name !== $va_path_components['table_name']; $va_ids = array(); foreach ($va_value_list as $vn_i => $va_values) { if (!is_array($va_values)) { continue; } // Handle specific intrinsic types $vs_template_value = $vs_template; foreach ($va_values as $vn_j => $va_value) { switch ($va_field_info['FIELD_TYPE']) { case FT_BIT: if ($pa_options['convertCodesToDisplayText']) { $va_value[$va_path_components['field_name']] = (bool) $vs_prop ? _t('yes') : _t('no'); } break; case FT_DATERANGE: if (caGetOption('GET_DIRECT_DATE', $pa_options, false) || caGetOption('getDirectDate', $pa_options, false)) { if (isset($pa_options['sortable']) && $pa_options['sortable']) { $va_value[$va_path_components['field_name']] = $va_value[$va_field_info['START']] . '/' . $va_value[$va_field_info['END']]; } else { $va_value[$va_path_components['field_name']] = $va_value[$va_field_info['START']]; } } else { $this->opo_tep->init(); $this->opo_tep->setUnixTimestamps($va_value[$va_field_info['START']], $va_value[$va_field_info['END']]); $va_value[$va_path_components['field_name']] = $this->opo_tep->getText($pa_options); } break; case FT_HISTORIC_DATERANGE: if (caGetOption('GET_DIRECT_DATE', $pa_options, false) || caGetOption('getDirectDate', $pa_options, false)) { if (caGetOption('sortable', $pa_options, false)) { $va_value[$va_path_components['field_name']] = $va_value[$va_field_info['START']] . '/' . $va_value[$va_field_info['END']]; } else { $va_value[$va_path_components['field_name']] = $va_value[$va_field_info['START']]; } } else { $this->opo_tep->init(); $this->opo_tep->setHistoricTimestamps($va_value[$va_field_info['START']], $va_value[$va_field_info['END']]); $va_value[$va_path_components['field_name']] = $this->opo_tep->getText($pa_options); } break; case FT_MEDIA: if (!($vs_version = $va_path_components['subfield_name'])) { $vs_version = "largeicon"; } // See if an info element was passed, eg. ca_object_representations.media.icon.width should return the width of the media rather than a tag or url to the media $vs_info_element = $va_path_components['num_components'] == 4 ? $va_path_components['components'][3] : null; if (isset($pa_options['unserialize']) && $pa_options['unserialize']) { return caUnserializeForDatabase($va_value[$va_path_components['field_name']]); } else { $o_media_settings = new MediaProcessingSettings($va_path_components['table_name'], $va_path_components['field_name']); $va_versions = $o_media_settings->getMediaTypeVersions('*'); if (!isset($va_versions[$vs_version])) { $va_tmp = array_keys($va_versions); $vs_version = array_shift($va_tmp); } if ($vs_info_element) { // Return media info $va_value[$va_path_components['field_name']] = $this->getMediaInfo($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $vs_info_element, $pa_options); } elseif (isset($pa_options['returnURL']) && $pa_options['returnURL']) { $va_value[$va_path_components['field_name']] = $this->getMediaUrl($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $pa_options); } else { $va_value[$va_path_components['field_name']] = $this->getMediaTag($va_path_components['table_name'] . '.' . $va_path_components['field_name'], $vs_version, $pa_options); } } break; default: // noop break; } $vs_prop = $va_value[$va_path_components['field_name']]; // Decode list items to text if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'], "LIST_CODE"))) { $va_value[$va_path_components['field_name']] = $t_list->getItemFromListForDisplayByItemID($vs_list_code, $vs_prop); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && ($vs_list_code = $t_instance->getFieldInfo($va_path_components['field_name'], "LIST"))) { $va_value[$va_path_components['field_name']] = $t_list->getItemFromListForDisplayByItemValue($vs_list_code, $vs_prop); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && $va_path_components['field_name'] === 'locale_id' && (int) $vs_prop > 0) { $t_locale = new ca_locales($vs_prop); $va_value[$va_path_components['field_name']] = $t_locale->getName(); } else { if (isset($pa_options['convertCodesToDisplayText']) && $pa_options['convertCodesToDisplayText'] && is_array($va_list = $t_instance->getFieldInfo($va_path_components['field_name'], "BOUNDS_CHOICE_LIST"))) { foreach ($va_list as $vs_option => $vs_value) { if ($vs_value == $vs_prop) { $va_value[$va_path_components['field_name']] = $vs_option; break; } } } } } } $vs_pk = $this->opo_datamodel->getTablePrimaryKeyName($va_original_path_components['table_name']); if ($vs_template) { foreach ($va_value_list as $vn_id => $va_values) { foreach ($va_values as $vn_i => $va_value) { $vs_prop = caProcessTemplateForIDs($vs_template, $va_original_path_components['table_name'], array($va_value[$vs_pk]), array('returnAsArray' => false)); $va_return_values[] = $vs_prop; $va_ids[] = $va_value[$vs_pk]; } } } else { $vs_prop = $va_value[$va_path_components['field_name']]; $va_return_values[] = $vs_prop; if ($vb_is_related) { $va_ids[] = $va_value[$vs_pk]; } } } } if ($vb_return_as_link && $vb_is_related) { $va_return_values = caCreateLinksFromText($va_return_values, $va_original_path_components['table_name'], $va_ids, $vs_return_as_link_class, $vs_return_as_link_target); } if (isset($pa_options['convertLineBreaks']) && $pa_options['convertLineBreaks']) { return caConvertLineBreaks(join($vs_delimiter, $va_return_values)); } else { return join($vs_delimiter, $va_return_values); } } } return null; }
public function testGetAttributeCount() { $t_element = ca_attributes::getElementInstance('internal_notes'); $this->opt_object->getDb()->dieOnError(true); $this->assertEquals(2, ca_attributes::getAttributeCount($this->opt_object->getDb(), $this->opt_object->tableNum(), $this->opt_object->getPrimaryKey(), $t_element->getPrimaryKey())); }