Passed
Pull Request — master (#1264)
by Timo
46:03 queued 42:05
created

ConnectionManager   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 548
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 92.24%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 7
dl 0
loc 548
ccs 202
cts 219
cp 0.9224
rs 8.439
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getRootPages() 0 10 1
B getConnection() 0 30 4
A buildSolrService() 0 4 1
A getConnectionFromConfiguration() 0 11 1
B getConfigurationByPageId() 0 25 2
A getConnectionByPageId() 0 6 1
A getConfigurationByRootPageId() 0 23 2
A getConnectionByRootPageId() 0 7 1
A getAllConfigurations() 0 8 1
A setAllConfigurations() 0 6 1
A getAllConnections() 0 11 2
A getConfigurationsBySite() 0 13 3
A getConnectionsBySite() 0 11 2
B getConfiguredSolrConnections() 0 22 4
A manipulateCacheActions() 0 13 2
A updateConnections() 0 9 2
A updateConnectionsInCacheMenu() 0 4 1
A updateConnectionByRootPageId() 0 21 3
A getConfiguredSolrConnectionByRootPage() 0 52 3
A getLanguageName() 0 18 3
A buildConnectionLabel() 0 13 1
A filterDuplicateConnections() 0 20 3
A getSystemLanguages() 0 19 3

How to fix   Complexity   

Complex Class

Complex classes like ConnectionManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ConnectionManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace ApacheSolrForTypo3\Solr;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2010-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\SiteRepository;
28
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
29
use ApacheSolrForTypo3\Solr\System\Page\Rootline;
30
use TYPO3\CMS\Backend\Routing\UriBuilder;
31
use TYPO3\CMS\Backend\Toolbar\ClearCacheActionsHookInterface;
32
use TYPO3\CMS\Core\Imaging\Icon;
33
use TYPO3\CMS\Core\Imaging\IconFactory;
34
use TYPO3\CMS\Core\Registry;
35
use TYPO3\CMS\Core\SingletonInterface;
36
use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
37
use TYPO3\CMS\Core\Utility\GeneralUtility;
38
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
39
use TYPO3\CMS\Frontend\Page\PageRepository;
40
41
/**
42
 * A class to easily create a connection to a Solr server.
43
 *
44
 * Internally keeps track of already existing connections and makes sure that no
45
 * duplicate connections are created.
46
 *
47
 * @author Ingo Renner <[email protected]>
48
 */
49
class ConnectionManager implements SingletonInterface, ClearCacheActionsHookInterface
50
{
51
52
    /**
53
     * @var array
54
     */
55
    protected static $connections = [];
56
57
    /**
58
     * @var \ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager
59
     */
60
    protected $logger = null;
61
62
    /**
63
     * Gets a Solr connection.
64
     *
65
     * Instead of generating a new connection with each call, connections are
66
     * kept and checked whether the requested connection already exists. If a
67
     * connection already exists, it's reused.
68
     *
69
     * @param string $host Solr host (optional)
70
     * @param int $port Solr port (optional)
71
     * @param string $path Solr path (optional)
72
     * @param string $scheme Solr scheme, defaults to http, can be https (optional)
73
     * @param string $username Solr user name (optional)
74
     * @param string $password Solr password (optional)
75
     * @return SolrService A solr connection.
76
     */
77
78 76
    public function getConnection($host = '', $port = 8983, $path = '/solr/', $scheme = 'http', $username = '', $password = '')
79
    {
80 76
        if (empty($host)) {
81 1
            $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__);
82 1
            $this->logger->log(
83 1
                SolrLogManager::WARNING,
84 1
                'ApacheSolrForTypo3\Solr\ConnectionManager::getConnection() called with empty host parameter. Using configuration from TSFE, might be inaccurate. Always provide a host or use the getConnectionBy* methods.'
85
            );
86
87 1
            $configuration = Util::getSolrConfiguration();
88 1
            $host = $configuration->getSolrHost();
89 1
            $port = $configuration->getSolrPort();
90 1
            $path = $configuration->getSolrPath();
91 1
            $scheme = $configuration->getSolrScheme();
92 1
            $username = $configuration->getSolrUsername();
93 1
            $password = $configuration->getSolrPassword();
94
        }
95
96 76
        $connectionHash = md5($scheme . '://' . $host . $port . $path . $username . $password);
97 76
        if (!isset(self::$connections[$connectionHash])) {
98 76
            $connection = $this->buildSolrService($host, $port, $path, $scheme);
99 75
            if (trim($username) !== '') {
100 1
                $connection->setAuthenticationCredentials($username, $password);
101
            }
102
103 75
            self::$connections[$connectionHash] = $connection;
104
        }
105
106 75
        return self::$connections[$connectionHash];
107
    }
108
109
    /**
110
     * Create a Solr Service instance from the passed connection configuration.
111
     *
112
     * @param string $host
113
     * @param int $port
114
     * @param string $path
115
     * @param string $scheme
116
     * @return SolrService|object
117
     */
118 71
    protected function buildSolrService($host, $port, $path, $scheme)
119
    {
120 71
        return GeneralUtility::makeInstance(SolrService::class, $host, $port, $path, $scheme);
121
    }
122
123
    /**
124
     * Creates a solr configuration from the configuration array and returns it.
125
     *
126
     * @param array $config The solr configuration array
127
     * @return SolrService
128
     */
129 69
    protected function getConnectionFromConfiguration(array $config)
130
    {
131 69
        return $this->getConnection(
132 69
            $config['solrHost'],
133 69
            $config['solrPort'],
134 69
            $config['solrPath'],
135 69
            $config['solrScheme'],
136 69
            $config['solrUsername'],
137 69
            $config['solrPassword']
138
        );
139
    }
140
141
    /**
142
     * Gets a Solr configuration for a page ID.
143
     *
144
     * @param int $pageId A page ID.
145
     * @param int $language The language ID to get the connection for as the path may differ. Optional, defaults to 0.
146
     * @param string $mount Comma list of MountPoint parameters
147
     * @return array A solr configuration.
148
     * @throws NoSolrConnectionFoundException
149
     */
150 59
    public function getConfigurationByPageId($pageId, $language = 0, $mount = '')
151
    {
152
        // find the root page
153 59
        $pageSelect = GeneralUtility::makeInstance(PageRepository::class);
154
155
        /** @var Rootline $rootLine */
156 59
        $rootLine = GeneralUtility::makeInstance(Rootline::class, $pageSelect->getRootLine($pageId, $mount));
157 59
        $siteRootPageId = $rootLine->getRootPageId();
158
159
        try {
160 59
            $solrConfiguration = $this->getConfigurationByRootPageId($siteRootPageId, $language);
161 2
        } catch (NoSolrConnectionFoundException $nscfe) {
162
            /* @var $noSolrConnectionException NoSolrConnectionFoundException */
163 2
            $noSolrConnectionException = GeneralUtility::makeInstance(
164 2
                NoSolrConnectionFoundException::class,
165 2
                $nscfe->getMessage() . ' Initial page used was [' . $pageId . ']',
166 2
                1275399922
167
            );
168 2
            $noSolrConnectionException->setPageId($pageId);
169
170 2
            throw $noSolrConnectionException;
171
        }
172
173 58
        return $solrConfiguration;
174
    }
175
176
    /**
177
     * Gets a Solr connection for a page ID.
178
     *
179
     * @param int $pageId A page ID.
180
     * @param int $language The language ID to get the connection for as the path may differ. Optional, defaults to 0.
181
     * @param string $mount Comma list of MountPoint parameters
182
     * @return SolrService A solr connection.
183
     * @throws NoSolrConnectionFoundException
184
     */
185 59
    public function getConnectionByPageId($pageId, $language = 0, $mount = '')
186
    {
187 59
        $solrServer = $this->getConfigurationByPageId($pageId, $language, $mount);
188 58
        $solrConnection = $this->getConnectionFromConfiguration($solrServer);
189 58
        return $solrConnection;
190
    }
191
192
    /**
193
     * Gets a Solr configuration for a root page ID.
194
     *
195
     * @param int $pageId A root page ID.
196
     * @param int $language The language ID to get the configuration for as the path may differ. Optional, defaults to 0.
197
     * @return array A solr configuration.
198
     * @throws NoSolrConnectionFoundException
199
     */
200 60
    public function getConfigurationByRootPageId($pageId, $language = 0)
201
    {
202 60
        $connectionKey = $pageId . '|' . $language;
203 60
        $solrServers = $this->getAllConfigurations();
204
205 60
        if (isset($solrServers[$connectionKey])) {
206 58
            $solrConfiguration = $solrServers[$connectionKey];
207
        } else {
208
            /* @var $noSolrConnectionException NoSolrConnectionFoundException */
209 3
            $noSolrConnectionException = GeneralUtility::makeInstance(
210 3
                NoSolrConnectionFoundException::class,
211
                'Could not find a Solr connection for root page ['
212 3
                . $pageId . '] and language [' . $language . '].',
213 3
                1275396474
214
            );
215 3
            $noSolrConnectionException->setRootPageId($pageId);
216 3
            $noSolrConnectionException->setLanguageId($language);
217
218 3
            throw $noSolrConnectionException;
219
        }
220
221 58
        return $solrConfiguration;
222
    }
223
224
    /**
225
     * Gets a Solr connection for a root page ID.
226
     *
227
     * @param int $pageId A root page ID.
228
     * @param int $language The language ID to get the connection for as the path may differ. Optional, defaults to 0.
229
     * @return SolrService A solr connection.
230
     * @throws NoSolrConnectionFoundException
231
     */
232 6
    public function getConnectionByRootPageId($pageId, $language = 0)
233
    {
234 6
        $config = $this->getConfigurationByRootPageId($pageId, $language);
235 6
        $solrConnection = $this->getConnectionFromConfiguration($config);
236
237 6
        return $solrConnection;
238
    }
239
240
    /**
241
     * Gets all connection configurations found.
242
     *
243
     * @return array An array of connection configurations.
244
     */
245 73
    public function getAllConfigurations()
246
    {
247
        /** @var $registry Registry */
248 73
        $registry = GeneralUtility::makeInstance(Registry::class);
249 73
        $solrConfigurations = $registry->get('tx_solr', 'servers', []);
250
251 73
        return $solrConfigurations;
252
    }
253
254
    /**
255
     * Stores the connections in the registry.
256
     *
257
     * @param array $solrConfigurations
258
     */
259 3
    protected function setAllConfigurations(array $solrConfigurations)
260
    {
261
        /** @var $registry Registry */
262 3
        $registry = GeneralUtility::makeInstance(Registry::class);
263 3
        $registry->set('tx_solr', 'servers', $solrConfigurations);
264 3
    }
265
266
    /**
267
     * Gets all connections found.
268
     *
269
     * @return SolrService[] An array of initialized ApacheSolrForTypo3\Solr\SolrService connections
270
     */
271 7
    public function getAllConnections()
272
    {
273 7
        $connections = [];
274
275 7
        $solrConfigurations = $this->getAllConfigurations();
276 7
        foreach ($solrConfigurations as $solrConfiguration) {
277 7
            $connections[] = $this->getConnectionFromConfiguration($solrConfiguration);
278
        }
279
280 7
        return $connections;
281
    }
282
283
    /**
284
     * Gets all connection configurations for a given site.
285
     *
286
     * @param Site $site A TYPO3 site
287
     * @return array An array of Solr connection configurations for a site
288
     */
289 22
    public function getConfigurationsBySite(Site $site)
290
    {
291 22
        $solrConfigurations = [];
292
293 22
        $allConfigurations = $this->getAllConfigurations();
294 22
        foreach ($allConfigurations as $configuration) {
295 22
            if ($configuration['rootPageUid'] == $site->getRootPageId()) {
296 22
                $solrConfigurations[] = $configuration;
297
            }
298
        }
299
300 22
        return $solrConfigurations;
301
    }
302
303
    /**
304
     * Gets all connections configured for a given site.
305
     *
306
     * @param Site $site A TYPO3 site
307
     * @return SolrService[] An array of Solr connection objects (ApacheSolrForTypo3\Solr\SolrService)
308
     */
309 16
    public function getConnectionsBySite(Site $site)
310
    {
311 16
        $connections = [];
312
313 16
        $solrServers = $this->getConfigurationsBySite($site);
314 16
        foreach ($solrServers as $solrServer) {
315 16
            $connections[] = $this->getConnectionFromConfiguration($solrServer);
316
        }
317
318 16
        return $connections;
319
    }
320
321
    // updates
322
323
    /**
324
     * Adds a menu entry to the clear cache menu to detect Solr connections.
325
     *
326
     * @param array $cacheActions Array of CacheMenuItems
327
     * @param array $optionValues Array of AccessConfigurations-identifiers (typically  used by userTS with options.clearCache.identifier)
328
     */
329
    public function manipulateCacheActions(&$cacheActions, &$optionValues)
330
    {
331
        if ($GLOBALS['BE_USER']->isAdmin()) {
332
            $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
333
            $optionValues[] = 'clearSolrConnectionCache';
334
            $cacheActions[] = [
335
                'id' => 'clearSolrConnectionCache',
336
                'title' => 'LLL:EXT:solr/Resources/Private/Language/locallang.xlf:cache_initialize_solr_connections',
337
                'href' => $uriBuilder->buildUriFromRoute('ajax_solr_updateConnections'),
338
                'iconIdentifier' => 'extensions-solr-module-initsolrconnections'
339
            ];
340
        }
341
    }
342
343
    /**
344
     * Updates the connections in the registry.
345
     *
346
     */
347 2
    public function updateConnections()
348
    {
349 2
        $solrConnections = $this->getConfiguredSolrConnections();
350 2
        $solrConnections = $this->filterDuplicateConnections($solrConnections);
351
352 2
        if (!empty($solrConnections)) {
353 2
            $this->setAllConfigurations($solrConnections);
354
        }
355 2
    }
356
357
    /**
358
     * Entrypoint for the ajax request
359
     */
360
    public function updateConnectionsInCacheMenu()
361
    {
362
        $this->updateConnections();
363
    }
364
365
    /**
366
     * Updates the Solr connections for a specific root page ID / site.
367
     *
368
     * @param int $rootPageId A site root page id
369
     */
370 1
    public function updateConnectionByRootPageId($rootPageId)
371
    {
372 1
        $systemLanguages = $this->getSystemLanguages();
373 1
        $siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
374 1
        $site = $siteRepository->getSiteByRootPageId($rootPageId);
375 1
        $rootPage = $site->getRootPage();
376
377 1
        $updatedSolrConnections = [];
378 1
        foreach ($systemLanguages as $languageId) {
379 1
            $connection = $this->getConfiguredSolrConnectionByRootPage($rootPage, $languageId);
380
381 1
            if (!empty($connection)) {
382 1
                $updatedSolrConnections[$connection['connectionKey']] = $connection;
383
            }
384
        }
385
386 1
        $solrConnections = $this->getAllConfigurations();
387 1
        $solrConnections = array_merge($solrConnections, $updatedSolrConnections);
388 1
        $solrConnections = $this->filterDuplicateConnections($solrConnections);
389 1
        $this->setAllConfigurations($solrConnections);
390 1
    }
391
392
    /**
393
     * Finds the configured Solr connections. Also respects multi-site
394
     * environments.
395
     *
396
     * @return array An array with connections, each connection with keys rootPageTitle, rootPageUid, solrHost, solrPort, solrPath
397
     */
398 2
    protected function getConfiguredSolrConnections()
399
    {
400 2
        $configuredSolrConnections = [];
401
402
        // find website roots and languages for this installation
403 2
        $rootPages = $this->getRootPages();
404 2
        $languages = $this->getSystemLanguages();
405
406
        // find solr configurations and add them as function menu entries
407 2
        foreach ($rootPages as $rootPage) {
408 2
            foreach ($languages as $languageId) {
409 2
                $connection = $this->getConfiguredSolrConnectionByRootPage($rootPage,
410
                    $languageId);
411
412 2
                if (!empty($connection)) {
413 2
                    $configuredSolrConnections[$connection['connectionKey']] = $connection;
414
                }
415
            }
416
        }
417
418 2
        return $configuredSolrConnections;
419
    }
420
421
    /**
422
     * Gets the configured Solr connection for a specific root page and language ID.
423
     *
424
     * @param array $rootPage A root page record with at least title and uid
425
     * @param int $languageId ID of a system language
426
     * @return array A solr connection configuration.
427
     */
428 3
    protected function getConfiguredSolrConnectionByRootPage(array $rootPage, $languageId)
429
    {
430 3
        $connection = [];
431
432 3
        $languageId = intval($languageId);
433 3
        GeneralUtility::_GETset($languageId, 'L');
434 3
        $connectionKey = $rootPage['uid'] . '|' . $languageId;
435
436 3
        $pageSelect = GeneralUtility::makeInstance(PageRepository::class);
437 3
        $rootLine = $pageSelect->getRootLine($rootPage['uid']);
438
439 3
        $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
440 3
        $tmpl->tt_track = false; // Do not log time-performance information
441 3
        $tmpl->init();
442 3
        $tmpl->runThroughTemplates($rootLine); // This generates the constants/config + hierarchy info for the template.
443
444
        // fake micro TSFE to get correct condition parsing
445 3
        $GLOBALS['TSFE'] = new \stdClass();
446 3
        $GLOBALS['TSFE']->tmpl = new \stdClass();
447 3
        $GLOBALS['TSFE']->cObjectDepthCounter = 50;
448 3
        $GLOBALS['TSFE']->tmpl->rootLine = $rootLine;
449 3
        $GLOBALS['TSFE']->sys_page = $pageSelect;
450 3
        $GLOBALS['TSFE']->id = $rootPage['uid'];
451 3
        $GLOBALS['TSFE']->page = $rootPage;
452
453 3
        $tmpl->generateConfig();
454 3
        $GLOBALS['TSFE']->tmpl->setup = $tmpl->setup;
455
456 3
        $configuration = Util::getSolrConfigurationFromPageId($rootPage['uid'], false, $languageId);
457
458 3
        $solrIsEnabledAndConfigured = $configuration->getEnabled() && $configuration->getSolrHasConnectionConfiguration();
459 3
        if (!$solrIsEnabledAndConfigured) {
460
            return $connection;
461
        }
462
463
        $connection = [
464 3
            'connectionKey' => $connectionKey,
465 3
            'rootPageTitle' => $rootPage['title'],
466 3
            'rootPageUid' => $rootPage['uid'],
467 3
            'solrScheme' => $configuration->getSolrScheme(),
468 3
            'solrHost' => $configuration->getSolrHost(),
469 3
            'solrPort' => $configuration->getSolrPort(),
470 3
            'solrPath' => $configuration->getSolrPath(),
471 3
            'solrUsername' => $configuration->getSolrUsername(),
472 3
            'solrPassword' => $configuration->getSolrPassword(),
473
474 3
            'language' => $languageId
475
        ];
476
477 3
        $connection['label'] = $this->buildConnectionLabel($connection);
478 3
        return $connection;
479
    }
480
481
    /**
482
     * Gets the language name for a given language ID.
483
     *
484
     * @param int $languageId language ID
485
     * @return string Language name
486
     */
487 3
    protected function getLanguageName($languageId)
488
    {
489 3
        $languageName = '';
490
491 3
        $language = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
492 3
            'uid, title',
493 3
            'sys_language',
494 3
            'uid = ' . (integer)$languageId
495
        );
496
497 3
        if (count($language)) {
498
            $languageName = $language[0]['title'];
499 3
        } elseif ($languageId == 0) {
500 3
            $languageName = 'default';
501
        }
502
503 3
        return $languageName;
504
    }
505
506
    /**
507
     * Creates a human readable label from the connections' configuration.
508
     *
509
     * @param array $connection Connection configuration
510
     * @return string Connection label
511
     */
512 3
    protected function buildConnectionLabel(array $connection)
513
    {
514 3
        $connectionLabel = $connection['rootPageTitle']
515 3
            . ' (pid: ' . $connection['rootPageUid']
516 3
            . ', language: ' . $this->getLanguageName($connection['language'])
517 3
            . ') - '
518
#			. $connection['solrScheme'] . '://'
519 3
            . $connection['solrHost'] . ':'
520 3
            . $connection['solrPort']
521 3
            . $connection['solrPath'];
522
523 3
        return $connectionLabel;
524
    }
525
526
    /**
527
     * Filters duplicate connections. When detecting the configured connections
528
     * this is done with a little brute force by simply combining all root pages
529
     * with all languages, this method filters out the duplicates.
530
     *
531
     * @param array $connections An array of unfiltered connections, containing duplicates
532
     * @return array An array with connections, no duplicates.
533
     */
534 3
    protected function filterDuplicateConnections(array $connections)
535
    {
536 3
        $hashedConnections = [];
537 3
        $filteredConnections = [];
538
539
        // array_unique() doesn't work on multi dimensional arrays, so we need to flatten it first
540 3
        foreach ($connections as $key => $connection) {
541 3
            unset($connection['language']);
542 3
            $connectionHash = md5(implode('|', $connection));
543 3
            $hashedConnections[$key] = $connectionHash;
544
        }
545
546 3
        $hashedConnections = array_unique($hashedConnections);
547
548 3
        foreach ($hashedConnections as $key => $hash) {
549 3
            $filteredConnections[$key] = $connections[$key];
550
        }
551
552 3
        return $filteredConnections;
553
    }
554
555
    /**
556
     * Finds the system's configured languages.
557
     *
558
     * @return array An array of language IDs
559
     */
560 3
    protected function getSystemLanguages()
561
    {
562 3
        $languages = [0];
563
564 3
        $languageRecords = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
565 3
            'uid',
566 3
            'sys_language',
567 3
            'hidden = 0'
568
        );
569
570 3
        if (!is_array($languageRecords)) {
571
            return $languages;
572
        }
573
574 3
        foreach ($languageRecords as $languageRecord) {
575
            $languages[] = $languageRecord['uid'];
576
        }
577 3
        return $languages;
578
    }
579
580
    /**
581
     * Gets the site's root pages. The "Is root of website" flag must be set,
582
     * which usually is the case for pages with pid = 0.
583
     *
584
     * @return array An array of (partial) root page records, containing the uid and title fields
585
     */
586 2
    protected function getRootPages()
587
    {
588 2
        $rootPages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
589 2
            'uid, title',
590 2
            'pages',
591 2
            'is_siteroot = 1 AND deleted = 0 AND hidden = 0 AND pid != -1'
592
        );
593
594 2
        return $rootPages;
595
    }
596
}
597