Passed
Push — release-11.5.x ( 1c345b...71e6eb )
by Markus
26:38
created

SolrStatus   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 247
Duplicated Lines 0 %

Test Coverage

Coverage 82.11%

Importance

Changes 0
Metric Value
wmc 22
eloc 93
dl 0
loc 247
ccs 78
cts 95
cp 0.8211
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getStatus() 0 10 3
A formatSolrVersion() 0 15 2
A checkStreamBodySetting() 0 15 3
A checkPingTime() 0 10 2
A checkSolrConfigName() 0 10 2
A checkSolrVersion() 0 10 2
A checkAccessFilter() 0 11 2
A getConnectionStatus() 0 45 3
A checkSolrSchemaName() 0 10 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace ApacheSolrForTypo3\Solr\Report;
19
20
use ApacheSolrForTypo3\Solr\ConnectionManager;
21
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
22
use ApacheSolrForTypo3\Solr\PingFailedException;
23
use ApacheSolrForTypo3\Solr\System\Solr\Service\SolrAdminService;
24
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
25
use Throwable;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27
use TYPO3\CMS\Reports\Status;
28
29
/**
30
 * Provides a status report about whether a connection to the Solr server can
31
 * be established.
32
 *
33
 * @author Ingo Renner <[email protected]>
34
 */
35
class SolrStatus extends AbstractSolrStatus
36
{
37
    /**
38
     * Site Repository
39
     *
40
     * @var SiteRepository
41
     */
42
    protected $siteRepository;
43
44
    /**
45
     * Connection Manager
46
     *
47
     * @var ConnectionManager
48
     */
49
    protected $connectionManager;
50
51
    /**
52
     * Holds the response status
53
     *
54
     * @var int
55
     */
56
    protected int $responseStatus = Status::OK;
57
58
    /**
59
     * Holds the response message build by the checks
60
     *
61
     * @var string
62
     */
63
    protected string $responseMessage = '';
64
65
    /**
66
     * SolrStatus constructor.
67
     * @param SiteRepository|null $siteRepository
68
     * @param ConnectionManager|null $connectionManager
69
     */
70 2
    public function __construct(SiteRepository $siteRepository = null, ConnectionManager $connectionManager = null)
71
    {
72 2
        $this->siteRepository = $siteRepository ?? GeneralUtility::makeInstance(SiteRepository::class);
73 2
        $this->connectionManager = $connectionManager ?? GeneralUtility::makeInstance(ConnectionManager::class);
74
    }
75
76
    /**
77
     * Compiles a collection of status checks against each configured Solr server.
78
     *
79
     * @throws DBALDriverException
80
     * @throws Throwable
81
     *
82
     * @noinspection PhpMissingReturnTypeInspection see {@link \TYPO3\CMS\Reports\StatusProviderInterface::getStatus()}
83
     */
84 2
    public function getStatus()
85
    {
86 2
        $reports = [];
87 2
        foreach ($this->siteRepository->getAvailableSites() as $site) {
88 2
            foreach ($site->getAllSolrConnectionConfigurations() as $solrConfiguration) {
89 2
                $reports[] = $this->getConnectionStatus($solrConfiguration);
90
            }
91
        }
92
93 2
        return $reports;
94
    }
95
96
    /**
97
     * Checks whether a Solr server is available and provides some information.
98
     *
99
     * @param array $solrConnection Solr connection parameters
100
     * @return Status Status of the Solr connection
101
     */
102 2
    protected function getConnectionStatus(array $solrConnection): Status
103
    {
104 2
        $header = 'Your site has contacted the Apache Solr server.';
105 2
        $this->responseStatus = Status::OK;
106
107 2
        $solrAdmin = $this->connectionManager
108 2
            ->getSolrConnectionForNodes($solrConnection['read'], $solrConnection['write'])
109 2
            ->getAdminService();
110
111 2
        $solrVersion = $this->checkSolrVersion($solrAdmin);
112 2
        $accessFilter = $this->checkAccessFilter($solrAdmin);
113 2
        $pingTime = $this->checkPingTime($solrAdmin);
114 2
        $configName = $this->checkSolrConfigName($solrAdmin);
115 2
        $schemaName = $this->checkSolrSchemaName($solrAdmin);
116 2
        if (version_compare($solrVersion, '8.11.3', '>=')) {
117
            $streamBodySetting = $this->checkStreamBodySetting($solrAdmin);
118
        }
119
120 2
        if ($this->responseStatus !== Status::OK) {
121 1
            $header = 'Failed contacting the Solr server or invalid settings found.';
122
        }
123
124 2
        $variables = [
125 2
            'header' => $header,
126 2
            'connection' => $solrConnection,
127 2
            'solr' => $solrAdmin,
128 2
            'solrVersion' => $solrVersion,
129 2
            'pingTime' => $pingTime,
130 2
            'configName' => $configName,
131 2
            'schemaName' => $schemaName,
132 2
            'accessFilter' => $accessFilter,
133 2
            'streamBodySetting' => $streamBodySetting ?? null,
134 2
        ];
135
136 2
        $report = $this->getRenderedReport('SolrStatus.html', $variables);
137 2
        return GeneralUtility::makeInstance(
138 2
            Status::class,
139
            /** @scrutinizer ignore-type */
140 2
            'Apache Solr',
141
            /** @scrutinizer ignore-type */
142 2
            '',
143
            /** @scrutinizer ignore-type */
144 2
            $report,
145
            /** @scrutinizer ignore-type */
146 2
            $this->responseStatus
147 2
        );
148
    }
149
150
    /**
151
     * Checks the solr version and adds it to the report.
152
     *
153
     * @param SolrAdminService $solr
154
     * @return string solr version
155
     */
156 2
    protected function checkSolrVersion(SolrAdminService $solr): string
157
    {
158
        try {
159 2
            $solrVersion = $this->formatSolrVersion($solr->getSolrServerVersion());
160
        } catch (Throwable $e) {
161
            $this->responseStatus = Status::ERROR;
162
            $solrVersion = 'Error getting solr version: ' . $e->getMessage();
163
        }
164
165 2
        return $solrVersion;
166
    }
167
168
    /**
169
     * Checks the access filter setup and adds it to the report.
170
     *
171
     * @param SolrAdminService $solrAdminService
172
     * @return string
173
     */
174 2
    protected function checkAccessFilter(SolrAdminService $solrAdminService): string
175
    {
176
        try {
177 2
            $accessFilterPluginStatus = GeneralUtility::makeInstance(AccessFilterPluginInstalledStatus::class);
178 2
            $accessFilterPluginVersion = $accessFilterPluginStatus->getInstalledPluginVersion($solrAdminService);
179 1
            $accessFilterMessage = $accessFilterPluginVersion;
180 1
        } catch (Throwable $e) {
181 1
            $this->responseStatus = Status::ERROR;
182 1
            $accessFilterMessage = 'Error getting access filter: ' . $e->getMessage();
183
        }
184 2
        return $accessFilterMessage;
185
    }
186
187
    /**
188
     * Checks the ping time and adds it to the report.
189
     *
190
     * @param SolrAdminService $solrAdminService
191
     * @return string
192
     */
193 2
    protected function checkPingTime(SolrAdminService $solrAdminService): string
194
    {
195
        try {
196 2
            $pingQueryTime = $solrAdminService->getPingRoundTripRuntime();
197 1
            $pingMessage = (int)$pingQueryTime . ' ms';
198 1
        } catch (PingFailedException $e) {
199 1
            $this->responseStatus = Status::ERROR;
200 1
            $pingMessage = 'Ping error: ' . $e->getMessage();
201
        }
202 2
        return $pingMessage;
203
    }
204
205
    /**
206
     * Checks the solr config name and adds it to the report.
207
     *
208
     * @param SolrAdminService $solrAdminService
209
     * @return string
210
     */
211 2
    protected function checkSolrConfigName(SolrAdminService $solrAdminService): string
212
    {
213
        try {
214 2
            $solrConfigMessage = $solrAdminService->getSolrconfigName();
215 1
        } catch (Throwable $e) {
216 1
            $this->responseStatus = Status::ERROR;
217 1
            $solrConfigMessage = 'Error determining solr config: ' . $e->getMessage();
218
        }
219
220 2
        return $solrConfigMessage;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $solrConfigMessage could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
221
    }
222
223
    /**
224
     * Checks the solr schema name and adds it to the report.
225
     *
226
     * @param SolrAdminService $solrAdminService
227
     * @return string
228
     */
229 2
    protected function checkSolrSchemaName(SolrAdminService $solrAdminService): string
230
    {
231
        try {
232 2
            $solrSchemaMessage = $solrAdminService->getSchema()->getName();
233
        } catch (Throwable $e) {
234
            $this->responseStatus = Status::ERROR;
235
            $solrSchemaMessage = 'Error determining schema name: ' . $e->getMessage();
236
        }
237
238 2
        return $solrSchemaMessage;
239
    }
240
241
    protected function checkStreamBodySetting(SolrAdminService $solrAdminService): string
242
    {
243
        $systemProperties = $solrAdminService->getSystemProperties();
244
        if ($systemProperties === null) {
245
            $this->responseStatus = Status::ERROR;
246
            return 'Error determining system properties';
247
        }
248
249
        $streamSetting = (bool)($systemProperties['solr.enableStreamBody'] ?? false);
250
        if (!$streamSetting) {
251
            $this->responseStatus = Status::ERROR;
252
            return 'Content Streams not enabled';
253
        }
254
255
        return 'true';
256
    }
257
258
    /**
259
     * Formats the Apache Solr server version number. By default, this is going
260
     * to be the simple major.minor.patch-level version. Custom Builds provide
261
     * more information though, in case of custom-builds, their complete
262
     * version will be added, too.
263
     *
264
     * @param string $solrVersion Unformatted Apache Solr version number a provided by Solr.
265
     * @return string formatted short version number, in case of custom-builds followed by the complete version number
266
     */
267 2
    protected function formatSolrVersion(string $solrVersion): string
268
    {
269 2
        $explodedSolrVersion = explode('.', $solrVersion);
270
271 2
        $shortSolrVersion = $explodedSolrVersion[0]
272 2
            . '.' . $explodedSolrVersion[1]
273 2
            . '.' . $explodedSolrVersion[2];
274
275 2
        $formattedSolrVersion = $shortSolrVersion;
276
277 2
        if ($solrVersion != $shortSolrVersion) {
278 1
            $formattedSolrVersion .= ' (' . $solrVersion . ')';
279
        }
280
281 2
        return $formattedSolrVersion;
282
    }
283
}
284