diff --git a/module/VuFind/src/VuFind/Search/QueryAdapter.php b/module/VuFind/src/VuFind/Search/QueryAdapter.php index 10dfb625121f20374ffe562d5246281c73df732f..80b178b75f004c77ce311d3c8a557bf881cb135f 100644 --- a/module/VuFind/src/VuFind/Search/QueryAdapter.php +++ b/module/VuFind/src/VuFind/Search/QueryAdapter.php @@ -248,6 +248,13 @@ abstract class QueryAdapter 'b' => $operator ]; if (null !== ($op = $current->getOperator())) { + // Some search forms omit the operator for the first element; + // if we have an operator in a subsequent element, we should + // backfill a blank here for consistency; otherwise, VuFind + // may not construct correct search URLs. + if (isset($retVal[0]['f']) && !isset($retVal[0]['o'])) { + $retVal[0]['o'] = ''; + } $currentArr['o'] = $op; } $retVal[] = $currentArr; diff --git a/module/VuFind/tests/fixtures/searches/operators b/module/VuFind/tests/fixtures/searches/operators new file mode 100644 index 0000000000000000000000000000000000000000..f6c06e3ddfa1599112b278bda9d61796d1a49f8f Binary files /dev/null and b/module/VuFind/tests/fixtures/searches/operators differ diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php index 9ab9c5e3c92b54618a6b34ff5312907a83bf19ba..238a939f3493d8fc3ccdc308cb3f22585a0dee45 100644 --- a/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Search/QueryAdapterTest.php @@ -65,6 +65,36 @@ class QueryAdapterTest extends TestCase } } + /** + * Test that when one part of the query contains an operator, ALL parts of the + * query contain an operator. (We want to be sure that in cases where the first + * part of the query has no operator associated with it, a blank value is filled + * in as a placeholder. + * + * @return void + */ + public function testOperatorDefinedEverywhere() + { + $fixturePath = realpath(__DIR__ . '/../../../../fixtures/searches') . '/'; + $q = unserialize(file_get_contents($fixturePath . '/operators')); + $minified = QueryAdapter::minify($q); + + // First, check that count of 'o' values matches count of queries in group: + $callback = function ($carry, $item) { + return $carry + (isset($item['o']) ? 1 : 0); + }; + $this->assertEquals( + count($minified[0]['g']), + array_reduce($minified[0]['g'], $callback, 0) + ); + + // Next, confirm that first operator is set to empty (filler) value: + $this->assertEquals('', $minified[0]['g'][0]['o']); + + // Finally, make sure that we can round-trip back to the input. + $this->assertEquals($q, QueryAdapter::deminify($minified)); + } + /** * Test building an advanced query from a request. *