Skip to content

Commit

Permalink
Merge pull request #1263 from UN-OCHA/berliner/HPC-9971
Browse files Browse the repository at this point in the history
HPC-9971: Apply new attachment data point matching to GVE caseload tables, refactor for better code re-use
  • Loading branch information
berliner authored Dec 16, 2024
2 parents 750bd9f + 1025eb0 commit 7d4bb5c
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 80 deletions.
108 changes: 108 additions & 0 deletions html/modules/custom/ghi_blocks/src/Helpers/AttachmentMatcher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace Drupal\ghi_blocks\Helpers;

use Drupal\ghi_plans\ApiObjects\AttachmentPrototype\AttachmentPrototype;
use Drupal\ghi_plans\ApiObjects\Attachments\AttachmentInterface;
use Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment;

/**
* Helper function for attachment matching.
*/
class AttachmentMatcher {

/**
* Match an array of data attachments against an original attachment.
*
* This checks the attachment type and the attachment source to find
* attachments that correspond in their function.
*
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment $original_attachment
* The original attachment to match against.
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment[] $available_attachments
* The attachments to match.
*
* @return \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment[]
* The result set of matched attachments.
*/
public static function matchDataAttachments(AttachmentInterface $original_attachment, array $available_attachments) {
return array_filter($available_attachments, function (DataAttachment $attachment) use ($original_attachment) {
if ($original_attachment->getType() != $attachment->getType()) {
// Check the attachment type, e.g. "caseload" vs "indicator".
return FALSE;
}
if ($original_attachment->source->entity_type != $attachment->source->entity_type) {
// Check the source entity type, e.g. "governingEntity" vs "plan".
return FALSE;
}
if ($original_attachment->getPrototype()->getRefCode() != $attachment->getPrototype()->getRefCode()) {
// Check the attachment prototype ref code, e.g. "BP" vs "BF.
return FALSE;
}
return TRUE;
});
}

/**
* Match a data point index on the given attachments.
*
* Matching is done by type, such that a data point of attachment 2 is
* returned that has the same type as the given data point in attachment 1.
*
* @param int $data_point_index
* The data point index to match.
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment $attachment_1
* The first or original attachment.
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment $attachment_2
* The second or new attachment.
*
* @return int
* Either the original index if no match can be found or a new index.
*/
public static function matchDataPointOnAttachments($data_point_index, DataAttachment $attachment_1, DataAttachment $attachment_2) {
$prototype_1 = $attachment_1->getPrototype();
$prototype_2 = $attachment_2->getPrototype();
if (!$prototype_1 || !$prototype_2) {
return $data_point_index;
}
return self::matchDataPointOnAttachmentPrototypes($data_point_index, $prototype_1, $prototype_2);
}

/**
* Match a data point index on the given attachment prototypes.
*
* @param int $data_point_index
* The data point index to match.
* @param \Drupal\ghi_plans\ApiObjects\AttachmentPrototype\AttachmentPrototype $prototype_1
* The first or original attachment prototype.
* @param \Drupal\ghi_plans\ApiObjects\AttachmentPrototype\AttachmentPrototype $prototype_2
* The second or new attachment prototype.
*
* @return int
* Either the original index if no match can be found or a new index.
*/
public static function matchDataPointOnAttachmentPrototypes($data_point_index, AttachmentPrototype $prototype_1, AttachmentPrototype $prototype_2) {
// First get the original and the new fields. These are the types keyed by
// the field index.
$original_fields = $prototype_1->getFieldTypes();
$new_fields = $prototype_2->getFieldTypes();
if (!array_key_exists($data_point_index, $original_fields)) {
// This is fishy.
return $data_point_index;
}

// Compare the types.
if ($original_fields[$data_point_index] == ($new_fields[$data_point_index] ?? NULL)) {
// If they are the same, there is no need to go further.
return $data_point_index;
}
// It's referring to a different type now, let's see if we can find the
// same as the original type in the set of new fields.
$new_index = array_search($original_fields[$data_point_index], $new_fields);

// We either found a new index and can return it, or we didn't and we
// return the original.
return $new_index !== FALSE ? $new_index : $data_point_index;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Drupal\Core\Cache\Cache;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\ghi_blocks\Helpers\AttachmentMatcher;
use Drupal\ghi_blocks\Interfaces\ConfigValidationInterface;
use Drupal\ghi_blocks\Interfaces\MultiStepFormBlockInterface;
use Drupal\ghi_blocks\Interfaces\OverrideDefaultTitleBlockInterface;
Expand Down Expand Up @@ -1330,7 +1331,7 @@ public function fixConfigErrors() {
if (!$attachment instanceof DataAttachment) {
continue;
}
$filtered_attachments = $this->matchDataAttachments($attachment, $available_attachments);
$filtered_attachments = AttachmentMatcher::matchDataAttachments($attachment, $available_attachments);
foreach ($filtered_attachments as $filtered_attachment) {
$conf['attachments']['entity_attachments']['attachments']['attachment_id'][$filtered_attachment->id()] = $filtered_attachment->id();
$conf['attachments']['entity_attachments']['entities']['entity_ids'][$filtered_attachment->source->entity_id] = $filtered_attachment->source->entity_id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\ghi_base_objects\Helpers\BaseObjectHelper;
use Drupal\ghi_blocks\Helpers\AttachmentMatcher;
use Drupal\ghi_blocks\Interfaces\AttachmentTableInterface;
use Drupal\ghi_blocks\Interfaces\ConfigValidationInterface;
use Drupal\ghi_blocks\Interfaces\ConfigurableTableBlockInterface;
Expand Down Expand Up @@ -556,10 +557,33 @@ public function getConfigErrors() {
*/
public function fixConfigErrors() {
$conf = $this->getBlockConfig();
$original_prototype_id = $conf['base']['prototype_id'] ?? NULL;
$prototype_options = $this->getUniquePrototypeOptions();
if (count($prototype_options) == 1) {
$conf['base']['prototype_id'] = array_key_first($prototype_options);
}
if ($original_prototype_id && !empty($conf['base']['prototype_id'])) {
$new_prototype_id = $conf['base']['prototype_id'];
/** @var \Drupal\ghi_plans\Plugin\EndpointQuery\AttachmentPrototypeQuery $query */
$query = $this->endpointQueryManager->createInstance('attachment_prototype_query');
$original_prototype = $query->getPrototypeById($original_prototype_id);
$new_prototype = $query->getPrototypeById($new_prototype_id);
foreach ($conf['table']['columns'] as &$column) {
if ($column['item_type'] == 'data_point') {
$data_points = &$column['config']['data_point']['data_points'];
$data_points[0]['index'] = AttachmentMatcher::matchDataPointOnAttachmentPrototypes($data_points[0]['index'], $original_prototype, $new_prototype);
if ($column['config']['data_point']['processing'] != 'single') {
$data_points[1]['index'] = AttachmentMatcher::matchDataPointOnAttachmentPrototypes($data_points[1]['index'], $original_prototype, $new_prototype);
}
}
if ($column['item_type'] == 'spark_line_chart') {
$column['config']['data_point'] = AttachmentMatcher::matchDataPointOnAttachmentPrototypes($column['config']['data_point'], $original_prototype, $new_prototype);
if ($column['config']['show_baseline']) {
$column['config']['baseline'] = AttachmentMatcher::matchDataPointOnAttachmentPrototypes($column['config']['baseline'], $original_prototype, $new_prototype);
}
}
}
}
$this->setBlockConfig($conf);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\ghi_blocks\Helpers\AttachmentMatcher;
use Drupal\ghi_blocks\Traits\PlanFootnoteTrait;
use Drupal\ghi_form_elements\ConfigurationContainerItemPluginBase;
use Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment;
use Drupal\ghi_plans\Entity\Plan;
use Drupal\ghi_plans\Traits\AttachmentFilterTrait;
use Drupal\hpc_common\Helpers\StringHelper;
Expand Down Expand Up @@ -235,7 +235,6 @@ public function getConfigurationErrors() {
public function fixConfigurationErrors() {
$conf = &$this->config;
$attachment_id = &$conf['attachment']['attachment_id'];

$original_attachment = $this->getAttachmentObject();

/** @var \Drupal\ghi_plans\Entity\Plan $plan */
Expand All @@ -250,7 +249,7 @@ public function fixConfigurationErrors() {
$query = $this->endpointQueryManager->createInstance('plan_entities_query');
$query->setPlaceholder('plan_id', $plan->getSourceId());
$attachments = $query->getDataAttachments($this->getContextValue('base_object'));
$filtered_attachments = $this->matchDataAttachments($original_attachment, $attachments);
$filtered_attachments = AttachmentMatcher::matchDataAttachments($original_attachment, $attachments);

// Use the default plan caseload if available.
$caseload_id = $plan->getPlanCaseloadId();
Expand All @@ -268,51 +267,11 @@ public function fixConfigurationErrors() {
$new_attachment = $filtered_attachments[$attachment_id];
$data_point_conf = &$this->config['data_point'];
$data_points = &$data_point_conf['data_points'];
$data_points[0]['index'] = $this->matchDataPointOnAttachments($data_points[0]['index'], $original_attachment, $new_attachment);
$data_points[0]['index'] = AttachmentMatcher::matchDataPointOnAttachments($data_points[0]['index'], $original_attachment, $new_attachment);
if ($data_point_conf['processing'] != 'single') {
$data_points[1]['index'] = $this->matchDataPointOnAttachments($data_points[1]['index'], $original_attachment, $new_attachment);
$data_points[1]['index'] = AttachmentMatcher::matchDataPointOnAttachments($data_points[1]['index'], $original_attachment, $new_attachment);
}
}
}

/**
* Match a data point index on the given attachments.
*
* Matching is done by type, such that a data point of attachment 2 is
* returned that has the same type as the given data point in attachment 1.
*
* @param int $data_point_index
* The data point index to match.
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment $attachment_1
* The first or original attachment.
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment $attachment_2
* The second or new attachment.
*
* @return int
* Either the original index if no match can be found or a new index.
*/
private function matchDataPointOnAttachments($data_point_index, DataAttachment $attachment_1, DataAttachment $attachment_2) {
// First get the original and the new fields. These are the types keyed by
// the field index.
$original_fields = $attachment_1->getPrototype()->getFieldTypes();
$new_fields = $attachment_2->getPrototype()->getFieldTypes();
if (!array_key_exists($data_point_index, $original_fields)) {
// This is fishy.
return $data_point_index;
}

// Compare the types.
if ($original_fields[$data_point_index] == ($new_fields[$data_point_index] ?? NULL)) {
// If they are the same, there is no need to go further.
return $data_point_index;
}
// It's referring to a different type now, let's see if we can find the
// same as the original type in the set of new fields.
$new_index = array_search($original_fields[$data_point_index], $new_fields);

// We either found a new index and can return it, or we didn't and we
// return the original.
return $new_index !== FALSE ? $new_index : $data_point_index;
}

}
34 changes: 0 additions & 34 deletions html/modules/custom/ghi_plans/src/Traits/AttachmentFilterTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace Drupal\ghi_plans\Traits;

use Drupal\ghi_plans\ApiObjects\Attachments\AttachmentInterface;
use Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment;
use Drupal\hpc_common\Helpers\ArrayHelper;

/**
Expand Down Expand Up @@ -68,36 +66,4 @@ public function filterAttachments(array $attachments, array $filter) {
return ArrayHelper::filterArray($attachments, $this->prepareAttachmentFilter($filter));
}

/**
* Match an array of data attachments against an original attachment.
*
* This checks the attachment type and the attachment source to find
* attachments that correspond in their function.
*
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment $original_attachment
* The original attachment to match against.
* @param \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment[] $available_attachments
* The attachments to match.
*
* @return \Drupal\ghi_plans\ApiObjects\Attachments\DataAttachment[]
* The result set of matched attachments.
*/
public function matchDataAttachments(AttachmentInterface $original_attachment, array $available_attachments) {
return array_filter($available_attachments, function (DataAttachment $attachment) use ($original_attachment) {
if ($original_attachment->getType() != $attachment->getType()) {
// Check the attachment type, e.g. "caseload" vs "indicator".
return FALSE;
}
if ($original_attachment->source->entity_type != $attachment->source->entity_type) {
// Check the source entity type, e.g. "governingEntity" vs "plan".
return FALSE;
}
if ($original_attachment->getPrototype()->getRefCode() != $attachment->getPrototype()->getRefCode()) {
// Check the attachment prototype ref code, e.g. "BP" vs "BF.
return FALSE;
}
return TRUE;
});
}

}

0 comments on commit 7d4bb5c

Please sign in to comment.