Failed Conditions
Push — task/2976_TYPO3.11_compatibili... ( 14c9f4...2d3a36 )
by Rafael
23:17
created

CoreOptimizationModuleController   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 344
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 40
eloc 142
c 1
b 0
f 0
dl 0
loc 344
ccs 0
cts 118
cp 0
rs 9.2

14 Methods

Rating   Name   Duplication   Size   Complexity  
A importSynonymListAction() 0 24 5
A removeStopsWordsFromIndex() 0 19 3
A deleteAllSynonyms() 0 12 3
A deleteExistingSynonym() 0 9 4
A saveStopWordsAction() 0 31 6
A exportSynonymsAction() 0 5 1
A initializeView() 0 6 1
A exportStopWordsAction() 0 7 1
A importStopWordListAction() 0 7 1
A deleteAllSynonymsAction() 0 21 3
A indexAction() 0 22 3
A deleteSynonymsAction() 0 21 3
A addSynonymsAction() 0 25 5
A exportFile() 0 13 1

How to fix   Complexity   

Complex Class

Complex classes like CoreOptimizationModuleController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CoreOptimizationModuleController, and based on these observations, apply Extract Interface, too.

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 void
56
     * @noinspection PhpUnused
57
     */
58
    public function indexAction(): ResponseInterface
59
    {
60
        if ($this->selectedSolrCoreConnection === null) {
61
            $this->view->assign('can_not_proceed', true);
62
            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...
63
        }
64
65
        $synonyms = [];
66
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
67
        $rawSynonyms = $coreAdmin->getSynonyms();
68
        foreach ($rawSynonyms as $baseWord => $synonymList) {
69
            $synonyms[$baseWord] = implode(', ', $synonymList);
70
        }
71
72
        $stopWords = $coreAdmin->getStopWords();
73
        $this->view->assignMultiple([
74
            'synonyms' => $synonyms,
75
            'stopWords' => implode(PHP_EOL, $stopWords),
76
            'stopWordsCount' => count($stopWords)
77
        ]);
78
        $this->moduleTemplate->setContent($this->view->render());
79
        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...
80
    }
81
82
    /**
83
     * Add synonyms to selected core
84
     *
85
     * @param string $baseWord
86
     * @param string $synonyms
87
     * @param bool $overrideExisting
88
     * @return ResponseInterface
89
     * @noinspection PhpUnused
90
     */
91
    public function addSynonymsAction(string $baseWord, string $synonyms, bool $overrideExisting): ResponseInterface
92
    {
93
        if (empty($baseWord) || empty($synonyms)) {
94
            $this->addFlashMessage(
95
                'Please provide a base word and synonyms.',
96
                'Missing parameter',
97
                FlashMessage::ERROR
98
            );
99
        } else {
100
            $baseWord = mb_strtolower($baseWord);
101
            $synonyms = mb_strtolower($synonyms);
102
103
            $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

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