Failed Conditions
Push — master ( 0b92b6...391298 )
by Timo
03:36
created

IndexService::setContextTask()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace ApacheSolrForTypo3\Solr\Domain\Index;
4
5
/***************************************************************
6
 *  Copyright notice
7
 *
8
 *  (c) 2015-2016 Timo Hund <[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\ConnectionManager;
29
use ApacheSolrForTypo3\Solr\IndexQueue\Indexer;
30
use ApacheSolrForTypo3\Solr\IndexQueue\Item;
31
use ApacheSolrForTypo3\Solr\IndexQueue\Queue;
32
use ApacheSolrForTypo3\Solr\Site;
33
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
34
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
35
use ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask;
36
use TYPO3\CMS\Backend\Utility\BackendUtility;
37
use TYPO3\CMS\Core\Utility\GeneralUtility;
38
use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
39
40
/**
41
 * Service to perform indexing operations
42
 *
43
 * @author Timo Hund <[email protected]>
44
 */
45
class IndexService
46
{
47
    /**
48
     * @var TypoScriptConfiguration
49
     */
50
    protected $configuration;
51
52
    /**
53
     * @var Site
54
     */
55
    protected $site;
56
57
    /**
58
     * @var IndexQueueWorkerTask
59
     */
60
    protected $contextTask;
61
62
    /**
63
     * @var Queue
64
     */
65
    protected $indexQueue;
66
67
    /**
68
     * @var Dispatcher
69
     */
70
    protected $signalSlotDispatcher;
71
72
    /**
73
     * @var \ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager
74
     */
75
    protected $logger = null;
76
77
    /**
78
     * IndexService constructor.
79
     * @param Site $site
80
     * @param Queue|null $queue
81
     * @param Dispatcher|null $dispatcher
82
     * @param SolrLogManager|null $solrLogManager
83
     */
84 8
    public function __construct(Site $site, Queue $queue = null, Dispatcher $dispatcher = null, SolrLogManager $solrLogManager = null)
85
    {
86 8
        $this->site = $site;
87 8
        $this->indexQueue = is_null($queue) ? GeneralUtility::makeInstance(Queue::class) : $queue;
88 8
        $this->signalSlotDispatcher = is_null($dispatcher) ? GeneralUtility::makeInstance(Dispatcher::class) : $dispatcher;
89 8
        $this->logger = is_null($solrLogManager) ? GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__) : $solrLogManager;
0 ignored issues
show
Bug introduced by
__CLASS__ of type string is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

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

89
        $this->logger = is_null($solrLogManager) ? GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__) : $solrLogManager;
Loading history...
90 8
    }
91
92
    /**
93
     * @param \ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask $contextTask
94
     */
95 2
    public function setContextTask($contextTask)
96
    {
97 2
        $this->contextTask = $contextTask;
98 2
    }
99
100
    /**
101
     * @return \ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask
102
     */
103 6
    public function getContextTask()
104
    {
105 6
        return $this->contextTask;
106
    }
107
108
    /**
109
     * Indexes items from the Index Queue.
110
     *
111
     * @param int $limit
112
     * @return bool
113
     */
114 6
    public function indexItems($limit)
115
    {
116 6
        $errors     = 0;
117 6
        $indexRunId = uniqid();
118 6
        $configurationToUse = $this->site->getSolrConfiguration();
119 6
        $enableCommitsSetting = $configurationToUse->getEnableCommits();
120
121
        // get items to index
122 6
        $itemsToIndex = $this->indexQueue->getItemsToIndex($this->site, $limit);
123
124 6
        $this->emitSignal('beforeIndexItems', [$itemsToIndex, $this->getContextTask(), $indexRunId]);
125
126 6
        foreach ($itemsToIndex as $itemToIndex) {
127
            try {
128
                // try indexing
129 6
                $this->emitSignal('beforeIndexItem', [$itemToIndex, $this->getContextTask(), $indexRunId]);
130 6
                $this->indexItem($itemToIndex, $configurationToUse);
131 6
                $this->emitSignal('afterIndexItem', [$itemToIndex, $this->getContextTask(), $indexRunId]);
132
            } catch (\Exception $e) {
133
                $errors++;
134
                $this->indexQueue->markItemAsFailed($itemToIndex, $e->getCode() . ': ' . $e->__toString());
135 6
                $this->generateIndexingErrorLog($itemToIndex, $e);
136
            }
137
        }
138
139 6
        $this->emitSignal('afterIndexItems', [$itemsToIndex, $this->getContextTask(), $indexRunId]);
140
141 6
        if ($enableCommitsSetting && count($itemsToIndex) > 0) {
142 5
            $solrServers = GeneralUtility::makeInstance(ConnectionManager::class)->getConnectionsBySite($this->site);
143 5
            foreach ($solrServers as $solrServer) {
144 5
                $solrServer->getWriteService()->commit(false, false, false);
145
            }
146
        }
147
148 6
        return ($errors === 0);
149
    }
150
151
    /**
152
     * Generates a message in the error log when an error occured.
153
     *
154
     * @param Item $itemToIndex
155
     * @param \Exception  $e
156
     */
157
    protected function generateIndexingErrorLog(Item $itemToIndex, \Exception $e)
158
    {
159
        $message = 'Failed indexing Index Queue item ' . $itemToIndex->getIndexQueueUid();
160
        $data = ['code' => $e->getCode(), 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString(), 'item' => (array)$itemToIndex];
161
162
        $this->logger->log(
163
            SolrLogManager::ERROR,
164
            $message,
165
            $data
166
        );
167
    }
168
169
    /**
170
     * Builds an emits a singal for the IndexService.
171
     *
172
     * @param string $name
173
     * @param array $arguments
174
     * @return mixed
175
     */
176 6
    protected function emitSignal($name, $arguments)
177
    {
178 6
        return $this->signalSlotDispatcher->dispatch(__CLASS__, $name, $arguments);
179
    }
180
181
    /**
182
     * Indexes an item from the Index Queue.
183
     *
184
     * @param Item $item An index queue item to index
185
     * @param TypoScriptConfiguration $configuration
186
     * @return bool TRUE if the item was successfully indexed, FALSE otherwise
187
     */
188 5
    protected function indexItem(Item $item, TypoScriptConfiguration $configuration)
189
    {
190 5
        $indexer = $this->getIndexerByItem($item->getIndexingConfigurationName(), $configuration);
191
192
        // Remember original http host value
193 5
        $originalHttpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
194
195 5
        $this->initializeHttpServerEnvironment($item);
196 5
        $itemIndexed = $indexer->index($item);
197
198
        // update IQ item so that the IQ can determine what's been indexed already
199 5
        if ($itemIndexed) {
200 5
            $this->indexQueue->updateIndexTimeByItem($item);
201
        }
202
203 5
        if (!is_null($originalHttpHost)) {
204
            $_SERVER['HTTP_HOST'] = $originalHttpHost;
205
        } else {
206 5
            unset($_SERVER['HTTP_HOST']);
207
        }
208
209
        // needed since TYPO3 7.5
210 5
        GeneralUtility::flushInternalRuntimeCaches();
211
212 5
        return $itemIndexed;
213
    }
214
215
    /**
216
     * A factory method to get an indexer depending on an item's configuration.
217
     *
218
     * By default all items are indexed using the default indexer
219
     * (ApacheSolrForTypo3\Solr\IndexQueue\Indexer) coming with EXT:solr. Pages by default are
220
     * configured to be indexed through a dedicated indexer
221
     * (ApacheSolrForTypo3\Solr\IndexQueue\PageIndexer). In all other cases a dedicated indexer
222
     * can be specified through TypoScript if needed.
223
     *
224
     * @param string $indexingConfigurationName Indexing configuration name.
225
     * @param TypoScriptConfiguration $configuration
226
     * @return Indexer
227
     */
228 5
    protected function getIndexerByItem($indexingConfigurationName, TypoScriptConfiguration $configuration)
229
    {
230 5
        $indexerClass = $configuration->getIndexQueueIndexerByConfigurationName($indexingConfigurationName);
231 5
        $indexerConfiguration = $configuration->getIndexQueueIndexerConfigurationByConfigurationName($indexingConfigurationName);
232
233 5
        $indexer = GeneralUtility::makeInstance($indexerClass, $indexerConfiguration);
234 5
        if (!($indexer instanceof Indexer)) {
235
            throw new \RuntimeException(
236
                'The indexer class "' . $indexerClass . '" for indexing configuration "' . $indexingConfigurationName . '" is not a valid indexer. Must be a subclass of ApacheSolrForTypo3\Solr\IndexQueue\Indexer.',
237
                1260463206
238
            );
239
        }
240
241 5
        return $indexer;
242
    }
243
244
    /**
245
     * Gets the indexing progress.
246
     *
247
     * @return float Indexing progress as a two decimal precision float. f.e. 44.87
248
     */
249 2
    public function getProgress()
250
    {
251 2
        return $this->indexQueue->getStatisticsBySite($this->site)->getSuccessPercentage();
252
    }
253
254
    /**
255
     * Returns the amount of failed queue items for the current site.
256
     *
257
     * @return int
258
     */
259 1
    public function getFailCount()
260
    {
261 1
        return $this->indexQueue->getStatisticsBySite($this->site)->getFailedCount();
262
    }
263
264
    /**
265
     * Initializes the $_SERVER['HTTP_HOST'] environment variable in CLI
266
     * environments dependent on the Index Queue item's root page.
267
     *
268
     * When the Index Queue Worker task is executed by a cron job there is no
269
     * HTTP_HOST since we are in a CLI environment. RealURL needs the host
270
     * information to generate a proper URL though. Using the Index Queue item's
271
     * root page information we can determine the correct host although being
272
     * in a CLI environment.
273
     *
274
     * @param Item $item Index Queue item to use to determine the host.
275
     * @param
276
     */
277 5
    protected function initializeHttpServerEnvironment(Item $item)
278
    {
279 5
        static $hosts = [];
280 5
        $rootpageId = $item->getRootPageUid();
281 5
        $hostFound = !empty($hosts[$rootpageId]);
282
283 5
        if (!$hostFound) {
284 5
            $rootline = BackendUtility::BEgetRootLine($rootpageId);
285 5
            $host = BackendUtility::firstDomainRecord($rootline);
286 5
            $hosts[$rootpageId] = $host;
287
        }
288
289 5
        $_SERVER['HTTP_HOST'] = $hosts[$rootpageId];
290
291
        // needed since TYPO3 7.5
292 5
        GeneralUtility::flushInternalRuntimeCaches();
293 5
    }
294
}
295