Commit bf791c78 authored by jaapjansma's avatar jaapjansma
Browse files

Added token output for participant

parent 36128846
......@@ -26,6 +26,9 @@ class CompilerPass implements CompilerPassInterface {
$factoryDefinition->addMethodCall('addOutput', array(
'household_token', 'Civi\DataProcessorTokenOutput\Output\HouseholdToken', E::ts('Household Tokens')
));
$factoryDefinition->addMethodCall('addOutput', array(
'participant_token', 'Civi\DataProcessorTokenOutput\Output\ParticipantToken', E::ts('Participants Tokens')
));
}
......
<?php
/**
* @author Jaap Jansma <jaap.jansma@civicoop.org>
* @license AGPL-3.0
*/
namespace Civi\DataProcessorTokenOutput\Output;
use Civi\DataProcessor\DataFlow\EndOfFlowException;
use Civi\DataProcessor\DataFlow\Sort\SortCompareFactory;
use Civi\DataProcessor\DataFlow\SqlDataFlow;
use Civi\DataProcessor\Exception\DataSourceNotFoundException;
use Civi\DataProcessor\Exception\FieldNotFoundException;
use Civi\DataProcessor\Output\OutputInterface;
use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
use CRM_DataprocessorTokenOutput_ExtensionUtil as E;
class ParticipantToken implements OutputInterface, TokenOutput {
/**
* Returns true when this output has additional configuration
*
* @return bool
*/
public function hasConfiguration() {
return true;
}
/**
* When this output type has additional configuration you can add
* the fields on the form with this function.
*
* @param \CRM_Core_Form $form
* @param array $output
*/
public function buildConfigurationForm(\CRM_Core_Form $form, $output = []) {
$fieldSelect = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFilterFieldsInDataSources($output['data_processor_id']);
$dataProcessor = civicrm_api3('DataProcessor', 'getsingle', array('id' => $output['data_processor_id']));
$dataProcessorClass = \CRM_Dataprocessor_BAO_DataProcessor::dataProcessorToClass($dataProcessor);
$fields = array();
$sortFields = array();
foreach($dataProcessorClass->getDataFlow()->getOutputFieldHandlers() as $outputFieldHandler) {
$field = $outputFieldHandler->getOutputFieldSpecification();
$fields[$field->alias] = $field->title;
$sortFields['asc_'.$field->alias] = E::ts('Ascending sort %1', array(1=>$field->title));
$sortFields['desc_'.$field->alias] = E::ts('Descending sort %1', array(1=>$field->title));
}
$form->add('select', 'participant_id_field', E::ts('Participant ID field'), $fieldSelect, true, array(
'style' => 'min-width:250px',
'class' => 'crm-select2 huge',
'placeholder' => E::ts('- select -'),
));
$form->add('select', 'hidden_fields', E::ts('Hidden fields'), $fields, false, array(
'style' => 'min-width:250px',
'class' => 'crm-select2 huge',
'multiple' => true,
'placeholder' => E::ts('- select -'),
));
$form->add('select', 'sortfield', E::ts('Sort'), $sortFields, false, array(
'style' => 'min-width:250px',
'class' => 'crm-select2 huge',
'multiple' => false,
'placeholder' => E::ts('- select -'),
));
$defaults = array();
if ($output) {
if (isset($output['configuration']) && is_array($output['configuration'])) {
if (isset($output['configuration']['help_text'])) {
$defaults['help_text'] = $output['configuration']['help_text'];
}
if (isset($output['configuration']['participant_id_field'])) {
$defaults['participant_id_field'] = $output['configuration']['participant_id_field'];
}
if (isset($output['configuration']['hidden_fields'])) {
$defaults['hidden_fields'] = $output['configuration']['hidden_fields'];
}
if (isset($output['configuration']['sort'])) {
$defaults['sortfield'] = $output['configuration']['sort'];
}
}
}
if (!isset($defaults['default_limit'])) {
$sortFieldNames = array_keys($sortFields);
$defaults['sort'] = reset($sortFieldNames); // Get the first field.
}
$form->setDefaults($defaults);
}
/**
* When this output type has configuration specify the template file name
* for the configuration form.
*
* @return false|string
*/
public function getConfigurationTemplateFileName() {
return "CRM/DataprocessorTokenOutput/Form/ParticipantTokenConfiguration.tpl";
}
/**
* Process the submitted values and create a configuration array
*
* @param $submittedValues
* @param array $output
*
* @return array $output
*/
public function processConfiguration($submittedValues, &$output) {
$configuration['participant_id_field'] = $submittedValues['participant_id_field'];
$configuration['hidden_fields'] = $submittedValues['hidden_fields'];
$configuration['sort'] = $submittedValues['sortfield'];
return $configuration;
}
/**
* This function is called prior to removing an output
*
* @param array $output
*
* @return void
*/
public function deleteOutput($output) {
// Do nothing.
}
/**
* Sets the tokens for this output.
*
* @param $tokens
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param String $title
* @param String $name
* @param array $configuration
*/
public function tokens(&$tokens, AbstractProcessorType $dataProcessorClass, $title, $name, $configuration) {
// Retrieve the tokens for this output.
$hiddenFields = array();
if (isset($configuration['hidden_fields']) && is_array($configuration['hidden_fields'])) {
$hiddenFields = $configuration['hidden_fields'];
}
try {
$availableFields = $dataProcessorClass->getDataFlow()->getOutputFieldHandlers();
} catch (\Exception $e) {
return; // No fields available.
}
foreach($availableFields as $outputFieldHandler) {
$field = $outputFieldHandler->getOutputFieldSpecification();
if (!in_array($field->alias, $hiddenFields)) {
$tokens[$name][$name.'.'.$field->alias] = $field->title.' :: '.$title;
}
}
}
/**
* Sets the tokens for this output.
*
* @param int $contact_id
* @param $values
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param String $name
* @param array $configuration
*/
public function tokenValues($contact_id, &$values, AbstractProcessorType $dataProcessorClass, $name, $configuration) {
// Retrieve the tokens for this output.
$hiddenFields = array();
if (isset($configuration['hidden_fields']) && is_array($configuration['hidden_fields'])) {
$hiddenFields = $configuration['hidden_fields'];
}
try {
$availableFields = $dataProcessorClass->getDataFlow()->getOutputFieldHandlers();
} catch (\Exception $e) {
return; // No fields available.
}
$participantIdToUse = $this->getParticipantIdForToken($contact_id, $values, $configuration);
if (!$participantIdToUse) {
return;
}
$this->initializeDataProcessorClass($participantIdToUse, $dataProcessorClass, $configuration);
try {
$record = $dataProcessorClass->getDataFlow()->nextRecord();
} catch (EndOfFlowException $e) {
return; // Do nothing there is no data.
}
foreach($availableFields as $outputFieldHandler) {
$field = $outputFieldHandler->getOutputFieldSpecification();
if (!in_array($field->alias, $hiddenFields)) {
$values[$name.'.'.$field->alias] = $record[$field->alias]->formattedValue;
}
}
}
protected function initializeDataProcessorClass($participant_id, AbstractProcessorType $dataProcessorClass, $configuration) {
list($datasource_name, $field_name) = explode('::', $configuration['participant_id_field'], 2);
$dataSource = $dataProcessorClass->getDataSourceByName($datasource_name);
if (!$dataSource) {
throw new DataSourceNotFoundException(E::ts("Requires data source '%1' which could not be found. Did you rename or deleted the data source?", array(1=>$datasource_name)));
}
$fieldSpecification = $dataSource->getAvailableFilterFields()->getFieldSpecificationByAlias($field_name);
if (!$fieldSpecification) {
throw new FieldNotFoundException(E::ts("Requires a field with the name '%1' in the data source '%2'. Did you change the data source type?", array(
1 => $field_name,
2 => $datasource_name
)));
}
$dataFlow = $dataSource->ensureField($fieldSpecification);
if ($dataFlow && $dataFlow instanceof SqlDataFlow) {
$whereClause = new SqlDataFlow\SimpleWhereClause($dataFlow->getName(), $fieldSpecification->name, '=', $participant_id, $fieldSpecification->type);
$dataFlow->addWhereClause($whereClause);
}
$sortField = substr($configuration['sort'], 5);
$direction = 'desc';
if (stripos($configuration['sort'], 'asc_') === 0) {
$sortField = substr($configuration['sort'], 4);
$direction = 'asc';
}
$dataProcessorClass->getDataFlow()->addSort($sortField, $direction);
$dataProcessorClass->getDataFlow()->setLimit(1);
$dataProcessorClass->getDataFlow()->setOffset(0);
}
/**
* Function to set a different contact ID to be used in the data processor.
* This function is here so child classes can override it.
*
* @param $contactId
* @param $configuration
*
* @return mixed
*/
protected function getParticipantIdForToken($contactId, $values, $configuration) {
if (isset($values['extra_data']['participant']['id'])) {
// Coming from CiviRules
return $values['extra_data']['participant']['id'];
}
return false;
}
}
......@@ -16,7 +16,7 @@ use Civi\DataProcessor\Output\OutputInterface;
use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
use CRM_DataprocessorTokenOutput_ExtensionUtil as E;
class Token implements OutputInterface {
class Token implements OutputInterface, TokenOutput {
/**
* Returns true when this output has additional configuration
......
<?php
/**
* @author Jaap Jansma <jaap.jansma@civicoop.org>
* @license AGPL-3.0
*/
namespace Civi\DataProcessorTokenOutput\Output;
use Civi\DataProcessor\DataFlow\EndOfFlowException;
use Civi\DataProcessor\DataFlow\Sort\SortCompareFactory;
use Civi\DataProcessor\DataFlow\SqlDataFlow;
use Civi\DataProcessor\Exception\DataSourceNotFoundException;
use Civi\DataProcessor\Exception\FieldNotFoundException;
use Civi\DataProcessor\Output\OutputInterface;
use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
use CRM_DataprocessorTokenOutput_ExtensionUtil as E;
interface TokenOutput {
/**
* Sets the tokens for this output.
*
* @param $tokens
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param String $title
* @param String $name
* @param array $configuration
*/
public function tokens(&$tokens, AbstractProcessorType $dataProcessorClass, $title, $name, $configuration);
/**
* Sets the tokens for this output.
*
* @param int $contact_id
* @param $values
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param String $name
* @param array $configuration
*/
public function tokenValues($contact_id, &$values, AbstractProcessorType $dataProcessorClass, $name, $configuration);
}
......@@ -31,7 +31,7 @@ function dataprocessor_token_output_civicrm_tokens(&$tokens) {
$dao = _dataprocessor_token_output_get_dao();
while($dao->fetch()) {
$outputClass = $factory->getOutputByName($dao->type);
if (!$outputClass instanceof Civi\DataprocessorTokenOutput\Output\Token) {
if (!$outputClass instanceof Civi\DataprocessorTokenOutput\Output\TokenOutput) {
continue;
}
$dataprocessor = civicrm_api3('DataProcessor', 'getsingle', ['id' => $dao->data_processor_id]);
......@@ -59,7 +59,7 @@ function dataprocessor_token_output_civicrm_tokenValues(&$values, $cids, $job =
$dao = _dataprocessor_token_output_get_dao($tokens);
while($dao->fetch()) {
$outputClass = $factory->getOutputByName($dao->type);
if (!$outputClass instanceof Civi\DataprocessorTokenOutput\Output\Token) {
if (!$outputClass instanceof Civi\DataprocessorTokenOutput\Output\TokenOutput) {
continue;
}
$dataprocessor = civicrm_api3('DataProcessor', 'getsingle', ['id' => $dao->data_processor_id]);
......@@ -82,7 +82,7 @@ function _dataprocessor_token_output_get_dao($names=null) {
$sql = "SELECT o.*, d.name as data_processor_name, o.configuration
FROM civicrm_data_processor d
INNER JOIN civicrm_data_processor_output o ON d.id = o.data_processor_id
WHERE d.is_active = 1 AND (o.type = 'token' OR o.type = 'household_token')";
WHERE d.is_active = 1 AND (o.type = 'token' OR o.type = 'household_token' OR o.type = 'participant_token')";
if (is_array($names) && count($names)) {
$nameClauses = array();
foreach($names as $name => $tokens) {
......
......@@ -13,8 +13,8 @@
<url desc="Documentation">https://lab.civicrm.org/extensions/dataprocessor-token-output/blob/master/README.md</url>
<url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
</urls>
<releaseDate>2019-11-27</releaseDate>
<version>1.0</version>
<releaseDate>2020-04-29</releaseDate>
<version>1.1</version>
<develStage>stable</develStage>
<compatibility>
<ver>5.13</ver>
......
{crmScope extensionKey='dataprocessor-token-output'}
<div class="help">
{ts}At the moment the participant token only works when an e-mail is send from CiviRules.{/ts}
</div>
<div class="crm-section">
<div class="label">{$form.participant_id_field.label}</div>
<div class="content">{$form.participant_id_field.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section">
<div class="label">{$form.hidden_fields.label}</div>
<div class="content">{$form.hidden_fields.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section">
<div class="label">{$form.sortfield.label}</div>
<div class="content">{$form.sortfield.html}</div>
<div class="clear"></div>
</div>
{/crmScope}
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