Passed
Push — master ( 04715c...48f77b )
by Timo
47s
created

SolrService::__construct()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 20
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 9
cts 9
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 16
nc 16
nop 8
crap 5

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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