From 13124d65e1d83b8017568f16ff6312e3c0502d48 Mon Sep 17 00:00:00 2001 From: Jaap Jansma <jaap.jansma@civicoop.org> Date: Fri, 21 Feb 2025 11:38:54 +0100 Subject: [PATCH] Added Fallback Field Output Handler. --- CHANGELOG.md | 2 + .../DataFlow/AbstractDataFlow.php | 3 + Civi/DataProcessor/Factory.php | 1 + .../AbstractFieldOutputHandler.php | 12 ++ .../FallbackFieldOutputHandler.php | 182 ++++++++++++++++++ .../FieldOutputHandler/FieldOutput.php | 12 +- .../FallbackFieldOutputHandler.tpl | 12 ++ 7 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 Civi/DataProcessor/FieldOutputHandler/FallbackFieldOutputHandler.php create mode 100644 templates/CRM/Dataprocessor/Form/Field/Configuration/FallbackFieldOutputHandler.tpl diff --git a/CHANGELOG.md b/CHANGELOG.md index 162ff7a9..c9e61d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Version 1.119 (not yet released) +* Added Fallback Field Output Handler. + # Version 1.118 * Fixed issues with Aggregated Contribution data source diff --git a/Civi/DataProcessor/DataFlow/AbstractDataFlow.php b/Civi/DataProcessor/DataFlow/AbstractDataFlow.php index bb31229c..cd5051ea 100644 --- a/Civi/DataProcessor/DataFlow/AbstractDataFlow.php +++ b/Civi/DataProcessor/DataFlow/AbstractDataFlow.php @@ -178,6 +178,9 @@ abstract class AbstractDataFlow { foreach($this->outputFieldHandlers as $outputFieldHandler) { $formattedRecord[$outputFieldHandler->getOutputFieldSpecification()->alias] = $outputFieldHandler->formatField($record, $formattedRecord); } + foreach($this->outputFieldHandlers as $outputFieldHandler) { + $formattedRecord = $outputFieldHandler->postFormat($formattedRecord); + } return $formattedRecord; } diff --git a/Civi/DataProcessor/Factory.php b/Civi/DataProcessor/Factory.php index 8210c67d..9ce5a126 100644 --- a/Civi/DataProcessor/Factory.php +++ b/Civi/DataProcessor/Factory.php @@ -236,6 +236,7 @@ class Factory { $this->addOutputHandler('sanitize_string', new Definition('Civi\DataProcessor\FieldOutputHandler\SanitizeString'), E::ts('Replaces special characters by their HTML code and newlines by \\n.')); $this->addOutputHandler('conditionally_map_strings', new Definition('Civi\DataProcessor\FieldOutputHandler\ConditionallyMapStrings'), E::ts('Compare the input with up to 5 strings and map the output accordingly.')); $this->addOutputHandler('contact_count_number_of_cases', new Definition('Civi\DataProcessor\FieldOutputHandler\ContactCountNumberOfCases'), E::ts('Count the number of cases related to the given CiviCRM ID.')); + $this->addOutputHandler('fallback', new Definition('Civi\DataProcessor\FieldOutputHandler\FallbackFieldOutputHandler'), E::ts('Fallback field output')); $this->addFileFormat('csv', new Definition('Civi\DataProcessor\FileFormat\CSVFileFormat'), E::ts('CSV')); } diff --git a/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php index b7d944d1..4bdc8ba8 100644 --- a/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php +++ b/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php @@ -159,5 +159,17 @@ abstract class AbstractFieldOutputHandler { return array(); } + /** + * Do post formatting. + * + * Post formatting is additional formatting of the formatted values of a record. + * + * @param \Civi\DataProcessor\FieldOutputHandler\FieldOutput[] $record + * @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput[] + */ + public function postFormat(array $record) { + return $record; + } + } diff --git a/Civi/DataProcessor/FieldOutputHandler/FallbackFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/FallbackFieldOutputHandler.php new file mode 100644 index 00000000..c756c336 --- /dev/null +++ b/Civi/DataProcessor/FieldOutputHandler/FallbackFieldOutputHandler.php @@ -0,0 +1,182 @@ +<?php +/** + * Copyright (C) 2025 Jaap Jansma (jaap.jansma@civicoop.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +namespace Civi\DataProcessor\FieldOutputHandler; + +use Civi\DataProcessor\DataSpecification\FieldSpecification; +use CRM_Dataprocessor_ExtensionUtil as E; + +class FallbackFieldOutputHandler extends AbstractFieldOutputHandler { + + /** + * @var \Civi\DataProcessor\DataSpecification\FieldSpecification + */ + protected $outputFieldSpec; + + /** + * @var String + */ + protected $field; + + /** + * @var String + */ + protected $fallbackField; + + /** + * Initialize the processor + * + * @param String $alias + * @param String $title + * @param array $configuration + * @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $processorType + */ + public function initialize($alias, $title, $configuration) { + $this->outputFieldSpec = new FieldSpecification($alias, $this->getType(), $title); + $this->field = $configuration['field']; + $this->fallbackField = $configuration['fallback_field']; + } + + /** + * Returns the data type of this field + * + * @return String + */ + protected function getType() { + return 'String'; + } + + /** + * Returns the formatted value + * + * @param $rawRecord + * @param $formattedRecord + * + * @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput + */ + public function formatField($rawRecord, $formattedRecord) { + return new FieldOutput(); + } + + /** + * @return \Civi\DataProcessor\DataSpecification\FieldSpecification + */ + public function getOutputFieldSpecification() { + return $this->outputFieldSpec; + } + + /** + * Do post formatting. + * + * Post formatting is additional formatting of the formatted values of a + * record. + * + * @param \Civi\DataProcessor\FieldOutputHandler\FieldOutput[] $record + * + * @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput[] + */ + public function postFormat(array $record): array { + $alias = $this->getOutputFieldSpecification()->alias; + $field = $record[$this->field]; + $fallback = $record[$this->fallbackField]; + $record[$alias] = clone $fallback; + if ($field && !$field->isEmpty()) { + $record[$alias] = clone $field; + } + return $record; + } + + /** + * Returns true when this handler has additional configuration. + * + * @return bool + */ + public function hasConfiguration() { + return true; + } + + /** + * 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()) { + $fieldSelect = $this->getFieldOutputHandlers($field['data_processor_id']); + + $form->add('select', 'field', E::ts('Field'), $fieldSelect, true, array( + 'style' => 'min-width:250px', + 'class' => 'crm-select2 huge data-processor-field-for-name', + 'placeholder' => E::ts('- select -'), + )); + $form->add('select', 'fallback_field', E::ts('Fallback field'), $fieldSelect, true, array( + 'style' => 'min-width:250px', + 'class' => 'crm-select2 huge', + 'placeholder' => E::ts('- select -'), + )); + if (isset($field['configuration'])) { + $configuration = $field['configuration']; + $defaults = array(); + if (isset($configuration['field'])) { + $defaults['field'] = $configuration['field']; + } + if (isset($configuration['fallback_field'])) { + $defaults['fallback_field'] = $configuration['fallback_field']; + } + $form->setDefaults($defaults); + } + } + + /** + * 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/FallbackFieldOutputHandler.tpl"; + } + + + /** + * Process the submitted values and create a configuration array + * + * @param $submittedValues + * @return array + */ + public function processConfiguration($submittedValues) { + $configuration['field'] = $submittedValues['field']; + $configuration['fallback_field'] = $submittedValues['fallback_field']; + return $configuration; + } + + protected function getFieldOutputHandlers(int $dataProcessorId) { + $return = []; + $dataProcessor = civicrm_api3('DataProcessor', 'getsingle', array('id' => $dataProcessorId)); + $dataProcessorClass = \CRM_Dataprocessor_BAO_DataProcessor::dataProcessorToClass($dataProcessor); + $outputFieldHandlers = $dataProcessorClass->getDataFlow()->getOutputFieldHandlers(); + foreach ($outputFieldHandlers as $outputFieldHandler) { + if ($outputFieldHandler->getOutputFieldSpecification()->alias != $this->getOutputFieldSpecification()->alias) { + $return[$outputFieldHandler->getOutputFieldSpecification()->alias] = $outputFieldHandler->getOutputFieldSpecification()->title; + } + } + return $return; + } + +} diff --git a/Civi/DataProcessor/FieldOutputHandler/FieldOutput.php b/Civi/DataProcessor/FieldOutputHandler/FieldOutput.php index ca22747f..0db5012a 100644 --- a/Civi/DataProcessor/FieldOutputHandler/FieldOutput.php +++ b/Civi/DataProcessor/FieldOutputHandler/FieldOutput.php @@ -12,9 +12,19 @@ class FieldOutput { public $formattedValue; + protected $isEmpty = null; + public function __construct($rawValue=null) { $this->rawValue = $rawValue; $this->formattedValue = $rawValue; } -} \ No newline at end of file + public function isEmpty(): bool { + return $this->rawValue === NULL || $this->rawValue === ''; + } + + public function overrideIsEmpty(bool $isEmpty): void { + $this->isEmpty = $isEmpty; + } + +} diff --git a/templates/CRM/Dataprocessor/Form/Field/Configuration/FallbackFieldOutputHandler.tpl b/templates/CRM/Dataprocessor/Form/Field/Configuration/FallbackFieldOutputHandler.tpl new file mode 100644 index 00000000..e2c9132b --- /dev/null +++ b/templates/CRM/Dataprocessor/Form/Field/Configuration/FallbackFieldOutputHandler.tpl @@ -0,0 +1,12 @@ +{crmScope extensionKey='dataprocessor'} + <div class="crm-section"> + <div class="label">{$form.field.label}</div> + <div class="content">{$form.field.html}</div> + <div class="clear"></div> + </div> + <div class="crm-section"> + <div class="label">{$form.fallback_field.label}</div> + <div class="content">{$form.fallback_field.html}</div> + <div class="clear"></div> + </div> +{/crmScope} -- GitLab