3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * This class provides the functionality for batch profile update.
21 class CRM_Contact_Form_Task_Batch
extends CRM_Contact_Form_Task
{
24 * The title of the group.
31 * Maximum contacts that should be allowed to update.
34 protected $_maxContacts = 100;
37 * Maximum profile fields that will be displayed.
40 protected $_maxFields = 9;
43 * Variable to store redirect path.
46 protected $_userContext;
49 * When not to reset sort_name.
52 protected $_preserveDefault = TRUE;
55 * Build all the data structures needed to build the form.
57 public function preProcess() {
58 // initialize the task and row fields
63 * Build the form object.
65 public function buildQuickForm() {
66 $ufGroupId = $this->get('ufGroupId');
69 CRM_Core_Error
::fatal('ufGroupId is missing');
71 $this->_title
= ts('Update multiple contacts') . ' - ' . CRM_Core_BAO_UFGroup
::getTitle($ufGroupId);
72 CRM_Utils_System
::setTitle($this->_title
);
74 $this->addDefaultButtons(ts('Save'));
75 $this->_fields
= CRM_Core_BAO_UFGroup
::getFields($ufGroupId, FALSE, CRM_Core_Action
::VIEW
);
77 // remove file type field and then limit fields
78 $suppressFields = FALSE;
79 $removehtmlTypes = ['File'];
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)
84 $suppressFields = TRUE;
85 unset($this->_fields
[$name]);
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);
95 'name' => ts('Update Contact(s)'),
100 'name' => ts('Cancel'),
104 $this->assign('profileTitle', $this->_title
);
105 $this->assign('componentIds', $this->_contactIds
);
107 // if below fields are missing we should not reset sort name / display name
109 $preserveDefaultsArray = [
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);
125 if (in_array($field['name'], $preserveDefaultsArray)) {
126 $this->_preserveDefault
= FALSE;
131 $this->assign('fields', $this->_fields
);
133 // don't set the status message when form is submitted.
134 $buttonName = $this->controller
->getButtonName('submit');
136 if ($suppressFields && $buttonName != '_qf_BatchUpdateProfile_next') {
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');
140 $this->addDefaultButtons(ts('Update Contacts'));
141 $this->addFormRule(['CRM_Contact_Form_Task_Batch', 'formRule']);
145 * Set default values for the form.
150 public function setDefaultValues() {
151 if (empty($this->_fields
)) {
155 $defaults = $sortName = [];
156 foreach ($this->_contactIds
as $contactId) {
157 $details[$contactId] = [];
160 $sortName[$contactId] = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
165 CRM_Core_BAO_UFGroup
::setProfileDefaults($contactId, $this->_fields
, $defaults, FALSE);
168 $this->assign('sortName', $sortName);
176 * @param array $fields
177 * The input form values.
180 * true if no errors, else array of errors
182 public static function formRule($fields) {
184 $externalIdentifiers = [];
185 foreach ($fields['field'] as $componentId => $field) {
186 foreach ($field as $fieldName => $fieldValue) {
187 if ($fieldName == 'external_identifier') {
188 if (in_array($fieldValue, $externalIdentifiers)) {
189 $errors["field[$componentId][external_identifier]"] = ts('Duplicate value for External ID.');
192 $externalIdentifiers[$componentId] = $fieldValue;
202 * Process the form after the input has been submitted and validated.
204 public function postProcess() {
205 $params = $this->exportValues();
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.
210 $ufGroupId = $this->get('ufGroupId');
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) {
218 //validate subtype before updating
219 if (!empty($value['contact_sub_type']) && !CRM_Contact_BAO_ContactType
::isAllowEdit($key)) {
220 unset($value['contact_sub_type']);
221 $inValidSubtypeCnt++
;
224 $value['preserveDBName'] = $this->_preserveDefault
;
226 //parse street address, CRM-7768
227 self
::parseStreetAddress($value, $this);
229 CRM_Contact_BAO_Contact
::createProfileContact($value, $this->_fields
, $key, NULL, $ufGroupId, NULL, TRUE);
231 $values = CRM_Core_BAO_UFGroup
::checkFieldsEmptyValues($ufGroupId, $key, NULL);
232 CRM_Core_BAO_UFGroup
::commonSendMail($key, $values);
236 CRM_Core_Session
::setStatus('', ts("Updates Saved"), 'success');
237 if ($inValidSubtypeCnt) {
238 CRM_Core_Session
::setStatus(ts('Contact Subtype field of 1 contact has not been updated.', [
239 'plural' => 'Contact Subtype field of %count contacts has not been updated.',
240 'count' => $inValidSubtypeCnt,
241 ]), ts('Invalid Subtype'));
246 * Parse street address.
248 * @param array $contactValues
250 * @param CRM_Core_Form $form
253 public static function parseStreetAddress(&$contactValues, &$form) {
254 if (!is_array($contactValues) ||
!is_array($form->_fields
)) {
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
,
275 if (!$parseAddress) {
279 $allParseValues = [];
280 foreach ($contactValues as $key => $value) {
281 if (strpos($key, $addressFldKey) !== FALSE) {
282 $locTypeId = substr($key, strlen($addressFldKey) +
1);
284 // parse address field.
285 $parsedFields = CRM_Core_BAO_Address
::parseStreetAddress($value);
287 //street address consider to be parsed properly,
288 //If we get street_name and street_number.
289 if (empty($parsedFields['street_name']) ||
empty($parsedFields['street_number'])) {
290 $parsedFields = array_fill_keys(array_keys($parsedFields), '');
293 //merge parse values.
294 foreach ($parsedFields as $fldKey => $parseVal) {
296 $fldKey .= "-{$locTypeId}";
298 $allParseValues[$fldKey] = $parseVal;
303 //finally merge all parse values
304 if (!empty($allParseValues)) {
305 $contactValues +
= $allParseValues;