From 00e562ad513500bcbb43069a0adb87f238a18fad Mon Sep 17 00:00:00 2001 From: Chris Hallberg <crhallberg@gmail.com> Date: Tue, 22 Jul 2014 12:24:21 -0400 Subject: [PATCH] DPLA recommendation module. --- config/vufind/config.ini | 4 + config/vufind/searches.ini | 13 +- module/VuFind/config/module.config.php | 1 + .../VuFind/src/VuFind/Recommend/DPLATerms.php | 249 ++++++++++++++++++ .../VuFind/src/VuFind/Recommend/Factory.php | 19 ++ .../templates/Recommend/DPLATerms.phtml | 17 ++ .../templates/Recommend/DPLATerms.phtml | 17 ++ .../templates/Recommend/DPLATerms.phtml | 18 ++ .../templates/Recommend/DPLATerms.phtml | 1 + 9 files changed, 334 insertions(+), 5 deletions(-) create mode 100644 module/VuFind/src/VuFind/Recommend/DPLATerms.php create mode 100644 themes/blueprint/templates/Recommend/DPLATerms.phtml create mode 100644 themes/bootstrap/templates/Recommend/DPLATerms.phtml create mode 100644 themes/bootstrap3/templates/Recommend/DPLATerms.phtml create mode 100644 themes/jquerymobile/templates/Recommend/DPLATerms.phtml diff --git a/config/vufind/config.ini b/config/vufind/config.ini index dfbcf642fb5..bfef6086088 100644 --- a/config/vufind/config.ini +++ b/config/vufind/config.ini @@ -631,6 +631,10 @@ pw = "Password" ;apiKey = ApiKey ;OCLCCode = MYCODE +; DPLA +[DPLA] +apiKey = http://dp.la/info/developers/codex/policies/#get-a-key + ; These settings affect OpenURL generation and presentation; OpenURLs are used to ; help users find resources through your link resolver and to manage citations in ; Zotero. diff --git a/config/vufind/searches.ini b/config/vufind/searches.ini index 780d27422f9..3b91aa8cde9 100644 --- a/config/vufind/searches.ini +++ b/config/vufind/searches.ini @@ -166,6 +166,9 @@ CallNumber = callnumber ; Display catalog search results matching the terms found in the specified ; GET parameter (default = "lookfor"), limited to a specified number of ; matches (default = 5). This is designed for use with non-catalog modules. +; DLPATerms:[collapsed] +; Display results from the DPLA catalog. Provide a boolean to have the sidebar +; collapsed or open on page load. ; EuropeanaResults:[url]:[requestParam]:[limit]:[unwanted data providers] ; Display search results from Europeana.eu API. [url] is the base search URL ; default "api.europeana.eu/api/opensearch.rss" [requestParam] parameter name @@ -206,17 +209,17 @@ CallNumber = callnumber ; which will help with accurate analysis (default = Solr) ; [limit] is the number of records to display (default = 10) ; [display mode] determines how the records are displayed. Valid values are -; "standard" (for a basic display including titles and authors), +; "standard" (for a basic display including titles and authors), ; "images" for just images or "mixed" for both. (default = standard) ; [random mode] determines if the records are selected from the entire backend -; or from the current result set. Valid values are "retain" to limit results -; to the current result set or "disregard" to use the entire backend. +; or from the current result set. Valid values are "retain" to limit results +; to the current result set or "disregard" to use the entire backend. ; (default = retain) ; [minimumset] is the minimum result set count required to display random items, ; 0 = no minimum required. This setting can be used to prevent random items ; displaying in a small result set. (default = 0) ; [facet-n] A facet to apply to the random selection -; [facetvalue-n] The facet value to apply to the random selection +; [facetvalue-n] The facet value to apply to the random selection ; SideFacets:[regular facet section]:[checkbox facet section]:[ini name] ; Display the specified facets, where [ini name] is the name of an ini file ; in your config directory (defaults to "facets" if not supplied), @@ -371,7 +374,7 @@ method = ils ; a load on your ILS. ranges = 1,5,30 ; This setting only applies when using the "ils" method. It controls the maximum -; number of pages of results that will show up when doing a new item search. +; number of pages of results that will show up when doing a new item search. ; It is necessary to limit the number of results to avoid getting a "too many boolean ; clauses" error from the Solr index (see notes at ; http://vufind.org/jira/browse/VUFIND-128 for more details). However, if you diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index 2ea50f5d222..e6e1dc422d0 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -368,6 +368,7 @@ $config = array( 'authorityrecommend' => 'VuFind\Recommend\Factory::getAuthorityRecommend', 'catalogresults' => 'VuFind\Recommend\Factory::getCatalogResults', 'collectionsidefacets' => 'VuFind\Recommend\Factory::getCollectionSideFacets', + 'dplaterms' => 'VuFind\Recommend\Factory::getDPLATerms', 'europeanaresults' => 'VuFind\Recommend\Factory::getEuropeanaResults', 'expandfacets' => 'VuFind\Recommend\Factory::getExpandFacets', 'favoritefacets' => 'VuFind\Recommend\Factory::getFavoriteFacets', diff --git a/module/VuFind/src/VuFind/Recommend/DPLATerms.php b/module/VuFind/src/VuFind/Recommend/DPLATerms.php new file mode 100644 index 00000000000..76d9d876f9d --- /dev/null +++ b/module/VuFind/src/VuFind/Recommend/DPLATerms.php @@ -0,0 +1,249 @@ +<?php +/** + * DPLATerms Recommendations Module + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind2 + * @package Recommendations + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/vufind2:recommendation_modules Wiki + */ +namespace VuFind\Recommend; +use Zend\Http\Client as HttpClient, + Zend\Http\Client\Adapter\Exception\TimeoutException; + +/** + * DPLATerms Recommendations Module + * + * This class uses current search terms to query the DPLA API. + * + * @category VuFind2 + * @package Recommendations + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link http://vufind.org/wiki/vufind2:recommendation_modules Wiki + */ +class DPLATerms implements RecommendInterface +{ + /** + * Config + * + * @var string + */ + protected $apiKey; + + /** + * Vufind HTTP Client + * + * @var HttpClient + */ + protected $client; + + /** + * Setting of initial collapsedness + * + * @var bool + */ + protected $collapsed; + + /** + * Search results object + * + * @var \VuFind\Search\Base\Results + */ + protected $searchObject; + + /** + * Map of Solr field names to equivalent API parameters + * + * @var array + */ + protected $formatMap = array( + 'authorStr' => 'sourceResource.creator', + 'building' => 'provider.name', + 'format' => 'sourceResource.format', + 'geographic_facet' => 'sourceResource.spatial.region', + 'institution' => 'provider.name', + 'language' => 'sourceResource.language.name', + 'publishDate' => 'sourceResource.date.begin', + ); + + /** + * List of fields to retrieve from the API + * + * @var array + */ + protected $returnFields = array( + 'id', + 'dataProvider', + 'sourceResource.title', + 'sourceResource.description', + ); + + /** + * Constructor + * + * @param string $apiKey API key + * @param HttpClient $client VuFind HTTP client + */ + public function __construct($apiKey, HttpClient $client) + { + $this->apiKey = $apiKey; + $this->client = $client; + } + + /** + * setConfig + * + * Store the configuration of the recommendation module. + * + * @param string $settings Settings from searches.ini. + * + * @return void + */ + public function setConfig($settings) + { + $this->collapsed = filter_var($settings, FILTER_VALIDATE_BOOLEAN); + } + + /** + * Abstract-required method + * + * @param \VuFind\Search\Base\Params $params Search parameter object + * @param \Zend\StdLib\Parameters $request Parameter object representing user + * request. + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function init($params, $request) + { + // No action needed. + } + + /** + * process + * + * Called after the Search Results object has performed its main search. This + * may be used to extract necessary information from the Search Results object + * or to perform completely unrelated processing. + * + * @param \VuFind\Search\Base\Results $results Search results object + * + * @return void + */ + public function process($results) + { + $this->searchObject = $results; + } + + /** + * Get terms related to the query. + * + * @return array + */ + public function getResults() + { + $this->client->setUri('http://api.dp.la/v2/items'); + $this->client->setMethod('GET'); + $this->client->setParameterGet($this->getApiInput()); + try { + $response = $this->client->send(); + } catch (TimeoutException $e) { + error_log('DPLA API timeout -- skipping recommendations.'); + return array(); + } + if (!$response->isSuccess()) { + return array(); + } + return $this->processResults($response->getBody()); + } + + /** + * Get input parameters for API call. + * + * @return array + */ + protected function getApiInput() + { + // Extract the first search term from the search object: + $search = $this->searchObject->getParams()->getQuery(); + $filters = $this->searchObject->getParams()->getFilters(); + $lookfor = ($search instanceof \VuFindSearch\Query\Query) + ? $search->getString() + : ''; + + $params = array( + 'q' => $lookfor, + 'fields' => implode(',', $this->returnFields), + 'api_key' => $this->apiKey + ); + foreach ($filters as $field=>$filter) { + if (isset($this->formatMap[$field])) { + $params[$this->formatMap[$field]] = implode(',', $filter); + } + } + return $params; + } + + /** + * Process the API response. + * + * @param string $response API response + * + * @return array + */ + protected function processResults($response) + { + $body = json_decode($response); + $results = array(); + if ($body->count > 0) { + $title = 'sourceResource.title'; + $desc = 'sourceResource.description'; + foreach ($body->docs as $i => $doc) { + $results[$i] = array( + 'title' => is_array($doc->$title) + ? current($doc->$title) + : $doc->$title, + 'provider' => is_array($doc->dataProvider) + ? current($doc->dataProvider) + : $doc->dataProvider, + 'link' => 'http://dp.la/item/'.$doc->id + ); + if (isset($doc->$desc)) { + $results[$i]['desc'] = is_array($doc->$desc) + ? current($doc->$desc) + : $doc->$desc; + } + } + } + return $results; + } + + /** + * Return the list of facets configured to be collapsed + * + * @return array + */ + public function isCollapsed() + { + return $this->collapsed; + } +} \ No newline at end of file diff --git a/module/VuFind/src/VuFind/Recommend/Factory.php b/module/VuFind/src/VuFind/Recommend/Factory.php index 36d38ba1c66..12f04061064 100644 --- a/module/VuFind/src/VuFind/Recommend/Factory.php +++ b/module/VuFind/src/VuFind/Recommend/Factory.php @@ -112,6 +112,25 @@ class Factory ); } + /** + * Factory for DPLA Terms module. + * + * @param ServiceManager $sm Service manager. + * + * @return DPLATerms + */ + public static function getDPLATerms(ServiceManager $sm) + { + $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config'); + if (!isset($config->DPLA->apiKey)) { + throw new \Exception('DPLA API key missing from configuration.'); + } + return new DPLATerms( + $config->DPLA->apiKey, + $sm->getServiceLocator()->get('VuFind\Http')->createClient() + ); + } + /** * Factory for EuropeanaResults module. * diff --git a/themes/blueprint/templates/Recommend/DPLATerms.phtml b/themes/blueprint/templates/Recommend/DPLATerms.phtml new file mode 100644 index 00000000000..8df5a2cc8d5 --- /dev/null +++ b/themes/blueprint/templates/Recommend/DPLATerms.phtml @@ -0,0 +1,17 @@ +<? $results = $this->recommend->getResults(); ?> +<? if(!empty($results)): ?> + <dl class="narrowList navmenu<? if(!$this->recommend->isCollapsed()): ?> open<? endif ?>"> + <dt class="facet_dpla">DPLA</dt> + <? foreach($results as $item): ?> + <dd> + <a href="<?=$item['link'] ?>" target="new"><?=$this->escapeHtml($item['title']) ?></a> + <? if(!empty($item['desc'])): ?> + <span title="<?=$item['desc'] ?>"><?=$this->escapeHtml($this->truncate($item['desc'], 50)) ?></span></br> + <? endif; ?> + <span style="font-size:85%;font-style:italic"> + (<?=$this->transEsc('Provider') ?>: <?=$this->escapeHtml($item['provider']) ?>) + </span> + </dd> + <? endforeach; ?> + </ul> +<? endif; ?> diff --git a/themes/bootstrap/templates/Recommend/DPLATerms.phtml b/themes/bootstrap/templates/Recommend/DPLATerms.phtml new file mode 100644 index 00000000000..16382ddc9ba --- /dev/null +++ b/themes/bootstrap/templates/Recommend/DPLATerms.phtml @@ -0,0 +1,17 @@ +<? $results = $this->recommend->getResults(); ?> +<? if(!empty($results)): ?> + <ul class="nav nav-list collapsed<? if(!$this->recommend->isCollapsed()): ?> open<? endif ?>"> + <li class="nav-header">DPLA</li> + <? foreach($results as $item): ?> + <li> + <a href="<?=$item['link'] ?>" target="new"><?=$this->escapeHtml($item['title']) ?></a> + <? if(!empty($item['desc'])): ?> + <span title="<?=$item['desc'] ?>"><?=$this->escapeHtml($this->truncate($item['desc'], 50)) ?></span></br> + <? endif; ?> + <span style="font-size:85%;font-style:italic"> + (<?=$this->transEsc('Provider') ?>: <?=$this->escapeHtml($item['provider']) ?>) + </span> + </li> + <? endforeach; ?> + </ul> +<? endif; ?> diff --git a/themes/bootstrap3/templates/Recommend/DPLATerms.phtml b/themes/bootstrap3/templates/Recommend/DPLATerms.phtml new file mode 100644 index 00000000000..2ad9cd87ce8 --- /dev/null +++ b/themes/bootstrap3/templates/Recommend/DPLATerms.phtml @@ -0,0 +1,18 @@ +<? $results = $this->recommend->getResults(); ?> +<? if(!empty($results)): ?> + <ul class="list-group" id="side-panel-dpla"> + <li class="list-group-item title<? if($this->recommend->isCollapsed()): ?> collapsed<? endif ?>" data-toggle="collapse" href="#side-collapse-dpla"> + DPLA + </li> + <div id="side-collapse-dpla" class="collapse<? if(!$this->recommend->isCollapsed()): ?> in<? endif ?>"> + <? foreach($results as $item): ?> + <li class="list-group-item"> + <a href="<?=$item['link'] ?>" target="new"><?=$this->escapeHtml($item['title']) ?></a><br/> + <? if(!empty($item['desc'])): ?> + <span class="desc" title="<?=$item['desc'] ?>"><?=$this->escapeHtml($this->truncate($item['desc'], 50)) ?></span><br/> + <? endif; ?> + (<span class="from"><?=$this->transEsc('Provider') ?>: <?=$this->escapeHtml($item['provider']) ?></span>) + </li> + <? endforeach; ?> + </ul> +<? endif; ?> \ No newline at end of file diff --git a/themes/jquerymobile/templates/Recommend/DPLATerms.phtml b/themes/jquerymobile/templates/Recommend/DPLATerms.phtml new file mode 100644 index 00000000000..0df1e74df18 --- /dev/null +++ b/themes/jquerymobile/templates/Recommend/DPLATerms.phtml @@ -0,0 +1 @@ +<? /* Not supported in mobile theme. */ ?> \ No newline at end of file -- GitLab