3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2014
37 * This class generates form components for search-result tasks
40 class CRM_Contact_Form_Task
extends CRM_Core_Form
{
43 * the task being performed
50 * The array that holds all the contact ids
57 * The array that holds all the contact types
61 public $_contactTypes;
64 * The additional clause that we restrict the search with
68 protected $_componentClause = NULL;
71 * The name of the temp table where we store the contact IDs
75 protected $_componentTable = NULL;
78 * The array that holds all the component ids
82 protected $_componentIds;
85 * This includes the submitted values of the search form
87 static protected $_searchFormValues;
90 * build all the data structures needed to build the form
97 function preProcess() {
98 self
::preProcessCommon($this);
101 static function preProcessCommon(&$form, $useTable = FALSE) {
103 $form->_contactIds
= array();
104 $form->_contactTypes
= array();
106 // get the submitted values of the search form
107 // we'll need to get fv from either search or adv search in the future
108 $fragment = 'search';
109 if ($form->_action
== CRM_Core_Action
::ADVANCED
) {
110 self
::$_searchFormValues = $form->controller
->exportValues('Advanced');
111 $fragment .= '/advanced';
113 elseif ($form->_action
== CRM_Core_Action
::PROFILE
) {
114 self
::$_searchFormValues = $form->controller
->exportValues('Builder');
115 $fragment .= '/builder';
117 elseif ($form->_action
== CRM_Core_Action
::COPY
) {
118 self
::$_searchFormValues = $form->controller
->exportValues('Custom');
119 $fragment .= '/custom';
122 self
::$_searchFormValues = $form->controller
->exportValues('Basic');
125 //set the user context for redirection of task actions
126 $qfKey = CRM_Utils_Request
::retrieve('qfKey', 'String', $form);
127 $urlParams = 'force=1';
128 if (CRM_Utils_Rule
::qfKey($qfKey)) {
129 $urlParams .= "&qfKey=$qfKey";
132 $cacheKey = "civicrm search {$qfKey}";
134 $url = CRM_Utils_System
::url('civicrm/contact/' . $fragment, $urlParams);
135 $session = CRM_Core_Session
::singleton();
136 $session->replaceUserContext($url);
138 $form->_task
= CRM_Utils_Array
::value('task', self
::$_searchFormValues);
139 $crmContactTaskTasks = CRM_Contact_Task
::taskTitles();
140 $form->assign('taskName', CRM_Utils_Array
::value($form->_task
, $crmContactTaskTasks));
143 $form->_componentTable
= CRM_Core_DAO
::createTempTableName('civicrm_task_action', TRUE, $qfKey);
144 $sql = " DROP TABLE IF EXISTS {$form->_componentTable}";
145 CRM_Core_DAO
::executeQuery($sql);
147 $sql = "CREATE TABLE {$form->_componentTable} ( contact_id int primary key) ENGINE=MyISAM DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci";
148 CRM_Core_DAO
::executeQuery($sql);
151 // all contacts or action = save a search
152 if ((CRM_Utils_Array
::value('radio_ts', self
::$_searchFormValues) == 'ts_all') ||
153 ($form->_task
== CRM_Contact_Task
::SAVE_SEARCH
)
155 $sortByCharacter = $form->get('sortByCharacter');
156 $cacheKey = ($sortByCharacter && $sortByCharacter != 'all') ?
"{$cacheKey}_alphabet" : $cacheKey;
158 // since we don't store all contacts in prevnextcache, when user selects "all" use query to retrieve contacts
159 // rather than prevnext cache table for most of the task actions except export where we rebuild query to fetch
162 $allCids = CRM_Core_BAO_PrevNextCache
::getSelection($cacheKey, "getall");
165 $allCids[$cacheKey] = $form->getContactIds();
168 $form->_contactIds
= array();
171 $insertString = array();
172 foreach ($allCids[$cacheKey] as $cid => $ignore) {
174 $insertString[] = " ( {$cid} ) ";
175 if ($count %
200 == 0) {
176 $string = implode(',', $insertString);
177 $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string";
178 CRM_Core_DAO
::executeQuery($sql);
179 $insertString = array();
182 if (!empty($insertString)) {
183 $string = implode(',', $insertString);
184 $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string";
185 CRM_Core_DAO
::executeQuery($sql);
189 // filter duplicates here
191 // might be better to do this in the query, but that logic is a bit complex
192 // and it decides when to use distinct based on input criteria, which needs
193 // to be fixed and optimized.
195 foreach ($allCids[$cacheKey] as $cid => $ignore) {
196 $form->_contactIds
[] = $cid;
200 elseif (CRM_Utils_Array
::value('radio_ts', self
::$_searchFormValues) == 'ts_sel') {
201 // selected contacts only
202 // need to perform action on only selected contacts
203 $insertString = array();
205 // refire sql in case of custom seach
206 if ($form->_action
== CRM_Core_Action
::COPY
) {
207 // selected contacts only
208 // need to perform action on only selected contacts
209 foreach (self
::$_searchFormValues as $name => $value) {
210 if (substr($name, 0, CRM_Core_Form
::CB_PREFIX_LEN
) == CRM_Core_Form
::CB_PREFIX
) {
211 $contactID = substr($name, CRM_Core_Form
::CB_PREFIX_LEN
);
213 $insertString[] = " ( {$contactID} ) ";
216 $form->_contactIds
[] = substr($name, CRM_Core_Form
::CB_PREFIX_LEN
);
222 // fetching selected contact ids of passed cache key
223 $selectedCids = CRM_Core_BAO_PrevNextCache
::getSelection($cacheKey);
224 foreach ($selectedCids[$cacheKey] as $selectedCid => $ignore) {
226 $insertString[] = " ( {$selectedCid} ) ";
229 $form->_contactIds
[] = $selectedCid;
234 if (!empty($insertString)) {
235 $string = implode(',', $insertString);
236 $sql = "REPLACE INTO {$form->_componentTable} ( contact_id ) VALUES $string";
237 CRM_Core_DAO
::executeQuery($sql);
241 //contact type for pick up profiles as per selected contact types with subtypes
243 if ($selectedTypes = CRM_Utils_Array
::value('contact_type', self
::$_searchFormValues)) {
244 if (!is_array($selectedTypes)) {
245 $selectedTypes = explode(' ', $selectedTypes);
247 foreach ($selectedTypes as $ct => $dontcare) {
248 if (strpos($ct, CRM_Core_DAO
::VALUE_SEPARATOR
) === FALSE) {
249 $form->_contactTypes
[] = $ct;
252 $separator = strpos($ct, CRM_Core_DAO
::VALUE_SEPARATOR
);
253 $form->_contactTypes
[] = substr($ct, $separator +
1);
259 if (CRM_Utils_Array
::value('radio_ts', self
::$_searchFormValues) == 'ts_sel'
260 && ($form->_action
!= CRM_Core_Action
::COPY
)
262 $sel = CRM_Utils_Array
::value('radio_ts', self
::$_searchFormValues);
263 $form->assign('searchtype', $sel);
264 $result = CRM_Core_BAO_PrevNextCache
::getSelectedContacts();
265 $form->assign("value", $result);
268 if (!empty($form->_contactIds
)) {
269 $form->_componentClause
= ' contact_a.id IN ( ' . implode(',', $form->_contactIds
) . ' ) ';
270 $form->assign('totalSelectedContacts', count($form->_contactIds
));
272 $form->_componentIds
= $form->_contactIds
;
277 * Function to get the contact id for custom search
278 * we are not using prev/next table incase of custom search
280 public function getContactIds() {
281 // need to perform action on all contacts
282 // fire the query again and get the contact id's + display name
284 if ($this->get(CRM_Utils_Sort
::SORT_ID
)) {
285 $sortID = CRM_Utils_Sort
::sortIDValue($this->get(CRM_Utils_Sort
::SORT_ID
),
286 $this->get(CRM_Utils_Sort
::SORT_DIRECTION
)
290 $selectorName = $this->controller
->selectorName();
291 require_once(str_replace('_', DIRECTORY_SEPARATOR
, $selectorName) . '.php');
293 $fv = $this->get('formValues');
294 $customClass = $this->get('customSearchClass');
295 require_once 'CRM/Core/BAO/Mapping.php';
296 $returnProperties = CRM_Core_BAO_Mapping
::returnProperties(self
::$_searchFormValues);
298 $selector = new $selectorName($customClass, $fv, NULL, $returnProperties);
300 $params = $this->get('queryParams');
303 $sortByCharacter = $this->get('sortByCharacter');
304 if ($sortByCharacter && $sortByCharacter != 1) {
305 $params[] = array('sortByCharacter', '=', $sortByCharacter, 0, 0);
307 $queryOperator = $this->get('queryOperator');
308 if (!$queryOperator) {
309 $queryOperator = 'AND';
311 $dao = $selector->contactIDQuery($params, $this->_action
, $sortID,
312 CRM_Utils_Array
::value('display_relationship_type', $fv),
316 $contactIds = array();
317 while ($dao->fetch()) {
318 $contactIds[$dao->contact_id
] = $dao->contact_id
;
326 * This function sets the default values for the form. Relationship that in edit/view action
327 * the default values are retrieved from the database
333 function setDefaultValues() {
339 * This function is used to add the rules for form.
344 function addRules() {
348 * Function to actually build the form
353 public function buildQuickForm() {
354 $this->addDefaultButtons(ts('Confirm Action'));
358 * process the form after the input has been submitted and validated
364 public function postProcess() {
370 * simple shell that derived classes can call to add buttons to
371 * the form with a customized title for the main Submit
373 * @param string $title title of the main button
374 * @param string $nextType
375 * @param string $backType
376 * @param bool $submitOnce
378 * @internal param string $type button type for the form after processing
383 function addDefaultButtons($title, $nextType = 'next', $backType = 'back', $submitOnce = FALSE) {
384 $this->addButtons(array(
392 'name' => ts('Cancel'),
399 * replace ids of household members in $this->_contactIds with the id of their household.
406 public function mergeContactIdsByHousehold() {
407 if (empty($this->_contactIds
)) {
411 $contactRelationshipTypes = CRM_Contact_BAO_Relationship
::getContactRelationshipType(
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],
429 $relID = implode(',', $this->_contactIds
);
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';
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} ";
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";
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]);
459 if (!in_array($householdsDAO->household_id
, $this->_contactIds
)) {
460 $this->_contactIds
[] = $householdsDAO->household_id
;
463 $householdsDAO->free();