Failed Conditions
Push — master ( 5f60a5...9b80eb )
by Rafael
21:42
created

Classes/Util.php (1 issue)

Labels
Severity
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\Index\Queue\RecordMonitor\Helper\RootPageResolver;
28
use ApacheSolrForTypo3\Solr\Domain\Site\SiteRepository;
29
use ApacheSolrForTypo3\Solr\Domain\Site\SiteHashService;
30
use ApacheSolrForTypo3\Solr\System\Cache\TwoLevelCache;
31
use ApacheSolrForTypo3\Solr\System\Configuration\ConfigurationManager;
32
use ApacheSolrForTypo3\Solr\System\Configuration\ConfigurationPageResolver;
33
use ApacheSolrForTypo3\Solr\System\Configuration\ExtensionConfiguration;
34
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
35
use ApacheSolrForTypo3\Solr\System\DateTime\FormatService;
36
use TYPO3\CMS\Backend\Utility\BackendUtility;
0 ignored issues
show
The type TYPO3\CMS\Backend\Utility\BackendUtility was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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\Controller\TypoScriptFrontendController;
42
use TYPO3\CMS\Frontend\Page\PageRepository;
43
44
/**
45
 * Utility class for tx_solr
46
 *
47
 * @author Ingo Renner <[email protected]>
48
 */
49
class Util
50
{
51
52
    /**
53
     * Generates a document id for documents representing page records.
54
     *
55
     * @param int $uid The page's uid
56
     * @param int $typeNum The page's typeNum
57
     * @param int $language the language id, defaults to 0
58
     * @param string $accessGroups comma separated list of uids of groups that have access to that page
59
     * @param string $mountPointParameter The mount point parameter that is used to access the page.
60
     * @return string The document id for that page
61
     */
62 66
    public static function getPageDocumentId($uid, $typeNum = 0, $language = 0, $accessGroups = '0,-1', $mountPointParameter = '')
63
    {
64 66
        $additionalParameters = $typeNum . '/' . $language . '/' . $accessGroups;
65
66 66
        if ((string)$mountPointParameter !== '') {
67 2
            $additionalParameters = $mountPointParameter . '/' . $additionalParameters;
68
        }
69
70 66
        $documentId = self::getDocumentId('pages', $uid, $uid, $additionalParameters);
71
72 66
        return $documentId;
73
    }
74
75
    /**
76
     * Generates a document id in the form $siteHash/$type/$uid.
77
     *
78
     * @param string $table The records table name
79
     * @param int $rootPageId The record's site root id
80
     * @param int $uid The record's uid
81
     * @param string $additionalIdParameters Additional ID parameters
82
     * @return string A document id
83
     */
84 85
    public static function getDocumentId($table, $rootPageId, $uid, $additionalIdParameters = '')
85
    {
86 85
        $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
87 85
        $site = $siteRepository->getSiteByPageId($rootPageId);
88 85
        $siteHash = $site->getSiteHash();
89
90 85
        $documentId = $siteHash . '/' . $table . '/' . $uid;
91 85
        if (!empty($additionalIdParameters)) {
92 66
            $documentId .= '/' . $additionalIdParameters;
93
        }
94
95 85
        return $documentId;
96
    }
97
98
    /**
99
     * Shortcut to retrieve the TypoScript configuration for EXT:solr
100
     * (plugin.tx_solr) from TSFE.
101
     *
102
     * @return TypoScriptConfiguration
103
     */
104 175
    public static function getSolrConfiguration()
105
    {
106 175
        $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
107 175
        return $configurationManager->getTypoScriptConfiguration();
108
    }
109
110
    /**
111
     * Gets the Solr configuration for a specific root page id.
112
     * To be used from the backend.
113
     *
114
     * @param int $pageId Id of the (root) page to get the Solr configuration from.
115
     * @param bool $initializeTsfe Optionally initializes a full TSFE to get the configuration, defaults to FALSE
116
     * @param int $language System language uid, optional, defaults to 0
117
     * @return TypoScriptConfiguration The Solr configuration for the requested tree.
118
     */
119 151
    public static function getSolrConfigurationFromPageId($pageId, $initializeTsfe = false, $language = 0)
120
    {
121 151
        $rootPath = '';
122 151
        return self::getConfigurationFromPageId($pageId, $rootPath, $initializeTsfe, $language);
123
    }
124
125
    /**
126
     * Loads the TypoScript configuration for a given page id and language.
127
     * Language usage may be disabled to get the default TypoScript
128
     * configuration.
129
     *
130
     * @param int $pageId Id of the (root) page to get the Solr configuration from.
131
     * @param string $path The TypoScript configuration path to retrieve.
132
     * @param bool $initializeTsfe Optionally initializes a full TSFE to get the configuration, defaults to FALSE
133
     * @param int $language System language uid, optional, defaults to 0
134
     * @param bool $useTwoLevelCache Flag to enable the two level cache for the typoscript configuration array
135
     * @return TypoScriptConfiguration The Solr configuration for the requested tree.
136
     */
137 152
    public static function getConfigurationFromPageId($pageId, $path, $initializeTsfe = false, $language = 0, $useTwoLevelCache = true)
138
    {
139 152
        $pageId = self::getConfigurationPageIdToUse($pageId);
140
141 152
        static $configurationObjectCache = [];
142 152
        $cacheId = md5($pageId . '|' . $path . '|' . $language);
143 152
        if (isset($configurationObjectCache[$cacheId])) {
144 69
            return $configurationObjectCache[$cacheId];
145
        }
146
147
        // If we're on UID 0, we cannot retrieve a configuration currently.
148
        // getRootline() below throws an exception (since #typo3-60 )
149
        // as UID 0 cannot have any parent rootline by design.
150 152
        if ($pageId == 0) {
151 2
            return $configurationObjectCache[$cacheId] = self::buildTypoScriptConfigurationFromArray([], $pageId, $language, $path);
152
        }
153
154 151
        if ($useTwoLevelCache) {
155
            /** @var $cache TwoLevelCache */
156 151
            $cache = GeneralUtility::makeInstance(TwoLevelCache::class, 'tx_solr_configuration');
157 151
            $configurationArray = $cache->get($cacheId);
158
        }
159
160 151
        if (!empty($configurationArray)) {
161
            // we have a cache hit and can return it.
162
            return $configurationObjectCache[$cacheId] = self::buildTypoScriptConfigurationFromArray($configurationArray, $pageId, $language, $path);
163
        }
164
165
        // we have nothing in the cache. We need to build the configurationToUse
166 151
        $configurationArray = self::buildConfigurationArray($pageId, $path, $initializeTsfe, $language);
167
168 151
        if ($useTwoLevelCache && isset($cache)) {
169 151
            $cache->set($cacheId, $configurationArray);
170
        }
171
172 151
        return $configurationObjectCache[$cacheId] = self::buildTypoScriptConfigurationFromArray($configurationArray, $pageId, $language, $path);
173
    }
174
175
    /**
176
     * This method retrieves the closest pageId where a configuration is located, when this
177
     * feature is enabled.
178
     *
179
     * @param int $pageId
180
     * @return int
181
     */
182 152
    protected static function getConfigurationPageIdToUse($pageId)
183
    {
184 152
        $extensionConfiguration = GeneralUtility::makeInstance(ExtensionConfiguration::class);
185 152
        if ($extensionConfiguration->getIsUseConfigurationFromClosestTemplateEnabled()) {
186
            /** @var $configurationPageResolve ConfigurationPageResolver */
187
            $configurationPageResolver = GeneralUtility::makeInstance(ConfigurationPageResolver::class);
188
            $pageId = $configurationPageResolver->getClosestPageIdWithActiveTemplate($pageId);
189
            return $pageId;
190
        }
191 152
        return $pageId;
192
    }
193
194
    /**
195
     * Initializes a TSFE, if required and builds an configuration array, containing the solr configuration.
196
     *
197
     * @param integer $pageId
198
     * @param string $path
199
     * @param boolean $initializeTsfe
200
     * @param integer $language
201
     * @return array
202
     */
203 151
    protected static function buildConfigurationArray($pageId, $path, $initializeTsfe, $language)
204
    {
205 151
        if ($initializeTsfe) {
206 7
            self::initializeTsfe($pageId, $language);
207 6
            $configurationToUse = self::getConfigurationFromInitializedTSFE($path);
208
        } else {
209 151
            $configurationToUse = self::getConfigurationFromExistingTSFE($pageId, $path, $language);
210
        }
211
212 151
        return is_array($configurationToUse) ? $configurationToUse : [];
213
    }
214
215
    /**
216
     * Builds the configuration object from a config array and returns it.
217
     *
218
     * @param array $configurationToUse
219
     * @param int $pageId
220
     * @param int $languageId
221
     * @param string $typoScriptPath
222
     * @return TypoScriptConfiguration
223
     */
224 152
    protected static function buildTypoScriptConfigurationFromArray(array $configurationToUse, $pageId, $languageId, $typoScriptPath)
225
    {
226 152
        $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
227 152
        return $configurationManager->getTypoScriptConfiguration($configurationToUse, $pageId, $languageId, $typoScriptPath);
228
    }
229
230
    /**
231
     * This function is used to retrieve the configuration from a previous initialized TSFE
232
     * (see: getConfigurationFromPageId)
233
     *
234
     * @param string $path
235
     * @return mixed
236
     */
237 6
    private static function getConfigurationFromInitializedTSFE($path)
238
    {
239
        /** @var $tmpl ExtendedTemplateService */
240 6
        $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
241 6
        $configuration = $tmpl->ext_getSetup($GLOBALS['TSFE']->tmpl->setup, $path);
242 6
        $configurationToUse = $configuration[0];
243 6
        return $configurationToUse;
244
    }
245
246
    /**
247
     * This function is used to retrieve the configuration from an existing TSFE instance
248
     * @param $pageId
249
     * @param $path
250
     * @param $language
251
     * @return mixed
252
     */
253 151
    private static function getConfigurationFromExistingTSFE($pageId, $path, $language)
254
    {
255 151
        if (is_int($language)) {
256 151
            GeneralUtility::_GETset($language, 'L');
257
        }
258
259
            /** @var $pageSelect PageRepository */
260 151
        $pageSelect = GeneralUtility::makeInstance(PageRepository::class);
261 151
        $rootLine = $pageSelect->getRootLine($pageId);
262
263 151
        $initializedTsfe = false;
264 151
        $initializedPageSelect = false;
265 151
        if (empty($GLOBALS['TSFE']->sys_page)) {
266 81
            if (empty($GLOBALS['TSFE'])) {
267 81
                $GLOBALS['TSFE'] = new \stdClass();
268 81
                $GLOBALS['TSFE']->tmpl = new \stdClass();
269 81
                $GLOBALS['TSFE']->tmpl->rootLine = $rootLine;
270 81
                $GLOBALS['TSFE']->sys_page = $pageSelect;
271 81
                $GLOBALS['TSFE']->id = $pageId;
272 81
                $GLOBALS['TSFE']->tx_solr_initTsfe = 1;
273 81
                $initializedTsfe = true;
274
            }
275
276 81
            $GLOBALS['TSFE']->sys_page = $pageSelect;
277 81
            $initializedPageSelect = true;
278
        }
279
            /** @var $tmpl ExtendedTemplateService */
280 151
        $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
281 151
        $tmpl->tt_track = false; // Do not log time-performance information
282 151
        $tmpl->init();
283 151
        $tmpl->runThroughTemplates($rootLine); // This generates the constants/config + hierarchy info for the template.
284 151
        $tmpl->generateConfig();
285
286 151
        $getConfigurationFromInitializedTSFEAndWriteToCache = $tmpl->ext_getSetup($tmpl->setup, $path);
287 151
        $configurationToUse = $getConfigurationFromInitializedTSFEAndWriteToCache[0];
288
289 151
        if ($initializedPageSelect) {
290 81
            $GLOBALS['TSFE']->sys_page = null;
291
        }
292 151
        if ($initializedTsfe) {
293 81
            unset($GLOBALS['TSFE']);
294
        }
295 151
        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
     * @return void
305
     */
306 24
    public static function initializeTsfe($pageId, $language = 0, $useCache = true)
307
    {
308 24
        static $tsfeCache = [];
309
310
        // resetting, a TSFE instance with data from a different page Id could be set already
311 24
        unset($GLOBALS['TSFE']);
312
313 24
        $cacheId = $pageId . '|' . $language;
314
315 24
        if (!is_object($GLOBALS['TT'])) {
316 24
            $GLOBALS['TT'] = GeneralUtility::makeInstance(TimeTracker::class, false);
317
        }
318
319 24
        if (!isset($tsfeCache[$cacheId]) || !$useCache) {
320 24
            GeneralUtility::_GETset($language, 'L');
321
322 24
            $GLOBALS['TSFE'] = GeneralUtility::makeInstance(TypoScriptFrontendController::class,
323 24
                $GLOBALS['TYPO3_CONF_VARS'], $pageId, 0);
324
325
            // for certain situations we need to trick TSFE into granting us
326
            // access to the page in any case to make getPageAndRootline() work
327
            // see http://forge.typo3.org/issues/42122
328 24
            $pageRecord = BackendUtility::getRecord('pages', $pageId, 'fe_group');
329 24
            $groupListBackup = $GLOBALS['TSFE']->gr_list;
330 24
            $GLOBALS['TSFE']->gr_list = $pageRecord['fe_group'];
331
332 24
            $GLOBALS['TSFE']->sys_page = GeneralUtility::makeInstance(PageRepository::class);
333 24
            $GLOBALS['TSFE']->getPageAndRootline();
334
335
            // restore gr_list
336 24
            $GLOBALS['TSFE']->gr_list = $groupListBackup;
337
338 24
            $GLOBALS['TSFE']->initTemplate();
339 24
            $GLOBALS['TSFE']->forceTemplateParsing = true;
340 24
            $GLOBALS['TSFE']->initFEuser();
341 24
            $GLOBALS['TSFE']->initUserGroups();
342
            //  $GLOBALS['TSFE']->getCompressedTCarray(); // seems to cause conflicts sometimes
343
344 24
            $GLOBALS['TSFE']->no_cache = true;
345 24
            $GLOBALS['TSFE']->tmpl->start($GLOBALS['TSFE']->rootLine);
346 24
            $GLOBALS['TSFE']->no_cache = false;
347 24
            $GLOBALS['TSFE']->getConfigArray();
348
349 24
            $GLOBALS['TSFE']->settingLanguage();
350 24
            if (!$useCache) {
351
                $GLOBALS['TSFE']->settingLocale();
352
            }
353
354 24
            $GLOBALS['TSFE']->newCObj();
355 24
            $GLOBALS['TSFE']->absRefPrefix = self::getAbsRefPrefixFromTSFE($GLOBALS['TSFE']);
356 24
            $GLOBALS['TSFE']->calculateLinkVars();
357
358 24
            if ($useCache) {
359 24
                $tsfeCache[$cacheId] = $GLOBALS['TSFE'];
360
            }
361
        }
362
363 24
        if ($useCache) {
364 24
            $GLOBALS['TSFE'] = $tsfeCache[$cacheId];
365 24
            $GLOBALS['TSFE']->settingLocale();
366
        }
367 24
    }
368
369
    /**
370
     * Check if record ($table, $uid) is a workspace record
371
     *
372
     * @param string $table The table the record belongs to
373
     * @param int $uid The record's uid
374
     * @return bool TRUE if the record is in a draft workspace, FALSE if it's a LIVE record
375
     */
376 39
    public static function isDraftRecord($table, $uid)
377
    {
378 39
        $isWorkspaceRecord = false;
379
380 39
        if ((ExtensionManagementUtility::isLoaded('workspaces')) && (BackendUtility::isTableWorkspaceEnabled($table))) {
381
            $record = BackendUtility::getRecord($table, $uid, 'pid, t3ver_state');
382
383
            if ($record['pid'] == '-1' || $record['t3ver_state'] > 0) {
384
                $isWorkspaceRecord = true;
385
            }
386
        }
387
388 39
        return $isWorkspaceRecord;
389
    }
390
391
    /**
392
     * Checks whether a record is a localization overlay.
393
     *
394
     * @param string $tableName The record's table name
395
     * @param array $record The record to check
396
     * @return bool TRUE if the record is a language overlay, FALSE otherwise
397
     */
398 32
    public static function isLocalizedRecord($tableName, array $record)
399
    {
400 32
        $isLocalizedRecord = false;
401
402 32
        if (isset($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])) {
403 7
            $translationOriginalPointerField = $GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'];
404
405 7
            if ($record[$translationOriginalPointerField] > 0) {
406 3
                $isLocalizedRecord = true;
407
            }
408
        }
409
410 32
        return $isLocalizedRecord;
411
    }
412
413
    /**
414
     * Check if the page type of a page record is allowed
415
     *
416
     * @param array $pageRecord The pages database row
417
     * @param string $configurationName The name of the configuration to use.
418
     *
419
     * @return bool TRUE if the page type is allowed, otherwise FALSE
420
     */
421 30
    public static function isAllowedPageType(array $pageRecord, $configurationName = 'pages')
422
    {
423 30
        $isAllowedPageType = false;
424 30
        $configurationName = is_null($configurationName) ? 'pages' : $configurationName;
425 30
        $allowedPageTypes = self::getAllowedPageTypes($pageRecord['uid'], $configurationName);
426
427 30
        if (in_array($pageRecord['doktype'], $allowedPageTypes)) {
428 29
            $isAllowedPageType = true;
429
        }
430
431 30
        return $isAllowedPageType;
432
    }
433
434
    /**
435
     * Get allowed page types
436
     *
437
     * @param int $pageId Page ID
438
     * @param string $configurationName The name of the configuration to use.
439
     *
440
     * @return array Allowed page types to compare to a doktype of a page record
441
     */
442 30
    public static function getAllowedPageTypes($pageId, $configurationName = 'pages')
443
    {
444 30
        $rootPath = '';
445 30
        $configuration = self::getConfigurationFromPageId($pageId, $rootPath);
446 30
        return $configuration->getIndexQueueAllowedPageTypesArrayByConfigurationName($configurationName);
447
    }
448
449
    /**
450
     * Resolves the configured absRefPrefix to a valid value and resolved if absRefPrefix
451
     * is set to "auto".
452
     *
453
     * @param TypoScriptFrontendController $TSFE
454
     * @return string
455
     */
456 24
    public static function getAbsRefPrefixFromTSFE(TypoScriptFrontendController $TSFE)
457
    {
458 24
        $absRefPrefix = '';
459 24
        if (empty($TSFE->config['config']['absRefPrefix'])) {
460 21
            return $absRefPrefix;
461
        }
462
463 3
        $absRefPrefix = trim($TSFE->config['config']['absRefPrefix']);
464 3
        if ($absRefPrefix === 'auto') {
465 1
            $absRefPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
466
        }
467
468 3
        return $absRefPrefix;
469
    }
470
471
    /**
472
     * @todo This method is just added for pages_language_overlay compatibility checks and will be removed when TYPO8 support is dropped
473
     * @return boolean
474
     */
475 235
    public static function getIsTYPO3VersionBelow9()
476
    {
477 235
        return (bool)version_compare(TYPO3_branch, '9.0', '<');
478
    }
479
480
    /**
481
     * @todo This method is just added for pages_language_overlay compatibility checks and will be removed when TYPO8 support is dropped
482
     * @return string
483
     */
484
    public static function getPageOverlayTableName()
485
    {
486
        return self::getIsTYPO3VersionBelow9() ? 'pages_language_overlay' : 'pages';
487
    }
488
489
    /**
490
     * This function can be used to check if one of the strings in needles is
491
     * contained in the haystack.
492
     *
493
     *
494
     * Example:
495
     *
496
     * haystack: the brown fox
497
     * needles: ['hello', 'world']
498
     * result: false
499
     *
500
     * haystack: the brown fox
501
     * needles: ['is', 'fox']
502
     * result: true
503
     *
504
     * @param string $haystack
505
     * @param array $needles
506
     * @return bool
507
     */
508 52
    public static function containsOneOfTheStrings($haystack, array $needles)
509
    {
510 52
        foreach ($needles as $needle) {
511 52
            $position = strpos($haystack, $needle);
512 52
            if ($position !== false) {
513 52
                return true;
514
            }
515
        }
516
517 49
        return false;
518
    }
519
}
520