Completed
Branch master (b9fc31)
by Timo
05:19
created

SolrService::getSystemInformation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 0
crap 2
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\Solr\Parser\SchemaParser;
29
use ApacheSolrForTypo3\Solr\System\Solr\Parser\StopWordParser;
30
use ApacheSolrForTypo3\Solr\System\Solr\Parser\SynonymParser;
31
use ApacheSolrForTypo3\Solr\System\Solr\Schema\Schema;
32
use TYPO3\CMS\Core\Utility\GeneralUtility;
33
34
/**
35
 * Solr Service Access
36
 *
37
 * @author Ingo Renner <[email protected]>
38
 */
39
class SolrService extends \Apache_Solr_Service
40
{
41
    const LUKE_SERVLET = 'admin/luke';
42
    const SYSTEM_SERVLET = 'admin/system';
43
    const PLUGINS_SERVLET = 'admin/plugins';
44
    const CORES_SERVLET = 'admin/cores';
45
    const SCHEMA_SERVLET = 'schema';
46
    const SYNONYMS_SERVLET = 'schema/analysis/synonyms/';
47
    const STOPWORDS_SERVLET = 'schema/analysis/stopwords/';
48
49
    const SCHEME_HTTP = 'http';
50
    const SCHEME_HTTPS = 'https';
51
52
    /**
53
     * Server connection scheme. http or https.
54
     *
55
     * @var string
56
     */
57
    protected $_scheme = self::SCHEME_HTTP;
58
59
    /**
60
     * Constructed servlet URL for Luke
61
     *
62
     * @var string
63
     */
64
    protected $_lukeUrl;
65
66
    /**
67
     * Constructed servlet URL for plugin information
68
     *
69
     * @var string
70
     */
71
    protected $_pluginsUrl;
72
73
    /**
74
     * @var string
75
     */
76
    protected $_coresUrl;
77
78
    /**
79
     * @var string
80
     */
81
    protected $_extractUrl;
82
83
    /**
84
     * @var string
85
     */
86
    protected $_synonymsUrl;
87
88
    /**
89
     * @var string
90
     */
91
    protected $_stopWordsUrl;
92
93
    /**
94
     * @var string
95
     */
96
    protected $_schemaUrl;
97
98
    /**
99
     * @var bool
100
     */
101
    protected $debug = false;
102
103
    /**
104
     * @var \Apache_Solr_Response
105
     */
106
    protected $responseCache = null;
107
108
    /**
109
     * @var bool
110
     */
111
    protected $hasSearched = false;
112
113
    /**
114
     * @var array
115
     */
116
    protected $lukeData = [];
117
118
    protected $systemData = null;
119
    protected $pluginsData = null;
120
121
    protected $solrconfigName = null;
122
123
    /**
124
     * @var TypoScriptConfiguration
125
     */
126
    protected $configuration;
127
128
    /**
129
     * @var array
130
     */
131
    protected static $pingCache = [];
132
133
    /**
134
     * @var SynonymParser
135
     */
136
    protected $synonymParser = null;
137
138
    /**
139
     * @var StopWordParser
140
     */
141
    protected $stopWordParser = null;
142
143
    /**
144
     * @var SchemaParser
145
     */
146
    protected $schemaParser = null;
147
148
    /**
149
     * @var Schema
150
     */
151
    protected $schema;
152
153
    /**
154
     * Constructor
155
     *
156
     * @param string $host Solr host
157
     * @param string $port Solr port
158
     * @param string $path Solr path
159
     * @param string $scheme Scheme, defaults to http, can be https
160
     * @param TypoScriptConfiguration $typoScriptConfiguration
161
     * @param SynonymParser $synonymParser
162
     * @param StopWordParser $stopWordParser
163
     * @param SchemaParser $schemaParser
164
     */
165 74
    public function __construct(
166
        $host = '',
167
        $port = '8983',
168
        $path = '/solr/',
169
        $scheme = 'http',
170
        TypoScriptConfiguration $typoScriptConfiguration = null,
171
        SynonymParser $synonymParser = null,
172
        StopWordParser $stopWordParser = null,
173
        SchemaParser $schemaParser = null
174
    ) {
175 74
        $this->setScheme($scheme);
176 73
        $this->configuration = is_null($typoScriptConfiguration) ? Util::getSolrConfiguration() : $typoScriptConfiguration;
177 73
        $this->synonymParser = is_null($synonymParser) ? GeneralUtility::makeInstance(SynonymParser::class) : $synonymParser;
178 73
        $this->stopWordParser = is_null($stopWordParser) ? GeneralUtility::makeInstance(StopWordParser::class) : $stopWordParser;
179 73
        $this->schemaParser = is_null($schemaParser) ? GeneralUtility::makeInstance(SchemaParser::class) : $schemaParser;
180
181 73
        $this->initializeTimeoutFromConfiguration();
182
183 73
        parent::__construct($host, $port, $path);
184 73
    }
185
186
    /**
187
     * Initializes the timeout from TypoScript when configuration is present.
188
     *
189
     * @return void
190
     */
191 73
    protected function initializeTimeoutFromConfiguration()
192
    {
193 73
        $timeout = $this->configuration->getSolrTimeout();
194 73
        if ($timeout > 0) {
195 1
            $this->getHttpTransport()->setDefaultTimeout($timeout);
196 1
        }
197 73
    }
198
199
    /**
200
     * Creates a string representation of the Solr connection. Specifically
201
     * will return the Solr URL.
202
     *
203
     * @return string The Solr URL.
204
     */
205 43
    public function __toString()
206
    {
207 43
        return $this->_scheme . '://' . $this->_host . ':' . $this->_port . $this->_path;
208
    }
209
210
    /**
211
     * Returns the current time in milliseconds.
212
     *
213
     * @return double
214
     */
215 1
    protected function getMilliseconds()
216
    {
217 1
        return GeneralUtility::milliseconds();
218
    }
219
220
    /**
221
     * Performs a search.
222
     *
223
     * @param string $query query string / search term
224
     * @param int $offset result offset for pagination
225
     * @param int $limit number of results to retrieve
226
     * @param array $params additional HTTP GET parameters
227
     * @param string $method The HTTP method (Apache_Solr_Service::METHOD_GET or Apache_Solr_Service::METHOD::POST)
228
     * @return \Apache_Solr_Response Solr response
229
     * @throws \RuntimeException if Solr returns a HTTP status code other than 200
230
     */
231 26
    public function search($query, $offset = 0, $limit = 10, $params = [], $method = self::METHOD_GET)
232
    {
233 26
        $response = parent::search($query, $offset, $limit, $params, $method);
234 26
        $this->hasSearched = true;
235
236 26
        $this->responseCache = $response;
237
238 26
        if ($response->getHttpStatus() != 200) {
239 1
            throw new \RuntimeException(
240
                'Invalid query. Solr returned an error: '
241 1
                . $response->getHttpStatus() . ' '
242 1
                . $response->getHttpStatusMessage(),
243
                1293109870
244 1
            );
245
        }
246
247 25
        return $response;
248
    }
249
250
    /**
251
     * Call the /admin/ping servlet, can be used to quickly tell if a connection to the
252
     * server is available.
253
     *
254
     * Simply overrides the SolrPhpClient implementation, changing ping from a
255
     * HEAD to a GET request, see http://forge.typo3.org/issues/44167
256
     *
257
     * Also does not report the time, see https://forge.typo3.org/issues/64551
258
     *
259
     * @param float|int $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2)
260
     * @param boolean $useCache indicates if the ping result should be cached in the instance or not
261
     * @return bool TRUE if Solr can be reached, FALSE if not
262
     */
263 40
    public function ping($timeout = 2, $useCache = true)
264
    {
265 40
        $httpResponse = $this->performPingRequest($timeout, $useCache);
266 40
        return ($httpResponse->getStatusCode() === 200);
267
    }
268
269
    /**
270
     * Call the /admin/ping servlet, can be used to get the runtime of a ping request.
271
     *
272
     * @param float|int $timeout maximum time to wait for ping in seconds, -1 for unlimited (default is 2)
273
     * @param boolean $useCache indicates if the ping result should be cached in the instance or not
274
     * @return double runtime in milliseconds
275
     * @throws \ApacheSolrForTypo3\Solr\PingFailedException
276
     */
277 1
    public function getPingRoundTripRuntime($timeout = 2, $useCache = true)
278
    {
279 1
        $start = $this->getMilliseconds();
280 1
        $httpResponse = $this->performPingRequest($timeout, $useCache);
281 1
        $end = $this->getMilliseconds();
282
283 1
        if ($httpResponse->getStatusCode() !== 200) {
284
            $message = 'Solr ping failed with unexpected response code: ' . $httpResponse->getStatusCode();
285
            /** @var $exception \ApacheSolrForTypo3\Solr\PingFailedException */
286
            $exception = GeneralUtility::makeInstance(PingFailedException::class, $message);
287
            $exception->setHttpResponse($httpResponse);
288
            throw $exception;
289
        }
290
291 1
        return $end - $start;
292
    }
293
294
    /**
295
     * Performs a ping request and returns the result.
296
     *
297
     * @param int $timeout
298
     * @param boolean $useCache indicates if the ping result should be cached in the instance or not
299
     * @return \Apache_Solr_HttpTransport_Response
300
     */
301 41
    protected function performPingRequest($timeout = 2, $useCache = true)
302
    {
303 41
        $cacheKey = (string) ($this);
304 41
        if ($useCache && isset(static::$pingCache[$cacheKey])) {
305 35
            return static::$pingCache[$cacheKey];
306
        }
307
308 41
        $pingResult = $this->getHttpTransport()->performGetRequest($this->_pingUrl, $timeout);
309
310 41
        if ($useCache) {
311 40
            static::$pingCache[$cacheKey] = $pingResult;
312 40
        }
313
314 41
        return $pingResult;
315
    }
316
317
    /**
318
     * Performs a content and meta data extraction request.
319
     *
320
     * @param ExtractingQuery $query An extraction query
321
     * @return array An array containing the extracted content [0] and meta data [1]
322
     */
323 1
    public function extractByQuery(ExtractingQuery $query)
324
    {
325
        $headers = [
326 1
            'Content-Type' => 'multipart/form-data; boundary=' . $query->getMultiPartPostDataBoundary()
327 1
        ];
328
329
        try {
330 1
            $response = $this->requestServlet(
331 1
                self::EXTRACT_SERVLET,
332 1
                $query->getQueryParameters(),
333 1
                'POST',
334 1
                $headers,
335 1
                $query->getRawPostFileData()
336 1
            );
337 1
        } catch (\Exception $e) {
338
            GeneralUtility::devLog('Extracting text and meta data through Solr Cell over HTTP POST',
339
                'solr', 3, [
340
                    'query' => (array)$query,
341
                    'parameters' => $query->getQueryParameters(),
342
                    'file' => $query->getFile(),
343
                    'headers' => $headers,
344
                    'query url' => self::EXTRACT_SERVLET,
345
                    'exception' => $e->getMessage()
346
                ]);
347
        }
348
349
        return [
350 1
            $response->extracted,
351 1
            (array)$response->extracted_metadata
352 1
        ];
353
    }
354
355
    /**
356
     * Make a request to a servlet (a path) that's not a standard path.
357
     *
358
     * @param string $servlet Path to be added to the base Solr path.
359
     * @param array $parameters Optional, additional request parameters when constructing the URL.
360
     * @param string $method HTTP method to use, defaults to GET.
361
     * @param array $requestHeaders Key value pairs of header names and values. Should include 'Content-Type' for POST and PUT.
362
     * @param string $rawPost Must be an empty string unless method is POST or PUT.
363
     * @param float|bool $timeout Read timeout in seconds, defaults to FALSE.
364
     * @return \Apache_Solr_Response Response object
365
     * @throws \Apache_Solr_HttpTransportException if returned HTTP status is other than 200
366
     */
367 1
    public function requestServlet($servlet, $parameters = [], $method = 'GET', $requestHeaders = [], $rawPost = '', $timeout = false)
368
    {
369
        // Add default parameters
370 1
        $parameters['wt'] = self::SOLR_WRITER;
371 1
        $parameters['json.nl'] = $this->_namedListTreatment;
372 1
        $url = $this->_constructUrl($servlet, $parameters);
373
374 1
        $httpResponse = $this->getResponseFromTransport($url, $method, $requestHeaders, $rawPost, $timeout);
375 1
        $solrResponse = new \Apache_Solr_Response($httpResponse, $this->_createDocuments, $this->_collapseSingleValueArrays);
376 1
        if ($solrResponse->getHttpStatus() != 200) {
377
            throw new \Apache_Solr_HttpTransportException($solrResponse);
378
        }
379
380 1
        return $solrResponse;
381
    }
382
383
    /**
384
     * Decides which transport method to used, depending on the request method and retrieves the response.
385
     *
386
     * @param string $url
387
     * @param string $method
388
     * @param array $requestHeaders
389
     * @param string $rawPost
390
     * @param float|bool $timeout
391
     * @return \Apache_Solr_HttpTransport_Response
392
     */
393 1
    protected function getResponseFromTransport($url, $method, $requestHeaders, $rawPost, $timeout)
394
    {
395 1
        $httpTransport = $this->getHttpTransport();
396
397 1
        if ($method == self::METHOD_GET) {
398
            return $httpTransport->performGetRequest($url, $timeout);
399
        }
400 1
        if ($method == self::METHOD_POST) {
401
            // FIXME should respect all headers, not only Content-Type
402 1
            return $httpTransport->performPostRequest($url, $rawPost, $requestHeaders['Content-Type'], $timeout);
403
        }
404
405
        throw new \InvalidArgumentException('$method should be GET or POST');
406
    }
407
408
    /**
409
     * Return a valid http URL given this server's scheme, host, port, and path
410
     * and a provided servlet name.
411
     *
412
     * @param string $servlet Servlet name
413
     * @param array $params Additional URL parameters to attach to the end of the URL
414
     * @return string Servlet URL
415
     */
416 73
    protected function _constructUrl($servlet, $params = [])
417
    {
418 73
        $url = parent::_constructUrl($servlet, $params);
419
420 73
        if (!GeneralUtility::isFirstPartOfStr($url, $this->_scheme)) {
421 2
            $parsedUrl = parse_url($url);
422
423
            // unfortunately can't use str_replace as it replace all
424
            // occurrences of $needle and can't be limited to replace only once
425 2
            $url = $this->_scheme . substr($url, strlen($parsedUrl['scheme']));
426 2
        }
427
428 73
        return $url;
429
    }
430
431
    /**
432
     * Returns the set scheme
433
     *
434
     * @return string
435
     */
436 1
    public function getScheme()
437
    {
438 1
        return $this->_scheme;
439
    }
440
441
    /**
442
     * Set the scheme used. If empty will fallback to constants
443
     *
444
     * @param string $scheme Either http or https
445
     * @throws \UnexpectedValueException
446
     */
447 74
    public function setScheme($scheme)
448
    {
449
        // Use the provided scheme or use the default
450 74
        if (empty($scheme)) {
451 2
            throw new \UnexpectedValueException('Scheme parameter is empty', 1380756390);
452
        }
453
454 73
        $isHttpOrHttps = in_array($scheme, [self::SCHEME_HTTP, self::SCHEME_HTTPS]);
455 73
        if (!$isHttpOrHttps) {
456 1
            throw new \UnexpectedValueException('Unsupported scheme parameter, scheme must be http or https', 1380756442);
457
        }
458
459
        // we have a valid scheme
460 73
        $this->_scheme = $scheme;
461
462 73
        if ($this->_urlsInited) {
463 1
            $this->_initUrls();
464 1
        }
465 73
    }
466
467
    /**
468
     * get field meta data for the index
469
     *
470
     * @param int $numberOfTerms Number of top terms to fetch for each field
471
     * @return array
472
     */
473
    public function getFieldsMetaData($numberOfTerms = 0)
474
    {
475
        return $this->getLukeMetaData($numberOfTerms)->fields;
476
    }
477
478
    /**
479
     * Retrieves meta data about the index from the luke request handler
480
     *
481
     * @param int $numberOfTerms Number of top terms to fetch for each field
482
     * @return \Apache_Solr_Response Index meta data
483
     */
484
    public function getLukeMetaData($numberOfTerms = 0)
485
    {
486
        if (!isset($this->lukeData[$numberOfTerms])) {
487
            $lukeUrl = $this->_constructUrl(
488
                self::LUKE_SERVLET,
489
                [
490
                    'numTerms' => $numberOfTerms,
491
                    'wt' => self::SOLR_WRITER,
492
                    'fl' => '*'
493
                ]
494
            );
495
496
            $this->lukeData[$numberOfTerms] = $this->_sendRawGet($lukeUrl);
497
        }
498
499
        return $this->lukeData[$numberOfTerms];
500
    }
501
502
    /**
503
     * Central method for making a get operation against this Solr Server
504
     *
505
     * @param string $url
506
     * @param float|bool $timeout Read timeout in seconds
507
     * @return \Apache_Solr_Response
508
     */
509 35
    protected function _sendRawGet($url, $timeout = false)
510
    {
511 35
        $logSeverity = 0; // info
512
513
        try {
514 35
            $response = parent::_sendRawGet($url, $timeout);
515 35
        } catch (\Apache_Solr_HttpTransportException $e) {
0 ignored issues
show
Bug introduced by
The class Apache_Solr_HttpTransportException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
516 2
            $logSeverity = 3; // fatal error
517 2
            $response = $e->getResponse();
518
        }
519
520 35
        if ($this->configuration->getLoggingQueryRawGet() || $response->getHttpStatus() != 200) {
521
            $logData = [
522 2
                'query url' => $url,
523
                'response' => (array)$response
524 2
            ];
525
526 2
            if (!empty($e)) {
527 2
                $logData['exception'] = $e->__toString();
528 2
            } else {
529
                // trigger data parsing
530
                $response->response;
531
                $logData['response data'] = print_r($response, true);
532
            }
533
534 2
            GeneralUtility::devLog('Querying Solr using GET', 'solr',
535 2
                $logSeverity, $logData);
536 2
        }
537
538 35
        return $response;
539
    }
540
541
    /**
542
     * Returns whether a search has been executed or not.
543
     *
544
     * @return bool TRUE if a search has been executed, FALSE otherwise
545
     */
546
    public function hasSearched()
547
    {
548
        return $this->hasSearched;
549
    }
550
551
    /**
552
     * Gets the most recent response (if any)
553
     *
554
     * @return \Apache_Solr_Response Most recent response, or NULL if a search has not been executed yet.
555
     */
556 1
    public function getResponse()
557
    {
558 1
        return $this->responseCache;
559
    }
560
561
    /**
562
     * Enable/Disable debug mode
563
     *
564
     * @param bool $debug TRUE to enable debug mode, FALSE to turn off, off by default
565
     */
566
    public function setDebug($debug)
567
    {
568
        $this->debug = (boolean)$debug;
569
    }
570
571
    /**
572
     * Gets information about the plugins installed in Solr
573
     *
574
     * @return array A nested array of plugin data.
575
     */
576
    public function getPluginsInformation()
577
    {
578
        if (empty($this->pluginsData)) {
579
            $pluginsInformation = $this->_sendRawGet($this->_pluginsUrl);
580
581
            // access a random property to trigger response parsing
582
            $pluginsInformation->responseHeader;
583
            $this->pluginsData = $pluginsInformation;
584
        }
585
586
        return $this->pluginsData;
587
    }
588
589
    /**
590
     * Gets the name of the schema.xml file installed and in use on the Solr
591
     * server.
592
     *
593
     * @deprecated use getSchema()->getName() instead will be removed in 7.0
594
     * @return string Name of the active schema.xml
595
     */
596
    public function getSchemaName()
597
    {
598
        GeneralUtility::logDeprecatedFunction();
599
        return $this->getSchema()->getName();
600
    }
601
602
    /**
603
     * Gets information about the Solr server
604
     *
605
     * @return array A nested array of system data.
606
     */
607 3
    public function getSystemInformation()
608
    {
609 3
        if (empty($this->systemData)) {
610 3
            $systemInformation = $this->system();
611
612
            // access a random property to trigger response parsing
613 3
            $systemInformation->responseHeader;
614 3
            $this->systemData = $systemInformation;
615 3
        }
616
617 3
        return $this->systemData;
618
    }
619
620
    /**
621
     * Gets the name of the solrconfig.xml file installed and in use on the Solr
622
     * server.
623
     *
624
     * @return string Name of the active solrconfig.xml
625
     */
626 1
    public function getSolrconfigName()
627
    {
628 1
        if (is_null($this->solrconfigName)) {
629 1
            $solrconfigXmlUrl = $this->_scheme . '://'
630 1
                . $this->_host . ':' . $this->_port
631 1
                . $this->_path . 'admin/file/?file=solrconfig.xml';
632 1
            $response= $this->_sendRawGet($solrconfigXmlUrl);
633
634 1
            $solrconfigXml = simplexml_load_string($response->getRawResponse());
635 1
            if ($solrconfigXml === false) {
636
                throw new \InvalidArgumentException('No valid xml response from schema file: ' . $solrconfigXmlUrl);
637
            }
638 1
            $this->solrconfigName = (string)$solrconfigXml->attributes()->name;
639 1
        }
640
641 1
        return $this->solrconfigName;
642
    }
643
644
    /**
645
     * Gets the Solr server's version number.
646
     *
647
     * @return string Solr version number
648
     */
649 2
    public function getSolrServerVersion()
650
    {
651 2
        $systemInformation = $this->getSystemInformation();
652
653
        // don't know why $systemInformation->lucene->solr-spec-version won't work
654 2
        $luceneInformation = (array)$systemInformation->lucene;
655 2
        return $luceneInformation['solr-spec-version'];
656
    }
657
658
    /**
659
     * Deletes all index documents of a certain type and does a commit
660
     * afterwards.
661
     *
662
     * @param string $type The type of documents to delete, usually a table name.
663
     * @param bool $commit Will commit immediately after deleting the documents if set, defaults to TRUE
664
     */
665
    public function deleteByType($type, $commit = true)
666
    {
667
        $this->deleteByQuery('type:' . trim($type));
668
669
        if ($commit) {
670
            $this->commit(false, false, false);
671
        }
672
    }
673
674
    /**
675
     * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be
676
     * a complete and well formed "delete" xml document
677
     *
678
     * @param string $rawPost Expected to be utf-8 encoded xml document
679
     * @param float|int $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
680
     * @return \Apache_Solr_Response
681
     */
682 5
    public function delete($rawPost, $timeout = 3600)
683
    {
684 5
        $response = $this->_sendRawPost($this->_updateUrl, $rawPost, $timeout);
685
686 5
        GeneralUtility::devLog(
687 5
            'Delete Query sent.',
688 5
            'solr',
689 5
            1,
690
            [
691 5
                'query' => $rawPost,
692 5
                'query url' => $this->_updateUrl,
693
                'response' => (array)$response
694 5
            ]
695 5
        );
696
697 5
        return $response;
698
    }
699
700
    /**
701
     * Central method for making a post operation against this Solr Server
702
     *
703
     * @param string $url
704
     * @param string $rawPost
705
     * @param float|bool $timeout Read timeout in seconds
706
     * @param string $contentType
707
     * @return \Apache_Solr_Response
708
     */
709 51
    protected function _sendRawPost(
710
        $url,
711
        $rawPost,
712
        $timeout = false,
713
        $contentType = 'text/xml; charset=UTF-8'
714
    ) {
715 51
        $logSeverity = 0; // info
716
717
        try {
718 51
            $response = parent::_sendRawPost($url, $rawPost, $timeout,
719 51
                $contentType);
720 51
        } catch (\Apache_Solr_HttpTransportException $e) {
0 ignored issues
show
Bug introduced by
The class Apache_Solr_HttpTransportException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
721
            $logSeverity = 3; // fatal error
722
            $response = $e->getResponse();
723
        }
724
725 51
        if ($this->configuration->getLoggingQueryRawPost() || $response->getHttpStatus() != 200) {
726
            $logData = [
727
                'query url' => $url,
728
                'content' => $rawPost,
729
                'response' => (array)$response
730
            ];
731
732
            if (!empty($e)) {
733
                $logData['exception'] = $e->__toString();
734
            }
735
736
            GeneralUtility::devLog('Querying Solr using POST', 'solr',
737
                $logSeverity, $logData);
738
        }
739
740 51
        return $response;
741
    }
742
743
    /**
744
     * Get currently configured synonyms
745
     *
746
     * @param string $baseWord If given a base word, retrieves the synonyms for that word only
747
     * @return array
748
     */
749 1
    public function getSynonyms($baseWord = '')
750
    {
751 1
        $this->initializeSynonymsUrl();
752 1
        $synonymsUrl = $this->_synonymsUrl;
753 1
        if (!empty($baseWord)) {
754 1
            $synonymsUrl .= '/' . $baseWord;
755 1
        }
756
757 1
        $response = $this->_sendRawGet($synonymsUrl);
758 1
        return $this->synonymParser->parseJson($baseWord, $response->getRawResponse());
759
    }
760
761
    /**
762
     * Add list of synonyms for base word to managed synonyms map
763
     *
764
     * @param string $baseWord
765
     * @param array $synonyms
766
     *
767
     * @return \Apache_Solr_Response
768
     *
769
     * @throws \Apache_Solr_InvalidArgumentException If $baseWord or $synonyms are empty
770
     */
771 1
    public function addSynonym($baseWord, array $synonyms)
772
    {
773 1
        $this->initializeSynonymsUrl();
774 1
        $json = $this->synonymParser->toJson($baseWord, $synonyms);
775 1
        return $this->_sendRawPost($this->_synonymsUrl, $json,
776 1
            $this->getHttpTransport()->getDefaultTimeout(), 'application/json');
777
    }
778
779
    /**
780
     * Remove a synonym from the synonyms map
781
     *
782
     * @param string $baseWord
783
     * @return \Apache_Solr_Response
784
     * @throws \Apache_Solr_InvalidArgumentException
785
     */
786 1
    public function deleteSynonym($baseWord)
787
    {
788 1
        $this->initializeSynonymsUrl();
789 1
        if (empty($baseWord)) {
790
            throw new \Apache_Solr_InvalidArgumentException('Must provide base word.');
791
        }
792
793 1
        return $this->_sendRawDelete($this->_synonymsUrl . '/' . $baseWord);
794
    }
795
796
    /**
797
     * Central method for making a HTTP DELETE operation against the Solr server
798
     *
799
     * @param string $url
800
     * @param bool|float $timeout Read timeout in seconds
801
     * @return \Apache_Solr_Response
802
     */
803 2
    protected function _sendRawDelete($url, $timeout = false)
804
    {
805 2
        $logSeverity = 0; // info
806
807
        try {
808 2
            $httpTransport = $this->getHttpTransport();
809
810 2
            $httpResponse = $httpTransport->performDeleteRequest($url,
811 2
                $timeout);
812 2
            $solrResponse = new \Apache_Solr_Response($httpResponse,
813 2
                $this->_createDocuments, $this->_collapseSingleValueArrays);
814
815 2
            if ($solrResponse->getHttpStatus() != 200) {
816 2
                throw new \Apache_Solr_HttpTransportException($solrResponse);
817
            }
818 2
        } catch (\Apache_Solr_HttpTransportException $e) {
0 ignored issues
show
Bug introduced by
The class Apache_Solr_HttpTransportException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
819 2
            $logSeverity = 3; // fatal error
820 2
            $solrResponse = $e->getResponse();
821
        }
822
823 2
        if ($this->configuration->getLoggingQueryRawDelete() || $solrResponse->getHttpStatus() != 200) {
824
            $logData = [
825 2
                'query url' => $url,
826
                'response' => (array)$solrResponse
827 2
            ];
828
829 2
            if (!empty($e)) {
830 2
                $logData['exception'] = $e->__toString();
831 2
            } else {
832
                // trigger data parsing
833
                $solrResponse->response;
834
                $logData['response data'] = print_r($solrResponse, true);
835
            }
836
837 2
            GeneralUtility::devLog('Querying Solr using DELETE', 'solr',
838 2
                $logSeverity, $logData);
839 2
        }
840
841 2
        return $solrResponse;
842
    }
843
844
    /**
845
     * Get currently configured stop words
846
     *
847
     * @return array
848
     */
849 2
    public function getStopWords()
850
    {
851 2
        $this->initializeStopWordsUrl();
852 2
        $response = $this->_sendRawGet($this->_stopWordsUrl);
853 2
        return $this->stopWordParser->parseJson($response->getRawResponse());
854
    }
855
856
    /**
857
     * Adds stop words to the managed stop word list
858
     *
859
     * @param array|string $stopWords string for a single word, array for multiple words
860
     * @return \Apache_Solr_Response
861
     * @throws \Apache_Solr_InvalidArgumentException If $stopWords is empty
862
     */
863 1
    public function addStopWords($stopWords)
864
    {
865 1
        $this->initializeStopWordsUrl();
866 1
        $json = $this->stopWordParser->toJson($stopWords);
867 1
        return $this->_sendRawPost($this->_stopWordsUrl, $json,
868 1
            $this->getHttpTransport()->getDefaultTimeout(), 'application/json');
869
    }
870
871
    /**
872
     * Deletes a words from the managed stop word list
873
     *
874
     * @param string $stopWord stop word to delete
875
     * @return \Apache_Solr_Response
876
     * @throws \Apache_Solr_InvalidArgumentException If $stopWords is empty
877
     */
878 1
    public function deleteStopWord($stopWord)
879
    {
880 1
        $this->initializeStopWordsUrl();
881 1
        if (empty($stopWord)) {
882
            throw new \Apache_Solr_InvalidArgumentException('Must provide stop word.');
883
        }
884
885 1
        return $this->_sendRawDelete($this->_stopWordsUrl . '/' . $stopWord);
886
    }
887
888
    /**
889
     * Returns the core name from the configured path.
890
     *
891
     * @return string
892
     */
893 1
    public function getCoreName()
894
    {
895 1
        return (string) array_pop(explode('/', trim($this->_path, '/')));
0 ignored issues
show
Bug introduced by
explode('/', trim($this->_path, '/')) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
896
    }
897
898
    /**
899
     * Reloads the current core
900
     *
901
     * @return \Apache_Solr_Response
902
     */
903 1
    public function reloadCore()
904
    {
905 1
        return $this->reloadCoreByName($this->getCoreName());
906
    }
907
908
    /**
909
     * Reloads a core of the connection by a given corename.
910
     *
911
     * @param string $coreName
912
     * @return \Apache_Solr_Response
913
     */
914 1
    public function reloadCoreByName($coreName)
915
    {
916 1
        $coreAdminReloadUrl = $this->_coresUrl . '?action=reload&core=' . $coreName;
917 1
        return $this->_sendRawGet($coreAdminReloadUrl);
918
    }
919
920
    /**
921
     * initializes various URLs, including the Luke URL
922
     *
923
     * @return void
924
     */
925 73
    protected function _initUrls()
926
    {
927 73
        parent::_initUrls();
928
929 73
        $this->_lukeUrl = $this->_constructUrl(
930 73
            self::LUKE_SERVLET,
931
            [
932 73
                'numTerms' => '0',
933
                'wt' => self::SOLR_WRITER
934 73
            ]
935 73
        );
936
937 73
        $this->_pluginsUrl = $this->_constructUrl(
938 73
            self::PLUGINS_SERVLET,
939 73
            ['wt' => self::SOLR_WRITER]
940 73
        );
941
942 73
        $pathElements = explode('/', trim($this->_path, '/'));
943 73
        $this->_coresUrl =
944 73
            $this->_scheme . '://' .
945 73
            $this->_host . ':' .
946 73
            $this->_port . '/' .
947 73
            $pathElements[0] . '/' .
948 73
            self::CORES_SERVLET;
949
950 73
        $this->_schemaUrl = $this->_constructUrl(self::SCHEMA_SERVLET);
951 73
    }
952
953
    /**
954
     * @return void
955
     */
956 1
    protected function initializeSynonymsUrl()
957
    {
958 1
        if (trim($this->_synonymsUrl) !== '') {
959 1
            return;
960
        }
961 1
        $this->_synonymsUrl = $this->_constructUrl(self::SYNONYMS_SERVLET) . $this->getSchema()->getLanguage();
962 1
    }
963
964
    /**
965
     * @return void
966
     */
967 2
    protected function initializeStopWordsUrl()
968
    {
969 2
        if (trim($this->_stopWordsUrl) !== '') {
970 1
            return;
971
        }
972
973 2
        $this->_stopWordsUrl = $this->_constructUrl(self::STOPWORDS_SERVLET) . $this->getSchema()->getLanguage();
974 2
    }
975
976
    /**
977
     * Get the configured schema for the current core.
978
     *
979
     * @return Schema
980
     */
981 4
    public function getSchema()
982
    {
983 4
        if ($this->schema !== null) {
984
            return $this->schema;
985
        }
986 4
        $response = $this->_sendRawGet($this->_schemaUrl);
987 4
        $this->schema = $this->schemaParser->parseJson($response->getRawResponse());
988 4
        return $this->schema;
989
    }
990
}
991