Merge pull request #4896 from totten/master-movedep
[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 +--------------------------------------------------------------------+
26*/
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() {
6a488035
TO
74 /*
75 * initialize the task and row fields
76 */
77 parent::preProcess();
78 }
79
80 /**
c490a46a 81 * Build the form object
6a488035 82 *
6a488035
TO
83 *
84 * @return void
85 */
00be9182 86 public function buildQuickForm() {
6a488035
TO
87 $ufGroupId = $this->get('ufGroupId');
88
89 if (!$ufGroupId) {
90 CRM_Core_Error::fatal('ufGroupId is missing');
91 }
92 $this->_title = ts('Batch Update') . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId);
93 CRM_Utils_System::setTitle($this->_title);
94
95 $this->addDefaultButtons(ts('Save'));
96 $this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW);
97
98 // remove file type field and then limit fields
99 $suppressFields = FALSE;
100 $removehtmlTypes = array('File', 'Autocomplete-Select');
101 foreach ($this->_fields as $name => $field) {
102 if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) &&
103 in_array($this->_fields[$name]['html_type'], $removehtmlTypes)
104 ) {
105 $suppressFields = TRUE;
106 unset($this->_fields[$name]);
107 }
108 }
109
110 //FIX ME: phone ext field is added at the end and it gets removed because of below code
111 //$this->_fields = array_slice($this->_fields, 0, $this->_maxFields);
112
113 $this->addButtons(array(
114 array(
115 'type' => 'submit',
116 'name' => ts('Update Contact(s)'),
117 'isDefault' => TRUE,
118 ),
119 array(
120 'type' => 'cancel',
121 'name' => ts('Cancel'),
122 ),
123 )
124 );
125
126
127 $this->assign('profileTitle', $this->_title);
128 $this->assign('componentIds', $this->_contactIds);
129
130 // if below fields are missing we should not reset sort name / display name
131 // CRM-6794
132 $preserveDefaultsArray = array(
353ffa53
TO
133 'first_name',
134 'last_name',
135 'middle_name',
136 'organization_name',
137 'prefix_id',
138 'suffix_id',
6a488035
TO
139 'household_name',
140 );
8ef12e64 141
6a488035
TO
142 foreach ($this->_contactIds as $contactId) {
143 $profileFields = $this->_fields;
144 CRM_Core_BAO_Address::checkContactSharedAddressFields($profileFields, $contactId);
145 foreach ($profileFields as $name => $field) {
146 CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contactId);
147
148 if (in_array($field['name'], $preserveDefaultsArray)) {
149 $this->_preserveDefault = FALSE;
150 }
151 }
152 }
8ef12e64 153
6a488035
TO
154 $this->assign('fields', $this->_fields);
155
156 // don't set the status message when form is submitted.
157 $buttonName = $this->controller->getButtonName('submit');
158
159 if ($suppressFields && $buttonName != '_qf_BatchUpdateProfile_next') {
0feb9734 160 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
161 }
162
163 $this->addDefaultButtons(ts('Update Contacts'));
164 $this->addFormRule(array('CRM_Contact_Form_Task_Batch', 'formRule'));
165 }
166
167 /**
c490a46a 168 * Set default values for the form.
6a488035 169 *
6a488035 170 *
c927c151 171 * @return array
6a488035 172 */
00be9182 173 public function setDefaultValues() {
6a488035
TO
174 if (empty($this->_fields)) {
175 return;
176 }
177
178 $defaults = $sortName = array();
179 foreach ($this->_contactIds as $contactId) {
180 $details[$contactId] = array();
181
182 //build sortname
183 $sortName[$contactId] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
184 $contactId,
185 'sort_name'
186 );
187
188 CRM_Core_BAO_UFGroup::setProfileDefaults($contactId, $this->_fields, $defaults, FALSE);
189 }
190
191 $this->assign('sortName', $sortName);
8ef12e64 192
6a488035
TO
193 return $defaults;
194 }
195
196 /**
100fef9d 197 * Global form rule
6a488035 198 *
77c5b619
TO
199 * @param array $fields
200 * The input form values.
6a488035
TO
201 *
202 * @return true if no errors, else array of errors
6a488035
TO
203 * @static
204 */
00be9182 205 public static function formRule($fields) {
6a488035
TO
206 $errors = array();
207 $externalIdentifiers = array();
208 foreach ($fields['field'] as $componentId => $field) {
209 foreach ($field as $fieldName => $fieldValue) {
210 if ($fieldName == 'external_identifier') {
211 if (in_array($fieldValue, $externalIdentifiers)) {
7b99ead3 212 $errors["field[$componentId][external_identifier]"] = ts('Duplicate value for External ID.');
6a488035
TO
213 }
214 else {
215 $externalIdentifiers[$componentId] = $fieldValue;
216 }
217 }
218 }
219 }
220
221 return $errors;
222 }
223
224 /**
100fef9d 225 * Process the form after the input has been submitted and validated
6a488035 226 *
6a488035 227 *
355ba699 228 * @return void
6a488035
TO
229 */
230 public function postProcess() {
231 $params = $this->exportValues();
232
353ffa53
TO
233 $ufGroupId = $this->get('ufGroupId');
234 $notify = NULL;
6a488035
TO
235 $inValidSubtypeCnt = 0;
236 //send profile notification email if 'notify' field is set
237 $notify = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $ufGroupId, 'notify');
238 foreach ($params['field'] as $key => $value) {
239
240 //CRM-5521
241 //validate subtype before updating
a7488080 242 if (!empty($value['contact_sub_type']) && !CRM_Contact_BAO_ContactType::isAllowEdit($key)) {
6a488035
TO
243 unset($value['contact_sub_type']);
244 $inValidSubtypeCnt++;
245 }
246
247 $value['preserveDBName'] = $this->_preserveDefault;
248
249 //parse street address, CRM-7768
250 self::parseStreetAddress($value, $this);
251
4a679824 252 CRM_Contact_BAO_Contact::createProfileContact($value, $this->_fields, $key, NULL, $ufGroupId, NULL, TRUE);
6a488035
TO
253 if ($notify) {
254 $values = CRM_Core_BAO_UFGroup::checkFieldsEmptyValues($ufGroupId, $key, NULL);
255 CRM_Core_BAO_UFGroup::commonSendMail($key, $values);
256 }
257 }
258
259 CRM_Core_Session::setStatus('', ts("Updates Saved"), 'success');
260 if ($inValidSubtypeCnt) {
353ffa53
TO
261 CRM_Core_Session::setStatus(ts('Contact Subtype field of 1 contact has not been updated.', array(
262 'plural' => 'Contact Subtype field of %count contacts has not been updated.',
263 'count' => $inValidSubtypeCnt
264 )), ts('Invalid Subtype'));
6a488035
TO
265 }
266 }
6a488035 267
afe349ef 268 /**
100fef9d 269 * Parse street address
77c5b619
TO
270 * @param array $contactValues
271 * Contact values.
272 * @param CRM_Core_Form $form
273 * Form object.
afe349ef 274 */
05d1454b
C
275 public static function parseStreetAddress(&$contactValues, &$form) {
276 if (!is_array($contactValues) || !is_array($form->_fields)) {
6a488035
TO
277 return;
278 }
279
280 static $parseAddress;
281 $addressFldKey = 'street_address';
282 if (!isset($parseAddress)) {
283 $parseAddress = FALSE;
284 foreach ($form->_fields as $key => $fld) {
285 if (strpos($key, $addressFldKey) !== FALSE) {
286 $parseAddress = CRM_Utils_Array::value('street_address_parsing',
287 CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
288 'address_options'
289 ),
290 FALSE
291 );
292 break;
293 }
294 }
295 }
296
297 if (!$parseAddress) {
298 return;
299 }
300
301 $allParseValues = array();
302 foreach ($contactValues as $key => $value) {
303 if (strpos($key, $addressFldKey) !== FALSE) {
304 $locTypeId = substr($key, strlen($addressFldKey) + 1);
305
306 // parse address field.
307 $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($value);
308
309 //street address consider to be parsed properly,
310 //If we get street_name and street_number.
8cc574cf 311 if (empty($parsedFields['street_name']) || empty($parsedFields['street_number'])) {
6a488035
TO
312 $parsedFields = array_fill_keys(array_keys($parsedFields), '');
313 }
314
315 //merge parse values.
316 foreach ($parsedFields as $fldKey => $parseVal) {
317 if ($locTypeId) {
318 $fldKey .= "-{$locTypeId}";
319 }
320 $allParseValues[$fldKey] = $parseVal;
321 }
322 }
323 }
324
325 //finally merge all parse values
326 if (!empty($allParseValues)) {
327 $contactValues += $allParseValues;
328 }
329 }
330}