diff --git a/Civi/DataProcessor/Factory.php b/Civi/DataProcessor/Factory.php index b0018375af05c3f3d300d470f68bd8b9ca6c6725..d71aee2d54e9bf2f2826443fd8c9e986165fea49 100644 --- a/Civi/DataProcessor/Factory.php +++ b/Civi/DataProcessor/Factory.php @@ -197,6 +197,7 @@ class Factory { $this->addOutputHandler('number', new Definition('Civi\DataProcessor\FieldOutputHandler\NumberFieldOutputHandler'), E::ts('Formatted Number field value')); $this->addOutputHandler('date', new Definition('Civi\DataProcessor\FieldOutputHandler\DateFieldOutputHandler'), E::ts('Date field value')); $this->addOutputHandler('date_month_segment', new Definition('Civi\DataProcessor\FieldOutputHandler\DateMonthSegmentFieldOutputHandler'), E::ts('Segment text based on a date field (Per Month)')); + $this->addOutputHandler('date_range', new Definition('Civi\DataProcessor\FieldOutputHandler\DateRangeFieldOutputHandler'), E::ts('Date range value (with additional end date)')); $this->addOutputHandler('age', new Definition('Civi\DataProcessor\FieldOutputHandler\AgeFieldOutputHandler'), E::ts('Age field value')); $this->addOutputHandler('contact_has_relationship', new Definition('Civi\DataProcessor\FieldOutputHandler\ContactHasRelationshipFieldOutputHandler'), E::ts('Contact has relationship')); $this->addOutputHandler('contact_link', new Definition('Civi\DataProcessor\FieldOutputHandler\ContactLinkFieldOutputHandler'), E::ts('Link to view contact')); diff --git a/Civi/DataProcessor/FieldOutputHandler/DateRangeFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/DateRangeFieldOutputHandler.php new file mode 100644 index 0000000000000000000000000000000000000000..f27fbb8cc801c669668dd1df385fc3bcddb52d3d --- /dev/null +++ b/Civi/DataProcessor/FieldOutputHandler/DateRangeFieldOutputHandler.php @@ -0,0 +1,193 @@ +<?php +/** + * @author Gerhard Weber <gerhard.weber@civiservice.de> + * @license AGPL-3.0 + */ + +namespace Civi\DataProcessor\FieldOutputHandler; + +use CRM_Dataprocessor_ExtensionUtil as E; +use Civi\DataProcessor\Source\SourceInterface; +use Civi\DataProcessor\DataSpecification\FieldSpecification; + +class DateRangeFieldOutputHandler extends DateFieldOutputHandler { + + /** + * Field for end date. + * + * @var FieldSpecification + */ + protected $dateEnd; + + /** + * Source for end date. + * + * @var SourceInterface + */ + protected $dataSourceDateEnd; + + /** + * Additional optional format used if time is not set (default time '00:00:00'). + */ + protected $formatDateOnly = NULL; + + /** + * Separates start and end date. + */ + protected $separator; + + /** + * Initialize the processor + * + * @param String $alias + * @param String $title + * @param array $configuration + */ + public function initialize($alias, $title, $configuration) { + parent::initialize($alias, $title, $configuration); + + [$this->dataSourceDateEnd, $this->dateEnd] = $this->initializeField($configuration['date_end'], $configuration['date_end_datasource'], $alias . '_date_end'); + $this->formatDateOnly = isset($configuration['format_date_only']) ? $configuration['format_date_only'] : false; + $this->separator = isset($configuration['separator']) ? $configuration['separator'] : false; + } + + /** + * 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); + + // @nice-to-have get directly from form's first datasource? + $fieldSelect = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFieldsInDataSources($field['data_processor_id'], + array($this, 'isFieldValid') + ); + $form->add('select', 'date_end', E::ts('End date'), $fieldSelect, true, array( + 'style' => 'min-width:250px', + 'class' => 'crm-select2 huge data-processor-field-for-name', + 'placeholder' => E::ts('- select -'), + )); + + $form->add('text', 'format_date_only', E::ts('Format date only'), array( + 'style' => 'min-width:250px', + 'class' => 'huge', + )); + + $form->add('text', 'separator', E::ts('Separator'), + array('class' => 'medium'), + true + // @nice-to-have add description here (only possible in .tpl file?) + ); + + if (isset($field['configuration'])) { + $configuration = $field['configuration']; + $defaults = array(); + + if (isset($configuration['date_end']) && isset($configuration['date_end_datasource'])) { + $defaults['date_end'] = \CRM_Dataprocessor_Utils_DataSourceFields::getSelectedFieldValue($field['data_processor_id'], + $configuration['date_end_datasource'], $configuration['date_end']); + } + + foreach (array('separator', 'format_date_only') as $key) { + if (isset($configuration[$key])) { + $defaults[$key] = $configuration[$key]; + } + } + + $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/DateRangeFieldOutputHandler.tpl"; + } + + /** + * Process the submitted values and create a configuration array + * + * @param $submittedValues + * @return array + */ + public function processConfiguration($submittedValues) { + $configuration = parent::processConfiguration($submittedValues); + + [$datasource, $field] = explode('::', $submittedValues['date_end'], 2); + $configuration['date_end'] = $field; + $configuration['date_end_datasource'] = $datasource; + + foreach (array('separator', 'format_date_only') as $key) { + $configuration[$key] = isset($submittedValues[$key]) ? $submittedValues[$key] : false; + } + + return $configuration; + } + + /** + * Returns the formatted value + * + * @param $rawRecord + * @param $formattedRecord + * + * @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput + */ + public function formatField($rawRecord, $formattedRecord) { + $output = new FieldOutput($rawRecord[$this->inputFieldSpec->alias]); + $rawValue = $rawRecord[$this->inputFieldSpec->alias]; + if (($this->format || $this->formatDateOnly) && $rawValue) { + $output->formattedValue = $this->formatHelper($rawValue); + } + + $output2 = new FieldOutput($rawRecord[$this->dateEnd->alias]); + $rawValue2 = $rawRecord[$this->dateEnd->alias]; + if ($rawValue2) { + if ($this->format || $this->formatDateOnly) { + $output2->formattedValue = $this->formatHelper($rawValue2); + } + if ($this->separator) { + $output->formattedValue .= $this->separator; + } + $output->formattedValue .= $output2->formattedValue; + } + + return $output; + } + + /** + * Format raw date value. + * + * @param $raw_value + * Raw date value + * + * @return string + * Date string formatted according to configured format. + * If formatDateOnly is set it is used for default time (00:00:00). + * + * @throws \Exception + */ + protected function formatHelper($raw_value) { + $date = new \DateTime($raw_value); + if ($this->formatDateOnly && str_ends_with($raw_value, ' 00:00:00')) { + $format = $this->formatDateOnly; + } + else { + $format = $this->format; + } + + if (is_null($format)) { + return NULL; + } + + return $date->format($format); + } + +} diff --git a/templates/CRM/Dataprocessor/Form/Field/Configuration/DateRangeFieldOutputHandler.tpl b/templates/CRM/Dataprocessor/Form/Field/Configuration/DateRangeFieldOutputHandler.tpl new file mode 100644 index 0000000000000000000000000000000000000000..b289600bcb66ff968107609596fba2bbba65e4c2 --- /dev/null +++ b/templates/CRM/Dataprocessor/Form/Field/Configuration/DateRangeFieldOutputHandler.tpl @@ -0,0 +1,32 @@ +{crmScope extensionKey='dataprocessor'} + {include file="CRM/Dataprocessor/Form/Field/Configuration/DateFieldOutputHandler.tpl"} + + <hr > + <div class="crm-section"> + <div class="label">{$form.date_end.label}</div> + <div class="content">{$form.date_end.html}</div> + <div class="clear"></div> + </div> + <div class="crm-section"> + <div class="label">{$form.separator.label}</div> + <div class="content"> + {$form.separator.html} + <p class="description"> + {ts}The string to separate the start and end date (including spaces).{/ts} + </p> + </div> + <div class="clear"></div> + </div> + <hr > + <div class="crm-section"> + <div class="label">{$form.format_date_only.label}</div> + <div class="content"> + {$form.format_date_only.html} + <p class="description"> + {ts}Used if time is not set / default time <em>00:00:00</em>.{/ts}<br /> + {ts 1='https://www.php.net/manual/en/datetime.format.php#refsect1-datetime.format-parameters'}See <a href="%1" target="_blank">DateTime format on php.net</a> for help.{/ts} + </p> + </div> + <div class="clear"></div> + </div> +{/crmScope}