Commit | Line | Data |
---|---|---|
b26295b8 CW |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
b26295b8 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
b26295b8 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
b26295b8 CW |
11 | |
12 | /** | |
b26295b8 | 13 | * @package CRM |
ca5cec67 | 14 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
b26295b8 CW |
15 | */ |
16 | ||
17 | /** | |
2b4bc760 | 18 | * This class gets the name of the file to upload. |
19 | * | |
b26295b8 CW |
20 | * TODO: CRM-11254 - There's still a lot of duplicate code in the 5 child classes that should be moved here |
21 | */ | |
5e8faabc | 22 | abstract class CRM_Import_Form_MapField extends CRM_Import_Forms { |
b26295b8 CW |
23 | |
24 | /** | |
100fef9d | 25 | * Cache of preview data values |
b26295b8 CW |
26 | * |
27 | * @var array | |
b26295b8 CW |
28 | */ |
29 | protected $_dataValues; | |
30 | ||
31 | /** | |
100fef9d | 32 | * Mapper fields |
b26295b8 CW |
33 | * |
34 | * @var array | |
b26295b8 CW |
35 | */ |
36 | protected $_mapperFields; | |
37 | ||
b26295b8 | 38 | /** |
100fef9d | 39 | * Number of columns in import file |
b26295b8 CW |
40 | * |
41 | * @var int | |
b26295b8 CW |
42 | */ |
43 | protected $_columnCount; | |
44 | ||
45 | /** | |
100fef9d | 46 | * Column headers, if we have them |
b26295b8 CW |
47 | * |
48 | * @var array | |
b26295b8 CW |
49 | */ |
50 | protected $_columnHeaders; | |
51 | ||
52 | /** | |
100fef9d | 53 | * An array of booleans to keep track of whether a field has been used in |
b26295b8 CW |
54 | * form building already. |
55 | * | |
56 | * @var array | |
b26295b8 CW |
57 | */ |
58 | protected $_fieldUsed; | |
59 | ||
60 | /** | |
2b4bc760 | 61 | * Return a descriptive name for the page, used in wizard header. |
b26295b8 CW |
62 | * |
63 | * @return string | |
b26295b8 CW |
64 | */ |
65 | public function getTitle() { | |
66 | return ts('Match Fields'); | |
67 | } | |
68 | ||
8d0967f5 EM |
69 | /** |
70 | * Shared preProcess code. | |
71 | */ | |
72 | public function preProcess() { | |
73 | $this->assignMapFieldVariables(); | |
77a9ae24 EM |
74 | $this->_mapperFields = $this->getAvailableFields(); |
75 | asort($this->_mapperFields); | |
8d0967f5 EM |
76 | parent::preProcess(); |
77 | } | |
78 | ||
992a3d9e EM |
79 | /** |
80 | * Process the mapped fields and map it into the uploaded file | |
81 | * preview the file and extract some summary statistics | |
82 | * | |
83 | * @return void | |
84 | * @noinspection PhpDocSignatureInspection | |
85 | * @noinspection PhpUnhandledExceptionInspection | |
86 | */ | |
87 | public function postProcess() { | |
88 | $this->updateUserJobMetadata('submitted_values', $this->getSubmittedValues()); | |
89 | $this->saveMapping($this->getMappingTypeName()); | |
90 | $parser = $this->getParser(); | |
91 | $parser->init(); | |
92 | $parser->validate(); | |
93 | } | |
94 | ||
b26295b8 | 95 | /** |
fe482240 | 96 | * Attempt to match header labels with our mapper fields. |
b26295b8 | 97 | * |
79d7553f | 98 | * @param string $header |
99 | * @param array $patterns | |
b26295b8 CW |
100 | * |
101 | * @return string | |
b26295b8 CW |
102 | */ |
103 | public function defaultFromHeader($header, &$patterns) { | |
104 | foreach ($patterns as $key => $re) { | |
105 | // Skip empty key/patterns | |
106 | if (!$key || !$re || strlen("$re") < 5) { | |
107 | continue; | |
108 | } | |
109 | ||
110 | // Scan through the headerPatterns defined in the schema for a match | |
111 | if (preg_match($re, $header)) { | |
112 | $this->_fieldUsed[$key] = TRUE; | |
113 | return $key; | |
114 | } | |
115 | } | |
116 | return ''; | |
117 | } | |
118 | ||
119 | /** | |
fe482240 | 120 | * Guess at the field names given the data and patterns from the schema. |
b26295b8 | 121 | * |
79d7553f | 122 | * @param array $patterns |
123 | * @param string $index | |
b26295b8 CW |
124 | * |
125 | * @return string | |
b26295b8 | 126 | */ |
56dd62a0 | 127 | public function defaultFromData($patterns, $index) { |
353ffa53 | 128 | $best = ''; |
b26295b8 | 129 | $bestHits = 0; |
353ffa53 | 130 | $n = count($this->_dataValues); |
b26295b8 CW |
131 | |
132 | foreach ($patterns as $key => $re) { | |
133 | // Skip empty key/patterns | |
134 | if (!$key || !$re || strlen("$re") < 5) { | |
135 | continue; | |
136 | } | |
137 | ||
138 | /* Take a vote over the preview data set */ | |
139 | $hits = 0; | |
140 | for ($i = 0; $i < $n; $i++) { | |
141 | if (isset($this->_dataValues[$i][$index])) { | |
142 | if (preg_match($re, $this->_dataValues[$i][$index])) { | |
143 | $hits++; | |
144 | } | |
145 | } | |
146 | } | |
147 | if ($hits > $bestHits) { | |
148 | $bestHits = $hits; | |
149 | $best = $key; | |
150 | } | |
151 | } | |
152 | ||
153 | if ($best != '') { | |
154 | $this->_fieldUsed[$best] = TRUE; | |
155 | } | |
156 | return $best; | |
157 | } | |
158 | ||
ad05d047 | 159 | /** |
160 | * Add the saved mapping fields to the form. | |
161 | * | |
162 | * @param int|null $savedMappingID | |
163 | * | |
164 | * @throws \CiviCRM_API3_Exception | |
165 | */ | |
166 | protected function buildSavedMappingFields($savedMappingID) { | |
167 | //to save the current mappings | |
168 | if (!$savedMappingID) { | |
169 | $saveDetailsName = ts('Save this field mapping'); | |
170 | $this->applyFilter('saveMappingName', 'trim'); | |
171 | $this->add('text', 'saveMappingName', ts('Name')); | |
172 | $this->add('text', 'saveMappingDesc', ts('Description')); | |
173 | } | |
174 | else { | |
175 | $savedMapping = $this->get('savedMapping'); | |
176 | ||
177 | $mappingName = (string) civicrm_api3('Mapping', 'getvalue', ['id' => $savedMappingID, 'return' => 'name']); | |
178 | $this->set('loadedMapping', $savedMapping); | |
ad05d047 | 179 | $this->add('hidden', 'mappingId', $savedMappingID); |
180 | ||
181 | $this->addElement('checkbox', 'updateMapping', ts('Update this field mapping'), NULL); | |
182 | $saveDetailsName = ts('Save as a new field mapping'); | |
183 | $this->add('text', 'saveMappingName', ts('Name')); | |
184 | $this->add('text', 'saveMappingDesc', ts('Description')); | |
185 | } | |
262b7f26 | 186 | $this->assign('savedMappingName', $mappingName ?? NULL); |
ad05d047 | 187 | $this->addElement('checkbox', 'saveMapping', $saveDetailsName, NULL, ['onclick' => "showSaveDetails(this)"]); |
188 | } | |
189 | ||
02a237ce | 190 | /** |
191 | * Validate that sufficient fields have been supplied to match to a contact. | |
192 | * | |
193 | * @param string $contactType | |
194 | * @param array $importKeys | |
195 | * | |
196 | * @return string | |
197 | * Message if insufficient fields are present. Empty string otherwise. | |
198 | */ | |
199 | protected static function validateRequiredContactMatchFields(string $contactType, array $importKeys): string { | |
61194d45 | 200 | [$ruleFields, $threshold] = CRM_Dedupe_BAO_DedupeRuleGroup::dedupeRuleFieldsWeight([ |
02a237ce | 201 | 'used' => 'Unsupervised', |
202 | 'contact_type' => $contactType, | |
203 | ]); | |
204 | $weightSum = 0; | |
205 | foreach ($importKeys as $key => $val) { | |
206 | if (array_key_exists($val, $ruleFields)) { | |
207 | $weightSum += $ruleFields[$val]; | |
208 | } | |
209 | } | |
210 | $fieldMessage = ''; | |
211 | foreach ($ruleFields as $field => $weight) { | |
212 | $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; | |
213 | } | |
214 | if ($weightSum < $threshold) { | |
215 | return $fieldMessage . ' ' . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array( | |
216 | 1 => $threshold, | |
217 | )); | |
218 | } | |
219 | return ''; | |
220 | } | |
221 | ||
73edfc10 EM |
222 | /** |
223 | * Get the field mapped to the savable format. | |
224 | * | |
225 | * @param array $fieldMapping | |
226 | * @param int $mappingID | |
227 | * @param int $columnNumber | |
228 | * | |
229 | * @return array | |
230 | * @throws \CRM_Core_Exception | |
231 | */ | |
232 | protected function getMappedField(array $fieldMapping, int $mappingID, int $columnNumber): array { | |
233 | return $this->getParser()->getMappingFieldFromMapperInput($fieldMapping, $mappingID, $columnNumber); | |
234 | } | |
235 | ||
236 | /** | |
237 | * Save the mapping field. | |
238 | * | |
239 | * @param int $mappingID | |
240 | * @param int $columnNumber | |
241 | * @param bool $isUpdate | |
242 | * | |
243 | * @throws \API_Exception | |
244 | * @throws \CRM_Core_Exception | |
245 | */ | |
246 | protected function saveMappingField(int $mappingID, int $columnNumber, bool $isUpdate = FALSE): void { | |
247 | $fieldMapping = (array) $this->getSubmittedValue('mapper')[$columnNumber]; | |
248 | $mappedField = $this->getMappedField($fieldMapping, $mappingID, $columnNumber); | |
992a3d9e EM |
249 | if (empty($mappedField['name'])) { |
250 | $mappedField['name'] = 'do_not_import'; | |
251 | } | |
73edfc10 EM |
252 | if ($isUpdate) { |
253 | Civi\Api4\MappingField::update(FALSE) | |
254 | ->setValues($mappedField) | |
255 | ->addWhere('column_number', '=', $columnNumber) | |
256 | ->addWhere('mapping_id', '=', $mappingID) | |
257 | ->execute(); | |
258 | } | |
259 | else { | |
260 | Civi\Api4\MappingField::create(FALSE) | |
261 | ->setValues($mappedField)->execute(); | |
262 | } | |
263 | } | |
264 | ||
77a9ae24 EM |
265 | /** |
266 | * Save the Field Mapping. | |
267 | * | |
268 | * @param string $mappingType | |
269 | * | |
270 | * @throws \API_Exception | |
271 | * @throws \CRM_Core_Exception | |
272 | */ | |
273 | protected function saveMapping(string $mappingType): void { | |
274 | //Updating Mapping Records | |
275 | if ($this->getSubmittedValue('updateMapping')) { | |
276 | foreach (array_keys($this->getColumnHeaders()) as $i) { | |
277 | $this->saveMappingField($this->getSubmittedValue('mappingId'), $i, TRUE); | |
278 | } | |
279 | } | |
280 | //Saving Mapping Details and Records | |
281 | if ($this->getSubmittedValue('saveMapping')) { | |
282 | $mappingParams = [ | |
283 | 'name' => $this->getSubmittedValue('saveMappingName'), | |
284 | 'description' => $this->getSubmittedValue('saveMappingDesc'), | |
285 | 'mapping_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_Mapping', 'mapping_type_id', $mappingType), | |
286 | ]; | |
287 | $saveMapping = CRM_Core_BAO_Mapping::add($mappingParams); | |
288 | ||
289 | foreach (array_keys($this->getColumnHeaders()) as $i) { | |
290 | $this->saveMappingField($saveMapping->id, $i, FALSE); | |
291 | } | |
292 | $this->set('savedMapping', $saveMapping->id); | |
293 | } | |
294 | } | |
295 | ||
b26295b8 | 296 | } |