Merge pull request #21470 from mattwire/templatecontributioncreate
[civicrm-core.git] / CRM / Export / Utils.php
1 <?php
2
3 class CRM_Export_Utils {
4
5 /**
6 * This transforms the lists of fields for each contact type & component
7 * into a single unified list suitable for select2.
8 *
9 * The return values of CRM_Core_BAO_Mapping::getBasicFields contain a separate field list
10 * for every contact type and sub-type. This is extremely redundant as 90%+ of the fields
11 * in each list are the same. To avoid sending bloated data to the client-side, we turn
12 * it into a single list where fields not shared by every contact type get a contact_type
13 * attribute so they can be filtered appropriately by the selector.
14 *
15 * We also sort fields into optgroup categories, and add component fields appropriate to this export.
16 *
17 * @param $exportMode
18 * @return array
19 * @throws CiviCRM_API3_Exception
20 */
21 public static function getExportFields($exportMode) {
22 $fieldGroups = CRM_Core_BAO_Mapping::getBasicFields('Export');
23
24 $categories = [
25 'contact' => ['text' => ts('Contact Fields'), 'is_contact' => TRUE],
26 'address' => ['text' => ts('Address Fields'), 'is_contact' => TRUE],
27 'communication' => ['text' => ts('Communication Fields'), 'is_contact' => TRUE],
28 ];
29 $optionMap = [
30 'civicrm_website' => 'website_type_id',
31 'civicrm_phone' => 'phone_type_id',
32 'civicrm_im' => 'im_provider_id',
33 ];
34 // Whitelist of field properties we actually care about; others will be discarded
35 $fieldProps = ['id', 'text', 'has_location', 'option_list', 'relationship_type_id', 'related_contact_type'];
36 $relTypes = civicrm_api3('RelationshipType', 'get', ['options' => ['limit' => 0]])['values'];
37
38 // Add component fields
39 $compFields = [];
40 $compLabels = CRM_Core_BAO_Mapping::addComponentFields($compFields, 'Export', $exportMode);
41 foreach ($compLabels as $comp => $label) {
42 $categories[$comp] = ['text' => $label];
43 foreach ($compFields[$comp] as $key => $field) {
44 $field['text'] = $field['title'];
45 $field['id'] = $key;
46 $categories[$comp]['children'][] = array_intersect_key($field, array_flip($fieldProps));
47 }
48 }
49
50 // Unset groups, tags, notes for component export
51 if ($exportMode != CRM_Export_Form_Select::CONTACT_EXPORT) {
52 foreach (array_keys($fieldGroups) as $contactType) {
53 CRM_Utils_Array::remove($fieldGroups[$contactType], 'groups', 'tags', 'notes');
54 }
55 }
56
57 // Now combine all those redundant lists of fields into a single list with categories
58 foreach ($fieldGroups as $contactType => $fields) {
59 // 'related' was like a poor-mans optgroup.
60 unset($fields['related']);
61 foreach ($fields as $key => $field) {
62 $group = 'contact';
63 $field['text'] = $field['title'];
64 $field['id'] = $key;
65 $field['has_location'] = !empty($field['hasLocationType']);
66 if (isset($field['table_name']) && isset($optionMap[$field['table_name']])) {
67 $field['option_list'] = $optionMap[$field['table_name']];
68 $group = 'communication';
69 }
70 elseif (!empty($field['has_location'])) {
71 $group = 'address';
72 }
73 if ($key == 'email') {
74 $group = 'communication';
75 }
76 if (!empty($field['custom_group_id'])) {
77 $group = $field['custom_group_id'];
78 $categories[$group]['text'] = $field['groupTitle'];
79 $categories[$group]['is_contact'] = TRUE;
80 }
81 if (!empty($field['related'])) {
82 $group = 'related';
83 $categories[$group]['text'] = ts('Related Contact Info');
84 list($type, , $dir) = explode('_', $key);
85 $field['related_contact_type'] = $relTypes[$type]["contact_sub_type_$dir"] ?? $relTypes[$type]["contact_type_$dir"] ?? '*';
86 // Skip relationship types targeting disabled contacts
87 if ($field['related_contact_type'] != '*' && !isset($fieldGroups[$field['related_contact_type']])) {
88 continue;
89 }
90 }
91 if (empty($categories[$group]['children'][$key])) {
92 // Discard unwanted field props to save space
93 $categories[$group]['children'][$key] = array_intersect_key($field, array_flip($fieldProps));
94 }
95 // Set contact_type, which gets added to on every iteration
96 $categories[$group]['children'][$key]['contact_type'][] = $contactType;
97 // If a field applies to every contact type, remove the contact_type flag as it's redundant
98 if (count($fieldGroups) == count($categories[$group]['children'][$key]['contact_type'])) {
99 unset($categories[$group]['children'][$key]['contact_type']);
100 }
101 }
102 }
103 // We needed meaningful keys while organizing fields but if we send them client-side they'll just be in the way
104 foreach ($categories as &$category) {
105 $category['children'] = array_values($category['children']);
106 }
107 return array_values($categories);
108 }
109
110 }