/**
  *
  */
 private static function _evaluateCodeAttribute(SearchResult $pr_res, $po_node, array $pa_options = null)
 {
     if (!($va_codes = DisplayTemplateParser::_getCodesFromAttribute($po_node, ['includeBooleans' => true]))) {
         return [];
     }
     $pb_include_blanks = caGetOption('includeBlankValuesInArray', $pa_options, false);
     $ps_delimiter = caGetOption('delimiter', $pa_options, ';');
     $pb_mode = caGetOption('mode', $pa_options, 'present');
     // value 'present' or 'not_present'
     $pn_index = caGetOption('index', $pa_options, null);
     $vb_has_value = null;
     foreach ($va_codes as $vs_code => $vs_bool) {
         $va_val_list = $pr_res->get($vs_code, ['returnAsArray' => true, 'returnBlankValues' => true, 'convertCodesToDisplayText' => true, 'returnAsDecimal' => true, 'getDirectDate' => true]);
         if (!is_array($va_val_list)) {
             // no value
             $vb_value_present = false;
         } else {
             if (!is_null($pn_index)) {
                 if (!isset($va_val_list[$pn_index]) || (is_numeric($va_val_list[$pn_index]) && (double) $va_val_list[$pn_index] == 0 || !strlen(trim($va_val_list[$pn_index])))) {
                     $vb_value_present = false;
                     // no value
                 } else {
                     $va_val_list = array($va_val_list[$pn_index]);
                     if (!$pb_include_blanks) {
                         $va_val_list = array_filter($va_val_list);
                     }
                     $vb_value_present = (bool) sizeof($va_val_list);
                 }
             } else {
                 if (!$pb_include_blanks) {
                     foreach ($va_val_list as $vn_i => $vm_val) {
                         if (is_numeric($vm_val) && (double) $vm_val == 0 || !strlen(trim($vm_val))) {
                             unset($va_val_list[$vn_i]);
                         }
                     }
                 }
                 $vb_value_present = (bool) sizeof($va_val_list);
             }
         }
         if ($pb_mode !== 'present') {
             $vb_value_present = !$vb_value_present;
         }
         if (is_null($vb_has_value)) {
             $vb_has_value = $vb_value_present;
         }
         $vb_has_value = $vs_bool == 'OR' ? $vb_has_value || $vb_value_present : $vb_has_value && $vb_value_present;
     }
     return $vb_has_value;
 }
 public function testAttributesWithHTML()
 {
     $vm_ret = DisplayTemplateParser::evaluate("<unit relativeTo='ca_entities' delimiter='<br/>'>^ca_entities.preferred_labels.displayname</unit>", "ca_objects", array($this->opn_object_id), array('returnAsArray' => true));
     $this->assertInternalType('array', $vm_ret);
     $this->assertCount(1, $vm_ret);
     $this->assertEquals("Homer J. Simpson<br/>Bart Simpson", $vm_ret[0]);
     $vm_ret = DisplayTemplateParser::evaluate("<unit relativeTo='ca_entities' delimiter='  <br/>  '>^ca_entities.preferred_labels.displayname</unit>", "ca_objects", array($this->opn_object_id), array('returnAsArray' => true));
     $this->assertInternalType('array', $vm_ret);
     $this->assertCount(1, $vm_ret);
     $this->assertEquals("Homer J. Simpson  <br/>  Bart Simpson", $vm_ret[0]);
 }
 public function testSiblingRestrictToTypesDisplayTemplates()
 {
     $vm_ret = DisplayTemplateParser::evaluate("<unit delimiter='; ' restrictToTypes='image' relativeTo='ca_objects.siblings'>^ca_objects.preferred_labels.name</unit>", "ca_objects", array($this->opt_another_child_object->getPrimaryKey()), array('returnAsArray' => true));
     $this->assertInternalType('array', $vm_ret);
     $this->assertCount(1, $vm_ret);
     $this->assertEquals('My test still; Another test still', $vm_ret[0]);
     $vm_ret = DisplayTemplateParser::evaluate("<unit delimiter='; ' restrictToTypes='moving_image' relativeTo='ca_objects.siblings'>^ca_objects.preferred_labels.name</unit>", "ca_objects", array($this->opt_another_child_object->getPrimaryKey()), array('returnAsArray' => true));
     $this->assertInternalType('array', $vm_ret);
     $this->assertCount(1, $vm_ret);
     $this->assertEquals('A child movie', $vm_ret[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)
 *		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.
 *		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 primary template and all <unit>s 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]
 *		includeBlankValuesInTopLevelForPrefetch = include blank template values in *primary template* (not <unit>s) in returned array when returnAsArray is set. Used by template prefetcher to ensure returned values align with id indices. [Default is false]
 *
 * @return mixed Output of processed templates
 */
function caProcessTemplateForIDs($ps_template, $pm_tablename_or_num, $pa_row_ids, $pa_options = null)
{
    return DisplayTemplateParser::evaluate($ps_template, $pm_tablename_or_num, $pa_row_ids, $pa_options);
}