Passed
Push — task/2976_TYPO3.11_compatibili... ( 9f9205...0f123d )
by Rafael
27:04
created

onse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace ApacheSolrForTypo3\Solr\Controller\Backend\Search;
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
use ApacheSolrForTypo3\Solr\System\Mvc\Backend\Component\Exception\InvalidViewObjectNameException;
19
use ApacheSolrForTypo3\Solr\Utility\ManagedResourcesUtility;
20
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
21
use Psr\Http\Message\ResponseInterface;
22
use Throwable;
23
use TYPO3\CMS\Core\Http\RedirectResponse;
24
use TYPO3\CMS\Core\Messaging\FlashMessage;
25
use TYPO3\CMS\Core\Utility\GeneralUtility;
26
use TYPO3Fluid\Fluid\View\ViewInterface;
27
28
/**
29
 * Manage Synonyms and Stop words in Backend Module
30
 * @property ResponseInterface $response
31
 */
32
class CoreOptimizationModuleController extends AbstractModuleController
33
{
34
    /**
35
     * Set up the doc header properly here
36
     *
37
     * @param ViewInterface $view
38
     * @return void
39
     * @throws DBALDriverException
40
     * @throws InvalidViewObjectNameException
41
     * @throws Throwable
42
     * @noinspection PhpUnused
43
     */
44
    protected function initializeView($view)
45
    {
46
        parent::initializeView($view);
47
        $this->generateCoreSelectorMenuUsingPageTree();
48
        $coreOptimizationTabs = $this->moduleTemplate->getDynamicTabMenu([], 'coreOptimization');
49
        $this->view->assign('tabs', $coreOptimizationTabs);
50
    }
51
52
    /**
53
     * Gets synonyms and stopwords for the currently selected core
54
     *
55
     * @return ResponseInterface
56
     *
57
     * @noinspection PhpUnused
58
     */
59
    public function indexAction(): ResponseInterface
60
    {
61
        if ($this->selectedSolrCoreConnection === null) {
62
            $this->view->assign('can_not_proceed', true);
63
            return $this->htmlResponse();
64
        }
65
66
        $synonyms = [];
67
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
68
        $rawSynonyms = $coreAdmin->getSynonyms();
69
        foreach ($rawSynonyms as $baseWord => $synonymList) {
70
            $synonyms[$baseWord] = implode(', ', $synonymList);
71
        }
72
73
        $stopWords = $coreAdmin->getStopWords();
74
        $this->view->assignMultiple([
75
            'synonyms' => $synonyms,
76
            'stopWords' => implode(PHP_EOL, $stopWords),
77
            'stopWordsCount' => count($stopWords)
78
        ]);
79
        $this->moduleTemplate->setContent($this->view->render());
80
        return $this->htmlResponse($this->moduleTemplate->renderContent());
81
    }
82
83
    /**
84
     * Add synonyms to selected core
85
     *
86
     * @param string $baseWord
87
     * @param string $synonyms
88
     * @param bool $overrideExisting
89
     * @return ResponseInterface
90
     *
91
     * @noinspection PhpUnused
92
     */
93
    public function addSynonymsAction(string $baseWord, string $synonyms, bool $overrideExisting): ResponseInterface
94
    {
95
        if (empty($baseWord) || empty($synonyms)) {
96
            $this->addFlashMessage(
97
                'Please provide a base word and synonyms.',
98
                'Missing parameter',
99
                FlashMessage::ERROR
100
            );
101
        } else {
102
            $baseWord = mb_strtolower($baseWord);
103
            $synonyms = mb_strtolower($synonyms);
104
105
            $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
0 ignored issues
show
Bug introduced by
The method getAdminService() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

105
            /** @scrutinizer ignore-call */ 
106
            $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
106
            if ($overrideExisting && $coreAdmin->getSynonyms($baseWord)) {
107
                $coreAdmin->deleteSynonym($baseWord);
108
            }
109
            $coreAdmin->addSynonym($baseWord, GeneralUtility::trimExplode(',', $synonyms, true));
110
            $coreAdmin->reloadCore();
111
112
            $this->addFlashMessage(
113
                '"' . $synonyms . '" added as synonyms for base word "' . $baseWord . '"'
114
            );
115
        }
116
117
        return new RedirectResponse($this->uriBuilder->uriFor('index'), 303);
118
    }
119
120
    /**
121
     * @param string $fileFormat
122
     * @return ResponseInterface
123
     *
124
     * @noinspection PhpUnused
125
     */
126
    public function exportStopWordsAction(string $fileFormat = 'txt'): ResponseInterface
127
    {
128
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
129
        return $this->exportFile(
130
            implode(PHP_EOL, $coreAdmin->getStopWords()),
131
            'stopwords',
132
            $fileFormat
133
        );
134
    }
135
136
    /**
137
     * Exports synonyms to a download file.
138
     *
139
     * @param string $fileFormat
140
     * @return ResponseInterface
141
     *
142
     * @noinspection PhpUnused
143
     */
144
    public function exportSynonymsAction(string $fileFormat = 'txt'): ResponseInterface
145
    {
146
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
147
        $synonyms = $coreAdmin->getSynonyms();
148
        return $this->exportFile(ManagedResourcesUtility::exportSynonymsToTxt($synonyms), 'synonyms', $fileFormat);
149
    }
150
151
    /**
152
     * @param array $synonymFileUpload
153
     * @param bool $overrideExisting
154
     * @param bool $deleteSynonymsBefore
155
     * @return ResponseInterface
156
     *
157
     * @noinspection PhpUnused
158
     */
159
    public function importSynonymListAction(
160
        array $synonymFileUpload,
161
        bool $overrideExisting = false,
162
        bool $deleteSynonymsBefore = false
163
    ): ResponseInterface {
164
        if ($deleteSynonymsBefore) {
165
            $this->deleteAllSynonyms();
166
        }
167
168
        $fileLines = ManagedResourcesUtility::importSynonymsFromPlainTextContents($synonymFileUpload);
169
        $synonymCount = 0;
170
171
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
172
        foreach ($fileLines as $baseWord => $synonyms) {
173
            if (!isset($baseWord) || empty($synonyms)) {
174
                continue;
175
            }
176
            $this->deleteExistingSynonym($overrideExisting, $deleteSynonymsBefore, $baseWord);
177
            $coreAdmin->addSynonym($baseWord, $synonyms);
178
            $synonymCount++;
179
        }
180
181
        $coreAdmin->reloadCore();
182
        $this->addFlashMessage(
183
            $synonymCount . ' synonyms imported.'
184
        );
185
        return new RedirectResponse($this->uriBuilder->uriFor('index'), 303);
186
    }
187
188
    /**
189
     * @param array $stopwordsFileUpload
190
     * @param bool $replaceStopwords
191
     *
192
     * @return ResponseInterface
193
     *
194
     * @noinspection PhpUnused
195
     */
196
    public function importStopWordListAction(array $stopwordsFileUpload, bool $replaceStopwords): ResponseInterface
197
    {
198
        $this->saveStopWordsAction(
199
            ManagedResourcesUtility::importStopwordsFromPlainTextContents($stopwordsFileUpload),
200
            $replaceStopwords
201
        );
202
        return new RedirectResponse($this->uriBuilder->uriFor('index'), 303);
203
    }
204
205
    /**
206
     * Delete complete synonym list
207
     *
208
     * @return ResponseInterface
209
     *
210
     * @noinspection PhpUnused
211
     */
212
    public function deleteAllSynonymsAction(): ResponseInterface
213
    {
214
        $allSynonymsCouldBeDeleted = $this->deleteAllSynonyms();
215
216
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
217
        $reloadResponse = $coreAdmin->reloadCore();
218
219
        if ($allSynonymsCouldBeDeleted
220
            && $reloadResponse->getHttpStatus() == 200
221
        ) {
222
            $this->addFlashMessage(
223
                'All synonym removed.'
224
            );
225
        } else {
226
            $this->addFlashMessage(
227
                'Failed to remove all synonyms.',
228
                'An error occurred',
229
                FlashMessage::ERROR
230
            );
231
        }
232
        return new RedirectResponse($this->uriBuilder->uriFor('index'), 303);
233
    }
234
235
    /**
236
     * Deletes a synonym mapping by its base word.
237
     *
238
     * @param string $baseWord Synonym mapping base word
239
     *
240
     * @return ResponseInterface
241
     *
242
     * @noinspection PhpUnused
243
     */
244
    public function deleteSynonymsAction(string $baseWord): ResponseInterface
245
    {
246
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
247
        $deleteResponse = $coreAdmin->deleteSynonym($baseWord);
248
        $reloadResponse = $coreAdmin->reloadCore();
249
250
        if ($deleteResponse->getHttpStatus() == 200
251
            && $reloadResponse->getHttpStatus() == 200
252
        ) {
253
            $this->addFlashMessage(
254
                'Synonym removed.'
255
            );
256
        } else {
257
            $this->addFlashMessage(
258
                'Failed to remove synonym.',
259
                'An error occurred',
260
                FlashMessage::ERROR
261
            );
262
        }
263
264
        return new RedirectResponse($this->uriBuilder->uriFor('index'), 303);
265
    }
266
267
    /**
268
     * Saves the edited stop word list to Solr
269
     *
270
     * @param string $stopWords
271
     * @param bool $replaceStopwords
272
     *
273
     * @return ResponseInterface
274
     *
275
     * @noinspection PhpUnused
276
     */
277
    public function saveStopWordsAction(string $stopWords, bool $replaceStopwords = true): ResponseInterface
278
    {
279
        // lowercase stopword before saving because terms get lowercased before stopword filtering
280
        $newStopWords = mb_strtolower($stopWords);
281
        $newStopWords = GeneralUtility::trimExplode("\n", $newStopWords, true);
282
283
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
284
        $oldStopWords = $coreAdmin->getStopWords();
285
286
        if ($replaceStopwords) {
287
            $removedStopWords = array_diff($oldStopWords, $newStopWords);
288
            $wordsRemoved = $this->removeStopsWordsFromIndex($removedStopWords);
289
        } else {
290
            $wordsRemoved = true;
291
        }
292
293
        $wordsAdded = true;
294
        $addedStopWords = array_diff($newStopWords, $oldStopWords);
295
        if (!empty($addedStopWords)) {
296
            $wordsAddedResponse = $coreAdmin->addStopWords($addedStopWords);
297
            $wordsAdded = ($wordsAddedResponse->getHttpStatus() == 200);
298
        }
299
300
        $reloadResponse = $coreAdmin->reloadCore();
301
        if ($wordsRemoved && $wordsAdded && $reloadResponse->getHttpStatus() == 200) {
302
            $this->addFlashMessage(
303
                'Stop Words Updated.'
304
            );
305
        }
306
307
        return new RedirectResponse($this->uriBuilder->uriFor('index'), 303);
308
    }
309
310
    /**
311
     * @param string $content
312
     * @param string $type
313
     * @param string $fileExtension
314
     *
315
     * @return ResponseInterface
316
     */
317
    protected function exportFile(string $content, string $type = 'synonyms', string $fileExtension = 'txt'): ResponseInterface
318
    {
319
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
320
        return  $this->responseFactory->createResponse()
321
            ->withHeader('Content-Type', 'text/plain; charset=utf-8')
322
            ->withHeader('Cache-control', 'public')
323
            ->withHeader('Content-Description', 'File transfer')
324
            ->withHeader('Content-Description', 'File transfer')
325
            ->withHeader(
326
                'Content-disposition',
327
                'attachment; filename =' . $type . '_' . $coreAdmin->getPrimaryEndpoint()->getCore() . '.' . $fileExtension
328
            )
329
            ->withBody($this->streamFactory->createStream($content));
330
    }
331
332
    /**
333
     * Delete complete synonym list form solr
334
     *
335
     * @return bool
336
     */
337
    protected function deleteAllSynonyms(): bool
338
    {
339
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
340
        $synonyms = $coreAdmin->getSynonyms();
341
        $allSynonymsCouldBeDeleted = true;
342
343
        foreach ($synonyms as $baseWord => $synonym) {
344
            $deleteResponse = $coreAdmin->deleteSynonym($baseWord);
345
            $allSynonymsCouldBeDeleted = $allSynonymsCouldBeDeleted && $deleteResponse->getHttpStatus() == 200;
346
        }
347
348
        return $allSynonymsCouldBeDeleted;
349
    }
350
351
    /**
352
     * @param $stopwordsToRemove
353
     * @return bool
354
     */
355
    protected function removeStopsWordsFromIndex($stopwordsToRemove): bool
356
    {
357
        $wordsRemoved = true;
358
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
359
360
        foreach ($stopwordsToRemove as $word) {
361
            $response = $coreAdmin->deleteStopWord($word);
362
            if ($response->getHttpStatus() != 200) {
363
                $wordsRemoved = false;
364
                $this->addFlashMessage(
365
                    'Failed to remove stop word "' . $word . '".',
366
                    'An error occurred',
367
                    FlashMessage::ERROR
368
                );
369
                break;
370
            }
371
        }
372
373
        return $wordsRemoved;
374
    }
375
376
    /**
377
     * Delete synonym entry if selected before
378
     * @param bool $overrideExisting
379
     * @param bool $deleteSynonymsBefore
380
     * @param string $baseWord
381
     */
382
    protected function deleteExistingSynonym(bool $overrideExisting, bool $deleteSynonymsBefore, string $baseWord)
383
    {
384
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
385
386
        if (!$deleteSynonymsBefore &&
387
            $overrideExisting &&
388
            $coreAdmin->getSynonyms($baseWord)
389
        ) {
390
            $coreAdmin->deleteSynonym($baseWord);
391
        }
392
    }
393
}
394