Passed
Push — master ( a5d0a9...8581cd )
by Timo
23:17
created

sendFileResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 6
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Controller\Backend\Search;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2010-2017 dkd Internet Service GmbH <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 3 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\Utility\ManagedResourcesUtility;
28
use TYPO3\CMS\Backend\Template\ModuleTemplate;
29
use TYPO3\CMS\Core\Messaging\FlashMessage;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
32
33
/**
34
 * Manage Synonyms and Stop words in Backend Module
35
 * @property \TYPO3\CMS\Extbase\Mvc\Web\Response $response
36
 */
37
class CoreOptimizationModuleController extends AbstractModuleController
0 ignored issues
show
Bug introduced by
The type ApacheSolrForTypo3\Solr\...bstractModuleController was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
38
{
39
    /**
40
     * Set up the doc header properly here
41
     *
42
     * @param ViewInterface $view
43
     * @return void
44
     */
45
    protected function initializeView(ViewInterface $view)
46
    {
47
        parent::initializeView($view);
48
49
        $this->generateCoreSelectorMenuUsingPageTree();
50
        /* @var ModuleTemplate $module */ // holds the state of chosen tab
51
        $module = $this->objectManager->get(ModuleTemplate::class);
52
        $coreOptimizationTabs = $module->getDynamicTabMenu([], 'coreOptimization');
53
        $this->view->assign('tabs', $coreOptimizationTabs);
54
    }
55
56
    /**
57
     * Gets synonyms and stopwords for the currently selected core
58
     *
59
     * @return void
60
     */
61
    public function indexAction()
62
    {
63
        if ($this->selectedSolrCoreConnection === null) {
64
            $this->view->assign('can_not_proceed', true);
65
            return;
66
        }
67
68
        $synonyms = [];
69
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
70
        $rawSynonyms = $coreAdmin->getSynonyms();
71
        foreach ($rawSynonyms as $baseWord => $synonymList) {
72
            $synonyms[$baseWord] = implode(', ', $synonymList);
73
        }
74
75
        $stopWords = $coreAdmin->getStopWords();
76
        $this->view->assignMultiple([
77
            'synonyms' => $synonyms,
78
            'stopWords' => implode(PHP_EOL, $stopWords),
79
            'stopWordsCount' => count($stopWords)
80
        ]);
81
    }
82
83
    /**
84
     * Add synonyms to selected core
85
     *
86
     * @param string $baseWord
87
     * @param string $synonyms
88
     * @param bool $overrideExisting
89
     * @return void
90
     */
91
    public function addSynonymsAction(string $baseWord, string $synonyms, $overrideExisting)
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();
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
        $this->redirect('index');
116
    }
117
118
    /**
119
     * @param string $fileFormat
120
     * @return void
121
     */
122
    public function exportStopWordsAction($fileFormat = 'txt')
123
    {
124
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
125
        $this->exportFile(
126
            implode(PHP_EOL, $coreAdmin->getStopWords()),
127
            'stopwords',
128
            $fileFormat
129
        );
130
    }
131
132
    /**
133
     * Exports synonyms to a download file.
134
     *
135
     * @param string $fileFormat
136
     * @return string
137
     */
138
    public function exportSynonymsAction($fileFormat = 'txt')
139
    {
140
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
141
        $synonyms = $coreAdmin->getSynonyms();
142
        return $this->exportFile(ManagedResourcesUtility::exportSynonymsToTxt($synonyms), 'synonyms', $fileFormat);
143
    }
144
145
    /**
146
     * @param array $synonymFileUpload
147
     * @param bool $overrideExisting
148
     * @param bool $deleteSynonymsBefore
149
     * @return void
150
     */
151
    public function importSynonymListAction(array $synonymFileUpload, $overrideExisting, $deleteSynonymsBefore)
152
    {
153
        if ($deleteSynonymsBefore) {
154
            $this->deleteAllSynonyms();
155
        }
156
157
        $fileLines = ManagedResourcesUtility::importSynonymsFromPlainTextContents($synonymFileUpload);
158
        $synonymCount = 0;
159
160
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
161
        foreach ($fileLines as $baseWord => $synonyms) {
162
            if (!isset($baseWord) || empty($synonyms)) {
163
                continue;
164
            }
165
            $this->deleteExistingSynonym($overrideExisting, $deleteSynonymsBefore, $baseWord);
166
            $coreAdmin->addSynonym($baseWord, $synonyms);
167
            $synonymCount++;
168
        }
169
170
        $coreAdmin->reloadCore();
171
        $this->addFlashMessage(
172
            $synonymCount . ' synonyms imported.'
173
        );
174
        $this->redirect('index');
175
176
    }
177
178
    /**
179
     * @param array $stopwordsFileUpload
180
     * @param bool $replaceStopwords
181
     * @return void
182
     */
183
    public function importStopWordListAction(array $stopwordsFileUpload, $replaceStopwords)
184
    {
185
        $this->saveStopWordsAction(
186
            ManagedResourcesUtility::importStopwordsFromPlainTextContents($stopwordsFileUpload),
187
            $replaceStopwords
188
        );
189
    }
190
191
    /**
192
     * Delete complete synonym list
193
     *
194
     * @return void
195
     */
196
    public function deleteAllSynonymsAction()
197
    {
198
        $allSynonymsCouldBeDeleted = $this->deleteAllSynonyms();
199
200
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
201
        $reloadResponse = $coreAdmin->reloadCore();
202
203
        if ($allSynonymsCouldBeDeleted
204
            && $reloadResponse->getHttpStatus() == 200
205
        ) {
206
            $this->addFlashMessage(
207
                'All synonym removed.'
208
            );
209
        } else {
210
            $this->addFlashMessage(
211
                'Failed to remove all synonyms.',
212
                'An error occurred',
213
                FlashMessage::ERROR
214
            );
215
        }
216
        $this->redirect('index');
217
    }
218
219
    /**
220
     * Deletes a synonym mapping by its base word.
221
     *
222
     * @param string $baseWord Synonym mapping base word
223
     */
224
    public function deleteSynonymsAction($baseWord)
225
    {
226
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
227
        $deleteResponse = $coreAdmin->deleteSynonym($baseWord);
228
        $reloadResponse = $coreAdmin->reloadCore();
229
230
        if ($deleteResponse->getHttpStatus() == 200
231
            && $reloadResponse->getHttpStatus() == 200
232
        ) {
233
            $this->addFlashMessage(
234
                'Synonym removed.'
235
            );
236
        } else {
237
            $this->addFlashMessage(
238
                'Failed to remove synonym.',
239
                'An error occurred',
240
                FlashMessage::ERROR
241
            );
242
        }
243
244
        $this->redirect('index');
245
    }
246
247
    /**
248
     * Saves the edited stop word list to Solr
249
     *
250
     * @param string $stopWords
251
     * @param bool $replaceStopwords
252
     * @return void
253
     */
254
    public function saveStopWordsAction(string $stopWords, $replaceStopwords = true)
255
    {
256
        // lowercase stopword before saving because terms get lowercased before stopword filtering
257
        $newStopWords = mb_strtolower($stopWords);
258
        $newStopWords = GeneralUtility::trimExplode("\n", $newStopWords, true);
259
260
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
261
        $oldStopWords = $coreAdmin->getStopWords();
262
263
        if ($replaceStopwords) {
264
            $removedStopWords = array_diff($oldStopWords, $newStopWords);
265
            $wordsRemoved = $this->removeStopsWordsFromIndex($removedStopWords);
266
        } else {
267
            $wordsRemoved = true;
268
        }
269
270
        $wordsAdded = true;
271
        $addedStopWords = array_diff($newStopWords, $oldStopWords);
272
        if (!empty($addedStopWords)) {
273
            $wordsAddedResponse = $coreAdmin->addStopWords($addedStopWords);
274
            $wordsAdded = ($wordsAddedResponse->getHttpStatus() == 200);
275
        }
276
277
        $reloadResponse = $coreAdmin->reloadCore();
278
        if ($wordsRemoved && $wordsAdded && $reloadResponse->getHttpStatus() == 200) {
279
            $this->addFlashMessage(
280
                'Stop Words Updated.'
281
            );
282
        }
283
284
        $this->redirect('index');
285
    }
286
287
    /**
288
     * @param string $content
289
     * @param string $type
290
     * @param string $fileExtension
291
     * @return string
292
     */
293
    protected function exportFile($content, $type = 'synonyms', $fileExtension = 'txt') : string
294
    {
295
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
296
297
        $this->response->setHeader('Content-type', 'text/plain', true);
298
        $this->response->setHeader('Cache-control', 'public', true);
299
        $this->response->setHeader('Content-Description', 'File transfer', true);
300
        $this->response->setHeader(
301
            'Content-disposition',
302
            'attachment; filename =' . $type . '_' .
303
            $coreAdmin->getCoreName() . '.' . $fileExtension,
304
            true
305
        );
306
307
        $this->response->setContent($content);
308
        $this->sendFileResponse();
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
309
    }
310
311
    /**
312
     * This method send the headers and content and does an exit, since without the exit TYPO3 produces and error.
313
     * @return void
314
     */
315
    protected function sendFileResponse()
316
    {
317
        $this->response->sendHeaders();
318
        $this->response->shutdown();
319
        $this->response->send();
320
321
        exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
322
    }
323
324
    /**
325
     * Delete complete synonym list form solr
326
     *
327
     * @return bool
328
     */
329
    protected function deleteAllSynonyms() : bool
330
    {
331
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
332
        $synonyms = $coreAdmin->getSynonyms();
333
        $allSynonymsCouldBeDeleted = true;
334
335
        foreach ($synonyms as $baseWord => $synonym) {
336
            $deleteResponse = $coreAdmin->deleteSynonym($baseWord);
337
            $allSynonymsCouldBeDeleted = $allSynonymsCouldBeDeleted && $deleteResponse->getHttpStatus() == 200;
338
        }
339
340
        return $allSynonymsCouldBeDeleted;
341
    }
342
343
    /**
344
     * @param $stopwordsToRemove
345
     * @return bool
346
     */
347
    protected function removeStopsWordsFromIndex($stopwordsToRemove) : bool
348
    {
349
        $wordsRemoved = true;
350
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
351
352
        foreach ($stopwordsToRemove as $word) {
353
            $response = $coreAdmin->deleteStopWord($word);
354
            if ($response->getHttpStatus() != 200) {
355
                $wordsRemoved = false;
356
                $this->addFlashMessage(
357
                    'Failed to remove stop word "' . $word . '".',
358
                    'An error occurred',
359
                    FlashMessage::ERROR
360
                );
361
                break;
362
            }
363
        }
364
365
        return $wordsRemoved;
366
    }
367
368
    /**
369
     * Delete synonym entry if selceted before
370
     * @param bool $overrideExisting
371
     * @param bool $deleteSynonymsBefore
372
     * @param string $baseWord
373
     */
374
    protected function deleteExistingSynonym($overrideExisting, $deleteSynonymsBefore, $baseWord)
375
    {
376
        $coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
377
378
        if (!$deleteSynonymsBefore &&
379
            $overrideExisting &&
380
            $coreAdmin->getSynonyms($baseWord)
381
        ) {
382
            $coreAdmin->deleteSynonym($baseWord);
383
        }
384
385
    }
386
}
387