Commit 11671073 authored by jaapjansma's avatar jaapjansma
Browse files

Added exposure of aggregation on search/report

parent 2792abdf
......@@ -4,6 +4,7 @@
* Change Group Filter so that it also works with smart groups
* Fixed bug with date filter
* Added date group by function to date output field handler.
* Added exposure of Aggregation on the Search/Report output.
# Version 1.1.0
......
......@@ -66,7 +66,7 @@ abstract class CRM_Dataprocessor_Form_Output_AbstractUIOutputForm extends CRM_Co
$dataProcessorName = $this->getDataProcessorName();
$sql = "
SELECT civicrm_data_processor.id as data_processor_id, civicrm_data_processor_output.id AS output_id
FROM civicrm_data_processor
FROM civicrm_data_processor
INNER JOIN civicrm_data_processor_output ON civicrm_data_processor.id = civicrm_data_processor_output.data_processor_id
WHERE is_active = 1 AND civicrm_data_processor.name = %1 AND civicrm_data_processor_output.type = %2
";
......@@ -181,6 +181,7 @@ abstract class CRM_Dataprocessor_Form_Output_AbstractUIOutputForm extends CRM_Co
$filterElements[$fieldSpec->alias]['template'] = $filterHandler->getTemplateFileName();
}
$this->assign('filters', $filterElements);
$this->assign('additional_criteria_template', $this->getAdditionalCriteriaTemplate());
}
}
......@@ -193,4 +194,13 @@ abstract class CRM_Dataprocessor_Form_Output_AbstractUIOutputForm extends CRM_Co
protected function getCriteriaElementSize() {
return 'full';
}
/**
* Returns the name of the additional criteria template.
*
* @return false|String
*/
protected function getAdditionalCriteriaTemplate() {
return false;
}
}
......@@ -228,6 +228,8 @@ abstract class CRM_DataprocessorSearch_Form_AbstractSearch extends CRM_Dataproce
$sortFieldName = $sortField['name'];
}
$this->alterDataProcessor($this->dataProcessorClass);
$output = civicrm_api3("DataProcessorOutput", "getsingle", array('id' => $export_id));
$outputClass = $factory->getOutputByName($output['type']);
if ($outputClass instanceof \Civi\DataProcessor\Output\ExportOutputInterface) {
......
......@@ -90,4 +90,88 @@ class CRM_DataprocessorSearch_Form_Search extends CRM_DataprocessorSearch_Form_A
return $this->_taskList;
}
/**
* Build the criteria form
*/
protected function buildCriteriaForm() {
parent::buildCriteriaForm();
$this->buildAggregateForm();
}
/**
* Returns the name of the additional criteria template.
*
* @return false|String
*/
protected function getAdditionalCriteriaTemplate() {
if (isset($this->dataProcessorOutput['configuration']['expose_aggregate']) && $this->dataProcessorOutput['configuration']['expose_aggregate']) {
return "CRM/DataprocessorSearch/Form/Criteria/AggregateCriteria.tpl";
}
return false;
}
/**
* Build the aggregate form
*/
protected function buildAggregateForm() {
if (!isset($this->dataProcessorOutput['configuration']['expose_aggregate']) || !$this->dataProcessorOutput['configuration']['expose_aggregate']) {
return;
}
$size = $this->getCriteriaElementSize();
$sizeClass = 'huge';
$minWidth = 'min-width: 250px;';
if ($size =='compact') {
$sizeClass = 'medium';
$minWidth = '';
}
$aggregateFields = array();
$defaults = array();
foreach ($this->dataProcessorClass->getDataFlow()->getOutputFieldHandlers() as $outputFieldHandler) {
if ($outputFieldHandler instanceof \Civi\DataProcessor\FieldOutputHandler\OutputHandlerAggregate) {
$aggregateFields[$outputFieldHandler->getAggregateFieldSpec()->alias] = $outputFieldHandler->getOutputFieldSpecification()->title;
if ($outputFieldHandler->isAggregateField()) {
$defaults[] = $outputFieldHandler->getAggregateFieldSpec()->alias;
}
}
}
$this->add('select', "aggregateFields", '', $aggregateFields, false, [
'style' => $minWidth,
'class' => 'crm-select2 '.$sizeClass,
'multiple' => TRUE,
'placeholder' => E::ts('- Select -'),
]);
$this->setDefaults(['aggregateFields' => $defaults]);
}
/**
* Alter the data processor.
*
* Use this function in child classes to add for example additional filters.
*
* E.g. The contact summary tab uses this to add additional filtering on the contact id of
* the displayed contact.
*
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
*/
protected function alterDataProcessor(\Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass) {
if (isset($this->dataProcessorOutput['configuration']['expose_aggregate']) && $this->dataProcessorOutput['configuration']['expose_aggregate']) {
$aggregateFields = $this->_formValues['aggregateFields'];
foreach ($this->dataProcessorClass->getDataFlow()->getOutputFieldHandlers() as $outputFieldHandler) {
if ($outputFieldHandler instanceof \Civi\DataProcessor\FieldOutputHandler\OutputHandlerAggregate) {
$alias = $outputFieldHandler->getAggregateFieldSpec()->alias;
if (in_array($alias, $aggregateFields) && !$outputFieldHandler->isAggregateField()) {
$outputFieldHandler->enableAggregation();
} elseif (!in_array($alias, $aggregateFields) && $outputFieldHandler->isAggregateField()) {
$outputFieldHandler->disableAggregation();
}
}
}
}
}
}
......@@ -58,6 +58,7 @@ class CRM_DataprocessorSearch_Search implements UIOutputInterface {
$form->add('wysiwyg', 'help_text', E::ts('Help text for this search'), array('rows' => 6, 'cols' => 80));
$form->add('checkbox', 'expanded_search', E::ts('Expand criteria form initially'));
$form->add('checkbox', 'expose_aggregate', E::ts('Expose aggregate options'));
// navigation field
$navigationOptions = $navigation->getNavigationOptions();
......@@ -91,6 +92,9 @@ class CRM_DataprocessorSearch_Search implements UIOutputInterface {
if (isset($output['configuration']['expanded_search'])) {
$defaults['expanded_search'] = $output['configuration']['expanded_search'];
}
if (isset($output['configuration']['expose_aggregate'])) {
$defaults['expose_aggregate'] = $output['configuration']['expose_aggregate'];
}
}
}
if (!isset($defaults['permission'])) {
......@@ -124,6 +128,7 @@ class CRM_DataprocessorSearch_Search implements UIOutputInterface {
$configuration['hidden_fields'] = $submittedValues['hidden_fields'];
$configuration['help_text'] = $submittedValues['help_text'];
$configuration['expanded_search'] = isset($submittedValues['expanded_search']) ? $submittedValues['expanded_search'] : false;
$configuration['expose_aggregate'] = isset($submittedValues['expose_aggregate']) ? $submittedValues['expose_aggregate'] : false;
return $configuration;
}
......
......@@ -251,6 +251,18 @@ abstract class AbstractDataFlow {
$this->aggregateOutputHandlers[] = $aggregateOutputHandler;
}
/**
* @param \Civi\DataProcessor\DataFlow\OutputHandlerAggregate $aggregateOutputHandler
*/
public function removeAggregateOutputHandler(OutputHandlerAggregate $aggregateOutputHandler) {
foreach($this->aggregateOutputHandlers as $key => $item) {
if ($item->getAggregateFieldSpec()->alias == $aggregateOutputHandler->getAggregateFieldSpec()->alias) {
unset($this->aggregateOutputHandlers[$key]);
break;
}
}
}
/**
* Adds a field for sorting
*
......
......@@ -183,6 +183,38 @@ class DateFieldOutputHandler extends AbstractSimpleFieldOutputHandler implements
return $value;
}
/**
* Enable aggregation for this field.
*
* @return void
*/
public function enableAggregation() {
try {
$dataFlow = $this->dataSource->ensureField($this->getAggregateFieldSpec());
if ($dataFlow) {
$dataFlow->addAggregateOutputHandler($this);
}
} catch (\Exception $e) {
// Do nothing.
}
}
/**
* Disable aggregation for this field.
*
* @return void
*/
public function disableAggregation() {
try {
$dataFlow = $this->dataSource->ensureField($this->getAggregateFieldSpec());
if ($dataFlow) {
$dataFlow->removeAggregateOutputHandler($this);
}
} catch (\Exception $e) {
// Do nothing.
}
}
protected function getFunctions() {
return array(
'date' => array(
......
......@@ -11,7 +11,32 @@ use Civi\DataProcessor\Source\SourceInterface;
use Civi\DataProcessor\DataSpecification\FieldSpecification;
use Civi\DataProcessor\FieldOutputHandler\FieldOutput;
class OptionFieldOutputHandler extends AbstractSimpleFieldOutputHandler {
class OptionFieldOutputHandler extends AbstractSimpleFieldOutputHandler implements OutputHandlerAggregate {
/**
* @var bool
*/
protected $isAggregateField = false;
/**
* Initialize the processor
*
* @param String $alias
* @param String $title
* @param array $configuration
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $processorType
*/
public function initialize($alias, $title, $configuration) {
parent::initialize($alias, $title, $configuration);
$this->isAggregateField = isset($configuration['is_aggregate']) ? $configuration['is_aggregate'] : false;
if ($this->isAggregateField) {
$dataFlow = $this->dataSource->ensureField($this->getAggregateFieldSpec());
if ($dataFlow) {
$dataFlow->addAggregateOutputHandler($this);
}
}
}
/**
......@@ -63,5 +88,106 @@ class OptionFieldOutputHandler extends AbstractSimpleFieldOutputHandler {
return false;
}
/**
* @return \Civi\DataProcessor\DataSpecification\FieldSpecification
*/
public function getAggregateFieldSpec() {
return $this->inputFieldSpec;
}
/**
* @return bool
*/
public function isAggregateField() {
return $this->isAggregateField;
}
/**
* Enable aggregation for this field.
*
* @return void
*/
public function enableAggregation() {
try {
$dataFlow = $this->dataSource->ensureField($this->getAggregateFieldSpec());
if ($dataFlow) {
$dataFlow->addAggregateOutputHandler($this);
}
} catch (\Exception $e) {
// Do nothing.
}
}
/**
* Disable aggregation for this field.
*
* @return void
*/
public function disableAggregation() {
try {
$dataFlow = $this->dataSource->ensureField($this->getAggregateFieldSpec());
if ($dataFlow) {
$dataFlow->removeAggregateOutputHandler($this);
}
} catch (\Exception $e) {
// Do nothing.
}
}
/**
* Returns the value. And if needed a formatting could be applied.
* E.g. when the value is a date field and you want to aggregate on the month
* you can then return the month here.
*
* @param $value
*
* @return mixed
*/
public function formatAggregationValue($value) {
return $value;
}
/**
* When this handler has additional configuration you can add
* the fields on the form with this function.
*
* @param \CRM_Core_Form $form
* @param array $field
*/
public function buildConfigurationForm(\CRM_Core_Form $form, $field=array()) {
parent::buildConfigurationForm($form, $field);
$form->add('checkbox', 'is_aggregate', E::ts('Aggregate on this field'));
if (isset($field['configuration'])) {
$configuration = $field['configuration'];
$defaults = array();
if (isset($configuration['is_aggregate'])) {
$defaults['is_aggregate'] = $configuration['is_aggregate'];
}
$form->setDefaults($defaults);
}
}
/**
* Process the submitted values and create a configuration array
*
* @param $submittedValues
* @return array
*/
public function processConfiguration($submittedValues) {
$configuration = parent::processConfiguration($submittedValues);
$configuration['is_aggregate'] = isset($submittedValues['is_aggregate']) ? $submittedValues['is_aggregate'] : false;
return $configuration;
}
/**
* When this handler has configuration specify the template file name
* for the configuration form.
*
* @return false|string
*/
public function getConfigurationTemplateFileName() {
return "CRM/Dataprocessor/Form/Field/Configuration/OptionFieldOutputHandler.tpl";
}
}
......@@ -18,6 +18,21 @@ interface OutputHandlerAggregate {
*/
public function isAggregateField();
/**
* Enable aggregation for this field.
*
* @return void
*/
public function enableAggregation();
/**
* Disable aggregation for this field.
*
* @return void
*/
public function disableAggregation();
/**
* Returns the value. And if needed a formatting could be applied.
* E.g. when the value is a date field and you want to aggregate on the month
......
......@@ -39,6 +39,38 @@ class RawFieldOutputHandler extends AbstractSimpleFieldOutputHandler implements
}
}
/**
* Enable aggregation for this field.
*
* @return void
*/
public function enableAggregation() {
try {
$dataFlow = $this->dataSource->ensureField($this->getAggregateFieldSpec());
if ($dataFlow) {
$dataFlow->addAggregateOutputHandler($this);
}
} catch (\Exception $e) {
// Do nothing.
}
}
/**
* Disable aggregation for this field.
*
* @return void
*/
public function disableAggregation() {
try {
$dataFlow = $this->dataSource->ensureField($this->getAggregateFieldSpec());
if ($dataFlow) {
$dataFlow->removeAggregateOutputHandler($this);
}
} catch (\Exception $e) {
// Do nothing.
}
}
/**
* When this handler has additional configuration you can add
* the fields on the form with this function.
......
{crmScope extensionKey='dataprocessor'}
{include file="CRM/Dataprocessor/Form/Field/Configuration/SimpleFieldOutputHandler.tpl"}
<div class="crm-section">
<div class="label">{$form.is_aggregate.label}</div>
<div class="content">{$form.is_aggregate.html}</div>
<div class="clear"></div>
</div>
{/crmScope}
......@@ -17,7 +17,11 @@
{foreach from=$filters key=filterName item=filter}
{include file=$filter.template filterName=$filter.alias filter=$filter.filter}
{/foreach}
{if $additional_criteria_template}
{include file=$additional_criteria_template}
{/if}
</table>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="botton"}</div>
</div>
</div>
......
{crmScope extensionKey='dataprocessor'}
<tr>
<td class="label">{ts}Aggregate{/ts}</td>
<td>&nbsp;</td>
<td>{$form.aggregateFields.html}</td>
</tr>
{/crmScope}
......@@ -29,6 +29,11 @@
<div class="content">{$form.expanded_search.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section">
<div class="label">{$form.expose_aggregate.label}</div>
<div class="content">{$form.expose_aggregate.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section">
<div class="label">{$form.help_text.label}</div>
<div class="content">{$form.help_text.html}</div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment