diff --git a/module/AutocompleteTerms/Module.php b/module/AutocompleteTerms/Module.php new file mode 100644 index 0000000000..a027fa5ebe --- /dev/null +++ b/module/AutocompleteTerms/Module.php @@ -0,0 +1,92 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/dmj/vf2-proxy + */ +namespace AutocompleteTerms; +use Zend\ModuleManager\ModuleManager, + Zend\Mvc\MvcEvent; + +/** + * Template for ZF2 module for storing local overrides. + * + * @category VuFind2 + * @package Module + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/dmj/vf2-proxy + */ +class Module +{ + /** + * Get module configuration + * + * @return array + */ + public function getConfig() + { + return include __DIR__ . '/config/module.config.php'; + } + + /** + * Get autoloader configuration + * + * @return array + */ + public function getAutoloaderConfig() + { + return array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, + ), + ), + ); + } + + /** + * Initialize the module + * + * @param ModuleManager $m Module manager + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function init(ModuleManager $m) + { + } + + /** + * Bootstrap the module + * + * @param MvcEvent $e Event + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function onBootstrap(MvcEvent $e) + { + } +} diff --git a/module/AutocompleteTerms/config/module.config.php b/module/AutocompleteTerms/config/module.config.php new file mode 100644 index 0000000000..4937b1e5bc --- /dev/null +++ b/module/AutocompleteTerms/config/module.config.php @@ -0,0 +1,17 @@ + [ + 'allow_override' => true, + 'factories' => [ + 'AutocompleteTerms\Autocomplete\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', + ], + 'aliases' => [ + 'VuFind\AutocompletePluginManager' => 'AutocompleteTerms\Autocomplete\PluginManager', + 'VuFind\Autocomplete\PluginManager' => 'AutocompleteTerms\Autocomplete\PluginManager', + ], + ], +]; + +return $config; diff --git a/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/PluginFactory.php b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/PluginFactory.php new file mode 100644 index 0000000000..a0d5ae8f2b --- /dev/null +++ b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/PluginFactory.php @@ -0,0 +1,48 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:autosuggesters Wiki + */ +namespace AutocompleteTerms\Autocomplete; + +/** + * Autocomplete handler plugin factory + * + * @category VuFind + * @package Autocomplete + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:autosuggesters Wiki + */ +class PluginFactory extends \VuFind\ServiceManager\AbstractPluginFactory +{ + /** + * Constructor + */ + public function __construct() + { + $this->defaultNamespace = 'AutocompleteTerms\Autocomplete'; + } +} diff --git a/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/PluginManager.php b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/PluginManager.php new file mode 100644 index 0000000000..6882982f5b --- /dev/null +++ b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/PluginManager.php @@ -0,0 +1,114 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:autosuggesters Wiki + */ +namespace AutocompleteTerms\Autocomplete; + +/** + * Autocomplete handler plugin manager + * + * @category VuFind + * @package Autocomplete + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:autosuggesters Wiki + */ +class PluginManager extends \VuFind\Autocomplete\PluginManager +{ + /** + * Default plugin aliases. + * + * @var array + */ + protected $aliases = [ + 'none' => 'VuFind\Autocomplete\None', + 'eds' => 'VuFind\Autocomplete\Eds', + 'oclcidentities' => 'VuFind\Autocomplete\OCLCIdentities', + 'search2' => 'VuFind\Autocomplete\Search2', + 'search2cn' => 'VuFind\Autocomplete\Search2CN', + 'solr' => 'VuFind\Autocomplete\Solr', + 'solrauth' => 'VuFind\Autocomplete\SolrAuth', + 'solrcn' => 'VuFind\Autocomplete\SolrCN', + 'solrreserves' => 'VuFind\Autocomplete\SolrReserves', + 'tag' => 'VuFind\Autocomplete\Tag', + // for legacy 1.x compatibility + 'noautocomplete' => 'None', + 'oclcidentitiesautocomplete' => 'OCLCIdentities', + 'solrautocomplete' => 'Solr', + 'solrauthautocomplete' => 'SolrAuth', + 'solrcnautocomplete' => 'SolrCN', + 'solrreservesautocomplete' => 'SolrReserves', + 'tagautocomplete' => 'Tag', + 'terms' => 'AutocompleteTerms\Autocomplete\Terms', + ]; + + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'VuFind\Autocomplete\None' => 'Zend\ServiceManager\Factory\InvokableFactory', + 'VuFind\Autocomplete\Eds' => 'VuFind\Autocomplete\EdsFactory', + 'VuFind\Autocomplete\OCLCIdentities' => + 'Zend\ServiceManager\Factory\InvokableFactory', + 'VuFind\Autocomplete\Search2' => 'VuFind\Autocomplete\SolrFactory', + 'VuFind\Autocomplete\Search2CN' => 'VuFind\Autocomplete\SolrFactory', + 'VuFind\Autocomplete\Solr' => 'VuFind\Autocomplete\SolrFactory', + 'VuFind\Autocomplete\SolrAuth' => 'VuFind\Autocomplete\SolrFactory', + 'VuFind\Autocomplete\SolrCN' => 'VuFind\Autocomplete\SolrFactory', + 'VuFind\Autocomplete\SolrReserves' => 'VuFind\Autocomplete\SolrFactory', + 'VuFind\Autocomplete\Tag' => 'Zend\ServiceManager\Factory\InvokableFactory', + 'AutocompleteTerms\Autocomplete\Terms' => 'AutocompleteTerms\Autocomplete\TermsFactory', + ]; + + /** + * Constructor + * + * Make sure plugins are properly initialized. + * + * @param mixed $configOrContainerInstance Configuration or container instance + * @param array $v3config If $configOrContainerInstance is a + * container, this value will be passed to the parent constructor. + */ + public function __construct($configOrContainerInstance = null, + array $v3config = [] + ) { + $this->addAbstractFactory('AutocompleteTerms\Autocomplete\PluginFactory'); + parent::__construct($configOrContainerInstance, $v3config); + } + + /** + * Return the name of the base class or interface that plug-ins must conform + * to. + * + * @return string + */ + protected function getExpectedInterface() + { + return 'VuFind\Autocomplete\AutocompleteInterface'; + } +} diff --git a/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/Terms.php b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/Terms.php new file mode 100644 index 0000000000..24792865c8 --- /dev/null +++ b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/Terms.php @@ -0,0 +1,681 @@ + + * @author Chris Hallberg + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:autosuggesters Wiki + */ +namespace AutocompleteTerms\Autocomplete; + +/** + * Solr Autocomplete Module + * + * This class provides suggestions by using the local Solr index. + * + * @category VuFind + * @package Autocomplete + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:autosuggesters Wiki + */ +class Terms implements \VuFind\Autocomplete\AutocompleteInterface +{ + /** + * Autocomplete handler + * + * @var string + */ + protected $handler; + + /** + * Solr field to use for display + * + * @var string + */ + protected $displayField; + + /** + * Default Solr display field if none is configured + * + * @var string + */ + protected $defaultDisplayField = 'title'; + + /** + * Solr field to use for sorting + * + * @var string + */ + protected $sortField; + + /** + * Filters to apply to Solr search + * + * @var array + */ + protected $filters; + + /** + * Search object family to use + * + * @var string + */ + protected $searchClassId = 'Solr'; + + /** + * Search results object + * + * @var \VuFind\Search\Base\Results + */ + protected $searchObject; + + /** + * Results plugin manager + * + * @var \VuFind\Search\Results\PluginManager + */ + protected $resultsManager; + + protected $config; + + /** + * Constructor + * + * @param \VuFind\Search\Results\PluginManager $results Results plugin manager + */ + public function __construct(\VuFind\Search\Results\PluginManager $results, $config) + { + $this->resultsManager = $results; + $this->config = $config; + } + + /** + * Set parameters that affect the behavior of the autocomplete handler. + * These values normally come from the search configuration file. + * + * @param string $params Parameters to set + * + * @return void + */ + public function setConfig($params) + { + // Save the basic parameters: + $params = explode(':', $params); + $this->handler = (isset($params[0]) && !empty($params[0])) ? + $params[0] : null; + $this->displayField = (isset($params[1]) && !empty($params[1])) ? + explode(',', $params[1]) : [$this->defaultDisplayField]; + $this->sortField = (isset($params[2]) && !empty($params[2])) ? + $params[2] : null; + $this->filters = []; + if (count($params) > 3) { + for ($x = 3; $x < count($params); $x += 2) { + if (isset($params[$x + 1])) { + $this->filters[] = $params[$x] . ':' . $params[$x + 1]; + } + } + } + + // Set up the Search Object: + $this->initSearchObject(); + } + + /** + * Add filters (in addition to the configured ones) + * + * @param array $filters Filters to add + * + * @return void + */ + public function addFilters($filters) + { + $this->filters += $filters; + } + + /** + * Initialize the search object used for finding recommendations. + * + * @return void + */ + protected function initSearchObject() + { + // Build a new search object: + $this->searchObject = $this->resultsManager->get($this->searchClassId); + $this->searchObject->getOptions()->spellcheckEnabled(false); + } + + /** + * Process the user query to make it suitable for a Solr query. + * + * @param string $query Incoming user query + * + * @return string Processed query + */ + protected function mungeQuery($query) + { + // Modify the query so it makes a nice, truncated autocomplete query: + $forbidden = [':', '(', ')', '*', '+', '"']; + $query = str_replace($forbidden, " ", $query); + if (substr($query, -1) != " ") { + $query .= "*"; + } + return $query; + } + + /** + * This method returns an array of strings matching the user's query for + * display in the autocomplete box. + * + * @param string $query The user query + * + * @return array The suggestions for the provided query + */ + public function getSuggestions($query) + { + if (!is_object($this->searchObject)) { + throw new \Exception('Please set configuration first.'); + } + + try { + $this->searchObject->getParams()->setBasicSearch( + $this->mungeQuery($query), $this->handler + ); + $this->searchObject->getParams()->setSort($this->sortField); + foreach ($this->filters as $current) { + $this->searchObject->getParams()->addFilter($current); + } + + // Perform the search: + $searchResults = $this->searchObject->getResults(); + + $spellingSuggestions = $this->searchObject->getSpellingSuggestions(); + + // Build the recommendation list -- first we'll try with exact matches; + // if we don't get anything at all, we'll try again with a less strict + // set of rules. + $results = $this->getSuggestionsFromSearch($searchResults, $query, true); + if (empty($results)) { + $results = $this->getSuggestionsFromSearch( + $searchResults, $query, false + ); + } + } catch (\Exception $e) { + // Ignore errors -- just return empty results if we must. + } + return isset($results) ? array_unique($results) : []; + } + + /** + * Try to turn an array of record drivers into an array of suggestions. + * + * @param array $searchResults An array of record drivers + * @param string $query User search query + * @param bool $exact Ignore non-exact matches? + * + * @return array + */ + protected function getSuggestionsFromSearch($searchResults, $query, $exact) + { + /* + + Array + ( + [author_variant] => Array + ( + [0] => j n jn + ) + + [matchkey_str] => book:9783570010914:2008---- + [publishDate] => Array + ( + [0] => 2008 + ) + + [allfields] => 9783570010914 978-3-570-01091-4 3570010910 3-570-01091-0 0078_0099339 1178_KAT_D-0047206 OLDP870709313 ger GBVCP Neffe, Jürgen Darwin das Abenteuer des Lebens Jürgen Neffe 5. Aufl München C. Bertelsmann 2008 544 S Fototaf., Kt Naturwissenschaften gnd Biographien gnd Darwin, Charles gnd Naturwissenschaften Biographien DE-101 Darwin, Charles DE-601 GBV_ILN_475 SYSFLAG_1 GBV_OEVK GBV_ILN_478 BO 475 01 1 1360765301 Stadt/E R 11 u 20180305 1178 n 30-03-09 478 01 1381900798 N 910 Dar u 20180703 0078 n 05-03-09 475 01 20180305 478 01 20180703 + [spelling] => 9783570010914 978-3-570-01091-4 3570010910 3-570-01091-0 0078_0099339 1178_KAT_D-0047206 OLDP870709313 ger GBVCP Neffe, Jürgen Darwin das Abenteuer des Lebens Jürgen Neffe 5. Aufl München C. Bertelsmann 2008 544 S Fototaf., Kt Naturwissenschaften gnd Biographien gnd Darwin, Charles gnd Naturwissenschaften Biographien DE-101 Darwin, Charles DE-601 GBV_ILN_475 SYSFLAG_1 GBV_OEVK GBV_ILN_478 BO 475 01 1 1360765301 Stadt/E R 11 u 20180305 1178 n 30-03-09 478 01 1381900798 N 910 Dar u 20180703 0078 n 05-03-09 475 01 20180305 478 01 20180703 + [allfields_unstemmed] => 9783570010914 978-3-570-01091-4 3570010910 3-570-01091-0 0078_0099339 1178_KAT_D-0047206 OLDP870709313 ger GBVCP Neffe, Jürgen Darwin das Abenteuer des Lebens Jürgen Neffe 5. Aufl München C. Bertelsmann 2008 544 S Fototaf., Kt Naturwissenschaften gnd Biographien gnd Darwin, Charles gnd Naturwissenschaften Biographien DE-101 Darwin, Charles DE-601 GBV_ILN_475 SYSFLAG_1 GBV_OEVK GBV_ILN_478 BO 475 01 1 1360765301 Stadt/E R 11 u 20180305 1178 n 30-03-09 478 01 1381900798 N 910 Dar u 20180703 0078 n 05-03-09 475 01 20180305 478 01 20180703 + [allfieldsGer] => 9783570010914 978-3-570-01091-4 3570010910 3-570-01091-0 0078_0099339 1178_KAT_D-0047206 OLDP870709313 ger GBVCP Neffe, Jürgen Darwin das Abenteuer des Lebens Jürgen Neffe 5. Aufl München C. Bertelsmann 2008 544 S Fototaf., Kt Naturwissenschaften gnd Biographien gnd Darwin, Charles gnd Naturwissenschaften Biographien DE-101 Darwin, Charles DE-601 GBV_ILN_475 SYSFLAG_1 GBV_OEVK GBV_ILN_478 BO 475 01 1 1360765301 Stadt/E R 11 u 20180305 1178 n 30-03-09 478 01 1381900798 N 910 Dar u 20180703 0078 n 05-03-09 475 01 20180305 478 01 20180703 + [allfieldsSound] => 9783570010914 978-3-570-01091-4 3570010910 3-570-01091-0 0078_0099339 1178_KAT_D-0047206 OLDP870709313 ger GBVCP Neffe, Jürgen Darwin das Abenteuer des Lebens Jürgen Neffe 5. Aufl München C. Bertelsmann 2008 544 S Fototaf., Kt Naturwissenschaften gnd Biographien gnd Darwin, Charles gnd Naturwissenschaften Biographien DE-101 Darwin, Charles DE-601 GBV_ILN_475 SYSFLAG_1 GBV_OEVK GBV_ILN_478 BO 475 01 1 1360765301 Stadt/E R 11 u 20180305 1178 n 30-03-09 478 01 1381900798 N 910 Dar u 20180703 0078 n 05-03-09 475 01 20180305 478 01 20180703 + [format_phy_str_mv] => Array + ( + [0] => Book + ) + + [building] => Array + ( + [0] => 475 + [1] => 478 + ) + + [institution] => Array + ( + [0] => findex.gbv.de + ) + + [topic_facet] => Array + ( + [0] => Naturwissenschaften + [1] => Biographien + [2] => Darwin, Charles + ) + + [isfreeaccess_bool] => false + [id] => OEVK1328608808 + [signature_iln] => Array + ( + [0] => 475:R 11 + [1] => 478:N 910 Dar + ) + + [signature_iln_str_mv] => Array + ( + [0] => 475:R 11 + [1] => 478:N 910 Dar + ) + + [signature_iln_scis_mv] => Array + ( + [0] => 475:R 11 + [1] => 478:N 910 Dar + ) + + [genre_facet] => Array + ( + [0] => Naturwissenschaften + [1] => Biographien + [2] => Darwin, Charles + ) + + [standort_str_mv] => Array + ( + [0] => Stadt/E + ) + + [callnumber-first] => R - Medicine + [author] => Neffe, Jürgen + [spellingShingle] => Array + ( + [0] => Neffe, Jürgen + [1] => misc Naturwissenschaften + [2] => misc Biographien + [3] => misc Darwin, Charles + [4] => Darwin das Abenteuer des Lebens + ) + + [authorStr] => Neffe, Jürgen + [standort_iln_str_mv] => Array + ( + [0] => 475:Stadt/E + ) + + [format] => Array + ( + [0] => Book + ) + + [delete_txt_mv] => Array + ( + [0] => keep + ) + + [author_role] => Array + ( + [0] => + ) + + [collection] => Array + ( + [0] => ÖVK + ) + + [publishPlace] => Array + ( + [0] => München + ) + + [remote_str] => false + [abrufzeichen_iln_str_mv] => Array + ( + [0] => 475@20180305 + [1] => 478@20180703 + ) + + [abrufzeichen_iln_scis_mv] => Array + ( + [0] => 475@20180305 + [1] => 478@20180703 + ) + + [last_changed_iln_str_mv] => Array + ( + [0] => 475@30-03-09 + [1] => 478@05-03-09 + ) + + [illustrated] => Not Illustrated + [topic_title] => Array + ( + [0] => Darwin das Abenteuer des Lebens Jürgen Neffe + [1] => Naturwissenschaften + [2] => Biographien + [3] => DE-101 + [4] => Darwin, Charles + [5] => DE-601 + ) + + [publisher] => Array + ( + [0] => C. Bertelsmann + ) + + [publisherStr] => Array + ( + [0] => C. Bertelsmann + ) + + [topic] => Array + ( + [0] => misc Naturwissenschaften + [1] => misc Biographien + [2] => misc Darwin, Charles + ) + + [topic_unstemmed] => Array + ( + [0] => misc Naturwissenschaften + [1] => misc Biographien + [2] => misc Darwin, Charles + ) + + [topic_browse] => Array + ( + [0] => misc Naturwissenschaften + [1] => misc Biographien + [2] => misc Darwin, Charles + ) + + [format_facet] => Array + ( + [0] => Bücher + [1] => Gedruckte Bücher + ) + + [standort_txtP_mv] => Array + ( + [0] => Stadt/E + ) + + [signature] => Array + ( + [0] => R 11 + [1] => N 910 Dar + ) + + [signature_str_mv] => Array + ( + [0] => R 11 + [1] => N 910 Dar + ) + + [isbn] => Array + ( + [0] => 9783570010914 + [1] => 3570010910 + ) + + [edition] => 5. Aufl + [isfreeaccess_txt] => false + [title] => Array + ( + [0] => Darwin das Abenteuer des Lebens + ) + + [title_full] => Array + ( + [0] => Darwin das Abenteuer des Lebens Jürgen Neffe + ) + + [fullrecord] => 01180nam a2200409 c 4500001001500000003000700015005001700022008004100039020003700080020003000117024001700147024002300164024001800187040001500205100001900220245005200239250001200291264003500303300002400338655002900362655002100391655002500412689002400437689001600461689001100477689002000488689001100508912001600519912001400535912001300549912001600562951000700578980007400585980006700659995002200726995002200748#30;OEVK1328608808#30;DE-601#30;20180809134032.0#30;120721s2008 000 0 und d#30; #31;a9783570010914#31;9978-3-570-01091-4#30; #31;a3570010910#31;93-570-01091-0#30;8 #31;a0078_0099339#30;8 #31;a1178_KAT_D-0047206#30;8 #31;aOLDP870709313#30; #31;bger#31;cGBVCP#30;1 #31;aNeffe, Jürgen#30;10#31;aDarwin#31;bdas Abenteuer des Lebens#31;cJürgen Neffe#30; #31;a5. Aufl#30;31#31;aMünchen#31;bC. Bertelsmann#31;c2008#30; #31;a544 S#31;bFototaf., Kt#30; 7#31;aNaturwissenschaften#31;2gnd#30; 7#31;aBiographien#31;2gnd#30; 7#31;aDarwin, Charles#31;2gnd#30;00#31;aNaturwissenschaften#30;01#31;aBiographien#30;0 #31;5DE-101#30;00#31;aDarwin, Charles#30;0 #31;5DE-601#30; #31;aGBV_ILN_475#30; #31;aSYSFLAG_1#30; #31;aGBV_OEVK#30; #31;aGBV_ILN_478#30; #31;aBO#30; #31;2475#31;101#31;a1#31;b1360765301#31;fStadt/E#31;dR 11#31;eu#31;h20180305#31;x1178#31;yn#31;z30-03-09#30; #31;2478#31;101#31;b1381900798#31;dN 910 Dar#31;eu#31;h20180703#31;x0078#31;yn#31;z05-03-09#30; #31;2475#31;101#31;a20180305#30; #31;2478#31;101#31;a20180703#30;#29; + [author_sort] => Neffe, Jürgen + [callnumber-first-code] => R + [isOA_bool] => false + [recordtype] => marc + [genre] => Array + ( + [0] => Naturwissenschaften gnd + [1] => Biographien gnd + [2] => Darwin, Charles gnd + ) + + [publishDateSort] => 2008 + [selectkey] => Array + ( + [0] => 475:n + [1] => 478:n + ) + + [physical] => Array + ( + [0] => 544 S Fototaf., Kt + ) + + [author-letter] => Array + ( + [0] => Neffe, Jürgen + ) + + [format_se] => Array + ( + [0] => Bücher + ) + + [title_sub] => Array + ( + [0] => das Abenteuer des Lebens + ) + + [title_sort] => darwindas abenteuer des lebens + [title_auth] => Array + ( + [0] => Darwin das Abenteuer des Lebens + ) + + [title_short] => Array + ( + [0] => Darwin + ) + + [collection_details] => Array + ( + [0] => GBV_ILN_475 + [1] => SYSFLAG_1 + [2] => GBV_OEVK + [3] => GBV_ILN_478 + ) + + [ausleihindikator_str_mv] => Array + ( + [0] => 475:u + [1] => 478:u + ) + + [remote_bool] => false + [isOA_txt] => false + [hochschulschrift_bool] => false + [callnumber-a] => R 11 + [up_date] => 2019-09-29T01:24:33.505Z + [_version_] => 1645971005511827456 + [fullrecord_marcxml] => 01180nam a2200409 c 4500OEVK1328608808DE-60120180809134032.0120721s2008 000 0 und d9783570010914978-3-570-01091-435700109103-570-01091-00078_00993391178_KAT_D-0047206OLDP870709313gerGBVCPNeffe, JürgenDarwindas Abenteuer des LebensJürgen Neffe5. AuflMünchenC. Bertelsmann2008544 SFototaf., KtNaturwissenschaftengndBiographiengndDarwin, CharlesgndNaturwissenschaftenBiographienDE-101Darwin, CharlesDE-601GBV_ILN_475SYSFLAG_1GBV_OEVKGBV_ILN_478BO4750111360765301Stadt/ER 11u201803051178n30-03-09478011381900798N 910 Daru201807030078n05-03-0947501201803054780120180703 + + [score] => 750 + ) + + + */ + + $results = $this->getTerms($searchResults, $query); + + if (empty($results)) { + $results = $this->getTerms($searchResults, $query, true); + } + + return $results; + } + + private function getTerms($searchResults, $query, $allFields = false) { + $results = []; + foreach ($searchResults as $object) { + $current = $object->getRawData(); + $matches = []; + + $searchContents = ''; + if (!$allFields) { + if (isset($current[strtolower($this->handler)])) { + $searchContents = $current[strtolower($this->handler)]; + } + } else { + $searchContents = $current['allfields']; + } + + if (!is_array($searchContents)) { + $searchContents = [$searchContents]; + } + + foreach ($searchContents as $searchContent) { + $completeFields = false; + if (isset($this->config['Autocomplete_Types_Options']['CompleteFields'])) { + foreach ($this->config['Autocomplete_Types_Options']['CompleteFields'] as $completeField) { + if ($completeField == $this->handler) { + $completeFields = true; + } + } + } + + if (!$completeFields) { + preg_match_all('~\b' . $query . '[a-z]*\b~i', $searchContent, $matches); + foreach ($matches as $terms) { + foreach ($terms as $term) { + $results[] = strtolower($term); + } + } + } else { + if (stristr(strtolower($searchContent), $query)) { + $results[] = strtolower($searchContent); + } + } + } + } + + array_unique($results); + sort($results); + + return $results; + } + + /** + * Given the values from a Solr field and the user's search query, pick the best + * match to display as a recommendation. + * + * @param array|string $value Field value (or array of field values) + * @param string $query User search query + * @param bool $exact Ignore non-exact matches? + * + * @return bool|string String to use as recommendation, or false if + * no appropriate value was found. + */ + protected function pickBestMatch($value, $query, $exact) + { + // By default, assume no match: + $bestMatch = false; + + // Different processing for arrays vs. non-arrays: + if (is_array($value) && !empty($value)) { + // Do any of the values within this multi-valued array match the + // query? Try to find the closest available match. + foreach ($value as $next) { + if ($this->matchQueryTerms($next, $query)) { + $bestMatch = $next; + break; + } + } + + // If we didn't find an exact match, use the first value unless + // we have the "precise matches only" property set, in which case + // we don't want to use any of these values. + if (!$bestMatch && !$exact) { + $bestMatch = $value[0]; + } + } else { + // If we have a single value, we will use it if we're in non-strict + // mode OR if we're in strict mode and it actually matches. + if (!$exact || $this->matchQueryTerms($value, $query)) { + $bestMatch = $value; + } + } + return $bestMatch; + } + + /** + * Set the display field list. Useful for child classes. + * + * @param array $new Display field list. + * + * @return void + */ + protected function setDisplayField($new) + { + $this->displayField = $new; + } + + /** + * Set the sort field list. Useful for child classes. + * + * @param string $new Sort field list. + * + * @return void + */ + protected function setSortField($new) + { + $this->sortField = $new; + } + + /** + * Return true if all terms in the query occurs in the field data string. + * + * @param string $data The data field returned from solr + * @param string $query The query string entered by the user + * + * @return bool + */ + protected function matchQueryTerms($data, $query) + { + $terms = preg_split("/\s+/", $query); + foreach ($terms as $term) { + if (stripos($data, $term) === false) { + return false; + } + } + return true; + } +} diff --git a/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/TermsFactory.php b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/TermsFactory.php new file mode 100644 index 0000000000..92244429d4 --- /dev/null +++ b/module/AutocompleteTerms/src/AutocompleteTerms/Autocomplete/TermsFactory.php @@ -0,0 +1,69 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace AutocompleteTerms\Autocomplete; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Solr-driven autocomplete plugins. Works for \VuFind\Autocomplete\Solr + * and all of its subclasses. + * + * @category VuFind + * @package Autocomplete + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class TermsFactory implements \Zend\ServiceManager\Factory\FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + return new Terms( + $container->get('VuFind\Search\Results\PluginManager'), + $container->get('VuFind\Config\PluginManager')->get('searches') + ); + } +} diff --git a/module/DAIAplus/src/DAIAplus/AjaxHandler/GetArticleStatuses.php b/module/DAIAplus/src/DAIAplus/AjaxHandler/GetArticleStatuses.php index 559d61a9c9..e11de314d1 100644 --- a/module/DAIAplus/src/DAIAplus/AjaxHandler/GetArticleStatuses.php +++ b/module/DAIAplus/src/DAIAplus/AjaxHandler/GetArticleStatuses.php @@ -31,6 +31,7 @@ use VuFind\Record\Loader; use VuFind\AjaxHandler\AbstractBase; +use VuFind\I18n\Translator\TranslatorAwareInterface; use Zend\Config\Config; use Zend\Mvc\Controller\Plugin\Params; @@ -48,8 +49,9 @@ * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org/wiki/development Wiki */ -class GetArticleStatuses extends AbstractBase +class GetArticleStatuses extends AbstractBase implements TranslatorAwareInterface { + use \VuFind\I18n\Translator\TranslatorAwareTrait; protected $recordLoader; @@ -81,59 +83,59 @@ public function handleRequest(Params $params) $responses = []; $ids = $params->fromPost('id', $params->fromQuery('id', '')); $source = $params->fromPost('source', $params->fromQuery('source', '')); + $resolverChecks = $this->config['ResolverChecks']; if (!empty($ids) && !empty($source)) { - $listView = $params->fromPost('list', $params->fromQuery('list', '0')); - + $listView = ($params->fromPost('list', $params->fromQuery('list', 'false')) === 'true') ? 1 : 0; foreach ($ids as $id) { $driver = $this->recordLoader->load($id, $source); - $openUrl = $driver->getOpenUrl(); - $formats = $driver->getFormats(); - $format = $formats[0]; - $format = strtolower(str_ireplace('electronic ','',$format)); - $doi = $driver->getMarcData('Doi'); - - $sfxLink = $openUrl; - $sfxData = $driver->getMarcData('SFX'); - - if (is_array($sfxData)) { - foreach ($sfxData as $sfxDate) { - if (is_array($sfxDate)) { - foreach ($sfxDate as $key => $value) { - $sfxLink .= '&' . $key . '=' . urlencode($value['data'][0]); - if(strpos($openUrl, 'rft.' . $key . '=') === false) { - $openUrl .= '&rft.' . $key . '=' . urlencode($value['data'][0]); - } - } - } + + $urlAccess = ''; + if (isset($resolverChecks['fulltext']) && $resolverChecks['fulltext'] == 'y') { + $urlAccess = $this->checkFulltext($driver); + if (!empty($urlAccess)) { + $urlAccessLevel = 'article_access_level'; + $urlAccessLabel = 'Fulltext'; } } - - if(strpos($openUrl, 'rft.genre=') === false) { - $openUrl .= '&rft.genre=' . $format; + if (empty($urlAccess) && isset($resolverChecks['open_access']) && $resolverChecks['open_access'] == 'y') { + $urlAccess = $this->checkOpenAccess($driver); + if (!empty($urlAccess)) { + $urlAccessLevel = 'article_access_level'; + $urlAccessLabel = 'Fulltext (DOAJ)'; + } } - - $sfxDomain = $this->config['DAIA']['sfxDomain'] ?? ''; - $sfxLink = urlencode('http://sfx.gbv.de/sfx_' . $sfxDomain . '?' . $sfxLink); - - $isil = $this->config['Global']['isil']; - $url = $this->config['DAIA_' . $isil]['url']; - $url .= 'electronicavailability/' . $id . '?'; - $url .= 'apikey=' . $this->config['DAIA_' . $isil]['daiaplus_api_key']; - $url .= '&openurl=' . urlencode($openUrl); - $url .= '&list=' . $listView; - $url .= '&mediatype=' . urlencode($format); - - if ($doi[0]['doi']['data'][0]) { - $url .= '&doi=' . $doi[0]['doi']['data'][0]; + if (empty($urlAccess) && isset($resolverChecks['doi']) && $resolverChecks['doi'] == 'y') { + $urlAccess = $this->checkDoi($driver); + if (!empty($urlAccess)) { + $urlAccessLevel = 'article_access_level'; + $urlAccessLabel = 'Fulltext (DOI)'; + } + } + if (empty($urlAccess) && isset($resolverChecks['journal']) && $resolverChecks['journal'] == 'y') { + $urlAccess = $this->checkParentId($driver); + if (!empty($urlAccess)) { + $urlAccessLevel = 'print_access_level'; + $urlAccessLabel = 'Journal'; + } } - if ($sfxDomain) { - $url .= '&sfx=' . $sfxLink; + if (!empty($urlAccess)) { + $response = ['list' => ['url_access' => $urlAccess, + 'url_access_level' => $urlAccessLevel, + 'url_access_label' => $urlAccessLabel, + 'link_status' => 1], + 'items' => ['lr_check' => + ['url_access' => $urlAccess, + 'url_access_level' => $urlAccessLevel, + 'url_access_label' => $urlAccessLabel, + 'link_status' => 1] + ] + ]; + } else { + $url = $this->prepareUrl($driver, $id, $listView); + $response = json_decode($this->makeRequest($url), true); } - $url .= '&language=de'; - $url .= '&format=json'; - $response = json_decode($this->makeRequest($url), true); $response = $this->prepareData($response, $listView); $response['id'] = $id; $responses[] = $response; @@ -142,6 +144,111 @@ public function handleRequest(Params $params) return $this->formatResponse(['statuses' => $responses]); } + private function checkDoi($driver) { + $urlAccess = ''; + $doiData = $driver->getMarcData('ArticleDoi'); + foreach ($doiData as $doiDate) { + if (!empty(($doiDate['doi']['data'][0]))) { + $urlAccess = 'http://dx.doi.org/' . $doiDate['doi']['data'][0]; + break; + } + } + return $urlAccess; + } + + private function checkOpenAccess($driver) { + $urlAccess = ''; + $doajData = $driver->getMarcData('ArticleDoaj'); + foreach ($doajData as $doajDate) { + if (!empty(($doajDate['url']['data'][0]))) { + $urlAccess = $doajDate['url']['data'][0]; + break; + } + } + return $urlAccess; + } + + private function checkFulltext($driver) { + $urlAccess = ''; + $fulltextData = $driver->getMarcData('ArticleFulltext'); + foreach ($fulltextData as $fulltextDate) { + if (!empty(($fulltextDate['url']['data'][0]))) { + $urlAccess = $fulltextDate['url']['data'][0]; + break; + } + } + return $urlAccess; + } + + private function checkParentId($driver) { + $urlAccess = ''; + $parentData = $driver->getMarcData('ArticleParentId'); + foreach ($parentData as $parentDate) { + if (!empty(($parentDate['id']['data'][0]))) { + $parentId = $parentDate['id']['data'][0]; + break; + } + } + if (!empty($parentId)) { + $parentDriver = $this->recordLoader->load($parentId, 'Solr'); + $ilnMatch = $parentDriver->getMarcData('ILN'); + if (!empty($ilnMatch[0]['iln']['data'][0])) { + $urlAccess = '/vufind/Record/' . $parentId; + } + } + return $urlAccess; + } + + private function prepareUrl($driver, $id, $listView) { + $openUrl = $driver->getOpenUrl(); + $formats = $driver->getFormats(); + $format = strtolower(str_ireplace('electronic ','',$formats[0])); + $doi = $driver->getMarcData('Doi'); + + $sfxLink = $openUrl; + $sfxData = $driver->getMarcData('SFX'); + + if (is_array($sfxData)) { + foreach ($sfxData as $sfxDate) { + if (is_array($sfxDate)) { + foreach ($sfxDate as $key => $value) { + $sfxLink .= '&' . $key . '=' . urlencode($value['data'][0]); + if(strpos($openUrl, 'rft.' . $key . '=') === false) { + $openUrl .= '&rft.' . $key . '=' . urlencode($value['data'][0]); + } + } + } + } + } + + if(strpos($openUrl, 'rft.genre=') === false) { + $openUrl .= '&rft.genre=' . $format; + } + + $sfxDomain = $this->config['DAIA']['sfxDomain'] ?? ''; + $sfxLink = urlencode('http://sfx.gbv.de/sfx_' . $sfxDomain . '?' . $sfxLink); + + $isil = $this->config['Global']['isil']; + $url = $this->config['DAIA_' . $isil]['url']; + $url .= 'electronicavailability/' . $id . '?'; + $url .= 'apikey=' . $this->config['DAIA_' . $isil]['daiaplus_api_key']; + $url .= '&openurl=' . urlencode($openUrl); + $url .= '&list=' . $listView; + $url .= '&mediatype=' . urlencode($format); + + if ($doi[0]['doi']['data'][0]) { + $url .= '&doi=' . $doi[0]['doi']['data'][0]; + } + + if ($sfxDomain) { + $url .= '&sfx=' . $sfxLink; + } + + $url .= '&language=de'; + $url .= '&format=json'; + return $url; + } + private function makeRequest($url) { $req = curl_init(); curl_setopt($req, CURLOPT_URL, $url); @@ -155,35 +262,43 @@ private function makeRequest($url) { } private function prepareData($rawData, $list) { + $resolverLabels = $this->config['ResolverLabels']; $data = []; if (!empty($rawData['items']['sfx'])) { + $label = $resolverLabels['article'] ?: 'SFX'; $data[] = [ 'href' => $rawData['items']['sfx'], 'level' => 'article_access_level', - 'label' => 'SFX' + 'label' => $this->translate($label) ]; } elseif (!empty($rawData)) { if ($list == 1 && !empty($rawData['list']['url_access'])) { $urlAccess = (is_array($rawData['list']['url_access'])) ? $rawData['list']['url_access'][0] : $rawData['list']['url_access']; + $level = str_replace('_access_level', '', $rawData['list']['url_access_level']); + $label = $resolverLabels[$level] ?: $rawData['list']['url_access_label']; $data[] = [ 'href' => $urlAccess, 'level' => $rawData['list']['url_access_level'], - 'label' => $rawData['list']['url_access_label'], + 'label' => $this->translate($label), 'doi' => $rawData['list']['doi'] ]; } else { if (empty($rawData['list']['url_access'])) { + $level = str_replace('_access_level', '', $rawData['list']['url_access_level']); + $label = $resolverLabels[$level] ?: $rawData['list']['url_access_label']; $data[] = [ - 'label' => $rawData['list']['url_access_label'] + 'label' => $this->translate($label) ]; } else { foreach ($rawData['items'] as $item) { if (!empty($item) && !empty($item['url_access'])) { $urlAccess = (is_array($item['url_access'])) ? $item['url_access'][0] : $item['url_access']; + $level = str_replace('_access_level', '', $item['url_access_level']); + $label = $resolverLabels[$level] ?: $item['url_access_label']; $data[] = [ 'href' => $urlAccess, 'level' => $item['url_access_level'], - 'label' => $item['url_access_label'], + 'label' => $this->translate($label, [], $label), 'notification' => $item['access_notification'], 'doi' => $item['doi'] ]; diff --git a/module/DAIAplus/src/DAIAplus/AjaxHandler/GetItemStatuses.php b/module/DAIAplus/src/DAIAplus/AjaxHandler/GetItemStatuses.php index ab51355537..36b8ff6e6e 100644 --- a/module/DAIAplus/src/DAIAplus/AjaxHandler/GetItemStatuses.php +++ b/module/DAIAplus/src/DAIAplus/AjaxHandler/GetItemStatuses.php @@ -179,7 +179,7 @@ public function handleRequest(Params $params) foreach ($record as $index1 => $recordItem) { foreach ($recordItem['daiaplus']['actionArray'] as $index2 => $action) { if (!empty($action['beluga_core']['href'])) { - $id = $action['ppn']; + $id = $current['id']; $docId = $action['documentId']; $itemId = $action['itemId']; $type = $action['type']; diff --git a/module/ExtendedFacets/src/ExtendedFacets/Recommend/SideFacets.php b/module/ExtendedFacets/src/ExtendedFacets/Recommend/SideFacets.php index 8007f1a4df..7fe71aa9fd 100644 --- a/module/ExtendedFacets/src/ExtendedFacets/Recommend/SideFacets.php +++ b/module/ExtendedFacets/src/ExtendedFacets/Recommend/SideFacets.php @@ -93,6 +93,7 @@ public function getYearFacets($oldFacetList, $label) } } krsort($newFacetList); + $newFacetList = array_values($newFacetList); if (isset($filteredYearFacet)) { array_unshift($newFacetList, $filteredYearFacet); } diff --git a/module/FacetPrefix/Module.php b/module/FacetPrefix/Module.php new file mode 100644 index 0000000000..abd0ff70f6 --- /dev/null +++ b/module/FacetPrefix/Module.php @@ -0,0 +1,92 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/dmj/vf2-proxy + */ +namespace FacetPrefix; +use Zend\ModuleManager\ModuleManager, + Zend\Mvc\MvcEvent; + +/** + * Template for ZF2 module for storing local overrides. + * + * @category VuFind2 + * @package Module + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/dmj/vf2-proxy + */ +class Module +{ + /** + * Get module configuration + * + * @return array + */ + public function getConfig() + { + return include __DIR__ . '/config/module.config.php'; + } + + /** + * Get autoloader configuration + * + * @return array + */ + public function getAutoloaderConfig() + { + return array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, + ), + ), + ); + } + + /** + * Initialize the module + * + * @param ModuleManager $m Module manager + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function init(ModuleManager $m) + { + } + + /** + * Bootstrap the module + * + * @param MvcEvent $e Event + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function onBootstrap(MvcEvent $e) + { + } +} diff --git a/module/FacetPrefix/config/module.config.php b/module/FacetPrefix/config/module.config.php new file mode 100644 index 0000000000..e4ec815ace --- /dev/null +++ b/module/FacetPrefix/config/module.config.php @@ -0,0 +1,19 @@ + [ + 'allow_override' => true, + 'factories' => [ + 'FacetPrefix\Search\Params\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', + 'FacetPrefix\Search\Results\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', + ], + 'aliases' => [ + 'VuFind\Search\Params\PluginManager' => 'FacetPrefix\Search\Params\PluginManager', + 'VuFind\Search\Results\PluginManager' => 'FacetPrefix\Search\Results\PluginManager', + ], + ], +]; + +return $config; + diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Params/ParamsFactory.php b/module/FacetPrefix/src/FacetPrefix/Search/Params/ParamsFactory.php new file mode 100644 index 0000000000..0f8bc83072 --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Params/ParamsFactory.php @@ -0,0 +1,73 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace FacetPrefix\Search\Params; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * Generic factory for search params objects. + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ParamsFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + // Replace trailing "Params" with "Options" to get the options service: + $optionsService = preg_replace('/Params$/', 'Options', $requestedName); + // Replace leading "SearchKeys" with "VuFind" to get the VuFind options service: + $optionsService = preg_replace('/^FacetPrefix/', 'VuFind', $optionsService); + $optionsObj = $container->get('VuFind\Search\Options\PluginManager') + ->get($optionsService); + $configLoader = $container->get('VuFind\Config\PluginManager'); + // Clone the options instance in case caller modifies it: + return new $requestedName( + clone $optionsObj, $configLoader, ...($options ?: []) + ); + } +} diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Params/PluginManager.php b/module/FacetPrefix/src/FacetPrefix/Search/Params/PluginManager.php new file mode 100644 index 0000000000..6e38efa8b6 --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Params/PluginManager.php @@ -0,0 +1,133 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace FacetPrefix\Search\Params; + +/** + * Search params plugin manager + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +class PluginManager extends \VuFind\Search\Params\PluginManager +{ + /** + * Default plugin aliases. + * + * @var array + */ + protected $aliases = [ + 'browzine' => 'VuFind\Search\BrowZine\Params', + 'combined' => 'VuFind\Search\Combined\Params', + 'eds' => 'VuFind\Search\EDS\Params', + 'eit' => 'VuFind\Search\EIT\Params', + 'emptyset' => 'VuFind\Search\EmptySet\Params', + 'favorites' => 'VuFind\Search\Favorites\Params', + 'libguides' => 'VuFind\Search\LibGuides\Params', + 'mixedlist' => 'VuFind\Search\MixedList\Params', + 'pazpar2' => 'VuFind\Search\Pazpar2\Params', + 'primo' => 'VuFind\Search\Primo\Params', + 'search2' => 'FacetPrefix\Search\Search2\Params', + 'solr' => 'FacetPrefix\Search\Solr\Params', + 'solrauth' => 'VuFind\Search\SolrAuth\Params', + 'solrauthor' => 'VuFind\Search\SolrAuthor\Params', + 'solrauthorfacets' => 'VuFind\Search\SolrAuthorFacets\Params', + 'solrcollection' => 'VuFind\Search\SolrCollection\Params', + 'solrreserves' => 'VuFind\Search\SolrReserves\Params', + 'solrweb' => 'VuFind\Search\SolrWeb\Params', + 'summon' => 'VuFind\Search\Summon\Params', + 'tags' => 'VuFind\Search\Tags\Params', + 'worldcat' => 'VuFind\Search\WorldCat\Params', + 'VuFind\Search\Solr\Params' => 'FacetPrefix\Search\Solr\Params', + ]; + + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'VuFind\Search\BrowZine\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Combined\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\EDS\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\EIT\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\EmptySet\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Favorites\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\LibGuides\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\MixedList\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Pazpar2\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Primo\Params' => 'VuFind\Search\Params\ParamsFactory', + 'FacetPrefix\Search\Search2\Params' => 'FacetPrefix\Search\Solr\ParamsFactory', + 'FacetPrefix\Search\Solr\Params' => 'FacetPrefix\Search\Solr\ParamsFactory', + 'VuFind\Search\SolrAuth\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrAuthor\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrAuthorFacets\Params' => + 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrCollection\Params' => + 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrReserves\Params' => + 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrWeb\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Summon\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Tags\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\WorldCat\Params' => 'VuFind\Search\Params\ParamsFactory', + ]; + + /** + * Constructor + * + * Make sure plugins are properly initialized. + * + * @param mixed $configOrContainerInstance Configuration or container instance + * @param array $v3config If $configOrContainerInstance is a + * container, this value will be passed to the parent constructor. + */ + public function __construct($configOrContainerInstance = null, + array $v3config = [] + ) { + // These objects are not meant to be shared -- every time we retrieve one, + // we are building a brand new object. + $this->sharedByDefault = false; + + $this->addAbstractFactory('VuFind\Search\Params\PluginFactory'); + parent::__construct($configOrContainerInstance, $v3config); + } + + /** + * Return the name of the base class or interface that plug-ins must conform + * to. + * + * @return string + */ + protected function getExpectedInterface() + { + return 'VuFind\Search\Base\Params'; + } +} diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Primo/Params.php b/module/FacetPrefix/src/FacetPrefix/Search/Primo/Params.php new file mode 100644 index 0000000000..a6a825344b --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Primo/Params.php @@ -0,0 +1,67 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace FacetPrefix\Search\Primo; + +use Libraries\Libraries; +use VuFindSearch\ParamBag; + +class Params extends \Libraries\Search\Primo\Params +{ + + /** + * Constructor + * + * @param \VuFind\Search\Base\Options $options Options to use + * @param \VuFind\Config\PluginManager $configLoader Config loader + */ + public function __construct($options, \VuFind\Config\PluginManager $configLoader, + \VuFind\Search\Memory $searchMemory + ) { + parent::__construct($options, $configLoader); + } + + /** + * Return current facet configurations + * + * @return array $facetSet + */ + public function getFacetSettings() + { + $facetSet = parent::getFacetSettings(); + + $facetConfig = $this->configLoader->get('facets'); + if (isset($facetConfig->FacetPrefix)) { + foreach ($facetConfig->FacetPrefix as $facet => $prefix) { + $facetSet["f.{$facet}.facet.prefix"] = $prefix; + } + } + + return $facetSet; + } +} + diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Results/PluginManager.php b/module/FacetPrefix/src/FacetPrefix/Search/Results/PluginManager.php new file mode 100644 index 0000000000..019c81992f --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Results/PluginManager.php @@ -0,0 +1,103 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace FacetPrefix\Search\Results; + +/** + * Search results plugin manager + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +class PluginManager extends \Libraries\Search\Results\PluginManager +{ + /** + * Default plugin aliases. + * + * @var array + */ + protected $aliases = [ + 'browzine' => 'VuFind\Search\BrowZine\Results', + 'combined' => 'VuFind\Search\Combined\Results', + 'eds' => 'VuFind\Search\EDS\Results', + 'eit' => 'VuFind\Search\EIT\Results', + 'emptyset' => 'VuFind\Search\EmptySet\Results', + 'favorites' => 'VuFind\Search\Favorites\Results', + 'libguides' => 'VuFind\Search\LibGuides\Results', + 'mixedlist' => 'VuFind\Search\MixedList\Results', + 'pazpar2' => 'VuFind\Search\Pazpar2\Results', + 'primo' => 'VuFind\Search\Primo\Results', + 'search2' => 'VuFind\Search\Search2\Results', + 'solr' => 'VuFind\Search\Solr\Results', + 'solrauth' => 'VuFind\Search\SolrAuth\Results', + 'solrauthor' => 'VuFind\Search\SolrAuthor\Results', + 'solrauthorfacets' => 'VuFind\Search\SolrAuthorFacets\Results', + 'solrcollection' => 'VuFind\Search\SolrCollection\Results', + 'solrreserves' => 'VuFind\Search\SolrReserves\Results', + 'solrweb' => 'VuFind\Search\SolrWeb\Results', + 'summon' => 'VuFind\Search\Summon\Results', + 'tags' => 'VuFind\Search\Tags\Results', + 'worldcat' => 'VuFind\Search\WorldCat\Results', + ]; + + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'VuFind\Search\BrowZine\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Combined\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\EDS\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\EIT\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\EmptySet\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Favorites\Results' => + 'VuFind\Search\Favorites\ResultsFactory', + 'VuFind\Search\LibGuides\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\MixedList\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Pazpar2\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Primo\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Search2\Results' => 'FacetPrefix\Search\Search2\ResultsFactory', + 'VuFind\Search\Solr\Results' => 'FacetPrefix\Search\Solr\ResultsFactory', + 'VuFind\Search\SolrAuth\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrAuthor\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrAuthorFacets\Results' => + 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrCollection\Results' => + 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrReserves\Results' => + 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrWeb\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Summon\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Tags\Results' => 'VuFind\Search\Tags\ResultsFactory', + 'VuFind\Search\WorldCat\Results' => 'VuFind\Search\Results\ResultsFactory', + ]; + +} diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Results/ResultsFactory.php b/module/FacetPrefix/src/FacetPrefix/Search/Results/ResultsFactory.php new file mode 100644 index 0000000000..2105085c62 --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Results/ResultsFactory.php @@ -0,0 +1,72 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace FacetPrefix\Search\Results; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * Generic factory for search results objects. + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ResultsFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + // Replace trailing "Results" with "Params" to get the params service: + $paramsService = preg_replace('/Results$/', 'Params', $requestedName); + $paramsService = preg_replace('/^VuFind/', 'FacetPrefix', $paramsService); + $params = $container->get('FacetPrefix\Search\Params\PluginManager') + ->get($paramsService); + $searchService = $container->get('VuFindSearch\Service'); + $recordLoader = $container->get('VuFind\Record\Loader'); + return new $requestedName( + $params, $searchService, $recordLoader, ...($options ?: []) + ); + } +} diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Search2/Params.php b/module/FacetPrefix/src/FacetPrefix/Search/Search2/Params.php new file mode 100644 index 0000000000..42926f03f5 --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Search2/Params.php @@ -0,0 +1,70 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace FacetPrefix\Search\Search2; + +use Libraries\Libraries; +use VuFindSearch\ParamBag; +use VuFind\Search\Solr\HierarchicalFacetHelper; +use SearchKeys\Search\SearchKeysHelper; + +class Params extends \Libraries\Search\Search2\Params +{ + /** + * Constructor + * + * @param \VuFind\Search\Base\Options $options Options to use + * @param \VuFind\Config\PluginManager $configLoader Config loader + */ + public function __construct($options, \VuFind\Config\PluginManager $configLoader, + HierarchicalFacetHelper $facetHelper = null, + SearchKeysHelper $searchKeysHelper, + \VuFind\Search\Memory $searchMemory + ) { + parent::__construct($options, $configLoader, $facetHelper, $searchKeysHelper); + } + + /** + * Return current facet configurations + * + * @return array $facetSet + */ + public function getFacetSettings() + { + $facetSet = parent::getFacetSettings(); + + $facetConfig = $this->configLoader->get('facets'); + if (isset($facetConfig->FacetPrefix)) { + foreach ($facetConfig->FacetPrefix as $facet => $prefix) { + $facetSet["f.{$facet}.facet.prefix"] = $prefix; + } + } + + return $facetSet; + } +} + diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Solr/Params.php b/module/FacetPrefix/src/FacetPrefix/Search/Solr/Params.php new file mode 100644 index 0000000000..b25a3b4aaa --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Solr/Params.php @@ -0,0 +1,74 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace FacetPrefix\Search\Solr; + +use Libraries\Libraries; +use VuFindSearch\ParamBag; +use VuFind\Search\Solr\HierarchicalFacetHelper; +use SearchKeys\Search\SearchKeysHelper; + +//use VuFind\Search\Solr\Params as BaseParams; +use Libraries\Search\Solr\Params as BaseParams; + +class Params extends BaseParams +{ + + /** + * Constructor + * + * @param \VuFind\Search\Base\Options $options Options to use + * @param \VuFind\Config\PluginManager $configLoader Config loader + */ + public function __construct($options, \VuFind\Config\PluginManager $configLoader, + HierarchicalFacetHelper $facetHelper = null, + SearchKeysHelper $searchKeysHelper, + \VuFind\Search\Memory $searchMemory + ) { + parent::__construct($options, $configLoader, $facetHelper, $searchKeysHelper, $searchMemory); + } + + /** + * Return current facet configurations + * + * @return array $facetSet + */ + public function getFacetSettings() + { + $facetSet = parent::getFacetSettings(); + + $facetConfig = $this->configLoader->get('facets'); + if (isset($facetConfig->FacetPrefix)) { + foreach ($facetConfig->FacetPrefix as $facet => $prefix) { + $facetSet["f.{$facet}.facet.prefix"] = $prefix; + } + } + + return $facetSet; + } +} + diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Solr/ParamsFactory.php b/module/FacetPrefix/src/FacetPrefix/Search/Solr/ParamsFactory.php new file mode 100644 index 0000000000..5a8ef00f38 --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Solr/ParamsFactory.php @@ -0,0 +1,68 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace FacetPrefix\Search\Solr; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Solr search params objects. + * + * @category VuFind + * @package Search_Solr + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ParamsFactory extends \FacetPrefix\Search\Params\ParamsFactory +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options sent to factory.'); + } + $facetHelper = $container->get('VuFind\Search\Solr\HierarchicalFacetHelper'); + $searchKeysHelper = $container->get('SearchKeys\Search\SearchKeysHelper'); + $searchMemory = $container->get('VuFind\Search\Memory'); + return parent::__invoke($container, $requestedName, [$facetHelper, $searchKeysHelper, $searchMemory]); + } +} diff --git a/module/FacetPrefix/src/FacetPrefix/Search/Solr/ResultsFactory.php b/module/FacetPrefix/src/FacetPrefix/Search/Solr/ResultsFactory.php new file mode 100644 index 0000000000..406c52ec65 --- /dev/null +++ b/module/FacetPrefix/src/FacetPrefix/Search/Solr/ResultsFactory.php @@ -0,0 +1,67 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace FacetPrefix\Search\Solr; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Solr search results objects. + * + * @category VuFind + * @package Search_Solr + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ResultsFactory extends \FacetPrefix\Search\Results\ResultsFactory +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + $solr = parent::__invoke($container, $requestedName, $options); + $config = $container->get('VuFind\Config\PluginManager')->get('config'); + $solr->setSpellingProcessor( + new \VuFind\Search\Solr\SpellingProcessor($config->Spelling ?? null) + ); + return $solr; + } +} diff --git a/module/Libraries/src/Libraries/AjaxHandler/GetLibraries.php b/module/Libraries/src/Libraries/AjaxHandler/GetLibraries.php index dd45f05ee6..23d1aa57ce 100644 --- a/module/Libraries/src/Libraries/AjaxHandler/GetLibraries.php +++ b/module/Libraries/src/Libraries/AjaxHandler/GetLibraries.php @@ -104,7 +104,7 @@ public function handleRequest(Params $params) foreach ($queryArray as $queryItem) { $arrayKey = false; list($key, $value) = explode('=', $queryItem, 2); - if (preg_match('/([0-9]\[\]$)/', $key, $matches)) { + if (preg_match('/[0-9](\[\]$)/', $key, $matches)) { $key = str_replace($matches[1], '', $key); $arrayKey = true; } @@ -136,7 +136,6 @@ public function handleRequest(Params $params) $paramsObj->setFacetLimit(2000); $paramsObj->getOptions()->disableHighlighting(); $paramsObj->getOptions()->spellcheckEnabled(false); -//print_r($searchParams); if (!empty($facetSearch)) { $this->Libraries->selectLibrary($facetSearch); @@ -168,17 +167,14 @@ public function handleRequest(Params $params) $libraryData[$libraryCode] = ['fullname' => $this->translator->translate($library['fullname']), 'count' => $count]; } -//print_r($libraryData); - $locationFacets = []; - foreach ($locationList as $locationItem) { $locationFacets[$locationItem['value']] = $locationItem['count']; } $locationFacets = $this->Libraries->getLocationList($locationFacets); $data = [ - 'libraryCount' => count($libraryData) + 2, + 'libraryCount' => count($libraryData), 'libraryData' => $libraryData, 'locationFacets' => $locationFacets, 'locationFilter' => ['field' => $locationFilter['field'], 'value' => ''], @@ -188,5 +184,3 @@ public function handleRequest(Params $params) } } - - diff --git a/module/PAIAplus/src/PAIAplus/ILS/Driver/PAIA.php b/module/PAIAplus/src/PAIAplus/ILS/Driver/PAIA.php index 201f55c5ba..94e2053b3a 100644 --- a/module/PAIAplus/src/PAIAplus/ILS/Driver/PAIA.php +++ b/module/PAIAplus/src/PAIAplus/ILS/Driver/PAIA.php @@ -343,7 +343,7 @@ public function getPickUpLocations($patron = null, $holdDetails = null) } else if ($holdDetails['type'] == 'recall') { if (isset($this->config['pickUpLocations'])) { foreach ($this->config['pickUpLocations'] as $pickUpLocationData) { - if ($pickUpLocationData[0] == $holdDetails['storage_id']) { + if ($pickUpLocationData[0] == $holdDetails['storage_id'] || $pickUpLocationData[0] == urldecode($holdDetails['storage_id'])) { $pickupLocation[] = [ 'locationID' => $pickUpLocationData[1], 'locationDisplay' => $pickUpLocationData[2], diff --git a/module/RelevancePicker/Module.php b/module/RelevancePicker/Module.php new file mode 100644 index 0000000000..5bcde6ea58 --- /dev/null +++ b/module/RelevancePicker/Module.php @@ -0,0 +1,92 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/dmj/vf2-proxy + */ +namespace RelevancePicker; +use Zend\ModuleManager\ModuleManager, + Zend\Mvc\MvcEvent; + +/** + * Template for ZF2 module for storing local overrides. + * + * @category VuFind2 + * @package Module + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/dmj/vf2-proxy + */ +class Module +{ + /** + * Get module configuration + * + * @return array + */ + public function getConfig() + { + return include __DIR__ . '/config/module.config.php'; + } + + /** + * Get autoloader configuration + * + * @return array + */ + public function getAutoloaderConfig() + { + return array( + 'Zend\Loader\StandardAutoloader' => array( + 'namespaces' => array( + __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, + ), + ), + ); + } + + /** + * Initialize the module + * + * @param ModuleManager $m Module manager + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function init(ModuleManager $m) + { + } + + /** + * Bootstrap the module + * + * @param MvcEvent $e Event + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function onBootstrap(MvcEvent $e) + { + } +} diff --git a/module/RelevancePicker/config/module.config.php b/module/RelevancePicker/config/module.config.php new file mode 100644 index 0000000000..d5450df9e8 --- /dev/null +++ b/module/RelevancePicker/config/module.config.php @@ -0,0 +1,23 @@ + [ + 'allow_override' => true, + 'factories' => [ +// 'Libraries\AjaxHandler\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', + 'RelevancePicker\Search\BackendManager' => 'RelevancePicker\Search\BackendManagerFactory', + 'RelevancePicker\Search\Params\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', + 'RelevancePicker\Search\Results\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', + ], + 'aliases' => [ +// 'VuFind\AjaxHandler\PluginManager' => 'Libraries\AjaxHandler\PluginManager', + 'VuFind\Search\BackendManager' => 'RelevancePicker\Search\BackendManager', + 'VuFind\Search\Params\PluginManager' => 'RelevancePicker\Search\Params\PluginManager', + 'VuFind\Search\Results\PluginManager' => 'RelevancePicker\Search\Results\PluginManager', + ], + ], +]; + +return $config; + diff --git a/module/RelevancePicker/src/RelevancePicker/Backend/Solr/Response/Json/RecordCollection.php b/module/RelevancePicker/src/RelevancePicker/Backend/Solr/Response/Json/RecordCollection.php new file mode 100644 index 0000000000..7ab9ca7fba --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Backend/Solr/Response/Json/RecordCollection.php @@ -0,0 +1,66 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org + */ +namespace RelevancePicker\Backend\Solr\Response\Json; + +use VuFindSearch\Response\AbstractRecordCollection; + +/** + * Simple JSON-based record collection. + * + * @category VuFind + * @package Search + * @author David Maus + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org + */ +class RecordCollection extends \VuFindSearch\Backend\Solr\Response\Json\RecordCollection +{ + /** + * Return explain part. + * + * @return array + */ + public function getExplain() + { + $explainData = array(); + if (isset($this->response['debug']['explain'])) { + foreach ($this->response['debug']['explain'] as $ppn => $explain) { + $explainDataList = array(); + $lines = explode("\n", $explain); + foreach ($lines as $line) { + if (preg_match('/^[0-9 ].+of:$/', $line)) { + $explainDataList[] = $line; + } + } + $explainData[$ppn] = "\n" . implode("\n", $explainDataList); + } + } + return $explainData; + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Backend/Solr/Response/Json/RecordCollectionFactory.php b/module/RelevancePicker/src/RelevancePicker/Backend/Solr/Response/Json/RecordCollectionFactory.php new file mode 100644 index 0000000000..0313572718 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Backend/Solr/Response/Json/RecordCollectionFactory.php @@ -0,0 +1,106 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org + */ +namespace RelevancePicker\Backend\Solr\Response\Json; + +use VuFindSearch\Exception\InvalidArgumentException; +use VuFindSearch\Response\RecordCollectionFactoryInterface; +use VuFindSearch\Backend\Solr\Response\Json\Record; + +/** + * Simple JSON-based factory for record collection. + * + * @category VuFind + * @package Search + * @author David Maus + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org + */ +class RecordCollectionFactory implements RecordCollectionFactoryInterface +{ + /** + * Factory to turn data into a record object. + * + * @var Callable + */ + protected $recordFactory; + + /** + * Class of collection. + * + * @var string + */ + protected $collectionClass; + + /** + * Constructor. + * + * @param Callable $recordFactory Callback to construct records + * @param string $collectionClass Class of collection + * + * @return void + */ + public function __construct($recordFactory = null, + $collectionClass = 'RelevancePicker\Backend\Solr\Response\Json\RecordCollection' + ) { + if (null === $recordFactory) { + $this->recordFactory = function ($data) { + return new Record($data); + }; + } else { + $this->recordFactory = $recordFactory; + } + $this->collectionClass = $collectionClass; + } + + /** + * Return record collection. + * + * @param array $response Deserialized JSON response + * + * @return RecordCollection + */ + public function factory($response) + { + if (!is_array($response)) { + throw new InvalidArgumentException( + sprintf( + 'Unexpected type of value: Expected array, got %s', + gettype($response) + ) + ); + } + $collection = new $this->collectionClass($response); + if (isset($response['response']['docs'])) { + foreach ($response['response']['docs'] as $doc) { + $collection->add(call_user_func($this->recordFactory, $doc)); + } + } + return $collection; + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/BackendManager.php b/module/RelevancePicker/src/RelevancePicker/Search/BackendManager.php new file mode 100644 index 0000000000..66e382c68f --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/BackendManager.php @@ -0,0 +1,55 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +namespace RelevancePicker\Search; + +use Zend\ServiceManager\ServiceLocatorInterface; + +/** + * Manager for search backends. + * + * @category VuFind + * @package Search + * @author David Maus + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +class BackendManager extends \Libraries\Search\BackendManager +{ + /** + * Constructor. + * + * @param ServiceLocatorInterface $registry Backend registry + * + * @return void + */ + public function __construct(ServiceLocatorInterface $registry) + { + parent::__construct($registry); + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/BackendManagerFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/BackendManagerFactory.php new file mode 100644 index 0000000000..26ff7b1000 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/BackendManagerFactory.php @@ -0,0 +1,81 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\Search; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * Search Backend Manager factory. + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class BackendManagerFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options sent to factory.'); + } + return new $requestedName($this->getRegistry($container)); + } + + /** + * Create the backend registry. + * + * @param ContainerInterface $container Service manager + * + * @return BackendRegistry + */ + protected function getRegistry(ContainerInterface $container) + { + $config = $container->get('config'); + return new BackendRegistry( + $container, $config['vufind']['plugin_managers']['search_backend'] + ); + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/BackendRegistry.php b/module/RelevancePicker/src/RelevancePicker/Search/BackendRegistry.php new file mode 100644 index 0000000000..d40e7aa575 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/BackendRegistry.php @@ -0,0 +1,62 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +namespace RelevancePicker\Search; + +/** + * Registry for search backends. + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +class BackendRegistry extends \Libraries\Search\BackendRegistry +{ + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'BrowZine' => 'VuFind\Search\Factory\BrowZineBackendFactory', + 'EDS' => 'VuFind\Search\Factory\EdsBackendFactory', + 'EIT' => 'VuFind\Search\Factory\EITBackendFactory', + 'LibGuides' => 'VuFind\Search\Factory\LibGuidesBackendFactory', + 'Pazpar2' => 'VuFind\Search\Factory\Pazpar2BackendFactory', + 'Primo' => 'VuFind\Search\Factory\PrimoBackendFactory', + 'Search2' => 'RelevancePicker\Search\Factory\Search2BackendFactory', + 'Solr' => 'RelevancePicker\Search\Factory\SolrDefaultBackendFactory', + 'SolrAuth' => 'VuFind\Search\Factory\SolrAuthBackendFactory', + 'SolrReserves' => 'VuFind\Search\Factory\SolrReservesBackendFactory', + 'SolrWeb' => 'VuFind\Search\Factory\SolrWebBackendFactory', + 'Summon' => 'VuFind\Search\Factory\SummonBackendFactory', + 'WorldCat' => 'VuFind\Search\Factory\WorldCatBackendFactory', + ]; +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Factory/Search2BackendFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Factory/Search2BackendFactory.php new file mode 100644 index 0000000000..0d9a2c505f --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Factory/Search2BackendFactory.php @@ -0,0 +1,43 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace RelevancePicker\Search\Factory; + +class Search2BackendFactory extends \RelevancePicker\Search\Factory\SolrDefaultBackendFactory +{ + /** + * Constructor + */ + public function __construct() + { + parent::__construct(); + $this->mainConfig = $this->searchConfig = $this->facetConfig = 'Search2'; + $this->searchYaml = 'searchspecs2.yaml'; + } +} + + diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Factory/SolrDefaultBackendFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Factory/SolrDefaultBackendFactory.php new file mode 100644 index 0000000000..09c5417691 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Factory/SolrDefaultBackendFactory.php @@ -0,0 +1,53 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace RelevancePicker\Search\Factory; + +use RelevancePicker\Backend\Solr\Response\Json\RecordCollectionFactory; +use Libraries\Backend\Solr\Connector; +use Libraries\Search\Factory\SolrDefaultBackendFactory as BackendFactory; +use VuFind\Search\Factory\AbstractSolrBackendFactory; + +class SolrDefaultBackendFactory extends BackendFactory +{ + /** + * Create the SOLR backend. + * + * @param Connector $connector Connector + * + * @return Backend + */ + protected function createBackend(Connector $connector) + { + $backend = AbstractSolrBackendFactory::createBackend($connector); + $manager = $this->serviceLocator->get('RecordDriver\RecordDriver\PluginManager'); + $factory = new RecordCollectionFactory([$manager, 'getSolrRecord']); + $backend->setRecordCollectionFactory($factory); + return $backend; + } +} + diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Params/ParamsFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Params/ParamsFactory.php new file mode 100644 index 0000000000..48c13e26c8 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Params/ParamsFactory.php @@ -0,0 +1,73 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\Search\Params; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * Generic factory for search params objects. + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ParamsFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + // Replace trailing "Params" with "Options" to get the options service: + $optionsService = preg_replace('/Params$/', 'Options', $requestedName); + // Replace leading "SearchKeys" with "VuFind" to get the VuFind options service: + $optionsService = preg_replace('/^RelevancePicker/', 'VuFind', $optionsService); + $optionsObj = $container->get('VuFind\Search\Options\PluginManager') + ->get($optionsService); + $configLoader = $container->get('VuFind\Config\PluginManager'); + // Clone the options instance in case caller modifies it: + return new $requestedName( + clone $optionsObj, $configLoader, ...($options ?: []) + ); + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Params/PluginManager.php b/module/RelevancePicker/src/RelevancePicker/Search/Params/PluginManager.php new file mode 100644 index 0000000000..ef7317c397 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Params/PluginManager.php @@ -0,0 +1,132 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace RelevancePicker\Search\Params; + +/** + * Search params plugin manager + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +class PluginManager extends \VuFind\Search\Params\PluginManager +{ + /** + * Default plugin aliases. + * + * @var array + */ + protected $aliases = [ + 'browzine' => 'VuFind\Search\BrowZine\Params', + 'combined' => 'VuFind\Search\Combined\Params', + 'eds' => 'VuFind\Search\EDS\Params', + 'eit' => 'VuFind\Search\EIT\Params', + 'emptyset' => 'VuFind\Search\EmptySet\Params', + 'favorites' => 'VuFind\Search\Favorites\Params', + 'libguides' => 'VuFind\Search\LibGuides\Params', + 'mixedlist' => 'VuFind\Search\MixedList\Params', + 'pazpar2' => 'VuFind\Search\Pazpar2\Params', + 'primo' => 'VuFind\Search\Primo\Params', + 'search2' => 'RelevancePicker\Search\Search2\Params', + 'solr' => 'RelevancePicker\Search\Solr\Params', + 'solrauth' => 'VuFind\Search\SolrAuth\Params', + 'solrauthor' => 'VuFind\Search\SolrAuthor\Params', + 'solrauthorfacets' => 'VuFind\Search\SolrAuthorFacets\Params', + 'solrcollection' => 'VuFind\Search\SolrCollection\Params', + 'solrreserves' => 'VuFind\Search\SolrReserves\Params', + 'solrweb' => 'VuFind\Search\SolrWeb\Params', + 'summon' => 'VuFind\Search\Summon\Params', + 'tags' => 'VuFind\Search\Tags\Params', + 'worldcat' => 'VuFind\Search\WorldCat\Params', + ]; + + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'RelevancePicker\Search\Search2\Params' => 'RelevancePicker\Search\Search2\ParamsFactory', + 'RelevancePicker\Search\Solr\Params' => 'RelevancePicker\Search\Solr\ParamsFactory', + 'VuFind\Search\BrowZine\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Combined\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\EDS\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\EIT\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\EmptySet\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Favorites\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\LibGuides\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\MixedList\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Pazpar2\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Primo\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrAuth\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrAuthor\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrAuthorFacets\Params' => + 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrCollection\Params' => + 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrReserves\Params' => + 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\SolrWeb\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Summon\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\Tags\Params' => 'VuFind\Search\Params\ParamsFactory', + 'VuFind\Search\WorldCat\Params' => 'VuFind\Search\Params\ParamsFactory', + ]; + + /** + * Constructor + * + * Make sure plugins are properly initialized. + * + * @param mixed $configOrContainerInstance Configuration or container instance + * @param array $v3config If $configOrContainerInstance is a + * container, this value will be passed to the parent constructor. + */ + public function __construct($configOrContainerInstance = null, + array $v3config = [] + ) { + // These objects are not meant to be shared -- every time we retrieve one, + // we are building a brand new object. + $this->sharedByDefault = false; + + $this->addAbstractFactory('VuFind\Search\Params\PluginFactory'); + parent::__construct($configOrContainerInstance, $v3config); + } + + /** + * Return the name of the base class or interface that plug-ins must conform + * to. + * + * @return string + */ + protected function getExpectedInterface() + { + return 'VuFind\Search\Base\Params'; + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Results/PluginManager.php b/module/RelevancePicker/src/RelevancePicker/Search/Results/PluginManager.php new file mode 100644 index 0000000000..eef754299c --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Results/PluginManager.php @@ -0,0 +1,103 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace RelevancePicker\Search\Results; + +/** + * Search results plugin manager + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +class PluginManager extends \VuFind\Search\Results\PluginManager +{ + /** + * Default plugin aliases. + * + * @var array + */ + protected $aliases = [ + 'browzine' => 'VuFind\Search\BrowZine\Results', + 'combined' => 'VuFind\Search\Combined\Results', + 'eds' => 'VuFind\Search\EDS\Results', + 'eit' => 'VuFind\Search\EIT\Results', + 'emptyset' => 'VuFind\Search\EmptySet\Results', + 'favorites' => 'VuFind\Search\Favorites\Results', + 'libguides' => 'VuFind\Search\LibGuides\Results', + 'mixedlist' => 'VuFind\Search\MixedList\Results', + 'pazpar2' => 'VuFind\Search\Pazpar2\Results', + 'primo' => 'VuFind\Search\Primo\Results', + 'search2' => 'RelevancePicker\Search\Search2\Results', + 'solr' => 'RelevancePicker\Search\Solr\Results', + 'solrauth' => 'VuFind\Search\SolrAuth\Results', + 'solrauthor' => 'VuFind\Search\SolrAuthor\Results', + 'solrauthorfacets' => 'VuFind\Search\SolrAuthorFacets\Results', + 'solrcollection' => 'VuFind\Search\SolrCollection\Results', + 'solrreserves' => 'VuFind\Search\SolrReserves\Results', + 'solrweb' => 'VuFind\Search\SolrWeb\Results', + 'summon' => 'VuFind\Search\Summon\Results', + 'tags' => 'VuFind\Search\Tags\Results', + 'worldcat' => 'VuFind\Search\WorldCat\Results', + ]; + + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'RelevancePicker\Search\Solr\Results' => 'RelevancePicker\Search\Solr\ResultsFactory', + 'RelevancePicker\Search\Search2\Results' => 'RelevancePicker\Search\Search2\ResultsFactory', + 'VuFind\Search\BrowZine\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Combined\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\EDS\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\EIT\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\EmptySet\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Favorites\Results' => + 'VuFind\Search\Favorites\ResultsFactory', + 'VuFind\Search\LibGuides\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\MixedList\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Pazpar2\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Primo\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrAuth\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrAuthor\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrAuthorFacets\Results' => + 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrCollection\Results' => + 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrReserves\Results' => + 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\SolrWeb\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Summon\Results' => 'VuFind\Search\Results\ResultsFactory', + 'VuFind\Search\Tags\Results' => 'VuFind\Search\Tags\ResultsFactory', + 'VuFind\Search\WorldCat\Results' => 'VuFind\Search\Results\ResultsFactory', + ]; + +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Results/ResultsFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Results/ResultsFactory.php new file mode 100644 index 0000000000..b447aebfe6 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Results/ResultsFactory.php @@ -0,0 +1,72 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\Search\Results; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * Generic factory for search results objects. + * + * @category VuFind + * @package Search + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ResultsFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + // Replace trailing "Results" with "Params" to get the params service: + $paramsService = preg_replace('/Results$/', 'Params', $requestedName); +// $paramsService = preg_replace('/^VuFind/', 'RelevancePicker', $paramsService); + $params = $container->get('RelevancePicker\Search\Params\PluginManager') + ->get($paramsService); + $searchService = $container->get('VuFindSearch\Service'); + $recordLoader = $container->get('VuFind\Record\Loader'); + return new $requestedName( + $params, $searchService, $recordLoader, ...($options ?: []) + ); + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Search2/Params.php b/module/RelevancePicker/src/RelevancePicker/Search/Search2/Params.php new file mode 100644 index 0000000000..d10c560716 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Search2/Params.php @@ -0,0 +1,55 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace RelevancePicker\Search\Search2; + +class Params extends \RelevancePicker\Search\Solr\Params +{ + /** + * Initialize facet settings for the advanced search screen. + * + * @return void + */ + public function initAdvancedFacets() + { + $this->initFacetList('Advanced_Facets', 'Advanced_Settings'); + } + + /** + * Initialize facet settings for the home page. + * + * @return void + */ + public function initHomePageFacets() + { + // Load Advanced settings if HomePage settings are missing (legacy support): + if (!$this->initFacetList('HomePage_Facets', 'HomePage_Facet_Settings')) { + $this->initAdvancedFacets(); + } + } +} + diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Search2/ParamsFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Search2/ParamsFactory.php new file mode 100644 index 0000000000..a819353226 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Search2/ParamsFactory.php @@ -0,0 +1,68 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\Search\Search2; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Solr search params objects. + * + * @category VuFind + * @package Search_Solr + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ParamsFactory extends \RelevancePicker\Search\Params\ParamsFactory +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options sent to factory.'); + } + $facetHelper = $container->get('VuFind\Search\Solr\HierarchicalFacetHelper'); + $searchKeysHelper = $container->get('SearchKeys\Search\SearchKeysHelper'); + $searchMemory = $container->get('VuFind\Search\Memory'); + return parent::__invoke($container, $requestedName, [$facetHelper, $searchKeysHelper, $searchMemory]); + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Search2/Results.php b/module/RelevancePicker/src/RelevancePicker/Search/Search2/Results.php new file mode 100644 index 0000000000..bb7eae7fdc --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Search2/Results.php @@ -0,0 +1,39 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace RelevancePicker\Search\Search2; + +class Results extends \RelevancePicker\Search\Solr\Results +{ + /** + * Backend ID + * + * @var string + */ + protected $backendId = 'Search2'; +} + diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Search2/ResultsFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Search2/ResultsFactory.php new file mode 100644 index 0000000000..b7c13197e8 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Search2/ResultsFactory.php @@ -0,0 +1,67 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\Search\Search2; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Solr search results objects. + * + * @category VuFind + * @package Search_Solr + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ResultsFactory extends \RelevancePicker\Search\Results\ResultsFactory +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + $solr = parent::__invoke($container, $requestedName, $options); + $config = $container->get('VuFind\Config\PluginManager')->get('Search2'); + $solr->setSpellingProcessor( + new \VuFind\Search\Solr\SpellingProcessor($config->Spelling ?? null) + ); + return $solr; + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Solr/Params.php b/module/RelevancePicker/src/RelevancePicker/Search/Solr/Params.php new file mode 100644 index 0000000000..65fac89bcf --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Solr/Params.php @@ -0,0 +1,71 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace RelevancePicker\Search\Solr; + +use VuFindSearch\ParamBag; +use VuFind\Search\Solr\HierarchicalFacetHelper; +use SearchKeys\Search\SearchKeysHelper; + +//use VuFind\Search\Solr\Params as BaseParams; +use Libraries\Search\Solr\Params as BaseParams; + +class Params extends BaseParams +{ + protected $Libraries = null; + protected $selectedLibrary = null; + protected $includedLibraries = null; + protected $excludedLibraries = null; + protected $facetFieldPrefix = []; + + /** + * Constructor + * + * @param \VuFind\Search\Base\Options $options Options to use + * @param \VuFind\Config\PluginManager $configLoader Config loader + */ + public function __construct($options, \VuFind\Config\PluginManager $configLoader, + HierarchicalFacetHelper $facetHelper = null, + SearchKeysHelper $searchKeysHelper, + \VuFind\Search\Memory $searchMemory + ) { + parent::__construct($options, $configLoader, $facetHelper, $searchKeysHelper, $searchMemory); + } + + /** + * Create search backend parameters for advanced features. + * + * @return ParamBag + */ + public function getBackendParameters() + { + $backendParams = parent::getBackendParameters(); + $backendParams->add('debugQuery', 'on'); + return $backendParams; + } +} + diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Solr/ParamsFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Solr/ParamsFactory.php new file mode 100644 index 0000000000..c1bc9fd592 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Solr/ParamsFactory.php @@ -0,0 +1,68 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\Search\Solr; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Solr search params objects. + * + * @category VuFind + * @package Search_Solr + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ParamsFactory extends \RelevancePicker\Search\Params\ParamsFactory +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options sent to factory.'); + } + $facetHelper = $container->get('VuFind\Search\Solr\HierarchicalFacetHelper'); + $searchKeysHelper = $container->get('SearchKeys\Search\SearchKeysHelper'); + $searchMemory = $container->get('VuFind\Search\Memory'); + return parent::__invoke($container, $requestedName, [$facetHelper, $searchKeysHelper, $searchMemory]); + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Solr/Results.php b/module/RelevancePicker/src/RelevancePicker/Search/Solr/Results.php new file mode 100644 index 0000000000..bb0acc8c3e --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Solr/Results.php @@ -0,0 +1,100 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://github.com/subhh/beluga + */ +namespace RelevancePicker\Search\Solr; + +//use VuFind\Search\Solr\Params as BaseParams; +use VuFind\Search\Solr\Results as BaseResults; + +class Results extends BaseResults +{ + /** + * ExplainData. + * + * @array explain + */ + protected $explain = []; + + /** + * Support method for performAndProcessSearch -- perform a search based on the + * parameters passed to the object. + * + * @return void + */ + protected function performSearch() + { + $query = $this->getParams()->getQuery(); + $limit = $this->getParams()->getLimit(); + $offset = $this->getStartRecord() - 1; + $params = $this->getParams()->getBackendParameters(); + $searchService = $this->getSearchService(); + + try { + $collection = $searchService + ->search($this->backendId, $query, $offset, $limit, $params); + } catch (\VuFindSearch\Backend\Exception\BackendException $e) { + // If the query caused a parser error, see if we can clean it up: + if ($e->hasTag('VuFind\Search\ParserError') + && $newQuery = $this->fixBadQuery($query) + ) { + // We need to get a fresh set of $params, since the previous one was + // manipulated by the previous search() call. + $params = $this->getParams()->getBackendParameters(); + $collection = $searchService + ->search($this->backendId, $newQuery, $offset, $limit, $params); + } else { + throw $e; + } + } + + $this->responseFacets = $collection->getFacets(); + $this->resultTotal = $collection->getTotal(); + + // Process spelling suggestions + $spellcheck = $collection->getSpellcheck(); + $this->spellingQuery = $spellcheck->getQuery(); + $this->suggestions = $this->getSpellingProcessor() + ->getSuggestions($spellcheck, $this->getParams()->getQuery()); + + // Construct record drivers for all the items in the response: + $this->results = $collection->getRecords(); + + // Process Explain Data: + $this->explain = $collection->getExplain(); + } + + /** + * Get explain Data + * + * @return array. + */ + public function getExplain() + { + return $this->explain; + } +} + diff --git a/module/RelevancePicker/src/RelevancePicker/Search/Solr/ResultsFactory.php b/module/RelevancePicker/src/RelevancePicker/Search/Solr/ResultsFactory.php new file mode 100644 index 0000000000..4d099e4f88 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/Search/Solr/ResultsFactory.php @@ -0,0 +1,67 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\Search\Solr; + +use Interop\Container\ContainerInterface; + +/** + * Factory for Solr search results objects. + * + * @category VuFind + * @package Search_Solr + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class ResultsFactory extends \RelevancePicker\Search\Results\ResultsFactory +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + $solr = parent::__invoke($container, $requestedName, $options); + $config = $container->get('VuFind\Config\PluginManager')->get('config'); + $solr->setSpellingProcessor( + new \VuFind\Search\Solr\SpellingProcessor($config->Spelling ?? null) + ); + return $solr; + } +} diff --git a/module/RelevancePicker/src/RelevancePicker/View/Helper/RelevancePicker/Tooltip.php b/module/RelevancePicker/src/RelevancePicker/View/Helper/RelevancePicker/Tooltip.php new file mode 100644 index 0000000000..23d6d38bde --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/View/Helper/RelevancePicker/Tooltip.php @@ -0,0 +1,258 @@ + 'Personendaten', + 'title-main' => 'Titeldaten' , + 'title-alt' => 'Weitere Titel' , + 'title-series' => 'Reihentitel' , + 'topic' => 'Schlagwörter' , + 'class' => 'Klassifikation' , + 'fulltext' => 'Volltextdaten' + ]; + protected $clusterConfig = [ + 'author' => ['author', 'author2', 'author2_variant', 'author_corporate'], + 'title-main' => ['title', 'title_full', 'title_sub', 'title_auth', 'title_short'], + 'title-alt' => ['title_alt' ,'title_new', 'title_old'], + 'title-series' => ['series' ,'series2', 'journal'], + 'topic' => ['topic' ,'geographic'], + 'class' => ['class' ,'bklname'], + 'fulltext' => ['fulltext', 'contents', 'abstract'], + ]; + protected $clusters; + protected $searchTerm; + protected $results; + + public function __construct() { + } + + public function setData($explainData) { + $this->explainData = explode("\n", $explainData); + foreach ($this->clusterConfig as $cluster => $fields) { + foreach ($fields as $field) { + $this->clusters[$field] = $cluster; + } + } + $this->parseValues(); + } + + public function getValues() { + return $this->scores; + } + + public function getData() { + return $this->explainData; + } + + public function getResults() { + $allFieldTerms = $this->scores['clusters-terms']['all']; + $allFieldPhrase = $this->scores['clusters-phrase']['all']; + $allFields = $allFieldTerms + $allFieldPhrase; + $allBoostings = $this->scores['bq']['all']; + $all = $allFields + $allBoostings; + + foreach ($this->scores['bq'] as $key => $value) { + $key = str_replace('bq-', '', $key); + $term = $this->searchTerm[$key.$value]; + if ($key != 'all') { + $this->results['boosting-'.$key][$term] = array('field' => $key, 'term' => $term, 'value' => $value, 'percent' => round( 100 * $value / $allBoostings)); + $this->results['all']['boosting-'.$key] = array('percent' => round(100 * $value / $all)); + } + } + + foreach ($this->results['fields-terms'] as $term => $data) { + $cluster = $this->getCluster($data['field']); + $percent = round(100 * $data['value'] / $allFields); + if (isset( $cluster ) && $percent > 0) { + $this->results['fields-terms'][$term]['cluster'] = $this->clusterName[$cluster]; + $this->results['fields-terms'][$term]['percent'] = round(100 * $data['value'] / $allFields); + } else { + unset($this->results['fields-terms'][$term]); + } + } + foreach ($this->results['fields-phrase'] as $term => $data) { + $cluster = $this->getCluster($data['field']); + $percent = round(100 * $data['value'] / $allFields); + if (isset($cluster) && $percent > 0) { + $this->results['fields-phrase'][$term]['cluster'] = $this->clusterName[$cluster]; + $this->results['fields-phrase'][$term]['percent'] = round(100 * $data['value'] / $allFields); + } else { + unset($this->results['fields-phrase'][$term]); + } + } + $this->results['all']['fields-terms'] = array('percent' => round(100 * $allFieldTerms / $all)); + $this->results['all']['fields-phrase'] = array('percent' => round(100 * $allFieldPhrase / $all)); + $this->results['all']['fields-all'] = array('percent' => round(100 * $allFields / $all)); + + return $this->results; + } + + + protected function parseValues() { + $tie = 0; + $scores = $this->prepareScores(); + $this->scores = $scores; + $this->results = []; + $fieldFound = false; + foreach ($this->explainData as $line) { + $value = 0; + if (preg_match( '/^(\s*)([0-9.]+) = (sum|max) (plus ([0-9.]+) times others )?of:$/', $line, $matches)) { + $level = strlen( $matches[1] ) / 2; + if ($matches[3] == 'max') { + if (isset( $matches[5])) { + $tie = $matches[5]; + } + $this->calculateValues($scores, $tie); + $scores = $this->prepareScores(); + } + } elseif (preg_match( '/^(\s*)([0-9.]+) = weight\((Synonym\()?([^:]+):(.+)\)? in [0-9]+\) \[SchemaSimilarity\], result of:/', $line, $matches)) { + $statementLevel = strlen($matches[1]) / 2; + $value = floatval($matches[2]); + $field = $matches[4]; + $realField = str_replace('_unstemmed', '', $field); + $string = $matches[5]; + $this->searchTerm[$realField.$value] = str_replace('"', '', $string); + if ($statementLevel > $level || $statementLevel == 0) { + $fieldFound = true; + $suffix = (preg_match('/^"(.+)"$/' , $string)) ? 'phrase' : 'terms'; + if (!isset( $scores['fields-'.$suffix][$field])) { + $scores['fields-'.$suffix][$field] = 0; + } + $scores['fields-'.$suffix][$field] += $value; + } else { + if (!isset( $scores['bq-'.$field])) { + $scores['bq-'.$field] = [$string => 0]; + } + $scores['bq-'.$field][$string] += $value; + } + } elseif (preg_match( '/^(\s*)([0-9.]+) = FunctionQuery\((.+)\), product of:/' ,$line ,$matches)) { + $statementLevel = strlen( $matches[1] ) / 2; + $value = floatval($matches[2]); + $identifier = substr(md5($matches[3]) ,0 ,10); + if ($statementLevel <= $level) { + if (!isset( $scores['bf'][$identifier])) { + $scores['bf'][$identifier] = 0; + } + $scores['bf'][$identifier] += $value; + } elseif ( $value > 0 ) { + $scores['lost'] += $value; + } + } elseif ( $value > 0 ) { + $scores['lost'] += $value; + } + } + if ( $fieldFound ) { + $this->calculateValues($scores ,$tie); + $this->calculateClusters(); + } + } + + protected function getCluster($field) { + return $this->clusters[$field]; + } + + protected function prepareScores() { + return [ + 'all' => ['all' => 0, 'bf' => 0, 'bq' => 0, 'br' => 0], + 'bf' => ['all' => 0], + 'bq' => ['all' => 0], + 'br' => ['all' => 0, 'terms' => 0, 'phrase' => 0], + 'fields-all' => ['all' => 0], + 'fields-phrase' => ['all' => 0], + 'fields-terms' => ['all' => 0], + 'clusters-all' => ['all' => 0], + 'clusters-phrase' => ['all' => 0], + 'clusters-terms' => ['all' => 0], + 'lost' => 0 + ]; + } + + protected function calculateValues($scores, $tie) { + $maxItem = ['fields-phrase' => '' , 'fields-terms' => '']; + $maxValue = ['fields-phrase' => 0 , 'fields-terms' => 0]; + foreach ( $scores as $area => $areaScores ) { + foreach ( $areaScores as $item => $value ) { + $item = str_replace( '_unstemmed' , '' , $item ); + if ( strpos( $area , 'fields-' ) === 0 ) { + $suffix = ( strpos( $area , 'terms' ) !== false ) ? 'terms' : 'phrase'; + $this->scores['all']['all'] += $tie * $value; + $this->scores['all']['br'] += $tie * $value; + $this->scores['br']['all'] += $tie * $value; + $this->scores['br'][$suffix] += $tie * $value; + $this->scores['fields-all']['all'] += $tie * $value; + $this->scores['fields-all'][$item] += $tie * $value; + $this->scores[$area][$item] += $tie * $value; + $this->scores[$area]['all'] += $tie * $value; + if ( $value > $maxValue[$area] ) { + $maxItem[$area] = $item; + $maxValue[$area] = $value; + } + } else { + $this->scores['all']['all'] += $value; + $this->scores[$area]['all'] += $value; + if ( !isset( $this->scores[$area][$item])) { + $this->scores[$area][$item] = 0; + } + $this->scores[$area][$item] += $value; + if (strpos( $area , 'bq-' ) === 0 ) { + if (!isset( $this->scoreStructure['bq'][$area])) { + $this->scoreStructure['bq'][$area] = 0; + } + $this->scores['all']['bq'] += $value; + $this->scores['bq']['all'] += $value; + if (!isset( $this->scores['bq'][$area])) { + $this->scores['bq'][$area] = 0; + } + $this->scores['bq'][$area] += $value; + } elseif ($area == 'bf') { + $this->scores['all']['bf'] += $value; + if (!isset( $this->minimumBoostingValues[$item] ) || $value < $this->minimumBoostingValues[$item]) { + $this->minimumBoostingValues[$item] = $value; + } + } + } + } + if (strpos($area, 'fields-') === 0 && $maxValue[$area] > 0) { + $term = $this->searchTerm[$maxItem[$area].$maxValue[$area]]; + $this->results[$area][$term] = ['field' => $maxItem[$area] , 'term' => $term , 'value' => $maxValue[$area]]; + $suffix = (strpos($area, 'terms') !== false) ? 'terms' : 'phrase'; + $value = (1 - $tie) * $maxValue[$area]; + $this->scores['all']['all'] += $value; + $this->scores['all']['br'] += $value; + $this->scores['br']['all'] += $value; + $this->scores['br'][$suffix] += $value; + $this->scores['fields-all'][$maxItem[$area]] += $value; + $this->scores['fields-all']['all'] += $value; + $this->scores[$area][$maxItem[$area]] += $value; + $this->scores[$area]['all'] += $value; + } + } + } + + protected function calculateClusters() { + foreach (['-all' ,'-terms' ,'-phrase'] as $suffix) { + foreach ($this->scores['fields'.$suffix] as $item => $value) { + if ($item != 'all') { + if (!isset( $this->clusters[$item])) { + $this->clusters[$item] = 'others'; + } + if (!isset( $this->scores['clusters'.$suffix][$this->clusters[$item]])) { + $this->scores['clusters'.$suffix][$this->clusters[$item]] = 0; + } + $this->scores['clusters'.$suffix][$this->clusters[$item]] += $value; + $this->scores['clusters'.$suffix]['all'] += $value; + } + } + asort($this->scores['fields'.$suffix], SORT_NUMERIC); + $this->scores['fields'.$suffix] = array_reverse( $this->scores['fields'.$suffix] ); + } + } + +} diff --git a/module/RelevancePicker/src/RelevancePicker/View/Helper/RelevancePicker/TooltipFactory.php b/module/RelevancePicker/src/RelevancePicker/View/Helper/RelevancePicker/TooltipFactory.php new file mode 100644 index 0000000000..87ccef5f71 --- /dev/null +++ b/module/RelevancePicker/src/RelevancePicker/View/Helper/RelevancePicker/TooltipFactory.php @@ -0,0 +1,66 @@ + + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace RelevancePicker\View\Helper\RelevancePicker; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * SearchBox helper factory. + * + * @category VuFind + * @package View_Helpers + * @author Demian Katz + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class TooltipFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options sent to factory.'); + } + return new $requestedName(); + } +} diff --git a/themes/beluga-core-base/templates/search/relevancepicker-list-list.phtml b/themes/beluga-core-base/templates/search/relevancepicker-list-list.phtml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/themes/libraries/js/libraries.js b/themes/libraries/js/libraries.js index 70e87fdbda..350b304b2f 100644 --- a/themes/libraries/js/libraries.js +++ b/themes/libraries/js/libraries.js @@ -96,8 +96,8 @@ jQuery(document).ready(function() { jQuery.each(data.data.locationFacets, function(locationName, locationData) { var filter = encodeURI(locationData.filter); jQuery('div#location-list').append(locationTemplate); - jQuery('div#location-list .location-item-count').last().before(locationName); jQuery('div#location-list .location-item-count').last().html(formatNumber(locationData.count)); + jQuery('div#location-list .location-item-text').last().html(locationName); jQuery('div#location-list .location-item').last().attr('href', searchLink + queryString + '&filter[]=' + filter); }); jQuery('div#side-panel-location').attr('style', 'display:block'); diff --git a/themes/libraries/templates/search/libraries-results.phtml b/themes/libraries/templates/search/libraries-results.phtml index 0cfea4e371..ae6063daf3 100644 --- a/themes/libraries/templates/search/libraries-results.phtml +++ b/themes/libraries/templates/search/libraries-results.phtml @@ -50,7 +50,7 @@
- +
diff --git a/themes/lms/css/lmsactive.css b/themes/lms/css/lmsactive.css index 3523c2299e..b64eee32e8 100644 --- a/themes/lms/css/lmsactive.css +++ b/themes/lms/css/lmsactive.css @@ -32,4 +32,26 @@ footer { } .cart-controls { +} + +#lms-hint { + width: 75%; + margin: 25px auto; + background-color:#6D96D1; + text-align:center; + color:#ffffff; + padding:20px; + border-radius: 10px; +} + +#lms-text { + height: 20px; + overflow: hidden; +} + +#lms-toggle { + color:#ffffff !important; + display: inline-block; + margin-top: 10px; + text-decoration: underline; } \ No newline at end of file diff --git a/themes/lms/js/lms.js b/themes/lms/js/lms.js new file mode 100644 index 0000000000..402b746b10 --- /dev/null +++ b/themes/lms/js/lms.js @@ -0,0 +1,15 @@ +$(document).ready(function() { + $('#lms-toggle').on('click', function(e) { + e.preventDefault(); + + console.log($(this).data('display-height')); + + if ($('#lms-text').css('height') == $(this).data('display-height')) { + $('#lms-text').css('height', 'auto'); + $(this).html($(this).data('display-less')); + } else { + $('#lms-text').css('height', $(this).data('display-height')); + $(this).html($(this).data('display-more')); + } + }); +}); \ No newline at end of file diff --git a/themes/lms/mixin.config.php b/themes/lms/mixin.config.php index 390dcae79c..223272bbc0 100644 --- a/themes/lms/mixin.config.php +++ b/themes/lms/mixin.config.php @@ -5,5 +5,6 @@ ], 'js' => [ 'cart.js', + 'lms.js', ], ]; diff --git a/themes/lms/templates/cart/cart-lms-export.phtml b/themes/lms/templates/cart/cart-lms-export.phtml index 24b87a9f45..d39457e807 100644 --- a/themes/lms/templates/cart/cart-lms-export.phtml +++ b/themes/lms/templates/cart/cart-lms-export.phtml @@ -1,7 +1,7 @@ cart()->isLmsActive()): ?> - + - transEsc('LMS')?> + transEsc('LMS Export')?>