Passed
Push — master ( 202215...3acdae )
by Timo
57s
created

IndexService::getFailCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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 2 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\IndexQueue\Indexer;
29
use ApacheSolrForTypo3\Solr\IndexQueue\Item;
30
use ApacheSolrForTypo3\Solr\IndexQueue\Queue;
31
use ApacheSolrForTypo3\Solr\Site;
32
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
33
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
34
use ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask;
35
use TYPO3\CMS\Backend\Utility\BackendUtility;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
38
39
/**
40
 * Service to perform indexing operations
41
 *
42
 * @author Timo Hund <[email protected]>
43
 */
44
class IndexService
45
{
46
    /**
47
     * @var TypoScriptConfiguration
48
     */
49
    protected $configuration;
50
51
    /**
52
     * @var Site
53
     */
54
    protected $site;
55
56
    /**
57
     * @var IndexQueueWorkerTask
58
     */
59
    protected $contextTask;
60
61
    /**
62
     * @var Queue
63
     */
64
    protected $indexQueue;
65
66
    /**
67
     * @var Dispatcher
68
     */
69
    protected $signalSlotDispatcher;
70
71
    /**
72
     * @var \ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager
73
     */
74
    protected $logger = null;
75
76
    /**
77
     * IndexService constructor.
78
     * @param Site $site
79
     * @param Queue|null $queue
80
     * @param Dispatcher|null $dispatcher
81
     */
82 8
    public function __construct(Site $site, Queue $queue = null, Dispatcher $dispatcher = null)
83
    {
84 8
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__);
85 8
        $this->site = $site;
86 8
        $this->indexQueue = is_null($queue) ? GeneralUtility::makeInstance(Queue::class) : $queue;
87 8
        $this->signalSlotDispatcher = is_null($dispatcher) ? GeneralUtility::makeInstance(Dispatcher::class) : $dispatcher;
88 8
    }
89
90
    /**
91
     * @param \ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask $contextTask
92
     */
93 2
    public function setContextTask($contextTask)
94
    {
95 2
        $this->contextTask = $contextTask;
96 2
    }
97
98
    /**
99
     * @return \ApacheSolrForTypo3\Solr\Task\IndexQueueWorkerTask
100
     */
101 6
    public function getContextTask()
102
    {
103 6
        return $this->contextTask;
104
    }
105
106
    /**
107
     * Indexes items from the Index Queue.
108
     *
109
     * @param int $limit
110
     * @return bool
111
     */
112 6
    public function indexItems($limit)
113
    {
114 6
        $errors     = 0;
115 6
        $indexRunId = uniqid();
116 6
        $configurationToUse = $this->site->getSolrConfiguration();
117
118
        // get items to index
119 6
        $itemsToIndex = $this->indexQueue->getItemsToIndex($this->site, $limit);
120
121 6
        $this->emitSignal('beforeIndexItems', [$itemsToIndex, $this->getContextTask(), $indexRunId]);
122
123 6
        foreach ($itemsToIndex as $itemToIndex) {
124
            try {
125
                // try indexing
126 6
                $this->emitSignal('beforeIndexItem', [$itemToIndex, $this->getContextTask(), $indexRunId]);
127 6
                $this->indexItem($itemToIndex, $configurationToUse);
128 6
                $this->emitSignal('afterIndexItem', [$itemToIndex, $this->getContextTask(), $indexRunId]);
129 6
            } catch (\Exception $e) {
130
                $errors++;
131
                $this->indexQueue->markItemAsFailed($itemToIndex, $e->getCode() . ': ' . $e->__toString());
132
                $this->generateIndexingErrorLog($itemToIndex, $e);
133
            }
134 6
        }
135
136 6
        $this->emitSignal('afterIndexItems', [$itemsToIndex, $this->getContextTask(), $indexRunId]);
137
138 6
        return ($errors === 0);
139
    }
140
141
    /**
142
     * Generates a message in the error log when an error occured.
143
     *
144
     * @param Item $itemToIndex
145
     * @param \Exception  $e
146
     */
147
    protected function generateIndexingErrorLog(Item $itemToIndex, \Exception $e)
148
    {
149
        $message = 'Failed indexing Index Queue item ' . $itemToIndex->getIndexQueueUid();
150
        $data = ['code' => $e->getCode(), 'message' => $e->getMessage(), 'trace' => $e->getTrace(), 'item' => (array)$itemToIndex];
151
152
        $this->logger->log(
153
            SolrLogManager::ERROR,
154
            $message,
155
            $data
156
        );
157
    }
158
159
    /**
160
     * Builds an emits a singal for the IndexService.
161
     *
162
     * @param string $name
163
     * @param array $arguments
164
     * @return mixed
165
     */
166 6
    protected function emitSignal($name, $arguments)
167
    {
168 6
        return $this->signalSlotDispatcher->dispatch(__CLASS__, $name, $arguments);
169
    }
170
171
    /**
172
     * Indexes an item from the Index Queue.
173
     *
174
     * @param Item $item An index queue item to index
175
     * @param TypoScriptConfiguration $configuration
176
     * @return bool TRUE if the item was successfully indexed, FALSE otherwise
177
     */
178 5
    protected function indexItem(Item $item, TypoScriptConfiguration $configuration)
179
    {
180 5
        $indexer = $this->getIndexerByItem($item->getIndexingConfigurationName(), $configuration);
181
182
        // Remember original http host value
183 5
        $originalHttpHost = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
184
185 5
        $this->initializeHttpServerEnvironment($item);
186 5
        $itemIndexed = $indexer->index($item);
187
188
        // update IQ item so that the IQ can determine what's been indexed already
189 5
        if ($itemIndexed) {
190 5
            $item->updateIndexedTime();
191 5
        }
192
193 5
        if (!is_null($originalHttpHost)) {
194
            $_SERVER['HTTP_HOST'] = $originalHttpHost;
195
        } else {
196 5
            unset($_SERVER['HTTP_HOST']);
197
        }
198
199
        // needed since TYPO3 7.5
200 5
        GeneralUtility::flushInternalRuntimeCaches();
201
202 5
        return $itemIndexed;
203
    }
204
205
    /**
206
     * A factory method to get an indexer depending on an item's configuration.
207
     *
208
     * By default all items are indexed using the default indexer
209
     * (ApacheSolrForTypo3\Solr\IndexQueue\Indexer) coming with EXT:solr. Pages by default are
210
     * configured to be indexed through a dedicated indexer
211
     * (ApacheSolrForTypo3\Solr\IndexQueue\PageIndexer). In all other cases a dedicated indexer
212
     * can be specified through TypoScript if needed.
213
     *
214
     * @param string $indexingConfigurationName Indexing configuration name.
215
     * @param TypoScriptConfiguration $configuration
216
     * @return Indexer
217
     */
218 5
    protected function getIndexerByItem($indexingConfigurationName, TypoScriptConfiguration $configuration)
219
    {
220 5
        $indexerClass = $configuration->getIndexQueueIndexerByConfigurationName($indexingConfigurationName);
221 5
        $indexerConfiguration = $configuration->getIndexQueueIndexerConfigurationByConfigurationName($indexingConfigurationName);
222
223 5
        $indexer = GeneralUtility::makeInstance($indexerClass, $indexerConfiguration);
224 5
        if (!($indexer instanceof Indexer)) {
225
            throw new \RuntimeException(
226
                'The indexer class "' . $indexerClass . '" for indexing configuration "' . $indexingConfigurationName . '" is not a valid indexer. Must be a subclass of ApacheSolrForTypo3\Solr\IndexQueue\Indexer.',
227
                1260463206
228
            );
229
        }
230
231 5
        return $indexer;
232
    }
233
234
    /**
235
     * Gets the indexing progress.
236
     *
237
     * @return float Indexing progress as a two decimal precision float. f.e. 44.87
238
     */
239 2
    public function getProgress()
240
    {
241 2
        return $this->indexQueue->getStatisticsBySite($this->site)->getSuccessPercentage();
242
    }
243
244
    /**
245
     * Returns the amount of failed queue items for the current site.
246
     *
247
     * @return int
248
     */
249 1
    public function getFailCount()
250
    {
251 1
        return $this->indexQueue->getStatisticsBySite($this->site)->getFailedCount();
252
    }
253
254
    /**
255
     * Initializes the $_SERVER['HTTP_HOST'] environment variable in CLI
256
     * environments dependent on the Index Queue item's root page.
257
     *
258
     * When the Index Queue Worker task is executed by a cron job there is no
259
     * HTTP_HOST since we are in a CLI environment. RealURL needs the host
260
     * information to generate a proper URL though. Using the Index Queue item's
261
     * root page information we can determine the correct host although being
262
     * in a CLI environment.
263
     *
264
     * @param Item $item Index Queue item to use to determine the host.
265
     * @param
266
     */
267 5
    protected function initializeHttpServerEnvironment(Item $item)
268
    {
269 5
        static $hosts = [];
270 5
        $rootpageId = $item->getRootPageUid();
271 5
        $hostFound = !empty($hosts[$rootpageId]);
272
273 5
        if (!$hostFound) {
274 5
            $rootline = BackendUtility::BEgetRootLine($rootpageId);
275 5
            $host = BackendUtility::firstDomainRecord($rootline);
276 5
            $hosts[$rootpageId] = $host;
277 5
        }
278
279 5
        $_SERVER['HTTP_HOST'] = $hosts[$rootpageId];
280
281
        // needed since TYPO3 7.5
282 5
        GeneralUtility::flushInternalRuntimeCaches();
283 5
    }
284
}
285