Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.16% covered (success)
95.16%
59 / 62
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
Alma
95.16% covered (success)
95.16%
59 / 62
83.33% covered (warning)
83.33%
5 / 6
22
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 fetchLinks
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 parseLinks
93.18% covered (success)
93.18%
41 / 44
0.00% covered (danger)
0.00%
0 / 1
13.05
 getKeyWithId
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 mapServiceType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 cleanupText
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * Alma Link Resolver Driver
5 *
6 * PHP version 8
7 *
8 * Copyright (C) The National Library of Finland 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  Resolver_Drivers
25 * @author   Ere Maijala <ere.maijala@helsinki.fi>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:link_resolver_drivers Wiki
28 */
29
30namespace VuFind\Resolver\Driver;
31
32use function in_array;
33
34/**
35 * Alma Link Resolver Driver
36 *
37 * @category VuFind
38 * @package  Resolver_Drivers
39 * @author   Ere Maijala <ere.maijala@helsinki.fi>
40 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
41 * @link     https://vufind.org/wiki/development:plugins:link_resolver_drivers Wiki
42 */
43class Alma extends AbstractBase
44{
45    /**
46     * HTTP client
47     *
48     * @var \Laminas\Http\Client
49     */
50    protected $httpClient;
51
52    /**
53     * List of filter reasons that are ignored (displayed regardless of filtering)
54     *
55     * @var array
56     */
57    protected $ignoredFilterReasons = ['Date Filter'];
58
59    /**
60     * Constructor
61     *
62     * @param string               $baseUrl    Base URL for link resolver
63     * @param \Laminas\Http\Client $httpClient HTTP client
64     * @param array                $options    OpenURL Configuration (optional)
65     */
66    public function __construct(
67        $baseUrl,
68        \Laminas\Http\Client $httpClient,
69        array $options = []
70    ) {
71        parent::__construct($baseUrl);
72        $this->httpClient = $httpClient;
73        if (isset($options['ignoredFilterReasons'])) {
74            $this->ignoredFilterReasons
75                = empty($options['ignoredFilterReasons'])
76                    ? [] : array_filter((array)$options['ignoredFilterReasons']);
77        }
78    }
79
80    /**
81     * Fetch Links
82     *
83     * Fetches a set of links corresponding to an OpenURL
84     *
85     * @param string $openURL openURL (url-encoded)
86     *
87     * @return string         Raw XML returned by resolver
88     */
89    public function fetchLinks($openURL)
90    {
91        // Make the call to Alma and load results
92        $url = $this->getResolverUrl(
93            'svc_dat=CTO&response_type=xml&' . $openURL
94        );
95        return $this->httpClient->setUri($url)->send()->getBody();
96    }
97
98    /**
99     * Parse Links
100     *
101     * Parses an XML file returned by a link resolver
102     * and converts it to a standardised format for display
103     *
104     * @param string $xmlstr Raw XML returned by resolver
105     *
106     * @return array         Array of values
107     */
108    public function parseLinks($xmlstr)
109    {
110        $records = []; // array to return
111        try {
112            $xml = new \SimpleXmlElement($xmlstr);
113        } catch (\Exception $e) {
114            return $records;
115        }
116
117        foreach ($xml->context_services->children() as $service) {
118            $filtered = $this->getKeyWithId($service, 'Filtered');
119            if ('true' === $filtered) {
120                $reason = $this->getKeyWithId($service, 'Filter reason');
121                if (!in_array($reason, $this->ignoredFilterReasons)) {
122                    continue;
123                }
124            }
125            $originalServiceType = (string)$service->attributes()->service_type;
126            $serviceType = $this->mapServiceType($originalServiceType);
127            if (!$serviceType) {
128                continue;
129            }
130            if ('getWebService' === $serviceType) {
131                $title = $this->getKeyWithId($service, 'public_name');
132                $href = $this->getKeyWithId($service, 'url');
133                $access = '';
134            } else {
135                $title = $this->getKeyWithId($service, 'package_display_name');
136                if (!$title) {
137                    $title = $this->getKeyWithId($service, 'package_public_name');
138                }
139                $href = (string)$service->resolution_url;
140                if (
141                    'getOpenAccessFullText' === $originalServiceType
142                    || $this->getKeyWithId($service, 'Is_free')
143                ) {
144                    $access = 'open';
145                } else {
146                    $access = 'limited';
147                }
148            }
149            if ($coverage = $this->getKeyWithId($service, 'Availability')) {
150                $coverage = $this->cleanupText($coverage);
151            }
152            if ($notes = $this->getKeyWithId($service, 'public_note')) {
153                $notes = $this->cleanupText($notes);
154            }
155            $authentication = $this->getKeyWithId($service, 'Authentication_note');
156            if ($authentication) {
157                $authentication = $this->cleanupText($authentication);
158            }
159
160            $record = compact(
161                'title',
162                'coverage',
163                'access',
164                'href',
165                'notes',
166                'authentication'
167            );
168            $record['service_type'] = $serviceType;
169            $records[] = $record;
170        }
171        return $records;
172    }
173
174    /**
175     * Get a key with the specified id from the context_service element
176     *
177     * @param \SimpleXMLElement $service Service element
178     * @param string            $id      Key id
179     *
180     * @return string
181     */
182    protected function getKeyWithId(\SimpleXMLElement $service, $id)
183    {
184        foreach ($service->keys->children() as $key) {
185            if ((string)$key->attributes()->id === $id) {
186                return (string)$key;
187            }
188        }
189        return '';
190    }
191
192    /**
193     * Map Alma service types to VuFind. Returns an empty string for an unmapped
194     * value.
195     *
196     * @param string $serviceType Alma service type
197     *
198     * @return string
199     */
200    protected function mapServiceType($serviceType)
201    {
202        $map = [
203            'getFullTxt' => 'getFullTxt',
204            'getOpenAccessFullText' => 'getFullTxt',
205            'getHolding' => 'getHolding',
206            'GeneralElectronicService' => 'getWebService',
207            'DB' => 'getFullTxt',
208            'Package' => 'getFullTxt',
209        ];
210        return $map[$serviceType] ?? '';
211    }
212
213    /**
214     * Clean up textual information
215     *
216     * @param string $str Text
217     *
218     * @return string
219     */
220    protected function cleanupText($str)
221    {
222        $str = trim(preg_replace('/<br\/?>/', ' ', $str));
223        $str = strip_tags($str);
224        return $str;
225    }
226}