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

AbstractIndexer::deleteAllDocuments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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