387 lines
12 KiB
PHP
387 lines
12 KiB
PHP
|
<?php
|
||
|
namespace WapplerSystems\Meilisearch\Controller\Backend\Search;
|
||
|
|
||
|
/***************************************************************
|
||
|
* Copyright notice
|
||
|
*
|
||
|
* (c) 2010-2017 dkd Internet Service GmbH <solrs-support@dkd.de>
|
||
|
* All rights reserved
|
||
|
*
|
||
|
* This script is part of the TYPO3 project. The TYPO3 project is
|
||
|
* free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* The GNU General Public License can be found at
|
||
|
* http://www.gnu.org/copyleft/gpl.html.
|
||
|
*
|
||
|
* This script is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* This copyright notice MUST APPEAR in all copies of the script!
|
||
|
***************************************************************/
|
||
|
|
||
|
use WapplerSystems\Meilisearch\Utility\ManagedResourcesUtility;
|
||
|
use TYPO3\CMS\Backend\Template\ModuleTemplate;
|
||
|
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||
|
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
|
||
|
|
||
|
/**
|
||
|
* Manage Synonyms and Stop words in Backend Module
|
||
|
* @property \TYPO3\CMS\Extbase\Mvc\Web\Response $response
|
||
|
*/
|
||
|
class CoreOptimizationModuleController extends AbstractModuleController
|
||
|
{
|
||
|
/**
|
||
|
* Set up the doc header properly here
|
||
|
*
|
||
|
* @param ViewInterface $view
|
||
|
* @return void
|
||
|
*/
|
||
|
protected function initializeView(ViewInterface $view)
|
||
|
{
|
||
|
parent::initializeView($view);
|
||
|
|
||
|
$this->generateCoreSelectorMenuUsingPageTree();
|
||
|
/* @var ModuleTemplate $module */ // holds the state of chosen tab
|
||
|
$module = $this->objectManager->get(ModuleTemplate::class);
|
||
|
$coreOptimizationTabs = $module->getDynamicTabMenu([], 'coreOptimization');
|
||
|
$this->view->assign('tabs', $coreOptimizationTabs);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets synonyms and stopwords for the currently selected core
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function indexAction()
|
||
|
{
|
||
|
if ($this->selectedSolrCoreConnection === null) {
|
||
|
$this->view->assign('can_not_proceed', true);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$synonyms = [];
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
$rawSynonyms = $coreAdmin->getSynonyms();
|
||
|
foreach ($rawSynonyms as $baseWord => $synonymList) {
|
||
|
$synonyms[$baseWord] = implode(', ', $synonymList);
|
||
|
}
|
||
|
|
||
|
$stopWords = $coreAdmin->getStopWords();
|
||
|
$this->view->assignMultiple([
|
||
|
'synonyms' => $synonyms,
|
||
|
'stopWords' => implode(PHP_EOL, $stopWords),
|
||
|
'stopWordsCount' => count($stopWords)
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add synonyms to selected core
|
||
|
*
|
||
|
* @param string $baseWord
|
||
|
* @param string $synonyms
|
||
|
* @param bool $overrideExisting
|
||
|
* @return void
|
||
|
*/
|
||
|
public function addSynonymsAction(string $baseWord, string $synonyms, $overrideExisting)
|
||
|
{
|
||
|
if (empty($baseWord) || empty($synonyms)) {
|
||
|
$this->addFlashMessage(
|
||
|
'Please provide a base word and synonyms.',
|
||
|
'Missing parameter',
|
||
|
FlashMessage::ERROR
|
||
|
);
|
||
|
} else {
|
||
|
$baseWord = mb_strtolower($baseWord);
|
||
|
$synonyms = mb_strtolower($synonyms);
|
||
|
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
if ($overrideExisting && $coreAdmin->getSynonyms($baseWord)) {
|
||
|
$coreAdmin->deleteSynonym($baseWord);
|
||
|
}
|
||
|
$coreAdmin->addSynonym($baseWord, GeneralUtility::trimExplode(',', $synonyms, true));
|
||
|
$coreAdmin->reloadCore();
|
||
|
|
||
|
$this->addFlashMessage(
|
||
|
'"' . $synonyms . '" added as synonyms for base word "' . $baseWord . '"'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$this->redirect('index');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $fileFormat
|
||
|
* @return void
|
||
|
*/
|
||
|
public function exportStopWordsAction($fileFormat = 'txt')
|
||
|
{
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
$this->exportFile(
|
||
|
implode(PHP_EOL, $coreAdmin->getStopWords()),
|
||
|
'stopwords',
|
||
|
$fileFormat
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Exports synonyms to a download file.
|
||
|
*
|
||
|
* @param string $fileFormat
|
||
|
* @return string
|
||
|
*/
|
||
|
public function exportSynonymsAction($fileFormat = 'txt')
|
||
|
{
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
$synonyms = $coreAdmin->getSynonyms();
|
||
|
return $this->exportFile(ManagedResourcesUtility::exportSynonymsToTxt($synonyms), 'synonyms', $fileFormat);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param array $synonymFileUpload
|
||
|
* @param bool $overrideExisting
|
||
|
* @param bool $deleteSynonymsBefore
|
||
|
* @return void
|
||
|
*/
|
||
|
public function importSynonymListAction(array $synonymFileUpload, $overrideExisting, $deleteSynonymsBefore)
|
||
|
{
|
||
|
if ($deleteSynonymsBefore) {
|
||
|
$this->deleteAllSynonyms();
|
||
|
}
|
||
|
|
||
|
$fileLines = ManagedResourcesUtility::importSynonymsFromPlainTextContents($synonymFileUpload);
|
||
|
$synonymCount = 0;
|
||
|
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
foreach ($fileLines as $baseWord => $synonyms) {
|
||
|
if (!isset($baseWord) || empty($synonyms)) {
|
||
|
continue;
|
||
|
}
|
||
|
$this->deleteExistingSynonym($overrideExisting, $deleteSynonymsBefore, $baseWord);
|
||
|
$coreAdmin->addSynonym($baseWord, $synonyms);
|
||
|
$synonymCount++;
|
||
|
}
|
||
|
|
||
|
$coreAdmin->reloadCore();
|
||
|
$this->addFlashMessage(
|
||
|
$synonymCount . ' synonyms imported.'
|
||
|
);
|
||
|
$this->redirect('index');
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param array $stopwordsFileUpload
|
||
|
* @param bool $replaceStopwords
|
||
|
* @return void
|
||
|
*/
|
||
|
public function importStopWordListAction(array $stopwordsFileUpload, $replaceStopwords)
|
||
|
{
|
||
|
$this->saveStopWordsAction(
|
||
|
ManagedResourcesUtility::importStopwordsFromPlainTextContents($stopwordsFileUpload),
|
||
|
$replaceStopwords
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Delete complete synonym list
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
public function deleteAllSynonymsAction()
|
||
|
{
|
||
|
$allSynonymsCouldBeDeleted = $this->deleteAllSynonyms();
|
||
|
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
$reloadResponse = $coreAdmin->reloadCore();
|
||
|
|
||
|
if ($allSynonymsCouldBeDeleted
|
||
|
&& $reloadResponse->getHttpStatus() == 200
|
||
|
) {
|
||
|
$this->addFlashMessage(
|
||
|
'All synonym removed.'
|
||
|
);
|
||
|
} else {
|
||
|
$this->addFlashMessage(
|
||
|
'Failed to remove all synonyms.',
|
||
|
'An error occurred',
|
||
|
FlashMessage::ERROR
|
||
|
);
|
||
|
}
|
||
|
$this->redirect('index');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Deletes a synonym mapping by its base word.
|
||
|
*
|
||
|
* @param string $baseWord Synonym mapping base word
|
||
|
*/
|
||
|
public function deleteSynonymsAction($baseWord)
|
||
|
{
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
$deleteResponse = $coreAdmin->deleteSynonym($baseWord);
|
||
|
$reloadResponse = $coreAdmin->reloadCore();
|
||
|
|
||
|
if ($deleteResponse->getHttpStatus() == 200
|
||
|
&& $reloadResponse->getHttpStatus() == 200
|
||
|
) {
|
||
|
$this->addFlashMessage(
|
||
|
'Synonym removed.'
|
||
|
);
|
||
|
} else {
|
||
|
$this->addFlashMessage(
|
||
|
'Failed to remove synonym.',
|
||
|
'An error occurred',
|
||
|
FlashMessage::ERROR
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$this->redirect('index');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Saves the edited stop word list to Solr
|
||
|
*
|
||
|
* @param string $stopWords
|
||
|
* @param bool $replaceStopwords
|
||
|
* @return void
|
||
|
*/
|
||
|
public function saveStopWordsAction(string $stopWords, $replaceStopwords = true)
|
||
|
{
|
||
|
// lowercase stopword before saving because terms get lowercased before stopword filtering
|
||
|
$newStopWords = mb_strtolower($stopWords);
|
||
|
$newStopWords = GeneralUtility::trimExplode("\n", $newStopWords, true);
|
||
|
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
$oldStopWords = $coreAdmin->getStopWords();
|
||
|
|
||
|
if ($replaceStopwords) {
|
||
|
$removedStopWords = array_diff($oldStopWords, $newStopWords);
|
||
|
$wordsRemoved = $this->removeStopsWordsFromIndex($removedStopWords);
|
||
|
} else {
|
||
|
$wordsRemoved = true;
|
||
|
}
|
||
|
|
||
|
$wordsAdded = true;
|
||
|
$addedStopWords = array_diff($newStopWords, $oldStopWords);
|
||
|
if (!empty($addedStopWords)) {
|
||
|
$wordsAddedResponse = $coreAdmin->addStopWords($addedStopWords);
|
||
|
$wordsAdded = ($wordsAddedResponse->getHttpStatus() == 200);
|
||
|
}
|
||
|
|
||
|
$reloadResponse = $coreAdmin->reloadCore();
|
||
|
if ($wordsRemoved && $wordsAdded && $reloadResponse->getHttpStatus() == 200) {
|
||
|
$this->addFlashMessage(
|
||
|
'Stop Words Updated.'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$this->redirect('index');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $content
|
||
|
* @param string $type
|
||
|
* @param string $fileExtension
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function exportFile($content, $type = 'synonyms', $fileExtension = 'txt') : string
|
||
|
{
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
|
||
|
$this->response->setHeader('Content-type', 'text/plain', true);
|
||
|
$this->response->setHeader('Cache-control', 'public', true);
|
||
|
$this->response->setHeader('Content-Description', 'File transfer', true);
|
||
|
$this->response->setHeader(
|
||
|
'Content-disposition',
|
||
|
'attachment; filename =' . $type . '_' .
|
||
|
$coreAdmin->getPrimaryEndpoint()->getCore() . '.' . $fileExtension,
|
||
|
true
|
||
|
);
|
||
|
|
||
|
$this->response->setContent($content);
|
||
|
$this->sendFileResponse();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This method send the headers and content and does an exit, since without the exit TYPO3 produces and error.
|
||
|
* @return void
|
||
|
*/
|
||
|
protected function sendFileResponse()
|
||
|
{
|
||
|
$this->response->sendHeaders();
|
||
|
$this->response->send();
|
||
|
$this->response->shutdown();
|
||
|
|
||
|
exit();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Delete complete synonym list form solr
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
protected function deleteAllSynonyms() : bool
|
||
|
{
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
$synonyms = $coreAdmin->getSynonyms();
|
||
|
$allSynonymsCouldBeDeleted = true;
|
||
|
|
||
|
foreach ($synonyms as $baseWord => $synonym) {
|
||
|
$deleteResponse = $coreAdmin->deleteSynonym($baseWord);
|
||
|
$allSynonymsCouldBeDeleted = $allSynonymsCouldBeDeleted && $deleteResponse->getHttpStatus() == 200;
|
||
|
}
|
||
|
|
||
|
return $allSynonymsCouldBeDeleted;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $stopwordsToRemove
|
||
|
* @return bool
|
||
|
*/
|
||
|
protected function removeStopsWordsFromIndex($stopwordsToRemove) : bool
|
||
|
{
|
||
|
$wordsRemoved = true;
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
|
||
|
foreach ($stopwordsToRemove as $word) {
|
||
|
$response = $coreAdmin->deleteStopWord($word);
|
||
|
if ($response->getHttpStatus() != 200) {
|
||
|
$wordsRemoved = false;
|
||
|
$this->addFlashMessage(
|
||
|
'Failed to remove stop word "' . $word . '".',
|
||
|
'An error occurred',
|
||
|
FlashMessage::ERROR
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $wordsRemoved;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Delete synonym entry if selceted before
|
||
|
* @param bool $overrideExisting
|
||
|
* @param bool $deleteSynonymsBefore
|
||
|
* @param string $baseWord
|
||
|
*/
|
||
|
protected function deleteExistingSynonym($overrideExisting, $deleteSynonymsBefore, $baseWord)
|
||
|
{
|
||
|
$coreAdmin = $this->selectedSolrCoreConnection->getAdminService();
|
||
|
|
||
|
if (!$deleteSynonymsBefore &&
|
||
|
$overrideExisting &&
|
||
|
$coreAdmin->getSynonyms($baseWord)
|
||
|
) {
|
||
|
$coreAdmin->deleteSynonym($baseWord);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|