Failed Conditions
Push — task/2976_TYPO3.11_compatibili... ( 165ace...c614ef )
by Rafael
43:34
created

deleteSynonymsAction()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 21
ccs 0
cts 6
cp 0
rs 9.8333
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 12
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\Backend\Template\ModuleTemplate;
24
use TYPO3\CMS\Core\Http\RedirectResponse;
25
use TYPO3\CMS\Core\Messaging\FlashMessage;
26
use TYPO3\CMS\Core\Utility\GeneralUtility;
27
use TYPO3Fluid\Fluid\View\ViewInterface;
28
29
/**
30
 * Manage Synonyms and Stop words in Backend Module
31
 * @property ResponseInterface $response
32
 */
33
class CoreOptimizationModuleController extends AbstractModuleController
34
{
35
    /**
36
     * Set up the doc header properly here
37
     *
38
     * @param ViewInterface $view
39
     * @return void
40
     * @throws DBALDriverException
41
     * @throws InvalidViewObjectNameException
42
     * @throws Throwable
43
     * @noinspection PhpUnused
44
     */
45
    protected function initializeView($view)
46
    {
47
        parent::initializeView($view);
48
        $this->generateCoreSelectorMenuUsingPageTree();
49
        $coreOptimizationTabs = $this->moduleTemplate->getDynamicTabMenu([], 'coreOptimization');
50
        $this->view->assign('tabs', $coreOptimizationTabs);
51
    }
52
53
    /**
54
     * Gets synonyms and stopwords for the currently selected core
55
     *
56
     * @return void
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();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->htmlResponse() returns the type Psr\Http\Message\ResponseInterface which is incompatible with the documented return type void.
Loading history...
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());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->htmlRespon...plate->renderContent()) returns the type Psr\Http\Message\ResponseInterface which is incompatible with the documented return type void.
Loading history...
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
     * @noinspection PhpUnused
91
     */
92
    public function addSynonymsAction(string $baseWord, string $synonyms, bool $overrideExisting): ResponseInterface
93
    {
94
        if (empty($baseWord) || empty($synonyms)) {
95
            $this->addFlashMessage(
96
                'Please provide a base word and synonyms.',
97
                'Missing parameter',
98
                FlashMessage::ERROR
99
            );
100
        } else {
101
            $baseWord = mb_strtolower($baseWord);
102
            $synonyms = mb_strtolower($synonyms);
103
104
            $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

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