Merge pull request #20150 from MegaphoneJon/backoffice-xfer
[civicrm-core.git] / CRM / Export / Form / Select.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 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 |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
19 * This class gets the name of the file to upload
20 */
31aaf096 21class CRM_Export_Form_Select extends CRM_Core_Form_Task {
6a488035
TO
22
23 /**
fe482240 24 * Various Contact types.
6a488035 25 */
7da04cde 26 const
0e6e8724
DL
27 EXPORT_ALL = 1,
28 EXPORT_SELECTED = 2,
29 EXPORT_MERGE_DO_NOT_MERGE = 0,
30 EXPORT_MERGE_SAME_ADDRESS = 1,
31 EXPORT_MERGE_HOUSEHOLD = 2;
6a488035
TO
32
33 /**
fe482240 34 * Export modes.
6a488035 35 */
7da04cde 36 const
0e6e8724
DL
37 CONTACT_EXPORT = 1,
38 CONTRIBUTE_EXPORT = 2,
39 MEMBER_EXPORT = 3,
40 EVENT_EXPORT = 4,
41 PLEDGE_EXPORT = 5,
42 CASE_EXPORT = 6,
43 GRANT_EXPORT = 7,
44 ACTIVITY_EXPORT = 8;
6a488035
TO
45
46 /**
fe482240 47 * Current export mode.
6a488035
TO
48 *
49 * @var int
50 */
51 public $_exportMode;
52
53 public $_componentTable;
54
e2710fee 55 /**
56 * Use the form name to create the tpl file name.
57 *
58 * @return string
59 */
60 public function getTemplateFileName() {
61 return 'CRM/Export/Form/Select.tpl';
62 }
63
6a488035 64 /**
fe482240 65 * Build all the data structures needed to build the form.
6a488035
TO
66 *
67 * @param
68 *
69 * @return void
6a488035 70 */
00be9182 71 public function preProcess() {
df4c8e9c
CW
72 $this->preventAjaxSubmit();
73
6a488035 74 //special case for custom search, directly give option to download csv file
7b845814 75 $customSearchID = $this->get('customSearchID');
76 if ($customSearchID) {
77 CRM_Export_BAO_Export::exportCustom($this->get('customSearchClass'),
78 $this->get('formValues'),
79 $this->get(CRM_Utils_Sort::SORT_ORDER)
80 );
81 }
6a488035
TO
82
83 $this->_selectAll = FALSE;
84 $this->_exportMode = self::CONTACT_EXPORT;
be2fb01f 85 $this->_componentIds = [];
6a488035
TO
86 $this->_componentClause = NULL;
87
3b4adc92 88 // FIXME: This should use a modified version of CRM_Contact_Form_Search::getModeValue but it doesn't have all the contexts
ae70f47e 89 // FIXME: Or better still, use CRM_Core_DAO_AllCoreTables::getBriefName($daoName) to get the $entityShortName
dabe5cd5 90 $entityShortname = $this->getEntityShortName();
3b4adc92 91
6ec388a8 92 if (!in_array($entityShortname, ['Contact', 'Contribute', 'Member', 'Event', 'Pledge', 'Case', 'Grant', 'Activity'], TRUE)) {
93 // This is never reached - the exception here is just to clarify that entityShortName MUST be one of the above
94 // to save future refactorers & reviewers from asking that question.
95 throw new CRM_Core_Exception('Unreachable code');
96 }
97 $this->_exportMode = constant('CRM_Export_Form_Select::' . strtoupper($entityShortname) . '_EXPORT');
3b4adc92 98
ab3e9e4c 99 $this::$entityShortname = strtolower($entityShortname);
2d09a0c3 100 $values = $this->getSearchFormValues();
6a488035
TO
101
102 $count = 0;
103 $this->_matchingContacts = FALSE;
104 if (CRM_Utils_Array::value('radio_ts', $values) == 'ts_sel') {
105 foreach ($values as $key => $value) {
106 if (strstr($key, 'mark_x')) {
107 $count++;
108 }
109 if ($count > 2) {
110 $this->_matchingContacts = TRUE;
111 break;
112 }
113 }
114 }
115
f95d7a08 116 $this->callPreProcessing();
6886d6f2 117
3b4adc92
MW
118 // $component is used on CRM/Export/Form/Select.tpl to display extra information for contact export
119 ($this->_exportMode == self::CONTACT_EXPORT) ? $component = FALSE : $component = TRUE;
120 $this->assign('component', $component);
6a488035 121
f95d7a08 122 $this->assign('isShowMergeOptions', $this->isShowContactMergeOptions());
6a488035
TO
123
124 if ($this->_componentTable) {
125 $query = "
126SELECT count(*)
127FROM {$this->_componentTable}
128";
129 $totalSelectedRecords = CRM_Core_DAO::singleValueQuery($query);
130 }
131 else {
132 $totalSelectedRecords = count($this->_componentIds);
133 }
134 $this->assign('totalSelectedRecords', $totalSelectedRecords);
3b4adc92 135
6a488035
TO
136 // all records actions = save a search
137 if (($values['radio_ts'] == 'ts_all') || ($this->_task == CRM_Contact_Task::SAVE_SEARCH)) {
138 $this->_selectAll = TRUE;
139 $rowCount = $this->get('rowCount');
140 if ($rowCount > 2) {
141 $this->_matchingContacts = TRUE;
142 }
143 $this->assign('totalSelectedRecords', $rowCount);
144 }
145
146 $this->assign('matchingContacts', $this->_matchingContacts);
147 $this->set('componentIds', $this->_componentIds);
148 $this->set('selectAll', $this->_selectAll);
149 $this->set('exportMode', $this->_exportMode);
150 $this->set('componentClause', $this->_componentClause);
ab3e9e4c 151 $this->set('componentTable', $this->getTableName());
152 }
153
154 /**
155 * Get the name of the table for the relevant entity.
156 */
157 public function getTableName() {
158 throw new CRM_Core_Exception('should be over-riden');
6a488035
TO
159 }
160
161 /**
fe482240 162 * Build the form object.
6a488035
TO
163 *
164 * @return void
6a488035
TO
165 */
166 public function buildQuickForm() {
167 //export option
2428bd14
SL
168 $exportOptions = $exportOptionsJS = $mergeOptions = $mergeOptionsJS = $postalMailing = [];
169 $exportOptions[self::EXPORT_ALL] = ts('Export PRIMARY fields');
170 $exportOptions[self::EXPORT_SELECTED] = ts('Select fields for export');
171 $mergeOptions[self::EXPORT_MERGE_DO_NOT_MERGE] = ts('Do not merge');
172 $mergeOptions[self::EXPORT_MERGE_SAME_ADDRESS] = ts('Merge All Contacts with the Same Address');
173 $mergeOptions[self::EXPORT_MERGE_HOUSEHOLD] = ts('Merge Household Members into their Households');
174 foreach (array_keys($exportOptions) as $key) {
175 $exportOptionsJS[$key] = ['onClick' => 'showMappingOption( );'];
176 }
177 foreach (array_keys($mergeOptions) as $key) {
178 $mergeOptionsJS[$key] = ['onclick' => 'showGreetingOptions( );'];
179 }
180 $this->addRadio('exportOption', ts('Export Type'), $exportOptions, [], '<br/>', FALSE, $exportOptionsJS);
6a488035
TO
181 $postalMailing[] = $this->createElement('advcheckbox',
182 'postal_mailing_export',
183 NULL,
184 NULL
185 );
186
6a488035
TO
187 if ($this->_matchingContacts) {
188 $this->_greetingOptions = self::getGreetingOptions();
189
190 foreach ($this->_greetingOptions as $key => $value) {
ee769c00 191 $fieldLabel = ts('%1 (when merging contacts)', [1 => ucwords(str_replace('_', ' ', $key))]);
6a488035 192 $this->addElement('select', $key, $fieldLabel,
be2fb01f 193 $value, ['onchange' => "showOther(this);"]
6a488035
TO
194 );
195 $this->addElement('text', "{$key}_other", '');
196 }
197 }
198
199 if ($this->_exportMode == self::CONTACT_EXPORT) {
2428bd14 200 $this->addRadio('mergeOption', ts('Merge Options'), $mergeOptions, [], '<br/>', FALSE, $mergeOptionsJS);
6a488035
TO
201 $this->addGroup($postalMailing, 'postal_mailing_export', ts('Postal Mailing Export'), '<br/>');
202
203 $this->addElement('select', 'additional_group', ts('Additional Group for Export'),
be2fb01f
CW
204 ['' => ts('- select group -')] + CRM_Core_PseudoConstant::nestedGroup(),
205 ['class' => 'crm-select2 huge']
6a488035
TO
206 );
207 }
208
209 $this->buildMapping();
210
be2fb01f 211 $this->setDefaults([
6a488035 212 'exportOption' => self::EXPORT_ALL,
353ffa53 213 'mergeOption' => self::EXPORT_MERGE_DO_NOT_MERGE,
be2fb01f 214 ]);
6a488035 215
be2fb01f 216 $this->addButtons([
7b966967
SL
217 [
218 'type' => 'next',
219 'name' => ts('Continue'),
220 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
221 'isDefault' => TRUE,
222 ],
223 [
224 'type' => 'cancel',
225 'name' => ts('Cancel'),
226 ],
227 ]);
6a488035 228
be2fb01f 229 $this->addFormRule(['CRM_Export_Form_Select', 'formRule'], $this);
6a488035
TO
230 }
231
232 /**
fe482240 233 * Validation.
6a488035 234 *
b9add4b3
TO
235 * @param array $params
236 * (ref.) an assoc array of name/value pairs.
6a488035 237 *
fd31fa4c
EM
238 * @param $files
239 * @param $self
240 *
72b3a70c
CW
241 * @return bool|array
242 * mixed true or array of errors
6a488035 243 */
a0174743 244 public static function formRule($params, $files, $self) {
be2fb01f 245 $errors = [];
6a488035
TO
246
247 if (CRM_Utils_Array::value('mergeOption', $params) == self::EXPORT_MERGE_SAME_ADDRESS &&
248 $self->_matchingContacts
249 ) {
be2fb01f 250 $greetings = [
6a488035
TO
251 'postal_greeting' => 'postal_greeting_other',
252 'addressee' => 'addressee_other',
be2fb01f 253 ];
6a488035
TO
254
255 foreach ($greetings as $key => $value) {
9c1bc317 256 $otherOption = $params[$key] ?? NULL;
6a488035 257
8cc574cf 258 if ((CRM_Utils_Array::value($otherOption, $self->_greetingOptions[$key]) == ts('Other')) && empty($params[$value])) {
6a488035
TO
259
260 $label = ucwords(str_replace('_', ' ', $key));
ee769c00 261 $errors[$value] = ts('Please enter a value for %1 (when merging contacts), or select a pre-configured option from the list.', [1 => $label]);
6a488035
TO
262 }
263 }
264 }
265
266 return empty($errors) ? TRUE : $errors;
267 }
268
269 /**
fe482240 270 * Process the uploaded file.
6a488035 271 *
a0174743 272 * @throws \CRM_Core_Exception
6a488035
TO
273 */
274 public function postProcess() {
353ffa53
TO
275 $params = $this->controller->exportValues($this->_name);
276 $exportOption = $params['exportOption'];
277 $mergeSameAddress = CRM_Utils_Array::value('mergeOption', $params) == self::EXPORT_MERGE_SAME_ADDRESS ? 1 : 0;
6a488035
TO
278 $mergeSameHousehold = CRM_Utils_Array::value('mergeOption', $params) == self::EXPORT_MERGE_HOUSEHOLD ? 1 : 0;
279
280 $this->set('mergeSameAddress', $mergeSameAddress);
281 $this->set('mergeSameHousehold', $mergeSameHousehold);
282
283 // instead of increasing the number of arguments to exportComponents function, we
284 // will send $exportParams as another argument, which is an array and suppose to contain
285 // all submitted options or any other argument
286 $exportParams = $params;
287
9c1bc317 288 $mappingId = $params['mapping'] ?? NULL;
6a488035
TO
289 if ($mappingId) {
290 $this->set('mappingId', $mappingId);
291 }
292 else {
293 $this->set('mappingId', NULL);
294 }
295
6a488035 296 if ($exportOption == self::EXPORT_ALL) {
7b845814 297 CRM_Export_BAO_Export::exportComponents($this->_selectAll,
298 $this->_componentIds,
299 (array) $this->get('queryParams'),
300 $this->get(CRM_Utils_Sort::SORT_ORDER),
301 NULL,
302 $this->get('returnProperties'),
303 $this->_exportMode,
304 $this->_componentClause,
305 $this->_componentTable,
306 $mergeSameAddress,
307 $mergeSameHousehold,
308 $exportParams,
309 $this->get('queryOperator')
310 );
6a488035
TO
311 }
312
313 //reset map page
314 $this->controller->resetPage('Map');
315 }
316
317 /**
318 * Return a descriptive name for the page, used in wizard header
319 *
320 * @return string
6a488035
TO
321 */
322 public function getTitle() {
653f9ec1 323 return ts('Export Options');
6a488035
TO
324 }
325
326 /**
fe482240 327 * Build mapping form element.
6a488035 328 */
00be9182 329 public function buildMapping() {
6a488035
TO
330 switch ($this->_exportMode) {
331 case CRM_Export_Form_Select::CONTACT_EXPORT:
332 $exportType = 'Export Contact';
333 break;
334
335 case CRM_Export_Form_Select::CONTRIBUTE_EXPORT:
336 $exportType = 'Export Contribution';
337 break;
338
339 case CRM_Export_Form_Select::MEMBER_EXPORT:
340 $exportType = 'Export Membership';
341 break;
342
343 case CRM_Export_Form_Select::EVENT_EXPORT:
344 $exportType = 'Export Participant';
345 break;
346
347 case CRM_Export_Form_Select::PLEDGE_EXPORT:
348 $exportType = 'Export Pledge';
349 break;
350
351 case CRM_Export_Form_Select::CASE_EXPORT:
352 $exportType = 'Export Case';
353 break;
354
355 case CRM_Export_Form_Select::GRANT_EXPORT:
356 $exportType = 'Export Grant';
357 break;
358
359 case CRM_Export_Form_Select::ACTIVITY_EXPORT:
360 $exportType = 'Export Activity';
361 break;
362 }
363
95f52e3b 364 $this->set('mappingTypeId', CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_Mapping', 'mapping_type_id', $exportType));
6a488035 365
4f55a797 366 $mappings = CRM_Core_BAO_Mapping::getMappings($exportType, TRUE);
6a488035 367 if (!empty($mappings)) {
4f55a797 368 $this->add('select2', 'mapping', ts('Use Saved Field Mapping'), $mappings, FALSE, ['placeholder' => ts('- select -')]);
6a488035
TO
369 }
370 }
371
e0ef6999
EM
372 /**
373 * @return array
374 */
00be9182 375 public static function getGreetingOptions() {
be2fb01f
CW
376 $options = [];
377 $greetings = [
6a488035
TO
378 'postal_greeting' => 'postal_greeting_other',
379 'addressee' => 'addressee_other',
be2fb01f 380 ];
6a488035
TO
381
382 foreach ($greetings as $key => $value) {
be2fb01f 383 $params = [];
6a488035
TO
384 $optionGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', $key, 'id', 'name');
385
386 CRM_Core_DAO::commonRetrieveAll('CRM_Core_DAO_OptionValue', 'option_group_id', $optionGroupId,
be2fb01f 387 $params, ['label', 'filter']
6a488035
TO
388 );
389
390 $greetingCount = 1;
be2fb01f 391 $options[$key] = ["$greetingCount" => ts('List of names')];
6a488035
TO
392
393 foreach ($params as $id => $field) {
394 if (CRM_Utils_Array::value('filter', $field) == 4) {
395 $options[$key][++$greetingCount] = $field['label'];
396 }
397 }
398
399 $options[$key][++$greetingCount] = ts('Other');
400 }
401
402 return $options;
403 }
96025800 404
a0174743 405 /**
acc45bb8 406 * Get the query mode (eg. CRM_Contact_BAO_Query::MODE_CASE)
a0174743
MW
407 *
408 * @return int
409 */
410 public function getQueryMode() {
d5fd18f6 411 return (int) ($this->queryMode ?: $this->controller->get('component_mode'));
a0174743
MW
412 }
413
f95d7a08 414 /**
415 * Call the pre-processing function.
416 */
417 protected function callPreProcessing(): void {
418 throw new CRM_Core_Exception('This must be over-ridden');
419 }
420
421 /**
422 * Assign the title of the task to the tpl.
423 */
424 protected function isShowContactMergeOptions() {
425 throw new CRM_Core_Exception('This must be over-ridden');
426 }
427
239d4cf8 428 /**
429 * Get the name of the component.
430 *
431 * @return array
432 */
433 protected function getComponentName(): string {
d532b686 434 // CRM_Export_Controller_Standalone has this method
239d4cf8 435 if (method_exists($this->controller, 'getComponent')) {
436 return $this->controller->getComponent();
437 }
d532b686 438 // For others, just guess based on the name of the controller
239d4cf8 439 $formName = CRM_Utils_System::getClassName($this->controller->getStateMachine());
440 $componentName = explode('_', $formName);
441 return $componentName[1];
442 }
443
dabe5cd5 444 /**
445 * Get the DAO name for the given export.
446 *
447 * @return string
448 */
449 protected function getDAOName(): string {
450 switch ($this->getQueryMode()) {
451 case CRM_Contact_BAO_Query::MODE_CONTRIBUTE:
452 return 'Contribute';
453
454 case CRM_Contact_BAO_Query::MODE_MEMBER:
455 return 'Membership';
456
457 case CRM_Contact_BAO_Query::MODE_EVENT:
458 return 'Event';
459
460 case CRM_Contact_BAO_Query::MODE_PLEDGE:
461 return 'Pledge';
462
463 case CRM_Contact_BAO_Query::MODE_CASE:
464 return 'Case';
465
466 case CRM_Contact_BAO_Query::MODE_GRANT:
467 return 'Grant';
468
469 case CRM_Contact_BAO_Query::MODE_ACTIVITY:
470 return 'Activity';
471
472 default:
473 return $this->controller->get('entity') ?? $this->getComponentName();
474 }
475 }
476
477 /**
478 * Get the entity short name for a given export.
479 *
480 * @return string
481 */
482 protected function getEntityShortName(): string {
483 switch ($this->getQueryMode()) {
484 case CRM_Contact_BAO_Query::MODE_CONTRIBUTE:
485 return 'Contribute';
486
487 case CRM_Contact_BAO_Query::MODE_MEMBER:
488 return 'Member';
489
490 case CRM_Contact_BAO_Query::MODE_EVENT:
491 return 'Event';
492
493 case CRM_Contact_BAO_Query::MODE_PLEDGE:
494 return 'Pledge';
495
496 case CRM_Contact_BAO_Query::MODE_CASE:
497 return 'Case';
498
499 case CRM_Contact_BAO_Query::MODE_GRANT:
500 return 'Grant';
501
502 case CRM_Contact_BAO_Query::MODE_ACTIVITY:
503 return 'Activity';
504
505 default:
506 return $this->getComponentName();
507 }
508 }
509
6a488035 510}