1
|
|
|
<?php |
2
|
|
|
namespace ApacheSolrForTypo3\Solr; |
3
|
|
|
|
4
|
|
|
/*************************************************************** |
5
|
|
|
* Copyright notice |
6
|
|
|
* |
7
|
|
|
* (c) 2009-2015 Ingo Renner <[email protected]> |
8
|
|
|
* All rights reserved |
9
|
|
|
* |
10
|
|
|
* This script is part of the TYPO3 project. The TYPO3 project is |
11
|
|
|
* free software; you can redistribute it and/or modify |
12
|
|
|
* it under the terms of the GNU General Public License as published by |
13
|
|
|
* the Free Software Foundation; either version 2 of the License, or |
14
|
|
|
* (at your option) any later version. |
15
|
|
|
* |
16
|
|
|
* The GNU General Public License can be found at |
17
|
|
|
* http://www.gnu.org/copyleft/gpl.html. |
18
|
|
|
* |
19
|
|
|
* This script is distributed in the hope that it will be useful, |
20
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
21
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22
|
|
|
* GNU General Public License for more details. |
23
|
|
|
* |
24
|
|
|
* This copyright notice MUST APPEAR in all copies of the script! |
25
|
|
|
***************************************************************/ |
26
|
|
|
|
27
|
|
|
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration; |
28
|
|
|
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager; |
29
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\Parser\SchemaParser; |
30
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\Parser\StopWordParser; |
31
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\Parser\SynonymParser; |
32
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\Schema\Schema; |
33
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\SolrCommunicationException; |
34
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\SolrInternalServerErrorException; |
35
|
|
|
use ApacheSolrForTypo3\Solr\System\Solr\SolrUnavailableException; |
36
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
37
|
|
|
use Apache_Solr_HttpTransportException; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Solr Service Access |
41
|
|
|
* |
42
|
|
|
* @author Ingo Renner <[email protected]> |
43
|
|
|
*/ |
44
|
|
|
class SolrService extends \Apache_Solr_Service |
45
|
|
|
{ |
46
|
|
|
const LUKE_SERVLET = 'admin/luke'; |
47
|
|
|
const SYSTEM_SERVLET = 'admin/system'; |
48
|
|
|
const PLUGINS_SERVLET = 'admin/plugins'; |
49
|
|
|
const CORES_SERVLET = 'admin/cores'; |
50
|
|
|
const SCHEMA_SERVLET = 'schema'; |
51
|
|
|
const SYNONYMS_SERVLET = 'schema/analysis/synonyms/'; |
52
|
|
|
const STOPWORDS_SERVLET = 'schema/analysis/stopwords/'; |
53
|
|
|
|
54
|
|
|
const SCHEME_HTTP = 'http'; |
55
|
|
|
const SCHEME_HTTPS = 'https'; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Server connection scheme. http or https. |
59
|
|
|
* |
60
|
|
|
* @var string |
61
|
|
|
*/ |
62
|
|
|
protected $_scheme = self::SCHEME_HTTP; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Constructed servlet URL for Luke |
66
|
|
|
* |
67
|
|
|
* @var string |
68
|
|
|
*/ |
69
|
|
|
protected $_lukeUrl; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Constructed servlet URL for plugin information |
73
|
|
|
* |
74
|
|
|
* @var string |
75
|
|
|
*/ |
76
|
|
|
protected $_pluginsUrl; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @var string |
80
|
|
|
*/ |
81
|
|
|
protected $_coresUrl; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* @var string |
85
|
|
|
*/ |
86
|
|
|
protected $_extractUrl; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* @var string |
90
|
|
|
*/ |
91
|
|
|
protected $_synonymsUrl; |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @var string |
95
|
|
|
*/ |
96
|
|
|
protected $_stopWordsUrl; |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* @var string |
100
|
|
|
*/ |
101
|
|
|
protected $_schemaUrl; |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* @var bool |
105
|
|
|
*/ |
106
|
|
|
protected $debug = false; |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* @var \Apache_Solr_Response |
110
|
|
|
*/ |
111
|
|
|
protected $responseCache = null; |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* @var bool |
115
|
|
|
*/ |
116
|
|
|
protected $hasSearched = false; |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @var array |
120
|
|
|
*/ |
121
|
|
|
protected $lukeData = []; |
122
|
|
|
|
123
|
|
|
protected $systemData = null; |
124
|
|
|
protected $pluginsData = null; |
125
|
|
|
|
126
|
|
|
protected $solrconfigName = null; |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @var TypoScriptConfiguration |
130
|
|
|
*/ |
131
|
|
|
protected $configuration; |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* @var array |
135
|
|
|
*/ |
136
|
|
|
protected static $pingCache = []; |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* @var SynonymParser |
140
|
|
|
*/ |
141
|
|
|
protected $synonymParser = null; |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* @var StopWordParser |
145
|
|
|
*/ |
146
|
|
|
protected $stopWordParser = null; |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* @var SchemaParser |
150
|
|
|
*/ |
151
|
|
|
protected $schemaParser = null; |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* @var Schema |
155
|
|
|
*/ |
156
|
|
|
protected $schema; |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* @var \ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager |
160
|
|
|
*/ |
161
|
|
|
protected $logger = null; |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Constructor |
165
|
|
|
* |
166
|
|
|
* @param string $host Solr host |
167
|
|
|
* @param string $port Solr port |
168
|
|
|
* @param string $path Solr path |
169
|
|
|
* @param string $scheme Scheme, defaults to http, can be https |
170
|
|
|
* @param TypoScriptConfiguration $typoScriptConfiguration |
171
|
|
|
* @param SynonymParser $synonymParser |
172
|
|
|
* @param StopWordParser $stopWordParser |
173
|
|
|
* @param SchemaParser $schemaParser |
174
|
|
|
* @param SolrLogManager $logManager |
175
|
|
|
*/ |
176
|
119 |
|
public function __construct( |
177
|
|
|
$host = '', |
178
|
|
|
$port = '8983', |
179
|
|
|
$path = '/solr/', |
180
|
|
|
$scheme = 'http', |
181
|
|
|
TypoScriptConfiguration $typoScriptConfiguration = null, |
182
|
|
|
SynonymParser $synonymParser = null, |
183
|
|
|
StopWordParser $stopWordParser = null, |
184
|
|
|
SchemaParser $schemaParser = null, |
185
|
|
|
SolrLogManager $logManager = null |
186
|
|
|
) { |
187
|
|
|
|
188
|
119 |
|
$this->setScheme($scheme); |
189
|
|
|
|
190
|
118 |
|
$this->logger = is_null($logManager) ? GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__) : $logManager; |
191
|
118 |
|
$this->configuration = is_null($typoScriptConfiguration) ? Util::getSolrConfiguration() : $typoScriptConfiguration; |
192
|
118 |
|
$this->synonymParser = is_null($synonymParser) ? GeneralUtility::makeInstance(SynonymParser::class) : $synonymParser; |
193
|
118 |
|
$this->stopWordParser = is_null($stopWordParser) ? GeneralUtility::makeInstance(StopWordParser::class) : $stopWordParser; |
194
|
118 |
|
$this->schemaParser = is_null($schemaParser) ? GeneralUtility::makeInstance(SchemaParser::class) : $schemaParser; |
195
|
|
|
|
196
|
118 |
|
$this->initializeTimeoutFromConfiguration(); |
197
|
|
|
|
198
|
118 |
|
parent::__construct($host, $port, $path); |
199
|
118 |
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Initializes the timeout from TypoScript when configuration is present. |
203
|
|
|
* |
204
|
|
|
* @return void |
205
|
|
|
*/ |
206
|
118 |
|
protected function initializeTimeoutFromConfiguration() |
207
|
|
|
{ |
208
|
118 |
|
$timeout = $this->configuration->getSolrTimeout(); |
209
|
118 |
|
if ($timeout > 0) { |
210
|
1 |
|
$this->getHttpTransport()->setDefaultTimeout($timeout); |
211
|
|
|
} |
212
|
118 |
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Creates a string representation of the Solr connection. Specifically |
216
|
|
|
* will return the Solr URL. |
217
|
|
|
* |
218
|
|
|
* @return string The Solr URL. |
219
|
|
|
*/ |
220
|
66 |
|
public function __toString() |
221
|
|
|
{ |
222
|
66 |
|
return $this->_scheme . '://' . $this->_host . ':' . $this->_port . $this->_path; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Returns the current time in milliseconds. |
227
|
|
|
* |
228
|
|
|
* @return double |
229
|
|
|
*/ |
230
|
3 |
|
protected function getMilliseconds() |
231
|
|
|
{ |
232
|
3 |
|
return GeneralUtility::milliseconds(); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* Performs a search. |
237
|
|
|
* |
238
|
|
|
* @param string $query query string / search term |
239
|
|
|
* @param int $offset result offset for pagination |
240
|
|
|
* @param int $limit number of results to retrieve |
241
|
|
|
* @param array $params additional HTTP GET parameters |
242
|
|
|
* @param string $method The HTTP method (Apache_Solr_Service::METHOD_GET or Apache_Solr_Service::METHOD::POST) |
243
|
|
|
* @return \Apache_Solr_Response Solr response |
244
|
|
|
* @throws \RuntimeException if Solr returns a HTTP status code other than 200 |
245
|
|
|
*/ |
246
|
37 |
|
public function search($query, $offset = 0, $limit = 10, $params = [], $method = self::METHOD_GET) |
247
|
|
|
{ |
248
|
37 |
|
$response = parent::search($query, $offset, $limit, $params, $method); |
249
|
37 |
|
$this->hasSearched = true; |
250
|
|
|
|
251
|
37 |
|
$this->responseCache = $response; |
252
|
|
|
|
253
|
37 |
|
$status = $response->getHttpStatus(); |
254
|
37 |
|
$isValidResponse = $status === 200; |
255
|
37 |
|
if ($isValidResponse) { |
256
|
34 |
|
return $response; |
257
|
|
|
} |
258
|
|
|
|
259
|
3 |
|
$this->handleErrorResponses($response); |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* This method maps the failed solr requests to a meaningful exception. |
264
|
|
|
* |
265
|
|
|
* @param \Apache_Solr_Response $response |
266
|
|
|
* @throws SolrCommunicationException |
267
|
|
|
* @return \Apache_Solr_Response |
268
|
|
|
*/ |
269
|
3 |
|
protected function handleErrorResponses(\Apache_Solr_Response $response) |
270
|
|
|
{ |
271
|
3 |
|
$status = $response->getHttpStatus(); |
272
|
3 |
|
$message = $response->getHttpStatusMessage(); |
273
|
|
|
|
274
|
3 |
|
if ($status === 0) { |
275
|
2 |
|
$e = new SolrUnavailableException('Solr Server not available: ' . $message, 1505989391); |
276
|
2 |
|
$e->setSolrResponse($response); |
277
|
2 |
|
throw $e; |
278
|
|
|
} |
279
|
|
|
|
280
|
1 |
|
if ($status === 500) { |
281
|
1 |
|
$e = new SolrInternalServerErrorException('Internal Server error during search: ' . $message, 1505989897); |
282
|
1 |
|
$e->setSolrResponse($response); |
283
|
1 |
|
throw $e; |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
$e = new SolrCommunicationException('Invalid query. Solr returned an error: ' . $status . ' ' . $message, 1293109870); |
287
|
|
|
$e->setSolrResponse($response); |
288
|
|
|
|
289
|
|
|
throw $e; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Call the /admin/ping servlet, can be used to quickly tell if a connection to the |
294
|
|
|
* server is available. |
295
|
|
|
* |
296
|
|
|
* Simply overrides the SolrPhpClient implementation, changing ping from a |
297
|
|
|
* HEAD to a GET request, see http://forge.typo3.org/issues/44167 |
298
|
|
|
* |
299
|
|
|
* Also does not report the time, see https://forge.typo3.org/issues/64551 |
300
|
|
|
* |
301
|
|
|
* @param int $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2) |
302
|
|
|
* @param boolean $useCache indicates if the ping result should be cached in the instance or not |
303
|
|
|
* @return bool TRUE if Solr can be reached, FALSE if not |
304
|
|
|
*/ |
305
|
61 |
|
public function ping($timeout = 2, $useCache = true) |
306
|
|
|
{ |
307
|
61 |
|
$httpResponse = $this->performPingRequest($timeout, $useCache); |
308
|
61 |
|
return ($httpResponse->getStatusCode() === 200); |
|
|
|
|
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* Call the /admin/ping servlet, can be used to get the runtime of a ping request. |
313
|
|
|
* |
314
|
|
|
* @param int $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2) |
315
|
|
|
* @param boolean $useCache indicates if the ping result should be cached in the instance or not |
316
|
|
|
* @return double runtime in milliseconds |
317
|
|
|
* @throws \ApacheSolrForTypo3\Solr\PingFailedException |
318
|
|
|
*/ |
319
|
3 |
|
public function getPingRoundTripRuntime($timeout = 2, $useCache = true) |
320
|
|
|
{ |
321
|
3 |
|
$start = $this->getMilliseconds(); |
322
|
3 |
|
$httpResponse = $this->performPingRequest($timeout, $useCache); |
323
|
3 |
|
$end = $this->getMilliseconds(); |
324
|
|
|
|
325
|
3 |
|
if ($httpResponse->getStatusCode() !== 200) { |
326
|
1 |
|
$message = 'Solr ping failed with unexpected response code: ' . $httpResponse->getStatusCode(); |
327
|
|
|
/** @var $exception \ApacheSolrForTypo3\Solr\PingFailedException */ |
328
|
1 |
|
$exception = GeneralUtility::makeInstance(PingFailedException::class, $message); |
329
|
1 |
|
$exception->setHttpResponse($httpResponse); |
330
|
1 |
|
throw $exception; |
331
|
|
|
} |
332
|
|
|
|
333
|
2 |
|
return $end - $start; |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Performs a ping request and returns the result. |
338
|
|
|
* |
339
|
|
|
* @param int $timeout |
340
|
|
|
* @param boolean $useCache indicates if the ping result should be cached in the instance or not |
341
|
|
|
* @return \Apache_Solr_HttpTransport_Response |
342
|
|
|
*/ |
343
|
64 |
|
protected function performPingRequest($timeout = 2, $useCache = true) |
344
|
|
|
{ |
345
|
64 |
|
$cacheKey = (string)($this); |
346
|
64 |
|
if ($useCache && isset(static::$pingCache[$cacheKey])) { |
347
|
53 |
|
return static::$pingCache[$cacheKey]; |
348
|
|
|
} |
349
|
|
|
|
350
|
64 |
|
$pingResult = $this->getHttpTransport()->performGetRequest($this->_pingUrl, $timeout); |
351
|
|
|
|
352
|
64 |
|
if ($useCache) { |
353
|
63 |
|
static::$pingCache[$cacheKey] = $pingResult; |
354
|
|
|
} |
355
|
|
|
|
356
|
64 |
|
return $pingResult; |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* Performs a content and meta data extraction request. |
361
|
|
|
* |
362
|
|
|
* @param ExtractingQuery $query An extraction query |
363
|
|
|
* @return array An array containing the extracted content [0] and meta data [1] |
364
|
|
|
*/ |
365
|
1 |
|
public function extractByQuery(ExtractingQuery $query) |
366
|
|
|
{ |
367
|
|
|
$headers = [ |
368
|
1 |
|
'Content-Type' => 'multipart/form-data; boundary=' . $query->getMultiPartPostDataBoundary() |
369
|
|
|
]; |
370
|
|
|
|
371
|
|
|
try { |
372
|
1 |
|
$response = $this->requestServlet( |
373
|
1 |
|
self::EXTRACT_SERVLET, |
374
|
1 |
|
$query->getQueryParameters(), |
375
|
1 |
|
'POST', |
376
|
1 |
|
$headers, |
377
|
1 |
|
$query->getRawPostFileData() |
378
|
|
|
); |
379
|
|
|
} catch (\Exception $e) { |
380
|
|
|
$this->logger->log( |
381
|
|
|
SolrLogManager::ERROR, |
382
|
|
|
'Extracting text and meta data through Solr Cell over HTTP POST', |
383
|
|
|
[ |
384
|
|
|
'query' => (array)$query, |
385
|
|
|
'parameters' => $query->getQueryParameters(), |
386
|
|
|
'file' => $query->getFile(), |
387
|
|
|
'headers' => $headers, |
388
|
|
|
'query url' => self::EXTRACT_SERVLET, |
389
|
|
|
'exception' => $e->getMessage() |
390
|
|
|
] |
391
|
|
|
); |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
return [ |
395
|
1 |
|
$response->extracted, |
396
|
1 |
|
(array)$response->extracted_metadata |
397
|
|
|
]; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* Make a request to a servlet (a path) that's not a standard path. |
402
|
|
|
* |
403
|
|
|
* @param string $servlet Path to be added to the base Solr path. |
404
|
|
|
* @param array $parameters Optional, additional request parameters when constructing the URL. |
405
|
|
|
* @param string $method HTTP method to use, defaults to GET. |
406
|
|
|
* @param array $requestHeaders Key value pairs of header names and values. Should include 'Content-Type' for POST and PUT. |
407
|
|
|
* @param string $rawPost Must be an empty string unless method is POST or PUT. |
408
|
|
|
* @param float|bool $timeout Read timeout in seconds, defaults to FALSE. |
409
|
|
|
* @return \Apache_Solr_Response Response object |
410
|
|
|
* @throws \Apache_Solr_HttpTransportException if returned HTTP status is other than 200 |
411
|
|
|
*/ |
412
|
1 |
|
public function requestServlet($servlet, $parameters = [], $method = 'GET', $requestHeaders = [], $rawPost = '', $timeout = false) |
413
|
|
|
{ |
414
|
|
|
// Add default parameters |
415
|
1 |
|
$parameters['wt'] = self::SOLR_WRITER; |
416
|
1 |
|
$parameters['json.nl'] = $this->_namedListTreatment; |
417
|
1 |
|
$url = $this->_constructUrl($servlet, $parameters); |
418
|
|
|
|
419
|
1 |
|
$httpResponse = $this->getResponseFromTransport($url, $method, $requestHeaders, $rawPost, $timeout); |
420
|
1 |
|
$solrResponse = new \Apache_Solr_Response($httpResponse, $this->_createDocuments, $this->_collapseSingleValueArrays); |
421
|
1 |
|
if ($solrResponse->getHttpStatus() != 200) { |
422
|
|
|
throw new \Apache_Solr_HttpTransportException($solrResponse); |
423
|
|
|
} |
424
|
|
|
|
425
|
1 |
|
return $solrResponse; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* Decides which transport method to used, depending on the request method and retrieves the response. |
430
|
|
|
* |
431
|
|
|
* @param string $url |
432
|
|
|
* @param string $method |
433
|
|
|
* @param array $requestHeaders |
434
|
|
|
* @param string $rawPost |
435
|
|
|
* @param float|bool $timeout |
436
|
|
|
* @return \Apache_Solr_HttpTransport_Response |
437
|
|
|
*/ |
438
|
1 |
|
protected function getResponseFromTransport($url, $method, $requestHeaders, $rawPost, $timeout) |
439
|
|
|
{ |
440
|
1 |
|
$httpTransport = $this->getHttpTransport(); |
441
|
|
|
|
442
|
1 |
|
if ($method == self::METHOD_GET) { |
443
|
|
|
return $httpTransport->performGetRequest($url, $timeout); |
444
|
|
|
} |
445
|
1 |
|
if ($method == self::METHOD_POST) { |
446
|
|
|
// FIXME should respect all headers, not only Content-Type |
447
|
1 |
|
return $httpTransport->performPostRequest($url, $rawPost, $requestHeaders['Content-Type'], $timeout); |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
throw new \InvalidArgumentException('$method should be GET or POST'); |
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
/** |
454
|
|
|
* Return a valid http URL given this server's scheme, host, port, and path |
455
|
|
|
* and a provided servlet name. |
456
|
|
|
* |
457
|
|
|
* @param string $servlet Servlet name |
458
|
|
|
* @param array $params Additional URL parameters to attach to the end of the URL |
459
|
|
|
* @return string Servlet URL |
460
|
|
|
*/ |
461
|
118 |
|
protected function _constructUrl($servlet, $params = []) |
462
|
|
|
{ |
463
|
118 |
|
$url = parent::_constructUrl($servlet, $params); |
464
|
|
|
|
465
|
118 |
|
if (!GeneralUtility::isFirstPartOfStr($url, $this->_scheme)) { |
466
|
2 |
|
$parsedUrl = parse_url($url); |
467
|
|
|
|
468
|
|
|
// unfortunately can't use str_replace as it replace all |
469
|
|
|
// occurrences of $needle and can't be limited to replace only once |
470
|
2 |
|
$url = $this->_scheme . substr($url, strlen($parsedUrl['scheme'])); |
471
|
|
|
} |
472
|
|
|
|
473
|
118 |
|
return $url; |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* Returns the set scheme |
478
|
|
|
* |
479
|
|
|
* @return string |
480
|
|
|
*/ |
481
|
3 |
|
public function getScheme() |
482
|
|
|
{ |
483
|
3 |
|
return $this->_scheme; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* Set the scheme used. If empty will fallback to constants |
488
|
|
|
* |
489
|
|
|
* @param string $scheme Either http or https |
490
|
|
|
* @throws \UnexpectedValueException |
491
|
|
|
*/ |
492
|
119 |
|
public function setScheme($scheme) |
493
|
|
|
{ |
494
|
|
|
// Use the provided scheme or use the default |
495
|
119 |
|
if (empty($scheme)) { |
496
|
2 |
|
throw new \UnexpectedValueException('Scheme parameter is empty', 1380756390); |
497
|
|
|
} |
498
|
|
|
|
499
|
118 |
|
$isHttpOrHttps = in_array($scheme, [self::SCHEME_HTTP, self::SCHEME_HTTPS]); |
500
|
118 |
|
if (!$isHttpOrHttps) { |
501
|
1 |
|
throw new \UnexpectedValueException('Unsupported scheme parameter, scheme must be http or https', 1380756442); |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
// we have a valid scheme |
505
|
118 |
|
$this->_scheme = $scheme; |
506
|
|
|
|
507
|
118 |
|
if ($this->_urlsInited) { |
508
|
1 |
|
$this->_initUrls(); |
509
|
|
|
} |
510
|
118 |
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* get field meta data for the index |
514
|
|
|
* |
515
|
|
|
* @param int $numberOfTerms Number of top terms to fetch for each field |
516
|
|
|
* @return array |
517
|
|
|
*/ |
518
|
|
|
public function getFieldsMetaData($numberOfTerms = 0) |
519
|
|
|
{ |
520
|
|
|
return $this->getLukeMetaData($numberOfTerms)->fields; |
521
|
|
|
} |
522
|
|
|
|
523
|
|
|
/** |
524
|
|
|
* Retrieves meta data about the index from the luke request handler |
525
|
|
|
* |
526
|
|
|
* @param int $numberOfTerms Number of top terms to fetch for each field |
527
|
|
|
* @return \Apache_Solr_Response Index meta data |
528
|
|
|
*/ |
529
|
|
|
public function getLukeMetaData($numberOfTerms = 0) |
530
|
|
|
{ |
531
|
|
|
if (!isset($this->lukeData[$numberOfTerms])) { |
532
|
|
|
$lukeUrl = $this->_constructUrl( |
533
|
|
|
self::LUKE_SERVLET, |
534
|
|
|
[ |
535
|
|
|
'numTerms' => $numberOfTerms, |
536
|
|
|
'wt' => self::SOLR_WRITER, |
537
|
|
|
'fl' => '*' |
538
|
|
|
] |
539
|
|
|
); |
540
|
|
|
|
541
|
|
|
$this->lukeData[$numberOfTerms] = $this->_sendRawGet($lukeUrl); |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
return $this->lukeData[$numberOfTerms]; |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
/** |
548
|
|
|
* Central method for making a get operation against this Solr Server |
549
|
|
|
* |
550
|
|
|
* @param string $url |
551
|
|
|
* @param float|bool $timeout Read timeout in seconds |
552
|
|
|
* @return \Apache_Solr_Response |
553
|
|
|
*/ |
554
|
51 |
|
protected function _sendRawGet($url, $timeout = false) |
555
|
|
|
{ |
556
|
51 |
|
$logSeverity = SolrLogManager::INFO; |
557
|
51 |
|
$exception = null; |
558
|
|
|
|
559
|
|
|
try { |
560
|
51 |
|
$response = parent::_sendRawGet($url, $timeout); |
|
|
|
|
561
|
6 |
|
} catch (\Apache_Solr_HttpTransportException $exception) { |
562
|
6 |
|
$logSeverity = SolrLogManager::ERROR; |
563
|
6 |
|
$response = $exception->getResponse(); |
564
|
|
|
} |
565
|
|
|
|
566
|
51 |
|
if ($this->configuration->getLoggingQueryRawGet() || $response->getHttpStatus() != 200) { |
567
|
6 |
|
$this->writeLog($logSeverity, 'Querying Solr using GET', $url, $response, $exception); |
568
|
|
|
} |
569
|
|
|
|
570
|
51 |
|
return $response; |
571
|
|
|
} |
572
|
|
|
|
573
|
|
|
/** |
574
|
|
|
* Returns whether a search has been executed or not. |
575
|
|
|
* |
576
|
|
|
* @return bool TRUE if a search has been executed, FALSE otherwise |
577
|
|
|
*/ |
578
|
|
|
public function hasSearched() |
579
|
|
|
{ |
580
|
|
|
return $this->hasSearched; |
581
|
|
|
} |
582
|
|
|
|
583
|
|
|
/** |
584
|
|
|
* Gets the most recent response (if any) |
585
|
|
|
* |
586
|
|
|
* @return \Apache_Solr_Response Most recent response, or NULL if a search has not been executed yet. |
587
|
|
|
*/ |
588
|
|
|
public function getResponse() |
589
|
|
|
{ |
590
|
|
|
return $this->responseCache; |
591
|
|
|
} |
592
|
|
|
|
593
|
|
|
/** |
594
|
|
|
* Enable/Disable debug mode |
595
|
|
|
* |
596
|
|
|
* @param bool $debug TRUE to enable debug mode, FALSE to turn off, off by default |
597
|
|
|
*/ |
598
|
|
|
public function setDebug($debug) |
599
|
|
|
{ |
600
|
|
|
$this->debug = (boolean)$debug; |
601
|
|
|
} |
602
|
|
|
|
603
|
|
|
/** |
604
|
|
|
* Gets information about the plugins installed in Solr |
605
|
|
|
* |
606
|
|
|
* @return array A nested array of plugin data. |
607
|
|
|
*/ |
608
|
3 |
|
public function getPluginsInformation() |
609
|
|
|
{ |
610
|
3 |
|
if (empty($this->pluginsData)) { |
611
|
3 |
|
$pluginsInformation = $this->_sendRawGet($this->_pluginsUrl); |
612
|
|
|
|
613
|
|
|
// access a random property to trigger response parsing |
614
|
3 |
|
$pluginsInformation->responseHeader; |
615
|
2 |
|
$this->pluginsData = $pluginsInformation; |
616
|
|
|
} |
617
|
|
|
|
618
|
2 |
|
return $this->pluginsData; |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* Gets information about the Solr server |
623
|
|
|
* |
624
|
|
|
* @return array A nested array of system data. |
625
|
|
|
*/ |
626
|
5 |
|
public function getSystemInformation() |
627
|
|
|
{ |
628
|
5 |
|
if (empty($this->systemData)) { |
629
|
5 |
|
$systemInformation = $this->system(); |
630
|
|
|
|
631
|
|
|
// access a random property to trigger response parsing |
632
|
5 |
|
$systemInformation->responseHeader; |
633
|
4 |
|
$this->systemData = $systemInformation; |
634
|
|
|
} |
635
|
|
|
|
636
|
4 |
|
return $this->systemData; |
637
|
|
|
} |
638
|
|
|
|
639
|
|
|
/** |
640
|
|
|
* Gets the name of the solrconfig.xml file installed and in use on the Solr |
641
|
|
|
* server. |
642
|
|
|
* |
643
|
|
|
* @return string Name of the active solrconfig.xml |
644
|
|
|
*/ |
645
|
3 |
|
public function getSolrconfigName() |
646
|
|
|
{ |
647
|
3 |
|
if (is_null($this->solrconfigName)) { |
648
|
3 |
|
$solrconfigXmlUrl = $this->_scheme . '://' |
649
|
3 |
|
. $this->_host . ':' . $this->_port |
650
|
3 |
|
. $this->_path . 'admin/file/?file=solrconfig.xml'; |
651
|
3 |
|
$response = $this->_sendRawGet($solrconfigXmlUrl); |
652
|
|
|
|
653
|
3 |
|
$solrconfigXml = simplexml_load_string($response->getRawResponse()); |
654
|
3 |
|
if ($solrconfigXml === false) { |
655
|
1 |
|
throw new \InvalidArgumentException('No valid xml response from schema file: ' . $solrconfigXmlUrl); |
656
|
|
|
} |
657
|
2 |
|
$this->solrconfigName = (string)$solrconfigXml->attributes()->name; |
658
|
|
|
} |
659
|
|
|
|
660
|
2 |
|
return $this->solrconfigName; |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
/** |
664
|
|
|
* Gets the Solr server's version number. |
665
|
|
|
* |
666
|
|
|
* @return string Solr version number |
667
|
|
|
*/ |
668
|
4 |
|
public function getSolrServerVersion() |
669
|
|
|
{ |
670
|
4 |
|
$systemInformation = $this->getSystemInformation(); |
671
|
|
|
|
672
|
|
|
// don't know why $systemInformation->lucene->solr-spec-version won't work |
673
|
3 |
|
$luceneInformation = (array)$systemInformation->lucene; |
674
|
3 |
|
return $luceneInformation['solr-spec-version']; |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
/** |
678
|
|
|
* Deletes all index documents of a certain type and does a commit |
679
|
|
|
* afterwards. |
680
|
|
|
* |
681
|
|
|
* @param string $type The type of documents to delete, usually a table name. |
682
|
|
|
* @param bool $commit Will commit immediately after deleting the documents if set, defaults to TRUE |
683
|
|
|
*/ |
684
|
|
|
public function deleteByType($type, $commit = true) |
685
|
|
|
{ |
686
|
|
|
$this->deleteByQuery('type:' . trim($type)); |
687
|
|
|
|
688
|
|
|
if ($commit) { |
689
|
|
|
$this->commit(false, false, false); |
690
|
|
|
} |
691
|
|
|
} |
692
|
|
|
|
693
|
|
|
/** |
694
|
|
|
* Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be |
695
|
|
|
* a complete and well formed "delete" xml document |
696
|
|
|
* |
697
|
|
|
* @param string $rawPost Expected to be utf-8 encoded xml document |
698
|
|
|
* @param float|int $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception) |
699
|
|
|
* @return \Apache_Solr_Response |
700
|
|
|
*/ |
701
|
11 |
|
public function delete($rawPost, $timeout = 3600) |
702
|
|
|
{ |
703
|
11 |
|
$response = $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout); |
704
|
|
|
|
705
|
11 |
|
$this->logger->log( |
706
|
11 |
|
SolrLogManager::NOTICE, |
707
|
11 |
|
'Delete Query sent.', |
708
|
|
|
[ |
709
|
11 |
|
'query' => $rawPost, |
710
|
11 |
|
'query url' => $this->_updateUrl, |
711
|
11 |
|
'response' => (array)$response |
712
|
|
|
] |
713
|
|
|
); |
714
|
|
|
|
715
|
11 |
|
return $response; |
716
|
|
|
} |
717
|
|
|
|
718
|
|
|
/** |
719
|
|
|
* Central method for making a post operation against this Solr Server |
720
|
|
|
* |
721
|
|
|
* @param string $url |
722
|
|
|
* @param string $rawPost |
723
|
|
|
* @param float|bool $timeout Read timeout in seconds |
724
|
|
|
* @param string $contentType |
725
|
|
|
* @return \Apache_Solr_Response |
726
|
|
|
*/ |
727
|
83 |
|
protected function _sendRawPost($url, $rawPost, $timeout = false, $contentType = 'text/xml; charset=UTF-8') |
728
|
|
|
{ |
729
|
83 |
|
$logSeverity = SolrLogManager::INFO; |
730
|
83 |
|
$exception = null; |
731
|
|
|
|
732
|
|
|
try { |
733
|
83 |
|
$response = parent::_sendRawPost($url, $rawPost, $timeout, $contentType); |
|
|
|
|
734
|
|
|
} catch (\Apache_Solr_HttpTransportException $exception) { |
735
|
|
|
$logSeverity = SolrLogManager::ERROR; |
736
|
|
|
$response = $exception->getResponse(); |
737
|
|
|
} |
738
|
|
|
|
739
|
83 |
|
if ($this->configuration->getLoggingQueryRawPost() || $response->getHttpStatus() != 200) { |
740
|
|
|
$this->writeLog($logSeverity, 'Querying Solr using POST', $url, $response, $exception, $rawPost); |
741
|
|
|
} |
742
|
|
|
|
743
|
83 |
|
return $response; |
744
|
|
|
} |
745
|
|
|
|
746
|
|
|
/** |
747
|
|
|
* Get currently configured synonyms |
748
|
|
|
* |
749
|
|
|
* @param string $baseWord If given a base word, retrieves the synonyms for that word only |
750
|
|
|
* @return array |
751
|
|
|
*/ |
752
|
2 |
|
public function getSynonyms($baseWord = '') |
753
|
|
|
{ |
754
|
2 |
|
$this->initializeSynonymsUrl(); |
755
|
2 |
|
$synonymsUrl = $this->_synonymsUrl; |
756
|
2 |
|
if (!empty($baseWord)) { |
757
|
2 |
|
$synonymsUrl .= '/' . $baseWord; |
758
|
|
|
} |
759
|
|
|
|
760
|
2 |
|
$response = $this->_sendRawGet($synonymsUrl); |
761
|
2 |
|
return $this->synonymParser->parseJson($baseWord, $response->getRawResponse()); |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
/** |
765
|
|
|
* Add list of synonyms for base word to managed synonyms map |
766
|
|
|
* |
767
|
|
|
* @param string $baseWord |
768
|
|
|
* @param array $synonyms |
769
|
|
|
* |
770
|
|
|
* @return \Apache_Solr_Response |
771
|
|
|
* |
772
|
|
|
* @throws \Apache_Solr_InvalidArgumentException If $baseWord or $synonyms are empty |
773
|
|
|
*/ |
774
|
2 |
|
public function addSynonym($baseWord, array $synonyms) |
775
|
|
|
{ |
776
|
2 |
|
$this->initializeSynonymsUrl(); |
777
|
2 |
|
$json = $this->synonymParser->toJson($baseWord, $synonyms); |
778
|
2 |
|
return $this->_sendRawPost($this->_synonymsUrl, $json, |
779
|
2 |
|
$this->getHttpTransport()->getDefaultTimeout(), 'application/json'); |
780
|
|
|
} |
781
|
|
|
|
782
|
|
|
/** |
783
|
|
|
* Remove a synonym from the synonyms map |
784
|
|
|
* |
785
|
|
|
* @param string $baseWord |
786
|
|
|
* @return \Apache_Solr_Response |
787
|
|
|
* @throws \Apache_Solr_InvalidArgumentException |
788
|
|
|
*/ |
789
|
2 |
|
public function deleteSynonym($baseWord) |
790
|
|
|
{ |
791
|
2 |
|
$this->initializeSynonymsUrl(); |
792
|
2 |
|
if (empty($baseWord)) { |
793
|
|
|
throw new \Apache_Solr_InvalidArgumentException('Must provide base word.'); |
794
|
|
|
} |
795
|
|
|
|
796
|
2 |
|
return $this->_sendRawDelete($this->_synonymsUrl . '/' . urlencode($baseWord)); |
797
|
|
|
} |
798
|
|
|
|
799
|
|
|
/** |
800
|
|
|
* Central method for making a HTTP DELETE operation against the Solr server |
801
|
|
|
* |
802
|
|
|
* @param string $url |
803
|
|
|
* @param bool|float $timeout Read timeout in seconds |
804
|
|
|
* @return \Apache_Solr_Response |
805
|
|
|
*/ |
806
|
4 |
|
protected function _sendRawDelete($url, $timeout = false) |
807
|
|
|
{ |
808
|
4 |
|
$logSeverity = SolrLogManager::INFO; |
809
|
4 |
|
$exception = null; |
810
|
|
|
|
811
|
|
|
try { |
812
|
4 |
|
$httpTransport = $this->getHttpTransport(); |
813
|
4 |
|
$httpResponse = $httpTransport->performDeleteRequest($url, $timeout); |
814
|
4 |
|
$solrResponse = new \Apache_Solr_Response($httpResponse, $this->_createDocuments, $this->_collapseSingleValueArrays); |
815
|
|
|
|
816
|
4 |
|
if ($solrResponse->getHttpStatus() != 200) { |
817
|
4 |
|
throw new \Apache_Solr_HttpTransportException($solrResponse); |
818
|
|
|
} |
819
|
4 |
|
} catch (\Apache_Solr_HttpTransportException $exception) { |
820
|
4 |
|
$logSeverity = SolrLogManager::ERROR; |
821
|
4 |
|
$solrResponse = $exception->getResponse(); |
822
|
|
|
} |
823
|
|
|
|
824
|
4 |
|
if ($this->configuration->getLoggingQueryRawDelete() || $solrResponse->getHttpStatus() != 200) { |
825
|
4 |
|
$this->writeLog($logSeverity, 'Querying Solr using DELETE', $url, $solrResponse, $exception); |
826
|
|
|
} |
827
|
|
|
|
828
|
4 |
|
return $solrResponse; |
829
|
|
|
} |
830
|
|
|
|
831
|
|
|
/** |
832
|
|
|
* Build the log data and writes the message to the log |
833
|
|
|
* |
834
|
|
|
* @param integer $logSeverity |
835
|
|
|
* @param string $message |
836
|
|
|
* @param string $url |
837
|
|
|
* @param \Apache_Solr_Response $solrResponse |
838
|
|
|
* @param \Exception $exception |
839
|
|
|
* @param string $contentSend |
840
|
|
|
*/ |
841
|
8 |
|
protected function writeLog($logSeverity, $message, $url, $solrResponse, $exception = null, $contentSend = '') |
842
|
|
|
{ |
843
|
8 |
|
$logData = $this->buildLogDataFromResponse($solrResponse, $exception, $url, $contentSend); |
844
|
8 |
|
$this->logger->log($logSeverity, $message, $logData); |
845
|
8 |
|
} |
846
|
|
|
|
847
|
|
|
/** |
848
|
|
|
* Parses the solr information to build data for the logger. |
849
|
|
|
* |
850
|
|
|
* @param \Apache_Solr_Response $solrResponse |
851
|
|
|
* @param \Exception $e |
852
|
|
|
* @param string $url |
853
|
|
|
* @param string $contentSend |
854
|
|
|
* @return array |
855
|
|
|
*/ |
856
|
8 |
|
protected function buildLogDataFromResponse(\Apache_Solr_Response $solrResponse, \Exception $e = null, $url = '', $contentSend = '') |
857
|
|
|
{ |
858
|
8 |
|
$logData = ['query url' => $url, 'response' => (array)$solrResponse]; |
859
|
|
|
|
860
|
8 |
|
if ($contentSend !== '') { |
861
|
|
|
$logData['content'] = $contentSend; |
862
|
|
|
} |
863
|
|
|
|
864
|
8 |
|
if (!empty($e)) { |
865
|
8 |
|
$logData['exception'] = $e->__toString(); |
866
|
8 |
|
return $logData; |
867
|
|
|
} else { |
868
|
|
|
// trigger data parsing |
869
|
|
|
$solrResponse->response; |
|
|
|
|
870
|
|
|
$logData['response data'] = print_r($solrResponse, true); |
871
|
|
|
return $logData; |
872
|
|
|
} |
873
|
|
|
} |
874
|
|
|
|
875
|
|
|
/** |
876
|
|
|
* Get currently configured stop words |
877
|
|
|
* |
878
|
|
|
* @return array |
879
|
|
|
*/ |
880
|
3 |
|
public function getStopWords() |
881
|
|
|
{ |
882
|
3 |
|
$this->initializeStopWordsUrl(); |
883
|
3 |
|
$response = $this->_sendRawGet($this->_stopWordsUrl); |
884
|
3 |
|
return $this->stopWordParser->parseJson($response->getRawResponse()); |
885
|
|
|
} |
886
|
|
|
|
887
|
|
|
/** |
888
|
|
|
* Adds stop words to the managed stop word list |
889
|
|
|
* |
890
|
|
|
* @param array|string $stopWords string for a single word, array for multiple words |
891
|
|
|
* @return \Apache_Solr_Response |
892
|
|
|
* @throws \Apache_Solr_InvalidArgumentException If $stopWords is empty |
893
|
|
|
*/ |
894
|
2 |
|
public function addStopWords($stopWords) |
895
|
|
|
{ |
896
|
2 |
|
$this->initializeStopWordsUrl(); |
897
|
2 |
|
$json = $this->stopWordParser->toJson($stopWords); |
898
|
2 |
|
return $this->_sendRawPost($this->_stopWordsUrl, $json, |
899
|
2 |
|
$this->getHttpTransport()->getDefaultTimeout(), 'application/json'); |
900
|
|
|
} |
901
|
|
|
|
902
|
|
|
/** |
903
|
|
|
* Deletes a words from the managed stop word list |
904
|
|
|
* |
905
|
|
|
* @param string $stopWord stop word to delete |
906
|
|
|
* @return \Apache_Solr_Response |
907
|
|
|
* @throws \Apache_Solr_InvalidArgumentException If $stopWords is empty |
908
|
|
|
*/ |
909
|
2 |
|
public function deleteStopWord($stopWord) |
910
|
|
|
{ |
911
|
2 |
|
$this->initializeStopWordsUrl(); |
912
|
2 |
|
if (empty($stopWord)) { |
913
|
|
|
throw new \Apache_Solr_InvalidArgumentException('Must provide stop word.'); |
914
|
|
|
} |
915
|
|
|
|
916
|
2 |
|
return $this->_sendRawDelete($this->_stopWordsUrl . '/' . urlencode($stopWord)); |
917
|
|
|
} |
918
|
|
|
|
919
|
|
|
/** |
920
|
|
|
* Returns the core name from the configured path. |
921
|
|
|
* |
922
|
|
|
* @return string |
923
|
|
|
*/ |
924
|
3 |
|
public function getCoreName() |
925
|
|
|
{ |
926
|
3 |
|
$paths = explode('/', trim($this->_path, '/')); |
927
|
|
|
|
928
|
3 |
|
return (string)array_pop($paths); |
929
|
|
|
} |
930
|
|
|
|
931
|
|
|
/** |
932
|
|
|
* Returns the core name from the configured path without the core name. |
933
|
|
|
* |
934
|
|
|
* @return string |
935
|
|
|
*/ |
936
|
118 |
|
public function getCoreBasePath() |
937
|
|
|
{ |
938
|
118 |
|
$pathWithoutLeadingAndTrailingSlashes = trim(trim($this->_path), "/"); |
939
|
118 |
|
$pathWithoutLastSegment = substr($pathWithoutLeadingAndTrailingSlashes, 0, strrpos($pathWithoutLeadingAndTrailingSlashes, "/")); |
940
|
118 |
|
return '/' . $pathWithoutLastSegment . '/'; |
941
|
|
|
} |
942
|
|
|
|
943
|
|
|
/** |
944
|
|
|
* Reloads the current core |
945
|
|
|
* |
946
|
|
|
* @return \Apache_Solr_Response |
947
|
|
|
*/ |
948
|
1 |
|
public function reloadCore() |
949
|
|
|
{ |
950
|
1 |
|
return $this->reloadCoreByName($this->getCoreName()); |
951
|
|
|
} |
952
|
|
|
|
953
|
|
|
/** |
954
|
|
|
* Reloads a core of the connection by a given corename. |
955
|
|
|
* |
956
|
|
|
* @param string $coreName |
957
|
|
|
* @return \Apache_Solr_Response |
958
|
|
|
*/ |
959
|
1 |
|
public function reloadCoreByName($coreName) |
960
|
|
|
{ |
961
|
1 |
|
$coreAdminReloadUrl = $this->_coresUrl . '?action=reload&core=' . $coreName; |
962
|
1 |
|
return $this->_sendRawGet($coreAdminReloadUrl); |
963
|
|
|
} |
964
|
|
|
|
965
|
|
|
/** |
966
|
|
|
* initializes various URLs, including the Luke URL |
967
|
|
|
* |
968
|
|
|
* @return void |
969
|
|
|
*/ |
970
|
118 |
|
protected function _initUrls() |
971
|
|
|
{ |
972
|
118 |
|
parent::_initUrls(); |
973
|
|
|
|
974
|
118 |
|
$this->_lukeUrl = $this->_constructUrl( |
975
|
118 |
|
self::LUKE_SERVLET, |
976
|
|
|
[ |
977
|
118 |
|
'numTerms' => '0', |
978
|
118 |
|
'wt' => self::SOLR_WRITER |
979
|
|
|
] |
980
|
|
|
); |
981
|
|
|
|
982
|
118 |
|
$this->_pluginsUrl = $this->_constructUrl( |
983
|
118 |
|
self::PLUGINS_SERVLET, |
984
|
118 |
|
['wt' => self::SOLR_WRITER] |
985
|
|
|
); |
986
|
|
|
|
987
|
118 |
|
$this->_coresUrl = |
988
|
118 |
|
$this->_scheme . '://' . |
989
|
118 |
|
$this->_host . ':' . |
990
|
118 |
|
$this->_port . |
991
|
118 |
|
$this->getCoreBasePath() . |
992
|
118 |
|
self::CORES_SERVLET; |
993
|
|
|
|
994
|
118 |
|
$this->_schemaUrl = $this->_constructUrl(self::SCHEMA_SERVLET); |
995
|
118 |
|
} |
996
|
|
|
|
997
|
|
|
/** |
998
|
|
|
* @return void |
999
|
|
|
*/ |
1000
|
2 |
|
protected function initializeSynonymsUrl() |
1001
|
|
|
{ |
1002
|
2 |
|
if (trim($this->_synonymsUrl) !== '') { |
1003
|
2 |
|
return; |
1004
|
|
|
} |
1005
|
2 |
|
$this->_synonymsUrl = $this->_constructUrl(self::SYNONYMS_SERVLET) . $this->getSchema()->getLanguage(); |
1006
|
2 |
|
} |
1007
|
|
|
|
1008
|
|
|
/** |
1009
|
|
|
* @return void |
1010
|
|
|
*/ |
1011
|
3 |
|
protected function initializeStopWordsUrl() |
1012
|
|
|
{ |
1013
|
3 |
|
if (trim($this->_stopWordsUrl) !== '') { |
1014
|
2 |
|
return; |
1015
|
|
|
} |
1016
|
|
|
|
1017
|
3 |
|
$this->_stopWordsUrl = $this->_constructUrl(self::STOPWORDS_SERVLET) . $this->getSchema()->getLanguage(); |
1018
|
3 |
|
} |
1019
|
|
|
|
1020
|
|
|
/** |
1021
|
|
|
* Get the configured schema for the current core. |
1022
|
|
|
* |
1023
|
|
|
* @return Schema |
1024
|
|
|
*/ |
1025
|
8 |
|
public function getSchema() |
1026
|
|
|
{ |
1027
|
8 |
|
if ($this->schema !== null) { |
1028
|
|
|
return $this->schema; |
1029
|
|
|
} |
1030
|
8 |
|
$response = $this->_sendRawGet($this->_schemaUrl); |
1031
|
8 |
|
$this->schema = $this->schemaParser->parseJson($response->getRawResponse()); |
1032
|
8 |
|
return $this->schema; |
1033
|
|
|
} |
1034
|
|
|
} |
1035
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.