Esempio n. 1
0
/**
 * 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);
}
Esempio n. 2
0
 /**
  * Checks if a relationship exists between the currently loaded row and the specified target
  *
  * @param mixed $pm_rel_table_name_or_num Table name (eg. "ca_entities") or number as defined in datamodel.conf of table containing row to creation relationship to.
  * @param int $pn_rel_id primary key value of row to creation relationship to.
  * @param mixed $pm_type_id Relationship type type_code or type_id, as defined in the ca_relationship_types table. This is required for all relationships that use relationship types. This includes all of the most common types of relationships.
  * @param string $ps_effective_date Optional date expression to qualify relation with. Any expression that the TimeExpressionParser can handle is supported here.
  * @param string $ps_direction Optional direction specification for self-relationships (relationships linking two rows in the same table). Valid values are 'ltor' (left-to-right) and  'rtol' (right-to-left); the direction determines which "side" of the relationship the currently loaded row is on: 'ltor' puts the current row on the left side. For many self-relations the direction determines the nature and display text for the relationship.
  * @param array $pa_options Options are:
  *		relation_id = an optional relation_id to ignore when checking for existence. If you are checking for relations other than one you know exists you can set this to ensure that relationship is not considered.
  *
  * @return mixed Array of matched relation_ids on success, false on error.
  */
 public function relationshipExists($pm_rel_table_name_or_num, $pn_rel_id, $pm_type_id = null, $ps_effective_date = null, $ps_direction = null, $pa_options = null)
 {
     if (!($va_rel_info = $this->_getRelationshipInfo($pm_rel_table_name_or_num))) {
         $this->postError(1240, _t('Related table specification "%1" is not valid', $pm_rel_table_name_or_num), 'BaseModel->addRelationship()');
         return false;
     }
     $vn_relation_id = isset($pa_options['relation_id']) && (int) $pa_options['relation_id'] ? (int) $pa_options['relation_id'] : null;
     $vs_relation_id_sql = null;
     $t_item_rel = $va_rel_info['t_item_rel'];
     if ($pm_type_id && !is_numeric($pm_type_id)) {
         $t_rel_type = new ca_relationship_types();
         if ($vs_linking_table = $t_rel_type->getRelationshipTypeTable($this->tableName(), $t_item_rel->tableName())) {
             $pn_type_id = $t_rel_type->getRelationshipTypeID($vs_linking_table, $pm_type_id);
         }
     } else {
         $pn_type_id = $pm_type_id;
     }
     if (!is_numeric($pn_rel_id)) {
         if ($t_rel_item = $this->_DATAMODEL->getInstanceByTableName($va_rel_info['related_table_name'], true)) {
             if ($this->inTransaction()) {
                 $t_rel_item->setTransaction($this->getTransaction());
             }
             if (($vs_idno_fld = $t_rel_item->getProperty('ID_NUMBERING_ID_FIELD')) && $t_rel_item->load(array($vs_idno_fld => $pn_rel_id))) {
                 $pn_rel_id = $t_rel_item->getPrimaryKey();
             }
         }
     }
     $va_query_params = array();
     $o_db = $this->getDb();
     if (($t_item_rel = $va_rel_info['t_item_rel']) && method_exists($t_item_rel, 'getLeftTableName')) {
         $vs_rel_table_name = $t_item_rel->tableName();
         $vs_type_sql = $vs_timestamp_sql = '';
         $vs_left_table_name = $t_item_rel->getLeftTableName();
         $vs_left_field_name = $t_item_rel->getLeftTableFieldName();
         $vs_right_table_name = $t_item_rel->getRightTableName();
         $vs_right_field_name = $t_item_rel->getRightTableFieldName();
         if ($va_rel_info['related_table_name'] == $this->tableName()) {
             // is self relation
             if ($ps_direction == 'rtol') {
                 $vn_left_id = (int) $pn_rel_id;
                 $vn_right_id = (int) $this->getPrimaryKey();
             } else {
                 $vn_left_id = (int) $this->getPrimaryKey();
                 $vn_right_id = (int) $pn_rel_id;
             }
         } else {
             if ($vs_left_table_name == $this->tableName()) {
                 $vn_left_id = (int) $this->getPrimaryKey();
                 $vn_right_id = (int) $pn_rel_id;
             } else {
                 $vn_left_id = (int) $pn_rel_id;
                 $vn_right_id = (int) $this->getPrimaryKey();
             }
         }
         $va_query_params = array($vn_left_id, $vn_right_id);
         if ($t_item_rel->hasField('type_id')) {
             $vs_type_sql = ' AND type_id = ?';
             $va_query_params[] = (int) $pn_type_id;
         }
         if ($ps_effective_date && $t_item_rel->hasField('sdatetime') && ($va_timestamps = caDateToHistoricTimestamps($ps_effective_date))) {
             $vs_timestamp_sql = " AND (sdatetime = ? AND edatetime = ?)";
             $va_query_params[] = (double) $va_timestamps['start'];
             $va_query_params[] = (double) $va_timestamps['end'];
         }
         if ($vn_relation_id) {
             $vs_relation_id_sql = " AND relation_id <> ?";
             $va_query_params[] = $vn_relation_id;
         }
         $qr_res = $o_db->query("\n\t\t\t\tSELECT relation_id\n\t\t\t\tFROM {$vs_rel_table_name}\n\t\t\t\tWHERE\n\t\t\t\t\t{$vs_left_field_name} = ? AND {$vs_right_field_name} = ?\n\t\t\t\t\t{$vs_type_sql} {$vs_timestamp_sql} {$vs_relation_id_sql}\n\t\t\t", $va_query_params);
         $va_ids = $qr_res->getAllFieldValues('relation_id');
         if ($va_rel_info['related_table_name'] == $this->tableName()) {
             $qr_res = $o_db->query("\n\t\t\t\t\tSELECT relation_id\n\t\t\t\t\tFROM {$vs_rel_table_name}\n\t\t\t\t\tWHERE\n\t\t\t\t\t\t{$vs_right_field_name} = ? AND {$vs_left_field_name} = ?\n\t\t\t\t\t\t{$vs_type_sql} {$vs_timestamp_sql} {$vs_relation_id_sql}\n\t\t\t\t", $va_query_params);
             $va_ids += $qr_res->getAllFieldValues('relation_id');
         }
         if (sizeof($va_ids)) {
             return $va_ids;
         }
     } else {
         if (sizeof($va_rel_info['path']) == 2) {
             // many-one rel
             $va_rel_keys = $va_rel_info['rel_keys'];
             $vb_is_one_table = $this->tableName() == $va_rel_keys['one_table'] ? true : false;
             $vs_where_sql = "(ot." . $va_rel_keys['one_table_field'] . " = ?) AND (mt." . $va_rel_keys['many_table_field'] . " = ?)";
             if ($vb_is_one_table) {
                 $va_query_params[] = (int) $this->getPrimaryKey();
                 $va_query_params[] = (int) $pn_rel_id;
             } else {
                 $va_query_params[] = (int) $pn_rel_id;
                 $va_query_params[] = (int) $this->getPrimaryKey();
             }
             $vs_relation_id_fld = $vb_is_one_table ? "mt." . $va_rel_keys['many_table_field'] : "ot." . $va_rel_keys['one_table_field'];
             $qr_res = $o_db->query($x = "\n\t\t\t\t\tSELECT {$vs_relation_id_fld}\n\t\t\t\t\tFROM {$va_rel_keys['one_table']} ot\n\t\t\t\t\tINNER JOIN {$va_rel_keys['many_table']} AS mt ON mt.{$va_rel_keys['many_table_field']} = ot.{$va_rel_keys['one_table_field']}\n\t\t\t\t\tWHERE\n\t\t\t\t\t\t{$vs_where_sql}\n\t\t\t\t", $va_query_params);
             if (sizeof($va_ids = $qr_res->getAllFieldValues($vs_relation_id_fld))) {
                 return $va_ids;
             }
         }
     }
     return false;
 }
 /**
  * Find row(s) with fields having values matching specific values. 
  * Results can be returned as model instances, numeric ids or search results (when possible).
  *
  * Exact matching is performed using values in $pa_values. Partial and pattern matching are not supported. Searches may include
  * multiple fields with boolean AND and OR. For example, you can find ca_objects rows with idno = 2012.001 and access = 1 by passing the
  * "boolean" option as "AND" and $pa_values set to array("idno" => "2012.001", "access" => 1).
  * You could find all rows with either the idno or the access values by setting "boolean" to "OR"
  *
  * Keys in the $pa_values parameters must be valid fields in the table which the model sub-class represents. You may also search on preferred and
  * non-preferred labels by specified keys and values for label table fields in "preferred_labels" and "nonpreferred_labels" sub-arrays. For example:
  *
  * array("idno" => 2012.001", "access" => 1, "preferred_labels" => array("name" => "Luna Park at Night"))
  *
  * will find rows with the idno, access and preferred label values.
  *
  * LabelableBaseModelWithAttributes::find() is not a replacement for the SearchEngine. It is intended as a quick and convenient way to programatically fetch rows using
  * simple, clear cut criteria. If you need to fetch rows based upon an identifer or status value LabelableBaseModelWithAttributes::find() will be quicker and less code than
  * using the SearchEngine. For full-text searches, searches on attributes, or searches that require transformations or complex boolean operations use
  * the SearchEngine.
  *
  * @param array $pa_values An array of values to match. Keys are field names, metadata element codes or preferred_labels and /or nonpreferred_labels. This must be an array with at least one key-value pair where the key is a valid field name for the model.
  * @param array $pa_options Options are:
  *		transaction = optional Transaction instance. If set then all database access is done within the context of the transaction
  *		returnAs = what to return; possible values are:
  *			searchResult			= a search result instance (aka. a subclass of BaseSearchResult), when the calling subclass is searchable (ie. <classname>Search and <classname>SearchResult classes are defined) 
  *			ids						= an array of ids (aka. primary keys)
  *			modelInstances			= an array of instances, one for each match. Each instance is the same class as the caller, a subclass of BaseModel 
  *			firstId					= the id (primary key) of the first match. This is the same as the first item in the array returned by 'ids'
  *			firstModelInstance		= the instance of the first match. This is the same as the first instance in the array returned by 'modelInstances'
  *			count					= the number of matches
  *		
  *			The default is ids
  *	
  *		limit = if searchResult, ids or modelInstances is set, limits number of returned matches. Default is no limit
  *		boolean = determines how multiple field values in $pa_values are combined to produce the final result. Possible values are:
  *			AND						= find rows that match all criteria in $pa_values
  *			OR						= find rows that match any criteria in $pa_values
  *
  *			The default is AND
  *
  *		labelBoolean = determines how multiple field values in $pa_values['preferred_labels'] and $pa_values['nonpreferred_labels'] are combined to produce the final result. Possible values are:
  *			AND						= find rows that match all criteria in $pa_values['preferred_labels']/$pa_values['nonpreferred_labels']
  *			OR						= find rows that match any criteria in $pa_values['preferred_labels']/$pa_values['nonpreferred_labels']
  *
  *			The default is AND
  *
  *		sort = field to sort on. Must be in <table>.<field> format and be an intrinsic field in either the primary table or the label table. Sort order can be set using the sortDirection option.
  *		sortDirection = the direction of the sort. Values are ASC (ascending) and DESC (descending). [Default is ASC]
  *		allowWildcards = consider "%" as a wildcard when searching. Any term including a "%" character will be queried using the SQL LIKE operator. [Default is false]
  *
  * @return mixed Depending upon the returnAs option setting, an array, subclass of LabelableBaseModelWithAttributes or integer may be returned.
  */
 public static function find($pa_values, $pa_options = null)
 {
     if (!is_array($pa_values) || sizeof($pa_values) == 0) {
         return null;
     }
     $ps_return_as = caGetOption('returnAs', $pa_options, 'ids', array('forceLowercase' => true, 'validValues' => array('searchResult', 'ids', 'modelInstances', 'firstId', 'firstModelInstance', 'count')));
     $ps_boolean = caGetOption('boolean', $pa_options, 'and', array('forceLowercase' => true, 'validValues' => array('and', 'or')));
     $ps_label_boolean = caGetOption('labelBoolean', $pa_options, 'and', array('forceLowercase' => true, 'validValues' => array('and', 'or')));
     $ps_sort = caGetOption('sort', $pa_options, null);
     $vs_table = get_called_class();
     $t_instance = new $vs_table();
     $vn_table_num = $t_instance->tableNum();
     $vs_table_pk = $t_instance->primaryKey();
     $t_label = $t_instance->getLabelTableInstance();
     $vs_label_table = $t_label->tableName();
     $vs_label_table_pk = $t_label->primaryKey();
     $vb_has_simple_fields = false;
     foreach ($pa_values as $vs_field => $vm_value) {
         if (!is_array($vm_value) && $t_instance->hasField($vs_field)) {
             $vb_has_simple_fields = true;
             break;
         }
     }
     $vb_has_label_fields = false;
     foreach ($pa_values as $vs_field => $vm_value) {
         if (in_array($vs_field, array('preferred_labels', 'nonpreferred_labels')) && is_array($vm_value) && sizeof($vm_value)) {
             $vb_has_label_fields = true;
             break;
         }
     }
     $vs_sort_proc = $ps_sort;
     if (preg_match("!^{$vs_table}.preferred_labels[\\.]{0,1}(.*)!", $ps_sort, $va_matches) || preg_match("!^{$vs_table}.nonpreferred_labels[\\.]{0,1}(.*)!", $ps_sort, $va_matches)) {
         $vs_sort_proc = $va_matches[1] && $t_label->hasField($va_matches[1]) ? "{$vs_label_table}." . $va_matches[1] : "{$vs_label_table}." . $t_label->getDisplayField();
         $vb_has_label_fields = true;
     }
     $vb_has_attributes = false;
     $va_element_codes = $t_instance->getApplicableElementCodes(null, true, false);
     foreach ($pa_values as $vs_field => $vm_value) {
         if (!is_array($vm_value) && in_array($vs_field, $va_element_codes)) {
             $vb_has_attributes = true;
             break;
         }
     }
     $va_joins = array();
     $va_sql_params = array();
     if ($vb_has_simple_fields) {
         //
         // Convert type id
         //
         if ($t_instance->ATTRIBUTE_TYPE_LIST_CODE) {
             if (isset($pa_values[$t_instance->ATTRIBUTE_TYPE_ID_FLD]) && !is_numeric($pa_values[$t_instance->ATTRIBUTE_TYPE_ID_FLD])) {
                 if (!is_array($pa_values[$t_instance->ATTRIBUTE_TYPE_ID_FLD])) {
                     $pa_values[$t_instance->ATTRIBUTE_TYPE_ID_FLD] = array($pa_values[$t_instance->ATTRIBUTE_TYPE_ID_FLD]);
                 }
                 foreach ($pa_values[$t_instance->ATTRIBUTE_TYPE_ID_FLD] as $vn_i => $vm_value) {
                     if (!is_numeric($vm_value)) {
                         if ($vn_id = ca_lists::getItemID($t_instance->ATTRIBUTE_TYPE_LIST_CODE, $vm_value)) {
                             $pa_values[$t_instance->ATTRIBUTE_TYPE_ID_FLD][$vn_i] = $vn_id;
                         }
                     }
                 }
             }
         }
         //
         // Convert other intrinsic list references
         //
         foreach ($pa_values as $vs_field => $vm_value) {
             if ($vs_field == $t_instance->ATTRIBUTE_TYPE_ID_FLD) {
                 continue;
             }
             if ($vs_list_code = $t_instance->getFieldInfo($vs_field, 'LIST_CODE')) {
                 if (!is_array($vm_value)) {
                     $pa_values[$vs_field] = $vm_value = array($vm_value);
                 }
                 foreach ($vm_value as $vn_i => $vm_ivalue) {
                     if (is_numeric($vm_ivalue)) {
                         continue;
                     }
                     if ($vn_id = ca_lists::getItemID($vs_list_code, $vm_ivalue)) {
                         $pa_values[$vs_field][$vn_i] = $vn_id;
                     }
                 }
             }
         }
     }
     $va_sql_wheres = array();
     if ($vb_has_simple_fields && !$vb_has_attributes && !$vb_has_label_fields) {
         return parent::find($pa_values, $pa_options);
     }
     $va_label_sql = array();
     if ($vb_has_label_fields) {
         $va_joins[] = " INNER JOIN {$vs_label_table} ON {$vs_label_table}.{$vs_table_pk} = {$vs_table}.{$vs_table_pk} ";
         if (isset($pa_values['preferred_labels']) && is_array($pa_values['preferred_labels'])) {
             $va_sql_wheres[] = "({$vs_label_table}.is_preferred = 1)";
             foreach ($pa_values['preferred_labels'] as $vs_field => $vm_value) {
                 if (!$t_label->hasField($vs_field)) {
                     return false;
                 }
                 if ($t_label->_getFieldTypeType($vs_field) == 0) {
                     if (!is_numeric($vm_value) && !is_null($vm_value)) {
                         $vm_value = intval($vm_value);
                     }
                 } else {
                     $vm_value = $t_label->quote($vs_field, is_null($vm_value) ? '' : $vm_value);
                 }
                 if (is_null($vm_value)) {
                     $va_sql_wheres[] = "({$vs_label_table}.{$vs_field} IS NULL)";
                 } elseif (caGetOption('allowWildcards', $pa_options, false) && strpos($vm_value, '%') !== false) {
                     $va_sql_wheres[] = "({$vs_label_table}.{$vs_field} LIKE {$vm_value})";
                 } else {
                     if ($vm_value === '') {
                         continue;
                     }
                     $va_sql_wheres[] = "({$vs_label_table}.{$vs_field} = {$vm_value})";
                 }
             }
             $va_label_sql[] = "(" . join(" {$ps_label_boolean} ", $va_sql_wheres) . ")";
             $va_sql_wheres = array();
         }
         if (isset($pa_values['nonpreferred_labels']) && is_array($pa_values['nonpreferred_labels'])) {
             $va_sql_wheres[] = "({$vs_label_table}.is_preferred = 0)";
             foreach ($pa_values['nonpreferred_labels'] as $vs_field => $vm_value) {
                 if (!$t_label->hasField($vs_field)) {
                     return false;
                 }
                 if ($t_label->_getFieldTypeType($vs_field) == 0) {
                     if (!is_numeric($vm_value) && !is_null($vm_value)) {
                         $vm_value = intval($vm_value);
                     }
                 } else {
                     $vm_value = $t_label->quote($vs_field, is_null($vm_value) ? '' : $vm_value);
                 }
                 if (is_null($vm_value)) {
                     $va_sql_wheres[] = "({$vs_label_table}.{$vs_field} IS NULL)";
                 } else {
                     if ($vm_value === '') {
                         continue;
                     }
                     $va_sql_wheres[] = "({$vs_label_table}.{$vs_field} = {$vm_value})";
                 }
             }
             $va_label_sql[] = "(" . join(" {$ps_label_boolean} ", $va_sql_wheres) . ")";
             $va_sql_wheres = array();
         }
     }
     if ($vb_has_simple_fields) {
         foreach ($pa_values as $vs_field => $vm_value) {
             //if (is_array($vm_value)) { continue; }
             if (!$t_instance->hasField($vs_field)) {
                 continue;
             }
             if ($t_instance->_getFieldTypeType($vs_field) == 0) {
                 if (!is_numeric($vm_value) && !is_null($vm_value)) {
                     if (is_array($vm_value)) {
                         foreach ($vm_value as $vn_i => $vm_ivalue) {
                             $vm_value[$vn_i] = intval($vm_ivalue);
                         }
                     } else {
                         $vm_value = intval($vm_value);
                     }
                 }
             }
             if (is_null($vm_value)) {
                 $va_label_sql[] = "({$vs_table}.{$vs_field} IS NULL)";
             } elseif (caGetOption('allowWildcards', $pa_options, false) && strpos($vm_value, '%') !== false) {
                 $va_label_sql[] = "({$vs_table}.{$vs_field} LIKE ?)";
                 $va_sql_params[] = $vm_value;
             } else {
                 if ($vm_value === '') {
                     continue;
                 }
                 if (is_array($vm_value)) {
                     if (!sizeof($vm_value)) {
                         continue;
                     }
                     $va_label_sql[] = "({$vs_table}.{$vs_field} IN (?))";
                 } else {
                     $va_label_sql[] = "({$vs_table}.{$vs_field} = ?)";
                 }
                 $va_sql_params[] = $vm_value;
             }
         }
     }
     if ($vb_has_attributes) {
         $va_joins[] = " INNER JOIN ca_attributes ON ca_attributes.row_id = {$vs_table}.{$vs_table_pk} AND ca_attributes.table_num = {$vn_table_num} ";
         $va_joins[] = " INNER JOIN ca_attribute_values ON ca_attribute_values.attribute_id = ca_attributes.attribute_id ";
         foreach ($pa_values as $vs_field => $vm_value) {
             if (($vn_element_id = array_search($vs_field, $va_element_codes)) !== false) {
                 $vs_q = " (ca_attribute_values.element_id = {$vn_element_id}) AND  ";
                 switch ($vn_datatype = $t_instance->_getElementDatatype($vs_field)) {
                     case 0:
                         // continue
                     // continue
                     case 15:
                         // media
                     // media
                     case 16:
                         // file
                         // SKIP
                         continue 2;
                         break;
                     case 2:
                         // date
                         if (is_array($va_date = caDateToHistoricTimestamps($vm_value))) {
                             $vs_q .= "((ca_attribute_values.value_decimal1 BETWEEN ? AND ?) OR (ca_attribute_values.value_decimal2 BETWEEN ? AND ?))";
                             array_push($va_sql_params, $va_date['start'], $va_date['end'], $va_date['start'], $va_date['end']);
                         } else {
                             continue 2;
                         }
                         break;
                     case 3:
                         // list
                         $vn_item_id = is_numeric($vm_value) ? (int) $vm_value : (int) caGetListItemID($vm_value);
                         $vs_q .= "(ca_attribute_values.item_id = ?)";
                         $va_sql_params[] = $vn_item_id;
                         break;
                     default:
                         if (!($vs_fld = Attribute::getSortFieldForDatatype($vn_datatype))) {
                             $vs_fld = 'value_longtext1';
                         }
                         if (caGetOption('allowWildcards', $pa_options, false) && strpos($vm_value, '%') !== false) {
                             $vs_q .= "(ca_attribute_values.{$vs_fld} LIKE ?)";
                         } else {
                             $vs_q .= "(ca_attribute_values.{$vs_fld} = ?)";
                         }
                         $va_sql_params[] = (string) $vm_value;
                         break;
                 }
                 $va_label_sql[] = "({$vs_q})";
             }
         }
     }
     if (!sizeof($va_label_sql)) {
         return null;
     }
     $vs_deleted_sql = $t_instance->hasField('deleted') ? "({$vs_table}.deleted = 0) AND " : '';
     $vs_sql = "SELECT * FROM {$vs_table}";
     $vs_sql .= join("\n", $va_joins);
     $vs_sql .= " WHERE {$vs_deleted_sql} " . join(" {$ps_boolean} ", $va_label_sql);
     $vs_orderby = '';
     if ($vs_sort_proc) {
         $vs_sort_direction = caGetOption('sortDirection', $pa_options, 'ASC', array('validValues' => array('ASC', 'DESC')));
         $va_tmp = explode(".", $vs_sort_proc);
         if (sizeof($va_tmp) == 2) {
             switch ($va_tmp[0]) {
                 case $vs_table:
                     if ($t_instance->hasField($va_tmp[1])) {
                         $vs_orderby = " ORDER BY {$vs_sort_proc} {$vs_sort_direction}";
                     }
                     break;
                 case $vs_label_table:
                     if ($t_label->hasField($va_tmp[1])) {
                         $vs_orderby = " ORDER BY {$vs_sort_proc} {$vs_sort_direction}";
                     }
                     break;
             }
         }
         if ($vs_orderby) {
             $vs_sql .= $vs_orderby;
         }
     }
     if (isset($pa_options['transaction']) && $pa_options['transaction'] instanceof Transaction) {
         $o_db = $pa_options['transaction']->getDb();
     } else {
         $o_db = new Db();
     }
     $vn_limit = isset($pa_options['limit']) && (int) $pa_options['limit'] > 0 ? (int) $pa_options['limit'] : null;
     $qr_res = $o_db->query($vs_sql, $va_sql_params);
     $vn_c = 0;
     $vs_pk = $t_instance->primaryKey();
     switch ($ps_return_as) {
         case 'firstmodelinstance':
             while ($qr_res->nextRow()) {
                 $o_instance = new $vs_table();
                 if ($o_instance->load($qr_res->get($vs_pk))) {
                     return $o_instance;
                 }
             }
             return null;
             break;
         case 'modelinstances':
             $va_instances = array();
             while ($qr_res->nextRow()) {
                 $o_instance = new $vs_table();
                 if ($o_instance->load($qr_res->get($vs_pk))) {
                     $va_instances[] = $o_instance;
                     $vn_c++;
                     if ($vn_limit && $vn_c >= $vn_limit) {
                         break;
                     }
                 }
             }
             return $va_instances;
             break;
         case 'firstid':
             if ($qr_res->nextRow()) {
                 return $qr_res->get($vs_pk);
             }
             return null;
             break;
         case 'count':
             return $qr_res->numRows();
             break;
         default:
         case 'ids':
         case 'searchresult':
             $va_ids = array();
             while ($qr_res->nextRow()) {
                 $va_ids[] = $qr_res->get($vs_pk);
                 $vn_c++;
                 if ($vn_limit && $vn_c >= $vn_limit) {
                     break;
                 }
             }
             if ($ps_return_as == 'searchresult') {
                 if (sizeof($va_ids) > 0) {
                     return $t_instance->makeSearchResult($t_instance->tableName(), $va_ids);
                 }
                 return null;
             } else {
                 return $va_ids;
             }
             break;
     }
 }
Esempio n. 4
0
/**
 * Returns true if the date expression ends after the current date/time. 
 * Only the end point of the expression is considered. 
 *
 * @param string $ps_date_expression
 * @return bool
 */
function caDateEndsInFuture($ps_date_expression)
{
    if ($va_date = caDateToHistoricTimestamps($ps_date_expression)) {
        $va_now = caDateToHistoricTimestamps(_t('now'));
        if ($va_date['end'] >= $va_now['end']) {
            return true;
        }
    }
    return false;
}
Esempio n. 5
0
 /**
  *
  *
  * @param array $pa_options Array of options:
  *		template =
  */
 public function getLocationHistory($pa_options = null)
 {
     $pn_object = caGetOption('object_id', $pa_options, null);
     if (!($vn_object_id = $pn_object_id > 0 ? $pn_object_id : $this->getPrimaryKey())) {
         return null;
     }
     $ps_display_template = caGetOption('template', $pa_options, '^ca_objects_x_storage_locations.relation_id');
     $va_current_date = caDateToHistoricTimestamps(_t('now'));
     $vn_current_date = $va_current_date['start'];
     //
     // Directly query the date field for performance
     //
     $o_db = $this->getDb();
     $qr_res = $o_db->query("\n \t\t\tSELECT csl.relation_id, csl.location_id, csl.object_id, csl.sdatetime, csl.edatetime\n \t\t\tFROM ca_objects_x_storage_locations csl\n \t\t\tINNER JOIN ca_storage_locations AS sl ON sl.location_id = csl.location_id\n \t\t\tWHERE\n \t\t\t\t(csl.object_id = ?) AND \n \t\t\t\t(sl.deleted = 0)\n \t\t\tORDER BY\n \t\t\t\t csl.sdatetime DESC, csl.relation_id DESC\n \t\t", array($vn_object_id));
     $va_relation_ids = $qr_res->getAllFieldValues('relation_id');
     $va_displays = caProcessTemplateForIDs($ps_display_template, 'ca_objects_x_storage_locations', $va_relation_ids, array('returnAsArray' => true));
     $qr_res->seek(0);
     $va_items = array();
     $vb_have_seen_the_present = false;
     while ($qr_res->nextRow()) {
         $va_row = $qr_res->getRow();
         $vn_relation_id = $va_row['relation_id'];
         if ($va_row['sdatetime'] > $vn_current_date) {
             $vs_status = 'FUTURE';
         } else {
             $vs_status = $vb_have_seen_the_present ? 'PAST' : 'PRESENT';
             $vb_have_seen_the_present = true;
         }
         $va_items[$vn_relation_id] = array('object_id' => $va_row['object_id'], 'location_id' => $va_row['location_id'], 'display' => array_shift($va_displays), 'status' => $vs_status);
     }
     return $va_items;
 }
Esempio n. 6
0
 /**
  * Generate SIMILE timeline output in specified format
  *
  * @param array $pa_viz_settings Array of visualization settings taken from visualization.conf
  * @param string $ps_format Specifies format to generate output in. Currently only 'HTML' is supported.
  * @param array $pa_options Array of options to use when rendering output. Supported options are:
  *		width =
  *		height =
  *		request = current request; required for generation of editor links
  */
 public function render($pa_viz_settings, $ps_format = 'HTML', $pa_options = null)
 {
     if (!($vo_data = $this->getData())) {
         return null;
     }
     $this->opn_num_items_rendered = 0;
     $po_request = isset($pa_options['request']) && $pa_options['request'] ? $pa_options['request'] : null;
     list($vs_width, $vs_height) = $this->_parseDimensions(caGetOption('width', $pa_options, 500), caGetOption('height', $pa_options, 500));
     $o_dm = Datamodel::load();
     // generate events
     $va_events = array();
     $va_sources = $pa_viz_settings['sources'];
     $vs_table = $vo_data->tableName();
     $vs_pk = $o_dm->getTablePrimaryKeyName($vs_table);
     $vs_first_date = $vn_first_date = null;
     $vs_last_date = $vn_last_date = null;
     $va_dates = array();
     while ($vo_data->nextHit()) {
         foreach ($va_sources as $vs_source_code => $va_source_info) {
             $vs_start = trim($vo_data->get($va_source_info['data'], array('start_as_iso8601' => true, 'dateFormat' => 'iso8601')));
             $vs_end = trim($vo_data->get($va_source_info['data'], array('end_as_iso8601' => true, 'dateFormat' => 'iso8601')));
             $vn_start = $vo_data->get($va_source_info['data'], array('startHistoricTimestamp' => true));
             $vn_end = $vo_data->get($va_source_info['data'], array('endHistoricTimestamp' => true));
             if ($vn_start < 0 || $vn_end < 0) {
                 continue;
             }
             // TODO: negative numbers mean "BC" which apparently cannot be plotted
             if ($vn_end >= 2000000) {
                 $va_iso = caGetISODates(_t("today"));
                 $vs_end = $va_iso['end'];
                 $va_historic = caDateToHistoricTimestamps(_t("today"));
                 $vn_end = $va_historic['end'];
             }
             if (!$vs_start || !$vs_end) {
                 continue;
             }
             if ($vs_start == _t('undated') || $vs_end == _t('undated')) {
                 continue;
             }
             if (is_null($vn_first_date) || $vn_first_date > $vn_start) {
                 $vn_first_date = $vn_start;
                 $vs_first_date = $vs_start;
             }
             if (is_null($vn_last_date) || $vn_last_date < $vn_end) {
                 $vn_last_date = $vn_end;
                 $vs_last_date = $vs_end;
             }
             $va_dates[] = $vs_start;
             $va_events[] = array('id' => $vs_table . '_' . ($vn_id = $vo_data->get("{$vs_table}.{$vs_pk}")), 'start' => $vs_start, 'end' => $vs_end, 'isDuration' => (int) $vn_start != (int) $vn_end ? true : false, 'title' => caProcessTemplateForIDs(strip_tags($va_source_info['display']['title_template']), $vs_table, array($vn_id)), 'description' => caProcessTemplateForIDs($va_source_info['display']['description_template'], $vs_table, array($vn_id)), 'link' => $po_request ? caEditorUrl($po_request, $vo_data->tableName(), $vn_id) : null, 'image' => $va_source_info['display']['image'] ? $vo_data->getWithTemplate($va_source_info['display']['image'], array('returnURL' => true)) : null, 'icon' => $va_source_info['display']['icon'] ? $vo_data->getWithTemplate($va_source_info['display']['icon'], array('returnURL' => true)) : null);
         }
     }
     $this->opn_num_items_rendered = sizeof($va_events);
     // Find median date - timeline will open there (as good a place as any, no?)
     $vs_default_date = $va_dates[floor((sizeof($va_dates) - 1) / 2)];
     // Derive scale for timeline bands
     $vn_span = $vn_last_date - $vn_first_date;
     if ($vn_span > 1000) {
         // millennia
         $vs_detail_band_scale = " Timeline.DateTime.CENTURY";
         $vs_overview_band_scale = " Timeline.DateTime.MILLENNIUM";
     } elseif ($vn_span > 100) {
         // centuries
         $vs_detail_band_scale = " Timeline.DateTime.DECADE";
         $vs_overview_band_scale = " Timeline.DateTime.CENTURY";
     } elseif ($vn_span > 10) {
         // decades
         $vs_detail_band_scale = " Timeline.DateTime.YEAR";
         $vs_overview_band_scale = " Timeline.DateTime.DECADE";
     } elseif ($vn_span > 1) {
         // years
         $vs_detail_band_scale = " Timeline.DateTime.MONTH";
         $vs_overview_band_scale = " Timeline.DateTime.YEAR";
     } elseif ($vn_span > 0.1) {
         // months
         $vs_detail_band_scale = " Timeline.DateTime.DAY";
         $vs_overview_band_scale = " Timeline.DateTime.MONTH";
     } else {
         // days
         $vs_detail_band_scale = " Timeline.DateTime.HOUR";
         $vs_overview_band_scale = " Timeline.DateTime.DAY";
     }
     $va_highlight_spans = array();
     $vs_highlight_span = '';
     if (isset($pa_options['highlightSpans']) && is_array($pa_options['highlightSpans'])) {
         foreach ($pa_options['highlightSpans'] as $vs_span_name => $va_span_info) {
             $va_range = caGetISODates($va_span_info['range']);
             $vs_span_color = isset($va_span_info['color']) && $va_span_info['color'] ? $va_span_info['color'] : '#FFC080';
             $vs_start_label = isset($va_span_info['startLabel']) && $va_span_info['startLabel'] ? $va_span_info['startLabel'] : '';
             $vs_end_label = isset($va_span_info['endLabel']) && $va_span_info['endLabel'] ? $va_span_info['endLabel'] : '';
             $vs_span_css_class = isset($va_span_info['class']) && $va_span_info['class'] ? $va_span_info['class'] : 't-highlight1';
             $va_highlight_spans[] = "new Timeline.SpanHighlightDecorator({\n\t\t\t\t\t\tdateTimeFormat: 'iso8601',\n                        startDate:  '" . $va_range['start'] . "',\n                        endDate:    '" . $va_range['end'] . "',\n                        color:      '{$vs_span_color}', \n                        opacity:    50,\n                        startLabel: '{$vs_start_label}', \n                        endLabel:   '{$vs_end_label}',\n                        cssClass: '{$vs_span_css_class}'\n                    })";
         }
         $vs_highlight_span = "caTimelineBands[0].decorators = [" . join(",\n", $va_highlight_spans) . "];";
     }
     $vs_buf = "\n\t<div id='caResultTimeline' style='width: {$vs_width}; height: {$vs_height}; border: 1px solid #aaa'></div>\n<script type='text/javascript'>\n\tvar caTimelineEventSource = new Timeline.DefaultEventSource();\n\tvar caTimelineEventJson = {\n\t\t\"dateTimeFormat\": \"iso8601\", \n\t\t\"events\" : " . json_encode($va_events) . "\n\t}; \n\tcaTimelineEventSource.loadJSON(caTimelineEventJson, '');\n\t\n\tvar theme = Timeline.ClassicTheme.create();\n\t\n\tvar caTimelineBands = [\n     Timeline.createBandInfo({\n\t\t\teventPainter:   Timeline.CompactEventPainter,\n\t\t\teventPainterParams: {\n\t\t\t\ticonLabelGap:     5,\n\t\t\t\tlabelRightMargin: 20,\n\n\t\t\t\ticonWidth:        72,\n\t\t\t\ticonHeight:       72,\n\n\t\t\t\tstackConcurrentPreciseInstantEvents: {\n\t\t\t\t\tlimit: 5,\n\t\t\t\t\tmoreMessageTemplate:    '%0 More',\n\t\t\t\t\ticon:                   null,\n\t\t\t\t\ticonWidth:              72,\n\t\t\t\t\ticonHeight:             72\n\t\t\t\t}\n\t\t\t},\n\t\t\teventSource:\t caTimelineEventSource,\n\t\t\tdate:\t\t\t'{$vs_default_date}',\n\t\t\twidth:          '85%', \n\t\t\tintervalUnit:  \t{$vs_detail_band_scale}, \n\t\t\tintervalPixels: 100,\n\t\t\ttheme: \t\t\ttheme\n\t}),\n     Timeline.createBandInfo({\n     \t eventSource:\t caTimelineEventSource,\n     \t date:\t\t\t'{$vs_default_date}',\n         width:          '10%', \n         intervalUnit:   {$vs_overview_band_scale}, \n         intervalPixels: 200,\n         layout: \t\t'overview',\n     \t theme: \t\t theme\n     })\n   ];\n\tcaTimelineBands[1].syncWith = 0;\n\tcaTimelineBands[1].highlight = true;\n\t\n\t{$vs_highlight_span}\n\t\n\tvar caTimeline = Timeline.create(document.getElementById('caResultTimeline'), caTimelineBands);\n</script>\t\n";
     return $vs_buf;
 }