/** * Prepopulate record fields according to rules in prepopulate.conf * * @param array $pa_options Options array. Available options are: * prepopulateConfig = override path to prepopulate.conf, e.g. for testing purposes * @return bool success or not */ public function prepopulateFields($pa_options = null) { if (!$this->getPrimaryKey()) { return false; } if (!($vs_prepopulate_cfg = caGetOption('prepopulateConfig', $pa_options, null))) { $vs_prepopulate_cfg = $this->getAppConfig()->get('prepopulate_config'); } $o_prepopulate_conf = Configuration::load($vs_prepopulate_cfg); if (!($o_prepopulate_conf->get('prepopulate_fields_on_save') || $o_prepopulate_conf->get('prepopulate_fields_on_load'))) { return false; } $va_rules = $o_prepopulate_conf->get('prepopulate_rules'); if (!$va_rules || !is_array($va_rules) || sizeof($va_rules) < 1) { return false; } global $g_ui_locale_id; // we need to unset the form timestamp to disable the 'Changes have been made since you loaded this data' warning when we update() $this // the warning makes sense because an update()/insert() is called before we arrive here but after the form_timestamp ... but we chose to ignore it $vn_timestamp = $_REQUEST['form_timestamp']; unset($_REQUEST['form_timestamp']); $vb_we_set_transaction = true; if (!$this->inTransaction()) { $this->setTransaction(new Transaction($this->getDb())); $vb_we_set_transaction = true; } // process rules $va_expression_vars = array(); // we only process those if and when we need them foreach ($va_rules as $vs_rule_key => $va_rule) { if ($this->tableName() != $va_rule['table']) { continue; } // check target $vs_target = $va_rule['target']; if (strlen($vs_target) < 1) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because target is not set"); continue; } // check template $vs_template = $va_rule['template']; if (strlen($vs_template) < 1) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because template is not set"); continue; } $vs_mode = caGetOption('mode', $va_rule, 'merge'); // respect restrictToTypes option if ($va_rule['restrictToTypes'] && is_array($va_rule['restrictToTypes']) && sizeof($va_rule['restrictToTypes']) > 0) { if (!in_array($this->getTypeCode(), $va_rule['restrictToTypes'])) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because current record type " . $this->getTypeCode() . " is not in restrictToTypes"); continue; } } // skip this rule if expression is true if ($va_rule['skipIfExpression'] && strlen($va_rule['skipIfExpression']) > 0) { $va_tags = caGetTemplateTags($va_rule['skipIfExpression']); foreach ($va_tags as $vs_tag) { if (!isset($va_expression_vars[$vs_tag])) { $va_expression_vars[$vs_tag] = $this->get($vs_tag, array('returnIdno' => true, 'delimiter' => ';')); } } if (ExpressionParser::evaluate($va_rule['skipIfExpression'], $va_expression_vars)) { Debug::msg("[prepopulateFields()] skipping rule {$vs_rule_key} because skipIfExpression evaluated true"); continue; } } // evaluate template $vs_value = caProcessTemplateForIDs($vs_template, $this->tableNum(), array($this->getPrimaryKey()), array('path' => true)); Debug::msg("[prepopulateFields()] processed template for rule {$vs_rule_key} value is: " . $vs_value); // inject into target $va_parts = explode('.', $vs_target); // intrinsic or simple (non-container) attribute if (sizeof($va_parts) == 2) { // intrinsic if ($this->hasField($va_parts[1])) { switch (strtolower($vs_mode)) { case 'overwrite': // always set $this->set($va_parts[1], $vs_value); break; case 'addifempty': default: if (!$this->get($va_parts[1])) { $this->set($va_parts[1], $vs_value); } else { Debug::msg("[prepopulateFields()] rule {$vs_rule_key}: intrinsic skipped because it already has value and mode is addIfEmpty or merge"); } break; } // attribute/element } elseif ($this->hasElement($va_parts[1])) { $va_attributes = $this->getAttributesByElement($va_parts[1]); if (sizeof($va_attributes) > 1) { Debug::msg("[prepopulateFields()] containers with multiple values are not supported"); continue; } switch (strtolower($vs_mode)) { case 'overwrite': // always replace first value we find $this->replaceAttribute(array($va_parts[1] => $vs_value, 'locale_id' => $g_ui_locale_id), $va_parts[1]); break; default: case 'addifempty': // only add value if none exists if (!$this->get($vs_target)) { $this->replaceAttribute(array($va_parts[1] => $vs_value, 'locale_id' => $g_ui_locale_id), $va_parts[1]); } break; } } // "container" } elseif (sizeof($va_parts) == 3) { // actual container if ($this->hasElement($va_parts[1])) { $va_attr = $this->getAttributesByElement($va_parts[1]); switch (sizeof($va_attr)) { case 1: switch (strtolower($vs_mode)) { case 'overwrite': $vo_attr = array_pop($va_attr); $va_value = array($va_parts[2] => $vs_value); foreach ($vo_attr->getValues() as $o_val) { if ($o_val->getElementCode() != $va_parts[2]) { $va_value[$o_val->getElementCode()] = $o_val->getDisplayValue(); } } $this->_editAttribute($vo_attr->getAttributeID(), $va_value); break; case 'addifempty': $vo_attr = array_pop($va_attr); $va_value = array($va_parts[2] => $vs_value); $vb_update = false; foreach ($vo_attr->getValues() as $o_val) { if ($o_val->getElementCode() != $va_parts[2]) { $va_value[$o_val->getElementCode()] = $o_val->getDisplayValue(); } else { if (!$o_val->getDisplayValue()) { $vb_update = true; } } } if ($vb_update) { $this->editAttribute($vo_attr->getAttributeID(), $va_parts[1], $va_value); } break; default: Debug::msg("[prepopulateFields()] unsupported mode {$vs_mode} for target bundle"); break; } break; case 0: // if no container value exists, always add it (ignoring mode) $this->addAttribute(array($va_parts[2] => $vs_value, 'locale_id' => $g_ui_locale_id), $va_parts[1]); break; default: Debug::msg("[prepopulateFields()] containers with multiple values are not supported"); break; } // labels } elseif ($va_parts[1] == 'preferred_labels' || $va_parts[1] == 'nonpreferred_labels') { $vb_preferred = $va_parts[1] == 'preferred_labels'; if (!($t_label = $this->getAppDatamodel()->getInstanceByTableName($this->getLabelTableName(), true))) { continue; } if (!$t_label->hasField($va_parts[2])) { continue; } switch ($this->getLabelCount($vb_preferred)) { case 0: // if no value exists, always add it (ignoring mode) $this->addLabel(array($va_parts[2] => $vs_value), $g_ui_locale_id, null, $vb_preferred); break; case 1: switch (strtolower($vs_mode)) { case 'overwrite': case 'addifempty': $va_labels = $this->getLabels(null, $vb_preferred ? __CA_LABEL_TYPE_PREFERRED__ : __CA_LABEL_TYPE_NONPREFERRED__); if (sizeof($va_labels)) { $va_labels = caExtractValuesByUserLocale($va_labels); $va_label = array_shift($va_labels); $va_label = $va_label[0]; $va_label[$va_parts[2]] = $vs_value; $vb_update = false; if (strtolower($vs_mode) == 'overwrite') { $va_label[$va_parts[2]] = $vs_value; $vb_update = true; } else { if (strlen(trim($va_label[$va_parts[2]])) == 0) { // in addifempty mode only edit label when field is not set $va_label[$va_parts[2]] = $vs_value; $vb_update = true; } } if ($vb_update) { $this->editLabel($va_label['label_id'], $va_label, $g_ui_locale_id, null, $vb_preferred); } } else { $this->addLabel(array($va_parts[2] => $vs_value), $g_ui_locale_id, null, $vb_preferred); } break; default: Debug::msg("[prepopulateFields()] unsupported mode {$vs_mode} for target bundle"); break; } break; default: Debug::msg("[prepopulateFields()] records with multiple labels are not supported"); break; } } } } $vn_old_mode = $this->getMode(); $this->setMode(ACCESS_WRITE); $this->update(); $this->setMode($vn_old_mode); $_REQUEST['form_timestamp'] = $vn_timestamp; if ($this->numErrors() > 0) { foreach ($this->getErrors() as $vs_error) { Debug::msg("[prepopulateFields()] there was an error while updating the record: " . $vs_error); } if ($vb_we_set_transaction) { $this->removeTransaction(false); } return false; } if ($vb_we_set_transaction) { $this->removeTransaction(true); } return true; }
/** * Replace "^" prefixed tags (eg. ^forename) in a template with values from an array * * @param string $ps_template String with embedded tags. Tags are just alphanumeric strings prefixed with a caret ("^") * @param string $pm_tablename_or_num Table name or number of table from which values are being formatted * @param string $pa_row_ids An array of primary key values in the specified table to be pulled into the template * @param array $pa_options Supported options are: * returnAsArray = if true an array of processed template values is returned, otherwise the template values are returned as a string joined together with a delimiter. Default is false. * delimiter = value to string together template values with when returnAsArray is false. Default is ';' (semicolon) * relatedValues = array of field values to return in template when directly referenced. Array should be indexed numerically in parallel with $pa_row_ids * relationshipValues = array of field values to return in template for relationship when directly referenced. Should be indexed by row_id and then by relation_id * placeholderPrefix = attribute container to implicitly place primary record fields into. Ex. if the table is "ca_entities" and the placeholder is "address" then tags like ^city will resolve to ca_entities.address.city * requireLinkTags = if set then links are only added when explicitly defined with <l> tags. Default is to make the entire text a link in the absence of <l> tags. * resolveLinksUsing = * primaryIDs = row_ids for primary rows in related table, keyed by table name; when resolving ambiguous relationships the row_ids will be excluded from consideration. This option is rarely used and exists primarily to take care of a single * edge case: you are processing a template relative to a self-relationship such as ca_entities_x_entities that includes references to the subject table (ca_entities, in the case of ca_entities_x_entities). There are * two possible paths to take in this situations; primaryIDs lets you specify which ones you *don't* want to take by row_id. For interstitial editors, the ids will be set to a single id: that of the subject (Eg. ca_entities) row * from which the interstitial was launched. * sort = optional list of tag values to sort repeating values within a row template on. The tag must appear in the template. You can specify more than one tag by separating the tags with semicolons. * sortDirection = The direction of the sort of repeating values within a row template. May be either ASC (ascending) or DESC (descending). [Default is ASC] * linkTarget = Optional target to use when generating <l> tag-based links. By default links point to standard detail pages, but plugins may define linkTargets that point elsewhere. * skipIfExpression = skip the elements in $pa_row_ids for which the given expression does not evaluate true * includeBlankValuesInArray = include blank template values in returned array when returnAsArray is set. If you need the returned array of values to line up with the row_ids in $pa_row_ids this should be set. [Default is false] * * @return mixed Output of processed templates */ function caProcessTemplateForIDs($ps_template, $pm_tablename_or_num, $pa_row_ids, $pa_options = null) { foreach (array('request', 'template', 'restrictToTypes', 'restrict_to_types', 'restrict_to_relationship_types', 'restrictToRelationshipTypes', 'useLocaleCodes') as $vs_k) { unset($pa_options[$vs_k]); } if (!isset($pa_options['convertCodesToDisplayText'])) { $pa_options['convertCodesToDisplayText'] = true; } $pb_return_as_array = (bool) caGetOption('returnAsArray', $pa_options, false); if (($pa_sort = caGetOption('sort', $pa_options, null)) && !is_array($pa_sort)) { $pa_sort = explode(";", $pa_sort); } $ps_sort_direction = caGetOption('sortDirection', $pa_options, null, array('forceUppercase' => true)); if (!in_array($ps_sort_direction, array('ASC', 'DESC'))) { $ps_sort_direction = 'ASC'; } $pa_check_access = caGetOption('checkAccess', $pa_options, null); if (!is_array($pa_row_ids) || !sizeof($pa_row_ids) || !$ps_template) { return $pb_return_as_array ? array() : ""; } unset($pa_options['returnAsArray']); if (!isset($pa_options['requireLinkTags'])) { $pa_options['requireLinkTags'] = true; } $ps_skip_if_expression = caGetOption('skipIfExpression', $pa_options, false); $va_primary_ids = caGetOption("primaryIDs", $pa_options, null); $o_dm = Datamodel::load(); $ps_tablename = is_numeric($pm_tablename_or_num) ? $o_dm->getTableName($pm_tablename_or_num) : $pm_tablename_or_num; $ps_resolve_links_using = caGetOption('resolveLinksUsing', $pa_options, $ps_tablename); $t_instance = $o_dm->getInstanceByTableName($ps_tablename, true); if ($ps_resolve_links_using != $ps_tablename) { $t_resolve_links_instance = $o_dm->getInstanceByTableName($ps_resolve_links_using, true); $vs_resolve_links_using_pk = $t_resolve_links_instance->primaryKey(); } $vs_pk = $t_instance->primaryKey(); $vs_delimiter = isset($pa_options['delimiter']) ? $pa_options['delimiter'] : '; '; $ps_template = str_replace("^_parent", "^{$ps_resolve_links_using}.parent.preferred_labels", $ps_template); $ps_template = str_replace("^_hierarchy", "^{$ps_resolve_links_using}._hierarchyName", $ps_template); $va_related_values = isset($pa_options['relatedValues']) && is_array($pa_options['relatedValues']) ? $pa_options['relatedValues'] : array(); $va_relationship_values = isset($pa_options['relationshipValues']) && is_array($pa_options['relationshipValues']) ? $pa_options['relationshipValues'] : array(); $o_doc = str_get_dom($ps_template); // parse template $ps_template = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_doc->html())); // replace template with parsed version; this allows us to do text find/replace later // Parse units from template $o_units = $o_doc('unit'); // only process non-nested <unit> tags $va_units = array(); $vn_unit_id = 1; foreach ($o_units as $o_unit) { if (!$o_unit) { continue; } $vs_html = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_unit->html())); $vs_content = $o_unit->getInnerText(); // is this nested in another unit? We skip these foreach ($va_units as $va_tmp) { if (strpos($va_tmp['directive'], $vs_html) !== false) { continue 2; } } $va_units[] = $va_unit = array('tag' => $vs_unit_tag = "[[#{$vn_unit_id}]]", 'directive' => $vs_html, 'content' => $vs_content, 'relativeTo' => (string) $o_unit->getAttribute("relativeto"), 'delimiter' => ($vs_d = (string) $o_unit->getAttribute("delimiter")) ? $vs_d : null, 'restrictToTypes' => (string) $o_unit->getAttribute("restricttotypes"), 'restrictToRelationshipTypes' => (string) $o_unit->getAttribute("restricttorelationshiptypes"), 'sort' => explode(";", $o_unit->getAttribute("sort")), 'sortDirection' => (string) $o_unit->getAttribute("sortDirection"), 'skipIfExpression' => (string) $o_unit->getAttribute("skipIfExpression")); $ps_template = str_ireplace($va_unit['directive'], $vs_unit_tag, $ps_template); $vn_unit_id++; } $o_doc = str_get_dom($ps_template); // parse template again with units replaced by unit tags in the format [[#X]] $ps_template = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_doc->html())); // replace template with parsed version; this allows us to do text find/replace later $va_tags = array(); if (preg_match_all(__CA_BUNDLE_DISPLAY_TEMPLATE_TAG_REGEX__, $ps_template, $va_matches)) { $va_tags = $va_matches[1]; } $va_directive_tags = array(); $va_directive_tag_vals = array(); $qr_res = caMakeSearchResult($ps_tablename, $pa_row_ids); if (!$qr_res) { return ''; } $va_proc_templates = array(); $vn_i = 0; $o_ifs = $o_doc("if"); // if $o_ifdefs = $o_doc("ifdef"); // if defined $o_ifnotdefs = $o_doc("ifnotdef"); // if not defined $o_mores = $o_doc("more"); // more tags - content suppressed if there are no defined values following the tag pair $o_betweens = $o_doc("between"); // between tags - content suppressed if there are not defined values on both sides of the tag pair $va_if = array(); foreach ($o_ifs as $o_if) { if (!$o_if) { continue; } $vs_html = $o_if->html(); $vs_content = $o_if->getInnerText(); $va_if[] = array('directive' => $vs_html, 'content' => $vs_content, 'rule' => $vs_rule = (string) $o_if->getAttribute('rule')); } foreach ($o_ifdefs as $o_ifdef) { if (!$o_ifdef) { continue; } $vs_code = (string) $o_ifdef->getAttribute('code'); $vs_code_proc = preg_replace("!%(.*)\$!", '', $vs_code); $va_directive_tags = array_merge($va_directive_tags, preg_split('![,\\|]{1}!', $vs_code_proc)); } foreach ($o_ifnotdefs as $o_ifnotdef) { if (!$o_ifnotdef) { continue; } $vs_code = (string) $o_ifnotdef->getAttribute('code'); $vs_code_proc = preg_replace("!%(.*)\$!", '', $vs_code); $va_directive_tags = array_merge($va_directive_tags, preg_split('![,\\|]{1}!', $vs_code_proc)); } $va_mores = array(); foreach ($o_mores as $o_more) { if (!$o_more) { continue; } $vs_html = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_more->html())); $vs_content = $o_more->getInnerText(); $va_mores[] = array('directive' => $vs_html, 'content' => $vs_content); } $va_betweens = array(); foreach ($o_betweens as $o_between) { if (!$o_between) { continue; } $vs_html = str_replace("<~root~>", "", str_replace("</~root~>", "", $o_between->html())); $vs_content = $o_between->getInnerText(); $va_betweens[] = array('directive' => $vs_html, 'content' => $vs_content); } $va_resolve_links_using_row_ids = array(); $va_tag_val_list = $va_defined_tag_list = array(); $va_expression_vars = array(); /** @var $qr_res SearchResult */ while ($qr_res->nextHit()) { $vs_pk_val = $qr_res->get($vs_pk, array('checkAccess' => $pa_check_access)); if (is_array($pa_check_access) && sizeof($pa_check_access) && !in_array($qr_res->get("{$ps_tablename}.access"), $pa_check_access)) { continue; } $vs_template = $ps_template; // check if we skip this row because of skipIfExpression if (strlen($ps_skip_if_expression) > 0) { $va_expression_tags = caGetTemplateTags($ps_skip_if_expression); foreach ($va_expression_tags as $vs_expression_tag) { if (!isset($va_expression_vars[$vs_expression_tag])) { $va_expression_vars[$vs_expression_tag] = $qr_res->get($vs_expression_tag, array('assumeDisplayField' => true, 'returnIdno' => true, 'delimiter' => ';')); } } if (ExpressionParser::evaluate($ps_skip_if_expression, $va_expression_vars)) { continue; } } // Grab values for codes used in ifdef and ifnotdef directives $va_directive_tag_vals = array(); foreach ($va_directive_tags as $vs_directive_tag) { $va_directive_tag_vals[$vs_directive_tag] = $qr_res->get($vs_directive_tag, array('assumeDisplayField' => true, 'convertCodesToDisplayText' => true, 'dontUseElementTemplate' => true)); } $o_parsed_template = str_get_dom($vs_template); while (sizeof($vo_templates = $o_parsed_template('ifcount:not(:has(ifdef,ifndef,ifcount)),ifdef:not(:has(ifdef,ifndef,ifcount)),ifndef:not(:has(ifdef,ifndef,ifcount))')) > 0) { foreach ($vo_templates as $vn_index => $vo_element) { $vs_code = $vo_element->code; switch ($vo_element->tag) { case 'ifdef': if (strpos($vs_code, "|") !== false) { $vs_bool = 'OR'; $va_tag_list = explode("|", $vs_code); $vb_output = false; } else { $vs_bool = 'AND'; $va_tag_list = explode(",", $vs_code); $vb_output = true; } foreach ($va_tag_list as $vs_tag_to_test) { $vs_tag_to_test = preg_replace("!%.*\$!", "", $vs_tag_to_test); $vb_value_is_set = isset($va_directive_tag_vals[$vs_tag_to_test]) && strlen($va_directive_tag_vals[$vs_tag_to_test]) > 1; switch ($vs_bool) { case 'OR': if ($vb_value_is_set) { $vb_output = true; break 2; } // any must be defined; if any is defined output break; case 'AND': default: if (!$vb_value_is_set) { $vb_output = false; break 2; } // all must be defined; if any is not defined don't output break; } } if ($vb_output) { $vs_template = str_replace($vo_element->html(), $vo_element->getInnerText(), $vs_template); } else { $vs_template = str_replace($vo_element->html(), '', $vs_template); } break; case 'ifndef': if (strpos($vs_code, "|") !== false) { $vs_bool = 'OR'; $va_tag_list = explode("|", $vs_code); $vb_output = false; } else { $vs_bool = 'AND'; $va_tag_list = explode(",", $vs_code); $vb_output = true; } $vb_output = true; foreach ($va_tag_list as $vs_tag_to_test) { $vb_value_is_set = (bool) (isset($va_directive_tag_vals[$vs_tag_to_test]) && strlen($va_directive_tag_vals[$vs_tag_to_test]) > 0); switch ($vs_bool) { case 'OR': if (!$vb_value_is_set) { $vb_output = true; break 2; } // any must be not defined; if anything is not set output break; case 'AND': default: if ($vb_value_is_set) { $vb_output = false; break 2; } // all must be not defined; if anything is set don't output break; } } if ($vb_output) { $vs_template = str_replace($vo_element->html(), $vo_element->getInnerText(), $vs_template); } else { $vs_template = str_replace($vo_element->html(), '', $vs_template); } break; case 'ifcount': if (is_array($va_if_codes = preg_split("![\\|,;]+!", $vs_code))) { $vn_min = (int) $vo_element->min; $vn_max = (int) $vo_element->max; $va_restrict_to_types = preg_split("![,; ]+!", $vo_element->restrictToTypes); $va_restrict_to_relationship_types = preg_split("![,; ]+!", $vo_element->restrictToRelationshipTypes); $vn_count = 0; foreach ($va_if_codes as $vs_if_code) { if ($t_table = $o_dm->getInstanceByTableName($vs_if_code, true)) { $va_count_vals = $qr_res->get($vs_if_code . "." . $t_table->primaryKey(), array('restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_relationship_types, 'returnAsArray' => true, 'checkAccess' => $pa_check_access)); } else { $va_count_vals = $qr_res->get($vs_if_code, array('returnAsArray' => true, 'restrictToTypes' => $va_restrict_to_types, 'restrictToRelationshipTypes' => $va_restrict_to_relationship_types, 'checkAccess' => $pa_check_access)); } if (is_array($va_count_vals)) { $va_bits = explode(".", $vs_if_code); $vs_fld = array_pop($va_bits); foreach ($va_count_vals as $vs_count_val) { if (is_array($vs_count_val)) { if (isset($vs_count_val[$vs_fld]) && !trim($vs_count_val[$vs_fld])) { continue; } $vb_is_set = false; foreach ($vs_count_val as $vs_f => $vs_v) { if (trim($vs_v)) { $vb_is_set = true; break; } } if (!$vb_is_set) { continue; } } else { if (!trim($vs_count_val)) { continue; } } $vn_count++; } } } if ($vn_min <= $vn_count && ($vn_max >= $vn_count || !$vn_max)) { $vs_template = str_replace($vo_element->html(), $vo_element->getInnerText(), $vs_template); } else { $vs_template = str_replace($vo_element->html(), '', $vs_template); } } break; } } $o_parsed_template = str_get_dom($vs_template); // reparse } $va_proc_templates[$vn_i] = $vs_template; foreach ($va_units as $k => $va_unit) { if (!$va_unit['content']) { continue; } $va_relative_to_tmp = $va_unit['relativeTo'] ? explode(".", $va_unit['relativeTo']) : array($ps_tablename); if (!($t_rel_instance = $o_dm->getInstanceByTableName($va_relative_to_tmp[0], true))) { continue; } $vs_unit_delimiter = caGetOption('delimiter', $va_unit, $vs_delimiter); $vs_unit_skip_if_expression = caGetOption('skipIfExpression', $va_unit, false); // additional get options for pulling related records $va_get_options = array('returnAsArray' => true, 'checkAccess' => $pa_check_access); if ($va_unit['restrictToTypes'] && strlen($va_unit['restrictToTypes']) > 0) { $va_get_options['restrictToTypes'] = preg_split('![\\|,;]+!', $va_unit['restrictToTypes']); } if ($va_unit['restrictToRelationshipTypes'] && strlen($va_unit['restrictToRelationshipTypes']) > 0) { $va_get_options['restrictToRelationshipTypes'] = preg_split('![\\|,;]+!', $va_unit['restrictToRelationshipTypes']); } if ($va_unit['sort'] && is_array($va_unit['sort'])) { $va_get_options['sort'] = $va_unit['sort']; $va_get_options['sortDirection'] = $va_unit['sortDirection']; } if (sizeof($va_relative_to_tmp) == 1 && $va_relative_to_tmp[0] == $ps_tablename || sizeof($va_relative_to_tmp) >= 1 && $va_relative_to_tmp[0] == $ps_tablename && $va_relative_to_tmp[1] != 'related') { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: $va_relative_ids = array($vs_pk_val); break; } // process template for all records selected by unit tag $va_tmpl_val = caProcessTemplateForIDs($va_unit['content'], $va_relative_to_tmp[0], $va_relative_ids, array_merge($pa_options, array('sort' => $va_get_options['sort'], 'sortDirection' => $va_get_options['sortDirection'], 'returnAsArray' => true, 'delimiter' => $vs_unit_delimiter, 'resolveLinksUsing' => null, 'skipIfExpression' => $vs_unit_skip_if_expression))); $va_proc_templates[$vn_i] = str_ireplace($va_unit['tag'], join($vs_unit_delimiter, $va_tmpl_val), $va_proc_templates[$vn_i]); } else { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'related': $va_relative_ids = $qr_res->get($t_rel_instance->tableName() . ".related." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: if (method_exists($t_instance, 'isSelfRelationship') && $t_instance->isSelfRelationship()) { $va_relative_ids = array_values($t_instance->getRelatedIDsForSelfRelationship($va_primary_ids[$t_rel_instance->tableName()], array($vs_pk_val))); } else { $va_relative_ids = array_values($qr_res->get($t_rel_instance->tableName() . "." . $t_rel_instance->primaryKey(), $va_get_options)); } break; } $vs_tmpl_val = caProcessTemplateForIDs($va_unit['content'], $va_relative_to_tmp[0], $va_relative_ids, array_merge($pa_options, array('sort' => $va_unit['sort'], 'sortDirection' => $va_unit['sortDirection'], 'delimiter' => $vs_unit_delimiter, 'resolveLinksUsing' => null, 'skipIfExpression' => $vs_unit_skip_if_expression))); $va_proc_templates[$vn_i] = str_ireplace($va_unit['tag'], $vs_tmpl_val, $va_proc_templates[$vn_i]); } } if (!strlen(trim($va_proc_templates[$vn_i]))) { $va_proc_templates[$vn_i] = null; } if (!sizeof($va_tags)) { $vn_i++; continue; } // if there are no tags in the template then we don't need to process further if ($ps_resolve_links_using !== $ps_tablename) { $va_resolve_links_using_row_ids += $qr_res->get("{$ps_resolve_links_using}.{$vs_resolve_links_using_pk}", array('returnAsArray' => true, 'checkAccess' => $pa_check_access)); // we need to remove "primary_ids" from the list, since for self-relations these will be the side(s) of the relations we're viewing *from* if (is_array($va_primary_ids[$ps_resolve_links_using]) && sizeof($va_primary_ids[$ps_resolve_links_using])) { $va_resolve_links_using_row_ids = array_values(array_diff($va_resolve_links_using_row_ids, $va_primary_ids[$ps_resolve_links_using])); } } $va_tag_val_list[$vn_i] = array(); $va_defined_tag_list[$vn_i] = array(); $va_tag_opts = $va_tag_filters = array(); foreach ($va_tags as $vs_tag) { $va_tmp = explode('.', $vs_tag); $vs_last_element = $va_tmp[sizeof($va_tmp) - 1]; $va_tag_opt_tmp = explode("%", $vs_last_element); if (sizeof($va_tag_opt_tmp) > 1) { $vs_tag_bit = array_shift($va_tag_opt_tmp); // get rid of getspec foreach ($va_tag_opt_tmp as $vs_tag_opt_raw) { if (preg_match("!^\\[([^\\]]+)\\]\$!", $vs_tag_opt_raw, $va_matches)) { if (sizeof($va_filter = explode("=", $va_matches[1])) == 2) { $va_tag_filters[$va_filter[0]] = $va_filter[1]; } continue; } $va_tag_tmp = explode("=", $vs_tag_opt_raw); $va_tag_tmp[0] = trim($va_tag_tmp[0]); $va_tag_tmp[1] = trim($va_tag_tmp[1]); if (in_array($va_tag_tmp[0], array('delimiter', 'hierarchicalDelimiter'))) { $va_tag_tmp[1] = str_replace("_", " ", $va_tag_tmp[1]); } if (sizeof($va_tag_line_tmp = explode("|", $va_tag_tmp[1])) > 1) { $va_tag_opts[trim($va_tag_tmp[0])] = $va_tag_line_tmp; } else { $va_tag_opts[trim($va_tag_tmp[0])] = $va_tag_tmp[1]; } } $va_tmp[sizeof($va_tmp) - 1] = $vs_tag_bit; // remove option from tag-part array $vs_tag_proc = join(".", $va_tmp); $va_proc_templates[$vn_i] = str_replace($vs_tag, $vs_tag_proc, $va_proc_templates[$vn_i]); $vs_tag = $vs_tag_proc; } switch ($vs_tag) { case 'DATE': $vs_format = urldecode(caGetOption('format', $va_tag_opts, 'd M Y')); $va_proc_templates[$vn_i] = str_replace("^{$vs_tag}", date($vs_format), $va_proc_templates[$vn_i]); continue 2; break; } $pa_options = array_merge($pa_options, $va_tag_opts); // Default label tag to hierarchies if (isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels'] && $vs_tag == 'label') { unset($va_related_values[$vs_pk_val][$vs_tag]); unset($va_relationship_values[$vs_pk_val][$vs_tag]); $va_tmp = array($ps_tablename, 'hierarchy', 'preferred_labels'); } if (!isset($va_relationship_values[$vs_pk_val])) { $va_relationship_values[$vs_pk_val] = array(0 => null); } foreach ($va_relationship_values[$vs_pk_val] as $vn_relation_id => $va_relationship_value_array) { $vb_is_related = false; $va_val = null; if (isset($va_relationship_value_array[$vs_tag]) && !(isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels'] && $vs_tag == 'label')) { $va_val = array($vs_val = $va_relationship_value_array[$vs_tag]); } elseif (isset($va_relationship_value_array[$vs_tag])) { $va_val = array($vs_val = $va_relationship_value_array[$vs_tag]); } else { if (isset($va_related_values[$vs_pk_val][$vs_tag])) { $va_val = array($vs_val = $va_related_values[$vs_pk_val][$vs_tag]); } else { // // see if this is a reference to a related table // if (in_array($vs_tag, array("relationship_typename", "relationship_type_id", "relationship_typecode", "relationship_type_code"))) { $vb_is_related = true; switch ($vs_tag) { case 'relationship_typename': $vs_spec = 'preferred_labels.' . (caGetOption('orientation', $pa_options, 'LTOR') == 'LTOR' ? 'typename' : 'typename_reverse'); break; case 'relationship_type_id': $vs_spec = 'type_id'; break; case 'relationship_typecode': case 'relationship_type_code': default: $vs_spec = 'type_code'; break; } $vs_rel = $qr_res->get("ca_relationship_types.{$vs_spec}", array_merge($pa_options, $va_tag_opts, array('returnAsArray' => false))); $va_val = array($vs_rel); } elseif ($ps_tablename != $va_tmp[0] && ($t_tmp = $o_dm->getInstanceByTableName($va_tmp[0], true))) { // if the part of the tag before a "." (or the tag itself if there are no periods) is a related table then try to fetch it as related to the current record if (isset($pa_options['placeholderPrefix']) && $pa_options['placeholderPrefix'] && $va_tmp[0] != $pa_options['placeholderPrefix'] && sizeof($va_tmp) == 1) { $vs_get_spec = array_shift($va_tmp) . "." . $pa_options['placeholderPrefix']; if (sizeof($va_tmp) > 0) { $vs_get_spec .= "." . join(".", $va_tmp); } } else { $vs_get_spec = $vs_tag; } $va_spec_bits = explode(".", $vs_get_spec); if (sizeof($va_spec_bits) == 1 && $o_dm->getTableNum($va_spec_bits[0])) { $vs_get_spec .= ".preferred_labels"; } $va_additional_options = array('returnAsArray' => true, 'checkAccess' => $pa_check_access); $vs_hierarchy_name = null; $vb_is_hierarchy = false; if (in_array($va_spec_bits[1], array('hierarchy', '_hierarchyName'))) { $t_rel = $o_dm->getInstanceByTableName($va_spec_bits[0], true); switch ($t_rel->getProperty('HIERARCHY_TYPE')) { case __CA_HIER_TYPE_SIMPLE_MONO__: $va_additional_options['removeFirstItems'] = 1; break; case __CA_HIER_TYPE_MULTI_MONO__: $vs_hierarchy_name = $t_rel->getHierarchyName($qr_res->get($t_rel->tableName() . "." . $t_rel->primaryKey(), array('checkAccess' => $pa_check_access))); $va_additional_options['removeFirstItems'] = 1; break; } } if ($va_spec_bits[1] != '_hierarchyName') { $va_val = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_additional_options, array('returnWithStructure' => true, 'returnBlankValues' => true, 'returnAllLocales' => true, 'useLocaleCodes' => false, 'filters' => $va_tag_filters, 'primaryIDs' => $va_primary_ids))); } else { $va_val = array(); } if (is_array($va_primary_ids) && isset($va_primary_ids[$va_spec_bits[0]]) && is_array($va_primary_ids[$va_spec_bits[0]])) { foreach ($va_primary_ids[$va_spec_bits[0]] as $vn_primary_id) { unset($va_val[$vn_primary_id]); } } if ($va_spec_bits[1] !== 'hierarchy') { $va_val = caExtractValuesByUserLocale($va_val); $va_val_tmp = array(); foreach ($va_val as $vn_d => $va_vals) { if (is_array($va_vals)) { $va_val_tmp = array_merge($va_val_tmp, array_values($va_vals)); } else { $va_val_tmp[] = $va_vals; } } $va_val = $va_val_tmp; } $va_val_proc = array(); switch ($va_spec_bits[1]) { case '_hierarchyName': if ($vs_hierarchy_name) { $va_val_proc[] = $vs_hierarchy_name; } break; case 'hierarchy': if (is_array($va_val) && sizeof($va_val) > 0) { $va_hier_list = array(); if ($vs_hierarchy_name) { array_unshift($va_hier_list, $vs_hierarchy_name); } $vs_name = end($va_spec_bits); foreach ($va_val as $va_hier) { $va_hier = caExtractValuesByUserLocale($va_hier); foreach ($va_hier as $va_hier_item) { foreach ($va_hier_item as $va_hier_value) { $va_hier_list[] = $va_hier_value[$vs_name] ? $va_hier_value[$vs_name] : array_shift($va_hier_value); } } } $va_val_proc[] = join(caGetOption("delimiter", $va_tag_opts, $vs_delimiter), $va_hier_list); } break; case 'parent': if (is_array($va_val)) { foreach ($va_val as $vm_label) { if (is_array($vm_label)) { $t_rel = $o_dm->getInstanceByTableName($va_spec_bits[0], true); if (!$t_rel || !method_exists($t_rel, "getLabelDisplayField")) { $va_val_proc[] = join("; ", $vm_label); } else { $va_val_proc[] = $vm_label[$t_rel->getLabelDisplayField()]; } } else { $va_val_proc[] = $vm_label; } } } break; default: $vs_terminal = end($va_spec_bits); foreach ($va_val as $va_val_container) { if (!is_array($va_val_container)) { if ($va_val_container) { $va_val_proc[] = $va_val_container; } continue; } // Add display field to *_labels terminals if (in_array($vs_terminal, array('preferred_labels', 'nonpreferred_labels')) && !$va_val_container[$vs_terminal]) { $t_rel = $o_dm->getInstanceByTableName($va_spec_bits[0], true); $vs_terminal = $t_rel->getLabelDisplayField(); } $va_val_proc[] = $va_val_container[$vs_terminal]; } break; } $va_val = $va_val_proc; $vb_is_related = true; } else { // // Handle non-related gets // // Default specifiers that end with a modifier to preferred labels if (sizeof($va_tmp) == 2 && in_array($va_tmp[1], array('hierarchy', 'children', 'parent', 'related'))) { array_push($va_tmp, 'preferred_labels'); } $vs_hierarchy_name = null; if (in_array($va_tmp[1], array('hierarchy', '_hierarchyName'))) { switch ($t_instance->getProperty('HIERARCHY_TYPE')) { case __CA_HIER_TYPE_SIMPLE_MONO__: $va_additional_options['removeFirstItems'] = 1; break; case __CA_HIER_TYPE_MULTI_MONO__: $vs_hierarchy_name = $t_instance->getHierarchyName($qr_res->get($t_instance->tableName() . "." . $t_instance->primaryKey(), array('checkAccess' => $pa_check_access))); $va_additional_options['removeFirstItems'] = 1; break; } } if ($va_tmp[0] == $ps_tablename) { array_shift($va_tmp); } // get rid of primary table if it's in the field spec if (!sizeof($va_tmp) && $t_instance->getProperty('LABEL_TABLE_NAME')) { $va_tmp[] = "preferred_labels"; } if (isset($pa_options['showHierarchicalLabels']) && $pa_options['showHierarchicalLabels']) { if (!in_array($va_tmp[0], array('hierarchy', 'children', 'parent', 'related')) && $va_tmp[1] == 'preferred_labels') { array_unshift($va_tmp, 'hierarchy'); } } if (isset($pa_options['placeholderPrefix']) && $pa_options['placeholderPrefix'] && $va_tmp[0] != $pa_options['placeholderPrefix']) { array_splice($va_tmp, -1, 0, $pa_options['placeholderPrefix']); } $vs_get_spec = "{$ps_tablename}." . join(".", $va_tmp); if (in_array($va_tmp[0], array('parent'))) { $va_val[] = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_tag_opts, array('returnAsArray' => false))); } elseif ($va_tmp[0] == '_hierarchyName') { $va_val[] = $vs_hierarchy_name; } else { $va_val_tmp = $qr_res->get($vs_get_spec, array_merge($pa_options, $va_tag_opts, array('returnAsArray' => true, 'returnBlankValues' => true, 'assumeDisplayField' => true, 'filters' => $va_tag_filters, 'checkAccess' => $pa_check_access))); $va_val = array(); if (is_array($va_val_tmp)) { //$va_val_tmp = array_reverse($va_val_tmp); if ($va_tmp[0] == 'hierarchy') { if ($vs_hierarchy_name) { array_shift($va_val_tmp); // remove root array_unshift($va_val_tmp, $vs_hierarchy_name); // replace with hierarchy name } if ($vs_delimiter_tmp = caGetOption('hierarchicalDelimiter', $va_tag_opts)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } elseif ($vs_delimiter_tmp = caGetOption('hierarchicalDelimiter', $pa_options)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } elseif ($vs_delimiter_tmp = caGetOption('delimiter', $va_tag_opts, $vs_delimiter)) { $vs_tag_val_delimiter = $vs_delimiter_tmp; } else { $vs_tag_val_delimiter = $vs_delimiter; } } else { $vs_tag_val_delimiter = caGetOption('delimiter', $va_tag_opts, $vs_delimiter); } foreach ($va_val_tmp as $vn_attr_id => $vm_attr_val) { if (is_array($vm_attr_val)) { $va_val[] = join($vs_tag_val_delimiter, $vm_attr_val); } else { $va_val[] = $vm_attr_val; } } } if (sizeof($va_val) > 1 && $va_tmp[0] == 'hierarchy') { $vs_tag_val_delimiter = caGetOption('delimiter', $va_tag_opts, $vs_delimiter); $va_val = array(join($vs_tag_val_delimiter, $va_val)); } } } } } if (is_array($va_val)) { if (sizeof($va_val) > 0) { foreach ($va_val as $vn_j => $vs_val) { if (!is_array($va_tag_val_list[$vn_i][$vn_j][$vs_tag]) || !in_array($vs_val, $va_tag_val_list[$vn_i][$vn_j][$vs_tag])) { $va_tag_val_list[$vn_i][$vn_j][$vs_tag][] = $vs_val; if (is_array($vs_val) && sizeof($vs_val) || strlen($vs_val) > 0) { $va_defined_tag_list[$vn_i][$vn_j][$vs_tag] = true; } } } } else { $va_tag_val_list[$vn_i][0][$vs_tag] = null; $va_defined_tag_list[$vn_i][0][$vs_tag] = false; } } } } $vn_i++; } foreach ($va_tag_val_list as $vn_i => $va_tags_list) { // do sorting? if (is_array($pa_sort)) { $va_sorted_values = $va_sorted_values_tmp = array(); foreach ($va_tags_list as $vn_j => $va_values_by_field) { $vs_key = ''; foreach ($pa_sort as $vn_k => $vs_sort) { if (!isset($va_values_by_field[$vs_sort])) { continue; } $vs_subkey = null; foreach ($va_values_by_field[$vs_sort] as $vn_x => $vs_sort_subval) { if ($va_date = caDateToHistoricTimestamps($vs_sort_subval)) { // try to treat it as a date if ($ps_sort_direction == 'DESC' && ($va_date[0] < $vs_subkey || is_null($vs_subkey))) { $vs_subkey = $va_date[0]; } elseif ($va_date[0] > $vs_subkey || is_null($vs_subkey)) { $vs_subkey = $va_date[0]; } } else { $vs_sort_subval = str_pad($vs_sort_subval, 20, ' ', STR_PAD_LEFT); if ($ps_sort_direction == 'DESC' && ($vs_sort_subval < $vs_subkey || is_null($vs_subkey))) { $vs_subkey = $vs_sort_subval; } elseif ($vs_sort_subval > $vs_subkey || is_null($vs_subkey)) { $vs_subkey = $vs_sort_subval; } } } $vs_key .= $vs_subkey; $va_sorted_values_tmp[$vs_key][] = $va_values_by_field; } } ksort($va_sorted_values_tmp); foreach ($va_sorted_values_tmp as $vs_key => $va_value_list) { foreach ($va_value_list as $vn_x => $va_val) { $va_sorted_values[$vs_key . $vn_x] = $va_val; } } if ($ps_sort_direction == 'DESC') { $va_sorted_values = array_reverse($va_sorted_values); } if (sizeof($va_sorted_values) > 0) { $va_tag_val_list[$vn_i] = $va_tags_list = $va_sorted_values; } } $va_acc = array(); foreach ($va_tags_list as $vn_j => $va_tags) { $va_tag_list = array(); $va_pt_vals = array(); $vs_template = $va_proc_templates[$vn_i]; // Process <if> foreach ($va_if as $va_def_con) { if (ExpressionParser::evaluate($va_def_con['rule'], $va_tags)) { $vs_template = str_replace($va_def_con['directive'], $va_def_con['content'], $vs_template); } else { $vs_template = str_replace($va_def_con['directive'], '', $vs_template); } } // Process <more> tags foreach ($va_mores as $vn_more_index => $va_more) { if (($vn_pos = strpos($vs_template, $va_more['directive'])) !== false) { if (isset($va_mores[$vn_more_index + 1]) && ($vn_next_more_pos = strpos(substr($vs_template, $vn_pos + strlen($va_more['directive'])), $va_mores[$vn_more_index + 1]['directive'])) !== false) { $vn_next_more_pos += $vn_pos; $vs_partial_template = substr($vs_template, $vn_pos + strlen($va_more['directive']), $vn_next_more_pos - $vn_pos); } else { $vs_partial_template = substr($vs_template, $vn_pos + strlen($va_more['directive'])); } $vb_output = false; foreach (array_keys($va_defined_tag_list[$vn_i][$vn_j]) as $vs_defined_tag) { if (strpos($vs_partial_template, $vs_defined_tag) !== false) { // content is defined $vb_output = true; break; } } if ($vb_output) { $vs_template = preg_replace('!' . $va_more['directive'] . '!', $va_more['content'], $vs_template, 1); } else { $vs_template = preg_replace('!' . $va_more['directive'] . '!', '', $vs_template, 1); } } } // Process <between> tags - text to be output if it is between two defined values $va_between_positions = array(); foreach ($va_betweens as $vn_between_index => $va_between) { $vb_output_before = $vb_output_after = false; if (($vn_cur_pos = strpos($vs_template, $va_between['directive'])) !== false) { $va_between_positions[$vn_between_index] = $vn_cur_pos; // Get parts of template before tag and after tag $vs_partial_template_before = substr($vs_template, 0, $vn_cur_pos); $vs_partial_template_after = substr($vs_template, $vn_cur_pos + strlen($va_between['directive'])); // Only get the template between our current position and the next <between> tag if (isset($va_betweens[$vn_between_index + 1]) && ($vn_after_pos_relative = strpos($vs_partial_template_after, $va_betweens[$vn_between_index + 1]['directive'])) !== false) { $vs_partial_template_after = substr($vs_partial_template_after, 0, $vn_after_pos_relative); } // Check for defined value before and after tag foreach (array_keys($va_defined_tag_list[$vn_i][$vn_j]) as $vs_defined_tag) { if (strpos($vs_partial_template_before, $vs_defined_tag) !== false) { // content is defined $vb_output_after = true; } if (strpos($vs_partial_template_after, $vs_defined_tag) !== false) { // content is defined $vb_output_before = true; break; } if ($vb_output_before && $vb_output_after) { break; } } } if ($vb_output_before && $vb_output_after) { $vs_template = preg_replace('!' . $va_between['directive'] . '!', $va_between['content'], $vs_template, 1); } else { $vs_template = preg_replace('!' . $va_between['directive'] . '!', '', $vs_template, 1); } } // // Need to sort tags by length descending (longest first) // so that when we go to substitute and you have a tag followed by itself with a suffix // (ex. ^measurements and ^measurements2) we don't substitute both for the stub (ex. ^measurements) // $va_tags_tmp = array_keys($va_tags); usort($va_tags_tmp, function ($a, $b) { return strlen($b) - strlen($a); }); $vs_pt = $vs_template; foreach ($va_tags_tmp as $vs_tag) { $vs_pt = str_replace('^' . $vs_tag, is_array($va_tags[$vs_tag]) ? join(" | ", $va_tags[$vs_tag]) : $va_tags[$vs_tag], $vs_pt); } if ($vs_pt) { $va_pt_vals[] = $vs_pt; } if ($vs_acc_val = join(isset($pa_options['delimiter']) ? $pa_options['delimiter'] : $vs_delimiter, $va_pt_vals)) { $va_acc[] = $vs_acc_val; } } $va_proc_templates[$vn_i] = join($vs_delimiter, $va_acc); } if ($pb_return_as_array && !caGetOption('includeBlankValuesInArray', $pa_options, false)) { foreach ($va_proc_templates as $vn_i => $vs_template) { if (!strlen(trim($vs_template))) { unset($va_proc_templates[$vn_i]); } } } // Transform links $va_proc_templates = caCreateLinksFromText($va_proc_templates, $ps_resolve_links_using, $ps_resolve_links_using != $ps_tablename ? $va_resolve_links_using_row_ids : $pa_row_ids, null, caGetOption('linkTarget', $pa_options, null), array_merge(array('addRelParameter' => true), $pa_options)); // Kill any lingering tags (just in case) foreach ($va_proc_templates as $vn_i => $vs_proc_template) { $va_proc_templates[$vn_i] = preg_replace("!\\^([A-Za-z0-9_\\.]+[%]{1}[^ \\^\t\r\n\"\\'<>\\(\\)\\{\\}\\/\\[\\]]*|[A-Za-z0-9_\\.]+)!", "", $vs_proc_template); $va_proc_templates[$vn_i] = str_replace("<![CDATA[", "", $va_proc_templates[$vn_i]); $va_proc_templates[$vn_i] = str_replace("]]>", "", $va_proc_templates[$vn_i]); } if ($pb_return_as_array) { return $va_proc_templates; } return join($vs_delimiter, $va_proc_templates); }
/** * */ private static function _processChildren(SearchResult $pr_res, $po_nodes, array $pa_vals, array $pa_options = null) { if (!is_array($pa_options)) { $pa_options = []; } if (!$po_nodes) { return ''; } $vs_acc = ''; $ps_tablename = $pr_res->tableName(); $o_dm = Datamodel::load(); $t_instance = $o_dm->getInstanceByTableName($ps_tablename, true); $ps_delimiter = caGetOption('delimiter', $pa_options, '; '); $pb_is_case = caGetOption('isCase', $pa_options, false, ['castTo' => 'boolean']); $pb_quote = caGetOption('quote', $pa_options, false, ['castTo' => 'boolean']); $pa_primary_ids = caGetOption('primaryIDs', $pa_options, null); $pb_include_blanks = caGetOption('includeBlankValuesInArray', $pa_options, false); unset($pa_options['quote']); $vn_last_unit_omit_count = null; foreach ($po_nodes as $vn_index => $o_node) { switch ($vs_tag = strtolower($o_node->tag)) { case 'case': if (!$pb_is_case) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, array_merge($pa_options, ['isCase' => true])); } break; case 'if': if (strlen($vs_rule = $o_node->rule) && ExpressionParser::evaluate($vs_rule, $pa_vals)) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), $pa_options); if ($pb_is_case) { break 2; } } break; case 'ifdef': case 'ifnotdef': $vb_defined = DisplayTemplateParser::_evaluateCodeAttribute($pr_res, $o_node, ['index' => caGetOption('index', $pa_options, null), 'mode' => $vs_tag == 'ifdef' ? 'present' : 'not_present']); if ($vs_tag == 'ifdef' && $vb_defined || $vs_tag == 'ifnotdef' && $vb_defined) { // Make sure returned values are not empty $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), $pa_options); if ($pb_is_case) { break 2; } } break; case 'ifcount': $vn_min = (int) $o_node->min; $vn_max = (int) $o_node->max; if (!is_array($va_codes = DisplayTemplateParser::_getCodesFromAttribute($o_node)) || !sizeof($va_codes)) { break; } $pa_check_access = $t_instance->hasField('access') ? caGetOption('checkAccess', $pa_options, null) : null; if (!is_array($pa_check_access) || !sizeof($pa_check_access)) { $pa_check_access = null; } $vb_bool = DisplayTemplateParser::_getCodesBooleanModeAttribute($o_node); $va_restrict_to_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToTypes']); $va_exclude_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeTypes']); $va_restrict_to_relationship_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToRelationshipTypes']); $va_exclude_to_relationship_types = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeRelationshipTypes']); $vm_count = $vb_bool == 'AND' ? 0 : []; foreach ($va_codes as $vs_code) { $va_vals = $pr_res->get($vs_code, ['checkAccess' => $pa_check_access, 'returnAsArray' => true, 'restrictToTypes' => $va_restrict_to_types, 'excludeTypes' => $va_exclude_types, 'restrictToRelationshipTypes' => $va_restrict_to_relationship_types, 'excludeRelationshipTypes' => $va_exclude_to_relationship_types]); if (is_array($va_vals)) { if ($vb_bool == 'AND') { $vm_count += sizeof($va_vals); } else { $vm_count[$vs_code] = sizeof($va_vals); } } } if ($vb_bool == 'AND') { if ($vn_min <= $vm_count && ($vn_max >= $vm_count || !$vn_max)) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), $pa_options); if ($pb_is_case) { break 2; } } } else { $vb_all_have_count = true; foreach ($vm_count as $vs_code => $vn_count) { if (!($vn_min <= $vn_count && ($vn_max >= $vn_count || !$vn_max))) { $vb_all_have_count = false; break 2; } } if ($vb_all_have_count) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); if ($pb_is_case) { break 2; } } } break; case 'more': // Does a placeholder with value follow this tag? // NOTE: We don't take into account <ifdef> and friends when finding a set placeholder; it may be set but not visible due to a conditional // This case is not covered at the moment on the assumption that if you're using <more> you're not using conditionals. This may or may not be a good assumption. for ($vn_i = $vn_index + 1; $vn_i < sizeof($po_nodes); $vn_i++) { if ($po_nodes[$vn_i] && $po_nodes[$vn_i]->tag == '~text~' && is_array($va_following_tags = caGetTemplateTags($po_nodes[$vn_i]->text))) { foreach ($va_following_tags as $vs_following_tag) { if (isset($pa_vals[$vs_following_tag]) && strlen($pa_vals[$vs_following_tag])) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); if ($pb_is_case) { break 2; } } } } } break; case 'between': // Does a placeholder with value precede this tag? // NOTE: We don't take into account <ifdef> and friends when finding a set placeholder; it may be set but not visible due to a conditional // This case is not covered at the moment on the assumption that if you're using <between> you're not using conditionals. This may or may not be a good assumption. $vb_has_preceding_value = false; for ($vn_i = 0; $vn_i < $vn_index; $vn_i++) { if ($po_nodes[$vn_i] && $po_nodes[$vn_i]->tag == '~text~' && is_array($va_preceding_tags = caGetTemplateTags($po_nodes[$vn_i]->text))) { foreach ($va_preceding_tags as $vs_preceding_tag) { if (isset($pa_vals[$vs_preceding_tag]) && strlen($pa_vals[$vs_preceding_tag])) { $vb_has_preceding_value = true; } } } } if ($vb_has_preceding_value) { // Does it have a value immediately following it? for ($vn_i = $vn_index + 1; $vn_i < sizeof($po_nodes); $vn_i++) { if ($po_nodes[$vn_i] && $po_nodes[$vn_i]->tag == '~text~' && is_array($va_following_tags = caGetTemplateTags($po_nodes[$vn_i]->text))) { foreach ($va_following_tags as $vs_following_tag) { if (isset($pa_vals[$vs_following_tag]) && strlen($pa_vals[$vs_following_tag])) { $vs_acc .= DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); if ($pb_is_case) { break 2; } } break; } } } } break; case 'expression': if ($vs_exp = trim($o_node->getInnerText())) { $vs_acc .= ExpressionParser::evaluate(DisplayTemplateParser::_processChildren($pr_res, $o_node->children, DisplayTemplateParser::_getValues($pr_res, DisplayTemplateParser::_getTags($o_node->children, $pa_options), $pa_options), array_merge($pa_options, ['quote' => true])), $pa_vals); if ($pb_is_case) { break 2; } } break; case 'unit': $va_relative_to_tmp = $o_node->relativeTo ? explode(".", $o_node->relativeTo) : [$ps_tablename]; if ($va_relative_to_tmp[0] && !($t_rel_instance = $o_dm->getInstanceByTableName($va_relative_to_tmp[0], true))) { continue; } $vn_last_unit_omit_count = 0; // <unit> attributes $vs_unit_delimiter = $o_node->delimiter ? (string) $o_node->delimiter : $ps_delimiter; $vb_unique = $o_node->unique ? (bool) $o_node->unique : false; $vb_aggregate_unique = $o_node->aggregateUnique ? (bool) $o_node->aggregateUnique : false; $vs_unit_skip_if_expression = (string) $o_node->skipIfExpression; $vn_start = (int) $o_node->start; $vn_length = (int) $o_node->length; $pa_check_access = $t_instance->hasField('access') ? caGetOption('checkAccess', $pa_options, null) : null; if (!is_array($pa_check_access) || !sizeof($pa_check_access)) { $pa_check_access = null; } // additional get options for pulling related records $va_get_options = ['returnAsArray' => true, 'checkAccess' => $pa_check_access]; $va_get_options['restrictToTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToTypes']); $va_get_options['excludeTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeTypes']); $va_get_options['restrictToRelationshipTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'restrictToRelationshipTypes']); $va_get_options['excludeRelationshipTypes'] = DisplayTemplateParser::_getCodesFromAttribute($o_node, ['attribute' => 'excludeRelationshipTypes']); if ($o_node->sort) { $va_get_options['sort'] = preg_split('![ ,;]+!', $o_node->sort); $va_get_options['sortDirection'] = $o_node->sortDirection; } if (sizeof($va_relative_to_tmp) == 1 && $va_relative_to_tmp[0] == $ps_tablename || sizeof($va_relative_to_tmp) >= 1 && $va_relative_to_tmp[0] == $ps_tablename && $va_relative_to_tmp[1] != 'related') { $vs_relative_to_container = null; switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'siblings': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".siblings." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: // If relativeTo is not set to a valid attribute try to guess from template if ($t_rel_instance->isValidMetadataElement(join(".", array_slice($va_relative_to_tmp, 1, 1)), true)) { $vs_relative_to_container = join(".", array_slice($va_relative_to_tmp, 0, 2)); } else { $va_tags = caGetTemplateTags($o_node->getInnerText()); foreach ($va_tags as $vs_tag) { $va_tag = explode('.', $vs_tag); while (sizeof($va_tag) > 1) { $vs_end = array_pop($va_tag); if ($t_rel_instance->isValidMetadataElement($vs_end, true)) { $va_tag[] = $vs_end; $vs_relative_to_container = join(".", $va_tag); break 2; } } } } $va_relative_ids = array($pr_res->getPrimaryKey()); break; } // process template for all records selected by unit tag $va_tmpl_val = DisplayTemplateParser::evaluate($o_node->getInnerText(), $ps_tablename, $va_relative_ids, array_merge($pa_options, ['sort' => $va_get_options['sort'], 'sortDirection' => $va_get_options['sortDirection'], 'returnAsArray' => true, 'delimiter' => $vs_unit_delimiter, 'skipIfExpression' => $vs_unit_skip_if_expression, 'placeholderPrefix' => (string) $o_node->relativeTo, 'restrictToTypes' => $va_get_options['restrictToTypes'], 'excludeTypes' => $va_get_options['excludeTypes'], 'isUnit' => true, 'unitStart' => $vn_start, 'unitLength' => $vn_length, 'relativeToContainer' => $vs_relative_to_container, 'includeBlankValuesInTopLevelForPrefetch' => false, 'unique' => $vb_unique, 'aggregateUnique' => $vb_aggregate_unique])); if ($vb_unique) { $va_tmpl_val = array_unique($va_tmpl_val); } if ($vn_start > 0 || !is_null($vn_length)) { $vn_last_unit_omit_count = sizeof($va_tmpl_val) - ($vn_length - $vn_start); } if (caGetOption('returnAsArray', $pa_options, false)) { return $va_tmpl_val; } $vs_acc .= join($vs_unit_delimiter, $va_tmpl_val); if ($pb_is_case) { break 2; } } else { switch (strtolower($va_relative_to_tmp[1])) { case 'hierarchy': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".hierarchy." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'parent': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".parent." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'children': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".children." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'siblings': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".siblings." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; case 'related': $va_relative_ids = $pr_res->get($t_rel_instance->tableName() . ".related." . $t_rel_instance->primaryKey(), $va_get_options); $va_relative_ids = array_values($va_relative_ids); break; default: if (method_exists($t_instance, 'isSelfRelationship') && $t_instance->isSelfRelationship() && is_array($pa_primary_ids) && isset($pa_primary_ids[$t_rel_instance->tableName()])) { $va_relative_ids = array_values($t_instance->getRelatedIDsForSelfRelationship($pa_primary_ids[$t_rel_instance->tableName()], array($pr_res->getPrimaryKey()))); } else { $va_relative_ids = $pr_res->get($t_rel_instance->primaryKey(true), $va_get_options); $va_relative_ids = is_array($va_relative_ids) ? array_values($va_relative_ids) : array(); } break; } $va_tmpl_val = DisplayTemplateParser::evaluate($o_node->getInnerText(), $va_relative_to_tmp[0], $va_relative_ids, array_merge($pa_options, ['sort' => $va_unit['sort'], 'sortDirection' => $va_unit['sortDirection'], 'delimiter' => $vs_unit_delimiter, 'returnAsArray' => true, 'skipIfExpression' => $vs_unit_skip_if_expression, 'placeholderPrefix' => (string) $o_node->relativeTo, 'restrictToTypes' => $va_get_options['restrictToTypes'], 'excludeTypes' => $va_get_options['excludeTypes'], 'isUnit' => true, 'unitStart' => $vn_start, 'unitLength' => $vn_length, 'includeBlankValuesInTopLevelForPrefetch' => false, 'unique' => $vb_unique, 'aggregateUnique' => $vb_aggregate_unique])); if ($vb_unique) { $va_tmpl_val = array_unique($va_tmpl_val); } if ($vn_start > 0 || !is_null($vn_length)) { $vn_num_vals = sizeof($va_tmpl_val); $va_tmpl_val = array_slice($va_tmpl_val, $vn_start, $vn_length > 0 ? $vn_length : null); $vn_last_unit_omit_count = $vn_num_vals - ($vn_length - $vn_start); } if (caGetOption('returnAsArray', $pa_options, false)) { return $va_tmpl_val; } $vs_acc .= join($vs_unit_delimiter, $va_tmpl_val); if ($pb_is_case) { break 2; } } break; case 'whenunitomits': if ($vn_last_unit_omit_count > 0) { $vs_proc_template = caProcessTemplate($o_node->getInnerText(), array_merge($pa_vals, ['omitcount' => (int) $vn_last_unit_omit_count]), ['quote' => $pb_quote]); $vs_acc .= $vs_proc_template; } break; default: if ($o_node->children && sizeof($o_node->children) > 0) { $vs_proc_template = DisplayTemplateParser::_processChildren($pr_res, $o_node->children, $pa_vals, $pa_options); } else { $vs_proc_template = caProcessTemplate($o_node->html(), $pa_vals, ['quote' => $pb_quote]); } if ($vs_tag === 'l') { $va_proc_templates = caCreateLinksFromText(["{$vs_proc_template}"], $ps_tablename, [$pr_res->getPrimaryKey()], null, caGetOption('linkTarget', $pa_options, null), array_merge(['addRelParameter' => true, 'requireLinkTags' => false], $pa_options)); $vs_proc_template = array_shift($va_proc_templates); } elseif (strlen($vs_tag) && $vs_tag[0] !== '~') { if ($o_node->children && sizeof($o_node->children) > 0) { $vs_attr = ''; if ($o_node->attributes) { foreach ($o_node->attributes as $attribute => $value) { $vs_attr .= " {$attribute}=\"" . htmlspecialchars(caProcessTemplate($value, $pa_vals, ['quote' => $pb_quote])) . "\""; } } $vs_proc_template = "<{$vs_tag}{$vs_attr}>{$vs_proc_template}</{$vs_tag}>"; } elseif ($o_node->attributes && sizeof($o_node->attributes) > 0) { $vs_attr = ''; foreach ($o_node->attributes as $attribute => $value) { $vs_attr .= " {$attribute}=\"" . htmlspecialchars(caProcessTemplate($value, $pa_vals, ['quote' => $pb_quote])) . "\""; } switch (strtolower($vs_tag)) { case 'br': case 'hr': case 'meta': case 'link': case 'base': case 'img': case 'embed': case 'param': case 'area': case 'col': case 'input': $vs_proc_template = "<{$vs_tag}{$vs_attr} />"; break; default: $vs_proc_template = "<{$vs_tag}{$vs_attr}></{$vs_tag}>"; break; } } else { $vs_proc_template = $o_node->html(); } } $vs_acc .= $vs_proc_template; break; } } return $vs_acc; }
/** * */ public function validateUsingMetadataDictionaryRules($pa_options = null) { if (!$this->getPrimaryKey()) { return null; } $o_db = $this->getDb(); $o_dm = Datamodel::load(); $t_violation = new ca_metadata_dictionary_rule_violations(); $va_rules = ca_metadata_dictionary_rules::getRules(array('bundles' => caGetOption('bundles', $pa_options, null))); $vn_violation_count = 0; $va_violations = array(); foreach ($va_rules as $va_rule) { $va_expression_tags = caGetTemplateTags($va_rule['expression']); $t_violation->clear(); $vb_skip = !$this->hasBundle($va_rule['bundle_name'], $this->getTypeID()); if (!$vb_skip) { // create array of values present in rule $va_row = array($va_rule['bundle_name'] => $vs_val = $this->get($va_rule['bundle_name'])); foreach ($va_expression_tags as $vs_tag) { $va_row[$vs_tag] = $this->get($vs_tag); } } // is there a violation recorded for this rule and row? if ($t_found = ca_metadata_dictionary_rule_violations::find(array('rule_id' => $va_rule['rule_id'], 'row_id' => $this->getPrimaryKey(), 'table_num' => $this->tableNum()), array('returnAs' => 'firstModelInstance'))) { $t_violation = $t_found; } if (!$vb_skip && ExpressionParser::evaluate($va_rule['expression'], $va_row)) { // violation if ($t_violation->getPrimaryKey()) { $t_violation->setMode(ACCESS_WRITE); $t_violation->update(); } else { $t_violation->setMode(ACCESS_WRITE); $t_violation->set('rule_id', $va_rule['rule_id']); $t_violation->set('table_num', $this->tableNum()); $t_violation->set('row_id', $this->getPrimaryKey()); $t_violation->insert(); } $va_violations[$va_rule['rule_level']][$va_rule['bundle_name']][] = $va_rule; $vn_violation_count++; } else { if ($t_violation->getPrimaryKey()) { $t_violation->setMode(ACCESS_WRITE); $t_violation->delete(true); // remove violation } } } return $va_violations; }
/** * get() value for attribute * * @param array $pa_value_list * @param BaseModel $pt_instance * @param array Options * * @return array|string */ private function _getAttributeValue($pa_value_list, $pt_instance, $pa_options) { $va_path_components =& $pa_options['pathComponents']; $vs_delimiter = isset($pa_options['delimiter']) ? $pa_options['delimiter'] : ';'; $va_return_values = array(); $vn_id = $this->get($pt_instance->primaryKey(true)); $vs_table_name = $pt_instance->tableName(); if (is_array($pa_value_list) && sizeof($pa_value_list)) { $va_val_proc = array(); foreach ($pa_value_list as $o_attribute) { $t_attr_element = $pt_instance->_getElementInstance($o_attribute->getElementID()); $vn_attr_type = $t_attr_element->get('datatype'); $va_acc = array(); $va_values = $o_attribute->getValues(); if ($pa_options['useLocaleCodes']) { if (!$o_attribute->getLocaleID() || !($vm_locale_id = SearchResult::$opo_locales->localeIDToCode($o_attribute->getLocaleID()))) { $vm_locale_id = __CA_DEFAULT_LOCALE__; } } else { if (!($vm_locale_id = $o_attribute->getLocaleID())) { $vm_locale_id = SearchResult::$opo_locales->localeCodeToID(__CA_DEFAULT_LOCALE__); } } $vb_did_return_value = false; foreach ($va_values as $o_value) { $vs_val_proc = null; $vb_dont_return_value = false; $vs_element_code = $o_value->getElementCode(); $va_auth_spec = null; if (is_a($o_value, "AuthorityAttributeValue")) { $va_auth_spec = $va_path_components['components']; if ($pt_instance->hasElement($va_path_components['subfield_name'], null, true, array('dontCache' => false))) { array_shift($va_auth_spec); array_shift($va_auth_spec); array_shift($va_auth_spec); } elseif ($pt_instance->hasElement($va_path_components['field_name'], null, true, array('dontCache' => false))) { array_shift($va_auth_spec); array_shift($va_auth_spec); $va_path_components['subfield_name'] = null; } } if ($va_path_components['subfield_name'] && $va_path_components['subfield_name'] !== $vs_element_code && !$o_value instanceof InformationServiceAttributeValue) { $vb_dont_return_value = true; if (!$pa_options['filter']) { continue; } } if (is_a($o_value, "AuthorityAttributeValue") && sizeof($va_auth_spec) > 0) { array_unshift($va_auth_spec, $vs_auth_table_name = $o_value->tableName()); if ($qr_res = caMakeSearchResult($vs_auth_table_name, array($o_value->getID()))) { if ($qr_res->nextHit()) { unset($pa_options['returnWithStructure']); $va_options['returnAsArray'] = true; $va_val_proc = $qr_res->get(join(".", $va_auth_spec), $pa_options); if (is_array($va_val_proc)) { foreach ($va_val_proc as $vn_i => $vs_v) { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID() . "_{$vn_i}"][$vs_element_code] = $vs_v; } } } } continue; } if (is_null($vs_val_proc)) { switch ($o_value->getType()) { case __CA_ATTRIBUTE_VALUE_LIST__: $t_element = $pt_instance->_getElementInstance($o_value->getElementID()); $vn_list_id = $t_element->get('list_id'); $vs_val_proc = $o_value->getDisplayValue(array_merge($pa_options, array('output' => $pa_options['output'], 'list_id' => $vn_list_id))); break; case __CA_ATTRIBUTE_VALUE_INFORMATIONSERVICE__: //ca_objects.informationservice.ulan_container // support subfield notations like ca_objects.wikipedia.abstract, but only if we're not already at subfield-level, e.g. ca_objects.container.wikipedia if ($va_path_components['subfield_name'] && $vs_element_code != $va_path_components['subfield_name'] && $vs_element_code == $va_path_components['field_name']) { $vs_val_proc = $o_value->getExtraInfo($va_path_components['subfield_name']); $vb_dont_return_value = false; break; } // support ca_objects.container.wikipedia.abstract if ($vs_element_code == $va_path_components['subfield_name'] && $va_path_components['num_components'] == 4) { $vs_val_proc = $o_value->getExtraInfo($va_path_components['components'][3]); $vb_dont_return_value = false; break; } // support ca_objects.wikipedia or ca_objects.container.wikipedia (Eg. no "extra" value specified) if ($vs_element_code == $va_path_components['field_name'] || $vs_element_code == $va_path_components['subfield_name']) { $vs_val_proc = $o_value->getDisplayValue(array_merge($pa_options, array('output' => $pa_options['output']))); $vb_dont_return_value = false; break; } continue 2; default: $vs_val_proc = $o_value->getDisplayValue(array_merge($pa_options, array('output' => $pa_options['output']))); break; } } if ($vn_attr_type == __CA_ATTRIBUTE_VALUE_CONTAINER__ && !$va_path_components['subfield_name'] && !$pa_options['returnWithStructure']) { if (strlen($vs_val_proc) > 0) { $va_val_proc[] = $vs_val_proc; } $vs_val_proc = join($vs_delimiter, $va_val_proc); } $va_spec = $va_path_components['components']; array_pop($va_spec); $va_acc[join('.', $va_spec) . '.' . $vs_element_code] = $o_value->getDisplayValue(array_merge($pa_options, array('output' => 'idno'))); if (!$vb_dont_return_value) { $vb_did_return_value = true; if ($pa_options['makeLink']) { $vs_val_proc = array_shift(caCreateLinksFromText(array($vs_val_proc), $vs_table_name, array($vn_id))); } if ($pa_options['returnWithStructure']) { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()][$vs_element_code] = $vs_val_proc; } else { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()] = $vs_val_proc; } } } if ($va_path_components['subfield_name'] && $pa_options['returnBlankValues'] && !$vb_did_return_value) { // value is missing so insert blank if ($pa_options['returnWithStructure']) { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()][$va_path_components['subfield_name']] = ''; } else { $va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()] = ''; } } if ($pa_options['filter']) { $va_tags = caGetTemplateTags($pa_options['filter']); $va_vars = array(); foreach ($va_tags as $vs_tag) { if (isset($va_acc[$vs_tag])) { $va_vars[$vs_tag] = $va_acc[$vs_tag]; } else { $va_vars[$vs_tag] = $this->get($vs_tag, array('convertCodesToIdno' => true)); } } if (ExpressionParser::evaluate($pa_options['filter'], $va_vars)) { unset($va_return_values[(int) $vn_id][$vm_locale_id][(int) $o_attribute->getAttributeID()]); continue; } } } } else { // is blank if ($pa_options['returnWithStructure'] && $pa_options['returnBlankValues']) { $va_return_values[(int) $vn_id][null][null][$va_path_components['subfield_name'] ? $va_path_components['subfield_name'] : $va_path_components['field_name']] = ''; } } if (!$pa_options['returnAllLocales']) { $va_return_values = caExtractValuesByUserLocale($va_return_values); } if ($pa_options['returnWithStructure']) { return is_array($va_return_values) ? $va_return_values : array(); } // // Flatten array for return as string or simple array value // $va_flattened_values = $this->_flattenArray($va_return_values, $pa_options); if ($pa_options['returnAsArray']) { return $va_flattened_values; } else { return sizeof($va_flattened_values) > 0 ? join($pa_options['delimiter'], $va_flattened_values) : null; } }
/** * */ public static function validate_using_metadata_dictionary_rules($po_opts = null) { require_once __CA_MODELS_DIR__ . '/ca_metadata_dictionary_rules.php'; require_once __CA_MODELS_DIR__ . '/ca_metadata_dictionary_rule_violations.php'; $o_dm = Datamodel::load(); $t_violation = new ca_metadata_dictionary_rule_violations(); $va_rules = ca_metadata_dictionary_rules::getRules(); print CLIProgressBar::start(sizeof($va_rules), _t('Evaluating')); $vn_total_rows = $vn_rule_num = 0; $vn_num_rules = sizeof($va_rules); foreach ($va_rules as $va_rule) { $vn_rule_num++; $va_expression_tags = caGetTemplateTags($va_rule['expression']); $va_tmp = explode(".", $va_rule['bundle_name']); if (!($t_instance = $o_dm->getInstanceByTableName($va_tmp[0]))) { CLIUtils::addError(_t("Table for bundle %1 is not valid", $va_tmp[0])); continue; } $vs_bundle_name_proc = str_replace("{$vs_table_name}.", "", $va_rule['bundle_name']); $vn_table_num = $t_instance->tableNum(); $qr_records = call_user_func_array(($vs_table_name = $t_instance->tableName()) . "::find", array(array('deleted' => 0), array('returnAs' => 'searchResult'))); if (!$qr_records) { continue; } $vn_total_rows += $qr_records->numHits(); CLIProgressBar::setTotal($vn_total_rows); $vn_count = 0; while ($qr_records->nextHit()) { $vn_count++; print CLIProgressBar::next(1, _t("Rule %1 [%2/%3]: record %4", $va_rule['rule_settings']['label'], $vn_rule_num, $vn_num_rules, $vn_count)); $t_violation->clear(); $vn_id = $qr_records->getPrimaryKey(); $vb_skip = !$t_instance->hasBundle($va_rule['bundle_name'], $qr_records->get('type_id')); if (!$vb_skip) { // create array of values present in rule $va_row = array($va_rule['bundle_name'] => $vs_val = $qr_records->get($va_rule['bundle_name'])); foreach ($va_expression_tags as $vs_tag) { $va_row[$vs_tag] = $qr_records->get($vs_tag); } } // is there a violation recorded for this rule and row? if ($t_found = ca_metadata_dictionary_rule_violations::find(array('rule_id' => $va_rule['rule_id'], 'row_id' => $vn_id, 'table_num' => $vn_table_num), array('returnAs' => 'firstModelInstance'))) { $t_violation = $t_found; } if (!$vb_skip && ExpressionParser::evaluate($va_rule['expression'], $va_row)) { // violation if ($t_violation->getPrimaryKey()) { $t_violation->setMode(ACCESS_WRITE); $t_violation->update(); } else { $t_violation->setMode(ACCESS_WRITE); $t_violation->set('rule_id', $va_rule['rule_id']); $t_violation->set('table_num', $t_instance->tableNum()); $t_violation->set('row_id', $qr_records->getPrimaryKey()); $t_violation->insert(); } } else { if ($t_violation->getPrimaryKey()) { $t_violation->delete(true); // remove violation } } } } print CLIProgressBar::finish(); }
/** * Returns list of variables defined in the expression * * @param string $ps_expression * @return array */ public static function getVariableList($ps_expression) { return caGetTemplateTags($ps_expression); }
/** * Replace "^" prefix-edtags (eg. ^forename) in a template with values from an array * * @param string $ps_template String with embedded tags. Tags are just alphanumeric strings prefixed with a caret ("^") * @param array $pa_values Array of values; keys must match tag names * @param array $pa_options Supported options are: * prefix = string to add to beginning of tags extracted from template before doing lookup into value array * removePrefix = string to remove from tags extracted from template before doing lookup into value array * getFrom = a model instance to draw data from. If set, $pa_values is ignored. * * @return string Output of processed template */ function caProcessTemplate($ps_template, $pa_values, $pa_options = null) { $vs_prefix = isset($pa_options['prefix']) ? $pa_options['prefix'] : null; $vs_remove_prefix = isset($pa_options['removePrefix']) ? $pa_options['removePrefix'] : null; $va_tags = caGetTemplateTags($ps_template); $t_instance = null; if (isset($pa_options['getFrom']) && method_exists($pa_options['getFrom'], 'get')) { $t_instance = $pa_options['getFrom']; } foreach ($va_tags as $vs_tag) { $va_tmp = explode("~", $vs_tag); $vs_proc_tag = array_shift($va_tmp); if ($vs_remove_prefix) { $vs_proc_tag = str_replace($vs_remove_prefix, '', $vs_proc_tag); } if ($vs_prefix) { $vs_proc_tag = $vs_prefix . $vs_proc_tag; } if ($t_instance && ($vs_gotten_val = $t_instance->get($vs_proc_tag, $pa_options))) { $vs_gotten_val = caProcessTemplateTagDirectives($vs_gotten_val, $va_tmp); $ps_template = str_replace('^' . $vs_tag, $vs_gotten_val, $ps_template); } else { if (is_array($vs_val = isset($pa_values[$vs_proc_tag]) ? $pa_values[$vs_proc_tag] : '')) { // If value is an array try to make a string of it $vs_val = join(" ", $vs_val); } $vs_val = caProcessTemplateTagDirectives($vs_val, $va_tmp); $ps_template = preg_replace("!\\^(?={$vs_tag}[^A-Za-z0-9]+|{$vs_tag}\$){$vs_tag}!", $vs_val, $ps_template); } } return $ps_template; }
/** * Replace "^" prefix-edtags (eg. ^forename) in a template with values from an array * * @param string $ps_template String with embedded tags. Tags are just alphanumeric strings prefixed with a caret ("^") * @param array $pa_values Array of values; keys must match tag names * @param array $pa_options Supported options are: * prefix = string to add to beginning of tags extracted from template before doing lookup into value array * removePrefix = string to remove from tags extracted from template before doing lookup into value array * getFrom = a model instance to draw data from. If set, $pa_values is ignored. * quote = quote replacement values (Eg. ^ca_objects.idno becomes "2015.001" rather than 2015.001). Value containing quotes will be escaped with a backslash. [Default is false] * * @return string Output of processed template */ function caProcessTemplate($ps_template, $pa_values, $pa_options = null) { $ps_prefix = caGetOption('prefix', $pa_options, null); $ps_remove_prefix = caGetOption('removePrefix', $pa_options, null); $pb_quote = caGetOption('quote', $pa_options, false); $va_tags = caGetTemplateTags($ps_template); $t_instance = null; if (isset($pa_options['getFrom']) && method_exists($pa_options['getFrom'], 'get')) { $t_instance = $pa_options['getFrom']; } foreach ($va_tags as $vs_tag) { $va_tmp = explode("~", $vs_tag); $vs_proc_tag = array_shift($va_tmp); if ($ps_remove_prefix) { $vs_proc_tag = str_replace($ps_remove_prefix, '', $vs_proc_tag); } if ($ps_prefix && !preg_match("!^" . preg_quote($ps_prefix, "!") . "!", $vs_proc_tag)) { $vs_proc_tag = $ps_prefix . $vs_proc_tag; } if ($t_instance && ($vs_gotten_val = $t_instance->get($vs_proc_tag, $pa_options))) { $vs_gotten_val = caProcessTemplateTagDirectives($vs_gotten_val, $va_tmp); $ps_template = preg_replace("/\\^" . preg_quote($vs_tag, '/') . "(?![A-Za-z0-9]+)/", $vs_gotten_val, $ps_template); } else { if (is_array($vs_val = isset($pa_values[$vs_proc_tag]) ? $pa_values[$vs_proc_tag] : '')) { // If value is an array try to make a string of it $vs_val = join(" ", $vs_val); } $vs_val = caProcessTemplateTagDirectives($vs_val, $va_tmp); if ($pb_quote) { $vs_val = '"' . addslashes($vs_val) . '"'; } $ps_template = preg_replace("!\\^(?={$vs_tag}[^A-Za-z0-9]+|{$vs_tag}\$){$vs_tag}!", str_replace("\$", "\\\$", $vs_val), $ps_template); // escape "$" to prevent interpretation as backreferences } } return $ps_template; }