Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
84.44% covered (warning)
84.44%
38 / 45
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Bokinfo
84.44% covered (warning)
84.44%
38 / 45
40.00% covered (danger)
40.00%
2 / 5
14.74
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUrl
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
5.12
 createHttpClient
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 testUrlFunction
62.50% covered (warning)
62.50%
5 / 8
0.00% covered (danger)
0.00%
0 / 1
3.47
 getImageUrl
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
4.01
1<?php
2
3/**
4 * Plugin for Bokinfo coverimages
5 *
6 * PHP version 8
7 *
8 * Copyright (C) imCode Partner AB 2022.
9 * Copyright (C) Moravian Library 2019.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2,
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23 *
24 * @category VuFind
25 * @package  Content
26 * @author   Jacob Sandin <jacob@imcode.com>
27 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
28 * @link     https://vufind.org/wiki/development Wiki
29 */
30
31namespace VuFind\Content\Covers;
32
33use SimpleXMLElement;
34
35use function strlen;
36
37/**
38 * Plugin for Bokinfo coverimages
39 *
40 * @category VuFind
41 * @package  Content
42 * @author   Jacob Sandin <jacob@imcode.com>
43 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
44 * @link     https://vufind.org/wiki/development Wiki
45 */
46class Bokinfo extends \VuFind\Content\AbstractCover implements
47    \Laminas\Log\LoggerAwareInterface,
48    \VuFindHttp\HttpServiceAwareInterface
49{
50    use \VuFind\Log\LoggerAwareTrait;
51    use \VuFindHttp\HttpServiceAwareTrait;
52
53    /**
54     * Constructor
55     */
56    public function __construct()
57    {
58        // Checked with vendor to be sure caching is allowed as of February, 2022.
59        $this->cacheAllowed = true;
60        $this->supportsIsbn = true;
61    }
62
63    /**
64     * Get image URL for a particular API key and set of IDs (or false if invalid).
65     *
66     * @param string $key  API key
67     * @param string $size Size of image to load (small/medium/large)
68     * @param array  $ids  Associative array of identifiers (keys may include 'isbn'
69     * pointing to an ISBN object and 'issn' pointing to a string)
70     *
71     * @return string|bool
72     */
73    public function getUrl($key, $size, $ids)
74    {
75        if (!isset($ids['isbn'])) {
76            return false;
77        }
78        if (empty($key)) {
79            return false;
80        }
81
82        $isbn = $ids['isbn']->get13();
83        try {
84            $client = $this->createHttpClient(
85                "https://api.bokinfo.se/book/get/$isbn"
86            );
87
88            $client->getRequest()->getHeaders()
89                  ->addHeaderLine('Ocp-Apim-Subscription-Key', $key);
90
91            $resp = $client->send();
92            $body = $resp->getBody();
93            $url = $this->getImageUrl($body);
94            if ($this->testUrlFunction($url)) {
95                return $url;
96            }
97        } catch (\Throwable $ex) {
98            return false;
99        }
100
101        return false;
102    }
103
104    /**
105     * Return a HTTP Client object
106     *
107     * @param string $url API Url
108     *
109     * @return HttpClient Http Client
110     */
111    protected function createHttpClient($url)
112    {
113        $client = $this->httpService->createClient($url);
114
115        $client->setOptions(
116            ['useragent' => 'VuFind', 'keepalive' => true]
117        );
118
119        return $client;
120    }
121
122    /**
123     * Test that the url is really working
124     *
125     * @param string $url image Url
126     *
127     * @return bool Http Client
128     */
129    protected function testUrlFunction($url)
130    {
131        try {
132            $client = $this->createHttpClient($url);
133            $resp = $client->send();
134            $headers = $resp->getHeaders();
135            if ($headers) {
136                return true;
137            }
138        } catch (\Throwable $ex) {
139            return false;
140        }
141        return false;
142    }
143
144    /**
145     * Find the image url in the XML returned from API
146     *
147     * @param string $rawXML XML returned from API
148     *
149     * @return string url of the image
150     */
151    protected function getImageUrl($rawXML)
152    {
153        if (!str_contains($rawXML, 'ResourceLink')) {
154            return '';
155        }
156
157        // This is already wrapped in try..catch
158        $xml = new SimpleXMLElement($rawXML);
159
160        foreach ($xml->getDocNamespaces() as $strPrefix => $strNamespace) {
161            if (strlen($strPrefix) == 0) {
162                $strPrefix = '_'; // Assign an arbitrary namespace prefix.
163            }
164            $xml->registerXPathNamespace($strPrefix, $strNamespace);
165        }
166
167        $result = $xml->xpath(
168            '//_:SupportingResource[_:ResourceContentType="01"]' .
169            '/_:ResourceVersion/_:ResourceLink'
170        );
171        return trim($result[0]);
172    }
173}