4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.6 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2014 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
11 | CiviCRM is free software; you can copy, modify, and distribute it |
12 | under the terms of the GNU Affero General Public License |
13 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
15 | CiviCRM is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | See the GNU Affero General Public License for more details. |
20 | You should have received a copy of the GNU Affero General Public |
21 | License and the CiviCRM Licensing Exception along |
22 | with this program; if not, contact CiviCRM LLC |
23 | at info[AT]civicrm[DOT]org. If you have questions about the |
24 | GNU Affero General Public License or the licensing of CiviCRM, |
25 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
26 +--------------------------------------------------------------------+
32 * @copyright CiviCRM LLC (c) 2004-2014
36 class CRM_Campaign_BAO_Query
{
37 //since normal activity clause clause get collides.
39 CIVICRM_ACTIVITY
= 'civicrm_survey_activity',
40 CIVICRM_ACTIVITY_TARGET
= 'civicrm_survey_activity_target',
41 CIVICRM_ACTIVITY_ASSIGNMENT
= 'civicrm_survey_activity_assignment';
44 * Static field for all the campaign fields
49 static $_campaignFields = NULL;
51 static $_applySurveyClause = FALSE;
54 * Function get the fields for campaign.
56 * @return array self::$_campaignFields an associative array of campaign fields
59 public static function &getFields() {
60 if (!isset(self
::$_campaignFields)) {
61 self
::$_campaignFields = array();
64 return self
::$_campaignFields;
68 * If survey, campaign are involved, add the specific fields.
74 public static function select(&$query) {
75 self
::$_applySurveyClause = FALSE;
76 if (is_array($query->_params
)) {
77 foreach ($query->_params
as $values) {
78 if (!is_array($values) ||
count($values) != 5) {
82 list($name, $op, $value, $grouping, $wildcard) = $values;
83 if ($name == 'campaign_survey_id') {
84 self
::$_applySurveyClause = TRUE;
89 // CRM-13810 Translate campaign_id to label for search builder
90 // CRM-14238 Only translate when we are in contact mode
91 // Other modes need the untranslated data for export and other functions
92 if (is_array($query->_select
) && $query->_mode
== CRM_Contact_BAO_Query
::MODE_CONTACTS
) {
93 foreach($query->_select
as $field => $queryString) {
94 if (substr($field, -11) == 'campaign_id') {
95 $query->_pseudoConstantsSelect
[$field] = array(
96 'pseudoField' => 'campaign_id',
98 'bao' => 'CRM_Activity_BAO_Activity',
105 //get survey clause in force,
106 //only when we have survey id.
107 if (!self
::$_applySurveyClause) {
111 //all below tables are require to fetch result.
113 //1. get survey activity target table in.
114 $query->_select
['survey_activity_target_contact_id'] = 'civicrm_activity_target.contact_id as survey_activity_target_contact_id';
115 $query->_select
['survey_activity_target_id'] = 'civicrm_activity_target.id as survey_activity_target_id';
116 $query->_element
['survey_activity_target_id'] = 1;
117 $query->_element
['survey_activity_target_contact_id'] = 1;
118 $query->_tables
[self
::CIVICRM_ACTIVITY_TARGET
] = 1;
119 $query->_whereTables
[self
::CIVICRM_ACTIVITY_TARGET
] = 1;
121 //2. get survey activity table in.
122 $query->_select
['survey_activity_id'] = 'civicrm_activity.id as survey_activity_id';
123 $query->_element
['survey_activity_id'] = 1;
124 $query->_tables
[self
::CIVICRM_ACTIVITY
] = 1;
125 $query->_whereTables
[self
::CIVICRM_ACTIVITY
] = 1;
127 //3. get the assignee table in.
128 $query->_select
['survey_interviewer_id'] = 'civicrm_activity_assignment.id as survey_interviewer_id';
129 $query->_element
['survey_interviewer_id'] = 1;
130 $query->_tables
[self
::CIVICRM_ACTIVITY_ASSIGNMENT
] = 1;
131 $query->_whereTables
[self
::CIVICRM_ACTIVITY_ASSIGNMENT
] = 1;
133 //4. get survey table.
134 $query->_select
['campaign_survey_id'] = 'civicrm_survey.id as campaign_survey_id';
135 $query->_element
['campaign_survey_id'] = 1;
136 $query->_tables
['civicrm_survey'] = 1;
137 $query->_whereTables
['civicrm_survey'] = 1;
139 //5. get campaign table.
140 $query->_select
['campaign_id'] = 'civicrm_campaign.id as campaign_id';
141 $query->_element
['campaign_id'] = 1;
142 $query->_tables
['civicrm_campaign'] = 1;
143 $query->_whereTables
['civicrm_campaign'] = 1;
149 public static function where(&$query) {
150 //get survey clause in force,
151 //only when we have survey id.
152 if (!self
::$_applySurveyClause) {
157 foreach (array_keys($query->_params
) as $id) {
158 if ($query->_mode
== CRM_Contact_BAO_Query
::MODE_CONTACTS
) {
159 $query->_useDistinct
= TRUE;
162 self
::whereClauseSingle($query->_params
[$id], $query);
170 public static function whereClauseSingle(&$values, &$query) {
171 //get survey clause in force,
172 //only when we have survey id.
173 if (!self
::$_applySurveyClause) {
177 list($name, $op, $value, $grouping, $wildcard) = $values;
180 case 'campaign_survey_id':
181 $query->_qill
[$grouping][] = ts('Survey - %1', array(1 => CRM_Core_DAO
::getFieldValue('CRM_Campaign_DAO_Survey', $value, 'title')));
183 $query->_where
[$grouping][] = CRM_Contact_BAO_Query
::buildClause('civicrm_activity.source_record_id',
184 $op, $value, 'Integer'
186 $query->_where
[$grouping][] = CRM_Contact_BAO_Query
::buildClause('civicrm_survey.id',
187 $op, $value, 'Integer'
191 case 'survey_status_id':
192 $activityStatus = CRM_Core_PseudoConstant
::activityStatus();
194 $query->_qill
[$grouping][] = ts('Survey Status - %1', array(1 => $activityStatus[$value]));
195 $query->_where
[$grouping][] = CRM_Contact_BAO_Query
::buildClause('civicrm_activity.status_id',
196 $op, $value, 'Integer'
200 case 'campaign_search_voter_for':
201 if (in_array($value, array('release', 'interview'))) {
202 $query->_where
[$grouping][] = '(civicrm_activity.is_deleted = 0 OR civicrm_activity.is_deleted IS NULL)';
206 case 'survey_interviewer_id':
207 $surveyInterviewerName = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact', $value, 'sort_name');
208 $query->_qill
[$grouping][] = ts('Survey Interviewer - %1', array(1 => $surveyInterviewerName));
209 $query->_where
[$grouping][] = CRM_Contact_BAO_Query
::buildClause('civicrm_activity_assignment.contact_id',
210 $op, $value, 'Integer'
217 * @param string $name
221 * @return null|string
223 public static function from($name, $mode, $side) {
225 //get survey clause in force,
226 //only when we have survey id.
227 if (!self
::$_applySurveyClause) {
231 $activityContacts = CRM_Core_OptionGroup
::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
232 $sourceID = CRM_Utils_Array
::key('Activity Source', $activityContacts);
233 $assigneeID = CRM_Utils_Array
::key('Activity Assignees', $activityContacts);
234 $targetID = CRM_Utils_Array
::key('Activity Targets', $activityContacts);
237 case self
::CIVICRM_ACTIVITY_TARGET
:
238 $from = " INNER JOIN civicrm_activity_contact civicrm_activity_target
239 ON ( civicrm_activity_target.contact_id = contact_a.id AND civicrm_activity_target.record_type_id = $targetID) ";
242 case self
::CIVICRM_ACTIVITY
:
243 $surveyActivityTypes = CRM_Campaign_PseudoConstant
::activityType();
244 $surveyKeys = "(" . implode(',', array_keys($surveyActivityTypes)) . ")";
245 $from = " INNER JOIN civicrm_activity ON ( civicrm_activity.id = civicrm_activity_target.activity_id
246 AND civicrm_activity.activity_type_id IN $surveyKeys ) ";
249 case self
::CIVICRM_ACTIVITY_ASSIGNMENT
:
251 INNER JOIN civicrm_activity_contact civicrm_activity_assignment ON ( civicrm_activity.id = civicrm_activity_assignment.activity_id AND
252 civicrm_activity_assignment.record_type_id = $assigneeID ) ";
255 case 'civicrm_survey':
256 $from = " INNER JOIN civicrm_survey ON ( civicrm_survey.id = civicrm_activity.source_record_id ) ";
259 case 'civicrm_campaign':
260 $from = " $side JOIN civicrm_campaign ON ( civicrm_campaign.id = civicrm_survey.campaign_id ) ";
269 * @param bool $includeCustomFields
273 static function defaultReturnProperties($mode,
274 $includeCustomFields = TRUE
277 if ($mode & CRM_Contact_BAO_Query
::MODE_CAMPAIGN
) {
281 'contact_sub_type' => 1,
286 'street_number' => 1,
287 'street_address' => 1,
290 'state_province' => 1,
294 'survey_activity_target_id' => 1,
295 'survey_activity_id' => 1,
296 'survey_status_id' => 1,
297 'campaign_survey_id' => 1,
299 'survey_interviewer_id' => 1,
300 'survey_activity_target_contact_id' => 1,
310 public static function tableNames(&$tables) {}
316 public static function searchAction(&$row, $id) {}
321 public static function info(&$tables) {
322 //get survey clause in force,
323 //only when we have survey id.
324 if (!self
::$_applySurveyClause) {
328 $weight = end($tables);
329 $tables[self
::CIVICRM_ACTIVITY_TARGET
] = ++
$weight;
330 $tables[self
::CIVICRM_ACTIVITY
] = ++
$weight;
331 $tables[self
::CIVICRM_ACTIVITY_ASSIGNMENT
] = ++
$weight;
332 $tables['civicrm_survey'] = ++
$weight;
333 $tables['civicrm_campaign'] = ++
$weight;
337 * Add all the elements shared between,
338 * normal voter search and voter listing (GOTV form)
341 * @param CRM_Core_Form $form
345 public static function buildSearchForm(&$form) {
347 $attributes = CRM_Core_DAO
::getAttribute('CRM_Core_DAO_Address');
348 $className = CRM_Utils_System
::getClassName($form);
350 $form->add('text', 'sort_name', ts('Contact Name'),
351 CRM_Core_DAO
::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')
353 $form->add('text', 'street_name', ts('Street Name'), $attributes['street_name']);
354 $form->add('text', 'street_number', ts('Street Number'), $attributes['street_number']);
355 $form->add('text', 'street_unit', ts('Street Unit'), $attributes['street_unit']);
356 $form->add('text', 'street_address', ts('Street Address'), $attributes['street_address']);
357 $form->add('text', 'city', ts('City'), $attributes['city']);
358 $form->add('text', 'postal_code', ts('Zip / Postal Code'), $attributes['postal_code']);
360 //@todo FIXME - using the CRM_Core_DAO::VALUE_SEPARATOR creates invalid html - if you can find the form
361 // this is loaded onto then replace with something like '__' & test
362 $separator = CRM_Core_DAO
::VALUE_SEPARATOR
;
363 $contactTypes = CRM_Contact_BAO_ContactType
::getSelectElements(FALSE, TRUE, $separator);
364 $form->add('select', 'contact_type', ts('Contact Type(s)'), $contactTypes, FALSE,
365 array('id' => 'contact_type', 'multiple' => 'multiple', 'class' => 'crm-select2')
367 $groups = CRM_Core_PseudoConstant
::nestedGroup();
368 $form->add('select', 'group', ts('Groups'), $groups, FALSE,
369 array('multiple' => 'multiple', 'class' => 'crm-select2')
372 $showInterviewer = FALSE;
373 if (CRM_Core_Permission
::check('administer CiviCampaign')) {
374 $showInterviewer = TRUE;
376 $form->assign('showInterviewer', $showInterviewer);
378 if ($showInterviewer ||
379 $className == 'CRM_Campaign_Form_Gotv'
382 $form->addEntityRef('survey_interviewer_id', ts('Interviewer'), array('class' => 'big'));
385 if (isset($form->_interviewerId
) && $form->_interviewerId
) {
386 $userId = $form->_interviewerId
;
389 $session = CRM_Core_Session
::singleton();
390 $userId = $session->get('userID');
394 $defaults['survey_interviewer_id'] = $userId;
395 $form->setDefaults($defaults);
399 //build ward and precinct custom fields.
401 SELECT fld.id, fld.label
402 FROM civicrm_custom_field fld
403 INNER JOIN civicrm_custom_group grp on fld.custom_group_id = grp.id
404 WHERE grp.name = %1';
405 $dao = CRM_Core_DAO
::executeQuery($query, array(1 => array('Voter_Info', 'String')));
406 $customSearchFields = array();
407 while ($dao->fetch()) {
409 'ward', 'precinct') as $name) {
410 if (stripos($name, $dao->label
) !== FALSE) {
412 $fieldName = 'custom_' . $dao->id
;
413 $customSearchFields[$name] = $fieldName;
414 CRM_Core_BAO_CustomField
::addQuickFormElement($form, $fieldName, $fieldId, FALSE, FALSE);
419 $form->assign('customSearchFields', $customSearchFields);
421 $surveys = CRM_Campaign_BAO_Survey
::getSurveys();
423 if (empty($surveys) &&
424 ($className == 'CRM_Campaign_Form_Search')
426 CRM_Core_Error
::statusBounce(ts('Could not find survey for %1 respondents.',
427 array(1 => $form->get('op'))
429 CRM_Utils_System
::url('civicrm/survey/add',
436 //If survey had associated campaign and
437 //campaign has some contact groups, don't
438 //allow to search the contacts those are not
439 //in given campaign groups ( ie not in constituents )
440 $props = array('class' => 'crm-select2');
441 if ($form->get('searchVoterFor') == 'reserve') {
442 $props['onChange'] = "buildCampaignGroups( );return false;";
444 $form->add('select', 'campaign_survey_id', ts('Survey'), $surveys, TRUE, $props);
448 * Retrieve all valid voter ids,
449 * and build respective clause to restrict search.
451 * @param array $criteria
453 * @return $voterClause as a string
457 * @param array $params
461 static public function voterClause($params) {
462 $voterClause = array();
463 $fromClause = $whereClause = NULL;
464 if (!is_array($params) ||
empty($params)) {
467 $surveyId = CRM_Utils_Array
::value('campaign_survey_id', $params);
468 $searchVoterFor = CRM_Utils_Array
::value('campaign_search_voter_for', $params);
470 //get the survey activities.
471 $activityStatus = CRM_Core_PseudoConstant
::activityStatus('name');
472 $status = array('Scheduled');
473 if ($searchVoterFor == 'reserve') {
474 $status[] = 'Completed';
477 $completedStatusId = NULL;
478 foreach ($status as $name) {
479 if ($statusId = array_search($name, $activityStatus)) {
480 $statusIds[] = $statusId;
481 if ($name == 'Completed') {
482 $completedStatusId = $statusId;
487 $voterActValues = CRM_Campaign_BAO_Survey
::getSurveyVoterInfo($surveyId, NULL, $statusIds);
489 if (!empty($voterActValues)) {
491 $voterIds = array_keys($voterActValues);
492 if ($searchVoterFor == 'reserve') {
493 $operator = 'NOT IN';
494 //filter out recontact survey contacts.
495 $recontactInterval = CRM_Core_DAO
::getFieldValue('CRM_Campaign_DAO_Survey',
496 $surveyId, 'recontact_interval'
498 $recontactInterval = unserialize($recontactInterval);
500 is_array($recontactInterval) &&
501 !empty($recontactInterval)
504 foreach ($voterActValues as $values) {
505 $numOfDays = CRM_Utils_Array
::value($values['result'], $recontactInterval);
507 $values['status_id'] == $completedStatusId
509 $recontactIntSeconds = $numOfDays * 24 * 3600;
510 $actDateTimeSeconds = CRM_Utils_Date
::unixTime($values['activity_date_time']);
511 $totalSeconds = $recontactIntSeconds +
$actDateTimeSeconds;
512 //don't consider completed survey activity
513 //unless it fulfill recontact interval criteria.
514 if ($totalSeconds <= time()) {
518 $voterIds[$values['voter_id']] = $values['voter_id'];
523 //lets dump these ids in tmp table and
524 //use appropriate join depend on operator.
525 if (!empty($voterIds)) {
526 $voterIdCount = count($voterIds);
528 //create temporary table to store voter ids.
529 $tempTableName = CRM_Core_DAO
::createTempTableName('civicrm_survey_respondent');
530 CRM_Core_DAO
::executeQuery("DROP TABLE IF EXISTS {$tempTableName}");
533 CREATE TEMPORARY TABLE {$tempTableName} (
534 id int unsigned NOT NULL AUTO_INCREMENT,
535 survey_contact_id int unsigned NOT NULL,
539 CRM_Core_DAO
::executeQuery($query);
544 $processIds = $voterIds;
545 $insertIds = array_splice($processIds, $insertedCount, $batch);
546 if (!empty($insertIds)) {
547 $insertSQL = "INSERT IGNORE INTO {$tempTableName}( survey_contact_id )
548 VALUES (" . implode('),(', $insertIds) . ');';
549 CRM_Core_DAO
::executeQuery($insertSQL);
551 $insertedCount +
= $batch;
552 } while ($insertedCount < $voterIdCount);
554 if ($operator == 'IN') {
555 $fromClause = " INNER JOIN {$tempTableName} ON ( {$tempTableName}.survey_contact_id = contact_a.id )";
558 $fromClause = " LEFT JOIN {$tempTableName} ON ( {$tempTableName}.survey_contact_id = contact_a.id )";
559 $whereClause = "( {$tempTableName}.survey_contact_id IS NULL )";
563 $voterClause = array(
564 'fromClause' => $fromClause,
565 'whereClause' => $whereClause,
572 * Build the campaign clause for component serach.
575 public static function componentSearchClause(&$params, &$query) {
576 $op = CRM_Utils_Array
::value('op', $params, '=');
577 $campaign = CRM_Utils_Array
::value('campaign', $params);
578 $tableName = CRM_Utils_Array
::value('tableName', $params);
579 $grouping = CRM_Utils_Array
::value('grouping', $params);
580 if (CRM_Utils_System
::isNull($campaign) ||
empty($tableName)) {
584 // fixme - what is the purpose of this code? $campaign should be
585 // an integer, not an array
586 if (is_array($campaign)) {
588 'current_campaign', 'past_campaign') as $ignore) {
589 $index = array_search($ignore, $campaign);
590 if ($index !== FALSE)unset($campaign[$index]);
594 $allCampaigns = CRM_Campaign_BAO_Campaign
::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
596 $campaignIds = $campaignTitles = array();
597 if (is_array($campaign)) {
598 foreach ($campaign as $campId) {
599 $campaignIds[$campId] = $campId;
600 $campaignTitles[$campId] = $allCampaigns[$campId];
602 if (count($campaignIds) > 1) {
604 $campaignIds = '(' . implode(',', $campaignIds) . ')';
607 $campaignIds = reset($campaignIds);
611 $campaignIds = $campaign;
612 if (array_key_exists($campaignIds, $allCampaigns)) {
613 $campaignTitles[$campaignIds] = $allCampaigns[$campaignIds];
616 $query->_qill
[$grouping][] = ts('Campaigns %1',
618 ) . ' ' . implode(' ' . ts('or') . ' ', $campaignTitles);
619 $query->_where
[$grouping][] = CRM_Contact_BAO_Query
::buildClause("{$tableName}.campaign_id",
624 $query->_tables
[$tableName] = $query->_whereTables
[$tableName] = 1;