Passed
Push — task/2976_TYPO3.11_compatibili... ( 4d1a77...3b9190 )
by Rafael
03:39
created

PageIndexer   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 313
Duplicated Lines 0 %

Test Coverage

Coverage 65.81%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 28
eloc 110
dl 0
loc 313
ccs 77
cts 117
cp 0.6581
rs 10
c 1
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getHighestAuthenticationServicePriority() 0 13 4
A registerAuthorizationService() 0 24 1
A activate() 0 10 1
A getData() 0 3 1
B hook_indexContent() 0 66 10
A getAccessRootline() 0 10 2
A getIndexQueueItem() 0 5 1
A authorizeFrontendUser() 0 22 3
A getSolrConnection() 0 8 1
A generatePageUrl() 0 27 4
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 Throwable;
38
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
39
use TYPO3\CMS\Core\Log\Logger;
40
use TYPO3\CMS\Core\SingletonInterface;
41
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
42
use TYPO3\CMS\Core\Utility\GeneralUtility;
43
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
44
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
45
use UnexpectedValueException;
46
47
/**
48
 * Index Queue Page Indexer frontend helper to ask the frontend page indexer to
49
 * index the page.
50
 *
51
 * @author Ingo Renner <[email protected]>
52
 */
53
class PageIndexer extends AbstractFrontendHelper implements SingletonInterface
54
{
55
56
    /**
57
     * This frontend helper's executed action.
58
     *
59
     * @var string
60
     */
61
    protected $action = 'indexPage';
62
63
    /**
64
     * the page currently being indexed.
65
     *
66
     * @var TypoScriptFrontendController
67
     */
68
    protected $page;
69
70
    /**
71
     * Response data
72
     *
73
     * @var array
74
     */
75
    protected $responseData = [];
76
77
    /**
78
     * @var Logger
79
     */
80
    protected $logger = null;
81
82
    /**
83
     * Activates a frontend helper by registering for hooks and other
84
     * resources required by the frontend helper to work.
85
     *
86
     * @noinspection PhpUnused
87
     */
88 10
    public function activate()
89
    {
90 10
        $pageIndexingHookRegistration = PageIndexer::class;
91
92 10
        $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'][__CLASS__] = $pageIndexingHookRegistration . '->hook_indexContent';
93
94
        // indexes fields defined in plugin.tx_solr.index.queue.pages.fields
95 10
        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['Indexer']['indexPageSubstitutePageDocument'][PageFieldMappingIndexer::class] = PageFieldMappingIndexer::class;
96
97 10
        $this->registerAuthorizationService();
98 10
    }
99
100
    /**
101
     * Returns the status of whether a page was indexed.
102
     *
103
     * @return array Page indexed status.
104
     * @noinspection PhpUnused
105
     */
106
    public function getData()
107
    {
108
        return $this->responseData;
109
    }
110
111
    #
112
    # Indexer authorisation for access restricted pages / content
113
    #
114
115
    /**
116
     * Fakes a logged in user to retrieve access restricted content.
117
     *
118
     * @return void
119
     * @noinspection PhpUnused
120
     */
121
    public function authorizeFrontendUser()
122
    {
123
        $accessRootline = $this->getAccessRootline();
124
        $stringAccessRootline = (string)$accessRootline;
125
126
        if (empty($stringAccessRootline)) {
127
            return;
128
        }
129
130
        if (!is_array($GLOBALS['TSFE']->fe_user->user)) {
131
            $GLOBALS['TSFE']->fe_user->user = [];
132
        }
133
134
        $groups = $accessRootline->getGroups();
135
        $groupList = implode(',', $groups);
136
137
        $GLOBALS['TSFE']->fe_user->user['username'] = AuthorizationService::SOLR_INDEXER_USERNAME;
138
        $GLOBALS['TSFE']->fe_user->user['usergroup'] = $groupList;
139
140
        $this->responseData['authorization'] = [
141
            'username' => $GLOBALS['TSFE']->fe_user->user['username'],
142
            'usergroups' => $GLOBALS['TSFE']->fe_user->user['usergroup']
143
        ];
144
    }
145
146
    /**
147
     * Gets the access rootline as defined by the request.
148
     *
149
     * @return Rootline The access rootline to use for indexing.
150
     */
151 10
    protected function getAccessRootline()
152
    {
153 10
        $stringAccessRootline = '';
154
155 10
        if ($this->request->getParameter('accessRootline')) {
156
            $stringAccessRootline = $this->request->getParameter('accessRootline');
157
        }
158
159
        /** @noinspection PhpIncompatibleReturnTypeInspection */
160 10
        return GeneralUtility::makeInstance(Rootline::class, /** @scrutinizer ignore-type */ $stringAccessRootline);
161
    }
162
163
    /**
164
     * Registers an authentication service to authorize / grant the indexer to
165
     * access protected pages.
166
     *
167
     * @return void
168
     */
169 10
    protected function registerAuthorizationService()
170
    {
171 10
        $overrulingPriority = $this->getHighestAuthenticationServicePriority() + 1;
172
173 10
        ExtensionManagementUtility::addService(
174 10
            'solr', // extension key
175 10
            'auth', // service type
176 10
            AuthorizationService::class,
177
            // service key
178
            [// service meta data
179 10
                'title' => 'Solr Indexer Authorization',
180 10
                'description' => 'Authorizes the Solr Index Queue indexer to access protected pages.',
181
182 10
                'subtype' => 'getUserFE,authUserFE,getGroupsFE',
183
184
                'available' => true,
185 10
                'priority' => $overrulingPriority,
186 10
                'quality' => 100,
187
188 10
                'os' => '',
189 10
                'exec' => '',
190
191 10
                'classFile' => ExtensionManagementUtility::extPath('solr') . 'Classes/IndexQueue/FrontendHelper/AuthorizationService.php',
192
                'className' => AuthorizationService::class,
193
            ]
194
        );
195 10
    }
196
197
    /**
198
     * Determines the highest priority of all registered authentication
199
     * services.
200
     *
201
     * @return int Highest priority of all registered authentication service
202
     */
203 10
    protected function getHighestAuthenticationServicePriority()
204
    {
205 10
        $highestPriority = 0;
206
207 10
        if (is_array($GLOBALS['T3_SERVICES']['auth'] ?? null)) {
208 10
            foreach ($GLOBALS['T3_SERVICES']['auth'] as $service) {
209 10
                if ($service['priority'] > $highestPriority) {
210 10
                    $highestPriority = $service['priority'];
211
                }
212
            }
213
        }
214
215 10
        return $highestPriority;
216
    }
217
218
    #
219
    # Indexing
220
    #
221
222
    /**
223
     * Generates the current page's URL.
224
     *
225
     * Uses the provided GET parameters, page id and language id.
226
     *
227
     * @return string URL of the current page.
228
     */
229 10
    protected function generatePageUrl()
230
    {
231 10
        if ($this->request->getParameter('overridePageUrl')) {
232
            return $this->request->getParameter('overridePageUrl');
233
        }
234
235
            /** @var $contentObject ContentObjectRenderer */
236 10
        $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
237
238 10
        $typolinkConfiguration = [
239 10
            'parameter' => intval($this->page->id),
240 10
            'linkAccessRestrictedPages' => '1'
241
        ];
242
243 10
        $language = GeneralUtility::_GET('L');
244 10
        if (!empty($language)) {
245
            $typolinkConfiguration['additionalParams'] = '&L=' . $language;
246
        }
247
248 10
        $url = $contentObject->typoLink_URL($typolinkConfiguration);
249
250
        // clean up
251 10
        if ($url == '') {
252
            $url = '/';
253
        }
254
255 10
        return $url;
256
    }
257
258
    /**
259
     * Handles the indexing of the page content during post-processing of a
260
     * generated page.
261
     *
262
     * @param array $params unused
263
     * @param TypoScriptFrontendController $page TypoScript frontend
264
     * @noinspection PhpUnused
265
     */
266 10
    public function hook_indexContent(array $params, TypoScriptFrontendController $page)
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

266
    public function hook_indexContent(/** @scrutinizer ignore-unused */ array $params, TypoScriptFrontendController $page)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
267
    {
268 10
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
269
270 10
        $this->page = $page;
271 10
        $configuration = Util::getSolrConfiguration();
272
273 10
        $logPageIndexed = $configuration->getLoggingIndexingPageIndexed();
274 10
        if (!$this->page->config['config']['index_enable']) {
275
            if ($logPageIndexed) {
276
                $this->logger->log(
277
                    SolrLogManager::ERROR,
278
                    'Indexing is disabled. Set config.index_enable = 1 .'
279
                );
280
            }
281
            return;
282
        }
283
284
        try {
285 10
            $indexQueueItem = $this->getIndexQueueItem();
286 10
            if (is_null($indexQueueItem)) {
287
                throw new UnexpectedValueException('Can not get index queue item', 1482162337);
288
            }
289
290 10
            $solrConnection = $this->getSolrConnection($indexQueueItem);
291
292
            /** @var $indexer Typo3PageIndexer */
293 10
            $indexer = GeneralUtility::makeInstance(Typo3PageIndexer::class, /** @scrutinizer ignore-type */ $page);
294 10
            $indexer->setSolrConnection($solrConnection);
295 10
            $indexer->setPageAccessRootline($this->getAccessRootline());
296 10
            $indexer->setPageUrl($this->generatePageUrl());
297 10
            $indexer->setMountPointParameter($GLOBALS['TSFE']->MP);
298 10
            $indexer->setIndexQueueItem($indexQueueItem);
299
300 10
            $this->responseData['pageIndexed'] = (int)$indexer->indexPage();
301 10
            $this->responseData['originalPageDocument'] = (array)$indexer->getPageSolrDocument();
302 10
            $this->responseData['solrConnection'] = [
303 10
                'rootPage' => $indexQueueItem->getRootPageUid(),
304 10
                'sys_language_uid' => Util::getLanguageUid(),
305 10
                'solr' => (string)$solrConnection->getNode('write')
306
            ];
307
308 10
            $documentsSentToSolr = $indexer->getDocumentsSentToSolr();
309 10
            foreach ($documentsSentToSolr as $document) {
310 10
                $this->responseData['documentsSentToSolr'][] = (array)$document;
311
            }
312
        } catch (Throwable $e) {
313
            if ($configuration->getLoggingExceptions()) {
314
                $this->logger->log(
315
                    SolrLogManager::ERROR,
316
                    'Exception while trying to index page ' . $page->id,
317
                    [
318
                        $e->__toString()
319
                    ]
320
                );
321
            }
322
        }
323
324 10
        if ($logPageIndexed) {
325
            $success = $this->responseData['pageIndexed'] ? 'Success' : 'Failed';
326
            $severity = $this->responseData['pageIndexed'] ? SolrLogManager::NOTICE : SolrLogManager::ERROR;
327
328
            $this->logger->log(
329
                $severity,
330
                'Page indexed: ' . $success,
331
                $this->responseData
332
            );
333
        }
334 10
    }
335
336
    /**
337
     * Gets the solr connection to use for indexing the page based on the
338
     * Index Queue item's properties.
339
     *
340
     * @param Item $indexQueueItem
341
     * @return SolrConnection Solr server connection
342
     * @throws NoSolrConnectionFoundException
343
     * @throws AspectNotFoundException
344
     */
345 10
    protected function getSolrConnection(Item $indexQueueItem)
346
    {
347
        /** @var $connectionManager ConnectionManager */
348 10
        $connectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
349
350 10
        return $connectionManager->getConnectionByRootPageId(
351 10
            $indexQueueItem->getRootPageUid(),
352 10
            Util::getLanguageUid()
353
        );
354
    }
355
356
    /**
357
     * This method retrieves the item from the index queue, that is indexed in this request.
358
     *
359
     * @return Item
360
     */
361 10
    protected function getIndexQueueItem()
362
    {
363
        /** @var $indexQueue Queue */
364 10
        $indexQueue = GeneralUtility::makeInstance(Queue::class);
365 10
        return $indexQueue->getItem($this->request->getParameter('item'));
366
    }
367
}
368