Passed
Push — release-11.0.x ( 534ada...88d5f5 )
by Rafael
23:03 queued 20:08
created

PageIndexer   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 316
Duplicated Lines 0 %

Test Coverage

Coverage 46.39%

Importance

Changes 0
Metric Value
wmc 29
eloc 113
dl 0
loc 316
ccs 77
cts 166
cp 0.4639
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getIndexQueueItem() 0 5 1
A getHighestAuthenticationServicePriority() 0 13 4
A generatePageUrl() 0 27 4
A getData() 0 3 1
A activate() 0 15 2
B hook_indexContent() 0 66 10
A getAccessRootline() 0 10 2
A authorizeFrontendUser() 0 22 3
A registerAuthorizationService() 0 24 1
A getSolrConnection() 0 8 1
1
<?php
2
3
namespace ApacheSolrForTypo3\Solr\IndexQueue\FrontendHelper;
4
5
/***************************************************************
6
 *  Copyright notice
7
 *
8
 *  (c) 2011-2015 Ingo Renner <[email protected]>
9
 *  All rights reserved
10
 *
11
 *  This script is part of the TYPO3 project. The TYPO3 project is
12
 *  free software; you can redistribute it and/or modify
13
 *  it under the terms of the GNU General Public License as published by
14
 *  the Free Software Foundation; either version 3 of the License, or
15
 *  (at your option) any later version.
16
 *
17
 *  The GNU General Public License can be found at
18
 *  http://www.gnu.org/copyleft/gpl.html.
19
 *
20
 *  This script is distributed in the hope that it will be useful,
21
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 *  GNU General Public License for more details.
24
 *
25
 *  This copyright notice MUST APPEAR in all copies of the script!
26
 ***************************************************************/
27
28
use ApacheSolrForTypo3\Solr\Access\Rootline;
29
use ApacheSolrForTypo3\Solr\ConnectionManager;
30
use ApacheSolrForTypo3\Solr\IndexQueue\Item;
31
use ApacheSolrForTypo3\Solr\IndexQueue\Queue;
32
use ApacheSolrForTypo3\Solr\NoSolrConnectionFoundException;
33
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
34
use ApacheSolrForTypo3\Solr\System\Solr\SolrConnection;
35
use ApacheSolrForTypo3\Solr\Typo3PageIndexer;
36
use ApacheSolrForTypo3\Solr\Util;
37
use Exception;
38
use TYPO3\CMS\Core\Log\Logger;
39
use TYPO3\CMS\Core\SingletonInterface;
40
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
41
use TYPO3\CMS\Core\Utility\GeneralUtility;
42
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
43
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
44
use UnexpectedValueException;
45
46
/**
47
 * Index Queue Page Indexer frontend helper to ask the frontend page indexer to
48
 * index the page.
49
 *
50
 * @author Ingo Renner <[email protected]>
51
 */
52
class PageIndexer extends AbstractFrontendHelper implements SingletonInterface
53
{
54
55
    /**
56
     * This frontend helper's executed action.
57
     *
58
     * @var string
59
     */
60
    protected $action = 'indexPage';
61
62
    /**
63
     * the page currently being indexed.
64
     *
65
     * @var TypoScriptFrontendController
66
     */
67
    protected $page;
68
69
    /**
70
     * Response data
71
     *
72
     * @var array
73
     */
74
    protected $responseData = [];
75
76
    /**
77
     * @var Logger
78
     */
79
    protected $logger = null;
80
81
    /**
82
     * Activates a frontend helper by registering for hooks and other
83
     * resources required by the frontend helper to work.
84
     *
85
     * @noinspection PhpUnused
86
     */
87 10
    public function activate()
88
    {
89 10
        $pageIndexingHookRegistration = PageIndexer::class;
90
91 10
        if (Util::getIsTYPO3VersionBelow10()) { // @todo: remove by dropping TYPO3 9.5 support, See: https://docs.typo3.org/c/typo3/cms-core/10.4/en-us/Changelog/10.0/Breaking-87193-DeprecatedFunctionalityRemoved.html
92
            $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['initFEuser'][__CLASS__] = $pageIndexingHookRegistration . '->authorizeFrontendUser';
93
            // disable TSFE cache for TYPO3 v9
94
            $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'][__CLASS__] = $pageIndexingHookRegistration . '->disableCaching';
95
        }
96 10
        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'][__CLASS__] = $pageIndexingHookRegistration;
97
98
        // indexes fields defined in plugin.tx_solr.index.queue.pages.fields
99 10
        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['Indexer']['indexPageSubstitutePageDocument'][PageFieldMappingIndexer::class] = PageFieldMappingIndexer::class;
100
101 10
        $this->registerAuthorizationService();
102 10
    }
103
104
    /**
105
     * Returns the status of whether a page was indexed.
106
     *
107
     * @return array Page indexed status.
108
     * @noinspection PhpUnused
109
     */
110
    public function getData()
111
    {
112
        return $this->responseData;
113
    }
114
115
    #
116
    # Indexer authorisation for access restricted pages / content
117
    #
118
119
    /**
120
     * Fakes a logged in user to retrieve access restricted content.
121
     *
122
     * @return void
123
     * @noinspection PhpUnused
124
     */
125
    public function authorizeFrontendUser()
126
    {
127
        $accessRootline = $this->getAccessRootline();
128
        $stringAccessRootline = (string)$accessRootline;
129
130
        if (empty($stringAccessRootline)) {
131
            return;
132
        }
133
134
        if (!is_array($GLOBALS['TSFE']->fe_user->user)) {
135
            $GLOBALS['TSFE']->fe_user->user = [];
136
        }
137
138
        $groups = $accessRootline->getGroups();
139
        $groupList = implode(',', $groups);
140
141
        $GLOBALS['TSFE']->fe_user->user['username'] = AuthorizationService::SOLR_INDEXER_USERNAME;
142
        $GLOBALS['TSFE']->fe_user->user['usergroup'] = $groupList;
143
144
        $this->responseData['authorization'] = [
145
            'username' => $GLOBALS['TSFE']->fe_user->user['username'],
146
            'usergroups' => $GLOBALS['TSFE']->fe_user->user['usergroup']
147
        ];
148
    }
149
150
    /**
151
     * Gets the access rootline as defined by the request.
152
     *
153
     * @return Rootline The access rootline to use for indexing.
154
     */
155 10
    protected function getAccessRootline()
156
    {
157 10
        $stringAccessRootline = '';
158
159 10
        if ($this->request->getParameter('accessRootline')) {
160
            $stringAccessRootline = $this->request->getParameter('accessRootline');
161
        }
162
163
        /** @noinspection PhpIncompatibleReturnTypeInspection */
164 10
        return GeneralUtility::makeInstance(Rootline::class, /** @scrutinizer ignore-type */ $stringAccessRootline);
165
    }
166
167
    /**
168
     * Registers an authentication service to authorize / grant the indexer to
169
     * access protected pages.
170
     *
171
     * @return void
172
     */
173 10
    protected function registerAuthorizationService()
174
    {
175 10
        $overrulingPriority = $this->getHighestAuthenticationServicePriority() + 1;
176
177 10
        ExtensionManagementUtility::addService(
178 10
            'solr', // extension key
179 10
            'auth', // service type
180 10
            AuthorizationService::class,
181
            // service key
182
            [// service meta data
183 10
                'title' => 'Solr Indexer Authorization',
184 10
                'description' => 'Authorizes the Solr Index Queue indexer to access protected pages.',
185
186 10
                'subtype' => 'getUserFE,authUserFE,getGroupsFE',
187
188
                'available' => true,
189 10
                'priority' => $overrulingPriority,
190 10
                'quality' => 100,
191
192 10
                'os' => '',
193 10
                'exec' => '',
194
195 10
                'classFile' => ExtensionManagementUtility::extPath('solr') . 'Classes/IndexQueue/FrontendHelper/AuthorizationService.php',
196
                'className' => AuthorizationService::class,
197
            ]
198
        );
199 10
    }
200
201
    /**
202
     * Determines the highest priority of all registered authentication
203
     * services.
204
     *
205
     * @return int Highest priority of all registered authentication service
206
     */
207 10
    protected function getHighestAuthenticationServicePriority()
208
    {
209 10
        $highestPriority = 0;
210
211 10
        if (is_array($GLOBALS['T3_SERVICES']['auth'])) {
212 10
            foreach ($GLOBALS['T3_SERVICES']['auth'] as $service) {
213 10
                if ($service['priority'] > $highestPriority) {
214 10
                    $highestPriority = $service['priority'];
215
                }
216
            }
217
        }
218
219 10
        return $highestPriority;
220
    }
221
222
    #
223
    # Indexing
224
    #
225
226
    /**
227
     * Generates the current page's URL.
228
     *
229
     * Uses the provided GET parameters, page id and language id.
230
     *
231
     * @return string URL of the current page.
232
     */
233 10
    protected function generatePageUrl()
234
    {
235 10
        if ($this->request->getParameter('overridePageUrl')) {
236
            return $this->request->getParameter('overridePageUrl');
237
        }
238
239
            /** @var $contentObject ContentObjectRenderer */
240 10
        $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
241
242
        $typolinkConfiguration = [
243 10
            'parameter' => intval($this->page->id),
244 10
            'linkAccessRestrictedPages' => '1'
245
        ];
246
247 10
        $language = GeneralUtility::_GET('L');
248 10
        if (!empty($language)) {
249
            $typolinkConfiguration['additionalParams'] = '&L=' . $language;
250
        }
251
252 10
        $url = $contentObject->typoLink_URL($typolinkConfiguration);
253
254
        // clean up
255 10
        if ($url == '') {
256
            $url = '/';
257
        }
258
259 10
        return $url;
260
    }
261
262
    /**
263
     * Handles the indexing of the page content during post processing of a
264
     * generated page.
265
     *
266
     * @param TypoScriptFrontendController $page TypoScript frontend
267
     * @noinspection PhpUnused
268
     */
269 10
    public function hook_indexContent(TypoScriptFrontendController $page)
270
    {
271 10
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
272
273 10
        $this->page = $page;
274 10
        $configuration = Util::getSolrConfiguration();
275
276 10
        $logPageIndexed = $configuration->getLoggingIndexingPageIndexed();
277 10
        if (!$this->page->config['config']['index_enable']) {
278
            if ($logPageIndexed) {
279
                $this->logger->log(
280
                    SolrLogManager::ERROR,
281
                    'Indexing is disabled. Set config.index_enable = 1 .'
282
                );
283
            }
284
            return;
285
        }
286
287
        try {
288 10
            $indexQueueItem = $this->getIndexQueueItem();
289 10
            if (is_null($indexQueueItem)) {
290
                throw new UnexpectedValueException('Can not get index queue item', 1482162337);
291
            }
292
293 10
            $solrConnection = $this->getSolrConnection($indexQueueItem);
294
295
            /** @var $indexer Typo3PageIndexer */
296 10
            $indexer = GeneralUtility::makeInstance(Typo3PageIndexer::class, /** @scrutinizer ignore-type */ $page);
297 10
            $indexer->setSolrConnection($solrConnection);
298 10
            $indexer->setPageAccessRootline($this->getAccessRootline());
299 10
            $indexer->setPageUrl($this->generatePageUrl());
300 10
            $indexer->setMountPointParameter($GLOBALS['TSFE']->MP);
301 10
            $indexer->setIndexQueueItem($indexQueueItem);
302
303 10
            $this->responseData['pageIndexed'] = (int)$indexer->indexPage();
304 10
            $this->responseData['originalPageDocument'] = (array)$indexer->getPageSolrDocument();
305 10
            $this->responseData['solrConnection'] = [
306 10
                'rootPage' => $indexQueueItem->getRootPageUid(),
307 10
                'sys_language_uid' => Util::getLanguageUid(),
308 10
                'solr' => (string)$solrConnection->getNode('write')
309
            ];
310
311 10
            $documentsSentToSolr = $indexer->getDocumentsSentToSolr();
312 10
            foreach ($documentsSentToSolr as $document) {
313 10
                $this->responseData['documentsSentToSolr'][] = (array)$document;
314
            }
315
        } catch (Exception $e) {
316
            if ($configuration->getLoggingExceptions()) {
317
                $this->logger->log(
318
                    SolrLogManager::ERROR,
319
                    'Exception while trying to index page ' . $page->id,
320
                    [
321
                        $e->__toString()
322
                    ]
323
                );
324
            }
325
        }
326
327 10
        if ($logPageIndexed) {
328
            $success = $this->responseData['pageIndexed'] ? 'Success' : 'Failed';
329
            $severity = $this->responseData['pageIndexed'] ? SolrLogManager::NOTICE : SolrLogManager::ERROR;
330
331
            $this->logger->log(
332
                $severity,
333
                'Page indexed: ' . $success,
334
                $this->responseData
335
            );
336
        }
337 10
    }
338
339
    /**
340
     * Gets the solr connection to use for indexing the page based on the
341
     * Index Queue item's properties.
342
     *
343
     * @param Item $indexQueueItem
344
     * @return SolrConnection Solr server connection
345
     * @throws NoSolrConnectionFoundException
346
     */
347 10
    protected function getSolrConnection(Item $indexQueueItem)
348
    {
349
        /** @var $connectionManager ConnectionManager */
350 10
        $connectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
351
352 10
        return $connectionManager->getConnectionByRootPageId(
353 10
            $indexQueueItem->getRootPageUid(),
354 10
            Util::getLanguageUid()
355
        );
356
    }
357
358
    /**
359
     * This method retrieves the item from the index queue, that is indexed in this request.
360
     *
361
     * @return Item
362
     */
363 10
    protected function getIndexQueueItem()
364
    {
365
        /** @var $indexQueue Queue */
366 10
        $indexQueue = GeneralUtility::makeInstance(Queue::class);
367 10
        return $indexQueue->getItem($this->request->getParameter('item'));
368
    }
369
}
370