Passed
Push — master ( 4e40a2...cc3f84 )
by Timo
24:09
created

Util::getConfigurationFromExistingTSFE()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 43
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 43
ccs 30
cts 30
cp 1
rs 8.8337
c 0
b 0
f 0
cc 6
nc 24
nop 3
crap 6
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 3 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\Domain\Site\SiteRepository;
28
use ApacheSolrForTypo3\Solr\System\Cache\TwoLevelCache;
29
use ApacheSolrForTypo3\Solr\System\Configuration\ConfigurationManager;
30
use ApacheSolrForTypo3\Solr\System\Configuration\ConfigurationPageResolver;
31
use ApacheSolrForTypo3\Solr\System\Configuration\ExtensionConfiguration;
32
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
33
use ApacheSolrForTypo3\Solr\System\TCA\TCAService;
34
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
35
use ApacheSolrForTypo3\Solr\System\Mvc\Frontend\Controller\OverriddenTypoScriptFrontendController;
36
use TYPO3\CMS\Backend\Utility\BackendUtility;
37
use TYPO3\CMS\Core\TimeTracker\TimeTracker;
38
use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
39
use TYPO3\CMS\Core\Utility\GeneralUtility;
40
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
41
use TYPO3\CMS\Frontend\Page\PageRepository;
42
43
/**
44
 * Utility class for tx_solr
45
 *
46
 * @author Ingo Renner <[email protected]>
47
 */
48
class Util
49
{
50
51
    /**
52
     * Generates a document id for documents representing page records.
53
     *
54
     * @param int $uid The page's uid
55
     * @param int $typeNum The page's typeNum
56
     * @param int $language the language id, defaults to 0
57
     * @param string $accessGroups comma separated list of uids of groups that have access to that page
58
     * @param string $mountPointParameter The mount point parameter that is used to access the page.
59
     * @return string The document id for that page
60
     */
61 66
    public static function getPageDocumentId($uid, $typeNum = 0, $language = 0, $accessGroups = '0,-1', $mountPointParameter = '')
62
    {
63 66
        $additionalParameters = $typeNum . '/' . $language . '/' . $accessGroups;
64
65 66
        if ((string)$mountPointParameter !== '') {
66 2
            $additionalParameters = $mountPointParameter . '/' . $additionalParameters;
67
        }
68
69 66
        $documentId = self::getDocumentId('pages', $uid, $uid, $additionalParameters);
70
71 66
        return $documentId;
72
    }
73
74
    /**
75
     * Generates a document id in the form $siteHash/$type/$uid.
76
     *
77
     * @param string $table The records table name
78
     * @param int $rootPageId The record's site root id
79
     * @param int $uid The record's uid
80
     * @param string $additionalIdParameters Additional ID parameters
81
     * @return string A document id
82
     */
83 85
    public static function getDocumentId($table, $rootPageId, $uid, $additionalIdParameters = '')
84
    {
85 85
        $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
86 85
        $site = $siteRepository->getSiteByPageId($rootPageId);
87 85
        $siteHash = $site->getSiteHash();
88
89 85
        $documentId = $siteHash . '/' . $table . '/' . $uid;
90 85
        if (!empty($additionalIdParameters)) {
91 66
            $documentId .= '/' . $additionalIdParameters;
92
        }
93
94 85
        return $documentId;
95
    }
96
97
    /**
98
     * Shortcut to retrieve the TypoScript configuration for EXT:solr
99
     * (plugin.tx_solr) from TSFE.
100
     *
101
     * @return TypoScriptConfiguration
102
     */
103 176
    public static function getSolrConfiguration()
104
    {
105 176
        $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
106 176
        return $configurationManager->getTypoScriptConfiguration();
107
    }
108
109
    /**
110
     * Gets the Solr configuration for a specific root page id.
111
     * To be used from the backend.
112
     *
113
     * @param int $pageId Id of the (root) page to get the Solr configuration from.
114
     * @param bool $initializeTsfe Optionally initializes a full TSFE to get the configuration, defaults to FALSE
115
     * @param int $language System language uid, optional, defaults to 0
116
     * @return TypoScriptConfiguration The Solr configuration for the requested tree.
117
     */
118 153
    public static function getSolrConfigurationFromPageId($pageId, $initializeTsfe = false, $language = 0)
119
    {
120 153
        $rootPath = '';
121 153
        return self::getConfigurationFromPageId($pageId, $rootPath, $initializeTsfe, $language);
122
    }
123
124
    /**
125
     * Loads the TypoScript configuration for a given page id and language.
126
     * Language usage may be disabled to get the default TypoScript
127
     * configuration.
128
     *
129
     * @param int $pageId Id of the (root) page to get the Solr configuration from.
130
     * @param string $path The TypoScript configuration path to retrieve.
131
     * @param bool $initializeTsfe Optionally initializes a full TSFE to get the configuration, defaults to FALSE
132
     * @param int $language System language uid, optional, defaults to 0
133
     * @param bool $useTwoLevelCache Flag to enable the two level cache for the typoscript configuration array
134
     * @return TypoScriptConfiguration The Solr configuration for the requested tree.
135
     */
136 154
    public static function getConfigurationFromPageId($pageId, $path, $initializeTsfe = false, $language = 0, $useTwoLevelCache = true)
137
    {
138 154
        $pageId = self::getConfigurationPageIdToUse($pageId);
139
140 154
        static $configurationObjectCache = [];
141 154
        $cacheId = md5($pageId . '|' . $path . '|' . $language . '|' . ($initializeTsfe ? '1' : '0'));
142 154
        if (isset($configurationObjectCache[$cacheId])) {
143 70
            return $configurationObjectCache[$cacheId];
144
        }
145
146
        // If we're on UID 0, we cannot retrieve a configuration currently.
147
        // getRootline() below throws an exception (since #typo3-60 )
148
        // as UID 0 cannot have any parent rootline by design.
149 154
        if ($pageId == 0) {
150 2
            return $configurationObjectCache[$cacheId] = self::buildTypoScriptConfigurationFromArray([], $pageId, $language, $path);
151
        }
152
153 153
        if ($useTwoLevelCache) {
154
            /** @var $cache TwoLevelCache */
155 153
            $cache = GeneralUtility::makeInstance(TwoLevelCache::class, /** @scrutinizer ignore-type */ 'tx_solr_configuration');
156 153
            $configurationArray = $cache->get($cacheId);
157
        }
158
159 153
        if (!empty($configurationArray)) {
160
            // we have a cache hit and can return it.
161
            return $configurationObjectCache[$cacheId] = self::buildTypoScriptConfigurationFromArray($configurationArray, $pageId, $language, $path);
162
        }
163
164
        // we have nothing in the cache. We need to build the configurationToUse
165 153
        $configurationArray = self::buildConfigurationArray($pageId, $path, $initializeTsfe, $language);
166
167 153
        if ($useTwoLevelCache && isset($cache)) {
168 153
            $cache->set($cacheId, $configurationArray);
169
        }
170
171 153
        return $configurationObjectCache[$cacheId] = self::buildTypoScriptConfigurationFromArray($configurationArray, $pageId, $language, $path);
172
    }
173
174
    /**
175
     * This method retrieves the closest pageId where a configuration is located, when this
176
     * feature is enabled.
177
     *
178
     * @param int $pageId
179
     * @return int
180
     */
181 154
    protected static function getConfigurationPageIdToUse($pageId)
182
    {
183 154
        $extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
184 154
        if ($extensionConfiguration->getIsUseConfigurationFromClosestTemplateEnabled()) {
185
            /** @var $configurationPageResolve ConfigurationPageResolver */
186
            $configurationPageResolver = GeneralUtility::makeInstance(ConfigurationPageResolver::class);
187
            $pageId = $configurationPageResolver->getClosestPageIdWithActiveTemplate($pageId);
188
            return $pageId;
189
        }
190 154
        return $pageId;
191
    }
192
193
    /**
194
     * Initializes a TSFE, if required and builds an configuration array, containing the solr configuration.
195
     *
196
     * @param integer $pageId
197
     * @param string $path
198
     * @param boolean $initializeTsfe
199
     * @param integer $language
200
     * @return array
201
     */
202 153
    protected static function buildConfigurationArray($pageId, $path, $initializeTsfe, $language)
203
    {
204 153
        if ($initializeTsfe) {
205 18
            self::initializeTsfe($pageId, $language);
206 18
            $configurationToUse = self::getConfigurationFromInitializedTSFE($path);
207
        } else {
208 153
            $configurationToUse = self::getConfigurationFromExistingTSFE($pageId, $path, $language);
209
        }
210
211 153
        return is_array($configurationToUse) ? $configurationToUse : [];
212
    }
213
214
    /**
215
     * Builds the configuration object from a config array and returns it.
216
     *
217
     * @param array $configurationToUse
218
     * @param int $pageId
219
     * @param int $languageId
220
     * @param string $typoScriptPath
221
     * @return TypoScriptConfiguration
222
     */
223 154
    protected static function buildTypoScriptConfigurationFromArray(array $configurationToUse, $pageId, $languageId, $typoScriptPath)
224
    {
225 154
        $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
226 154
        return $configurationManager->getTypoScriptConfiguration($configurationToUse, $pageId, $languageId, $typoScriptPath);
227
    }
228
229
    /**
230
     * This function is used to retrieve the configuration from a previous initialized TSFE
231
     * (see: getConfigurationFromPageId)
232
     *
233
     * @param string $path
234
     * @return mixed
235
     */
236 18
    private static function getConfigurationFromInitializedTSFE($path)
237
    {
238
        /** @var $tmpl ExtendedTemplateService */
239 18
        $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
240 18
        $configuration = $tmpl->ext_getSetup($GLOBALS['TSFE']->tmpl->setup, $path);
241 18
        $configurationToUse = $configuration[0];
242 18
        return $configurationToUse;
243
    }
244
245
    /**
246
     * This function is used to retrieve the configuration from an existing TSFE instance
247
     *
248
     * @param $pageId
249
     * @param $path
250
     * @param $language
251
     * @return mixed
252
     */
253 153
    private static function getConfigurationFromExistingTSFE($pageId, $path, $language)
254
    {
255 153
        if (is_int($language)) {
256 153
            GeneralUtility::_GETset($language, 'L');
257
        }
258
259
            /** @var $pageSelect PageRepository */
260 153
        $pageSelect = GeneralUtility::makeInstance(PageRepository::class);
261 153
        $rootLine = $pageSelect->getRootLine($pageId);
262
263 153
        $initializedTsfe = false;
264 153
        $initializedPageSelect = false;
265 153
        if (empty($GLOBALS['TSFE']->sys_page)) {
266 83
            if (empty($GLOBALS['TSFE'])) {
267 83
                $GLOBALS['TSFE'] = new \stdClass();
268 83
                $GLOBALS['TSFE']->tmpl = new \stdClass();
269 83
                $GLOBALS['TSFE']->tmpl->rootLine = $rootLine;
270 83
                $GLOBALS['TSFE']->sys_page = $pageSelect;
271 83
                $GLOBALS['TSFE']->id = $pageId;
272 83
                $GLOBALS['TSFE']->tx_solr_initTsfe = 1;
273 83
                $initializedTsfe = true;
274
            }
275
276 83
            $GLOBALS['TSFE']->sys_page = $pageSelect;
277 83
            $initializedPageSelect = true;
278
        }
279
            /** @var $tmpl ExtendedTemplateService */
280 153
        $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
281 153
        $tmpl->tt_track = false; // Do not log time-performance information
282 153
        $tmpl->init();
283 153
        $tmpl->runThroughTemplates($rootLine); // This generates the constants/config + hierarchy info for the template.
284 153
        $tmpl->generateConfig();
285
286 153
        $getConfigurationFromInitializedTSFEAndWriteToCache = $tmpl->ext_getSetup($tmpl->setup, $path);
287 153
        $configurationToUse = $getConfigurationFromInitializedTSFEAndWriteToCache[0];
288
289 153
        if ($initializedPageSelect) {
290 83
            $GLOBALS['TSFE']->sys_page = null;
291
        }
292 153
        if ($initializedTsfe) {
293 83
            unset($GLOBALS['TSFE']);
294
        }
295 153
        return $configurationToUse;
296
    }
297
298
    /**
299
     * Initializes the TSFE for a given page ID and language.
300
     *
301
     * @param int $pageId The page id to initialize the TSFE for
302
     * @param int $language System language uid, optional, defaults to 0
303
     * @param bool $useCache Use cache to reuse TSFE
304
     * @todo When we drop TYPO3 8 support we should use a middleware stack to initialize a TSFE for our needs
305
     * @return void
306
     */
307 23
    public static function initializeTsfe($pageId, $language = 0, $useCache = true)
308
    {
309 23
        static $tsfeCache = [];
310
311
        // resetting, a TSFE instance with data from a different page Id could be set already
312 23
        unset($GLOBALS['TSFE']);
313
314 23
        $cacheId = $pageId . '|' . $language;
315
316 23
        if (!is_object($GLOBALS['TT'])) {
317 23
            $GLOBALS['TT'] = GeneralUtility::makeInstance(TimeTracker::class, false);
318
        }
319
320 23
        if (!isset($tsfeCache[$cacheId]) || !$useCache) {
321 23
            GeneralUtility::_GETset($language, 'L');
322
323
324 23
            $GLOBALS['TSFE'] = GeneralUtility::makeInstance(OverriddenTypoScriptFrontendController::class, $GLOBALS['TYPO3_CONF_VARS'], $pageId, 0);
325
326
            // for certain situations we need to trick TSFE into granting us
327
            // access to the page in any case to make getPageAndRootline() work
328
            // see http://forge.typo3.org/issues/42122
329 23
            $pageRecord = BackendUtility::getRecord('pages', $pageId, 'fe_group');
330 23
            $groupListBackup = $GLOBALS['TSFE']->gr_list;
331 23
            $GLOBALS['TSFE']->gr_list = $pageRecord['fe_group'];
332
333 23
            $GLOBALS['TSFE']->sys_page = GeneralUtility::makeInstance(PageRepository::class);
334 23
            self::getPageAndRootlineOfTSFE($pageId);
0 ignored issues
show
Deprecated Code introduced by
The function ApacheSolrForTypo3\Solr\...PageAndRootlineOfTSFE() has been deprecated: This is only implemented to provide compatibility for TYPO3 8 and 9 when we drop TYPO3 8 support this should changed to use a middleware stack ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

334
            /** @scrutinizer ignore-deprecated */ self::getPageAndRootlineOfTSFE($pageId);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
335
336
            // restore gr_list
337 23
            $GLOBALS['TSFE']->gr_list = $groupListBackup;
338
339 23
            $GLOBALS['TSFE']->initTemplate();
340 23
            $GLOBALS['TSFE']->forceTemplateParsing = true;
341 23
            $GLOBALS['TSFE']->initFEuser();
342 23
            $GLOBALS['TSFE']->initUserGroups();
343
            //  $GLOBALS['TSFE']->getCompressedTCarray(); // seems to cause conflicts sometimes
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
344
345 23
            $GLOBALS['TSFE']->no_cache = true;
346 23
            $GLOBALS['TSFE']->tmpl->start($GLOBALS['TSFE']->rootLine);
347 23
            $GLOBALS['TSFE']->no_cache = false;
348 23
            $GLOBALS['TSFE']->getConfigArray();
349 23
            $GLOBALS['TSFE']->settingLanguage();
350 23
            if (!$useCache) {
351
                $GLOBALS['TSFE']->settingLocale();
352
            }
353
354 23
            $GLOBALS['TSFE']->newCObj();
355 23
            $GLOBALS['TSFE']->absRefPrefix = self::getAbsRefPrefixFromTSFE($GLOBALS['TSFE']);
356 23
            $GLOBALS['TSFE']->calculateLinkVars();
357
358 23
            if ($useCache) {
359 23
                $tsfeCache[$cacheId] = $GLOBALS['TSFE'];
360
            }
361
        }
362
363 23
        if ($useCache) {
364 23
            $GLOBALS['TSFE'] = $tsfeCache[$cacheId];
365 23
            $GLOBALS['TSFE']->settingLocale();
366
        }
367 23
    }
368
369
    /**
370
     * @deprecated This is only implemented to provide compatibility for TYPO3 8 and 9 when we drop TYPO3 8 support this
371
     * should changed to use a middleware stack
372
     * @param integer $pageId
373
     */
374 23
    private static function getPageAndRootlineOfTSFE($pageId)
375
    {
376
        //@todo This can be dropped when TYPO3 8 compatibility is dropped
377 23
        if (Util::getIsTYPO3VersionBelow9()) {
378 23
            $GLOBALS['TSFE']->getPageAndRootline();
379
        } else {
380
            //@todo When we drop the support of TYPO3 8 we should use the frontend middleware stack instead of initializing this on our own
381
            /** @var $siteRepository SiteRepository */
382
            $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
383
            $site = $siteRepository->getSiteByPageId($pageId);
384
            $GLOBALS['TSFE']->getPageAndRootlineWithDomain($site->getRootPageId());
385
        }
386 23
    }
387
388
    /**
389
     * Check if record ($table, $uid) is a workspace record
390
     *
391
     * @param string $table The table the record belongs to
392
     * @param int $uid The record's uid
393
     * @return bool TRUE if the record is in a draft workspace, FALSE if it's a LIVE record
394
     */
395 39
    public static function isDraftRecord($table, $uid)
396
    {
397 39
        $isWorkspaceRecord = false;
398
399 39
        if ((ExtensionManagementUtility::isLoaded('workspaces')) && (BackendUtility::isTableWorkspaceEnabled($table))) {
400
            $record = BackendUtility::getRecord($table, $uid, 'pid, t3ver_state');
401
402
            if ($record['pid'] == '-1' || $record['t3ver_state'] > 0) {
403
                $isWorkspaceRecord = true;
404
            }
405
        }
406
407 39
        return $isWorkspaceRecord;
408
    }
409
410
    /**
411
     * Check if the page type of a page record is allowed
412
     *
413
     * @param array $pageRecord The pages database row
414
     * @param string $configurationName The name of the configuration to use.
415
     *
416
     * @return bool TRUE if the page type is allowed, otherwise FALSE
417
     */
418 30
    public static function isAllowedPageType(array $pageRecord, $configurationName = 'pages')
419
    {
420 30
        $isAllowedPageType = false;
421 30
        $configurationName = $configurationName ?? 'pages';
422 30
        $allowedPageTypes = self::getAllowedPageTypes($pageRecord['uid'], $configurationName);
423
424 30
        if (in_array($pageRecord['doktype'], $allowedPageTypes)) {
425 29
            $isAllowedPageType = true;
426
        }
427
428 30
        return $isAllowedPageType;
429
    }
430
431
    /**
432
     * Get allowed page types
433
     *
434
     * @param int $pageId Page ID
435
     * @param string $configurationName The name of the configuration to use.
436
     *
437
     * @return array Allowed page types to compare to a doktype of a page record
438
     */
439 30
    public static function getAllowedPageTypes($pageId, $configurationName = 'pages')
440
    {
441 30
        $rootPath = '';
442 30
        $configuration = self::getConfigurationFromPageId($pageId, $rootPath);
443 30
        return $configuration->getIndexQueueAllowedPageTypesArrayByConfigurationName($configurationName);
444
    }
445
446
    /**
447
     * Resolves the configured absRefPrefix to a valid value and resolved if absRefPrefix
448
     * is set to "auto".
449
     *
450
     * @param TypoScriptFrontendController $TSFE
451
     * @return string
452
     */
453 23
    public static function getAbsRefPrefixFromTSFE(TypoScriptFrontendController $TSFE)
454
    {
455 23
        $absRefPrefix = '';
456 23
        if (empty($TSFE->config['config']['absRefPrefix'])) {
457 20
            return $absRefPrefix;
458
        }
459
460 3
        $absRefPrefix = trim($TSFE->config['config']['absRefPrefix']);
461 3
        if ($absRefPrefix === 'auto') {
462 1
            $absRefPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
463
        }
464
465 3
        return $absRefPrefix;
466
    }
467
468
    /**
469
     * @todo This method is just added for pages_language_overlay compatibility checks and will be removed when TYPO8 support is dropped
470
     * @return boolean
471
     */
472 242
    public static function getIsTYPO3VersionBelow9()
473
    {
474 242
        return (bool)version_compare(TYPO3_branch, '9.0', '<');
475
    }
476
477
    /**
478
     * @todo This method is just added for pages_language_overlay compatibility checks and will be removed when TYPO8 support is dropped
479
     * @return string
480
     */
481
    public static function getPageOverlayTableName()
482
    {
483
        return self::getIsTYPO3VersionBelow9() ? 'pages_language_overlay' : 'pages';
484
    }
485
486
    /**
487
     * This function can be used to check if one of the strings in needles is
488
     * contained in the haystack.
489
     *
490
     *
491
     * Example:
492
     *
493
     * haystack: the brown fox
494
     * needles: ['hello', 'world']
495
     * result: false
496
     *
497
     * haystack: the brown fox
498
     * needles: ['is', 'fox']
499
     * result: true
500
     *
501
     * @param string $haystack
502
     * @param array $needles
503
     * @return bool
504
     */
505 52
    public static function containsOneOfTheStrings($haystack, array $needles)
506
    {
507 52
        foreach ($needles as $needle) {
508 52
            $position = strpos($haystack, $needle);
509 52
            if ($position !== false) {
510 52
                return true;
511
            }
512
        }
513
514 49
        return false;
515
    }
516
}
517