Commit 1f9393e3 authored by jaapjansma's avatar jaapjansma
Browse files

Implemented token processor handling #1

parent db085098
......@@ -8,9 +8,11 @@ namespace Civi\DataProcessorTokenOutput\Output;
use Civi\DataProcessor\DataFlow\CombinedDataFlow\CombinedSqlDataFlow;
use Civi\DataProcessor\DataFlow\EndOfFlowException;
use Civi\DataProcessor\DataFlow\InvalidFlowException;
use Civi\DataProcessor\DataFlow\Sort\SortCompareFactory;
use Civi\DataProcessor\DataFlow\SqlDataFlow;
use Civi\DataProcessor\DataFlow\SqlTableDataFlow;
use Civi\DataProcessor\Exception\DataFlowException;
use Civi\DataProcessor\Exception\DataSourceNotFoundException;
use Civi\DataProcessor\Exception\FieldNotFoundException;
use Civi\DataProcessor\Output\OutputInterface;
......@@ -27,17 +29,118 @@ abstract class AbstractToken implements OutputInterface, TokenOutput {
*/
abstract protected function getIdFieldTitle();
/**
* @return string
*/
abstract protected function getTokenProcessorIdFieldName();
/**
* Checks whether the output is available for this evaluateTokenEvent.
*
* @param \Civi\Token\Event\TokenValueEvent $evaluateTokenEvent
*
* @return bool
*/
public function availableForEvaluateToken($evaluateTokenEvent) {
$ids = $evaluateTokenEvent->getTokenProcessor()->getContextValues($this->getTokenProcessorIdFieldName());
if (count($ids)) {
return TRUE;
}
return FALSE;
}
/**
* 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 int $contactId
* @param array $values
* @param array $configuration
* @param \Civi\Token\TokenRow $tokenRow
* @param $configuration
*
* @return int|null
*/
abstract protected function getIdForToken($contactId, $values, $configuration);
protected function getIdForTokenFromTokenRow($tokenRow, $configuration) {
if (isset($tokenRow->context[$this->getTokenProcessorIdFieldName()])) {
return $tokenRow->context[$this->getTokenProcessorIdFieldName()];
}
return null;
}
/**
* Return all available fields for the tokens.
*
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param $configuration
*
* @return array|void
*/
protected function getAvailableFields(AbstractProcessorType $dataProcessorClass, $configuration) {
$hiddenFields = array();
if (isset($configuration['hidden_fields']) && is_array($configuration['hidden_fields'])) {
$hiddenFields = $configuration['hidden_fields'];
}
try {
$allFields = $dataProcessorClass->getDataFlow()->getOutputFieldHandlers();
} catch (\Exception $e) {
return; // No fields available.
}
$availableFields = [];
foreach ($allFields as $outputFieldHandler) {
$field = $outputFieldHandler->getOutputFieldSpecification();
if (!in_array($field->alias, $hiddenFields)) {
$availableFields[] = $field;
}
}
return $availableFields;
}
/**
* Evaluate tokens
*
* @param \Civi\Token\Event\TokenValueEvent $evaluateTokenEvent
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param String $name
* @param array $configuration
*/
public function evaluateTokens($evaluateTokenEvent, AbstractProcessorType $dataProcessorClass, $name, $configuration) {
$availableFields = $this->getAvailableFields($dataProcessorClass, $configuration);
foreach($evaluateTokenEvent->getRows() as $row) {
$idToUse = $this->getIdForTokenFromTokenRow($row, $configuration);
if (!$idToUse) {
return;
}
try {
$this->initializeDataProcessorClass($idToUse, $dataProcessorClass, $configuration);
} catch (InvalidFlowException|DataSourceNotFoundException|FieldNotFoundException $e) {
return;
}
$record = false;
$allDataSetting = isset($configuration['all_data_setting']) ? $configuration['all_data_setting'] : false;
if ($allDataSetting) {
try {
$allRecords = $dataProcessorClass->getDataFlow()->allRecords();
if ($allRecords) {
$this->processAllDataForTokenProcessor($allDataSetting, $allRecords, $row, $availableFields, $name, $configuration);
$record = reset($allRecords);
}
} catch (EndOfFlowException|InvalidFlowException|DataFlowException $e) {
}
} else {
try {
$record = $dataProcessorClass->getDataFlow()->nextRecord();
} catch (EndOfFlowException|InvalidFlowException|DataFlowException $e) {
}
}
if ($record) {
try {
$this->processForTokenProcessor($record, $row, $availableFields, $name, $configuration);
} catch (EndOfFlowException|InvalidFlowException|DataFlowException $e) {
}
}
}
}
/**
* @return string
......@@ -256,46 +359,40 @@ abstract class AbstractToken implements OutputInterface, TokenOutput {
* @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 {
$allFields = $dataProcessorClass->getDataFlow()->getOutputFieldHandlers();
} catch (\Exception $e) {
return; // No fields available.
}
$availableFields = [];
foreach ($allFields as $outputFieldHandler) {
$field = $outputFieldHandler->getOutputFieldSpecification();
if (!in_array($field->alias, $hiddenFields)) {
$availableFields[] = $field;
}
}
$availableFields = $this->getAvailableFields($dataProcessorClass, $configuration);
$idToUse = $this->getIdForToken($contact_id, $values, $configuration);
if (!$idToUse) {
return;
}
$this->initializeDataProcessorClass($idToUse, $dataProcessorClass, $configuration);
try {
$this->initializeDataProcessorClass($idToUse, $dataProcessorClass, $configuration);
} catch (InvalidFlowException|FieldNotFoundException|DataSourceNotFoundException $e) {
return;
}
$record = false;
$allDataSetting = isset($configuration['all_data_setting']) ? $configuration['all_data_setting'] : false;
if ($allDataSetting) {
$allRecords = $dataProcessorClass->getDataFlow()->allRecords();
if ($allRecords) {
$this->processAllData($allDataSetting, $allRecords, $values, $availableFields, $name, $configuration);
$record = reset($allRecords);
try {
$allRecords = $dataProcessorClass->getDataFlow()->allRecords();
if ($allRecords) {
$this->processAllData($allDataSetting, $allRecords, $values, $availableFields, $name, $configuration);
$record = reset($allRecords);
}
} catch (EndOfFlowException|InvalidFlowException|DataFlowException $e) {
}
} else {
try {
$record = $dataProcessorClass->getDataFlow()->nextRecord();
} catch (EndOfFlowException $e) {
} catch (EndOfFlowException|InvalidFlowException|DataFlowException $e) {
}
}
if ($record) {
try {
$this->process($record, $values, $availableFields, $name, $configuration);
} catch (EndOfFlowException|InvalidFlowException|DataFlowException $e) {
}
}
$this->process($record, $values, $availableFields, $name, $configuration);
}
/**
......@@ -317,6 +414,25 @@ abstract class AbstractToken implements OutputInterface, TokenOutput {
}
}
/**
* Convert the data from the data processor to tokens.
*
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param \Civi\Token\TokenRow $tokenRow
* @param \Civi\DataProcessor\DataSpecification\FieldSpecification[] $availableFields
* @param string $name
* @param array $configuration
*
* @throws \Civi\DataProcessor\DataFlow\InvalidFlowException
*/
protected function processForTokenProcessor($record, &$tokenRow, $availableFields, $name, $configuration) {
$pre_text = isset($configuration['pre_text']) ? html_entity_decode($configuration['pre_text']) : '';
$post_text = isset($configuration['post_text']) ? html_entity_decode($configuration['post_text']) : '';
foreach($availableFields as $field) {
$tokenRow->format('text/html')->tokens($name, $field->alias, $pre_text.$record[$field->alias]->formattedValue . $post_text);
}
}
/**
* Convert the data from the data processor to tokens.
*
......@@ -329,7 +445,7 @@ abstract class AbstractToken implements OutputInterface, TokenOutput {
*
* @throws \Civi\DataProcessor\DataFlow\InvalidFlowException
*/
protected function processAllData($allDataSetting, $records, &$values, $availableFields, $name, $configuration) {
protected function processAllData($allDataSetting, $records, $values, $availableFields, $name, $configuration) {
$pre_text = isset($configuration['pre_text']) ? html_entity_decode($configuration['pre_text']) : '';
$post_text = isset($configuration['post_text']) ? html_entity_decode($configuration['post_text']) : '';
$allDataOptions = $this->allDataOptions();
......@@ -338,6 +454,27 @@ abstract class AbstractToken implements OutputInterface, TokenOutput {
}
}
/**
* Convert the data from the data processor to tokens.
*
* @param string $allDataSetting
* @param array $records
* @param \Civi\Token\TokenRow $tokenRow
* @param \Civi\DataProcessor\DataSpecification\FieldSpecification[] $availableFields
* @param string $name
* @param array $configuration
*
* @throws \Civi\DataProcessor\DataFlow\InvalidFlowException
*/
protected function processAllDataForTokenProcessor($allDataSetting, $records, &$tokenRow, $availableFields, $name, $configuration) {
$pre_text = isset($configuration['pre_text']) ? html_entity_decode($configuration['pre_text']) : '';
$post_text = isset($configuration['post_text']) ? html_entity_decode($configuration['post_text']) : '';
$allDataOptions = $this->allDataOptions();
if (isset($allDataOptions[$allDataSetting]) && isset($allDataOptions[$allDataSetting]['callback'])) {
$tokenRow->format('text/html')->tokens($name, $allDataOptions[$allDataSetting]['token_name'], $pre_text.call_user_func($allDataOptions[$allDataSetting]['callback'], $records, $availableFields).$post_text);
}
}
/**
* Initialize the data processor.
*
......
......@@ -19,6 +19,13 @@ class CaseToken extends AbstractToken {
*/
private static $_caseIds = null;
/**
* @return string
*/
protected function getTokenProcessorIdFieldName() {
return 'caseId';
}
/**
* Function to set a different contact ID to be used in the data processor.
* This function is here so child classes can override it.
......
......@@ -34,6 +34,13 @@ class ContactToken extends AbstractToken {
return 'contact_id_field';
}
/**
* @return string
*/
protected function getTokenProcessorIdFieldName() {
return 'contactId';
}
/**
* Function to set a different contact ID to be used in the data processor.
* This function is here so child classes can override it.
......
......@@ -27,6 +27,13 @@ class EventToken extends AbstractToken {
*/
private static $_eventIds = null;
/**
* @return string
*/
protected function getTokenProcessorIdFieldName() {
return 'eventId';
}
/**
* Function to set a different contact ID to be used in the data processor.
* This function is here so child classes can override it.
......
......@@ -34,6 +34,13 @@ class HouseholdToken extends AbstractToken {
return 'contact_id_field';
}
/**
* @return string
*/
protected function getTokenProcessorIdFieldName() {
return 'contactId';
}
/**
* When this output type has additional configuration you can add
* the fields on the form with this function.
......@@ -130,6 +137,35 @@ class HouseholdToken extends AbstractToken {
return $householdContactId;
}
/**
* 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 \Civi\Token\TokenRow $tokenRow
* @param $configuration
*
* @return int|null
*/
protected function getIdForTokenFromTokenRow($tokenRow, $configuration) {
if (isset($tokenRow->context[$this->getTokenProcessorIdFieldName()])) {
$contactId = $tokenRow->context[$this->getTokenProcessorIdFieldName()];
$householdContactId = FALSE;
try {
$contact = civicrm_api3('Contact', 'getsingle', ['id' => $contactId]);
} catch (\CiviCRM_API3_Exception $e) {
return null;
}
if ($contact['contact_type'] == 'Individual') {
$householdContactId = $this->retrieveHousehold($contactId, $configuration['relationship_types']);
}
elseif ($contact['contact_type'] == 'Household') {
$householdContactId = $contactId;
}
return $householdContactId;
}
return null;
}
protected function retrieveHousehold($contact_id, $relationship_types) {
$sql['a_b'] = "SELECT c.id
FROM civicrm_contact c
......
......@@ -27,6 +27,13 @@ class ParticipantToken extends AbstractToken {
*/
private static $_participantIds = null;
/**
* @return string
*/
protected function getTokenProcessorIdFieldName() {
return 'participantId';
}
/**
* Function to set a different contact ID to be used in the data processor.
* This function is here so child classes can override it.
......
......@@ -40,4 +40,22 @@ interface TokenOutput {
*/
public function tokenValues($contact_id, &$values, AbstractProcessorType $dataProcessorClass, $name, $configuration);
/**
* Evaluate tokens
*
* @param \Civi\Token\Event\TokenValueEvent $evaluateTokenEvent
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $dataProcessorClass
* @param String $name
* @param array $configuration
*/
public function evaluateTokens($evaluateTokenEvent, AbstractProcessorType $dataProcessorClass, $name, $configuration);
/**
* Checks whether the output is available for this evaluateTokenEvent.
*
* @param \Civi\Token\Event\TokenValueEvent $evaluateTokenEvent
* @return bool
*/
public function availableForEvaluateToken($evaluateTokenEvent);
}
......@@ -11,6 +11,42 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
*/
function dataprocessor_token_output_civicrm_container(ContainerBuilder $container) {
$container->addCompilerPass(new Civi\DataProcessorTokenOutput\CompilerPass());
$container->findDefinition('dispatcher')->addMethodCall('addListener',
array('civi.token.eval', 'dataprocessor_token_output_evaluate_tokens')
);
}
/**
* @param \Civi\Token\Event\TokenValueEvent $event
*
* @return void
*/
function dataprocessor_token_output_evaluate_tokens($event) {
$factory = dataprocessor_get_factory();
// Check whether the factory exists. Usually just after
// installation the factory does not exists but then no
// outputs exists either. So we can safely return this function.
if (!$factory) {
return;
}
$dao = _dataprocessor_token_output_get_dao();
while($dao->fetch()) {
$outputClass = $factory->getOutputByName($dao->type);
if (!$outputClass instanceof Civi\DataprocessorTokenOutput\Output\TokenOutput) {
continue;
}
if (!$outputClass->availableForEvaluateToken($event)) {
continue;
}
// Find data processors for this output.
$dataprocessor = civicrm_api3('DataProcessor', 'getsingle', ['id' => $dao->data_processor_id]);
$configuration = json_decode($dao->configuration, true);
$dataProcessorClass = CRM_Dataprocessor_BAO_DataProcessor::dataProcessorToClass($dataprocessor);
$outputClass->evaluateTokens($event, $dataProcessorClass, $dataprocessor['name'], $configuration);
}
}
/**
......
......@@ -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>2021-11-24</releaseDate>
<version>1.9</version>
<releaseDate>2022-08-03</releaseDate>
<version>1.10</version>
<develStage>stable</develStage>
<compatibility>
<ver>5.13</ver>
......
Supports Markdown
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