From 370678f2140632967a802b4802433ffce0a312bc Mon Sep 17 00:00:00 2001 From: Benn Oshrin Date: Wed, 28 Dec 2022 10:35:54 -0500 Subject: [PATCH] Initial controller logic to facilitate reconciliation view comparison (CO-2481) --- app/src/Controller/MatchgridsController.php | 3 + app/src/Lib/Match/MatchService.php | 78 +++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/app/src/Controller/MatchgridsController.php b/app/src/Controller/MatchgridsController.php index e1000cf5..550ebdf7 100644 --- a/app/src/Controller/MatchgridsController.php +++ b/app/src/Controller/MatchgridsController.php @@ -342,6 +342,9 @@ public function reconcile(string $id) { } $this->set('vv_candidates', $candidates); + // Calculate which attributes differ, accounting for the configuration + // rules, for the frontend to render + $this->set('vv_candidate_diff', $MatchService->diffCandidates($origReq[$rowId], $candidates)); // Also set the original request separately to make it easier for the view $this->set('vv_request', $origReq[$rowId]); $this->set('vv_title', __('match.op.reconcile.request', [$sor, $sorid])); diff --git a/app/src/Lib/Match/MatchService.php b/app/src/Lib/Match/MatchService.php index eb7f725d..ec6c1ad1 100644 --- a/app/src/Lib/Match/MatchService.php +++ b/app/src/Lib/Match/MatchService.php @@ -31,6 +31,7 @@ use Cake\Log\Log; use Cake\ORM\TableRegistry; +use Cake\Utility\Hash; use \App\Lib\Enum\ConfidenceModeEnum; use \App\Lib\Enum\ReferenceIdEnum; @@ -96,6 +97,83 @@ public function attachReferenceId(string $sor, string $sorid, AttributeManager $ return $refId; } + /** + * Calculate which attributes from a set of candidates differ from the original. + * Primarily intended to facilitate frontend rendering, the results of this + * function may not exactly match what search() does. + * + * @since COmanage Match v1.1.0 + * @param array $original Original request data + * @param array $candidates Set of candidates, as returned by getRawResults() + * @return array An array of arrays, indexed by requested ID and then attribute + */ + + public function diffCandidates(array $original, array $candidates) { + $ret = []; + + // Walk through the attribute configuration and map it into a hash + // based on attribute name for easier manipulation. + $attrConfig = []; + + foreach($this->mgConfig->attributes as $a) { + $attrConfig[$a->name] = $a; + } + + foreach($candidates as $c) { + if($c['id'] == $original['id']) { + // This is also the original request, basically skip it + + $ret[ $c['id'] ] = []; + continue; + } + + foreach(array_keys($c) as $attr) { + // This will include both actual attributes (eg: "firstname") + // AND metadata (eg: "sorid"). We'll effectively skip the metadata + // because it won't have an Attribute configuration. + + if(!empty($attrConfig[$attr])) { + // There's a fair amount of conceptual overlap between this code + // and search(), below. We don't perform all possible checks here, + // though plausibly over time more could be added. eg: Dictionary + // checks require a SQL call to process, we can't just figure it + // out in PHP code. Also, RuleAttributes can affect how matching + // works, and right now we don't look at those at all. + + $origvalue = $original[$attr]; + $value = $c[$attr]; + + if($attrConfig[$attr]->alphanumeric) { + $origvalue = preg_replace('/[^A-Za-z0-9]/', '', $origvalue); + $value = preg_replace('/[^A-Za-z0-9]/', '', $value); + } + + if(!$attrConfig[$attr]->case_sensitive) { + $origvalue = mb_strtolower($origvalue ?: ""); + $value = mb_strtolower($value ?: ""); + } + + // Null equivalents are handled by Attribute Manager. + + if($attrConfig[$attr]->null_equivalents) { + if(!preg_match('/[1-9[:alpha:]]/', $origvalue)) { + $origvalue = ""; + } + if(!preg_match('/[1-9[:alpha:]]/', $value)) { + $value = ""; + } + } + + if($value != $origvalue) { + $ret[ $c['id'] ][] = $attr; + } + } + } + } + + return $ret; + } + /** * Generate a Reference ID in accordance with the current configuration. *