diff --git a/config/vufind/config.ini b/config/vufind/config.ini index 570828c495093cc00e7916815bf816cc7991c86c..ae1d24c5dd9dea4fb3155da9665d2ce286d5c2d1 100644 --- a/config/vufind/config.ini +++ b/config/vufind/config.ini @@ -1012,6 +1012,20 @@ pw = "Password" ;[DPLA] ;apiKey = http://dp.la/info/developers/codex/policies/#get-a-key +; These settings affect dynamic DOI-based link inclusion; this can provide links +; to full text or contextual information. +[DOI] +; This setting controls whether or not DOI-based links are enabled, and which +; API is used to fetch the data. Currently supported options: BrowZine (requires +; credentials to be configured in BrowZine.ini) or false (to disable). Disabled +; by default. +;resolver = BrowZine + +; The following settings control where DOI-based links are displayed: +show_in_results = true ; include in search results +show_in_record = false ; include in core record metadata +show_in_holdings = false ; include in holdings tab of record view + ; 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/languages/en.ini b/languages/en.ini index a2bc88fa69d634fea3a31f1729c3d3e65f079653..71a2cd7dadad4559456054291bf0c6433274f9e1 100644 --- a/languages/en.ini +++ b/languages/en.ini @@ -1083,6 +1083,7 @@ Video = "Video" Video Clips = "Video Clips" Videos = "Videos" View Book Bag = "View Book Bag" +View Complete Issue = "View Complete Issue" View Full Collection = "View Full Collection" View Full Record = "View Full Record" View in EDS = "View in EDS" diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index 2628622831f7311d2c9d07f7572aac71650ecdac..e765766ab0bd7ec345d93c437a5e555d406649c7 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -342,6 +342,7 @@ $config = [ 'VuFind\Db\AdapterFactory' => 'VuFind\Service\ServiceWithConfigIniFactory', 'VuFind\Db\Row\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', 'VuFind\Db\Table\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', + 'VuFind\DoiLinker\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory', 'VuFind\Export' => 'VuFind\ExportFactory', 'VuFind\Favorites\FavoritesService' => 'VuFind\Favorites\FavoritesServiceFactory', 'VuFind\GeoFeatures\BasemapConfig' => 'VuFind\GeoFeatures\AbstractConfigFactory', @@ -515,6 +516,7 @@ $config = [ 'cover_layer' => [ /* see VuFind\Cover\Layer\PluginManager for defaults */ ], 'db_row' => [ /* see VuFind\Db\Row\PluginManager for defaults */ ], 'db_table' => [ /* see VuFind\Db\Table\PluginManager for defaults */ ], + 'doilinker' => [ /* see VuFind\DoiLinker\PluginManager for defaults */ ], 'hierarchy_driver' => [ /* see VuFind\Hierarchy\Driver\PluginManager for defaults */ ], 'hierarchy_treedataformatter' => [ /* see VuFind\Hierarchy\TreeDataFormatter\PluginManager for defaults */ ], 'hierarchy_treedatasource' => [ /* see VuFind\Hierarchy\TreeDataSource\PluginManager for defaults */ ], diff --git a/module/VuFind/src/VuFind/AjaxHandler/DoiLookup.php b/module/VuFind/src/VuFind/AjaxHandler/DoiLookup.php new file mode 100644 index 0000000000000000000000000000000000000000..deb055ba809529152658c3fcce3df421663455b3 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/DoiLookup.php @@ -0,0 +1,86 @@ +<?php +/** + * AJAX handler to look up DOI data. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use VuFind\DoiLinker\PluginManager; +use Zend\Mvc\Controller\Plugin\Params; + +/** + * AJAX handler to look up DOI data. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class DoiLookup extends AbstractBase +{ + /** + * DOI Linker Plugin Manager + * + * @var PluginManager + */ + protected $pluginManager; + + /** + * DOI resolver configuration value + * + * @var string + */ + protected $resolver; + + /** + * Constructor + * + * @param PluginManager $pluginManager DOI Linker Plugin Manager + * @param string $resolver DOI resolver configuration value + */ + public function __construct(PluginManager $pluginManager, $resolver) + { + $this->pluginManager = $pluginManager; + $this->resolver = $resolver; + } + + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, HTTP status code] + */ + public function handleRequest(Params $params) + { + $response = []; + if ($this->pluginManager->has($this->resolver)) { + $dois = (array)$params->fromQuery('doi', []); + $response = $this->pluginManager->get($this->resolver)->getLinks($dois); + } + return $this->formatResponse($response); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/DoiLookupFactory.php b/module/VuFind/src/VuFind/AjaxHandler/DoiLookupFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..fb41749f91e84acb254463b29a21f84b861489e4 --- /dev/null +++ b/module/VuFind/src/VuFind/AjaxHandler/DoiLookupFactory.php @@ -0,0 +1,69 @@ +<?php +/** + * Factory for DoiLookup AJAX handler. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\AjaxHandler; + +use Interop\Container\ContainerInterface; + +/** + * Factory for DoiLookup AJAX handler. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class DoiLookupFactory 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 + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + $config = $container->get('VuFind\Config\PluginManager')->get('config'); + $pluginManager = $container->get('VuFind\DoiLinker\PluginManager'); + return new $requestedName($pluginManager, $config->DOI->resolver ?? null); + } +} diff --git a/module/VuFind/src/VuFind/AjaxHandler/PluginManager.php b/module/VuFind/src/VuFind/AjaxHandler/PluginManager.php index 5f0e3295b8e5fcc9dd97d4174566ce1b72947541..793f53e3c84128472bfa0b1ad1ca1c26828ed57a 100644 --- a/module/VuFind/src/VuFind/AjaxHandler/PluginManager.php +++ b/module/VuFind/src/VuFind/AjaxHandler/PluginManager.php @@ -47,6 +47,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager 'checkRequestIsValid' => 'VuFind\AjaxHandler\CheckRequestIsValid', 'commentRecord' => 'VuFind\AjaxHandler\CommentRecord', 'deleteRecordComment' => 'VuFind\AjaxHandler\DeleteRecordComment', + 'doiLookup' => 'VuFind\AjaxHandler\DoiLookup', 'getACSuggestions' => 'VuFind\AjaxHandler\GetACSuggestions', 'getFacetData' => 'VuFind\AjaxHandler\GetFacetData', 'getIlsStatus' => 'VuFind\AjaxHandler\GetIlsStatus', @@ -82,6 +83,7 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager 'VuFind\AjaxHandler\CommentRecordFactory', 'VuFind\AjaxHandler\DeleteRecordComment' => 'VuFind\AjaxHandler\DeleteRecordCommentFactory', + 'VuFind\AjaxHandler\DoiLookup' => 'VuFind\AjaxHandler\DoiLookupFactory', 'VuFind\AjaxHandler\GetACSuggestions' => 'VuFind\AjaxHandler\GetACSuggestionsFactory', 'VuFind\AjaxHandler\GetFacetData' => diff --git a/module/VuFind/src/VuFind/DoiLinker/BrowZine.php b/module/VuFind/src/VuFind/DoiLinker/BrowZine.php new file mode 100644 index 0000000000000000000000000000000000000000..f3c05beb8c51d5255fd34648c1ab5cc594e9c1a6 --- /dev/null +++ b/module/VuFind/src/VuFind/DoiLinker/BrowZine.php @@ -0,0 +1,94 @@ +<?php +/** + * BrowZine DOI linker + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace VuFind\DoiLinker; + +use VuFind\I18n\Translator\TranslatorAwareInterface; +use VuFindSearch\Backend\BrowZine\Connector; + +/** + * BrowZine DOI linker + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +class BrowZine implements DoiLinkerInterface, TranslatorAwareInterface +{ + use \VuFind\I18n\Translator\TranslatorAwareTrait; + + /** + * BrowZine connector + * + * @var Connector + */ + protected $connector; + + /** + * Constructor + * + * @param Connector $connector Connector + */ + public function __construct(Connector $connector) + { + $this->connector = $connector; + } + + /** + * Given an array of DOIs, perform a lookup and return an associative array + * of arrays, keyed by DOI. Each array contains one or more associative arrays + * with 'link' and 'label' keys. + * + * @param array $doiArray DOIs to look up + * + * @return array + */ + public function getLinks(array $doiArray) + { + $response = []; + foreach ($doiArray as $doi) { + $data = $this->connector->lookupDoi($doi)['data'] ?? null; + if (!empty($data['browzineWebLink'])) { + $response[$doi][] = [ + 'link' => $data['browzineWebLink'], + 'label' => $this->translate('View Complete Issue'), + 'data' => $data, + ]; + } + if (!empty($data['fullTextFile'])) { + $response[$doi][] = [ + 'link' => $data['fullTextFile'], + 'label' => $this->translate('PDF Full Text'), + 'data' => $data, + ]; + } + } + return $response; + } +} diff --git a/module/VuFind/src/VuFind/DoiLinker/BrowZineFactory.php b/module/VuFind/src/VuFind/DoiLinker/BrowZineFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..4256b24dae4502e1b6201709904053ac8117fe62 --- /dev/null +++ b/module/VuFind/src/VuFind/DoiLinker/BrowZineFactory.php @@ -0,0 +1,68 @@ +<?php +/** + * BrowZine DOI linker factory + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace VuFind\DoiLinker; + +use Interop\Container\ContainerInterface; + +/** + * BrowZine DOI linker factory + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +class BrowZineFactory 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 + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options passed to factory.'); + } + $backend = $container->get('VuFind\Search\BackendManager')->get('BrowZine'); + return new $requestedName($backend->getConnector()); + } +} diff --git a/module/VuFind/src/VuFind/DoiLinker/DoiLinkerInterface.php b/module/VuFind/src/VuFind/DoiLinker/DoiLinkerInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..bc967339f7064cbb94675b40759d960b9d13b7b6 --- /dev/null +++ b/module/VuFind/src/VuFind/DoiLinker/DoiLinkerInterface.php @@ -0,0 +1,51 @@ +<?php +/** + * DOI linker interface + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace VuFind\DoiLinker; + +/** + * DOI linker interface + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +interface DoiLinkerInterface +{ + /** + * Given an array of DOIs, perform a lookup and return an associative array + * of arrays, keyed by DOI. Each array contains one or more associative arrays + * with 'link' and 'label' keys. + * + * @param array $doiArray DOIs to look up + * + * @return array + */ + public function getLinks(array $doiArray); +} diff --git a/module/VuFind/src/VuFind/DoiLinker/PluginManager.php b/module/VuFind/src/VuFind/DoiLinker/PluginManager.php new file mode 100644 index 0000000000000000000000000000000000000000..38dd88ccfcf10b9064dee8d80f6bf6eeba8c1832 --- /dev/null +++ b/module/VuFind/src/VuFind/DoiLinker/PluginManager.php @@ -0,0 +1,69 @@ +<?php +/** + * DOI linker plugin manager + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:record_drivers Wiki + */ +namespace VuFind\DoiLinker; + +/** + * DOI linker plugin manager + * + * @category VuFind + * @package DOI + * @author Demian Katz <demian.katz@villanova.edu> + * @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\ServiceManager\AbstractPluginManager +{ + /** + * Default plugin aliases. + * + * @var array + */ + protected $aliases = [ + 'browzine' => 'VuFind\DoiLinker\BrowZine', + ]; + + /** + * Default plugin factories. + * + * @var array + */ + protected $factories = [ + 'VuFind\DoiLinker\BrowZine' => 'VuFind\DoiLinker\BrowZineFactory', + ]; + + /** + * Return the name of the base class or interface that plug-ins must conform + * to. + * + * @return string + */ + protected function getExpectedInterface() + { + return 'VuFind\DoiLinker\DoiLinkerInterface'; + } +} diff --git a/module/VuFind/src/VuFind/View/Helper/Root/Doi.php b/module/VuFind/src/VuFind/View/Helper/Root/Doi.php new file mode 100644 index 0000000000000000000000000000000000000000..de56f1c67342e93d980196deb5d8dc614d802886 --- /dev/null +++ b/module/VuFind/src/VuFind/View/Helper/Root/Doi.php @@ -0,0 +1,151 @@ +<?php +/** + * DOI view helper + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package View_Helpers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\View\Helper\Root; + +/** + * DOI view helper + * + * @category VuFind + * @package View_Helpers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class Doi extends \Zend\View\Helper\AbstractHelper +{ + /** + * Context helper + * + * @var \VuFind\View\Helper\Root\Context + */ + protected $context; + + /** + * VuFind OpenURL configuration + * + * @var \Zend\Config\Config + */ + protected $config; + + /** + * Current RecordDriver + * + * @var \VuFind\RecordDriver + */ + protected $recordDriver; + + /** + * OpenURL context ('results', 'record' or 'holdings') + * + * @var string + */ + protected $area; + + /** + * Constructor + * + * @param Context $context Context helper + * @param \Zend\Config\Config $config VuFind OpenURL config + */ + public function __construct(Context $context, $config = null) + { + $this->context = $context; + $this->config = $config; + } + + /** + * Set up context for helper + * + * @param \VuFind\RecordDriver $driver The current record driver + * @param string $area DOI context ('results', 'record' + * or 'holdings' + * + * @return object + */ + public function __invoke($driver, $area) + { + $this->recordDriver = $driver; + $this->area = $area; + return $this; + } + + /** + * Public method to render the OpenURL template + * + * @param bool $imagebased Indicates if an image based link + * should be displayed or not (null for system default) + * + * @return string + */ + public function renderTemplate($imagebased = null) + { + // Build parameters needed to display the control: + $doi = $this->recordDriver->tryMethod('getCleanDOI'); + $params = compact('doi'); + + // Render the subtemplate: + return $this->context->__invoke($this->getView())->renderInContext( + 'Helpers/doi.phtml', $params + ); + } + + /** + * Does the configuration indicate that we should display DOI links in + * the specified context? + * + * @return bool + */ + protected function checkContext() + { + // Doesn't matter the target area if no resolver is specified: + if (empty($this->config->resolver)) { + return false; + } + + // If a setting exists, return that: + $key = 'show_in_' . $this->area; + if (isset($this->config->$key)) { + return $this->config->$key; + } + + // If we got this far, use the defaults -- true for results, false for + // everywhere else. + return $this->area == 'results'; + } + + /** + * Public method to check whether OpenURLs are active for current record + * + * @return bool + */ + public function isActive() + { + $doi = $this->recordDriver->tryMethod('getCleanDOI'); + return !empty($doi) && $this->checkContext(); + } +} diff --git a/module/VuFind/src/VuFind/View/Helper/Root/DoiFactory.php b/module/VuFind/src/VuFind/View/Helper/Root/DoiFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..b552966621c6510f2febe6326c08058b3ae9f7ea --- /dev/null +++ b/module/VuFind/src/VuFind/View/Helper/Root/DoiFactory.php @@ -0,0 +1,68 @@ +<?php +/** + * DOI helper factory. + * + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package View_Helpers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFind\View\Helper\Root; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * DOI helper factory. + * + * @category VuFind + * @package View_Helpers + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class DoiFactory 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.'); + } + $config = $container->get('VuFind\Config\PluginManager')->get('config'); + $helpers = $container->get('ViewHelperManager'); + return new $requestedName($helpers->get('context'), $config->DOI ?? null); + } +} diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php index 0e2622b0258bdfe5aa260d26bf33cd6358abca88..daa50dbeb2f7080b0e1a9737178593d936b70905 100644 --- a/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php +++ b/module/VuFind/tests/unit-tests/src/VuFindTest/View/Helper/Root/RecordDataFormatterTest.php @@ -55,6 +55,7 @@ class RecordDataFormatterTest extends \VuFindTest\Unit\ViewHelperTestCase $this->getMockBuilder('VuFind\Auth\ILSAuthenticator')->disableOriginalConstructor()->getMock() ), 'context' => $context, + 'doi' => new \VuFind\View\Helper\Root\Doi($context), 'openUrl' => new \VuFind\View\Helper\Root\OpenUrl($context, [], $this->getMockBuilder('VuFind\Resolver\Driver\PluginManager')->disableOriginalConstructor()->getMock()), 'proxyUrl' => new \VuFind\View\Helper\Root\ProxyUrl(), 'record' => new \VuFind\View\Helper\Root\Record(), diff --git a/module/VuFindSearch/src/VuFindSearch/Backend/BrowZine/Connector.php b/module/VuFindSearch/src/VuFindSearch/Backend/BrowZine/Connector.php index 3a76f84b107d6135b307f7e8f0ba08daae9fda2f..6f45b076177e2d51c1f1c862821077c420faac1c 100644 --- a/module/VuFindSearch/src/VuFindSearch/Backend/BrowZine/Connector.php +++ b/module/VuFindSearch/src/VuFindSearch/Backend/BrowZine/Connector.php @@ -87,6 +87,23 @@ class Connector implements \Zend\Log\LoggerAwareInterface $this->libraryId = $id; } + /** + * Perform a DOI lookup + * + * @param string $doi DOI + * @param bool $includeJournal Include journal data in response? + * + * @return mixed + */ + public function lookupDoi($doi, $includeJournal = false) + { + // Documentation says URL encoding of DOI is not necessary. + return $this->request( + 'articles/doi/' . $doi, + $includeJournal ? ['include' => 'journal'] : [] + ); + } + /** * Perform a search * diff --git a/themes/bootstrap3/js/doi.js b/themes/bootstrap3/js/doi.js new file mode 100644 index 0000000000000000000000000000000000000000..98287f28612311f5a013d0cf461c3a6a016e14d7 --- /dev/null +++ b/themes/bootstrap3/js/doi.js @@ -0,0 +1,59 @@ +/*global Hunt, VuFind */ +VuFind.register('doi', function Doi() { + function embedDoiLinks(el) { + var element = $(el); + var doi = []; + var elements = element.hasClass('doiLink') ? element : element.find('.doiLink'); + elements.each(function extractDoiData(i, doiLinkEl) { + var currentDoi = $(doiLinkEl).data('doi'); + if (doi.indexOf(currentDoi) === -1) { + doi[doi.length] = currentDoi; + } + }); + if (doi.length === 0) { + return; + } + var url = VuFind.path + '/AJAX/JSON?' + $.param({ + method: 'doiLookup', + doi: doi, + }); + $.ajax({ + dataType: 'json', + url: url + }) + .done(function embedDoiLinksDone(response) { + elements.each(function populateDoiLinks(x, doiEl) { + var currentDoi = $(doiEl).data('doi'); + if ("undefined" !== response.data[currentDoi]) { + $(doiEl).empty(); + for (var i = 0; i < response.data[currentDoi].length; i++) { + var newLink = $('<a />'); + newLink.attr('href', response.data[currentDoi][i].link); + newLink.text(response.data[currentDoi][i].label); + $(doiEl).append(newLink); + $(doiEl).append("<br />"); + } + } + }); + }); + } + + // Assign actions to the OpenURL links. This can be called with a container e.g. when + // combined results fetched with AJAX are loaded. + function init(_container) { + var container = _container || $('body'); + // assign action to the openUrlWindow link class + if (typeof Hunt === 'undefined') { + embedDoiLinks(container); + } else { + new Hunt( + container.find('.doiLink').toArray(), + { enter: embedDoiLinks } + ); + } + } + return { + init: init, + embedDoiLinks: embedDoiLinks + }; +}); diff --git a/themes/bootstrap3/templates/Helpers/doi.phtml b/themes/bootstrap3/templates/Helpers/doi.phtml new file mode 100644 index 0000000000000000000000000000000000000000..55f9676ad355f2fee6df9db949fc1ba294708009 --- /dev/null +++ b/themes/bootstrap3/templates/Helpers/doi.phtml @@ -0,0 +1,2 @@ +<?=$this->inlineScript(\Zend\View\Helper\HeadScript::FILE, 'doi.js', 'SET');?> +<span class="doiLink" data-doi="<?=$this->escapeHtml($doi)?>"></span> \ No newline at end of file diff --git a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/data-onlineAccess.phtml b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/data-onlineAccess.phtml index 4a545667a7a334f39747fc02532589fb69523ce8..4d96751f6f9b8d4fcf84b72d837649361b07f7e2 100644 --- a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/data-onlineAccess.phtml +++ b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/data-onlineAccess.phtml @@ -1,14 +1,15 @@ <?php $openUrl = $this->openUrl($this->driver, 'record'); $openUrlActive = $openUrl->isActive(); + $doi = $this->doi($this->driver, 'record'); + $doiActive = $doi->isActive(); // Account for replace_other_urls setting $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); ?> -<?php if (!empty($urls) || $openUrlActive): ?> - <?php foreach ($urls as $current): ?> - <a href="<?=$this->escapeHtmlAttr($this->proxyUrl($current['url']))?>"><?=$this->escapeHtml($current['desc'])?></a><br/> - <?php endforeach; ?> - <?php if ($openUrlActive): ?> - <?=$openUrl->renderTemplate()?><br/> - <?php endif; ?> +<?php foreach ($urls as $current): ?> + <a href="<?=$this->escapeHtmlAttr($this->proxyUrl($current['url']))?>"><?=$this->escapeHtml($current['desc'])?></a><br/> +<?php endforeach; ?> +<?php if ($openUrlActive): ?> + <?=$openUrl->renderTemplate()?><br/> <?php endif; ?> +<?php if ($doiActive): ?><?=$doi->renderTemplate()?><?php endif; ?> diff --git a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/list-entry.phtml b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/list-entry.phtml index 323229a2109b3ac78389c5c7ff45e71042a76ff4..98d94ee07e44e062090ec66f796480db52021d9e 100644 --- a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/list-entry.phtml +++ b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/list-entry.phtml @@ -137,16 +137,23 @@ */ $openUrl = $this->openUrl($this->driver, 'results'); $openUrlActive = $openUrl->isActive(); + $doi = $this->doi($this->driver, 'results'); + $doiActive = $doi->isActive(); // Account for replace_other_urls setting $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); - if ($openUrlActive || !empty($urls)): + if ($openUrlActive || $doiActive || !empty($urls)): ?> <?php if ($openUrlActive): ?> <br/> <?=$openUrl->renderTemplate()?> <?php endif;?> + <?php if ($doiActive): ?> + <br/> + <?=$doi->renderTemplate()?> + <?php endif; ?> + <?php if (!is_array($urls)) { $urls = []; } if(!$this->driver->isCollection()): foreach ($urls as $current): ?> diff --git a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-grid.phtml b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-grid.phtml index bb091ff369f061e43bcbc47b685846ff549517b5..e76e183deb676e1da67c39e304513dac1af19f99 100644 --- a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-grid.phtml +++ b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-grid.phtml @@ -5,6 +5,8 @@ */ $openUrl = $this->openUrl($this->driver, 'results'); $openUrlActive = $openUrl->isActive(); +$doi = $this->doi($this->driver, 'results'); +$doiActive = $doi->isActive(); // Account for replace_other_urls setting $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); ?> @@ -29,11 +31,14 @@ $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); <a class="title" href="<?=$this->recordLink()->getUrl($this->driver)?>"> <?=$this->record($this->driver)->getTitleHtml(80)?> </a> - <?php if ($openUrlActive || !empty($urls)): ?> + <?php if ($openUrlActive || $doiActive || !empty($urls)): ?> <br/><br/> <?php if ($openUrlActive): ?> <?=$openUrl->renderTemplate()?><br /> <?php endif; ?> + <?php if ($doiActive): ?> + <?=$doi->renderTemplate()?><br /> + <?php endif; ?> <?php if (!is_array($urls)) $urls = []; foreach ($urls as $current): ?> <a href="<?=$this->escapeHtmlAttr($this->proxyUrl($current['url']))?>" class="fulltext" target="new"><i class="fa fa-external-link" aria-hidden="true"></i> <?=($current['url'] == $current['desc']) ? $this->transEsc('Get full text') : $this->escapeHtml($current['desc'])?></a> <br/> diff --git a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-list.phtml b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-list.phtml index 3f8f07cc084a0f2826baca627e8bc53a6f39fb46..c97910034a87922bfc51e4ee819996690cac8d53 100644 --- a/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-list.phtml +++ b/themes/bootstrap3/templates/RecordDriver/DefaultRecord/result-list.phtml @@ -121,14 +121,20 @@ */ $openUrl = $this->openUrl($this->driver, 'results'); $openUrlActive = $openUrl->isActive(); + $doi = $this->doi($this->driver, 'results'); + $doiActive = $doi->isActive(); // Account for replace_other_urls setting $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); - if ($openUrlActive || !empty($urls)): ?> + if ($openUrlActive || $doiActive || !empty($urls)): ?> <?php if ($openUrlActive): ?> <br/> <?=$openUrl->renderTemplate()?> <?php endif; ?> + <?php if ($doiActive): ?> + <br/> + <?=$doi->renderTemplate()?> + <?php endif; ?> <?php if (!is_array($urls)) $urls = []; if(!$this->driver->isCollection()): foreach ($urls as $current): ?> diff --git a/themes/bootstrap3/templates/RecordDriver/Pazpar2/result-list.phtml b/themes/bootstrap3/templates/RecordDriver/Pazpar2/result-list.phtml index a836656fef657d44f406b7250b43c66662173e4a..014b44758b27e3950af83fa3f0828a53239dba88 100644 --- a/themes/bootstrap3/templates/RecordDriver/Pazpar2/result-list.phtml +++ b/themes/bootstrap3/templates/RecordDriver/Pazpar2/result-list.phtml @@ -79,13 +79,20 @@ */ $openUrl = $this->openUrl($this->driver, 'results'); $openUrlActive = $openUrl->isActive(); + $doi = $this->doi($this->driver, 'results'); + $doiActive = $doi->isActive(); // Account for replace_other_urls setting $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); - if ($openUrlActive || !empty($urls)): ?> + + if ($openUrlActive || $doiActive || !empty($urls)): ?> <?php if ($openUrlActive): ?> <br/> <?=$openUrl->renderTemplate()?> <?php endif; ?> + <?php if ($doiActive): ?> + <br/> + <?=$doi->renderTemplate()?> + <?php endif; ?> <?php if (!is_array($urls)) $urls = []; if(!$this->driver->isCollection()): foreach ($urls as $current): ?> diff --git a/themes/bootstrap3/templates/RecordTab/holdingsils.phtml b/themes/bootstrap3/templates/RecordTab/holdingsils.phtml index 3d4f71b9831d329283d71192b4d14c6befdceeb3..fefcb15662def1bca294bca16bd2b42edc00e539 100644 --- a/themes/bootstrap3/templates/RecordTab/holdingsils.phtml +++ b/themes/bootstrap3/templates/RecordTab/holdingsils.phtml @@ -4,6 +4,8 @@ $user = $account->isLoggedIn(); $openUrl = $this->openUrl($this->driver, 'holdings'); $openUrlActive = $openUrl->isActive(); + $doi = $this->doi($this->driver, 'holdings'); + $doiActive = $doi->isActive(); // Account for replace_other_urls setting $urls = $this->record($this->driver)->getLinkDetails($openUrlActive); $offlineMode = $this->ils()->getOfflineMode(); @@ -42,7 +44,7 @@ <?php $holdingTitleHold = $this->driver->tryMethod('getRealTimeTitleHold'); if (!empty($holdingTitleHold)): ?> <a class="placehold" data-lightbox title="<?=$this->transEsc('request_place_text')?>" href="<?=$this->recordLink()->getRequestUrl($holdingTitleHold)?>"><i class="fa fa-flag" aria-hidden="true"></i> <?=$this->transEsc('title_hold_place')?></a> <?php endif; ?> -<?php if (!empty($urls) || $openUrlActive): ?> +<?php if (!empty($urls) || $openUrlActive || $doiActive): ?> <h3><?=$this->transEsc("Internet")?></h3> <?php if (!empty($urls)): ?> <?php foreach ($urls as $current): ?> @@ -50,6 +52,7 @@ <?php endforeach; ?> <?php endif; ?> <?php if ($openUrlActive): ?><?=$openUrl->renderTemplate()?><?php endif; ?> + <?php if ($doiActive): ?><?=$doi->renderTemplate()?><?php endif; ?> <?php endif; ?> <?php foreach ($holdings['holdings'] ?? [] as $holding): ?> <h3> diff --git a/themes/root/theme.config.php b/themes/root/theme.config.php index d175736cfc7abff1ea122edcefe462b5efa00f60..0f2215e799b60b4cc73c83bd9f2037e3e9841463 100644 --- a/themes/root/theme.config.php +++ b/themes/root/theme.config.php @@ -18,6 +18,7 @@ return [ 'VuFind\View\Helper\Root\CurrentPath' => 'Zend\ServiceManager\Factory\InvokableFactory', 'VuFind\View\Helper\Root\DateTime' => 'VuFind\View\Helper\Root\DateTimeFactory', 'VuFind\View\Helper\Root\DisplayLanguageOption' => 'VuFind\View\Helper\Root\DisplayLanguageOptionFactory', + 'VuFind\View\Helper\Root\Doi' => 'VuFind\View\Helper\Root\DoiFactory', 'VuFind\View\Helper\Root\Export' => 'VuFind\View\Helper\Root\ExportFactory', 'VuFind\View\Helper\Root\Feedback' => 'VuFind\View\Helper\Root\FeedbackFactory', 'VuFind\View\Helper\Root\Flashmessages' => 'VuFind\View\Helper\Root\FlashmessagesFactory', @@ -77,6 +78,7 @@ return [ 'currentPath' => 'VuFind\View\Helper\Root\CurrentPath', 'dateTime' => 'VuFind\View\Helper\Root\DateTime', 'displayLanguageOption' => 'VuFind\View\Helper\Root\DisplayLanguageOption', + 'doi' => 'VuFind\View\Helper\Root\Doi', 'export' => 'VuFind\View\Helper\Root\Export', 'feedback' => 'VuFind\View\Helper\Root\Feedback', 'flashmessages' => 'VuFind\View\Helper\Root\Flashmessages',