1
|
|
|
<?php namespace Scriptotek\Sru; |
2
|
|
|
|
3
|
|
|
use Http\Client\Common\Plugin\AuthenticationPlugin; |
4
|
|
|
use Http\Client\Common\PluginClient; |
5
|
|
|
use Http\Client\HttpClient; |
6
|
|
|
use Http\Discovery\HttpClientDiscovery; |
7
|
|
|
use Http\Client\Common\Plugin\ErrorPlugin; |
8
|
|
|
use Http\Discovery\MessageFactoryDiscovery; |
9
|
|
|
use Http\Message\Authentication\BasicAuth; |
10
|
|
|
use Http\Message\MessageFactory; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* SRU client |
14
|
|
|
*/ |
15
|
|
|
class Client |
16
|
|
|
{ |
17
|
|
|
/** @var HttpClient */ |
18
|
|
|
protected $httpClient; |
19
|
|
|
|
20
|
|
|
/** @var MessageFactory */ |
21
|
|
|
protected $messageFactory; |
22
|
|
|
|
23
|
|
|
/** @var string SRU service base URL */ |
24
|
|
|
protected $url; |
25
|
|
|
|
26
|
|
|
/** @var string Requested schema for the returned records */ |
27
|
|
|
protected $schema; |
28
|
|
|
|
29
|
|
|
/** @var string SRU protocol version */ |
30
|
|
|
protected $version; |
31
|
|
|
|
32
|
|
|
/** @var string Some user agent string to identify our client */ |
33
|
|
|
protected $userAgent; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var string|string[] Proxy configuration details. |
37
|
|
|
* |
38
|
|
|
* Either a string 'host:port' or an |
39
|
|
|
* array('host:port', 'username', 'password'). |
40
|
|
|
*/ |
41
|
|
|
protected $proxy; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var string[] Array containing username and password |
45
|
|
|
*/ |
46
|
|
|
protected $credentials; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* Create a new client |
50
|
|
|
* |
51
|
|
|
* @param string $url Base URL to the SRU service |
52
|
|
|
* @param array $options Associative array of options |
53
|
|
|
* @param HttpClient $httpClient |
54
|
|
|
* @param MessageFactory|null $messageFactory |
55
|
|
|
* @throws \ErrorException |
56
|
|
|
*/ |
57
|
|
|
public function __construct( |
58
|
|
|
$url, |
59
|
|
|
$options = null, |
60
|
|
|
HttpClient $httpClient = null, |
61
|
|
|
MessageFactory $messageFactory = null |
62
|
|
|
) { |
63
|
|
|
$this->url = $url; |
64
|
|
|
$options = $options ?: array(); |
65
|
|
|
|
66
|
|
|
$plugins = [new ErrorPlugin()]; |
67
|
|
|
|
68
|
|
|
$this->schema = isset($options['schema']) |
69
|
|
|
? $options['schema'] |
70
|
|
|
: 'marcxml'; |
71
|
|
|
|
72
|
|
|
$this->version = isset($options['version']) |
73
|
|
|
? $options['version'] |
74
|
|
|
: '1.1'; |
75
|
|
|
|
76
|
|
|
$this->userAgent = isset($options['user-agent']) |
77
|
|
|
? $options['user-agent'] |
78
|
|
|
: null; |
79
|
|
|
|
80
|
|
|
if (isset($options['credentials'])) { |
81
|
|
|
$authentication = new BasicAuth($options['credentials'][0], $options['credentials'][1]); |
82
|
|
|
$plugins[] = new AuthenticationPlugin($authentication); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
if (isset($options['proxy'])) { |
86
|
|
|
throw new\ErrorException('Not supported'); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
$this->httpClient = new PluginClient($httpClient ?: HttpClientDiscovery::find(), $plugins); |
90
|
|
|
$this->messageFactory = $messageFactory ?: MessageFactoryDiscovery::find(); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Construct the URL for a CQL query |
95
|
|
|
* |
96
|
|
|
* @param string $cql The CQL query |
97
|
|
|
* @param int $start Start value in result set (optional) |
98
|
|
|
* @param int $count Number of records to request (optional) |
99
|
|
|
* @param array $extraParams Extra GET parameters |
100
|
|
|
* @return string |
101
|
|
|
*/ |
102
|
|
|
public function urlTo($cql, $start = 1, $count = 10, $extraParams = array()) |
103
|
|
|
{ |
104
|
|
|
$qs = array( |
105
|
|
|
'operation' => 'searchRetrieve', |
106
|
|
|
'version' => $this->version, |
107
|
|
|
'recordSchema' => $this->schema, |
108
|
|
|
'maximumRecords' => $count, |
109
|
|
|
'query' => $cql |
110
|
|
|
); |
111
|
|
|
|
112
|
|
|
if ($start != 1) { |
113
|
|
|
// At least the BIBSYS SRU service, specifying startRecord results in |
114
|
|
|
// a less clear error message when there's no results |
115
|
|
|
$qs['startRecord'] = $start; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
foreach ($extraParams as $key => $value) { |
119
|
|
|
$qs[$key] = $value; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
return $this->url . '?' . http_build_query($qs); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Get HTTP client configuration options (authentication, proxy, headers) |
127
|
|
|
* |
128
|
|
|
* @return array |
129
|
|
|
*/ |
130
|
|
|
public function getHttpHeaders() |
131
|
|
|
{ |
132
|
|
|
$headers = array( |
133
|
|
|
'Accept' => 'application/xml' |
134
|
|
|
); |
135
|
|
|
if ($this->userAgent) { |
136
|
|
|
$headers['User-Agent'] = $this->userAgent; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return $headers; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Perform a searchRetrieve request |
144
|
|
|
* |
145
|
|
|
* @deprecated |
146
|
|
|
* @param string $cql |
147
|
|
|
* @param int $start Start value in result set (optional) |
148
|
|
|
* @param int $count Number of records to request (optional) |
149
|
|
|
* @param array $extraParams Extra GET parameters |
150
|
|
|
* @return SearchRetrieveResponse |
151
|
|
|
*/ |
152
|
|
|
public function search($cql, $start = 1, $count = 10, $extraParams = array()) |
153
|
|
|
{ |
154
|
|
|
$url = $this->urlTo($cql, $start, $count, $extraParams); |
155
|
|
|
$body = $this->request('GET', $url); |
156
|
|
|
|
157
|
|
|
return new SearchRetrieveResponse($body, $this); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Perform a searchRetrieve request and return an iterator over the records |
162
|
|
|
* |
163
|
|
|
* @param string $cql |
164
|
|
|
* @param int $batchSize Number of records to request per request |
165
|
|
|
* @param array $extraParams Extra GET parameters |
166
|
|
|
* @param mixed $httpClient A http client |
167
|
|
|
* @return Records |
168
|
|
|
*/ |
169
|
|
|
public function all($cql, $batchSize = 10, $extraParams = array(), $httpClient = null) |
170
|
|
|
{ |
171
|
|
|
return new Records($cql, $this, $batchSize, $extraParams, $httpClient); |
|
|
|
|
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Alias for `all()` |
176
|
|
|
* @deprecated |
177
|
|
|
* @param $cql |
178
|
|
|
* @param int $batchSize |
179
|
|
|
* @param array $extraParams |
180
|
|
|
* @param null $httpClient |
181
|
|
|
* @return Records |
182
|
|
|
*/ |
183
|
|
|
public function records($cql, $batchSize = 10, $extraParams = array(), $httpClient = null) |
184
|
|
|
{ |
185
|
|
|
return $this->all($cql, $batchSize, $extraParams, $httpClient); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Perform a searchRetrieve request and return first record |
190
|
|
|
* |
191
|
|
|
* @param string $cql |
192
|
|
|
* @param array $extraParams Extra GET parameters |
193
|
|
|
* @param mixed $httpClient A http client |
194
|
|
|
* @return Record |
195
|
|
|
*/ |
196
|
|
|
public function first($cql, $extraParams = array(), $httpClient = null) |
197
|
|
|
{ |
198
|
|
|
$recs = new Records($cql, $this, 1, $extraParams, $httpClient); |
|
|
|
|
199
|
|
|
return $recs->numberOfRecords() ? $recs->current() : null; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Perform an explain request |
204
|
|
|
* |
205
|
|
|
* @return ExplainResponse |
206
|
|
|
*/ |
207
|
|
|
public function explain() |
208
|
|
|
{ |
209
|
|
|
$url = $this->url . '?' . http_build_query(array( |
210
|
|
|
'operation' => 'explain', |
211
|
|
|
'version' => $this->version, |
212
|
|
|
)); |
213
|
|
|
|
214
|
|
|
$body = $this->request('GET', $url); |
215
|
|
|
|
216
|
|
|
return new ExplainResponse($body, $this); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* @param string $method |
221
|
|
|
* @param string $url |
222
|
|
|
* @return string |
223
|
|
|
*/ |
224
|
|
|
public function request($method, $url) |
225
|
|
|
{ |
226
|
|
|
$request = $this->messageFactory->createRequest($method, $url, $this->getHttpHeaders()); |
227
|
|
|
$response = $this->httpClient->sendRequest($request); |
228
|
|
|
|
229
|
|
|
return (string) $response->getBody(); |
230
|
|
|
} |
231
|
|
|
} |
232
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.