Commit e4013590 authored by jaapjansma's avatar jaapjansma

Added field to display relationships

parent 20bef140
......@@ -21,6 +21,7 @@
* Added a Date field.
* Added function to clone a data processor.
* Added Case ID field on the activity source.
* Added field to display relationships.
# Version 1.0.7
......
......@@ -290,7 +290,7 @@ abstract class CRM_DataprocessorSearch_Form_AbstractSearch extends CRM_Dataproce
if ($value instanceof Markupable) {
$row['record'][$column] = $value->getMarkupOut();
} elseif ($value instanceof FieldOutput) {
$row['record'][$column] = $value->formattedValue;
$row['record'][$column] = htmlspecialchars($value->formattedValue);
}
}
......
......@@ -98,4 +98,4 @@ class SimpleNonRequiredJoin extends SimpleJoin {
}
}
\ No newline at end of file
}
......@@ -146,6 +146,7 @@ class Factory {
$this->addOutputHandler('contact_link', 'Civi\DataProcessor\FieldOutputHandler\ContactLinkFieldOutputHandler', E::ts('Link to view contact'));
$this->addOutputHandler('file_field', 'Civi\DataProcessor\FieldOutputHandler\FileFieldOutputHandler', E::ts('File download link'));
$this->addOutputHandler('option_label', 'Civi\DataProcessor\FieldOutputHandler\OptionFieldOutputHandler', E::ts('Option label'));
$this->addOutputHandler('relationships', 'Civi\DataProcessor\FieldOutputHandler\RelationshipsFieldOutputHandler', E::ts('Relationships'));
$this->addOutputHandler('case_roles', 'Civi\DataProcessor\FieldOutputHandler\CaseRolesFieldOutputHandler', E::ts('Case Roles'));
$this->addOutputHandler('groups_of_contact', 'Civi\DataProcessor\FieldOutputHandler\GroupsOfContactFieldOutputHandler', E::ts('Display the groups of a contact'));
$this->addOutputHandler('event_repeating_info', 'Civi\DataProcessor\FieldOutputHandler\EventRepeatingInfoFieldOutputHandler', E::ts('Display info about repeating event'));
......
......@@ -86,7 +86,10 @@ class ContactLinkFieldOutputHandler extends AbstractFieldOutputHandler implement
2=>$configuration['datasource'])
));
}
$this->contactIdField = $this->contactIdSource->getAvailableFields()->getFieldSpecificationByName($configuration['contact_id_field']);
$this->contactIdField = $this->contactIdSource->getAvailableFields()->getFieldSpecificationByAlias($configuration['contact_id_field']);
if (!$this->contactIdField) {
$this->contactIdField = $this->contactIdSource->getAvailableFields()->getFieldSpecificationByName($configuration['contact_id_field']);
}
if (!$this->contactIdField) {
throw new FieldNotFoundException(E::ts("Field %1 requires a field with the name '%2' in the data source '%3'. Did you change the data source type?", array(
1 => $title,
......@@ -103,7 +106,10 @@ class ContactLinkFieldOutputHandler extends AbstractFieldOutputHandler implement
2=>$configuration['contact_name_datasource'])
));
}
$this->contactNameField = $this->contactNameSource->getAvailableFields()->getFieldSpecificationByName($configuration['contact_name_field']);
$this->contactNameField = $this->contactNameSource->getAvailableFields()->getFieldSpecificationByAlias($configuration['contact_name_field']);
if (!$this->contactNameField) {
$this->contactNameField = $this->contactNameSource->getAvailableFields()->getFieldSpecificationByName($configuration['contact_name_field']);
}
if (!$this->contactNameField) {
throw new FieldNotFoundException(E::ts("Field %1 requires a field with the name '%2' in the data source '%3'. Did you change the data source type?", array(
1 => $title,
......
<?php
/**
* @author Jaap Jansma <jaap.jansma@civicoop.org>
* @license AGPL-3.0
*/
namespace Civi\DataProcessor\FieldOutputHandler;
use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
use CRM_Dataprocessor_ExtensionUtil as E;
use Civi\DataProcessor\Source\SourceInterface;
use Civi\DataProcessor\DataSpecification\FieldSpecification;
use Civi\DataProcessor\Exception\DataSourceNotFoundException;
use Civi\DataProcessor\Exception\FieldNotFoundException;
use Civi\DataProcessor\FieldOutputHandler\FieldOutput;
class RelationshipsFieldOutputHandler extends AbstractFieldOutputHandler {
/**
* @var \Civi\DataProcessor\Source\SourceInterface
*/
protected $dataSource;
/**
* @var SourceInterface
*/
protected $contactIdSource;
/**
* @var FieldSpecification
*/
protected $contactIdField;
/**
* @var FieldSpecification
*/
protected $outputFieldSpecification;
/**
* @var array
*/
protected $relationship_type_ids = array();
protected $show_label = true;
/**
* @return \Civi\DataProcessor\DataSpecification\FieldSpecification
*/
public function getOutputFieldSpecification() {
return $this->outputFieldSpecification;
}
/**
* Returns the data type of this field
*
* @return String
*/
protected function getType() {
return 'String';
}
/**
* 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->outputFieldSpecification = new FieldSpecification($alias, 'String', $title, null, $alias);
$this->contactIdSource = $this->dataProcessor->getDataSourceByName($configuration['datasource']);
if (!$this->contactIdSource) {
throw new DataSourceNotFoundException(E::ts("Field %1 requires data source '%2' which could not be found. Did you rename or deleted the data source?", array(1=>$title, 2=>$configuration['datasource'])));
}
$this->contactIdField = $this->contactIdSource->getAvailableFields()->getFieldSpecificationByAlias($configuration['field']);
if (!$this->contactIdField) {
$this->contactIdField = $this->contactIdSource->getAvailableFields()->getFieldSpecificationByName($configuration['field']);
}
if (!$this->contactIdField) {
throw new FieldNotFoundException(E::ts("Field %1 requires a field with the name '%2' in the data source '%3'. Did you change the data source type?", array(
1 => $title,
2 => $configuration['field'],
3 => $configuration['datasource']
)));
}
$this->contactIdSource->ensureFieldInSource($this->contactIdField);
$this->outputFieldSpecification = new FieldSpecification($this->contactIdField->name, 'String', $title, null, $alias);
if (isset($configuration['relationship_types']) && is_array($configuration['relationship_types'])) {
$this->relationship_type_ids = array();
foreach($configuration['relationship_types'] as $rel_type) {
$dir = substr($rel_type, 0, 3);
$rel_type_name = substr($rel_type, 4);
if ($dir == 'a_b') {
$rel_type_id = civicrm_api3('RelationshipType', 'getvalue', ['return' => 'id', 'name_a_b' => $rel_type_name]);
} else {
$rel_type_id = civicrm_api3('RelationshipType', 'getvalue', ['return' => 'id', 'name_b_a' => $rel_type_name]);
}
$this->relationship_type_ids[] = array('dir' => $dir, 'id' => $rel_type_id);
};
}
if (isset($configuration['show_label'])) {
$this->show_label = $configuration['show_label'];
}
}
/**
* Returns the formatted value
*
* @param $rawRecord
* @param $formattedRecord
*
* @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput
*/
public function formatField($rawRecord, $formattedRecord) {
$contactId = $rawRecord[$this->contactIdField->alias];
$sql['a_b'] = "SELECT c.id, c.display_name, t.label_a_b as label, r.relationship_type_id, c.contact_type, c.contact_sub_type
FROM civicrm_contact c
INNER JOIN civicrm_relationship r ON r.contact_id_b = c.id
INNER JOIN civicrm_relationship_type t on r.relationship_type_id = t.id
WHERE c.is_deleted = 0 AND r.is_active = 1 AND r.contact_id_a = %1";
$sql['b_a'] = "SELECT c.id, c.display_name, t.label_b_a as label, r.relationship_type_id, c.contact_type, c.contact_sub_type
FROM civicrm_contact c
INNER JOIN civicrm_relationship r ON r.contact_id_a = c.id
INNER JOIN civicrm_relationship_type t on r.relationship_type_id = t.id
WHERE c.is_deleted = 0 AND r.is_active = 1 AND r.contact_id_b = %1";
if (count($this->relationship_type_ids)) {
$relationShipTypeIdsA_B = array();
$relationShipTypeIdsB_A = array();
foreach($this->relationship_type_ids as $rel_type) {
if ($rel_type['dir'] == 'a_b') {
$relationShipTypeIdsA_B[] = $rel_type['id'];
} else {
$relationShipTypeIdsB_A[] = $rel_type['id'];
}
}
if (count($relationShipTypeIdsA_B)) {
$sql['a_b'] .= " AND t.id IN (" . implode(", ", $relationShipTypeIdsA_B) . ") ";
} else {
unset($sql['a_b']);
}
if (count($relationShipTypeIdsB_A)) {
$sql['b_a'] .= " AND t.id IN (" . implode(", ", $relationShipTypeIdsB_A) . ") ";
} else {
unset($sql['b_a']);
}
}
$formattedValues = [];
$htmlFormattedValues = [];
if (count($sql)) {
$sql = implode(" UNION ", $sql);
$sql .= " ORDER BY label, display_name";
$sqlParams[1] = [$contactId, 'Integer'];
$dao = \CRM_Core_DAO::executeQuery($sql, $sqlParams);
while ($dao->fetch()) {
$url = \CRM_Utils_System::url('civicrm/contact/view', [
'reset' => 1,
'cid' => $dao->id,
]);
$link = '<a href="' . $url . '">' . $dao->display_name . '</a>';
$image = \CRM_Contact_BAO_Contact_Utils::getImage($dao->contact_sub_type ? $dao->contact_sub_type : $dao->contact_type, FALSE, $dao->id);
if ($this->show_label) {
$htmlFormattedValues[] = $dao->label . ':&nbsp;' . $link;
$formattedValues[] = $dao->label.': '.$dao->display_name;
}
else {
$htmlFormattedValues[] = $link;
$formattedValues[] = $dao->display_name;
}
}
}
$output = new HTMLFieldOutput($contactId);
$output->formattedValue = implode(",", $formattedValues);
$output->setHtmlOutput(implode("<br>", $formattedValues));
return $output;
}
/**
* 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 = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFieldsInDataSources($field['data_processor_id']);
$relationshipTypeApi = civicrm_api3('RelationshipType', 'get', array('is_active' => 1, 'options' => array('limit' => 0)));
$relationshipTypes = array();
foreach($relationshipTypeApi['values'] as $relationship_type) {
$relationshipTypes['a_b_'.$relationship_type['name_a_b']] = $relationship_type['label_a_b'];
$relationshipTypes['b_a_'.$relationship_type['name_b_a']] = $relationship_type['label_b_a'];
}
$form->add('select', 'contact_id_field', E::ts('Contact ID Field'), $fieldSelect, true, array(
'style' => 'min-width:250px',
'class' => 'crm-select2 huge data-processor-field-for-name',
'placeholder' => E::ts('- select -'),
));
$form->add('select', 'relationship_types', E::ts('Restrict to relationship'), $relationshipTypes, false, array(
'style' => 'min-width:250px',
'class' => 'crm-select2 huge',
'placeholder' => E::ts('- Show all roles -'),
'multiple' => true,
));
$form->add('checkbox', 'show_label', E::ts('Show relationship type'), false, false);
if (isset($field['configuration'])) {
$configuration = $field['configuration'];
$defaults = array();
if (isset($configuration['field']) && isset($configuration['datasource'])) {
$defaults['contact_id_field'] = $configuration['datasource'] . '::' . $configuration['field'];
}
if (isset($configuration['relationship_types'])) {
$defaults['relationship_types'] = $configuration['relationship_types'];
}
if (isset($configuration['show_label'])) {
$defaults['show_label'] = $configuration['show_label'];
} elseif (!isset($configuration['show_label'])) {
$defaults['show_label'] = 1;
}
$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/RelationshipsFieldOutputHandler.tpl";
}
/**
* Process the submitted values and create a configuration array
*
* @param $submittedValues
* @return array
*/
public function processConfiguration($submittedValues) {
list($datasource, $field) = explode('::', $submittedValues['contact_id_field'], 2);
$configuration['field'] = $field;
$configuration['datasource'] = $datasource;
$configuration['relationship_types'] = isset($submittedValues['relationship_types']) ? $submittedValues['relationship_types'] : array();
$configuration['show_label'] = isset($submittedValues['show_label']) ? $submittedValues['show_label'] : 0;
return $configuration;
}
}
......@@ -180,8 +180,13 @@ abstract class AbstractCivicrmEntitySource extends AbstractSource {
* @throws \Exception
*/
protected function addFilter($filter_field_alias, $op, $values) {
if ($this->getAvailableFilterFields()->doesFieldExist($filter_field_alias)) {
$spec = $this->getAvailableFilterFields()->getFieldSpecificationByName($filter_field_alias);
$spec = null;
if ($this->getAvailableFields()->doesAliasExists($filter_field_alias)) {
$spec = $this->getAvailableFields()->getFieldSpecificationByAlias($filter_field_alias);
} elseif ($this->getAvailableFields()->doesFieldExist($filter_field_alias)) {
$spec = $this->getAvailableFields()->getFieldSpecificationByName($filter_field_alias);
}
if ($spec) {
if ($spec instanceof CustomFieldSpecification) {
$customGroupDataFlow = $this->ensureCustomGroup($spec->customGroupTableName, $spec->customGroupName);
$customGroupTableAlias = $customGroupDataFlow->getTableAlias();
......
......@@ -14,6 +14,25 @@ use CRM_Dataprocessor_ExtensionUtil as E;
class HouseholdSource extends AbstractCivicrmEntitySource {
protected $skipFields = array(
'first_name',
'middle_name',
'last_name',
'formal_title',
'job_title',
'gender_id',
'prefix_id',
'suffix_id',
'birth_date',
'organization_name',
'legal_name',
'legal_identifier',
'sic_code',
'home_URL',
'is_deceased',
'deceased_date',
);
protected $skipFilterFields = array(
'contact_type',
'first_name',
'middle_name',
......@@ -74,7 +93,7 @@ class HouseholdSource extends AbstractCivicrmEntitySource {
public function getAvailableFilterFields() {
if (!$this->availableFilterFields) {
$this->availableFilterFields = new DataSpecification();
$this->loadFields($this->availableFilterFields, $this->skipFields);
$this->loadFields($this->availableFilterFields, $this->skipFilterFields);
$this->loadCustomGroupsAndFields($this->availableFilterFields, true, 'Household');
}
return $this->availableFilterFields;
......@@ -105,4 +124,4 @@ class HouseholdSource extends AbstractCivicrmEntitySource {
}
}
\ No newline at end of file
}
......@@ -14,6 +14,13 @@ use CRM_Dataprocessor_ExtensionUtil as E;
class IndividualSource extends AbstractCivicrmEntitySource {
protected $skipFields = array(
'household_name',
'legal_name',
'sic_code',
'organization_name',
);
protected $skipFilterFields = array(
'contact_type',
'household_name',
'legal_name',
......@@ -66,7 +73,7 @@ class IndividualSource extends AbstractCivicrmEntitySource {
public function getAvailableFilterFields() {
if (!$this->availableFilterFields) {
$this->availableFilterFields = new DataSpecification();
$this->loadFields($this->availableFilterFields, $this->skipFields);
$this->loadFields($this->availableFilterFields, $this->skipFilterFields);
$this->loadCustomGroupsAndFields($this->availableFilterFields, true, 'Individual');
}
return $this->availableFilterFields;
......@@ -97,4 +104,4 @@ class IndividualSource extends AbstractCivicrmEntitySource {
}
}
\ No newline at end of file
}
......@@ -14,6 +14,21 @@ use CRM_Dataprocessor_ExtensionUtil as E;
class OrganizationSource extends AbstractCivicrmEntitySource {
protected $skipFields = array(
'first_name',
'middle_name',
'last_name',
'formal_title',
'job_title',
'gender_id',
'prefix_id',
'suffix_id',
'birth_date',
'household_name',
'is_deceased',
'deceased_date',
);
protected $skipFilterFields = array(
'contact_type',
'first_name',
'middle_name',
......@@ -70,7 +85,7 @@ class OrganizationSource extends AbstractCivicrmEntitySource {
public function getAvailableFilterFields() {
if (!$this->availableFilterFields) {
$this->availableFilterFields = new DataSpecification();
$this->loadFields($this->availableFilterFields, $this->skipFields);
$this->loadFields($this->availableFilterFields, $this->skipFilterFields);
$this->loadCustomGroupsAndFields($this->availableFilterFields, true, 'Organization');
}
return $this->availableFilterFields;
......@@ -101,4 +116,4 @@ class OrganizationSource extends AbstractCivicrmEntitySource {
}
}
\ No newline at end of file
}
......@@ -49,7 +49,7 @@
<td>{$row.contact_type}</td>
{foreach from=$columnHeaders key=headerName item=headerTitle}
{assign var=columnValue value=$record.$headerName}
<td>{$columnValue|escape:'html'}</td>
<td>{$columnValue}</td>
{/foreach}
<td>
......
{crmScope extensionKey='dataprocessor'}
<div class="crm-section">
<div class="label">{$form.contact_id_field.label}</div>
<div class="content">{$form.contact_id_field.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section">
<div class="label">{$form.relationship_types.label}</div>
<div class="content">{$form.relationship_types.html}</div>
<div class="clear"></div>
</div>
<div class="crm-section">
<div class="label"></div>
<div class="content">{$form.show_label.html}&nbsp;{$form.show_label.label}</div>
<div class="clear"></div>
</div>
{/crmScope}
......@@ -52,7 +52,7 @@
{if $id_field && $taskMetaData}<td>{$form.$cbName.html}</td>{/if}
{foreach from=$columnHeaders key=headerName item=headerTitle}
{assign var=columnValue value=$record.$headerName}
<td>{$columnValue|escape:'html'}</td>
<td>{$columnValue}</td>
{/foreach}
<td>
......
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