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

SiteRepository::buildTypo3ManagedSite()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 61
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 5.0039

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 33
dl 0
loc 61
ccs 35
cts 37
cp 0.9459
rs 9.0808
c 2
b 0
f 0
cc 5
nc 5
nop 1
crap 5.0039

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Domain\Site;
19
20
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\RecordMonitor\Helper\RootPageResolver;
21
use ApacheSolrForTypo3\Solr\FrontendEnvironment;
22
use ApacheSolrForTypo3\Solr\System\Cache\TwoLevelCache;
23
use ApacheSolrForTypo3\Solr\System\Configuration\ExtensionConfiguration;
24
use ApacheSolrForTypo3\Solr\System\Records\Pages\PagesRepository;
25
use ApacheSolrForTypo3\Solr\System\Util\SiteUtility;
26
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
27
use InvalidArgumentException;
28
use Throwable;
29
use TYPO3\CMS\Backend\Utility\BackendUtility;
30
use TYPO3\CMS\Core\Registry;
31
use TYPO3\CMS\Core\Site\Entity\Site as CoreSite;
32
use TYPO3\CMS\Core\Site\SiteFinder;
33
use TYPO3\CMS\Core\Utility\GeneralUtility;
34
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
35
36
/**
37
 * SiteRepository
38
 *
39
 * Responsible to retrieve instances of Site objects
40
 *
41
 * @author Thomas Hohn <[email protected]>
42
 */
43
class SiteRepository
44
{
45
    /**
46
     * Rootpage resolver
47
     *
48
     * @var RootPageResolver
49
     */
50
    protected RootPageResolver $rootPageResolver;
51
52
    /**
53
     * @var TwoLevelCache
54
     */
55
    protected TwoLevelCache $runtimeCache;
56
57
    /**
58
     * @var Registry
59
     */
60
    protected Registry $registry;
61
62
    /**
63
     * @var SiteFinder
64
     */
65
    protected SiteFinder $siteFinder;
66
67
    /**
68
     * @var ExtensionConfiguration
69
     */
70
    protected ExtensionConfiguration $extensionConfiguration;
71
72
    /**
73
     * @var FrontendEnvironment
74
     */
75
    protected FrontendEnvironment $frontendEnvironment;
76
77
    /**
78
     * SiteRepository constructor.
79
     *
80
     * @param RootPageResolver|null $rootPageResolver
81
     * @param TwoLevelCache|null $twoLevelCache
82
     * @param Registry|null $registry
83
     * @param SiteFinder|null $siteFinder
84
     * @param ExtensionConfiguration|null $extensionConfiguration
85
     * @param FrontendEnvironment|null $frontendEnvironment
86
     */
87 240
    public function __construct(
88
        RootPageResolver $rootPageResolver = null,
89
        TwoLevelCache $twoLevelCache = null,
90
        Registry $registry = null,
91
        SiteFinder $siteFinder = null,
92
        ExtensionConfiguration $extensionConfiguration = null,
93
        FrontendEnvironment $frontendEnvironment = null
94
    ) {
95 240
        $this->rootPageResolver = $rootPageResolver ?? GeneralUtility::makeInstance(RootPageResolver::class);
96 240
        $this->runtimeCache = $twoLevelCache ?? GeneralUtility::makeInstance(TwoLevelCache::class, /** @scrutinizer ignore-type */'runtime');
97 240
        $this->registry = $registry ?? GeneralUtility::makeInstance(Registry::class);
98 240
        $this->siteFinder = $siteFinder ?? GeneralUtility::makeInstance(SiteFinder::class);
99 240
        $this->extensionConfiguration = $extensionConfiguration ?? GeneralUtility::makeInstance(ExtensionConfiguration::class);
100 240
        $this->frontendEnvironment = $frontendEnvironment ?? GeneralUtility::makeInstance(FrontendEnvironment::class);
101
    }
102
103
    /**
104
     * Gets the Site for a specific page ID.
105
     *
106
     * @param int $pageId The page ID to get a Site object for.
107
     * @param string $mountPointIdentifier
108
     * @return SiteInterface Site for the given page ID.
109
     * @throws DBALDriverException
110
     */
111 164
    public function getSiteByPageId(int $pageId, string $mountPointIdentifier = '')
112
    {
113 164
        $rootPageId = $this->rootPageResolver->getRootPageId($pageId, false, $mountPointIdentifier);
114 164
        return $this->getSiteByRootPageId($rootPageId);
115
    }
116
117
    /**
118
     * Gets the Site for a specific root page-id.
119
     *
120
     * @param int $rootPageId Root page Id to get a Site object for.
121
     * @return SiteInterface Site for the given page-id.
122
     * @throws DBALDriverException
123
     */
124 189
    public function getSiteByRootPageId(int $rootPageId)
125
    {
126 189
        $cacheId = 'SiteRepository' . '_' . 'getSiteByPageId' . '_' . $rootPageId;
127
128 189
        $methodResult = $this->runtimeCache->get($cacheId);
129 189
        if (!empty($methodResult)) {
130 150
            return $methodResult;
131
        }
132
133 189
        $methodResult = $this->buildSite($rootPageId);
134 182
        $this->runtimeCache->set($cacheId, $methodResult);
135
136 182
        return $methodResult;
137
    }
138
139
    /**
140
     * Returns the first available Site.
141
     *
142
     * @param bool $stopOnInvalidSite
143
     * @return Site|null
144
     * @throws DBALDriverException
145
     * @throws Throwable
146
     */
147 21
    public function getFirstAvailableSite(bool $stopOnInvalidSite = false): ?Site
148
    {
149 21
        $sites = $this->getAvailableSites($stopOnInvalidSite);
150 21
        return array_shift($sites);
151
    }
152
153
    /**
154
     * Gets all available TYPO3 sites with Solr configured.
155
     *
156
     * @param bool $stopOnInvalidSite
157
     * @return Site[] An array of available sites
158
     * @throws DBALDriverException
159
     * @throws Throwable
160
     */
161 105
    public function getAvailableSites(bool $stopOnInvalidSite = false): array
162
    {
163 105
        $cacheId = 'SiteRepository' . '_' . 'getAvailableSites';
164
165 105
        $sites = $this->runtimeCache->get($cacheId);
166 105
        if (!empty($sites)) {
167 22
            return $sites;
168
        }
169
170 105
        $sites = $this->getAvailableTYPO3ManagedSites($stopOnInvalidSite);
171 105
        $this->runtimeCache->set($cacheId, $sites);
172
173 105
        return $sites ?? [];
174
    }
175
176
    /**
177
     * @param bool $stopOnInvalidSite
178
     * @return array
179
     * @throws DBALDriverException
180
     * @throws Throwable
181
     */
182 105
    protected function getAvailableTYPO3ManagedSites(bool $stopOnInvalidSite): array
183
    {
184 105
        $typo3ManagedSolrSites = [];
185 105
        $typo3Sites = $this->siteFinder->getAllSites();
186 105
        foreach ($typo3Sites as $typo3Site) {
187
            try {
188 105
                $rootPageId = $typo3Site->getRootPageId();
189 105
                if (isset($typo3ManagedSolrSites[$rootPageId])) {
190
                    //get each site only once
191
                    continue;
192
                }
193 105
                $typo3ManagedSolrSite = $this->buildSite($rootPageId);
194 105
                if ($typo3ManagedSolrSite->isEnabled()) {
195 105
                    $typo3ManagedSolrSites[$rootPageId] = $typo3ManagedSolrSite;
196
                }
197 22
            } catch (Throwable $e) {
198 22
                if ($stopOnInvalidSite) {
199
                    throw $e;
200
                }
201
            }
202
        }
203 105
        return $typo3ManagedSolrSites;
204
    }
205
206
    /**
207
     * Creates an instance of the Site object.
208
     *
209
     * @param int $rootPageId
210
     * @return SiteInterface
211
     * @throws DBALDriverException
212
     */
213 213
    protected function buildSite(int $rootPageId)
214
    {
215 213
        $rootPageRecord = BackendUtility::getRecord('pages', $rootPageId);
216 213
        if (empty($rootPageRecord)) {
217 27
            throw new InvalidArgumentException(
218 27
                "The rootPageRecord for the given rootPageRecord ID '$rootPageId' could not be found in the database and can therefore not be used as site root rootPageRecord.",
219
                1487326416
220
            );
221
        }
222
223 207
        $this->validateRootPageRecord($rootPageId, $rootPageRecord);
224
225 206
        return $this->buildTypo3ManagedSite($rootPageRecord);
226
    }
227
228
    /**
229
     * @param string $domain
230
     * @return string
231
     */
232 206
    protected function getSiteHashForDomain(string $domain): string
233
    {
234
        /** @var $siteHashService SiteHashService */
235 206
        $siteHashService = GeneralUtility::makeInstance(SiteHashService::class);
236 206
        return $siteHashService->getSiteHashForDomain($domain);
237
    }
238
239
    /**
240
     * @param int $rootPageId
241
     * @param array $rootPageRecord
242
     * @throws InvalidArgumentException
243
     */
244 207
    protected function validateRootPageRecord(int $rootPageId, array $rootPageRecord)
245
    {
246 207
        if (!Site::isRootPage($rootPageRecord)) {
247 3
            throw new InvalidArgumentException(
248 3
                "The rootPageRecord for the given rootPageRecord ID '$rootPageId' is not marked as root rootPageRecord and can therefore not be used as site root rootPageRecord.",
249
                1309272922
250
            );
251
        }
252
    }
253
254
    /**
255
     * Builds a TYPO3 managed site with TypoScript configuration.
256
     *
257
     * @param array $rootPageRecord
258
     *
259
     * @return Site
260
     *
261
     * @throws DBALDriverException
262
     */
263 206
    protected function buildTypo3ManagedSite(array $rootPageRecord): ?Site
264
    {
265 206
        $typo3Site = $this->getTypo3Site($rootPageRecord['uid']);
266 206
        if (!$typo3Site instanceof CoreSite) {
267
            return null;
268
        }
269
270 206
        $domain = $typo3Site->getBase()->getHost();
271
272 206
        $siteHash = $this->getSiteHashForDomain($domain);
273 206
        $defaultLanguage = $typo3Site->getDefaultLanguage()->getLanguageId();
274 206
        $pageRepository = GeneralUtility::makeInstance(PagesRepository::class);
275 206
        $availableLanguageIds = array_map(function ($language) {
276 206
            return $language->getLanguageId();
277 206
        }, $typo3Site->getLanguages());
278
279
        // Try to get first instantiable TSFE for one of site languages, to get TypoScript with `plugin.tx_solr.index.*`,
280
        // to be able to collect indexing configuration,
281
        // which are required for BE-Modules/CLI-Commands or RecordMonitor within BE/TCE-commands.
282
        // If TSFE for none of languages can be initialized, then the \ApacheSolrForTypo3\Solr\Domain\Site\Site object unusable at all,
283
        // so the rest of the steps in this method are not necessary, and therefore the null will be returned.
284 206
        $tsfeFactory = GeneralUtility::makeInstance(FrontendEnvironment\Tsfe::class);
285 206
        $tsfeToUseForTypoScriptConfiguration = $tsfeFactory->getTsfeByPageIdAndLanguageFallbackChain($typo3Site->getRootPageId(), ...$availableLanguageIds);
286 206
        if (!$tsfeToUseForTypoScriptConfiguration instanceof TypoScriptFrontendController) {
287
            return null;
288
        }
289
290 206
        $solrConnectionConfigurations = [];
291
292 206
        foreach ($availableLanguageIds as $languageUid) {
293 206
            $solrConnection = SiteUtility::getSolrConnectionConfiguration($typo3Site, $languageUid);
294 206
            if ($solrConnection !== null) {
295 206
                $solrConnectionConfigurations[$languageUid] = $solrConnection;
296 206
            }
297 206
        }
298 206
299
        $solrConfiguration = $this->frontendEnvironment->getSolrConfigurationFromPageId(
300 206
            $rootPageRecord['uid'],
301 206
            $tsfeToUseForTypoScriptConfiguration->getLanguage()->getLanguageId()
302 206
        );
303
304
        return GeneralUtility::makeInstance(
305 206
            Site::class,
306 206
            /** @scrutinizer ignore-type */
307 206
            $solrConfiguration,
308 206
            /** @scrutinizer ignore-type */
309
            $rootPageRecord,
310
            /** @scrutinizer ignore-type */
311 206
            $domain,
312 206
            /** @scrutinizer ignore-type */
313 206
            $siteHash,
314
            /** @scrutinizer ignore-type */
315
            $pageRepository,
316 206
            /** @scrutinizer ignore-type */
317 206
            $defaultLanguage,
318 206
            /** @scrutinizer ignore-type */
319 206
            $availableLanguageIds,
320
            /** @scrutinizer ignore-type */
321
            $solrConnectionConfigurations,
322
            /** @scrutinizer ignore-type */
323
            $typo3Site
324
        );
325
    }
326
327 206
    /**
328 206
     * Returns {@link \TYPO3\CMS\Core\Site\Entity\Site}.
329 206
     *
330
     * @param int $pageUid
331
     * @return CoreSite|null
332 206
     */
333
    protected function getTypo3Site(int $pageUid): ?CoreSite
334
    {
335
        try {
336
            return $this->siteFinder->getSiteByPageId($pageUid);
337
        } catch (Throwable $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
338
        }
339
        return null;
340
    }
341
}
342