PageRenderTime 35ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/sites/all/modules/contrib/civicrm/CRM/Contact/Form/Search/Custom/RandomSegment.php

https://gitlab.com/virtualrealms/d7civicrm
PHP | 403 lines | 239 code | 69 blank | 95 comment | 29 complexity | e93a513a28df28cb65e46b12f87e87df MD5 | raw file
  1. <?php
  2. /*
  3. +--------------------------------------------------------------------+
  4. | CiviCRM version 5 |
  5. +--------------------------------------------------------------------+
  6. | Copyright CiviCRM LLC (c) 2004-2019 |
  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. * @package CRM
  30. * @copyright CiviCRM LLC (c) 2004-2019
  31. */
  32. class CRM_Contact_Form_Search_Custom_RandomSegment extends CRM_Contact_Form_Search_Custom_Base implements CRM_Contact_Form_Search_Interface {
  33. protected $_debug = 0;
  34. protected $_aclFrom = NULL;
  35. protected $_aclWhere = NULL;
  36. /**
  37. * Class constructor.
  38. *
  39. * @param array $formValues
  40. */
  41. public function __construct(&$formValues) {
  42. parent::__construct($formValues);
  43. $this->_columns = [
  44. ts('Contact ID') => 'contact_id',
  45. ts('Contact Type') => 'contact_type',
  46. ts('Name') => 'sort_name',
  47. ts('Email') => 'email',
  48. ];
  49. $this->initialize();
  50. }
  51. public function initialize() {
  52. $this->_segmentSize = CRM_Utils_Array::value('segmentSize', $this->_formValues);
  53. $this->_includeGroups = CRM_Utils_Array::value('includeGroups', $this->_formValues);
  54. $this->_excludeGroups = CRM_Utils_Array::value('excludeGroups', $this->_formValues);
  55. $this->_allSearch = FALSE;
  56. $this->_groups = FALSE;
  57. if (empty($this->_includeGroups) && empty($this->_excludeGroups)) {
  58. //empty search
  59. $this->_allSearch = TRUE;
  60. }
  61. if (!empty($this->_includeGroups) || !empty($this->_excludeGroups)) {
  62. //group(s) selected
  63. $this->_groups = TRUE;
  64. }
  65. }
  66. /**
  67. * @param CRM_Core_Form $form
  68. */
  69. public function buildForm(&$form) {
  70. $form->add('text',
  71. 'segmentSize',
  72. ts('Segment Size'),
  73. TRUE
  74. );
  75. $groups = CRM_Core_PseudoConstant::nestedGroup();
  76. $select2style = [
  77. 'multiple' => TRUE,
  78. 'style' => 'width: 100%; max-width: 60em;',
  79. 'class' => 'crm-select2',
  80. 'placeholder' => ts('- select -'),
  81. ];
  82. $form->add('select', 'includeGroups',
  83. ts('Include Group(s)'),
  84. $groups,
  85. FALSE,
  86. $select2style
  87. );
  88. $form->add('select', 'excludeGroups',
  89. ts('Exclude Group(s)'),
  90. $groups,
  91. FALSE,
  92. $select2style
  93. );
  94. $this->setTitle('Create a random segment of contacts');
  95. /**
  96. * if you are using the standard template, this array tells the template what elements
  97. * are part of the search criteria
  98. */
  99. $form->assign('elements', ['segmentSize', 'includeGroups', 'excludeGroups']);
  100. }
  101. /**
  102. * @return null
  103. */
  104. public function summary() {
  105. return NULL;
  106. }
  107. /**
  108. * @param int $offset
  109. * @param int $rowcount
  110. * @param null $sort
  111. * @param bool $includeContactIDs
  112. * @param bool $justIDs
  113. *
  114. * @return string
  115. */
  116. public function all(
  117. $offset = 0, $rowcount = 0, $sort = NULL,
  118. $includeContactIDs = FALSE, $justIDs = FALSE
  119. ) {
  120. if ($justIDs) {
  121. $selectClause = "contact_a.id as contact_id";
  122. }
  123. else {
  124. $selectClause = "contact_a.id as contact_id,
  125. contact_a.contact_type as contact_type,
  126. contact_a.sort_name as sort_name,
  127. civicrm_email.email as email";
  128. }
  129. return $this->sql($selectClause,
  130. $offset, $rowcount, $sort,
  131. $includeContactIDs, NULL
  132. );
  133. }
  134. /**
  135. * @return string
  136. */
  137. public function from() {
  138. //define table name
  139. $randomNum = md5(uniqid());
  140. $this->_tableName = "civicrm_temp_custom_{$randomNum}";
  141. //block for Group search
  142. $smartGroup = [];
  143. $group = new CRM_Contact_DAO_Group();
  144. $group->is_active = 1;
  145. $group->find();
  146. while ($group->fetch()) {
  147. $allGroups[] = $group->id;
  148. if ($group->saved_search_id) {
  149. $smartGroup[$group->saved_search_id] = $group->id;
  150. }
  151. }
  152. $includedGroups = implode(',', $allGroups);
  153. if (!empty($this->_includeGroups)) {
  154. $iGroups = implode(',', $this->_includeGroups);
  155. }
  156. else {
  157. //if no group selected search for all groups
  158. $iGroups = $includedGroups;
  159. }
  160. if (is_array($this->_excludeGroups)) {
  161. $xGroups = implode(',', $this->_excludeGroups);
  162. }
  163. else {
  164. $xGroups = 0;
  165. }
  166. $sql = "DROP TEMPORARY TABLE IF EXISTS Xg_{$this->_tableName}";
  167. CRM_Core_DAO::executeQuery($sql);
  168. $sql = "CREATE TEMPORARY TABLE Xg_{$this->_tableName} ( contact_id int primary key) ENGINE=HEAP";
  169. CRM_Core_DAO::executeQuery($sql);
  170. //used only when exclude group is selected
  171. if ($xGroups != 0) {
  172. $excludeGroup = "INSERT INTO Xg_{$this->_tableName} ( contact_id )
  173. SELECT DISTINCT civicrm_group_contact.contact_id
  174. FROM civicrm_group_contact
  175. WHERE
  176. civicrm_group_contact.status = 'Added' AND
  177. civicrm_group_contact.group_id IN ( {$xGroups} )";
  178. CRM_Core_DAO::executeQuery($excludeGroup);
  179. //search for smart group contacts
  180. foreach ($this->_excludeGroups as $keys => $values) {
  181. if (in_array($values, $smartGroup)) {
  182. $ssId = CRM_Utils_Array::key($values, $smartGroup);
  183. $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId);
  184. $smartSql = $smartSql . " AND contact_a.id NOT IN (
  185. SELECT contact_id FROM civicrm_group_contact
  186. WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')";
  187. $smartGroupQuery = " INSERT IGNORE INTO Xg_{$this->_tableName}(contact_id) $smartSql";
  188. CRM_Core_DAO::executeQuery($smartGroupQuery);
  189. }
  190. }
  191. }
  192. $sql = "DROP TEMPORARY TABLE IF EXISTS Ig_{$this->_tableName}";
  193. CRM_Core_DAO::executeQuery($sql);
  194. $sql = "CREATE TEMPORARY TABLE Ig_{$this->_tableName}
  195. ( id int PRIMARY KEY AUTO_INCREMENT,
  196. contact_id int,
  197. group_names varchar(64)) ENGINE=HEAP";
  198. if ($this->_debug > 0) {
  199. print "-- Include groups query: <pre>";
  200. print "$sql;";
  201. print "</pre>";
  202. }
  203. CRM_Core_DAO::executeQuery($sql);
  204. $includeGroup = "INSERT INTO Ig_{$this->_tableName} (contact_id, group_names)
  205. SELECT civicrm_group_contact.contact_id, civicrm_group.name as group_name
  206. FROM civicrm_group_contact
  207. LEFT JOIN civicrm_group
  208. ON civicrm_group_contact.group_id = civicrm_group.id";
  209. //used only when exclude group is selected
  210. if ($xGroups != 0) {
  211. $includeGroup .= " LEFT JOIN Xg_{$this->_tableName}
  212. ON civicrm_group_contact.contact_id = Xg_{$this->_tableName}.contact_id";
  213. }
  214. $includeGroup .= " WHERE
  215. civicrm_group_contact.status = 'Added' AND
  216. civicrm_group_contact.group_id IN($iGroups)";
  217. //used only when exclude group is selected
  218. if ($xGroups != 0) {
  219. $includeGroup .= " AND Xg_{$this->_tableName}.contact_id IS null";
  220. }
  221. if ($this->_debug > 0) {
  222. print "-- Include groups query: <pre>";
  223. print "$includeGroup;";
  224. print "</pre>";
  225. }
  226. CRM_Core_DAO::executeQuery($includeGroup);
  227. //search for smart group contacts
  228. foreach ($this->_includeGroups as $keys => $values) {
  229. if (in_array($values, $smartGroup)) {
  230. $ssId = CRM_Utils_Array::key($values, $smartGroup);
  231. $smartSql = CRM_Contact_BAO_SavedSearch::contactIDsSQL($ssId);
  232. $smartSql .= " AND contact_a.id NOT IN (
  233. SELECT contact_id FROM civicrm_group_contact
  234. WHERE civicrm_group_contact.group_id = {$values} AND civicrm_group_contact.status = 'Removed')";
  235. //used only when exclude group is selected
  236. if ($xGroups != 0) {
  237. $smartSql .= " AND contact_a.id NOT IN (SELECT contact_id FROM Xg_{$this->_tableName})";
  238. }
  239. $smartGroupQuery = " INSERT IGNORE INTO Ig_{$this->_tableName}(contact_id)
  240. $smartSql";
  241. CRM_Core_DAO::executeQuery($smartGroupQuery);
  242. $insertGroupNameQuery = "UPDATE IGNORE Ig_{$this->_tableName}
  243. SET group_names = (SELECT title FROM civicrm_group
  244. WHERE civicrm_group.id = $values)
  245. WHERE Ig_{$this->_tableName}.contact_id IS NOT NULL
  246. AND Ig_{$this->_tableName}.group_names IS NULL";
  247. CRM_Core_DAO::executeQuery($insertGroupNameQuery);
  248. }
  249. }
  250. $this->buildACLClause('contact_a');
  251. $from = "FROM civicrm_contact contact_a";
  252. $fromTail = "LEFT JOIN civicrm_email ON ( contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1 )";
  253. $fromTail .= " INNER JOIN Ig_{$this->_tableName} temptable1 ON (contact_a.id = temptable1.contact_id)";
  254. // now create a temp table to store the randomized contacts
  255. $sql = "DROP TEMPORARY TABLE IF EXISTS random_{$this->_tableName}";
  256. CRM_Core_DAO::executeQuery($sql);
  257. $sql = "CREATE TEMPORARY TABLE random_{$this->_tableName} ( id int primary key ) ENGINE=HEAP";
  258. CRM_Core_DAO::executeQuery($sql);
  259. if (substr($this->_segmentSize, -1) == '%') {
  260. $countSql = "SELECT DISTINCT contact_a.id $from $fromTail
  261. WHERE " . $this->where();
  262. $dao = CRM_Core_DAO::executeQuery($countSql);
  263. $totalSize = $dao->N;
  264. $multiplier = substr($this->_segmentSize, 0, strlen($this->_segmentSize) - 1);
  265. $multiplier /= 100;
  266. $this->_segmentSize = round($totalSize * $multiplier);
  267. }
  268. $sql = "INSERT INTO random_{$this->_tableName} ( id )
  269. SELECT DISTINCT contact_a.id $from $fromTail
  270. WHERE " . $this->where() . "
  271. ORDER BY RAND()
  272. LIMIT {$this->_segmentSize}";
  273. CRM_Core_DAO::executeQuery($sql);
  274. $from = "FROM random_{$this->_tableName} random";
  275. $from .= " INNER JOIN civicrm_contact contact_a ON random.id = contact_a.id {$this->_aclFrom}";
  276. $from .= " $fromTail";
  277. return $from;
  278. }
  279. /**
  280. * @param bool $includeContactIDs
  281. *
  282. * @return string
  283. */
  284. public function where($includeContactIDs = FALSE) {
  285. $where = '(1)';
  286. if ($this->_aclWhere) {
  287. $where .= " AND {$this->_aclWhere} ";
  288. }
  289. return '(1)';
  290. }
  291. /**
  292. * @return string
  293. */
  294. public function templateFile() {
  295. return 'CRM/Contact/Form/Search/Custom.tpl';
  296. }
  297. /**
  298. * @param $title
  299. */
  300. public function setTitle($title) {
  301. if ($title) {
  302. CRM_Utils_System::setTitle($title);
  303. }
  304. else {
  305. CRM_Utils_System::setTitle(ts('Search'));
  306. }
  307. }
  308. /**
  309. * @return mixed
  310. */
  311. /**
  312. * @return mixed
  313. */
  314. public function count() {
  315. $sql = $this->all();
  316. $dao = CRM_Core_DAO::executeQuery($sql);
  317. return $dao->N;
  318. }
  319. /**
  320. * Destructor function.
  321. */
  322. public function __destruct() {
  323. // the temporary tables are dropped automatically
  324. // so we don't do it here
  325. // but let mysql clean up
  326. return NULL;
  327. }
  328. /**
  329. * @param string $tableAlias
  330. */
  331. public function buildACLClause($tableAlias = 'contact') {
  332. list($this->_aclFrom, $this->_aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause($tableAlias);
  333. }
  334. }