Completed
Push — master ( c7f02f...d53d83 )
by Timo
14:49
created

Site::clearSitePagesCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
namespace ApacheSolrForTypo3\Solr;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2011-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\Site\SiteHashService;
28
use ApacheSolrForTypo3\Solr\Domain\Index\Queue\RecordMonitor\Helper\ConfigurationAwareRecordService;
29
use TYPO3\CMS\Backend\Utility\BackendUtility;
30
use TYPO3\CMS\Core\Registry;
31
use TYPO3\CMS\Core\Utility\GeneralUtility;
32
use TYPO3\CMS\Frontend\Page\PageRepository;
33
34
/**
35
 * A site is a branch in a TYPO3 installation. Each site's root page is marked
36
 * by the "Use as Root Page" flag.
37
 *
38
 * @author Ingo Renner <[email protected]>
39
 */
40
class Site
41
{
42
    /**
43
     * Cache for ApacheSolrForTypo3\Solr\Site objects
44
     *
45
     * @var array
46
     */
47
    protected static $sitesCache = [];
48
49
    /**
50
     * Small cache for the list of pages in a site, so that the results of this
51
     * rather expensive operation can be used by all initializers without having
52
     * each initializer do it again.
53
     *
54
     * TODO Move to caching framework once TYPO3 4.6 is the minimum required
55
     * version.
56
     *
57
     * @var array
58
     */
59
    protected static $sitePagesCache = [];
60
61
    /**
62
     * Root page record.
63
     *
64
     * @var array
65
     */
66
    protected $rootPage = [];
67
68
    /**
69
     * The site's sys_language_mode
70
     *
71
     * @var string
72
     */
73
    protected $sysLanguageMode = null;
74
75
    /**
76
     * Constructor.
77
     *
78
     * @param int $rootPageId Site root page ID (uid). The page must be marked as site root ("Use as Root Page" flag).
79
     */
80 73
    public function __construct($rootPageId)
81
    {
82 73
        $page = BackendUtility::getRecord('pages', $rootPageId);
83
84 73
        if (!self::isRootPage($page)) {
0 ignored issues
show
Bug introduced by
It seems like $page defined by \TYPO3\CMS\Backend\Utili...d('pages', $rootPageId) on line 82 can also be of type null; however, ApacheSolrForTypo3\Solr\Site::isRootPage() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
85
            throw new \InvalidArgumentException(
86
                'The page for the given page ID \'' . $rootPageId
87
                . '\' is not marked as root page and can therefore not be used as site root page.',
88
                1309272922
89
            );
90
        }
91
92 73
        $this->rootPage = $page;
0 ignored issues
show
Documentation Bug introduced by
It seems like $page can be null. However, the property $rootPage is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
93 73
    }
94
95
    /**
96
     * Gets the Site for a specific page Id.
97
     *
98
     * @param int $pageId The page Id to get a Site object for.
99
     * @return Site Site for the given page Id.
100
     */
101 57
    public static function getSiteByPageId($pageId)
102
    {
103 57
        $rootPageId = Util::getRootPageId($pageId);
104
105 57
        if (!isset(self::$sitesCache[$rootPageId])) {
106 57
            self::$sitesCache[$rootPageId] = GeneralUtility::makeInstance(__CLASS__,
107
                $rootPageId);
108
        }
109
110 57
        return self::$sitesCache[$rootPageId];
111
    }
112
113
    /**
114
     * Creates a dropdown selector of available TYPO3 sites with Solr
115
     * configured.
116
     *
117
     * @param string $selectorName Name to be used in the select's name attribute
118
     * @param Site $selectedSite Optional, currently selected site
119
     * @return string Site selector HTML code
120
     * @todo Extract into own class like indexing configuration selector
121
     */
122
    public static function getAvailableSitesSelector(
123
        $selectorName,
124
        Site $selectedSite = null
125
    ) {
126
        $sites = self::getAvailableSites();
127
        $selector = '<select name="' . $selectorName . '" class="form-control">';
128
129
        foreach ($sites as $site) {
130
            $selectedAttribute = '';
131
            if ($selectedSite !== null && $site->getRootPageId() == $selectedSite->getRootPageId()) {
132
                $selectedAttribute = ' selected="selected"';
133
            }
134
135
            $selector .= '<option value="' . $site->getRootPageId() . '"' . $selectedAttribute . '>'
136
                . $site->getLabel()
137
                . '</option>';
138
        }
139
140
        $selector .= '</select>';
141
142
        return $selector;
143
    }
144
145
    /**
146
     * Gets all available TYPO3 sites with Solr configured.
147
     *
148
     * @param bool $stopOnInvalidSite
149
     *
150
     * @return Site[] An array of available sites
151
     */
152 22
    public static function getAvailableSites($stopOnInvalidSite = false)
153
    {
154 22
        static $sitesCached;
155 22
        $sites = [];
156
157
        // Check if $sites has been cached
158 22
        if (isset($sitesCached)) {
159 1
            return $sitesCached;
160
        }
161
162 22
        $servers = self::getSolrServersFromRegistry();
163
164 22
        foreach ($servers as $server) {
165 22
            if (isset($sites[$server['rootPageUid']])) {
166
                //get each site only once
167
                continue;
168
            }
169
170
            try {
171 22
                $sites[$server['rootPageUid']] = GeneralUtility::makeInstance(__CLASS__, $server['rootPageUid']);
172
            } catch (\InvalidArgumentException $e) {
173
                if ($stopOnInvalidSite) {
174 22
                    throw $e;
175
                }
176
            }
177
        }
178
179 22
        $sitesCached = $sites;
180
181 22
        return $sitesCached;
182
    }
183
184
    /**
185
     * Returns the first available Site.
186
     *
187
     * @param bool $stopOnInvalidSite
188
     *
189
     * @return Site
190
     */
191 20
    public static function getFirstAvailableSite($stopOnInvalidSite = false)
192
    {
193 20
        $sites = self::getAvailableSites($stopOnInvalidSite);
194 20
        return array_shift($sites);
195
    }
196
197
    /**
198
     * Clears the $sitePagesCache
199
     *
200
     */
201
    public static function clearSitePagesCache()
202
    {
203
        self::$sitePagesCache = [];
204
    }
205
206
    /**
207
     * Takes an pagerecord and checks whether the page is marked as root page.
208
     *
209
     * @param array $page pagerecord
210
     * @return bool true if the page is marked as root page, false otherwise
211
     */
212 99
    public static function isRootPage($page)
213
    {
214 99
        if ($page['is_siteroot']) {
215 99
            return true;
216
        }
217
218 45
        return false;
219
    }
220
221
    /**
222
     * Gets the site's root page ID (uid).
223
     *
224
     * @return int The site's root page ID.
225
     */
226 30
    public function getRootPageId()
227
    {
228 30
        return $this->rootPage['uid'];
229
    }
230
231
    /**
232
     * Gets the site's label. The label is build from the the site title and root
233
     * page ID (uid).
234
     *
235
     * @return string The site's label.
236
     */
237 9
    public function getLabel()
238
    {
239 9
        $rootlineTitles = [];
240 9
        $rootLine = BackendUtility::BEgetRootLine($this->rootPage['uid']);
241
        // Remove last
242 9
        array_pop($rootLine);
243 9
        $rootLine = array_reverse($rootLine);
244 9
        foreach ($rootLine as $rootLineItem) {
245 9
            $rootlineTitles[] = $rootLineItem['title'];
246
        }
247 9
        return implode(' - ', $rootlineTitles) . ', Root Page ID: ' . $this->rootPage['uid'];
248
    }
249
250
    /**
251
     * Retrieves the configured solr servers from the registry.
252
     *
253
     * @return array
254
     */
255 22
    protected static function getSolrServersFromRegistry()
256
    {
257
        /** @var $registry Registry */
258 22
        $registry = GeneralUtility::makeInstance(Registry::class);
259 22
        $servers = (array) $registry->get('tx_solr', 'servers', []);
260 22
        return $servers;
261
    }
262
263
    /**
264
     * Gets the site's Solr TypoScript configuration (plugin.tx_solr.*)
265
     *
266
     * @return  \ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration The Solr TypoScript configuration
267
     */
268 22
    public function getSolrConfiguration()
269
    {
270 22
        return Util::getSolrConfigurationFromPageId($this->rootPage['uid']);
271
    }
272
273
    /**
274
     * Gets the system languages (IDs) for which Solr connections have been
275
     * configured.
276
     *
277
     * @return array Array of system language IDs for which connections have been configured on this site.
278
     */
279
    public function getLanguages()
280
    {
281
        $siteLanguages = [];
282
283
        $servers = self::getSolrServersFromRegistry();
284
285
        foreach ($servers as $connectionKey => $solrConnection) {
286
            list($siteRootPageId, $systemLanguageId) = explode('|',
287
                $connectionKey);
288
289
            if ($siteRootPageId == $this->rootPage['uid']) {
290
                $siteLanguages[] = $systemLanguageId;
291
            }
292
        }
293
294
        return $siteLanguages;
295
    }
296
297
    /**
298
     * Gets the site's default language as configured in
299
     * config.sys_language_uid. If sys_language_uid is not set, 0 is assumed to
300
     * be the default.
301
     *
302
     * @return int The site's default language.
303
     */
304 1
    public function getDefaultLanguage()
305
    {
306 1
        $siteDefaultLanguage = 0;
307
308 1
        $configuration = Util::getConfigurationFromPageId(
309 1
            $this->rootPage['uid'],
310 1
            'config',
311 1
            false,
312 1
            false
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
313
        );
314
315 1
        $siteDefaultLanguage = $configuration->getValueByPathOrDefaultValue('sys_language_uid', $siteDefaultLanguage);
316
        // default language is set through default L GET parameter -> overruling config.sys_language_uid
317 1
        $siteDefaultLanguage = $configuration->getValueByPathOrDefaultValue('defaultGetVars.L', $siteDefaultLanguage);
318
319 1
        return $siteDefaultLanguage;
320
    }
321
322
    /**
323
     * Generates a list of page IDs in this site. Attention, this includes
324
     * all page types! Deleted pages are not included.
325
     *
326
     * @param int|string $rootPageId Page ID from where to start collection sub pages
327
     * @param int $maxDepth Maximum depth to descend into the site tree
328
     * @return array Array of pages (IDs) in this site
329
     */
330 8
    public function getPages($rootPageId = 'SITE_ROOT', $maxDepth = 999)
331
    {
332
        // when we have a cached value, we can return it.
333 8
        if (!empty(self::$sitePagesCache[$rootPageId])) {
334 7
            return self::$sitePagesCache[$rootPageId];
335
        }
336
337 8
        $pageIds = [];
338 8
        $maxDepth = intval($maxDepth);
339
340 8
        $recursionRootPageId = intval($rootPageId);
341 8
        if ($rootPageId == 'SITE_ROOT') {
342 8
            $recursionRootPageId = $this->rootPage['uid'];
343 8
            $pageIds[] = (int) $this->rootPage['uid'];
344
        }
345
346 8
        if ($maxDepth <= 0) {
347
            // exiting the recursion loop, may write to cache now
348
            self::$sitePagesCache[$rootPageId] = $pageIds;
349
            return $pageIds;
350
        }
351
352
        // get the page ids of the current level and if needed call getPages recursive
353 8
        $pageIds = $this->getPageIdsFromCurrentDepthAndCallRecursive($maxDepth, $recursionRootPageId, $pageIds);
354
355
        // exiting the recursion loop, may write to cache now
356 8
        self::$sitePagesCache[$rootPageId] = $pageIds;
357 8
        return $pageIds;
358
    }
359
360
    /**
361
     * This method retrieves the pages ids from the current tree level an calls getPages recursive,
362
     * when the maxDepth has not been reached.
363
     *
364
     * @param int $maxDepth
365
     * @param int $recursionRootPageId
366
     * @param array $pageIds
367
     * @return array
368
     */
369 8
    protected function getPageIdsFromCurrentDepthAndCallRecursive($maxDepth, $recursionRootPageId, $pageIds)
370
    {
371 8
        static $initialPagesAdditionalWhereClause;
372
373
        // Only fetch $initialPagesAdditionalWhereClause on first call
374 8
        if (empty($initialPagesAdditionalWhereClause)) {
375 8
            $configurationAwareRecordService = GeneralUtility::makeInstance(ConfigurationAwareRecordService::class);
376
            // Fetch configuration in order to be able to read initialPagesAdditionalWhereClause
377 8
            $solrConfiguration = $this->getSolrConfiguration();
378 8
            $indexQueueConfigurationName = $configurationAwareRecordService->getIndexingConfigurationName('pages', $this->rootPage['uid'], $solrConfiguration);
379 8
            $initialPagesAdditionalWhereClause = $solrConfiguration->getInitialPagesAdditionalWhereClause($indexQueueConfigurationName);
380
        }
381
382 8
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid = ' . $recursionRootPageId . ' ' . BackendUtility::deleteClause('pages') . $initialPagesAdditionalWhereClause);
383
384 8
        while ($page = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
385 6
            $pageIds[] = (int) $page['uid'];
386
387 6
            if ($maxDepth > 1) {
388 6
                $pageIds = array_merge($pageIds, $this->getPages($page['uid'], $maxDepth - 1));
389
            }
390
        }
391 8
        $GLOBALS['TYPO3_DB']->sql_free_result($result);
392 8
        return $pageIds;
393
    }
394
395
    /**
396
     * Generates the site's unique Site Hash.
397
     *
398
     * The Site Hash is build from the site's main domain, the system encryption
399
     * key, and the extension "tx_solr". These components are concatenated and
400
     * sha1-hashed.
401
     *
402
     * @return string Site Hash.
403
     */
404 52
    public function getSiteHash()
405
    {
406
        /** @var $siteHashService SiteHashService */
407 52
        $siteHashService = GeneralUtility::makeInstance(SiteHashService::class);
408 52
        return $siteHashService->getSiteHashForDomain($this->getDomain());
409
    }
410
411
    /**
412
     * Gets the site's main domain. More specifically the first domain record in
413
     * the site tree.
414
     *
415
     * @return string The site's main domain.
416
     */
417 56
    public function getDomain()
418
    {
419 56
        $pageSelect = GeneralUtility::makeInstance(PageRepository::class);
420 56
        $rootLine = $pageSelect->getRootLine($this->rootPage['uid']);
421
422 56
        return BackendUtility::firstDomainRecord($rootLine);
423
    }
424
425
    /**
426
     * Gets the site's root page.
427
     *
428
     * @return array The site's root page.
429
     */
430 1
    public function getRootPage()
431
    {
432 1
        return $this->rootPage;
433
    }
434
435
    /**
436
     * Gets the site's root page's title.
437
     *
438
     * @return string The site's root page's title
439
     */
440
    public function getTitle()
441
    {
442
        return $this->rootPage['title'];
443
    }
444
445
    /**
446
     * Gets the site's config.sys_language_mode setting
447
     *
448
     * @return string The site's config.sys_language_mode
449
     */
450 11
    public function getSysLanguageMode()
451
    {
452 11
        if (is_null($this->sysLanguageMode)) {
453 11
            Util::initializeTsfe($this->getRootPageId());
454 11
            $this->sysLanguageMode = $GLOBALS['TSFE']->sys_language_mode;
455
        }
456
457 11
        return $this->sysLanguageMode;
458
    }
459
}
460