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