Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
Unpaywall
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
3 / 3
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 getLinks
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
5
 callApi
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3/**
4 * Unpaywall DOI linker
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2019.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  DOI
25 * @author   Josef Moravec <moravec@mzk.cz>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:doi_linkers Wiki
28 */
29
30namespace VuFind\DoiLinker;
31
32use VuFind\I18n\Translator\TranslatorAwareInterface;
33use VuFindHttp\HttpServiceAwareInterface;
34
35/**
36 * Unpaywall DOI linker
37 *
38 * @category VuFind
39 * @package  DOI
40 * @author   Josef Moravec <moravec@mzk.cz>
41 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
42 * @link     https://vufind.org/wiki/development:plugins:doi_linkers Wiki
43 */
44class Unpaywall implements
45    DoiLinkerInterface,
46    TranslatorAwareInterface,
47    HttpServiceAwareInterface
48{
49    use \VuFindHttp\HttpServiceAwareTrait;
50    use \VuFind\I18n\Translator\TranslatorAwareTrait;
51
52    /**
53     * URL to Unpaywall API
54     *
55     * @var string api url
56     */
57    protected $apiUrl;
58
59    /**
60     * E-mail used as parameter when calling API
61     *
62     * @var string email
63     */
64    protected $email;
65
66    /**
67     * Constructor
68     *
69     * @param \Laminas\Config\Config $config DOI section of main VuFind config
70     *
71     * @throws \Exception
72     */
73    public function __construct($config)
74    {
75        if (!isset($config->unpaywall_email)) {
76            throw new \Exception(
77                'Missing configuration for Unpaywall DOI linker: unpaywall_email'
78            );
79        }
80        $this->email = $config->unpaywall_email;
81        $this->apiUrl = $config->unpaywall_api_url ?? 'https://api.unpaywall.org/v2';
82    }
83
84    /**
85     * Given an array of DOIs, perform a lookup and return an associative array
86     * of arrays, keyed by DOI. Each array contains one or more associative arrays
87     * with required 'link' (URL to related resource) and 'label' (display text)
88     * keys and an optional 'icon' (URL to icon graphic) or localIcon (name of
89     * configured icon in theme) key.
90     *
91     * @param array $doiArray DOIs to look up
92     *
93     * @return array
94     */
95    public function getLinks(array $doiArray)
96    {
97        $response = [];
98        foreach ($doiArray as $doi) {
99            $json = $this->callApi($doi);
100            if ($json === null) {
101                continue;
102            }
103            $data = json_decode($json, true);
104            if (!empty($data['best_oa_location']['url_for_pdf'])) {
105                $response[$doi][] = [
106                    'link' => $data['best_oa_location']['url_for_pdf'],
107                    'label' => $this->translate('PDF Full Text'),
108                ];
109            } elseif (!empty($data['best_oa_location']['url'])) {
110                $response[$doi][] = [
111                    'link' => $data['best_oa_location']['url'],
112                    'label' => $this->translate('online_resources'),
113                ];
114            }
115        }
116        return $response;
117    }
118
119    /**
120     * Takes a DOI and do an API call to Unpaywall service
121     *
122     * @param string $doi DOI
123     *
124     * @return null|string
125     */
126    protected function callApi($doi)
127    {
128        $url = $this->apiUrl . '/' . urlencode($doi) . '?'
129            . http_build_query(['email' => $this->email]);
130        $client = $this->httpService->createClient($url);
131        $response = $client->send();
132        if ($response->isSuccess()) {
133            return $response->getBody();
134        }
135        return null;
136    }
137}