Passed
Pull Request — master (#1491)
by Georg
20:26 queued 04:30
created

Util::underscoredToUpperCamelCase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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