Passed
Push — release-11.5.x ( 1520e1...01d568 )
by Rafael
43:11
created

ConnectionManager::getConnectionByTypo3Site()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 16
ccs 6
cts 6
cp 1
rs 9.9
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3
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;
19
20
use ApacheSolrForTypo3\Solr\Domain\Site\Site;
21
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
22
use ApacheSolrForTypo3\Solr\System\Records\Pages\PagesRepository as PagesRepositoryAtExtSolr;
23
use ApacheSolrForTypo3\Solr\System\Records\SystemLanguage\SystemLanguageRepository;
24
use ApacheSolrForTypo3\Solr\System\Solr\Node;
25
use ApacheSolrForTypo3\Solr\System\Solr\SolrConnection;
26
use ApacheSolrForTypo3\Solr\System\Util\SiteUtility;
27
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
28
use InvalidArgumentException;
29
use function json_encode;
30
use Throwable;
31
use TYPO3\CMS\Core\SingletonInterface;
32
use TYPO3\CMS\Core\Site\Entity\Site as Typo3Site;
33
use TYPO3\CMS\Core\Utility\GeneralUtility;
34
35
/**
36
 * ConnectionManager is responsible to create SolrConnection objects.
37
 *
38
 * @author Ingo Renner <[email protected]>
39
 */
40
class ConnectionManager implements SingletonInterface
41
{
42
    /**
43
     * @var array
44
     */
45
    protected static array $connections = [];
46
47
    /**
48
     * @var SystemLanguageRepository
49
     */
50
    protected SystemLanguageRepository $systemLanguageRepository;
51
52
    /**
53
     * @var PagesRepositoryAtExtSolr
54
     */
55
    protected PagesRepositoryAtExtSolr $pagesRepositoryAtExtSolr;
56
57
    /**
58
     * @var SiteRepository
59
     */
60
    protected SiteRepository $siteRepository;
61
62
    /**
63
     * @param SystemLanguageRepository|null $systemLanguageRepository
64
     * @param PagesRepositoryAtExtSolr|null $pagesRepositoryAtExtSolr
65 132
     * @param SiteRepository|null $siteRepository
66
     */
67
    public function __construct(
68
        SystemLanguageRepository $systemLanguageRepository = null,
69
        PagesRepositoryAtExtSolr $pagesRepositoryAtExtSolr = null,
70 132
        SiteRepository $siteRepository = null
71 132
    ) {
72 132
        $this->systemLanguageRepository = $systemLanguageRepository ?? GeneralUtility::makeInstance(SystemLanguageRepository::class);
73
        $this->siteRepository = $siteRepository ?? GeneralUtility::makeInstance(SiteRepository::class);
74
        $this->pagesRepositoryAtExtSolr = $pagesRepositoryAtExtSolr ?? GeneralUtility::makeInstance(PagesRepositoryAtExtSolr::class);
75
    }
76
77
    /**
78
     * Creates a solr connection for read and write endpoints
79
     *
80
     * @param array $readNodeConfiguration
81
     * @param array $writeNodeConfiguration
82 119
     * @return SolrConnection|object
83
     */
84 119
    public function getSolrConnectionForNodes(array $readNodeConfiguration, array $writeNodeConfiguration)
85 119
    {
86 119
        $connectionHash = md5(json_encode($readNodeConfiguration) . json_encode($writeNodeConfiguration));
87 119
        if (!isset(self::$connections[$connectionHash])) {
88 119
            $readNode = Node::fromArray($readNodeConfiguration);
89
            $writeNode = Node::fromArray($writeNodeConfiguration);
90 119
            self::$connections[$connectionHash] = GeneralUtility::makeInstance(SolrConnection::class, $readNode, $writeNode);
91
        }
92
        return self::$connections[$connectionHash];
93
    }
94
95
    /**
96
     * Creates a solr configuration from the configuration array and returns it.
97
     *
98
     * @param array $config The solr configuration array
99 119
     * @return SolrConnection
100
     */
101 119
    public function getConnectionFromConfiguration(array $config)
102
    {
103
        if (empty($config['read']) && !empty($config['solrHost'])) {
104
            throw new InvalidArgumentException('Invalid registry data please re-initialize your solr connections');
105 119
        }
106
107
        return $this->getSolrConnectionForNodes($config['read'], $config['write']);
108
    }
109
110
    /**
111
     * Gets a Solr connection for a page ID.
112
     *
113
     * @param int $pageId A page ID.
114
     * @param ?int $language The language ID to get the connection for as the path may differ. Optional, defaults to 0.
115
     * @param ?string $mount Comma list of MountPoint parameters
116
     * @return SolrConnection A solr connection.
117
     * @throws DBALDriverException
118 104
     * @throws NoSolrConnectionFoundException
119
     */
120
    public function getConnectionByPageId(int $pageId, int $language = 0, string $mount = ''): SolrConnection
121 104
    {
122 103
        try {
123 103
            $site = $this->siteRepository->getSiteByPageId($pageId, $mount);
124 103
            $this->throwExceptionOnInvalidSite($site, 'No site for pageId ' . $pageId);
125 3
            $config = $site->getSolrConnectionConfiguration($language);
126 2
            return $this->getConnectionFromConfiguration($config);
127
        } catch (InvalidArgumentException $e) {
128
            throw $this->buildNoConnectionExceptionForPageAndLanguage($pageId, $language);
129
        }
130
    }
131
132
    /**
133
     * Gets a Solr connection for a TYPO3 site and language
134
     *
135
     * @param Typo3Site $typo3Site
136
     * @param int $languageUid
137
     * @return SolrConnection A Solr connection.
138
     * @throws NoSolrConnectionFoundException
139 13
     */
140
    public function getConnectionByTypo3Site(Typo3Site $typo3Site, int $languageUid = 0): SolrConnection
141
    {
142 13
        $config = SiteUtility::getSolrConnectionConfiguration($typo3Site, $languageUid);
143 12
        if ($config === null) {
144 12
            throw $this->buildNoConnectionExceptionForPageAndLanguage(
145 12
                $typo3Site->getRootPageId(),
146 1
                $languageUid
147 1
            );
148
        }
149
150
        try {
151
            return $this->getConnectionFromConfiguration($config);
152
        } catch (InvalidArgumentException $e) {
153
            throw $this->buildNoConnectionExceptionForPageAndLanguage(
154
                $typo3Site->getRootPageId(),
155
                $languageUid
156
            );
157
        }
158 4
    }
159
160 4
    /**
161 4
     * Gets a Solr connection for a root page ID.
162 4
     *
163 4
     * @param int $pageId A root page ID.
164
     * @param ?int $language The language ID to get the connection for as the path may differ. Optional, defaults to 0.
165
     * @return SolrConnection A solr connection.
166
     * @throws DBALDriverException
167 4
     * @throws NoSolrConnectionFoundException
168
     */
169
    public function getConnectionByRootPageId(int $pageId, ?int $language = 0): SolrConnection
170
    {
171
        try {
172
            $site = $this->siteRepository->getSiteByRootPageId($pageId);
173
            $this->throwExceptionOnInvalidSite($site, 'No site for pageId ' . $pageId);
174
            $config = $site->getSolrConnectionConfiguration($language ?? 0);
175
            return $this->getConnectionFromConfiguration($config);
176 24
        } catch (InvalidArgumentException $e) {
177
            throw $this->buildNoConnectionExceptionForPageAndLanguage($pageId, $language);
178 24
        }
179
    }
180 24
181 24
    /**
182
     * Gets all connections found.
183
     *
184 24
     * @return SolrConnection[] An array of initialized ApacheSolrForTypo3\Solr\System\Solr\SolrConnection connections
185
     * @throws DBALDriverException
186
     * @throws Throwable
187
     */
188
    public function getAllConnections(): array
189
    {
190
        $solrConnections = [];
191
        foreach ($this->siteRepository->getAvailableSites() as $site) {
192
            foreach ($site->getAllSolrConnectionConfigurations() as $solrConfiguration) {
193
                $solrConnections[] = $this->getConnectionFromConfiguration($solrConfiguration);
194
            }
195
        }
196
197
        return $solrConnections;
198
    }
199
200
    /**
201
     * Gets all connections configured for a given site.
202
     *
203
     * @param Site $site A TYPO3 site
204
     * @return SolrConnection[] An array of Solr connection objects (ApacheSolrForTypo3\Solr\System\Solr\SolrConnection)
205
     */
206
    public function getConnectionsBySite(Site $site): array
207
    {
208
        $connections = [];
209
210
        foreach ($site->getAllSolrConnectionConfigurations() as $languageId => $solrConnectionConfiguration) {
211
            $connections[$languageId] = $this->getConnectionFromConfiguration($solrConnectionConfiguration);
212
        }
213
214 3
        return $connections;
215
    }
216 3
217 3
    /**
218
     * Creates a human-readable label from the connections' configuration.
219 3
     *
220 3
     * @param array $connection Connection configuration
221
     * @return string Connection label
222
     * @deprecated since v11.5 and will be removed in v11.6, as unused since v11.0.0
223
     */
224
    protected function buildConnectionLabel(array $connection): string
225
    {
226
        trigger_error(
227
            'ConnectionManager->buildConnectionLabel is deprecated since v11.5 and will be removed in v11.6, as unsed since v11.0.0',
228
            E_USER_DEPRECATED
229
        );
230 105
231
        return $connection['connectionKey']
232 105
            . ' (pid: ' . $connection['rootPageUid']
233 105
            . ', language: ' . $this->systemLanguageRepository->findOneLanguageTitleByLanguageId($connection['language'])
234
            . ') - Read node: '
235
            . $connection['read']['host'] . ':'
236
            . $connection['read']['port']
237
            . $connection['read']['path']
238
            . ' - Write node: '
239
            . $connection['write']['host'] . ':'
240
            . $connection['write']['port']
241
            . $connection['write']['path'];
242
    }
243
244 3
    /**
245
     * @param $pageId
246
     * @param $language
247 3
     * @return NoSolrConnectionFoundException
248
     */
249
    protected function buildNoConnectionExceptionForPageAndLanguage($pageId, $language): NoSolrConnectionFoundException
250
    {
251
        $message = 'Could not find a Solr connection for page [' . $pageId . '] and language [' . $language . '].';
252
        $noSolrConnectionException = $this->buildNoConnectionException($message);
253
254
        $noSolrConnectionException->setLanguageId($language);
255
        return $noSolrConnectionException;
256
    }
257
258
    /**
259
     * Throws a no connection exception when no site was passed.
260
     *
261
     * @param Site|null $site
262
     * @param string $message
263
     * @throws NoSolrConnectionFoundException
264
     */
265
    protected function throwExceptionOnInvalidSite(?Site $site, string $message)
266
    {
267
        if (!is_null($site)) {
268
            return;
269
        }
270
271
        throw $this->buildNoConnectionException($message);
272
    }
273
274
    /**
275
     * Build a NoSolrConnectionFoundException with the passed message.
276
     * @param string $message
277
     * @return NoSolrConnectionFoundException
278
     */
279
    protected function buildNoConnectionException(string $message): NoSolrConnectionFoundException
280
    {
281
        /* @var NoSolrConnectionFoundException $noSolrConnectionException */
282
        return GeneralUtility::makeInstance(
283
            NoSolrConnectionFoundException::class,
284
            /** @scrutinizer ignore-type */
285
            $message,
286
            /** @scrutinizer ignore-type */
287
            1575396474
288
        );
289
    }
290
}
291