From be9bcd1c51246aef66823fa3715389b6ddbf49f5 Mon Sep 17 00:00:00 2001 From: Jaap Jansma <jaap.jansma@civicoop.org> Date: Fri, 28 Feb 2020 10:46:18 +0100 Subject: [PATCH] Added data sources for custom groups which are a multiple data set. --- CHANGELOG.md | 1 + Civi/DataProcessor/Factory/Definition.php | 6 +- .../Source/AbstractCivicrmEntitySource.php | 5 +- .../MultipleCustomGroupSource.php | 40 ++++++ .../Contact/MultipleCustomGroupSource.php | 134 ++++++++++++++++++ dataprocessor.php | 6 +- 6 files changed, 184 insertions(+), 8 deletions(-) create mode 100644 Civi/DataProcessor/Source/CompilerPass/MultipleCustomGroupSource.php create mode 100644 Civi/DataProcessor/Source/Contact/MultipleCustomGroupSource.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f17e248b..40fb124a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add Recurring Contribution as datasource * Added Field Output Handler for Is Active fields based on dates (start date and end date). * Refactored the factory. +* Added data sources for custom groups which are a multiple data set. # Version 1.2.0 diff --git a/Civi/DataProcessor/Factory/Definition.php b/Civi/DataProcessor/Factory/Definition.php index d3d99570..91f2928d 100644 --- a/Civi/DataProcessor/Factory/Definition.php +++ b/Civi/DataProcessor/Factory/Definition.php @@ -32,8 +32,10 @@ class Definition { */ public function get() { $reflectionClass = new \ReflectionClass($this->class); - if ($reflectionClass->getConstructor()) { - return $reflectionClass->newInstance($this->arguments); + if ($this->arguments && $reflectionClass->getConstructor()) { + return $reflectionClass->newInstanceArgs($this->arguments); + } elseif ($reflectionClass->getConstructor()) { + return $reflectionClass->newInstance(); } else { return $reflectionClass->newInstanceWithoutConstructor(); } diff --git a/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php b/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php index 9f617637..79fe06ff 100644 --- a/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php +++ b/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php @@ -123,7 +123,7 @@ abstract class AbstractCivicrmEntitySource extends AbstractSource { * @return \Civi\DataProcessor\DataFlow\SqlDataFlow */ protected function getEntityDataFlow() { - return new SqlTableDataFlow($this->getTable(), $this->getSourceName(), $this->getSourceTitle()); + return new SqlTableDataFlow($this->getTable(), $this->getSourceName()); } /** @@ -187,9 +187,6 @@ abstract class AbstractCivicrmEntitySource extends AbstractSource { $spec = $this->getAvailableFields()->getFieldSpecificationByName($filter_field_alias); } - - - if ($spec) { if ($spec instanceof CustomFieldSpecification) { $customGroupDataFlow = $this->ensureCustomGroup($spec->customGroupTableName, $spec->customGroupName); diff --git a/Civi/DataProcessor/Source/CompilerPass/MultipleCustomGroupSource.php b/Civi/DataProcessor/Source/CompilerPass/MultipleCustomGroupSource.php new file mode 100644 index 00000000..2fddc4e5 --- /dev/null +++ b/Civi/DataProcessor/Source/CompilerPass/MultipleCustomGroupSource.php @@ -0,0 +1,40 @@ +<?php +/** + * @author Jaap Jansma <jaap.jansma@civicoop.org> + * @license AGPL-3.0 + */ + +namespace Civi\DataProcessor\Source\CompilerPass; + +use CRM_Dataprocessor_ExtensionUtil as E; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; + +class MultipleCustomGroupSource implements CompilerPassInterface { + + /** + * You can modify the container here before it is dumped to PHP code. + */ + public function process(ContainerBuilder $container) { + if (!$container->hasDefinition('data_processor_factory')) { + return; + } + $factoryDefinition = $container->getDefinition('data_processor_factory'); + + try { + $dao = \CRM_Core_DAO::executeQuery("SELECT * FROM civicrm_custom_group WHERE is_multiple = '1' and is_active = '1'"); + while($dao->fetch()) { + $arguments = [ + '\Civi\DataProcessor\Source\Contact\MultipleCustomGroupSource', + [$dao->name, $dao->title, $dao->table_name], + ]; + $definition = new Definition('Civi\DataProcessor\Factory\Definition', $arguments); + $factoryDefinition->addMethodCall('addDataSource', array('multi_custom_group_'.$dao->name, $definition, E::ts('Custom group: %1', [1=>$dao->title]))); + } + } catch (\CiviCRM_API3_Exception $e) { + // Do nothing + } + } + +} diff --git a/Civi/DataProcessor/Source/Contact/MultipleCustomGroupSource.php b/Civi/DataProcessor/Source/Contact/MultipleCustomGroupSource.php new file mode 100644 index 00000000..d3e1073a --- /dev/null +++ b/Civi/DataProcessor/Source/Contact/MultipleCustomGroupSource.php @@ -0,0 +1,134 @@ +<?php +/** + * @author Jaap Jansma <jaap.jansma@civicoop.org> + * @license AGPL-3.0 + */ + +namespace Civi\DataProcessor\Source\Contact; + +use Civi\DataProcessor\DataFlow\SqlTableDataFlow; +use Civi\DataProcessor\DataSpecification\DataSpecification; +use Civi\DataProcessor\DataSpecification\FieldExistsException; +use Civi\DataProcessor\DataSpecification\FieldSpecification; +use Civi\DataProcessor\Source\AbstractSource; +use Civi\DataProcessor\DataSpecification\CustomFieldSpecification; + +use CRM_Dataprocessor_ExtensionUtil as E; + + +class MultipleCustomGroupSource extends AbstractSource { + + /** + * @var string + */ + protected $custom_group_name; + + /** + * @var string + */ + protected $custom_group_title; + + /** + * @var string + */ + protected $custom_group_table_name; + + /** + * @var \Civi\DataProcessor\DataSpecification\DataSpecification + */ + protected $availableFields; + + /** + * @var \Civi\DataProcessor\DataSpecification\DataSpecification + */ + protected $availableFilterFields; + + public function __construct($custom_group_name, $custom_group_title, $custom_group_table_name) { + parent::__construct(); + $this->custom_group_name = $custom_group_name; + $this->custom_group_title = $custom_group_title; + $this->custom_group_table_name = $custom_group_table_name; + } + + /** + * Initialize the join + * + * @return void + */ + public function initialize() { + if (!$this->dataFlow) { + $this->dataFlow = new SqlTableDataFlow($this->custom_group_table_name, $this->getSourceName()); + } + } + + /** + * @return \Civi\DataProcessor\DataSpecification\DataSpecification + * @throws \Exception + */ + public function getAvailableFields() { + if (!$this->availableFields) { + $this->availableFields = new DataSpecification(); + $this->availableFields->addFieldSpecification('entity_id', new FieldSpecification('entity_id','Integer', E::ts('Contact ID'), null, $this->getSourceName().'_entity_id')); + $this->loadCustomGroupsAndFields($this->availableFields, false); + } + return $this->availableFields; + } + + /** + * @return \Civi\DataProcessor\DataSpecification\DataSpecification + * @throws \Exception + */ + public function getAvailableFilterFields() { + if (!$this->availableFilterFields) { + $this->availableFilterFields = new DataSpecification(); + $this->availableFilterFields->addFieldSpecification('entity_id', new FieldSpecification('entity_id','Integer', E::ts('Contact ID'), null, $this->getSourceName().'_entity_id')); + $this->loadCustomGroupsAndFields($this->availableFilterFields, true); + } + return $this->availableFilterFields; + } + + /** + * Add custom fields to the available fields section + * + * @param DataSpecification $dataSpecification + * @param bool $onlySearchAbleFields + * @param $entity + * @throws \Civi\DataProcessor\DataSpecification\FieldExistsException + * @throws \Exception + */ + protected function loadCustomGroupsAndFields(DataSpecification $dataSpecification, $onlySearchAbleFields) { + $params['options']['limit'] = 0; + $params['custom_group_id'] = $this->custom_group_name; + $params['is_active'] = 1; + if ($onlySearchAbleFields) { + $params['is_searchable'] = 1; + } + $customFields = civicrm_api3('CustomField', 'get', $params); + foreach ($customFields['values'] as $field) { + $alias = $this->getSourceName() . '_' . $field['name']; + $customFieldSpec = new CustomFieldSpecification( + $this->custom_group_name, $this->custom_group_table_name, $this->custom_group_title, + $field, + $alias + ); + $dataSpecification->addFieldSpecification($customFieldSpec->name, $customFieldSpec); + } + } + + /** + * Ensures a field is in the data source + * + * @param \Civi\DataProcessor\DataSpecification\FieldSpecification $fieldSpecification + * @throws \Exception + */ + public function ensureFieldInSource(FieldSpecification $fieldSpecification) { + try { + $this->dataFlow->getDataSpecification()->addFieldSpecification($fieldSpecification->alias, $fieldSpecification); + } catch (FieldExistsException $e) { + // Do nothing. + } + } + + + +} diff --git a/dataprocessor.php b/dataprocessor.php index 998e190a..170f6696 100644 --- a/dataprocessor.php +++ b/dataprocessor.php @@ -29,6 +29,8 @@ function dataprocessor_civicrm_container(ContainerBuilder $container) { $apiKernelDefinition = $container->getDefinition('civi_api_kernel'); $apiProviderDefinition = new Definition('Civi\DataProcessor\Output\Api'); $apiKernelDefinition->addMethodCall('registerApiProvider', array($apiProviderDefinition)); + + $container->addCompilerPass(new \Civi\DataProcessor\Source\CompilerPass\MultipleCustomGroupSource()); } /** @@ -51,8 +53,8 @@ function dataprocessor_civicrm_alterAPIPermissions($entity, $action, &$params, & $actionCamelCase = _civicrm_api_get_camel_name($api_action); $dao = CRM_Core_DAO::executeQuery(" SELECT * - FROM civicrm_data_processor_output o - INNER JOIN civicrm_data_processor p ON o.data_processor_id = p.id + FROM civicrm_data_processor_output o + INNER JOIN civicrm_data_processor p ON o.data_processor_id = p.id WHERE p.is_active = 1 AND (LOWER(api_entity) = LOWER(%1) OR LOWER(api_entity) = LOWER(%2)) AND ( -- GitLab