Passed
Pull Request — develop (#167)
by Daniel
04:48
created

AbstractIndexer::generateSearchIdentifiers()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 4
1
<?php
2
3
namespace Codappix\SearchCore\Domain\Index;
4
5
/*
6
 * Copyright (C) 2017  Daniel Siepmann <[email protected]>
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
 * 02110-1301, USA.
22
 */
23
24
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
25
use Codappix\SearchCore\Configuration\InvalidArgumentException;
26
use Codappix\SearchCore\Connection\ConnectionInterface;
27
use Elastica\Query;
28
use TYPO3\CMS\Core\Utility\GeneralUtility;
29
30
abstract class AbstractIndexer implements IndexerInterface
31
{
32
    /**
33
     * @var ConnectionInterface
34
     */
35
    protected $connection;
36
37
    /**
38
     * @var ConfigurationContainerInterface
39
     */
40
    protected $configuration;
41
42
    /**
43
     * @var string
44
     */
45
    protected $identifier = '';
46
47
    /**
48
     * @var \Codappix\SearchCore\DataProcessing\Service
49
     * @inject
50
     */
51
    protected $dataProcessorService;
52
53
    /**
54
     * @var \TYPO3\CMS\Core\Log\Logger
55
     */
56
    protected $logger;
57
58
    /**
59
     * Inject log manager to get concrete logger from it.
60
     *
61
     * @param \TYPO3\CMS\Core\Log\LogManager $logManager
62
     */
63 54
    public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager)
64
    {
65 54
        $this->logger = $logManager->getLogger(__CLASS__);
66 54
    }
67
68
    /**
69
     * AbstractIndexer constructor.
70
     * @param ConnectionInterface $connection
71
     * @param ConfigurationContainerInterface $configuration
72
     */
73 54
    public function __construct(ConnectionInterface $connection, ConfigurationContainerInterface $configuration)
74
    {
75 54
        $this->connection = $connection;
76 54
        $this->configuration = $configuration;
77 54
    }
78
79
    /**
80
     * @return void
81
     */
82 26
    public function indexAllDocuments()
83
    {
84 26
        $this->logger->info('Start indexing');
85 26
        foreach ($this->getRecordGenerator() as $records) {
86 26
            if ($records === null) {
87
                break;
88
            }
89
90 26
            foreach ($records as &$record) {
91 26
                $this->prepareRecord($record);
92
            }
93
94 26
            $this->logger->debug('Index records.', [$records]);
95 26
            $this->connection->addDocuments($this->getDocumentName(), $records);
96
        }
97 26
        $this->logger->info('Finish indexing');
98 26
    }
99
100
    /**
101
     * @param string $identifier
102
     * @return void
103
     */
104 4
    public function indexDocument(string $identifier)
105
    {
106 4
        $this->logger->info('Start indexing single record.', [$identifier]);
107
        try {
108 4
            $record = $this->getRecord((int)$identifier);
109 2
            $this->prepareRecord($record);
110
111 2
            $this->connection->addDocument($this->getDocumentName(), $record);
112 2
        } catch (NoRecordFoundException $e) {
113 2
            $this->logger->info('Could not index document. Try to delete it therefore.', [$e->getMessage()]);
114 2
            $this->connection->deleteDocument($this->getDocumentName(), $this->getDocumentIdentifier($identifier));
115
        }
116 4
        $this->logger->info('Finish indexing');
117 4
    }
118
119
    /**
120
     * @return void
121
     */
122 2
    public function delete()
123
    {
124 2
        $this->logger->info('Start deletion of index.');
125 2
        $this->connection->deleteIndex();
126 2
        $this->logger->info('Finish deletion.');
127 2
    }
128
129
    /**
130
     * @return void
131
     */
132 2
    public function deleteDocuments()
133
    {
134 2
        $this->logger->info('Start deletion of indexed documents.');
135 2
        $this->connection->deleteIndexByQuery(Query::create([
136
            'query' => [
137
                'term' => [
138 2
                    'search_document_type' => $this->getDocumentName()
139
                ]
140
            ]
141
        ]));
142 2
        $this->logger->info('Finish deletion.');
143 2
    }
144
145
    /**
146
     * @return \Generator
147
     */
148 26
    protected function getRecordGenerator(): \Generator
149
    {
150 26
        $offset = 0;
151 26
        $limit = $this->getLimit();
152
153 26
        while (($records = $this->getRecords($offset, $limit)) !== null) {
154 26
            if (!empty($records)) {
155 26
                yield $records;
156
            }
157 26
            $offset += $limit;
158
        }
159 26
    }
160
161
    /**
162
     * @param array $record
163
     * @return void
164
     */
165 28
    protected function prepareRecord(array &$record)
166
    {
167
        try {
168 28
            foreach ($this->configuration->get('indexing.' . $this->identifier . '.dataProcessing') as $configuration) {
169 26
                $record = $this->dataProcessorService->executeDataProcessor($configuration, $record, $this->identifier);
170
            }
171 2
        } catch (InvalidArgumentException $e) {
172
            // Nothing to do.
173
        }
174 28
        $this->generateSearchIdentifiers($record);
175 28
        $this->handleAbstract($record);
176 28
    }
177
178
    /**
179
     * @param array $record
180
     * @return void
181
     */
182 28
    protected function generateSearchIdentifiers(array &$record)
183
    {
184 28
        if (!isset($record['search_document'])) {
185 28
            $record['search_document_type'] = $this->getDocumentName();
186
        }
187 28
        if (!isset($record['search_identifier']) && isset($record['uid'])) {
188 28
            $record['search_identifier'] = $this->getDocumentIdentifier($record['uid']);
189
        }
190 28
    }
191
192
    /**
193
     * @param array $record
194
     * @return void
195
     */
196 28
    protected function handleAbstract(array &$record)
197
    {
198 28
        $record['search_abstract'] = '';
199
200
        try {
201 28
            $fieldsToUse = GeneralUtility::trimExplode(
202 28
                ',',
203 28
                $this->configuration->get('indexing.' . $this->identifier . '.abstractFields')
204
            );
205 10
            if ($fieldsToUse === []) {
206
                throw new InvalidArgumentException('No fields to use', 1538487209251);
207
            }
208
209 10
            foreach ($fieldsToUse as $fieldToUse) {
210 10
                if (isset($record[$fieldToUse]) && trim($record[$fieldToUse])) {
211 10
                    $record['search_abstract'] = trim($record[$fieldToUse]);
212 10
                    break;
213
                }
214
            }
215 20
        } catch (InvalidArgumentException $e) {
216
            // Nothing to do.
217
        }
218 28
    }
219
220
    /**
221
     * Returns the limit to use to fetch records.
222
     *
223
     * @return integer
224
     */
225 26
    protected function getLimit(): int
226
    {
227
        // TODO: Make configurable.
228 26
        return 50;
229
    }
230
231 52
    public function setIdentifier(string $identifier)
232
    {
233 52
        $this->identifier = $identifier;
234 52
    }
235
236
    public function getIdentifier(): string
237
    {
238
        return $this->identifier;
239
    }
240
241
    /**
242
     * @param integer $offset
243
     * @param integer $limit
244
     * @return array|null
245
     */
246
    abstract protected function getRecords(int $offset, int $limit);
247
248
    /**
249
     * @param integer $identifier
250
     * @return array
251
     */
252
    abstract protected function getRecord(int $identifier): array;
253
254
    /**
255
     * @return string
256
     */
257
    abstract protected function getDocumentName(): string;
258
259
    /**
260
     * @param string $identifier
261
     * @return string
262
     */
263
    abstract public function getDocumentIdentifier($identifier): string;
264
}
265