Passed
Pull Request — develop (#167)
by
unknown
20:25
created

AbstractIndexer::generateSearchIdentifiers()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 20
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 52
     * @param \TYPO3\CMS\Core\Log\LogManager $logManager
62
     */
63 52
    public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager)
64 52
    {
65
        $this->logger = $logManager->getLogger(__CLASS__);
66 50
    }
67
68 50
    /**
69 50
     * @param string $identifier
70
     * @return void
71 52
     */
72
    public function setIdentifier(string $identifier)
73 52
    {
74 52
        $this->identifier = $identifier;
75 52
    }
76
77 24
    /**
78
     * AbstractIndexer constructor.
79 24
     * @param ConnectionInterface $connection
80 24
     * @param ConfigurationContainerInterface $configuration
81 24
     */
82 24
    public function __construct(ConnectionInterface $connection, ConfigurationContainerInterface $configuration)
83
    {
84
        $this->connection = $connection;
85 24
        $this->configuration = $configuration;
86 24
    }
87
88
    /**
89 24
     * @return void
90 24
     */
91
    public function indexAllDocuments()
92 24
    {
93 24
        $this->logger->info('Start indexing');
94
        foreach ($this->getRecordGenerator() as $records) {
95 4
            if ($records === null) {
96
                break;
97 4
            }
98
99 4
            foreach ($records as &$record) {
100 2
                $this->prepareRecord($record);
101
            }
102 2
103 2
            $this->logger->debug('Index records.', [$records]);
104 2
            $this->connection->addDocuments($this->getDocumentName(), $records);
105 2
        }
106
        $this->logger->info('Finish indexing');
107 4
    }
108 4
109
    /**
110 2
     * @param string $identifier
111
     * @return void
112 2
     */
113 2
    public function indexDocument(string $identifier)
114 2
    {
115 2
        $this->logger->info('Start indexing single record.', [$identifier]);
116
        try {
117 24
            $record = $this->getRecord((int)$identifier);
118
            $this->prepareRecord($record);
119 24
120 24
            $this->connection->addDocument($this->getDocumentName(), $record);
121
        } catch (NoRecordFoundException $e) {
122 24
            $this->logger->info('Could not index document. Try to delete it therefore.', [$e->getMessage()]);
123 24
            $this->connection->deleteDocument($this->getDocumentName(), $this->getIdentifier($identifier));
124 24
        }
125
        $this->logger->info('Finish indexing');
126
    }
127
128 26
    /**
129
     * @return void
130
     */
131 26
    public function delete()
132 24
    {
133
        $this->logger->info('Start deletion of index.');
134 2
        $this->connection->deleteIndex();
135
        $this->logger->info('Finish deletion.');
136
    }
137
138 26
    /**
139 26
     * @return void
140
     */
141 26
    public function deleteDocuments()
142
    {
143 26
        $this->logger->info('Start deletion of indexed documents.');
144
        $this->connection->deleteIndexByQuery(Query::create([
145
            'query' => [
146 26
                'term' => [
147 26
                    'search_document_type' => $this->getDocumentName()
148 26
                ]
149
            ]
150 8
        ]));
151
        $this->logger->info('Finish deletion.');
152
    }
153 8
154 8
    /**
155 8
     * @return \Generator
156 8
     */
157
    protected function getRecordGenerator()
158
    {
159 18
        $offset = 0;
160 18
        $limit = $this->getLimit();
161
162 8
        while (($records = $this->getRecords($offset, $limit)) !== null) {
163
            if (!empty($records)) {
164
                yield $records;
165
            }
166
            $offset += $limit;
167 24
        }
168
    }
169
170 24
    /**
171
     * @param array $record
172
     * @return void
173
     */
174
    protected function prepareRecord(array &$record)
175
    {
176
        try {
177
            foreach ($this->configuration->get('indexing.' . $this->identifier . '.dataProcessing') as $configuration) {
178
                $record = $this->dataProcessorService->executeDataProcessor($configuration, $record, $this->identifier);
179
            }
180
        } catch (InvalidArgumentException $e) {
181
            // Nothing to do.
182
        }
183
        $this->generateSearchIdentifiers($record);
184
        $this->handleAbstract($record);
185
    }
186
187
    /**
188
     * @param array $record
189
     * @return void
190
     */
191
    protected function generateSearchIdentifiers(array &$record)
192
    {
193
        if (!isset($record['search_document'])) {
194
            $record['search_document_type'] = $this->getDocumentName();
195
        }
196
        if (!isset($record['search_identifier']) && isset($record['uid'])) {
197
            $record['search_identifier'] = $this->getIdentifier($record['uid']);
198
        }
199
    }
200
201
    /**
202
     * @param array $record
203
     * @return void
204
     */
205
    protected function handleAbstract(array &$record)
206
    {
207
        $record['search_abstract'] = '';
208
209
        try {
210
            $fieldsToUse = GeneralUtility::trimExplode(
211
                ',',
212
                $this->configuration->get('indexing.' . $this->identifier . '.abstractFields')
213
            );
214
            if ($fieldsToUse === []) {
215
                throw new InvalidArgumentException('No fields to use', 1538487209251);
216
            }
217
218
            foreach ($fieldsToUse as $fieldToUse) {
219
                if (isset($record[$fieldToUse]) && trim($record[$fieldToUse])) {
220
                    $record['search_abstract'] = trim($record[$fieldToUse]);
221
                    break;
222
                }
223
            }
224
        } catch (InvalidArgumentException $e) {
225
            // Nothing to do.
226
        }
227
    }
228
229
    /**
230
     * Returns the limit to use to fetch records.
231
     *
232
     * @return integer
233
     */
234
    protected function getLimit(): int
235
    {
236
        // TODO: Make configurable.
237
        return 50;
238
    }
239
240
    /**
241
     * @param integer $offset
242
     * @param integer $limit
243
     * @return array|null
244
     */
245
    abstract protected function getRecords(int $offset, int $limit);
246
247
    /**
248
     * @param integer $identifier
249
     * @return array
250
     */
251
    abstract protected function getRecord(int $identifier): array;
252
253
    /**
254
     * @return string
255
     */
256
    abstract protected function getDocumentName(): string;
257
258
    /**
259
     * @param string $identifier
260
     * @return string
261
     */
262
    abstract public function getIdentifier($identifier): string;
263
}
264