$fieldOptions = self::getPseudoconstantList($field, $fieldName, $result, $action);
$dataType = NULL;
}
+ // Store contact_type value before replacing pseudoconstant (e.g. transforming it to contact_type:label)
+ // Used by self::contactFieldsToRemove below
+ if ($value && isset($field['entity']) && $field['entity'] === 'Contact' && $field['name'] === 'contact_type') {
+ $prefix = strrpos($fieldName, '.');
+ $contactTypePaths[$prefix ? substr($fieldName, 0, $prefix + 1) : ''] = $value;
+ }
if ($fieldExpr->supportsExpansion) {
if (!empty($field['serialize']) && is_string($value)) {
$value = \CRM_Core_DAO::unSerializeField($value, $field['serialize']);
$value = self::replacePseudoconstant($fieldOptions, $value);
}
}
- // Keep track of contact types for self::contactFieldsToRemove
- if ($value && isset($field['entity']) && $field['entity'] === 'Contact' && $field['name'] === 'contact_type') {
- $prefix = strrpos($fieldName, '.');
- $contactTypePaths[$prefix ? substr($fieldName, 0, $prefix + 1) : ''] = $value;
- }
$result[$key] = self::convertDataType($value, $dataType);
}
// Remove inapplicable contact fields
}
/**
- * Evaluates conditional style rules
+ * Add icons to a column
+ *
+ * Note: Only one icon is allowed per side (left/right).
+ * If more than one per side is given, latter icons are treated as fallbacks
+ * and only shown if prior ones are missing.
*
* @param array{icon: string, field: string, if: array, side: string}[] $icons
* @param array $data
*/
protected function getColumnIcons(array $icons, array $data) {
$result = [];
- foreach ($icons as $icon) {
+ // Reverse order so latter icons become fallbacks and earlier ones take priority
+ foreach (array_reverse($icons) as $icon) {
$iconClass = $icon['icon'] ?? NULL;
- if (!$iconClass && !empty($icon['field'])) {
- $iconClass = $data[$icon['field']] ?? NULL;
+ if (!$iconClass && !empty($icon['field']) && !empty($data[$icon['field']])) {
+ // Icon field may be multivalued e.g. contact_sub_type
+ $iconClass = \CRM_Utils_Array::first(array_filter((array) $data[$icon['field']]));
}
if ($iconClass) {
$condition = $this->getRuleCondition($icon['if'] ?? []);
if (!is_null($condition[0]) && !(self::filterCompare($data, $condition))) {
continue;
}
- $result[] = ['class' => $iconClass, 'side' => $icon['side'] ?? 'left'];
+ $side = $icon['side'] ?? 'left';
+ $result[$side] = ['class' => $iconClass, 'side' => $side];
}
}
- return $result;
+ return array_values($result);
}
/**
// Icon based on activity type
$this->assertEquals([['class' => 'fa-slideshare', 'side' => 'left']], $result[0]['columns'][0]['icons']);
// Activity type icon + conditional icon based on status
- $this->assertEquals([['class' => 'fa-phone', 'side' => 'left'], ['class' => 'fa-star', 'side' => 'right']], $result[1]['columns'][0]['icons']);
+ $this->assertEquals([['class' => 'fa-star', 'side' => 'right'], ['class' => 'fa-phone', 'side' => 'left']], $result[1]['columns'][0]['icons']);
}
/**
$this->assertEquals(3, $result[2]['columns'][1]['val']);
}
+ public function testContactTypeIcons(): void {
+ $this->createTestRecord('ContactType', [
+ 'label' => 'Star',
+ 'name' => 'Star',
+ 'parent_id:name' => 'Individual',
+ 'icon' => 'fa-star',
+ ]);
+ $this->createTestRecord('ContactType', [
+ 'label' => 'None',
+ 'name' => 'None',
+ 'parent_id:name' => 'Individual',
+ 'icon' => NULL,
+ ]);
+
+ $lastName = uniqid(__FUNCTION__);
+ $sampleData = [
+ [
+ 'first_name' => 'Starry',
+ 'contact_sub_type' => ['Star'],
+ ],
+ [
+ 'first_name' => 'No icon',
+ 'contact_sub_type' => ['None'],
+ ],
+ [
+ 'first_name' => 'Both',
+ 'contact_sub_type' => ['None', 'Star'],
+ ],
+ ];
+ $records = $this->saveTestRecords('Contact', [
+ 'records' => $sampleData,
+ 'defaults' => ['last_name' => $lastName],
+ ]);
+
+ $params = [
+ 'checkPermissions' => FALSE,
+ 'return' => 'page:1',
+ 'savedSearch' => [
+ 'api_entity' => 'Contact',
+ 'api_params' => [
+ 'version' => 4,
+ 'select' => ['first_name', 'last_name'],
+ ],
+ ],
+ 'display' => [
+ 'type' => 'table',
+ 'label' => '',
+ 'settings' => [
+ 'actions' => TRUE,
+ 'pager' => [],
+ 'columns' => [
+ [
+ 'key' => 'first_name',
+ 'label' => 'First',
+ 'dataType' => 'String',
+ 'type' => 'field',
+ 'icons' => [
+ ['field' => 'contact_sub_type:icon'],
+ ['field' => 'contact_type:icon'],
+ ],
+ ],
+ ],
+ 'sort' => [
+ ['sort_name', 'ASC'],
+ ],
+ ],
+ ],
+ 'filters' => ['last_name' => $lastName],
+ ];
+
+ $result = civicrm_api4('SearchDisplay', 'run', $params);
+ $this->assertCount(3, $result);
+
+ // Contacts will be returned in order by sort_name
+ $this->assertEquals('Both', $result[0]['columns'][0]['val']);
+ $this->assertEquals('fa-star', $result[0]['columns'][0]['icons'][0]['class']);
+ $this->assertEquals('No icon', $result[1]['columns'][0]['val']);
+ $this->assertEquals('fa-user', $result[1]['columns'][0]['icons'][0]['class']);
+ $this->assertEquals('Starry', $result[2]['columns'][0]['val']);
+ $this->assertEquals('fa-star', $result[2]['columns'][0]['icons'][0]['class']);
+ }
+
}