From 9e03102a77e1814c3c23801bd823a1ed84686764 Mon Sep 17 00:00:00 2001
From: Nick Clemens <nick@bywatersolutions.com>
Date: Tue, 12 May 2020 14:06:27 +0000
Subject: [PATCH] Bug 25467: Build and cache hidden fields and use them for
 filtering

---
 Koha/Filter/MARC/ViewPolicy.pm | 88 +++++++++++++++++++++++++-----------------
 1 file changed, 53 insertions(+), 35 deletions(-)

diff --git a/Koha/Filter/MARC/ViewPolicy.pm b/Koha/Filter/MARC/ViewPolicy.pm
index 4d7adfdf67..775d053397 100644
--- a/Koha/Filter/MARC/ViewPolicy.pm
+++ b/Koha/Filter/MARC/ViewPolicy.pm
@@ -89,21 +89,27 @@ sub filter {
         unless ( exists $self->{_cached_frameworks}->{$frameworkcode} ) {
             $self->{_cached_frameworks}->{$frameworkcode} = GetMarcStructure( 0, $frameworkcode, { unsafe => 1 } );
         }
-
         my $marcsubfieldstructure = $self->{_cached_frameworks}->{$frameworkcode};
+        unless ( exists $self->{_cached_hidden_fields}->{$frameworkcode}->{$interface} ){
+            $self->{_cached_hidden_fields}->{$frameworkcode}->{$interface} =
+                _get_hidden_fields_from_framework({
+                    marcsubfieldstructure => $marcsubfieldstructure,
+                    hide                  => $hide,
+                    interface             => $interface,
+                });
+        }
+        my $hidden_fields = $self->{_cached_hidden_fields}->{$frameworkcode}->{$interface};
 
         #if ($marcsubfieldstructure->{'000'}->{'@'}->{hidden}>0) {
         # LDR field is excluded from $current_record->fields().
         # if we hide it here, the MARCXML->MARC::Record->MARCXML
         # transformation blows up.
         #}
-        foreach my $field ( $result->fields() ) {
+        foreach my $field ( keys %{$hidden_fields} ) {
             _filter_field(
                 {
                     field                 => $field,
-                    marcsubfieldstructure => $marcsubfieldstructure,
-                    hide                  => $hide,
-                    interface             => $interface,
+                    subfields             => $hidden_fields->{$field},
                     result                => $result
                 }
             );
@@ -112,50 +118,62 @@ sub filter {
     return;
 }
 
-sub _filter_field {
-    my ($parameter) = @_;
-
-    my $field                 = $parameter->{field};
-    my $marcsubfieldstructure = $parameter->{marcsubfieldstructure};
-    my $hide                  = $parameter->{hide};
-    my $interface             = $parameter->{interface};
-    my $result                = $parameter->{result};
-
-    my $tag = $field->tag();
-    if ( $tag >= FIRST_NONCONTROL_TAG ) {
-        foreach my $subpairs ( $field->subfields() ) {
-            my ( $subtag, $value ) = @{$subpairs};
-
+sub _get_hidden_fields_from_framework {
+    my ($params) = @_;
+    my $mss       = $params->{marcsubfieldstructure};
+    my $interface = $params->{interface};
+    my $hide      = $params->{hide};
+    my $hidden_fields;
+    foreach my $tag (keys %{$mss}) {
+        if ( $tag >= FIRST_NONCONTROL_TAG ) {
+            foreach my $subtag (keys %{$mss->{$tag}}) {
+                next unless ref $mss->{$tag}->{$subtag} eq 'HASH';
+                my $visibility = $mss->{$tag}->{$subtag}->{hidden};
+                $visibility //= 0;
+                if( $hide->{$interface}->{$visibility}){
+                    $hidden_fields->{$tag}->{$subtag} = 1;
+                }
+            }
+        } else {
             # visibility is a "level" (-9 to +9), default to 0
             # -8 is flagged, and 9/-9 are not implemented.
-            my $visibility =
-              $marcsubfieldstructure->{$tag}->{$subtag}->{hidden};
+            my $visibility = $mss->{$tag}->{q{@}}->{hidden};
             $visibility //= 0;
             if ( $hide->{$interface}->{$visibility} ) {
+                $hidden_fields->{$tag}->{q{@}} = 1;
+            }
+        }
+    }
+    return $hidden_fields;
+}
+
+
+sub _filter_field {
+    my ($parameter) = @_;
 
+    my $field       = $parameter->{field};
+    my $subfields   = $parameter->{subfields};
+    my $result      = $parameter->{result};
+
+    my @result_fields = $result->field($field);
+    return unless @result_fields;
+    foreach my $result_field ( @result_fields ){
+        if ( $field >= FIRST_NONCONTROL_TAG ) {
+            foreach my $subfield ( keys %{$subfields}) {
                 # deleting last subfield doesn't delete field, so
                 # this detects that case to delete the field.
-                if ( scalar $field->subfields() <= 1 ) {
-                    $result->delete_fields($field);
+                if ( scalar $result_field->subfields() <= 1 ) {
+                    $result->delete_fields($result_field);
                 }
                 else {
-                    $field->delete_subfield( code => $subtag );
+                    $result_field->delete_subfield( code => $subfield );
                 }
             }
+        } else {
+            $result->delete_fields($result_field);
         }
     }
 
-    # control tags don't have subfields, use @ trick.
-    else {
-        # visibility is a "level" (-9 to +9), default to 0
-        # -8 is flagged, and 9/-9 are not implemented.
-        my $visibility = $marcsubfieldstructure->{$tag}->{q{@}}->{hidden};
-        $visibility //= 0;
-        if ( $hide->{$interface}->{$visibility} ) {
-            $result->delete_fields($field);
-        }
-
-    }
     return;
 }
 
-- 
2.11.0