Passed
Push — main ( 6731d6...4efee0 )
by Dan Michael O.
11:38
created

Client   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 203
Duplicated Lines 0 %

Importance

Changes 8
Bugs 2 Features 0
Metric Value
eloc 53
c 8
b 2
f 0
dl 0
loc 203
rs 10
wmc 19

8 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 33 7
A explain() 0 10 1
A request() 0 10 3
A urlTo() 0 21 3
A first() 0 4 2
A records() 0 3 1
A all() 0 3 1
A search() 0 6 1
1
<?php
2
3
namespace Scriptotek\Sru;
4
5
use Http\Client\Common\Plugin\AuthenticationPlugin;
6
use Http\Client\Common\PluginClient;
7
use Http\Client\Common\Exception\ServerErrorException;
8
use Http\Factory\Discovery\HttpClient;
9
use Http\Factory\Discovery\HttpFactory;
10
use Http\Message\Authentication\BasicAuth;
11
use Psr\Http\Client\ClientInterface;
12
use Psr\Http\Message\RequestFactoryInterface;
13
14
/**
15
 * SRU client
16
 */
17
class Client
18
{
19
    /** @var ClientInterface */
20
    protected $httpClient;
21
22
    /**
23
     * @var RequestFactoryInterface
24
     */
25
    private $requestFactory;
26
27
    /** @var string SRU service base URL */
28
    protected $url;
29
30
    /** @var string Requested schema for the returned records */
31
    protected $schema;
32
33
    /** @var string SRU protocol version */
34
    protected $version;
35
36
    /** @var string Some user agent string to identify our client */
37
    protected $userAgent;
38
39
    /** @var array Custom headers */
40
    public $headers;
41
42
    /**
43
     * @var string|string[] Proxy configuration details.
44
     *
45
     * Either a string 'host:port' or an
46
     * array('host:port', 'username', 'password').
47
     */
48
    protected $proxy;
49
50
    /**
51
     * @var string[] Array containing username and password
52
     */
53
    protected $credentials;
54
55
    /**
56
     * Create a new client
57
     *
58
     * @param string                   $url             Base URL to the SRU service
59
     * @param ?array                   $options         Associative array of options
60
     * @param ?ClientInterface         $httpClient
61
     * @param ?RequestFactoryInterface $requestFactory
62
     * @throws \ErrorException
63
     */
64
    public function __construct(
65
        string $url,
66
        ?array $options = null,
67
        ClientInterface $httpClient = null,
68
        RequestFactoryInterface $requestFactory = null
69
    ) {
70
        $this->url = $url;
71
        $options = $options ?: [];
72
73
        $plugins = [];
74
75
        $this->schema = $options['schema'] ?? 'marcxml';
76
77
        $this->version = $options['version'] ?? '1.1';
78
79
        $this->headers = $options['headers'] ?? ['Accept' => 'application/xml'];
80
81
        if (isset($options['user-agent'])) {
82
            // legacy option
83
            $this->headers['User-Agent'] = $options['user-agent'];
84
        }
85
86
        if (isset($options['credentials'])) {
87
            $authentication = new BasicAuth($options['credentials'][0], $options['credentials'][1]);
88
            $plugins[] = new AuthenticationPlugin($authentication);
89
        }
90
91
        if (isset($options['proxy'])) {
92
            throw new \ErrorException('Not supported');
93
        }
94
95
        $this->httpClient = new PluginClient($httpClient ?: HttpClient::client(), $plugins);
96
        $this->requestFactory = $requestFactory ?: HttpFactory::requestFactory();
97
    }
98
99
    /**
100
     * Construct the URL for a CQL query
101
     *
102
     * @param string $cql The CQL query
103
     * @param int $start Start value in result set (optional)
104
     * @param int $count Number of records to request (optional)
105
     * @param array $extraParams Extra GET parameters
106
     * @return string
107
     */
108
    public function urlTo(string $cql, int $start = 1, int $count = 10, array $extraParams = []): string
109
    {
110
        $qs = array(
111
            'operation' => 'searchRetrieve',
112
            'version' => $this->version,
113
            'recordSchema' => $this->schema,
114
            'maximumRecords' => $count,
115
            'query' => $cql
116
        );
117
118
        if ($start != 1) {
119
            // At least the BIBSYS SRU service, specifying startRecord results in
120
            // a less clear error message when there's no results
121
            $qs['startRecord'] = $start;
122
        }
123
124
        foreach ($extraParams as $key => $value) {
125
            $qs[$key] = $value;
126
        }
127
128
        return $this->url . '?' . http_build_query($qs);
129
    }
130
131
    /**
132
     * Perform a searchRetrieve request
133
     *
134
     * @param string $cql
135
     * @param int $start Start value in result set (optional)
136
     * @param int $count Number of records to request (optional)
137
     * @param array $extraParams Extra GET parameters
138
     * @return SearchRetrieveResponse
139
     *@deprecated
140
     */
141
    public function search(string $cql, int $start = 1, int $count = 10, array $extraParams = []): SearchRetrieveResponse
142
    {
143
        $url = $this->urlTo($cql, $start, $count, $extraParams);
144
        $body = $this->request('GET', $url);
145
146
        return new SearchRetrieveResponse($body, $this, $url);
147
    }
148
149
    /**
150
     * Perform a searchRetrieve request and return an iterator over the records
151
     *
152
     * @param string $cql
153
     * @param int $batchSize Number of records to request per request
154
     * @param array $extraParams Extra GET parameters
155
     * @return Records
156
     */
157
    public function all(string $cql, int $batchSize = 10, array $extraParams = []): Records
158
    {
159
        return new Records($cql, $this, $batchSize, $extraParams);
160
    }
161
162
    /**
163
     * Alias for `all()`
164
     * @param string $cql
165
     * @param int $batchSize
166
     * @param array $extraParams
167
     * @return Records
168
     *@deprecated
169
     */
170
    public function records(string $cql, int $batchSize = 10, array $extraParams = []): Records
171
    {
172
        return $this->all($cql, $batchSize, $extraParams);
173
    }
174
175
    /**
176
     * Perform a searchRetrieve request and return first record
177
     *
178
     * @param string $cql
179
     * @param array $extraParams Extra GET parameters
180
     * @return ?Record
181
     */
182
    public function first(string $cql, array $extraParams = []): ?Record
183
    {
184
        $recs = new Records($cql, $this, 1, $extraParams);
185
        return $recs->numberOfRecords() ? $recs->current() : null;
186
    }
187
188
    /**
189
     * Perform an explain request
190
     *
191
     * @return ExplainResponse
192
     */
193
    public function explain(): ExplainResponse
194
    {
195
        $url = $this->url . '?' . http_build_query(array(
196
            'operation' => 'explain',
197
            'version' => $this->version,
198
        ));
199
200
        $body = $this->request('GET', $url);
201
202
        return new ExplainResponse($body, $this, $url);
203
    }
204
205
    /**
206
     * @param string $method
207
     * @param string $url
208
     * @return string
209
     */
210
    public function request(string $method, string $url): string
211
    {
212
        $request = $this->requestFactory->createRequest($method, $url, $this->headers);
0 ignored issues
show
Unused Code introduced by
The call to Psr\Http\Message\Request...erface::createRequest() has too many arguments starting with $this->headers. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

212
        /** @scrutinizer ignore-call */ 
213
        $request = $this->requestFactory->createRequest($method, $url, $this->headers);

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. Please note the @ignore annotation hint above.

Loading history...
213
        $response = $this->httpClient->sendRequest($request);
214
215
        if ($response->getStatusCode() >= 500 && $response->getStatusCode() < 600) {
216
            throw new ServerErrorException($response->getReasonPhrase(), $request, $response);
217
        }
218
219
        return (string) $response->getBody();
220
    }
221
}
222