fixed spelling of address on lines 122 and 247
[civicrm-core.git] / CRM / Contact / Form / Task / Batch.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/**
5a409b50 19 * This class provides the functionality for batch profile update.
6a488035
TO
20 */
21class CRM_Contact_Form_Task_Batch extends CRM_Contact_Form_Task {
22
23 /**
fe482240 24 * The title of the group.
6a488035
TO
25 *
26 * @var string
27 */
28 protected $_title;
29
30 /**
fe482240 31 * Maximum contacts that should be allowed to update.
69078420 32 * @var int
6a488035
TO
33 */
34 protected $_maxContacts = 100;
35
36 /**
fe482240 37 * Maximum profile fields that will be displayed.
69078420 38 * @var int
6a488035
TO
39 */
40 protected $_maxFields = 9;
41
42 /**
fe482240 43 * Variable to store redirect path.
69078420 44 * @var string
6a488035
TO
45 */
46 protected $_userContext;
47
48 /**
fe482240 49 * When not to reset sort_name.
69078420 50 * @var bool
6a488035
TO
51 */
52 protected $_preserveDefault = TRUE;
8ef12e64 53
6a488035 54 /**
fe482240 55 * Build all the data structures needed to build the form.
6a488035 56 */
00be9182 57 public function preProcess() {
d424ffde 58 // initialize the task and row fields
6a488035
TO
59 parent::preProcess();
60 }
61
62 /**
fe482240 63 * Build the form object.
6a488035 64 */
00be9182 65 public function buildQuickForm() {
6a488035
TO
66 $ufGroupId = $this->get('ufGroupId');
67
68 if (!$ufGroupId) {
2d296f18 69 CRM_Core_Error::statusBounce(ts('ufGroupId is missing'));
6a488035 70 }
b581842f 71 $this->_title = ts('Update multiple contacts') . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId);
6a488035
TO
72 CRM_Utils_System::setTitle($this->_title);
73
74 $this->addDefaultButtons(ts('Save'));
75 $this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW);
76
77 // remove file type field and then limit fields
78 $suppressFields = FALSE;
be2fb01f 79 $removehtmlTypes = ['File'];
6a488035
TO
80 foreach ($this->_fields as $name => $field) {
81 if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) &&
82 in_array($this->_fields[$name]['html_type'], $removehtmlTypes)
83 ) {
84 $suppressFields = TRUE;
85 unset($this->_fields[$name]);
86 }
87 }
88
89 //FIX ME: phone ext field is added at the end and it gets removed because of below code
90 //$this->_fields = array_slice($this->_fields, 0, $this->_maxFields);
91
be2fb01f 92 $this->addButtons([
69078420
SL
93 [
94 'type' => 'submit',
95 'name' => ts('Update Contact(s)'),
96 'isDefault' => TRUE,
97 ],
98 [
99 'type' => 'cancel',
100 'name' => ts('Cancel'),
101 ],
102 ]);
6a488035 103
6a488035
TO
104 $this->assign('profileTitle', $this->_title);
105 $this->assign('componentIds', $this->_contactIds);
106
107 // if below fields are missing we should not reset sort name / display name
108 // CRM-6794
be2fb01f 109 $preserveDefaultsArray = [
353ffa53
TO
110 'first_name',
111 'last_name',
112 'middle_name',
113 'organization_name',
114 'prefix_id',
115 'suffix_id',
6a488035 116 'household_name',
be2fb01f 117 ];
8ef12e64 118
6a488035
TO
119 foreach ($this->_contactIds as $contactId) {
120 $profileFields = $this->_fields;
121 CRM_Core_BAO_Address::checkContactSharedAddressFields($profileFields, $contactId);
122 foreach ($profileFields as $name => $field) {
123 CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contactId);
124
125 if (in_array($field['name'], $preserveDefaultsArray)) {
126 $this->_preserveDefault = FALSE;
127 }
128 }
129 }
8ef12e64 130
6a488035
TO
131 $this->assign('fields', $this->_fields);
132
133 // don't set the status message when form is submitted.
134 $buttonName = $this->controller->getButtonName('submit');
135
136 if ($suppressFields && $buttonName != '_qf_BatchUpdateProfile_next') {
657c89d9 137 CRM_Core_Session::setStatus(ts("File type field(s) in the selected profile are not supported for Update multiple contacts."), ts('Some Fields Excluded'), 'info');
6a488035
TO
138 }
139
140 $this->addDefaultButtons(ts('Update Contacts'));
be2fb01f 141 $this->addFormRule(['CRM_Contact_Form_Task_Batch', 'formRule']);
6a488035
TO
142 }
143
144 /**
c490a46a 145 * Set default values for the form.
6a488035 146 *
6a488035 147 *
c927c151 148 * @return array
6a488035 149 */
00be9182 150 public function setDefaultValues() {
6a488035 151 if (empty($this->_fields)) {
317fceb4 152 return NULL;
6a488035
TO
153 }
154
be2fb01f 155 $defaults = $sortName = [];
6a488035 156 foreach ($this->_contactIds as $contactId) {
be2fb01f 157 $details[$contactId] = [];
6a488035
TO
158
159 //build sortname
160 $sortName[$contactId] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
161 $contactId,
162 'sort_name'
163 );
164
165 CRM_Core_BAO_UFGroup::setProfileDefaults($contactId, $this->_fields, $defaults, FALSE);
166 }
167
168 $this->assign('sortName', $sortName);
8ef12e64 169
6a488035
TO
170 return $defaults;
171 }
172
173 /**
fe482240 174 * Global form rule.
6a488035 175 *
77c5b619
TO
176 * @param array $fields
177 * The input form values.
6a488035 178 *
72b3a70c
CW
179 * @return bool|array
180 * true if no errors, else array of errors
6a488035 181 */
00be9182 182 public static function formRule($fields) {
be2fb01f
CW
183 $errors = [];
184 $externalIdentifiers = [];
6a488035
TO
185 foreach ($fields['field'] as $componentId => $field) {
186 foreach ($field as $fieldName => $fieldValue) {
187 if ($fieldName == 'external_identifier') {
188 if (in_array($fieldValue, $externalIdentifiers)) {
7b99ead3 189 $errors["field[$componentId][external_identifier]"] = ts('Duplicate value for External ID.');
6a488035
TO
190 }
191 else {
192 $externalIdentifiers[$componentId] = $fieldValue;
193 }
194 }
195 }
196 }
197
198 return $errors;
199 }
200
201 /**
fe482240 202 * Process the form after the input has been submitted and validated.
6a488035
TO
203 */
204 public function postProcess() {
205 $params = $this->exportValues();
206
3eb99314 207 // @todo extract submit functions &
208 // extend CRM_Event_Form_Task_BatchTest::testSubmit with a data provider to test
209 // handling of custom data, specifically checkbox fields.
353ffa53
TO
210 $ufGroupId = $this->get('ufGroupId');
211 $notify = NULL;
6a488035
TO
212 $inValidSubtypeCnt = 0;
213 //send profile notification email if 'notify' field is set
214 $notify = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $ufGroupId, 'notify');
215 foreach ($params['field'] as $key => $value) {
216
217 //CRM-5521
218 //validate subtype before updating
a7488080 219 if (!empty($value['contact_sub_type']) && !CRM_Contact_BAO_ContactType::isAllowEdit($key)) {
6a488035
TO
220 unset($value['contact_sub_type']);
221 $inValidSubtypeCnt++;
222 }
223
224 $value['preserveDBName'] = $this->_preserveDefault;
225
226 //parse street address, CRM-7768
227 self::parseStreetAddress($value, $this);
228
4a679824 229 CRM_Contact_BAO_Contact::createProfileContact($value, $this->_fields, $key, NULL, $ufGroupId, NULL, TRUE);
6a488035
TO
230 if ($notify) {
231 $values = CRM_Core_BAO_UFGroup::checkFieldsEmptyValues($ufGroupId, $key, NULL);
232 CRM_Core_BAO_UFGroup::commonSendMail($key, $values);
233 }
234 }
235
236 CRM_Core_Session::setStatus('', ts("Updates Saved"), 'success');
237 if ($inValidSubtypeCnt) {
be2fb01f 238 CRM_Core_Session::setStatus(ts('Contact Subtype field of 1 contact has not been updated.', [
69078420
SL
239 'plural' => 'Contact Subtype field of %count contacts has not been updated.',
240 'count' => $inValidSubtypeCnt,
241 ]), ts('Invalid Subtype'));
6a488035
TO
242 }
243 }
6a488035 244
afe349ef 245 /**
fe482240 246 * Parse street address.
5a409b50 247 *
77c5b619
TO
248 * @param array $contactValues
249 * Contact values.
250 * @param CRM_Core_Form $form
251 * Form object.
afe349ef 252 */
05d1454b
C
253 public static function parseStreetAddress(&$contactValues, &$form) {
254 if (!is_array($contactValues) || !is_array($form->_fields)) {
6a488035
TO
255 return;
256 }
257
258 static $parseAddress;
259 $addressFldKey = 'street_address';
260 if (!isset($parseAddress)) {
261 $parseAddress = FALSE;
262 foreach ($form->_fields as $key => $fld) {
263 if (strpos($key, $addressFldKey) !== FALSE) {
264 $parseAddress = CRM_Utils_Array::value('street_address_parsing',
265 CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
266 'address_options'
267 ),
268 FALSE
269 );
270 break;
271 }
272 }
273 }
274
275 if (!$parseAddress) {
276 return;
277 }
278
be2fb01f 279 $allParseValues = [];
6a488035
TO
280 foreach ($contactValues as $key => $value) {
281 if (strpos($key, $addressFldKey) !== FALSE) {
282 $locTypeId = substr($key, strlen($addressFldKey) + 1);
283
284 // parse address field.
285 $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($value);
286
287 //street address consider to be parsed properly,
288 //If we get street_name and street_number.
8cc574cf 289 if (empty($parsedFields['street_name']) || empty($parsedFields['street_number'])) {
6a488035
TO
290 $parsedFields = array_fill_keys(array_keys($parsedFields), '');
291 }
292
293 //merge parse values.
294 foreach ($parsedFields as $fldKey => $parseVal) {
295 if ($locTypeId) {
296 $fldKey .= "-{$locTypeId}";
297 }
298 $allParseValues[$fldKey] = $parseVal;
299 }
300 }
301 }
302
303 //finally merge all parse values
304 if (!empty($allParseValues)) {
305 $contactValues += $allParseValues;
306 }
307 }
96025800 308
6a488035 309}