Merge pull request #4737 from eileenmcnaughton/master
[civicrm-core.git] / CRM / Contact / Form / Task.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
06b69b18 4 | CiviCRM version 4.5 |
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 generates form components for search-result tasks
38 *
39 */
40class CRM_Contact_Form_Task extends CRM_Core_Form {
41
42 /**
100fef9d 43 * The task being performed
6a488035
TO
44 *
45 * @var int
46 */
47 protected $_task;
48
49 /**
50 * The array that holds all the contact ids
51 *
52 * @var array
53 */
54 public $_contactIds;
55
56 /**
57 * The array that holds all the contact types
58 *
59 * @var array
60 */
61 public $_contactTypes;
62
63 /**
64 * The additional clause that we restrict the search with
65 *
66 * @var string
67 */
68 protected $_componentClause = NULL;
69
70 /**
71 * The name of the temp table where we store the contact IDs
72 *
73 * @var string
74 */
75 protected $_componentTable = NULL;
76
77 /**
78 * The array that holds all the component ids
79 *
80 * @var array
81 */
82 protected $_componentIds;
83
84 /**
85 * This includes the submitted values of the search form
86 */
87 static protected $_searchFormValues;
88
89 /**
100fef9d 90 * Build all the data structures needed to build the form
6a488035
TO
91 *
92 * @param
93 *
94 * @return void
95 * @access public
8ef12e64 96 */
6a488035
TO
97 function preProcess() {
98 self::preProcessCommon($this);
99 }
100
86538308 101 /**
c490a46a 102 * @param CRM_Core_Form $form
86538308
EM
103 * @param bool $useTable
104 */
6a488035
TO
105 static function preProcessCommon(&$form, $useTable = FALSE) {
106
107 $form->_contactIds = array();
108 $form->_contactTypes = array();
109
110 // get the submitted values of the search form
111 // we'll need to get fv from either search or adv search in the future
112 $fragment = 'search';
113 if ($form->_action == CRM_Core_Action::ADVANCED) {
114 self::$_searchFormValues = $form->controller->exportValues('Advanced');
115 $fragment .= '/advanced';
116 }
117 elseif ($form->_action == CRM_Core_Action::PROFILE) {
118 self::$_searchFormValues = $form->controller->exportValues('Builder');
119 $fragment .= '/builder';
120 }
121 elseif ($form->_action == CRM_Core_Action::COPY) {
122 self::$_searchFormValues = $form->controller->exportValues('Custom');
123 $fragment .= '/custom';
124 }
125 else {
126 self::$_searchFormValues = $form->controller->exportValues('Basic');
127 }
128
129 //set the user context for redirection of task actions
130 $qfKey = CRM_Utils_Request::retrieve('qfKey', 'String', $form);
131 $urlParams = 'force=1';
132 if (CRM_Utils_Rule::qfKey($qfKey)) {
133 $urlParams .= "&qfKey=$qfKey";
134 }
135
136 $cacheKey = "civicrm search {$qfKey}";
137
138 $url = CRM_Utils_System::url('civicrm/contact/' . $fragment, $urlParams);
139 $session = CRM_Core_Session::singleton();
140 $session->replaceUserContext($url);
141
142 $form->_task = CRM_Utils_Array::value('task', self::$_searchFormValues);
143 $crmContactTaskTasks = CRM_Contact_Task::taskTitles();
144 $form->assign('taskName', CRM_Utils_Array::value($form->_task, $crmContactTaskTasks));
145
146 if ($useTable) {
147 $form->_componentTable = CRM_Core_DAO::createTempTableName('civicrm_task_action', TRUE, $qfKey);
148 $sql = " DROP TABLE IF EXISTS {$form->_componentTable}";
149 CRM_Core_DAO::executeQuery($sql);
150
151 $sql = "CREATE TABLE {$form->_componentTable} ( contact_id int primary key) ENGINE=MyISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci";
152 CRM_Core_DAO::executeQuery($sql);
153 }
154
155 // all contacts or action = save a search
156 if ((CRM_Utils_Array::value('radio_ts', self::$_searchFormValues) == 'ts_all') ||
157 ($form->_task == CRM_Contact_Task::SAVE_SEARCH)
158 ) {
159 $sortByCharacter = $form->get('sortByCharacter');
5d272ea2 160 $cacheKey = ($sortByCharacter && $sortByCharacter != 'all') ? "{$cacheKey}_alphabet" : $cacheKey;
8ef12e64 161
66ceb5d9 162 // since we don't store all contacts in prevnextcache, when user selects "all" use query to retrieve contacts
8e1a7c71 163 // rather than prevnext cache table for most of the task actions except export where we rebuild query to fetch
164 // final result set
165 if ($useTable) {
166 $allCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey, "getall");
167 }
168 else {
169 $allCids[$cacheKey] = $form->getContactIds();
170 }
6a488035
TO
171
172 $form->_contactIds = array();
173 if ($useTable) {
174 $count = 0;
175 $insertString = array();
176 foreach ($allCids[$cacheKey] as $cid => $ignore) {
177 $count++;
178 $insertString[] = " ( {$cid} ) ";
179 if ($count % 200 == 0) {
180 $string = implode(',', $insertString);
181 $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string";
182 CRM_Core_DAO::executeQuery($sql);
183 $insertString = array();
184 }
185 }
186 if (!empty($insertString)) {
187 $string = implode(',', $insertString);
188 $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string";
189 CRM_Core_DAO::executeQuery($sql);
190 }
191 }
192 else {
193 // filter duplicates here
194 // CRM-7058
195 // might be better to do this in the query, but that logic is a bit complex
196 // and it decides when to use distinct based on input criteria, which needs
197 // to be fixed and optimized.
198
199 foreach ($allCids[$cacheKey] as $cid => $ignore) {
200 $form->_contactIds[] = $cid;
201 }
202 }
203 }
204 elseif (CRM_Utils_Array::value('radio_ts', self::$_searchFormValues) == 'ts_sel') {
205 // selected contacts only
206 // need to perform action on only selected contacts
207 $insertString = array();
208
209 // refire sql in case of custom seach
210 if ($form->_action == CRM_Core_Action::COPY) {
211 // selected contacts only
212 // need to perform action on only selected contacts
213 foreach (self::$_searchFormValues as $name => $value) {
214 if (substr($name, 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) {
215 $contactID = substr($name, CRM_Core_Form::CB_PREFIX_LEN);
216 if ($useTable) {
217 $insertString[] = " ( {$contactID} ) ";
218 }
219 else {
220 $form->_contactIds[] = substr($name, CRM_Core_Form::CB_PREFIX_LEN);
221 }
222 }
223 }
224 }
225 else {
5d272ea2 226 // fetching selected contact ids of passed cache key
227 $selectedCids = CRM_Core_BAO_PrevNextCache::getSelection($cacheKey);
228 foreach ($selectedCids[$cacheKey] as $selectedCid => $ignore) {
229 if ($useTable) {
230 $insertString[] = " ( {$selectedCid} ) ";
231 }
232 else {
233 $form->_contactIds[] = $selectedCid;
234 }
6a488035
TO
235 }
236 }
8ef12e64 237
6a488035
TO
238 if (!empty($insertString)) {
239 $string = implode(',', $insertString);
240 $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string";
241 CRM_Core_DAO::executeQuery($sql);
242 }
243 }
244
245 //contact type for pick up profiles as per selected contact types with subtypes
246 //CRM-5521
247 if ($selectedTypes = CRM_Utils_Array::value('contact_type', self::$_searchFormValues)) {
248 if (!is_array($selectedTypes)) {
249 $selectedTypes = explode(' ', $selectedTypes);
250 }
251 foreach ($selectedTypes as $ct => $dontcare) {
252 if (strpos($ct, CRM_Core_DAO::VALUE_SEPARATOR) === FALSE) {
253 $form->_contactTypes[] = $ct;
254 }
255 else {
256 $separator = strpos($ct, CRM_Core_DAO::VALUE_SEPARATOR);
257 $form->_contactTypes[] = substr($ct, $separator + 1);
258 }
259 }
260 }
261
8ef12e64 262
6a488035 263 if (CRM_Utils_Array::value('radio_ts', self::$_searchFormValues) == 'ts_sel'
5d272ea2 264 && ($form->_action != CRM_Core_Action::COPY)
265 ) {
6a488035 266 $sel = CRM_Utils_Array::value('radio_ts', self::$_searchFormValues);
5d272ea2 267 $form->assign('searchtype', $sel);
6a488035
TO
268 $result = CRM_Core_BAO_PrevNextCache::getSelectedContacts();
269 $form->assign("value", $result);
270 }
8ef12e64 271
6a488035
TO
272 if (!empty($form->_contactIds)) {
273 $form->_componentClause = ' contact_a.id IN ( ' . implode(',', $form->_contactIds) . ' ) ';
274 $form->assign('totalSelectedContacts', count($form->_contactIds));
275
276 $form->_componentIds = $form->_contactIds;
277 }
278 }
279
280 /**
100fef9d 281 * Get the contact id for custom search
6a488035
TO
282 * we are not using prev/next table incase of custom search
283 */
284 public function getContactIds() {
285 // need to perform action on all contacts
286 // fire the query again and get the contact id's + display name
287 $sortID = NULL;
288 if ($this->get(CRM_Utils_Sort::SORT_ID)) {
289 $sortID = CRM_Utils_Sort::sortIDValue($this->get(CRM_Utils_Sort::SORT_ID),
290 $this->get(CRM_Utils_Sort::SORT_DIRECTION)
291 );
292 }
293
294 $selectorName = $this->controller->selectorName();
5d272ea2 295 require_once(str_replace('_', DIRECTORY_SEPARATOR, $selectorName) . '.php');
6a488035
TO
296
297 $fv = $this->get('formValues');
298 $customClass = $this->get('customSearchClass');
299 require_once 'CRM/Core/BAO/Mapping.php';
300 $returnProperties = CRM_Core_BAO_Mapping::returnProperties(self::$_searchFormValues);
301
5d272ea2 302 $selector = new $selectorName($customClass, $fv, NULL, $returnProperties);
6a488035
TO
303
304 $params = $this->get('queryParams');
305
306 // fix for CRM-5165
307 $sortByCharacter = $this->get('sortByCharacter');
a7cddb8c 308 if ($sortByCharacter && $sortByCharacter != 1) {
6a488035
TO
309 $params[] = array('sortByCharacter', '=', $sortByCharacter, 0, 0);
310 }
311 $queryOperator = $this->get('queryOperator');
312 if (!$queryOperator) {
313 $queryOperator = 'AND';
314 }
66ceb5d9 315 $dao = $selector->contactIDQuery($params, $this->_action, $sortID,
5d272ea2 316 CRM_Utils_Array::value('display_relationship_type', $fv),
6a488035
TO
317 $queryOperator
318 );
319
320 $contactIds = array();
5d272ea2 321 while ($dao->fetch()) {
6a488035
TO
322 $contactIds[$dao->contact_id] = $dao->contact_id;
323 }
324
325 return $contactIds;
326 }
327
328
329 /**
c490a46a 330 * Set default values for the form. Relationship that in edit/view action
6a488035
TO
331 * the default values are retrieved from the database
332 *
333 * @access public
334 *
e2046b33 335 * @return array
6a488035
TO
336 */
337 function setDefaultValues() {
338 $defaults = array();
339 return $defaults;
340 }
341
342 /**
343 * This function is used to add the rules for form.
344 *
345 * @return void
346 * @access public
347 */
5d272ea2 348 function addRules() {
349 }
6a488035
TO
350
351 /**
c490a46a 352 * Build the form object
6a488035
TO
353 *
354 * @return void
355 * @access public
356 */
357 public function buildQuickForm() {
358 $this->addDefaultButtons(ts('Confirm Action'));
359 }
360
361 /**
100fef9d 362 * Process the form after the input has been submitted and validated
6a488035
TO
363 *
364 * @access public
365 *
366 * @return void
367 */
5d272ea2 368 public function postProcess() {
369 }
370
6a488035 371 /**
100fef9d 372 * Simple shell that derived classes can call to add buttons to
6a488035
TO
373 * the form with a customized title for the main Submit
374 *
375 * @param string $title title of the main button
c490a46a 376 * @param string $nextType button type for the form after processing
77b97be7
EM
377 * @param string $backType
378 * @param bool $submitOnce
379 *
6a488035
TO
380 * @return void
381 * @access public
382 */
383 function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
384 $this->addButtons(array(
385 array(
386 'type' => $nextType,
387 'name' => $title,
388 'isDefault' => TRUE,
389 ),
390 array(
391 'type' => $backType,
392 'name' => ts('Cancel'),
393 ),
394 )
395 );
396 }
57884c26
DJ
397
398 /**
100fef9d 399 * Replace ids of household members in $this->_contactIds with the id of their household.
57884c26
DJ
400 * CRM-8338
401 *
402 * @access public
403 *
404 * @return void
405 */
406 public function mergeContactIdsByHousehold() {
407 if (empty($this->_contactIds)) {
408 return;
409 }
410
411 $contactRelationshipTypes = CRM_Contact_BAO_Relationship::getContactRelationshipType(
412 NULL,
413 NULL,
414 NULL,
415 NULL,
416 TRUE,
417 'name',
418 FALSE
419 );
420
421 // Get Head of Household & Household Member relationships
422 $relationKeyMOH = CRM_Utils_Array::key('Household Member of', $contactRelationshipTypes);
423 $relationKeyHOH = CRM_Utils_Array::key('Head of Household for', $contactRelationshipTypes);
424 $householdRelationshipTypes = array(
425 $relationKeyMOH => $contactRelationshipTypes[$relationKeyMOH],
426 $relationKeyHOH => $contactRelationshipTypes[$relationKeyHOH],
427 );
428
429 $relID = implode(',', $this->_contactIds);
430
431 foreach ($householdRelationshipTypes as $rel => $dnt) {
432 list($id, $direction) = explode('_', $rel, 2);
433 // identify the relationship direction
434 $contactA = 'contact_id_a';
435 $contactB = 'contact_id_b';
436 if ($direction == 'b_a') {
437 $contactA = 'contact_id_b';
438 $contactB = 'contact_id_a';
439 }
440
441 // Find related households.
442 $relationSelect = "SELECT contact_household.id as household_id, {$contactA} as refContact ";
443 $relationFrom = " FROM civicrm_contact contact_household
444 INNER JOIN civicrm_relationship crel ON crel.{$contactB} = contact_household.id AND crel.relationship_type_id = {$id} ";
445
446 // Check for active relationship status only.
447 $today = date('Ymd');
448 $relationActive = " AND (crel.is_active = 1 AND ( crel.end_date is NULL OR crel.end_date >= {$today} ) )";
449 $relationWhere = " WHERE contact_household.is_deleted = 0 AND crel.{$contactA} IN ( {$relID} ) {$relationActive}";
450 $relationGroupBy = " GROUP BY crel.{$contactA}";
451 $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationGroupBy";
452
453 $householdsDAO = CRM_Core_DAO::executeQuery($relationQueryString);
454 while ($householdsDAO->fetch()) {
455 // Remove contact's id from $this->_contactIds and replace with their household's id.
456 foreach (array_keys($this->_contactIds, $householdsDAO->refContact) as $idKey) {
457 unset($this->_contactIds[$idKey]);
458 }
459 if (!in_array($householdsDAO->household_id, $this->_contactIds)) {
460 $this->_contactIds[] = $householdsDAO->household_id;
461 }
462 }
463 $householdsDAO->free();
464 }
465 }
6a488035
TO
466}
467