From 91f9699a222a38bc3eb26aafabf6a7039c5f1feb Mon Sep 17 00:00:00 2001
From: Robert Lange <robert.lange@uni-leipzig.de>
Date: Wed, 16 Sep 2020 10:54:10 +0200
Subject: [PATCH] refs #17725 [fid_bbi] searchspecs YAML inheritance

* prepare searchspecs comparism test and fixtures

** add SearchSpecsReaderTest.php
** add fixtures - soft symlinks and expected result before refactoring / using parent yaml
* minimize searchspecs.yaml and replace access_facet by facet_avail

** for config
** for alpha
** delete more redundant configuration to local
---
 fid_bbi/alpha/config/vufind/searchspecs.yaml  |   2 +
 fid_bbi/config/vufind/searchspecs.yaml        | 489 +----------------
 .../config/vufind/searchspecs.yaml            |   1 +
 .../alpha/config/vufind/searchspecs.yaml      |   1 +
 .../fid_bbi/config/vufind/searchspecs.yaml    |   1 +
 .../alpha/config/vufind/searchspecs.yaml      |   1 +
 .../local/config/vufind/searchspecs.yaml      |   1 +
 .../result/fid_bbi/alpha/searchspecs.yaml     | 501 ++++++++++++++++++
 .../result/fid_bbi/searchspecs.yaml           | 501 ++++++++++++++++++
 .../Config/SearchSpecsReaderTest.php          |  93 ++++
 10 files changed, 1104 insertions(+), 487 deletions(-)
 create mode 100644 fid_bbi/alpha/config/vufind/searchspecs.yaml
 create mode 120000 module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/config/vufind/searchspecs.yaml
 create mode 120000 module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/alpha/config/vufind/searchspecs.yaml
 create mode 120000 module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/config/vufind/searchspecs.yaml
 create mode 120000 module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/alpha/config/vufind/searchspecs.yaml
 create mode 120000 module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/config/vufind/searchspecs.yaml
 create mode 100644 module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/alpha/searchspecs.yaml
 create mode 100644 module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/searchspecs.yaml
 create mode 100644 module/fid_bbi/tests/unit-tests/src/fid_bbiTest/Config/SearchSpecsReaderTest.php

diff --git a/fid_bbi/alpha/config/vufind/searchspecs.yaml b/fid_bbi/alpha/config/vufind/searchspecs.yaml
new file mode 100644
index 00000000000..0f5518b8304
--- /dev/null
+++ b/fid_bbi/alpha/config/vufind/searchspecs.yaml
@@ -0,0 +1,2 @@
+---
+"@parent_yaml": "../../../config/vufind/searchspecs.yaml"
\ No newline at end of file
diff --git a/fid_bbi/config/vufind/searchspecs.yaml b/fid_bbi/config/vufind/searchspecs.yaml
index 3fd1fbd46f1..2e121c3d2d9 100644
--- a/fid_bbi/config/vufind/searchspecs.yaml
+++ b/fid_bbi/config/vufind/searchspecs.yaml
@@ -150,466 +150,7 @@
 # See the CallNumber search below for an example of custom munging in action.
 #-----------------------------------------------------------------------------------
 
-# These searches use Dismax when possible:
-Author:
-  DismaxParams:
-    - [bf , ord(publishDateSort)^10]
-  DismaxFields:
-    - author^400
-    - author2^300
-    - author_id^100
-    - author_ref^150
-    - author_corporate^200
-    - author_corporate2^200
-    - author_orig^200
-    - author2_orig^200
-    - author_corporate_orig^200
-    - author_corporate2_orig^200
-    - author_fuller^50
-    - author2_fuller
-    - author_additional
-    - author_variant
-    - author2_variant
-  QueryFields:
-    author:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author_fuller:
-      - [onephrase, 200]
-      - [and, 100]
-      - [or, 50]
-    author2:
-      - [onephrase, 100]
-      - [and, 50]
-      - [or, ~]
-    author_ref:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author_corporate:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author_corporate2:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author_orig:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author2_orig:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author_corporate_orig:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author_corporate2_orig:
-      - [onephrase, 350]
-      - [and, 200]
-      - [or, 100]
-    author_id:
-      - [onephrase, 450]
-      - [and, 300]
-      - [or, 200]
-    author2_fuller:
-      - [onephrase, 100]
-      - [and, 50]
-      - [or, ~]
-    author_additional:
-      - [onephrase, 100]
-      - [and, 50]
-      - [or, ~]
-    author_variant:
-      - [onephrase, 100]
-      - [and, 50]
-      - [or, ~]
-    author2_variant:
-      - [onephrase, 100]
-      - [and, 50]
-      - [or, ~]
-
-ISN:
-  DismaxFields:
-    - isbn
-    - issn
-    - ismn
-  QueryFields:
-    issn:
-      - [and, 100]
-      - [or, ~]
-    isbn:
-      - [and, 100]
-      - [or, ~]
-    ismn:
-      - [and, 100]
-      - [or, ~]
-
-Signatur:
-#  DismaxParams:
-#    - [mm, 0]
-#  DismaxFields:
-#    - callnumber_ISIL
-  QueryFields:
-    callnumber_ISIL:
-      - [onephrase, 1000]
-      - [and, 100]
-      - [or, ~]
-
-Barcode:
-#  DismaxParams:
-#    - [mm, 0]
-#  DismaxFields:
-#    - barcode_ISIL
-  QueryFields:
-    barcode_ISIL:
-      - [onephrase, 1000]
-      - [and, 100]
-      - [or, ~]
-
-Subject:
-  DismaxFields:
-    - topic_unstemmed^150
-    - topic^100
-    - topic_id^100
-    - topic_ref^100
-    #- geographic^50
-    #- genre^50
-    #- era
-  QueryFields:
-    topic_unstemmed:
-      - [onephrase, 350]
-      - [and, 150]
-      - [or, ~]
-    topic:
-      - [onephrase, 300]
-      - [and, 100]
-      - [or, ~]
-    topic_ref:
-      - [onephrase, 100]
-      - [and, 50]
-      - [or, ~]
-    topic_id:
-      - [onephrase, 100]
-      - [and, 50]
-      - [or, ~]
-    #- geographic:
-    #  - [onephrase, 300]
-    #  - [and, 100]
-    #  - [or, ~]
-    #- genre:
-    #  - [onephrase, 300]
-    #  - [and, 100]
-    #  - [or, ~]
-    #- era:
-    #  - [and, 100]
-    #  - [or, ~]
-#  ExactSettings:
-#    DismaxFields:
-#      - topic_unstemmed^150
-#    QueryFields:
-#      - topic_unstemmed:
-#        - [onephrase, 350]
-#        - [and, 150]
-#        - [or, ~]
-
-# This field definition is a compromise that supports both journal-level and
-# article-level data.  The disadvantage is that hits in article titles will
-# be mixed in.  If you are building a purely article-oriented index, you should
-# customize this to remove all of the title_* fields and focus entirely on the
-# container_title field.
-JournalTitle:
-  DismaxFields:
-    - title_short^500
-    - title_full_unstemmed^450
-    - title_full^400
-    - title^300
-    - container_title^250
-    - title_alt^200
-    - title_new^100
-    - title_old
-    - series^100
-    - series2
-  QueryFields:
-    title_short:
-      - [onephrase, 500]
-    title_full_unstemmed:
-      - [onephrase, 450]
-      - [and, 400]
-    title_full:
-      - [onephrase, 400]
-    title:
-      - [onephrase, 300]
-      - [and, 250]
-    container_title:
-      - [onephrase, 275]
-      - [and, 225]
-    title_alt:
-      - [and, 200]
-    title_new:
-      - [and, 100]
-    title_old:
-      - [and, ~]  
-    series:
-      - [onephrase, 100]
-      - [and, 50]
-    series2:
-      - [onephrase, 50]
-      - [and , ~]
-  FilterQuery: "format:Journal OR format:Article OR format:ElectronicBookPart"
-#  ExactSettings:
-#    DismaxFields:
-#      - title_full_unstemmed^450
-#    QueryFields:
-#      - title_full_unstemmed:
-#        - [onephrase, 450]
-#        - [and, 400]
-#    FilterQuery: "format:Journal OR format:Article"
-
-Title:
-  DismaxParams:
-    - [mm, 3]
-    - [bf , ord(publishDateSort)^10]
-  DismaxFields:
-#    - title_sub^200
-#    - title_short^300
-    - title_full_unstemmed^150
-    - title_full^100
-    - title^900
-    - title_alt^200
-    - title_new^100
-    - title_old
-    - title_orig^400
-    - series^100
-    - series2
-    - series_orig^100
-  QueryFields:
-    title_short:
-      - [onephrase, 500]
-    title_full_unstemmed:
-      - [onephrase, 150]
-      - [and, 100]
-    title_full:
-      - [onephrase, 100]
-    title:
-      - [onephrase, 300]
-      - [and, 250]
-    title_alt:
-      - [and, 200]
-    title_new:
-      - [and, 100]
-    title_old:
-      - [and, ~]
-    title_orig:
-      - [onephrase, 500]
-      - [and, 200]
-    series:
-      - [onephrase, 100]
-      - [and, 50]
-    series2:
-      - [onephrase, 50]
-      - [and , ~]
-    series_orig:
-      - [onephrase, 100]
-      - [and, 50]
-#  ExactSettings:
-#    DismaxFields:
-#      - title_full_unstemmed^450
-#    QueryFields:
-#      - title_full_unstemmed:
-#        - [onephrase, 450]
-#        - [and, 400]
-
-Series:
-  DismaxFields:
-    - series^100
-    - series2
-    - series_orig^100
-  QueryFields:
-    series:
-      - [onephrase, 500]
-      - [and, 200]
-      - [or, 100]
-    series2:
-      - [onephrase, 50]
-      - [and, 50]
-      - [or, ~]
-    series_orig:
-      - [onephrase, 500]
-      - [and, 200]
-      - [or, 100]
-
-Series2:
-  DismaxFields:
-    - series2
-  QueryFields:
-    series2:
-      - [onephrase, 200]
-      - [and, 50]
-
-AllFields:
-  DismaxParams:
-    - [mm, 3]
-    - [bf , ord(publishDateSort)^10]
-#    - [bf , "if(exists(query({!v='source_id:0'})),10,1)^1000"]
-    - [bf, "if(exists(query({!v='access_facet:Local*'})),10,1)^1000"]
-  DismaxFields:
-    - title_short^1000
-    - title_full_unstemmed^1000
-    - title_full^400
-    - title^500
-    - title_alt^200
-    - title_new^100
-    - title_orig^500
-    - series^50
-    - series2^30
-    - series_orig^50
-    - author^500
-    - author_fuller^150
-    - author_corporate^300
-    - author2^400
-    - author_corporate2^100
-    - author_ref^500
-    - author_orig^300
-    - author2_orig^300
-    - author_corporate_orig^300
-    - author_corporate2_orig^100
-    - topic_ref^10
-    - contents^10
-    - topic_unstemmed^15
-    - topic^10
-    - geographic^10
-    - genre^10
-    - rvk_label
-    - allfields_unstemmed^10
-    - allfields
-    - fulltext
-    - isbn
-    - issn
-    - ismn
-
-  QueryFields:
-    0:
-      0:
-        - OR
-        - 50
-      title_short:
-        - [onephrase, 1000]
-      title_full_unstemmed:
-        - [onephrase, 1000]
-        - [and, 500]
-      title_full:
-        - [onephrase, 400]
-      title:
-        - [onephrase, 300]
-        - [and, 250]
-      title_alt:
-        - [and, 200]
-      title_new:
-        - [and, 100]
-      title_orig:
-        - [onephrase, 500]
-        - [and, 400]
-    series:
-      - [onephrase, 300]
-      - [and, 100]
-    series2:
-      - [and, 30]
-    series_orig:
-      - [onephrase, 200]
-      - [and, 100]
-    author:
-      - [onephrase, 500]
-      - [and, 250]
-    author_fuller:
-      - [onephrase, 150]
-      - [and, 125]
-    author_ref:
-      - [onephrase, 250]
-      - [and, 250]
-      - [or, 250]
-    author_orig:
-      - [onephrase, 500]
-      - [and, 250]
-    author2_orig:
-      - [and, 50]
-    author_corporate_orig:
-      - [onephrase, 500]
-      - [and, 400]
-    author_corporate2_orig:
-      - [and, 50]
-    author_corporate:
-      - [onephrase, 500]
-      - [and, 400]
-    author2:
-      - [and, 50]
-    author_additional:
-      - [and, 50]
-    author_corporate2:
-      - [and, 50]
-    contents:
-      - [and, 10]
-    topic_unstemmed:
-      - [onephrase, 55]
-      - [and, 50]
-    topic:
-      - [onephrase, 50]
-    topic_ref:
-      - [onephrase, 10]
-      - [and, 5]
-      - [or, 5]
-    topic_id:
-      - [onephrase, 50]
-      - [and, 25]
-    allfields_unstemmed:
-      - [or, 10]
-#    fulltext_unstemmed:
-#      - [or, 10]
-    allfields:
-      - [or, ~]
-    fulltext:
-      - [or, ~]
-#    description:
-#      - [or, ~]
-    rvk_label:
-      - [onephrase, 500]
-      - [and, 250]
-      - [or, 250]
-    isbn:
-      - [onephrase, 500]
-    issn:
-      - [onephrase, 500]
-    ismn:
-      - [onephrase, 500]
-    imprint:
-      - [onephrase, 500]
-
-#  ExactSettings:
-#    DismaxFields:
-#      - title_full_unstemmed^600
-#      - topic_unstemmed^550
-#      - allfields_unstemmed^10
-#      - fulltext_unstemmed^10
-#      - isbn
-#      - issn
-#    QueryFields:
-#      title_full_unstemmed:
-#        - [onephrase, 600]
-#        - [and, 500]
-#      topic_unstemmed:
-#        - [onephrase, 550]
-#        - [and, 500]
-#      allfields_unstemmed:
-#        - [or, 10]
-#      fulltext_unstemmed:
-#        - [or, 10]
-#      isbn:
-#        - [onephrase, ~]
-#      issn:
-#        - [onephrase, ~]
+"@parent_yaml": "../../../local/config/vufind/searchspecs.yaml"
 
 # These are advanced searches that never use Dismax:
 id:
@@ -750,30 +291,4 @@ oclc_num:
       - [preg_replace, "/^0*/", ""]
   QueryFields:
     oclc_num:
-      - [oclc_num, ~]
-      
-rvk:
-  DismaxFields:
-    - rvk_facet^100
-  QueryFields:
-    rvk_facet:
-      - [and, 50]
-      - [or, 50]
-      
-rvk_path:
-  QueryFields:
-    rvk_path:
-      - [onephrase, ~]
-
-multipart:
-  DismaxFields:
-    - multipart_link^100
-  QueryFields:
-    multipart_link:
-      - [and, 50]
-      - [or, 50]  
-
-titleUniform:
-  QueryFields:
-    title_id_str_mv:
-      - [onephrase, ~]
\ No newline at end of file
+      - [oclc_num, ~]
\ No newline at end of file
diff --git a/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/config/vufind/searchspecs.yaml b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/config/vufind/searchspecs.yaml
new file mode 120000
index 00000000000..183f7ab71ef
--- /dev/null
+++ b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/config/vufind/searchspecs.yaml
@@ -0,0 +1 @@
+../../../../../../../../../config/vufind/searchspecs.yaml
\ No newline at end of file
diff --git a/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/alpha/config/vufind/searchspecs.yaml b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/alpha/config/vufind/searchspecs.yaml
new file mode 120000
index 00000000000..7dcf075da82
--- /dev/null
+++ b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/alpha/config/vufind/searchspecs.yaml
@@ -0,0 +1 @@
+../../../../../../../../../../../fid_bbi/alpha/config/vufind/searchspecs.yaml
\ No newline at end of file
diff --git a/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/config/vufind/searchspecs.yaml b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/config/vufind/searchspecs.yaml
new file mode 120000
index 00000000000..5d440a8714a
--- /dev/null
+++ b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/fid_bbi/config/vufind/searchspecs.yaml
@@ -0,0 +1 @@
+../../../../../../../../../../fid_bbi/config/vufind/searchspecs.yaml
\ No newline at end of file
diff --git a/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/alpha/config/vufind/searchspecs.yaml b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/alpha/config/vufind/searchspecs.yaml
new file mode 120000
index 00000000000..59ae9378e2e
--- /dev/null
+++ b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/alpha/config/vufind/searchspecs.yaml
@@ -0,0 +1 @@
+../../../../../../../../../../../local/alpha/config/vufind/searchspecs.yaml
\ No newline at end of file
diff --git a/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/config/vufind/searchspecs.yaml b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/config/vufind/searchspecs.yaml
new file mode 120000
index 00000000000..74dc0578aea
--- /dev/null
+++ b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/local/config/vufind/searchspecs.yaml
@@ -0,0 +1 @@
+../../../../../../../../../../local/config/vufind/searchspecs.yaml
\ No newline at end of file
diff --git a/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/alpha/searchspecs.yaml b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/alpha/searchspecs.yaml
new file mode 100644
index 00000000000..dcbbd065000
--- /dev/null
+++ b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/alpha/searchspecs.yaml
@@ -0,0 +1,501 @@
+Author:
+  DismaxParams:
+    -
+      - bf
+      - ord(publishDateSort)^10
+  DismaxFields:
+    - author^400
+    - author2^300
+    - author_id^100
+    - author_ref^150
+    - author_corporate^200
+    - author_corporate2^200
+    - author_orig^200
+    - author2_orig^200
+    - author_corporate_orig^200
+    - author_corporate2_orig^200
+    - author_fuller^50
+    - author2_fuller
+    - author_additional
+    - author_variant
+    - author2_variant
+  QueryFields:
+    author:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_fuller:
+      - [onephrase, 200]
+      - [and, 100]
+      - [or, 50]
+    author2:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author_ref:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate2:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_id:
+      - [onephrase, 450]
+      - [and, 300]
+      - [or, 200]
+    author2_fuller:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author_additional:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author_variant:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author2_variant:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+ISN:
+  DismaxFields:
+    - isbn
+    - issn
+    - ismn
+  QueryFields:
+    issn:
+      - [and, 100]
+      - [or, null]
+    isbn:
+      - [and, 100]
+      - [or, null]
+    ismn:
+      - [and, 100]
+      - [or, null]
+Signatur:
+  QueryFields:
+    callnumber_ISIL:
+      - [onephrase, 1000]
+      - [and, 100]
+      - [or, null]
+Barcode:
+  QueryFields:
+    barcode_ISIL:
+      - [onephrase, 1000]
+      - [and, 100]
+      - [or, null]
+Subject:
+  DismaxFields:
+    - topic_unstemmed^150
+    - topic^100
+    - topic_id^100
+    - topic_ref^100
+  QueryFields:
+    topic_unstemmed:
+      - [onephrase, 350]
+      - [and, 150]
+      - [or, null]
+    topic:
+      - [onephrase, 300]
+      - [and, 100]
+      - [or, null]
+    topic_ref:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    topic_id:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+JournalTitle:
+  DismaxFields:
+    - title_short^500
+    - title_full_unstemmed^450
+    - title_full^400
+    - title^300
+    - container_title^250
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - series^100
+    - series2
+  QueryFields:
+    title_short:
+      - [onephrase, 500]
+    title_full_unstemmed:
+      - [onephrase, 450]
+      - [and, 400]
+    title_full:
+      - [onephrase, 400]
+    title:
+      - [onephrase, 300]
+      - [and, 250]
+    container_title:
+      - [onephrase, 275]
+      - [and, 225]
+    title_alt:
+      - [and, 200]
+    title_new:
+      - [and, 100]
+    title_old:
+      - [and, null]
+    series:
+      - [onephrase, 100]
+      - [and, 50]
+    series2:
+      - [onephrase, 50]
+      - [and, null]
+  FilterQuery: 'format:Journal OR format:Article OR format:ElectronicBookPart'
+Title:
+  DismaxParams:
+    -
+      - mm
+      - 3
+    -
+      - bf
+      - ord(publishDateSort)^10
+  DismaxFields:
+    - title_full_unstemmed^150
+    - title_full^100
+    - title^900
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - title_orig^400
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    title_short:
+      - [onephrase, 500]
+    title_full_unstemmed:
+      - [onephrase, 150]
+      - [and, 100]
+    title_full:
+      - [onephrase, 100]
+    title:
+      - [onephrase, 300]
+      - [and, 250]
+    title_alt:
+      - [and, 200]
+    title_new:
+      - [and, 100]
+    title_old:
+      - [and, null]
+    title_orig:
+      - [onephrase, 500]
+      - [and, 200]
+    series:
+      - [onephrase, 100]
+      - [and, 50]
+    series2:
+      - [onephrase, 50]
+      - [and, null]
+    series_orig:
+      - [onephrase, 100]
+      - [and, 50]
+Series:
+  DismaxFields:
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    series:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+    series2:
+      - [onephrase, 50]
+      - [and, 50]
+      - [or, null]
+    series_orig:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+Series2:
+  DismaxFields:
+    - series2
+  QueryFields:
+    series2:
+      - [onephrase, 200]
+      - [and, 50]
+AllFields:
+  DismaxParams:
+    -
+      - mm
+      - 3
+    -
+      - bf
+      - ord(publishDateSort)^10
+    -
+      - bf
+      - 'if(exists(query({!v=''facet_avail:Local*''})),10,1)^1000'
+  DismaxFields:
+    - title_short^1000
+    - title_full_unstemmed^1000
+    - title_full^400
+    - title^500
+    - title_alt^200
+    - title_new^100
+    - title_orig^500
+    - series^50
+    - series2^30
+    - series_orig^50
+    - author^500
+    - author_fuller^150
+    - author_corporate^300
+    - author2^400
+    - author_corporate2^100
+    - author_ref^500
+    - author_orig^300
+    - author2_orig^300
+    - author_corporate_orig^300
+    - author_corporate2_orig^100
+    - topic_ref^10
+    - contents^10
+    - topic_unstemmed^15
+    - topic^10
+    - geographic^10
+    - genre^10
+    - rvk_label
+    - allfields_unstemmed^10
+    - allfields
+    - fulltext
+    - isbn
+    - issn
+    - ismn
+  QueryFields:
+    0:
+      0: [OR, 50]
+      title_short: [[onephrase, 1000]]
+      title_full_unstemmed: [[onephrase, 1000], [and, 500]]
+      title_full: [[onephrase, 400]]
+      title: [[onephrase, 300], [and, 250]]
+      title_alt: [[and, 200]]
+      title_new: [[and, 100]]
+      title_orig: [[onephrase, 500], [and, 400]]
+    series:
+      - [onephrase, 300]
+      - [and, 100]
+    series2:
+      - [and, 30]
+    series_orig:
+      - [onephrase, 200]
+      - [and, 100]
+    author:
+      - [onephrase, 500]
+      - [and, 250]
+    author_fuller:
+      - [onephrase, 150]
+      - [and, 125]
+    author_ref:
+      - [onephrase, 250]
+      - [and, 250]
+      - [or, 250]
+    author_orig:
+      - [onephrase, 500]
+      - [and, 250]
+    author2_orig:
+      - [and, 50]
+    author_corporate_orig:
+      - [onephrase, 500]
+      - [and, 400]
+    author_corporate2_orig:
+      - [and, 50]
+    author_corporate:
+      - [onephrase, 500]
+      - [and, 400]
+    author2:
+      - [and, 50]
+    author_additional:
+      - [and, 50]
+    author_corporate2:
+      - [and, 50]
+    contents:
+      - [and, 10]
+    topic_unstemmed:
+      - [onephrase, 55]
+      - [and, 50]
+    topic:
+      - [onephrase, 50]
+    topic_ref:
+      - [onephrase, 10]
+      - [and, 5]
+      - [or, 5]
+    topic_id:
+      - [onephrase, 50]
+      - [and, 25]
+    allfields_unstemmed:
+      - [or, 10]
+    allfields:
+      - [or, null]
+    fulltext:
+      - [or, null]
+    rvk_label:
+      - [onephrase, 500]
+      - [and, 250]
+      - [or, 250]
+    isbn:
+      - [onephrase, 500]
+    issn:
+      - [onephrase, 500]
+    ismn:
+      - [onephrase, 500]
+    imprint:
+      - [onephrase, 500]
+id:
+  QueryFields:
+    id:
+      - [onephrase, null]
+ParentID:
+  QueryFields:
+    hierarchy_parent_id:
+      - [onephrase, null]
+ids:
+  QueryFields:
+    id:
+      - [or, null]
+TopicBrowse:
+  QueryFields:
+    topic_browse:
+      - [onephrase, null]
+AuthorBrowse:
+  QueryFields:
+    author_browse:
+      - [onephrase, null]
+TitleBrowse:
+  QueryFields:
+    title_full:
+      - [onephrase, null]
+DeweyBrowse:
+  QueryFields:
+    dewey-raw:
+      - [onephrase, null]
+LccBrowse:
+  QueryFields:
+    callnumber-a:
+      - [onephrase, null]
+publisher:
+  DismaxFields:
+    - publisher^100
+  QueryFields:
+    publisher:
+      - [and, 100]
+      - [or, null]
+year:
+  DismaxFields:
+    - publishDate^100
+  QueryFields:
+    publishDate:
+      - [and, 100]
+      - [or, null]
+language:
+  QueryFields:
+    language:
+      - [and, null]
+toc:
+  DismaxFields:
+    - contents^100
+  QueryFields:
+    contents:
+      - [and, 100]
+      - [or, null]
+topic:
+  QueryFields:
+    topic:
+      - [and, 50]
+    topic_facet:
+      - [and, null]
+geographic:
+  QueryFields:
+    geographic:
+      - [and, 50]
+    geographic_facet:
+      - [and, null]
+genre:
+  QueryFields:
+    genre:
+      - [and, 50]
+    genre_facet:
+      - [and, null]
+era:
+  QueryFields:
+    era:
+      - [and, null]
+oclc_num:
+  CustomMunge:
+    oclc_num:
+      - [preg_replace, '/[^0-9]/', '']
+      - [preg_replace, '/^0*/', '']
+  QueryFields:
+    oclc_num:
+      - [oclc_num, null]
+rvk:
+  DismaxFields:
+    - rvk_facet^100
+  QueryFields:
+    rvk_facet:
+      - [and, 50]
+      - [or, 50]
+rvk_path:
+  QueryFields:
+    rvk_path:
+      - [onephrase, null]
+multipart:
+  DismaxFields:
+    - multipart_link^100
+  QueryFields:
+    multipart_link:
+      - [and, 50]
+      - [or, 50]
+titleUniform:
+  QueryFields:
+    title_id_str_mv:
+      - [onephrase, null]
+Coordinate:
+  DismaxFields:
+    - long_lat_display
+  DismaxHandler: edismax
+CallNumber:
+  CustomMunge:
+    callnumber_exact:
+      - [preg_replace, '/[ "]/', '']
+      - [preg_replace, '/(\\:)/', ':']
+      - [preg_replace, '/:/', '\:']
+      - [preg_replace, '/\*+$/', '']
+    callnumber_fuzzy:
+      - [preg_replace, '/[ "]/', '']
+      - [preg_replace, '/(\\:)/', ':']
+      - [preg_replace, '/:/', '\:']
+      - [preg_replace, '/\*+$/', '']
+      - [append, '*']
+  QueryFields:
+    callnumber-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, null]
+    dewey-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, null]
\ No newline at end of file
diff --git a/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/searchspecs.yaml b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/searchspecs.yaml
new file mode 100644
index 00000000000..1e8bfdcad8d
--- /dev/null
+++ b/module/fid_bbi/tests/fixtures/configs/yaml/searchspecs/result/fid_bbi/searchspecs.yaml
@@ -0,0 +1,501 @@
+Author:
+  DismaxParams:
+    -
+      - bf
+      - ord(publishDateSort)^10
+  DismaxFields:
+    - author^400
+    - author2^300
+    - author_id^100
+    - author_ref^150
+    - author_corporate^200
+    - author_corporate2^200
+    - author_orig^200
+    - author2_orig^200
+    - author_corporate_orig^200
+    - author_corporate2_orig^200
+    - author_fuller^50
+    - author2_fuller
+    - author_additional
+    - author_variant
+    - author2_variant
+  QueryFields:
+    author:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_fuller:
+      - [onephrase, 200]
+      - [and, 100]
+      - [or, 50]
+    author2:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author_ref:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate2:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_corporate2_orig:
+      - [onephrase, 350]
+      - [and, 200]
+      - [or, 100]
+    author_id:
+      - [onephrase, 450]
+      - [and, 300]
+      - [or, 200]
+    author2_fuller:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author_additional:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author_variant:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    author2_variant:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+ISN:
+  DismaxFields:
+    - isbn
+    - issn
+    - ismn
+  QueryFields:
+    issn:
+      - [and, 100]
+      - [or, null]
+    isbn:
+      - [and, 100]
+      - [or, null]
+    ismn:
+      - [and, 100]
+      - [or, null]
+Signatur:
+  QueryFields:
+    callnumber_ISIL:
+      - [onephrase, 1000]
+      - [and, 100]
+      - [or, null]
+Barcode:
+  QueryFields:
+    barcode_ISIL:
+      - [onephrase, 1000]
+      - [and, 100]
+      - [or, null]
+Subject:
+  DismaxFields:
+    - topic_unstemmed^150
+    - topic^100
+    - topic_id^100
+    - topic_ref^100
+  QueryFields:
+    topic_unstemmed:
+      - [onephrase, 350]
+      - [and, 150]
+      - [or, null]
+    topic:
+      - [onephrase, 300]
+      - [and, 100]
+      - [or, null]
+    topic_ref:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+    topic_id:
+      - [onephrase, 100]
+      - [and, 50]
+      - [or, null]
+JournalTitle:
+  DismaxFields:
+    - title_short^500
+    - title_full_unstemmed^450
+    - title_full^400
+    - title^300
+    - container_title^250
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - series^100
+    - series2
+  QueryFields:
+    title_short:
+      - [onephrase, 500]
+    title_full_unstemmed:
+      - [onephrase, 450]
+      - [and, 400]
+    title_full:
+      - [onephrase, 400]
+    title:
+      - [onephrase, 300]
+      - [and, 250]
+    container_title:
+      - [onephrase, 275]
+      - [and, 225]
+    title_alt:
+      - [and, 200]
+    title_new:
+      - [and, 100]
+    title_old:
+      - [and, null]
+    series:
+      - [onephrase, 100]
+      - [and, 50]
+    series2:
+      - [onephrase, 50]
+      - [and, null]
+  FilterQuery: 'format:Journal OR format:Article OR format:ElectronicBookPart'
+Title:
+  DismaxParams:
+    -
+      - mm
+      - 3
+    -
+      - bf
+      - ord(publishDateSort)^10
+  DismaxFields:
+    - title_full_unstemmed^150
+    - title_full^100
+    - title^900
+    - title_alt^200
+    - title_new^100
+    - title_old
+    - title_orig^400
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    title_short:
+      - [onephrase, 500]
+    title_full_unstemmed:
+      - [onephrase, 150]
+      - [and, 100]
+    title_full:
+      - [onephrase, 100]
+    title:
+      - [onephrase, 300]
+      - [and, 250]
+    title_alt:
+      - [and, 200]
+    title_new:
+      - [and, 100]
+    title_old:
+      - [and, null]
+    title_orig:
+      - [onephrase, 500]
+      - [and, 200]
+    series:
+      - [onephrase, 100]
+      - [and, 50]
+    series2:
+      - [onephrase, 50]
+      - [and, null]
+    series_orig:
+      - [onephrase, 100]
+      - [and, 50]
+Series:
+  DismaxFields:
+    - series^100
+    - series2
+    - series_orig^100
+  QueryFields:
+    series:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+    series2:
+      - [onephrase, 50]
+      - [and, 50]
+      - [or, null]
+    series_orig:
+      - [onephrase, 500]
+      - [and, 200]
+      - [or, 100]
+Series2:
+  DismaxFields:
+    - series2
+  QueryFields:
+    series2:
+      - [onephrase, 200]
+      - [and, 50]
+AllFields:
+  DismaxParams:
+    -
+      - mm
+      - 3
+    -
+      - bf
+      - ord(publishDateSort)^10
+    -
+      - bf
+      - 'if(exists(query({!v=''facet_avail:Local*''})),10,1)^1000'
+  DismaxFields:
+    - title_short^1000
+    - title_full_unstemmed^1000
+    - title_full^400
+    - title^500
+    - title_alt^200
+    - title_new^100
+    - title_orig^500
+    - series^50
+    - series2^30
+    - series_orig^50
+    - author^500
+    - author_fuller^150
+    - author_corporate^300
+    - author2^400
+    - author_corporate2^100
+    - author_ref^500
+    - author_orig^300
+    - author2_orig^300
+    - author_corporate_orig^300
+    - author_corporate2_orig^100
+    - topic_ref^10
+    - contents^10
+    - topic_unstemmed^15
+    - topic^10
+    - geographic^10
+    - genre^10
+    - rvk_label
+    - allfields_unstemmed^10
+    - allfields
+    - fulltext
+    - isbn
+    - issn
+    - ismn
+  QueryFields:
+    0:
+      0: [OR, 50]
+      title_short: [[onephrase, 1000]]
+      title_full_unstemmed: [[onephrase, 1000], [and, 500]]
+      title_full: [[onephrase, 400]]
+      title: [[onephrase, 300], [and, 250]]
+      title_alt: [[and, 200]]
+      title_new: [[and, 100]]
+      title_orig: [[onephrase, 500], [and, 400]]
+    series:
+      - [onephrase, 300]
+      - [and, 100]
+    series2:
+      - [and, 30]
+    series_orig:
+      - [onephrase, 200]
+      - [and, 100]
+    author:
+      - [onephrase, 500]
+      - [and, 250]
+    author_fuller:
+      - [onephrase, 150]
+      - [and, 125]
+    author_ref:
+      - [onephrase, 250]
+      - [and, 250]
+      - [or, 250]
+    author_orig:
+      - [onephrase, 500]
+      - [and, 250]
+    author2_orig:
+      - [and, 50]
+    author_corporate_orig:
+      - [onephrase, 500]
+      - [and, 400]
+    author_corporate2_orig:
+      - [and, 50]
+    author_corporate:
+      - [onephrase, 500]
+      - [and, 400]
+    author2:
+      - [and, 50]
+    author_additional:
+      - [and, 50]
+    author_corporate2:
+      - [and, 50]
+    contents:
+      - [and, 10]
+    topic_unstemmed:
+      - [onephrase, 55]
+      - [and, 50]
+    topic:
+      - [onephrase, 50]
+    topic_ref:
+      - [onephrase, 10]
+      - [and, 5]
+      - [or, 5]
+    topic_id:
+      - [onephrase, 50]
+      - [and, 25]
+    allfields_unstemmed:
+      - [or, 10]
+    allfields:
+      - [or, null]
+    fulltext:
+      - [or, null]
+    rvk_label:
+      - [onephrase, 500]
+      - [and, 250]
+      - [or, 250]
+    isbn:
+      - [onephrase, 500]
+    issn:
+      - [onephrase, 500]
+    ismn:
+      - [onephrase, 500]
+    imprint:
+      - [onephrase, 500]
+id:
+  QueryFields:
+    id:
+      - [onephrase, null]
+ParentID:
+  QueryFields:
+    hierarchy_parent_id:
+      - [onephrase, null]
+ids:
+  QueryFields:
+    id:
+      - [or, null]
+TopicBrowse:
+  QueryFields:
+    topic_browse:
+      - [onephrase, null]
+AuthorBrowse:
+  QueryFields:
+    author_browse:
+      - [onephrase, null]
+TitleBrowse:
+  QueryFields:
+    title_full:
+      - [onephrase, null]
+DeweyBrowse:
+  QueryFields:
+    dewey-raw:
+      - [onephrase, null]
+LccBrowse:
+  QueryFields:
+    callnumber-a:
+      - [onephrase, null]
+publisher:
+  DismaxFields:
+    - publisher^100
+  QueryFields:
+    publisher:
+      - [and, 100]
+      - [or, null]
+year:
+  DismaxFields:
+    - publishDate^100
+  QueryFields:
+    publishDate:
+      - [and, 100]
+      - [or, null]
+language:
+  QueryFields:
+    language:
+      - [and, null]
+toc:
+  DismaxFields:
+    - contents^100
+  QueryFields:
+    contents:
+      - [and, 100]
+      - [or, null]
+topic:
+  QueryFields:
+    topic:
+      - [and, 50]
+    topic_facet:
+      - [and, null]
+geographic:
+  QueryFields:
+    geographic:
+      - [and, 50]
+    geographic_facet:
+      - [and, null]
+genre:
+  QueryFields:
+    genre:
+      - [and, 50]
+    genre_facet:
+      - [and, null]
+era:
+  QueryFields:
+    era:
+      - [and, null]
+oclc_num:
+  CustomMunge:
+    oclc_num:
+      - [preg_replace, '/[^0-9]/', '']
+      - [preg_replace, '/^0*/', '']
+  QueryFields:
+    oclc_num:
+      - [oclc_num, null]
+rvk:
+  DismaxFields:
+    - rvk_facet^100
+  QueryFields:
+    rvk_facet:
+      - [and, 50]
+      - [or, 50]
+rvk_path:
+  QueryFields:
+    rvk_path:
+      - [onephrase, null]
+multipart:
+  DismaxFields:
+    - multipart_link^100
+  QueryFields:
+    multipart_link:
+      - [and, 50]
+      - [or, 50]
+titleUniform:
+  QueryFields:
+    title_id_str_mv:
+      - [onephrase, null]
+Coordinate:
+  DismaxFields:
+    - long_lat_display
+  DismaxHandler: edismax
+CallNumber:
+  CustomMunge:
+    callnumber_exact:
+      - [preg_replace, '/[ "]/', '']
+      - [preg_replace, '/(\\:)/', ':']
+      - [preg_replace, '/:/', '\:']
+      - [preg_replace, '/\*+$/', '']
+    callnumber_fuzzy:
+      - [preg_replace, '/[ "]/', '']
+      - [preg_replace, '/(\\:)/', ':']
+      - [preg_replace, '/:/', '\:']
+      - [preg_replace, '/\*+$/', '']
+      - [append, '*']
+  QueryFields:
+    callnumber-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, null]
+    dewey-search:
+      - [callnumber_exact, 1000]
+      - [callnumber_fuzzy, null]
diff --git a/module/fid_bbi/tests/unit-tests/src/fid_bbiTest/Config/SearchSpecsReaderTest.php b/module/fid_bbi/tests/unit-tests/src/fid_bbiTest/Config/SearchSpecsReaderTest.php
new file mode 100644
index 00000000000..daaf91d523d
--- /dev/null
+++ b/module/fid_bbi/tests/unit-tests/src/fid_bbiTest/Config/SearchSpecsReaderTest.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Config SearchSpecsReader Test Class
+ *
+ * PHP version 7
+ *
+ * Copyright (C) Villanova University 2010.
+ * Copyright (C) Leipzig University Library 2020.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category Finc
+ * @package  Tests
+ * @author   Robert Lange <lange@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+namespace fid_bbiTest\Config;
+
+use fincTest\Config\SearchSpecsReaderTest as FincSearchSpecsReaderTest;
+
+/**
+ * Config SearchSpecsReader Test Class
+ *
+ * @category VuFind
+ * @package  Tests
+ * @author   Robert Lange <lange@ub.uni-leipzig.de>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     https://vufind.org/wiki/development:testing:unit_tests Wiki
+ */
+class SearchSpecsReaderTest extends FincSearchSpecsReaderTest
+{
+    /**
+     * Name of default yaml name to test.
+     *
+     * @var string
+     */
+    protected static $defaultYamlName = 'searchspecs.yaml';
+
+    /**
+     * Test @parent_yaml directive.
+     *
+     * @return void
+     */
+    public function testParentYaml()
+    {
+        if (self::$writeFailed) {
+            $this->markTestSkipped('Could not write test configurations.');
+        }
+
+        $this->basePathToFixtures = __DIR__ . "/../../../../fixtures/configs/yaml/searchspecs";
+        $this->basePathToLogging = __DIR__ . "/log";
+
+        /* check if live instance searchspecs.yaml is equal to old /desired live searchspecs.yaml */
+        $this->isEcpectedSpec('fid_bbi', false);
+
+        /* check if alpha instance searchspecs.yaml is equal to old /desired alpha searchspecs.yaml */
+        $this->isEcpectedSpec('fid_bbi/alpha', false);
+    }
+
+    /**
+     * Override Vufind testSearchSpecsRead
+     *
+     * searchspecs.yaml file should define author dismax fields
+     * @return void
+     */
+    public function testSearchSpecsRead()
+    {
+        $this->basePathToFixtures = __DIR__ . "/../../../../fixtures/configs/yaml/searchspecs";
+        $this->basePathToLogging = __DIR__ . "/log";
+        $basePathAppendix = "config/vufind/" . self::$defaultYamlName;
+
+        $vufindYaml = "$this->basePathToFixtures/$basePathAppendix";
+        $currentEnvYaml = "$this->basePathToFixtures/fid_bbi/$basePathAppendix";
+
+        $specs = $this->callMethod(self::$reader, 'getFromPaths', [$vufindYaml, $currentEnvYaml]);
+
+        $this->assertTrue(
+      isset($specs['Author']['DismaxFields']) && !empty($specs['Author']['DismaxFields'])
+        );
+    }
+}
-- 
GitLab