Skip to content

Commit

Permalink
Merge pull request #17250 from eileenmcnaughton/act_search
Browse files Browse the repository at this point in the history
Remove slow join from activity search
  • Loading branch information
seamuslee001 authored Jun 29, 2020
2 parents 84500e3 + d1d108e commit bd1d54e
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 56 deletions.
8 changes: 5 additions & 3 deletions CRM/Activity/BAO/Activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -905,13 +905,15 @@ public static function filterActivityTypes($params) {
*/
public function addSelectWhereClause() {
$clauses = [];
// @todo - check if $permissedActivityTYpes === all activity types and do not add critieria if so.
$permittedActivityTypeIDs = self::getPermittedActivityTypes();
$allActivityTypes = self::buildOptions('activity_type_id');
if (empty($permittedActivityTypeIDs)) {
// This just prevents a mysql fail if they have no access - should be extremely edge case.
$permittedActivityTypeIDs = [0];
}
$clauses['activity_type_id'] = ('IN (' . implode(', ', $permittedActivityTypeIDs) . ')');
if (array_keys($allActivityTypes) !== array_keys($permittedActivityTypeIDs)) {
$clauses['activity_type_id'] = ('IN (' . implode(', ', $permittedActivityTypeIDs) . ')');
}

$contactClause = CRM_Utils_SQL::mergeSubquery('Contact');
if ($contactClause) {
Expand Down Expand Up @@ -2131,7 +2133,7 @@ public static function exportableFields($name = 'Activity') {

// TODO: ideally we should retrieve all fields from xml, in this case since activity processing is done
// my case hence we have defined fields as case_*
if ($name == 'Activity') {
if ($name === 'Activity') {
$exportableFields = CRM_Activity_DAO_Activity::export();
$exportableFields['source_contact_id'] = [
'title' => ts('Source Contact ID'),
Expand Down
17 changes: 4 additions & 13 deletions CRM/Activity/BAO/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,13 @@ public static function select(&$query) {
$query->_tables['civicrm_activity'] = $query->_whereTables['civicrm_activity'] = 1;
}

if (!empty($query->_returnProperties['activity_type_id'])) {
$query->_select['activity_type_id'] = 'activity_type.value as activity_type_id';
if (!empty($query->_returnProperties['activity_type_id'])
|| !empty($query->_returnProperties['activity_type'])
) {
$query->_select['activity_type_id'] = 'civicrm_activity.activity_type_id';
$query->_element['activity_type_id'] = 1;
$query->_tables['civicrm_activity'] = 1;
$query->_tables['activity_type'] = 1;
$query->_whereTables['civicrm_activity'] = 1;
$query->_whereTables['activity_type'] = 1;
}

if (!empty($query->_returnProperties['activity_type'])) {
$query->_select['activity_type'] = 'activity_type.label as activity_type';
$query->_element['activity_type'] = 1;
$query->_tables['civicrm_activity'] = 1;
$query->_tables['activity_type'] = 1;
$query->_whereTables['civicrm_activity'] = 1;
$query->_whereTables['activity_type'] = 1;
}

if (!empty($query->_returnProperties['activity_subject'])) {
Expand Down
31 changes: 0 additions & 31 deletions CRM/Activity/Selector/Search.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,37 +154,6 @@ public function __construct(

$this->_activityClause = $activityClause;

// CRM-12675
$components = CRM_Core_Component::getNames();
$componentClause = [];
foreach ($components as $componentID => $componentName) {
// CRM-19201: Add support for searching CiviCampaign and CiviCase
// activities. For CiviCase, "access all cases and activities" is
// required here rather than "access my cases and activities" to
// prevent those with only the later permission from seeing a list
// of all cases which might present a privacy issue.
// @todo this is the cause of the current devastatingly bad performance on
// activity search - it involves a bad join.
// The correct fix is to use the permission infrastrucutre - ie. add in the
// clause generated by CRM_Activity_BAO_Query::addSelectWhere
// but some testing needs to check that before making the change
// see https://github.com/civicrm/civicrm-core/blob/be2fb01f90f5f299dd07402a41fed7c7c7567f00/CRM/Utils/SQL.php#L48
// for how it's done in the api kernel.
if (!CRM_Core_Permission::access($componentName, TRUE, TRUE)) {
$componentClause[] = " (activity_type.component_id IS NULL OR activity_type.component_id <> {$componentID}) ";
}
}

if (!empty($componentClause)) {
$componentRestriction = implode(' AND ', $componentClause);
if (empty($this->_activityClause)) {
$this->_activityClause = $componentRestriction;
}
else {
$this->_activityClause .= ' AND ' . $componentRestriction;
}
}

// type of selector
$this->_action = $action;
$this->_query = new CRM_Contact_BAO_Query($this->_queryParams,
Expand Down
22 changes: 22 additions & 0 deletions CRM/Contact/BAO/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -5047,6 +5047,28 @@ public function generatePermissionClause($onlyDeleted = FALSE, $count = FALSE) {
$this->_skipDeleteClause
);

if (isset($this->_tables['civicrm_activity'])) {
$bao = new CRM_Activity_BAO_Activity();
$clauses = $subclauses = [];
foreach ((array) $bao->addSelectWhereClause() as $field => $vals) {
if ($vals && $field !== 'id') {
$clauses[] = $bao->tableName() . ".$field " . $vals;
}
elseif ($vals) {
$subclauses[] = "$field " . implode(" AND $field ", (array) $vals);
}
}
if ($subclauses) {
$clauses[] = $bao->tableName() . '.`id` IN (SELECT `id` FROM `' . $bao->tableName() . '` WHERE ' . implode(' AND ', $subclauses) . ')';
}
if (!empty($clauses) && $this->_permissionWhereClause) {
$this->_permissionWhereClause .= ' AND (' . implode(' AND ', $clauses) . ')';
}
elseif (!empty($clauses)) {
$this->_permissionWhereClause .= '(' . implode(' AND ', $clauses) . ')';
}
}

// regenerate fromClause since permission might have added tables
if ($this->_permissionWhereClause) {
//fix for row count in qill (in contribute/membership find)
Expand Down
4 changes: 2 additions & 2 deletions CRM/Core/DAO.php
Original file line number Diff line number Diff line change
Expand Up @@ -2640,7 +2640,7 @@ public function getOptionLabels() {
*
* @param string $context
*
* @throws Exception
* @throws CRM_Core_Exception
* @return array
*/
public static function buildOptionsContext($context = NULL) {
Expand All @@ -2654,7 +2654,7 @@ public static function buildOptionsContext($context = NULL) {
];
// Validation: enforce uniformity of this param
if ($context !== NULL && !isset($contexts[$context])) {
throw new Exception("'$context' is not a valid context for buildOptions.");
throw new CRM_Core_Exception("'$context' is not a valid context for buildOptions.");
}
return $contexts;
}
Expand Down
2 changes: 1 addition & 1 deletion CRM/Export/BAO/ExportProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ public function getExportFileName() {
* @return string
*/
public function getHeaderForRow($field) {
if (substr($field, -11) == 'campaign_id') {
if (substr($field, -11) === 'campaign_id') {
// @todo - set this correctly in the xml rather than here.
// This will require a generalised handling cleanup
return ts('Campaign ID');
Expand Down
3 changes: 3 additions & 0 deletions tests/phpunit/CRM/Activity/Selector/SearchTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ class CRM_Activity_Selector_SearchTest extends CiviUnitTestCase {

/**
* Test activity search applies a permission based component filter.
*
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
public function testActivitySearchComponentPermission() {
$this->activityCreate(['activity_type_id' => 'Contribution']);
Expand Down
12 changes: 6 additions & 6 deletions tests/phpunit/CRM/Contact/SelectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,24 @@ public function testSelectorQuery($dataSet) {
$this->assertLike($this->strWrangle($queryString), $this->strWrangle($sql[$index]));
}
// Ensure that search builder return individual contact as per criteria
if ($dataSet['context'] == 'builder') {
if ($dataSet['context'] === 'builder') {
$contactID = $this->individualCreate(['first_name' => 'James', 'last_name' => 'Bond']);
if ('Search builder behaviour for Activity' == $dataSet['description']) {
if ('Search builder behaviour for Activity' === $dataSet['description']) {
$this->callAPISuccess('Activity', 'create', [
'activity_type_id' => 'Meeting',
'subject' => "Test",
'subject' => 'Test',
'source_contact_id' => $contactID,
]);
$rows = CRM_Core_DAO::executeQuery(implode(' ', $sql))->fetchAll();
$this->assertEquals(1, count($rows));
$this->assertCount(1, $rows);
$this->assertEquals($contactID, $rows[0]['source_contact_id']);
}
else {
$this->callAPISuccess('Address', 'create', [
'contact_id' => $contactID,
'location_type_id' => "Home",
'location_type_id' => 'Home',
'is_primary' => 1,
'country_id' => "IN",
'country_id' => 'IN',
]);
$rows = $selector->getRows(CRM_Core_Action::VIEW, 0, 50, '');
$this->assertEquals(1, count($rows));
Expand Down

0 comments on commit bd1d54e

Please sign in to comment.