diff --git a/module/VuFind/src/VuFind/Config/SearchSpecsReader.php b/module/VuFind/src/VuFind/Config/SearchSpecsReader.php index 3398214c76cc393813ff1c10d40a808f1a726e84..8bc6b752e9fca8f11b684477c7e5ba47582a8834 100644 --- a/module/VuFind/src/VuFind/Config/SearchSpecsReader.php +++ b/module/VuFind/src/VuFind/Config/SearchSpecsReader.php @@ -74,39 +74,75 @@ class SearchSpecsReader { // Load data if it is not already in the object's cache: if (!isset($this->searchSpecs[$filename])) { - // Connect to searchspecs cache: - $cache = (null !== $this->cacheManager) - ? $this->cacheManager->getCache('searchspecs') : false; + $this->searchSpecs[$filename] = $this->getFromPaths( + Locator::getBaseConfigPath($filename), + Locator::getLocalConfigPath($filename) + ); + } + + return $this->searchSpecs[$filename]; + } + + /** + * Given core and local filenames, retrieve the searchspecs data. + * + * @param string $defaultFile Full path to file containing default YAML + * @param string $customFile Full path to file containing local customizations + * (may be null if no local file exists). + * + * @return array + */ + protected function getFromPaths($defaultFile, $customFile = null) + { + // Connect to searchspecs cache: + $cache = (null !== $this->cacheManager) + ? $this->cacheManager->getCache('searchspecs') : false; - // Determine full configuration file path: - $fullpath = Locator::getBaseConfigPath($filename); - $local = Locator::getLocalConfigPath($filename); + // Generate cache key: + $cacheKey = basename($defaultFile) . '-' + . (file_exists($defaultFile) ? filemtime($defaultFile) : 0); + if (!empty($customFile)) { + $cacheKey .= '-local-' . filemtime($customFile); + } + $cacheKey = md5($cacheKey); - // Generate cache key: - $cacheKey = $filename . '-' - . (file_exists($fullpath) ? filemtime($fullpath) : 0); - if (!empty($local)) { - $cacheKey .= '-local-' . filemtime($local); + // Generate data if not found in cache: + if ($cache === false || !($results = $cache->getItem($cacheKey))) { + $results = $this->parseYaml($customFile, $defaultFile); + if ($cache !== false) { + $cache->setItem($cacheKey, $results); } - $cacheKey = md5($cacheKey); + } - // Generate data if not found in cache: - if ($cache === false || !($results = $cache->getItem($cacheKey))) { - $results = file_exists($fullpath) - ? Yaml::parse(file_get_contents($fullpath)) : []; - if (!empty($local)) { - $localResults = Yaml::parse(file_get_contents($local)); - foreach ($localResults as $key => $value) { - $results[$key] = $value; - } - } - if ($cache !== false) { - $cache->setItem($cacheKey, $results); + return $results; + } + + /** + * Process a YAML file (and its parent, if necessary). + * + * @param string $file YAML file to load (will evaluate to empty array + * if file does not exist). + * @param string $defaultParent Parent YAML file from which $file should + * inherit (unless overridden by a specific directive in $file). None by + * default. + * + * @return array + */ + protected function parseYaml($file, $defaultParent = null) + { + // First load current file: + $results = (!empty($file) && file_exists($file)) + ? Yaml::parse(file_get_contents($file)) : []; + + // Now load in missing sections from parent, if applicable: + if (null !== $defaultParent) { + foreach ($this->parseYaml($defaultParent) as $section => $contents) { + if (!isset($results[$section])) { + $results[$section] = $contents; } } - $this->searchSpecs[$filename] = $results; } - return $this->searchSpecs[$filename]; + return $results; } } diff --git a/module/VuFind/tests/fixtures/configs/yaml/core.yaml b/module/VuFind/tests/fixtures/configs/yaml/core.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6662da1d1c2c2596955134fdecc36ad746915154 --- /dev/null +++ b/module/VuFind/tests/fixtures/configs/yaml/core.yaml @@ -0,0 +1,4 @@ +top: + foo: "bar" +bottom: + goo: "gar" \ No newline at end of file diff --git a/module/VuFind/tests/fixtures/configs/yaml/local.yaml b/module/VuFind/tests/fixtures/configs/yaml/local.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5dbebb0f4d97cfcec662d23980fca8fadb39e21c --- /dev/null +++ b/module/VuFind/tests/fixtures/configs/yaml/local.yaml @@ -0,0 +1,4 @@ +top: + foo: "xyzzy" +middle: + moo: "cow" \ No newline at end of file diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php index 10dea204f4f736ae1cd1c03d2dcb7a15b69d85df..ce7e7fdf408c907e239bc3c520b2b6db762f9826 100644 --- a/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Config/SearchSpecsReaderTest.php @@ -68,4 +68,50 @@ class SearchSpecsReaderTest extends \VuFindTest\Unit\TestCase $specs = $reader->get('notreallyasearchspecs.yaml'); $this->assertEquals([], $specs); } + + /** + * Test direct loading of two single files. + * + * @return void + */ + public function testYamlLoad() + { + $reader = new SearchSpecsReader(); + $core = __DIR__ . '/../../../../fixtures/configs/yaml/core.yaml'; + $local = __DIR__ . '/../../../../fixtures/configs/yaml/local.yaml'; + $this->assertEquals( + [ + 'top' => ['foo' => 'bar'], + 'bottom' => ['goo' => 'gar'], + ], + $this->callMethod($reader, 'getFromPaths', [$core]) + ); + $this->assertEquals( + [ + 'top' => ['foo' => 'xyzzy'], + 'middle' => ['moo' => 'cow'], + ], + $this->callMethod($reader, 'getFromPaths', [$local]) + ); + } + + /** + * Test merging of two files. + * + * @return void + */ + public function testYamlMerge() + { + $reader = new SearchSpecsReader(); + $core = __DIR__ . '/../../../../fixtures/configs/yaml/core.yaml'; + $local = __DIR__ . '/../../../../fixtures/configs/yaml/local.yaml'; + $this->assertEquals( + [ + 'top' => ['foo' => 'xyzzy'], + 'middle' => ['moo' => 'cow'], + 'bottom' => ['goo' => 'gar'], + ], + $this->callMethod($reader, 'getFromPaths', [$core, $local]) + ); + } }