Completed
Pull Request — develop (#167)
by Daniel
25:11
created

AbstractIndexer::deleteDocuments()   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 52
     */
62
    public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager)
63 52
    {
64 52
        $this->logger = $logManager->getLogger(__CLASS__);
65
    }
66 50
67
    public function __construct(ConnectionInterface $connection, ConfigurationContainerInterface $configuration)
68 50
    {
69 50
        $this->connection = $connection;
70
        $this->configuration = $configuration;
71 52
    }
72
73 52
    public function indexAllDocuments()
74 52
    {
75 52
        $this->logger->info('Start indexing');
76
        foreach ($this->getRecordGenerator() as $records) {
77 24
            if ($records === null) {
78
                break;
79 24
            }
80 24
81 24
            foreach ($records as &$record) {
82 24
                $this->prepareRecord($record);
83
            }
84
85 24
            $this->logger->debug('Index records.', [$records]);
86 24
            $this->connection->addDocuments($this->getDocumentName(), $records);
87
        }
88
        $this->logger->info('Finish indexing');
89 24
    }
90 24
91
    public function indexDocument(string $identifier)
92 24
    {
93 24
        $this->logger->info('Start indexing single record.', [$identifier]);
94
        try {
95 4
            $record = $this->getRecord((int)$identifier);
96
            $this->prepareRecord($record);
97 4
98
            $this->connection->addDocument($this->getDocumentName(), $record);
99 4
        } catch (NoRecordFoundException $e) {
100 2
            $this->logger->info('Could not index document. Try to delete it therefore.', [$e->getMessage()]);
101
            $this->connection->deleteDocument($this->getDocumentName(), $this->getDocumentIdentifier($identifier));
102 2
        }
103 2
        $this->logger->info('Finish indexing');
104 2
    }
105 2
106
    public function delete()
107 4
    {
108 4
        $this->logger->info('Start deletion of index.');
109
        $this->connection->deleteIndex();
110 2
        $this->logger->info('Finish deletion.');
111
    }
112 2
113 2
    public function deleteDocuments()
114 2
    {
115 2
        $this->logger->info('Start deletion of indexed documents.');
116
        $this->connection->deleteIndexByDocumentType($this->getDocumentName());
117 24
        $this->logger->info('Finish deletion.');
118
    }
119 24
120 24
    protected function getRecordGenerator(): \Generator
121
    {
122 24
        $offset = 0;
123 24
        $limit = $this->getLimit();
124 24
125
        while (($records = $this->getRecords($offset, $limit)) !== null) {
126
            if (!empty($records)) {
127
                yield $records;
128 26
            }
129
            $offset += $limit;
130
        }
131 26
    }
132 24
133
    protected function prepareRecord(array &$record)
134 2
    {
135
        try {
136
            foreach ($this->configuration->get('indexing.' . $this->identifier . '.dataProcessing') as $configuration) {
137
                $record = $this->dataProcessorService->executeDataProcessor($configuration, $record, $this->identifier);
138 26
            }
139 26
        } catch (InvalidArgumentException $e) {
140
            // Nothing to do.
141 26
        }
142
        $this->generateSearchIdentifiers($record);
143 26
        $this->handleAbstract($record);
144
    }
145
146 26
    protected function generateSearchIdentifiers(array &$record)
147 26
    {
148 26
        if (!isset($record['search_document'])) {
149
            $record['search_document_type'] = $this->getDocumentName();
150 8
        }
151
        if (!isset($record['search_identifier']) && isset($record['uid'])) {
152
            $record['search_identifier'] = $this->getDocumentIdentifier($record['uid']);
153 8
        }
154 8
    }
155 8
156 8
    protected function handleAbstract(array &$record)
157
    {
158
        $record['search_abstract'] = '';
159 18
160 18
        try {
161
            $fieldsToUse = GeneralUtility::trimExplode(
162 8
                ',',
163
                $this->configuration->get('indexing.' . $this->identifier . '.abstractFields')
164
            );
165
            if ($fieldsToUse === []) {
166
                throw new InvalidArgumentException('No fields to use', 1538487209251);
167 24
            }
168
169
            foreach ($fieldsToUse as $fieldToUse) {
170 24
                if (isset($record[$fieldToUse]) && trim($record[$fieldToUse])) {
171
                    $record['search_abstract'] = trim($record[$fieldToUse]);
172
                    break;
173
                }
174
            }
175
        } catch (InvalidArgumentException $e) {
176
            // Nothing to do.
177
        }
178
    }
179
180
    /**
181
     * Returns the limit to use to fetch records.
182
     */
183
    protected function getLimit(): int
184
    {
185
        // TODO: Make configurable.
186
        return 50;
187
    }
188
189
    public function setIdentifier(string $identifier)
190
    {
191
        $this->identifier = $identifier;
192
    }
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 public function getDocumentIdentifier($identifier): string;
212
}
213