Skip to content

Commit

Permalink
CRM-20545 - port extended reports metadata approach to adding columns
Browse files Browse the repository at this point in the history
  • Loading branch information
eileenmcnaughton committed Nov 14, 2017
1 parent ebe4024 commit 415f0f4
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 61 deletions.
276 changes: 276 additions & 0 deletions CRM/Report/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -4928,4 +4928,280 @@ protected function setTableAlias($table, $tableName) {
return $this->_aliases[$tableName];
}

/**
* Function to add columns to reports.
*
* This is ported from extended reports, which also adds join filters to the options.
*
* @param string $type
* @param array $options
* - prefix - A string to prepend to the table name
* - prefix_label A string to prepend to the fields
* - fields (bool) - should the fields for this table be made available
* - group_by (bool) - should the group bys for this table be made available.
* - order_by (bool) - should the group bys for this table be made available.
* - filters (bool) - should the filters for this table by made available.
* - fields_defaults (array) array of fields that should be displayed by default.
* - filters_defaults (array) array of fields that should be filtered by default.
* - join_filters (array) fields available for filtering joins (requires additional custom code).
* - join_fields (array) fields available from join (requires additional custom code).
* - group_by_defaults (array) array of group bys that should be applied by default.
* - order_by_defaults (array) array of order bys that should be applied by default.
* - custom_fields (array) array of entity types for custom fields (not usually required).
* - contact_type (string) optional restriction on contact type for some tables.
* - fields_excluded (array) fields that are in the generic set for the table but not in the report.
*
* @return array
*/
protected function getColumns($type, $options = array()) {
$defaultOptions = array(
'prefix' => '',
'prefix_label' => '',
'fields' => TRUE,
'group_bys' => FALSE,
'order_bys' => TRUE,
'filters' => TRUE,
'join_filters' => FALSE,
'fields_defaults' => array(),
'filters_defaults' => array(),
'group_bys_defaults' => array(),
'order_bys_defaults' => array(),
);
$options = array_merge($defaultOptions, $options);

$fn = 'get' . $type . 'Columns';
return $this->$fn($options);
}

/**
* Get columns for contact table.
*
* @param array $options
*
* @return array
*/
protected function getContactColumns($options = array()) {
$defaultOptions = array(
'custom_fields' => array('Individual', 'Contact', 'Organization'),
'fields_defaults' => array('display_name', 'id'),
'order_bys_defaults' => array('sort_name ASC'),
'contact_type' => NULL,
);

$options = array_merge($defaultOptions, $options);

$tableAlias = $options['prefix'] . 'contact';

$spec = array(
$options['prefix'] . 'display_name' => array(
'name' => 'display_name',
'title' => ts($options['prefix_label'] . 'Contact Name'),
'is_fields' => TRUE,
),
$options['prefix'] . 'sort_name' => array(
'name' => 'sort_name',
'title' => ts($options['prefix_label'] . 'Contact Name (in sort format)'),
'is_fields' => TRUE,
'is_filters' => TRUE,
'is_order_bys' => TRUE,
),
$options['prefix'] . 'id' => array(
'name' => 'id',
'title' => ts($options['prefix_label'] . 'Contact ID'),
'alter_display' => 'alterContactID',
'type' => CRM_Utils_Type::T_INT,
'is_order_bys' => TRUE,
'is_group_bys' => TRUE,
'is_fields' => TRUE,
),
$options['prefix'] . 'external_identifier' => array(
'name' => 'external_identifier',
'title' => ts($options['prefix_label'] . 'External ID'),
'type' => CRM_Utils_Type::T_INT,
'is_fields' => TRUE,
),
$options['prefix'] . 'contact_type' => array(
'title' => ts($options['prefix_label'] . 'Contact Type'),
'name' => 'contact_type',
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contact_BAO_Contact::buildOptions('contact_type'),
'is_fields' => TRUE,
'is_filters' => TRUE,
'is_group_bys' => TRUE,
),
$options['prefix'] . 'contact_sub_type' => array(
'title' => ts($options['prefix_label'] . 'Contact Sub Type'),
'name' => 'contact_sub_type',
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contact_BAO_Contact::buildOptions('contact_sub_type'),
'is_fields' => TRUE,
'is_filters' => TRUE,
'is_group_bys' => TRUE,
),
$options['prefix'] . 'is_deleted' => array(
'title' => ts($options['prefix_label'] . 'Is deleted'),
'name' => 'is_deleted',
'type' => CRM_Utils_Type::T_BOOLEAN,
'is_fields' => FALSE,
'is_filters' => TRUE,
'is_group_bys' => FALSE,
),
);
$individualFields = array(
$options['prefix'] . 'first_name' => array(
'name' => 'first_name',
'title' => ts($options['prefix_label'] . 'First Name'),
'is_fields' => TRUE,
'is_filters' => TRUE,
'is_order_bys' => TRUE,
),
$options['prefix'] . 'middle_name' => array(
'name' => 'middle_name',
'title' => ts($options['prefix_label'] . 'Middle Name'),
'is_fields' => TRUE,
),
$options['prefix'] . 'last_name' => array(
'name' => 'last_name',
'title' => ts($options['prefix_label'] . 'Last Name'),
'default_order' => 'ASC',
'is_fields' => TRUE,
),
$options['prefix'] . 'nick_name' => array(
'name' => 'nick_name',
'title' => ts($options['prefix_label'] . 'Nick Name'),
'is_fields' => TRUE,
),
$options['prefix'] . 'gender_id' => array(
'name' => 'gender_id',
'title' => ts($options['prefix_label'] . 'Gender'),
'options' => CRM_Contact_BAO_Contact::buildOptions('gender_id'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'alter_display' => 'alterGenderID',
'is_fields' => TRUE,
'is_filters' => TRUE,
),
'birth_date' => array(
'title' => ts($options['prefix_label'] . 'Birth Date'),
'operatorType' => CRM_Report_Form::OP_DATE,
'type' => CRM_Utils_Type::T_DATE,
'is_fields' => TRUE,
'is_filters' => TRUE,
),
'age' => array(
'title' => ts($options['prefix_label'] . 'Age'),
'dbAlias' => 'TIMESTAMPDIFF(YEAR, ' . $tableAlias . '.birth_date, CURDATE())',
'type' => CRM_Utils_Type::T_INT,
'is_fields' => TRUE,
),
$options['prefix'] . 'is_deceased' => array(
'title' => ts($options['prefix_label'] . 'Is deceased'),
'name' => 'is_deceased',
'type' => CRM_Utils_Type::T_BOOLEAN,
'is_fields' => FALSE,
'is_filters' => TRUE,
'is_group_bys' => FALSE,
),
);
if (!$options['contact_type'] || $options['contact_type'] === 'Individual') {
$spec = array_merge($spec, $individualFields);
}

if (!empty($options['custom_fields'])) {
$this->_customGroupExtended[$options['prefix'] . 'civicrm_contact'] = array(
'extends' => $options['custom_fields'],
'title' => $options['prefix_label'],
'filters' => $options['filters'],
'prefix' => $options['prefix'],
'prefix_label' => $options['prefix_label'],
);
}

return $this->buildColumns($spec, $options['prefix'] . 'civicrm_contact', 'CRM_Contact_DAO_Contact', $tableAlias, $this->getDefaultsFromOptions($options), $options);
}

/**
* Build the columns.
*
* The normal report class needs you to remember to do a few things that are often erratic
*
* 1) use a unique key for any field that might not be unique (e.g. start date, label)
* - this class will prepend an alias to the key & set the 'name' if you don't set it yourself.
* You can suppress the alias with 'no_field_disambiguation' if transitioning existing reports. This
* means any saved filters / fields on saved report instances. This will mean that matching names from
* different tables may be ambigious, but it will smooth any code transition.
* - note that it assumes the value being passed in is the actual table field name
*
* 2) set the field & set it to no display if you don't want the field but you might want to use the field in other
* contexts - the code looks up the fields array for data - so it both defines the field spec & the fields you want to show
*
* 3) this function also sets the 'metadata' array - the extended report class now uses this in place
* of the fields array to reduce the issues caused when metadata is needed but 'fields' are not defined. Code in
* the core classes can start to move towards that.
*
* @param array $specs
* @param string $tableName
* @param string $daoName
* @param string $tableAlias
* @param array $defaults
* @param array $options
*
* @return array
*/
protected function buildColumns($specs, $tableName, $daoName = NULL, $tableAlias = NULL, $defaults = array(), $options = array()) {
if (!$tableAlias) {
$tableAlias = str_replace('civicrm_', '', $tableName);
}
$types = array('filters', 'group_bys', 'order_bys', 'join_filters');
$columns = array($tableName => array_fill_keys($types, array()));
// The code that uses this no longer cares if it is a DAO or BAO so just call it a DAO.
$columns[$tableName]['dao'] = $daoName;
$columns[$tableName]['alias'] = $tableAlias;

foreach ($specs as $specName => $spec) {
if (empty($spec['name'])) {
$spec['name'] = $specName;
}

$fieldAlias = (empty($options['no_field_disambiguation']) ? $tableAlias . '_' : '') . $specName;
$columns[$tableName]['metadata'][$fieldAlias] = $spec;
$columns[$tableName]['fields'][$fieldAlias] = $spec;
if (isset($defaults['fields_defaults']) && in_array($spec['name'], $defaults['fields_defaults'])) {
$columns[$tableName]['fields'][$fieldAlias]['default'] = TRUE;
}

if (!$spec['is_fields'] || (isset($options['fields_excluded']) && in_array($specName, $options['fields_excluded']))) {
$columns[$tableName]['fields'][$fieldAlias]['no_display'] = TRUE;
}

if (isset($options['fields_required']) && in_array($specName, $options['fields_required'])) {
$columns[$tableName]['fields'][$fieldAlias]['required'] = TRUE;
}

foreach ($types as $type) {
if ($options[$type] && !empty($spec['is_' . $type])) {
$columns[$tableName][$type][$fieldAlias] = $spec;
if (isset($defaults[$type . '_defaults']) && isset($defaults[$type . '_defaults'][$spec['name']])) {
$columns[$tableName][$type][$fieldAlias]['default'] = $defaults[$type . '_defaults'][$spec['name']];
}
}
}
}
return $columns;
}

/**
* @param $options
*
* @return array
*/
protected function getDefaultsFromOptions($options) {
$defaults = array(
'fields_defaults' => $options['fields_defaults'],
'filters_defaults' => $options['filters_defaults'],
'group_bys_defaults' => $options['group_bys_defaults'],
'order_bys_defaults' => $options['order_bys_defaults'],
);
return $defaults;
}

}
68 changes: 9 additions & 59 deletions CRM/Report/Form/Contribute/Detail.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,65 +67,15 @@ public function __construct() {
$this->activeCampaigns = $getCampaigns['campaigns'];
asort($this->activeCampaigns);
}
$this->_columns = array(
'civicrm_contact' => array(
'dao' => 'CRM_Contact_DAO_Contact',
'fields' => $this->getBasicContactFields(),
'filters' => array(
'sort_name' => array(
'title' => ts('Donor Name'),
'operator' => 'like',
),
'id' => array(
'title' => ts('Contact ID'),
'no_display' => TRUE,
'type' => CRM_Utils_Type::T_INT,
),
'gender_id' => array(
'title' => ts('Gender'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'),
),
'birth_date' => array(
'title' => ts('Birth Date'),
'operatorType' => CRM_Report_Form::OP_DATE,
),
'contact_type' => array(
'title' => ts('Contact Type'),
),
'contact_sub_type' => array(
'title' => ts('Contact Subtype'),
),
),
'grouping' => 'contact-fields',
'order_bys' => array(
'sort_name' => array(
'title' => ts('Last Name, First Name'),
'default' => '1',
'default_weight' => '0',
'default_order' => 'ASC',
),
'first_name' => array(
'name' => 'first_name',
'title' => ts('First Name'),
),
'gender_id' => array(
'name' => 'gender_id',
'title' => ts('Gender'),
),
'birth_date' => array(
'name' => 'birth_date',
'title' => ts('Birth Date'),
),
'contact_type' => array(
'title' => ts('Contact Type'),
),
'contact_sub_type' => array(
'title' => ts('Contact Subtype'),
),
),

),
$this->_columns = array_merge($this->getColumns('Contact', array(
'order_bys_defaults' => array('sort_name' => 'ASC '),
'fields_defaults' => array('sort_name'),
'fields_excluded' => array('id'),
'fields_required' => array('id'),
'filters_defaults' => array('is_deleted' => FALSE),
'no_field_disambiguation' => TRUE,
)), array(
'civicrm_email' => array(
'dao' => 'CRM_Core_DAO_Email',
'fields' => array(
Expand Down Expand Up @@ -358,7 +308,7 @@ public function __construct() {
),
),
),
) + $this->addAddressFields(FALSE);
)) + $this->addAddressFields(FALSE);
// The tests test for this variation of the sort_name field. Don't argue with the tests :-).
$this->_columns['civicrm_contact']['fields']['sort_name']['title'] = ts('Donor Name');
$this->_groupFilter = TRUE;
Expand Down
9 changes: 8 additions & 1 deletion CRM/Report/Form/Contribute/HouseholdSummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,14 @@ public function __construct() {
),
),
'filters' => array(
'household_name' => array('title' => ts('Household Name')),
'household_name' => array(
'title' => ts('Household Name'),
),
'is_deleted' => array(
'no_display' => TRUE,
'default' => 0,
'type' => CRM_Utils_Type::T_BOOLEAN,
),
),
'grouping' => 'household-fields',
),
Expand Down
9 changes: 8 additions & 1 deletion CRM/Report/Form/Contribute/OrganizationSummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,14 @@ public function __construct() {
),
),
'filters' => array(
'organization_name' => array('title' => ts('Organization Name')),
'organization_name' => array(
'title' => ts('Organization Name'),
),
'is_deleted' => array(
'no_display' => TRUE,
'default' => 0,
'type' => CRM_Utils_Type::T_BOOLEAN,
),
),
'grouping' => 'organization-fields',
),
Expand Down

0 comments on commit 415f0f4

Please sign in to comment.