Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
8.93% |
5 / 56 |
|
0.00% |
0 / 13 |
CRAP | |
0.00% |
0 / 1 |
Connector | |
8.93% |
5 / 56 |
|
0.00% |
0 / 13 |
497.09 | |
0.00% |
0 / 1 |
__construct | |
71.43% |
5 / 7 |
|
0.00% |
0 / 1 |
3.21 | |||
init | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
query | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
72 | |||
send | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
6 | |||
ping | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
record | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
search | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
session | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
settings | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
show | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
stat | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
termlist | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
bytarget | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * Central class for connecting to Pazpar2 resources used by VuFind. |
5 | * |
6 | * PHP version 8 |
7 | * |
8 | * Copyright (C) Villanova University 2011. |
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 Connection |
25 | * @author Chris Hallberg <challber@villanova.edu> |
26 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
27 | * @link https://vufind.org/wiki/development:architecture Wiki |
28 | */ |
29 | |
30 | namespace VuFindSearch\Backend\Pazpar2; |
31 | |
32 | use Laminas\Http\Client; |
33 | use Laminas\Http\Request; |
34 | use VuFindSearch\Backend\Exception\HttpErrorException; |
35 | use VuFindSearch\ParamBag; |
36 | |
37 | use function sprintf; |
38 | |
39 | /** |
40 | * Central class for connecting to resources used by VuFind. |
41 | * |
42 | * @category VuFind |
43 | * @package Connection |
44 | * @author Chris Hallberg <challber@villanova.edu> |
45 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
46 | * @link https://vufind.org/wiki/development:architecture Wiki |
47 | */ |
48 | class Connector implements \Laminas\Log\LoggerAwareInterface |
49 | { |
50 | use \VuFind\Log\LoggerAwareTrait; |
51 | |
52 | /** |
53 | * Base url for searches |
54 | * |
55 | * @var string |
56 | */ |
57 | protected $base; |
58 | |
59 | /** |
60 | * The HTTP_Request object used for REST transactions |
61 | * |
62 | * @var Client |
63 | */ |
64 | protected $client; |
65 | |
66 | /** |
67 | * Session ID |
68 | * |
69 | * @var string |
70 | */ |
71 | protected $session = false; |
72 | |
73 | /** |
74 | * Constructor |
75 | * |
76 | * @param string $base Base URL for Pazpar2 |
77 | * @param Client $client An HTTP client object |
78 | * @param bool $autoInit Should we auto-initialize the Pazpar2 connection? |
79 | */ |
80 | public function __construct($base, Client $client, $autoInit = false) |
81 | { |
82 | $this->base = $base; |
83 | if (empty($this->base)) { |
84 | throw new \Exception('Missing Pazpar2 base URL.'); |
85 | } |
86 | |
87 | $this->client = $client; |
88 | $this->client->setMethod(Request::METHOD_GET); // always use GET |
89 | |
90 | if ($autoInit) { |
91 | $this->init(); |
92 | } |
93 | } |
94 | |
95 | /** |
96 | * Initializes a session. Returns session ID to be used in subsequent requests. |
97 | * Adds session to the base |
98 | * |
99 | * @return session id |
100 | */ |
101 | public function init() |
102 | { |
103 | $this->session = false; // clear any existing session |
104 | $session = $this->query('init'); |
105 | if (!isset($session->session)) { |
106 | throw new \Exception('Session initialization failed.'); |
107 | } |
108 | $this->session = $session->session; |
109 | return $session; |
110 | } |
111 | |
112 | /** |
113 | * Requests and receives information from pazpar |
114 | * |
115 | * @param string $command the command to be executed |
116 | * @param ParamBag $data optional extra data |
117 | * |
118 | * @return SimpleXMLElement Response |
119 | */ |
120 | protected function query($command, ParamBag $data = null) |
121 | { |
122 | // If we don't have a session as long as we're not being explicit |
123 | if (!$this->session && $command !== 'init') { |
124 | $this->init(); |
125 | } |
126 | |
127 | // Don't change input when manipulating parameters: |
128 | $params = (null === $data) ? new ParamBag() : clone $data; |
129 | |
130 | // Add session and command: |
131 | if ($this->session) { |
132 | $params->set('session', $this->session); |
133 | } |
134 | $params->set('command', $command); |
135 | |
136 | $this->client->setUri($this->base . '?' . implode('&', $params->request())); |
137 | $xmlStr = $this->send($this->client); |
138 | $xml = simplexml_load_string($xmlStr); |
139 | |
140 | // If our session has expired, start a new session |
141 | if ( |
142 | $command !== 'init' |
143 | && $xml->session == $this->session && isset($this->session) |
144 | ) { |
145 | $this->init(); |
146 | return $this->query($command, $data); |
147 | } |
148 | return $xml; |
149 | } |
150 | |
151 | /** |
152 | * Send a request and return the response. |
153 | * |
154 | * @param Client $client Prepare HTTP client |
155 | * |
156 | * @return string Response body |
157 | * |
158 | * @throws \VuFindSearch\Backend\Exception\RemoteErrorException Server |
159 | * signaled a server error (HTTP 5xx) |
160 | * @throws \VuFindSearch\Backend\Exception\RequestErrorException Server |
161 | * signaled a client error (HTTP 4xx) |
162 | */ |
163 | protected function send(Client $client) |
164 | { |
165 | $this->debug( |
166 | sprintf('=> %s %s', $client->getMethod(), $client->getUri()) |
167 | ); |
168 | |
169 | $time = microtime(true); |
170 | $response = $client->send(); |
171 | $time = microtime(true) - $time; |
172 | |
173 | $this->debug( |
174 | sprintf( |
175 | '<= %s %s', |
176 | $response->getStatusCode(), |
177 | $response->getReasonPhrase() |
178 | ), |
179 | ['time' => $time] |
180 | ); |
181 | |
182 | if (!$response->isSuccess()) { |
183 | throw HttpErrorException::createFromResponse($response); |
184 | } |
185 | return $response->getBody(); |
186 | } |
187 | |
188 | /** |
189 | * Keeps a session alive. An idle session will time out after one minute. |
190 | * The ping command can be used to keep the session alive absent other activity. |
191 | * It is suggested that any browser client have a simple alarm handler |
192 | * which sends a ping every 50 seconds or so once a session has been initialized |
193 | * |
194 | * @return void |
195 | */ |
196 | public function ping() |
197 | { |
198 | $this->query('ping'); |
199 | } |
200 | |
201 | /** |
202 | * Retrieves a detailed record. |
203 | * Unlike the show command, this command returns |
204 | * metadata records before merging takes place. |
205 | * |
206 | * @param string $id array of options as described above |
207 | * |
208 | * @return associative array of XML data |
209 | */ |
210 | public function record($id) |
211 | { |
212 | return $this->query('record', new ParamBag(['id' => $id])); |
213 | } |
214 | |
215 | /** |
216 | * Launches a search. |
217 | * |
218 | * Option (default): |
219 | * - query : search string ('') |
220 | * - filter : setting+operator+args pairs, such as 'pz:id=4|17, pz:id~3' |
221 | * - limit : Narrows the search by one or more fields (typically facets) |
222 | * as name=arg1|arg2| pairs separated by comma (none) |
223 | * - startrecs : int (0) |
224 | * - maxrecs : int (100) |
225 | * |
226 | * TODO: Make the array more useful to get the correct format? |
227 | * |
228 | * @param ParamBag $options array of options as described above |
229 | * |
230 | * @return associative array of XML data |
231 | */ |
232 | public function search(ParamBag $options = null) |
233 | { |
234 | return $this->query('search', $options); |
235 | } |
236 | |
237 | /** |
238 | * Return session id |
239 | * |
240 | * @return session id |
241 | */ |
242 | public function session() |
243 | { |
244 | return $this->session; |
245 | } |
246 | |
247 | /** |
248 | * Applies settings to this session |
249 | * Each setting parameter has the form name[target]=value |
250 | * |
251 | * TODO: Make the array more useful to get the correct format? |
252 | * |
253 | * @param string $settings settings to be sets |
254 | * |
255 | * @return bool Success/failure status |
256 | */ |
257 | public function settings($settings = false) |
258 | { |
259 | if ($settings === false) { |
260 | return false; |
261 | } |
262 | $set = $this->query('settings', $settings); |
263 | return $set->status == 'OK'; |
264 | } |
265 | |
266 | /** |
267 | * Proper alias of results |
268 | * |
269 | * Options (default): |
270 | * - start : int (0) |
271 | * - num : int (20) |
272 | * - block : 1 = wait until enough records are found (0) |
273 | * - sort : column:1 [increasing] or 0 [decreasing] (none) |
274 | * |
275 | * @param ParamBag $options array of options as described above |
276 | * |
277 | * @return array Associative array of XML data |
278 | */ |
279 | public function show(ParamBag $options = null) |
280 | { |
281 | return $this->query('show', $options); |
282 | } |
283 | |
284 | /** |
285 | * Provides status information about an ongoing search. |
286 | * |
287 | * @return associative array of XML data |
288 | */ |
289 | public function stat() |
290 | { |
291 | return $this->query('stat'); |
292 | } |
293 | |
294 | /** |
295 | * Retrieves term list(s). |
296 | * |
297 | * Options (default): |
298 | * - name : comma-separated list of termlist names (all termlists) |
299 | * - num : maximum number of entries to return (15) |
300 | * |
301 | * @param ParamBag $options array of options as described above |
302 | * |
303 | * @return array Associative array of XML data |
304 | */ |
305 | public function termlist(ParamBag $options = null) |
306 | { |
307 | return $this->query('termlist', $options); |
308 | } |
309 | |
310 | /** |
311 | * Returns information about the status of each active client. |
312 | * |
313 | * @param string $id client id |
314 | * |
315 | * @return array Associative array of XML data |
316 | */ |
317 | public function bytarget($id) |
318 | { |
319 | return $this->query('bytarget', new ParamBag(['id' => $id])); |
320 | } |
321 | } |