3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
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-2019
33 class CRM_Contact_Form_Search_Custom_FullText
extends CRM_Contact_Form_Search_Custom_Base
implements CRM_Contact_Form_Search_Interface
{
38 * @var array CRM_Contact_Form_Search_Custom_FullText_AbstractPartialQuery
40 protected $_partialQueries = NULL;
42 protected $_formValues;
46 protected $_text = NULL;
48 protected $_table = NULL;
50 protected $_tableName = NULL;
52 protected $_entityIDTableName = NULL;
54 protected $_tableFields = NULL;
57 * @var array|null NULL if no limit; or array(0 => $limit, 1 => $offset)
59 protected $_limitClause = NULL;
62 * @var array|null NULL if no limit; or array(0 => $limit, 1 => $offset)
64 protected $_limitRowClause = NULL;
67 * @var array|null NULL if no limit; or array(0 => $limit, 1 => $offset)
69 protected $_limitDetailClause = NULL;
71 protected $_limitNumber = 10;
72 protected $_limitNumberPlus1 = 11; // this should be one more than self::LIMIT
74 protected $_foundRows = array();
79 * @param array $formValues
81 public function __construct(&$formValues) {
82 $this->_partialQueries
= array(
83 new CRM_Contact_Form_Search_Custom_FullText_Contact(),
84 new CRM_Contact_Form_Search_Custom_FullText_Activity(),
85 new CRM_Contact_Form_Search_Custom_FullText_Case(),
86 new CRM_Contact_Form_Search_Custom_FullText_Contribution(),
87 new CRM_Contact_Form_Search_Custom_FullText_Participant(),
88 new CRM_Contact_Form_Search_Custom_FullText_Membership(),
91 $formValues['table'] = $this->getFieldValue($formValues, 'table', 'String');
92 $this->_table
= $formValues['table'];
94 $formValues['text'] = trim($this->getFieldValue($formValues, 'text', 'String', ''));
95 $this->_text
= $formValues['text'];
98 $this->_limitClause
= array($this->_limitNumberPlus1
, NULL);
99 $this->_limitRowClause
= $this->_limitDetailClause
= array($this->_limitNumber
, NULL);
102 // when there is table specified, we would like to use the pager. But since
103 // 1. this custom search has slightly different structure ,
104 // 2. we are in constructor right now,
105 // we 'll use a small hack -
106 $rowCount = CRM_Utils_Array
::value('crmRowCount', $_REQUEST, CRM_Utils_Pager
::ROWCOUNT
);
107 $pageId = CRM_Utils_Array
::value('crmPID', $_REQUEST, 1);
108 $offset = ($pageId - 1) * $rowCount;
109 $this->_limitClause
= NULL;
110 $this->_limitRowClause
= array($rowCount, NULL);
111 $this->_limitDetailClause
= array($rowCount, $offset);
114 $this->_formValues
= $formValues;
118 * Get a value from $formValues. If missing, get it from the request.
123 * @param null $default
126 public function getFieldValue($formValues, $field, $type, $default = NULL) {
127 $value = CRM_Utils_Array
::value($field, $formValues);
129 return CRM_Utils_Request
::retrieve($field, $type, CRM_Core_DAO
::$_nullObject, FALSE, $default);
134 public function __destruct() {
137 public function initialize() {
138 static $initialized = FALSE;
143 $this->buildTempTable();
149 public function buildTempTable() {
150 $table = CRM_Utils_SQL_TempTable
::build()->setCategory('custom')->setMemory()->setUtf8();
151 $this->_tableName
= $table->getName();
153 $this->_tableFields
= array(
154 'id' => 'int unsigned NOT NULL AUTO_INCREMENT',
155 'table_name' => 'varchar(16)',
156 'contact_id' => 'int unsigned',
157 'sort_name' => 'varchar(128)',
158 'display_name' => 'varchar(128)',
159 'assignee_contact_id' => 'int unsigned',
160 'assignee_sort_name' => 'varchar(128)',
161 'target_contact_id' => 'int unsigned',
162 'target_sort_name' => 'varchar(128)',
163 'activity_id' => 'int unsigned',
164 'activity_type_id' => 'int unsigned',
165 'record_type' => 'varchar(16)',
166 'client_id' => 'int unsigned',
167 'case_id' => 'int unsigned',
168 'case_start_date' => 'datetime',
169 'case_end_date' => 'datetime',
170 'case_is_deleted' => 'tinyint',
171 'subject' => 'varchar(255)',
172 'details' => 'varchar(255)',
173 'contribution_id' => 'int unsigned',
174 'financial_type' => 'varchar(255)',
175 'contribution_page' => 'varchar(255)',
176 'contribution_receive_date' => 'datetime',
177 'contribution_total_amount' => 'decimal(20,2)',
178 'contribution_trxn_Id' => 'varchar(255)',
179 'contribution_source' => 'varchar(255)',
180 'contribution_status' => 'varchar(255)',
181 'contribution_check_number' => 'varchar(255)',
182 'participant_id' => 'int unsigned',
183 'event_title' => 'varchar(255)',
184 'participant_fee_level' => 'varchar(255)',
185 'participant_fee_amount' => 'int unsigned',
186 'participant_source' => 'varchar(255)',
187 'participant_register_date' => 'datetime',
188 'participant_status' => 'varchar(255)',
189 'participant_role' => 'varchar(255)',
190 'membership_id' => 'int unsigned',
191 'membership_fee' => 'int unsigned',
192 'membership_type' => 'varchar(255)',
193 'membership_start_date' => 'datetime',
194 'membership_end_date' => 'datetime',
195 'membership_source' => 'varchar(255)',
196 'membership_status' => 'varchar(255)',
197 // We may have multiple files to list on one record.
198 // The temporary-table approach can't store full details for all of them
199 'file_ids' => 'varchar(255)', // comma-separate id listing
205 foreach ($this->_tableFields
as $name => $desc) {
206 $sql .= "$name $desc,\n";
212 $table->createWithColumns($sql);
214 $entityIdTable = CRM_Utils_SQL_TempTable
::build()->setCategory('custom')->setMemory()->setUtf8();
215 $this->_entityIDTableName
= $entityIdTable->getName();
217 id int unsigned NOT NULL AUTO_INCREMENT,
218 entity_id int unsigned NOT NULL,
220 UNIQUE INDEX unique_entity_id ( entity_id ),
223 $entityIdTable->createWithColumns($sql);
225 if (!empty($this->_formValues
['is_unit_test'])) {
226 $this->_tableNameForTest
= $this->_tableName
;
230 public function fillTable() {
231 foreach ($this->_partialQueries
as $partialQuery) {
232 /** @var $partialQuery CRM_Contact_Form_Search_Custom_FullText_AbstractPartialQuery */
233 if (!$this->_table ||
$this->_table
== $partialQuery->getName()) {
234 if ($partialQuery->isActive()) {
235 $result = $partialQuery->fillTempTable($this->_text
, $this->_entityIDTableName
, $this->_tableName
, $this->_limitClause
, $this->_limitDetailClause
);
236 $this->_foundRows
[$partialQuery->getName()] = $result['count'];
241 $this->filterACLContacts();
244 public function filterACLContacts() {
245 if (CRM_Core_Permission
::check('view all contacts')) {
246 CRM_Core_DAO
::executeQuery("DELETE FROM {$this->_tableName} WHERE contact_id IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)");
250 $session = CRM_Core_Session
::singleton();
251 $contactID = $session->get('userID');
256 CRM_Contact_BAO_Contact_Permission
::cache($contactID);
258 $params = array(1 => array($contactID, 'Integer'));
262 FROM {$this->_tableName} t
263 WHERE NOT EXISTS ( SELECT c.contact_id
264 FROM civicrm_acl_contact_cache c
265 WHERE c.user_id = %1 AND t.contact_id = c.contact_id )
267 CRM_Core_DAO
::executeQuery($sql, $params);
271 FROM {$this->_tableName} t
272 WHERE t.table_name = 'Activity' AND
273 NOT EXISTS ( SELECT c.contact_id
274 FROM civicrm_acl_contact_cache c
275 WHERE c.user_id = %1 AND ( t.target_contact_id = c.contact_id OR t.target_contact_id IS NULL ) )
277 CRM_Core_DAO
::executeQuery($sql, $params);
281 FROM {$this->_tableName} t
282 WHERE t.table_name = 'Activity' AND
283 NOT EXISTS ( SELECT c.contact_id
284 FROM civicrm_acl_contact_cache c
285 WHERE c.user_id = %1 AND ( t.assignee_contact_id = c.contact_id OR t.assignee_contact_id IS NULL ) )
287 CRM_Core_DAO
::executeQuery($sql, $params);
291 * @param CRM_Core_Form $form
293 public function buildForm(&$form) {
294 $config = CRM_Core_Config
::singleton();
296 $form->applyFilter('__ALL__', 'trim');
303 // also add a select box to allow the search to be constrained
304 $tables = array('' => ts('All tables'));
305 foreach ($this->_partialQueries
as $partialQuery) {
306 /** @var $partialQuery CRM_Contact_Form_Search_Custom_FullText_AbstractPartialQuery */
307 if ($partialQuery->isActive()) {
308 $tables[$partialQuery->getName()] = $partialQuery->getLabel();
312 $form->add('select', 'table', ts('Tables'), $tables);
314 $form->assign('csID', $form->get('csid'));
316 // also add the limit constant
317 $form->assign('limit', self
::LIMIT
);
320 if (!empty($form->_formValues
)) {
323 if (isset($form->_formValues
['text'])) {
324 $defaults['text'] = $form->_formValues
['text'];
327 if (isset($form->_formValues
['table'])) {
328 $defaults['table'] = $form->_formValues
['table'];
329 $form->assign('table', $form->_formValues
['table']);
332 $form->setDefaults($defaults);
336 * You can define a custom title for the search form
338 $this->setTitle(ts('Full-text Search'));
340 $searchService = CRM_Core_BAO_File
::getSearchService();
341 $form->assign('allowFileSearch', !empty($searchService) && CRM_Core_Permission
::check('access uploaded files'));
347 public function &columns() {
348 $this->_columns
= array(
349 ts('Contact ID') => 'contact_id',
350 ts('Name') => 'sort_name',
353 return $this->_columns
;
359 public function summary() {
363 foreach ($this->_partialQueries
as $partialQuery) {
364 /** @var $partialQuery CRM_Contact_Form_Search_Custom_FullText_AbstractPartialQuery */
365 $summary[$partialQuery->getName()] = array();
368 // now iterate through the table and add entries to the relevant section
369 $sql = "SELECT * FROM {$this->_tableName}";
371 $sql .= " {$this->toLimit($this->_limitRowClause)} ";
373 $dao = CRM_Core_DAO
::executeQuery($sql);
375 $activityTypes = CRM_Core_PseudoConstant
::activityType(TRUE, TRUE);
376 $roleIds = CRM_Event_PseudoConstant
::participantRole();
377 while ($dao->fetch()) {
379 foreach ($this->_tableFields
as $name => $dontCare) {
380 if ($name != 'activity_type_id') {
381 $row[$name] = $dao->$name;
384 $row['activity_type'] = CRM_Utils_Array
::value($dao->$name, $activityTypes);
387 if (isset($row['participant_role'])) {
388 $participantRole = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $row['participant_role']);
389 $viewRoles = array();
390 foreach ($participantRole as $v) {
391 $viewRoles[] = $roleIds[$v];
393 $row['participant_role'] = implode(', ', $viewRoles);
395 if (!empty($row['file_ids'])) {
396 $fileIds = (explode(',', $row['file_ids']));
398 foreach ($fileIds as $fileId) {
399 $paperclip = CRM_Core_BAO_File
::paperIconAttachment('*', $fileId);
401 $fileHtml .= implode('', $paperclip);
404 $row['fileHtml'] = $fileHtml;
406 $summary[$dao->table_name
][] = $row;
409 $summary['Count'] = array();
410 foreach (array_keys($summary) as $table) {
411 $summary['Count'][$table] = CRM_Utils_Array
::value($table, $this->_foundRows
);
412 if ($summary['Count'][$table] >= self
::LIMIT
) {
413 $summary['addShowAllLink'][$table] = TRUE;
416 $summary['addShowAllLink'][$table] = FALSE;
424 * @return null|string
426 public function count() {
430 return $this->_foundRows
[$this->_table
];
433 return CRM_Core_DAO
::singleValueQuery("SELECT count(id) FROM {$this->_tableName}");
439 * @param int $rowcount
441 * @param bool $returnSQL
443 * @return null|string
445 public function contactIDs($offset = 0, $rowcount = 0, $sort = NULL, $returnSQL = FALSE) {
449 return $this->all($offset, $rowcount, $sort, FALSE, TRUE);
452 return CRM_Core_DAO
::singleValueQuery("SELECT contact_id FROM {$this->_tableName}");
458 * @param int $rowcount
460 * @param bool $includeContactIDs
461 * @param bool $justIDs
465 public function all($offset = 0, $rowcount = 0, $sort = NULL, $includeContactIDs = FALSE, $justIDs = FALSE) {
469 $select = "contact_a.id as contact_id";
473 contact_a.contact_id as contact_id ,
474 contact_a.sort_name as sort_name
480 FROM {$this->_tableName} contact_a
481 {$this->toLimit($this->_limitRowClause)}
489 public function from() {
494 * @param bool $includeContactIDs
498 public function where($includeContactIDs = FALSE) {
505 public function templateFile() {
506 return 'CRM/Contact/Form/Search/Custom/FullText.tpl';
512 public function setDefaultValues() {
519 public function alterRow(&$row) {
525 public function setTitle($title) {
527 CRM_Utils_System
::setTitle($title);
532 * @param int|array $limit
535 * @see CRM_Contact_Form_Search_Custom_FullText_AbstractPartialQuery::toLimit
537 public function toLimit($limit) {
538 if (is_array($limit)) {
539 list ($limit, $offset) = $limit;
544 $result = "LIMIT {$limit}";
546 $result .= " OFFSET {$offset}";