Passed
Pull Request — master (#1148)
by
unknown
32:02
created

SolrService::getResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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