Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REF] Activity Summary report - move temp table generation etc from postProcess to buildQuery, remove postProcess, don't skip in unit tests #14375

Merged
merged 2 commits into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 132 additions & 135 deletions CRM/Report/Form/ActivitySummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,60 +297,62 @@ public function select() {

/**
* Generate from clause.
*
* @param bool|FALSE $durationMode
*/
public function from($durationMode = FALSE) {
public function from() {
$activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
$assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
$targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
$sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);

if (!$durationMode) {
$this->_from = "
FROM civicrm_activity {$this->_aliases['civicrm_activity']}

LEFT JOIN civicrm_activity_contact target_activity
ON {$this->_aliases['civicrm_activity']}.id = target_activity.activity_id AND
target_activity.record_type_id = {$targetID}
LEFT JOIN civicrm_activity_contact assignment_activity
ON {$this->_aliases['civicrm_activity']}.id = assignment_activity.activity_id AND
assignment_activity.record_type_id = {$assigneeID}
LEFT JOIN civicrm_activity_contact source_activity
ON {$this->_aliases['civicrm_activity']}.id = source_activity.activity_id AND
source_activity.record_type_id = {$sourceID}
LEFT JOIN civicrm_contact contact_civireport
ON target_activity.contact_id = contact_civireport.id
LEFT JOIN civicrm_contact civicrm_contact_assignee
ON assignment_activity.contact_id = civicrm_contact_assignee.id
LEFT JOIN civicrm_contact civicrm_contact_source
ON source_activity.contact_id = civicrm_contact_source.id
{$this->_aclFrom}
LEFT JOIN civicrm_option_value
ON ( {$this->_aliases['civicrm_activity']}.activity_type_id = civicrm_option_value.value )
LEFT JOIN civicrm_option_group
ON civicrm_option_group.id = civicrm_option_value.option_group_id
LEFT JOIN civicrm_case_activity
ON civicrm_case_activity.activity_id = {$this->_aliases['civicrm_activity']}.id
LEFT JOIN civicrm_case
ON civicrm_case_activity.case_id = civicrm_case.id
LEFT JOIN civicrm_case_contact
ON civicrm_case_contact.case_id = civicrm_case.id ";

$this->joinPhoneFromContact();
}
else {
$this->_from = "
$this->_from = "
FROM civicrm_activity {$this->_aliases['civicrm_activity']}

LEFT JOIN civicrm_activity_contact target_activity
ON {$this->_aliases['civicrm_activity']}.id = target_activity.activity_id AND
target_activity.record_type_id = {$targetID}
LEFT JOIN civicrm_activity_contact assignment_activity
ON {$this->_aliases['civicrm_activity']}.id = assignment_activity.activity_id AND
assignment_activity.record_type_id = {$assigneeID}
LEFT JOIN civicrm_activity_contact source_activity
ON {$this->_aliases['civicrm_activity']}.id = source_activity.activity_id AND
source_activity.record_type_id = {$sourceID}
LEFT JOIN civicrm_contact contact_civireport
ON target_activity.contact_id = contact_civireport.id
LEFT JOIN civicrm_contact civicrm_contact_assignee
ON assignment_activity.contact_id = civicrm_contact_assignee.id
LEFT JOIN civicrm_contact civicrm_contact_source
ON source_activity.contact_id = civicrm_contact_source.id
{$this->_aclFrom}
LEFT JOIN civicrm_option_value
ON ( {$this->_aliases['civicrm_activity']}.activity_type_id = civicrm_option_value.value )
LEFT JOIN civicrm_option_group
ON civicrm_option_group.id = civicrm_option_value.option_group_id
LEFT JOIN civicrm_case_activity
ON civicrm_case_activity.activity_id = {$this->_aliases['civicrm_activity']}.id
LEFT JOIN civicrm_case
ON civicrm_case_activity.case_id = civicrm_case.id
LEFT JOIN civicrm_case_contact
ON civicrm_case_contact.case_id = civicrm_case.id ";

$this->joinPhoneFromContact();

$this->joinEmailFromContact();
}

/**
* Generate from clause for when calculating activity durations.
*/
public function activityDurationFrom() {
$activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
$targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
$this->_from = "
FROM civicrm_activity {$this->_aliases['civicrm_activity']}
LEFT JOIN civicrm_activity_contact target_activity
ON {$this->_aliases['civicrm_activity']}.id = target_activity.activity_id AND
target_activity.record_type_id = {$targetID}
LEFT JOIN civicrm_contact contact_civireport
ON target_activity.contact_id = contact_civireport.id
{$this->_aclFrom}";
}

$this->joinEmailFromContact();
}

/**
Expand Down Expand Up @@ -412,6 +414,95 @@ public function where($durationMode = FALSE) {
}
}

/**
* Build the report query.
*
* @param bool $applyLimit
*
* @return string
*/
public function buildQuery($applyLimit = TRUE) {
$this->buildGroupTempTable();
$this->select();
$this->from();
$this->customDataFrom();
$this->buildPermissionClause();
$this->where();
$this->groupBy();
$this->orderBy();

foreach ($this->unselectedOrderByColumns() as $alias => $field) {
$clause = $this->getSelectClauseWithGroupConcatIfNotGroupedBy($field['table_name'], $field['name'], $field);
if (!$clause) {
$clause = "{$field['dbAlias']} as {$alias}";
}
$this->_select .= ", $clause ";
}

if ($applyLimit && empty($this->_params['charts'])) {
$this->limit();
}
CRM_Utils_Hook::alterReportVar('sql', $this, $this);

// order_by columns not selected for display need to be included in SELECT
$unselectedSectionColumns = $this->unselectedSectionColumns();
foreach ($unselectedSectionColumns as $alias => $section) {
$this->_select .= ", {$section['dbAlias']} as {$alias}";
}

// build temporary table column names base on column headers of result
$dbColumns = [];
foreach ($this->_columnHeaders as $fieldName => $dontCare) {
$dbColumns[] = $fieldName . ' VARCHAR(128)';
}

// create temp table to store main result
$this->_tempTableName = $this->createTemporaryTable('tempTable', "
id int unsigned NOT NULL AUTO_INCREMENT, " . implode(', ', $dbColumns) . ' , PRIMARY KEY (id)',
TRUE);

// build main report query
$sql = "{$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} {$this->_having} {$this->_orderBy} {$this->_limit}";
$this->addToDeveloperTab($sql);

// store the result in temporary table
$insertCols = '';
$insertQuery = "INSERT INTO {$this->_tempTableName} ( " . implode(',', array_keys($this->_columnHeaders)) . " )
{$sql}";
CRM_Core_DAO::executeQuery($insertQuery);

// now build the query for duration sum
$this->activityDurationFrom();
$this->where(TRUE);
$this->groupBy(FALSE);

// build the query to calulate duration sum
$sql = "SELECT SUM(activity_civireport.duration) as civicrm_activity_duration_total {$this->_from} {$this->_where} {$this->_groupBy} {$this->_having} {$this->_orderBy} {$this->_limit}";

// create temp table to store duration
$this->_tempDurationSumTableName = $this->createTemporaryTable('tempDurationSumTable', "
id int unsigned NOT NULL AUTO_INCREMENT, civicrm_activity_duration_total VARCHAR(128), PRIMARY KEY (id)",
TRUE);

// store the result in temporary table
$insertQuery = "INSERT INTO {$this->_tempDurationSumTableName} (civicrm_activity_duration_total)
{$sql}";
CRM_Core_DAO::executeQuery($insertQuery);

$sql = "SELECT {$this->_tempTableName}.*, {$this->_tempDurationSumTableName}.civicrm_activity_duration_total
FROM {$this->_tempTableName} INNER JOIN {$this->_tempDurationSumTableName}
ON ({$this->_tempTableName}.id = {$this->_tempDurationSumTableName}.id)";

// finally add duration total to column headers
$this->_columnHeaders['civicrm_activity_duration_total'] = ['no_display' => 1];

// reset the sql building to default, which is used / called during other actions like "add to group"
$this->from();
$this->where();

return $sql;
}

/**
* Group the fields.
*
Expand Down Expand Up @@ -503,100 +594,6 @@ public static function formRule($fields, $files, $self) {
return $errors;
}

public function postProcess() {
// get the acl clauses built before we assemble the query
$this->buildACLClause($this->_aliases['civicrm_contact']);

// get ready with post process params
$this->beginPostProcess();

// build query
$sql = $this->buildQuery();

// main sql statement
$this->select();
$this->from();
$this->customDataFrom();
$this->where();
$this->groupBy();
$this->orderBy();

// order_by columns not selected for display need to be included in SELECT
$unselectedSectionColumns = $this->unselectedSectionColumns();
foreach ($unselectedSectionColumns as $alias => $section) {
$this->_select .= ", {$section['dbAlias']} as {$alias}";
}

if (!empty($applyLimit) && empty($this->_params['charts'])) {
$this->limit();
}
CRM_Utils_Hook::alterReportVar('sql', $this, $this);

// build temporary table column names base on column headers of result
$dbColumns = [];
foreach ($this->_columnHeaders as $fieldName => $dontCare) {
$dbColumns[] = $fieldName . ' VARCHAR(128)';
}

// create temp table to store main result
$this->_tempTableName = $this->createTemporaryTable('tempTable', "
id int unsigned NOT NULL AUTO_INCREMENT, " . implode(', ', $dbColumns) . ' , PRIMARY KEY (id)',
TRUE);

// build main report query
$sql = "{$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} {$this->_having} {$this->_orderBy} {$this->_limit}";

// store the result in temporary table
$insertCols = '';
$insertQuery = "INSERT INTO {$this->_tempTableName} ( " . implode(',', array_keys($this->_columnHeaders)) . " )
{$sql}";
CRM_Core_DAO::executeQuery($insertQuery);

// now build the query for duration sum
$this->from(TRUE);
$this->where(TRUE);
$this->groupBy(FALSE);

// build the query to calulate duration sum
$sql = "SELECT SUM(activity_civireport.duration) as civicrm_activity_duration_total {$this->_from} {$this->_where} {$this->_groupBy} {$this->_having} {$this->_orderBy} {$this->_limit}";

// create temp table to store duration
$this->_tempDurationSumTableName = $this->createTemporaryTable('tempDurationSumTable', "
id int unsigned NOT NULL AUTO_INCREMENT, civicrm_activity_duration_total VARCHAR(128), PRIMARY KEY (id)",
TRUE);

// store the result in temporary table
$insertQuery = "INSERT INTO {$this->_tempDurationSumTableName} (civicrm_activity_duration_total)
{$sql}";
CRM_Core_DAO::executeQuery($insertQuery);

// build array of result based on column headers. This method also allows
// modifying column headers before using it to build result set i.e $rows.
$rows = [];
$query = "SELECT {$this->_tempTableName}.*, {$this->_tempDurationSumTableName}.civicrm_activity_duration_total
FROM {$this->_tempTableName} INNER JOIN {$this->_tempDurationSumTableName}
ON ({$this->_tempTableName}.id = {$this->_tempDurationSumTableName}.id)";

// finally add duration total to column headers
$this->_columnHeaders['civicrm_activity_duration_total'] = ['no_display' => 1];

$this->buildRows($query, $rows);

// format result set.
$this->formatDisplay($rows);

// assign variables to templates
$this->doTemplateAssignment($rows);

//reset the sql building to default, which is used / called during other actions like "add to group"
// now build the query for duration sum
$this->from();
$this->where();

// do print / pdf / instance stuff if needed
$this->endPostProcess($rows);
}

/**
* @param $rows
*
Expand Down
5 changes: 2 additions & 3 deletions tests/phpunit/api/v3/ReportTemplateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@ public static function getReportTemplates() {
$reportsToSkip = array(
'event/income' => 'I do no understand why but error is Call to undefined method CRM_Report_Form_Event_Income::from() in CRM/Report/Form.php on line 2120',
'contribute/history' => 'Declaration of CRM_Report_Form_Contribute_History::buildRows() should be compatible with CRM_Report_Form::buildRows($sql, &$rows)',
'activitySummary' => 'We use temp tables for the main query generation and name are dynamic. These names are not available in stats() when called directly.',
);

$reports = civicrm_api3('report_template', 'get', array('return' => 'value', 'options' => array('limit' => 500)));
Expand Down Expand Up @@ -934,9 +933,9 @@ public function testReportsWithNoTInSmartGroupFilter($template) {
}

/**
* Test activity summary report - requiring all current fields to be output.
* Test activity details report - requiring all current fields to be output.
*/
public function testActivitySummary() {
public function testActivityDetails() {
$this->createContactsWithActivities();
$fields = [
'contact_source' => '1',
Expand Down