Passed
Pull Request — develop (#167)
by Daniel
05:07
created

AbstractIndexer::deleteDocuments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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