first commit

This commit is contained in:
Sven Wappler
2021-04-17 00:26:33 +02:00
commit 866c63cc63
813 changed files with 100696 additions and 0 deletions

View File

@@ -0,0 +1,214 @@
<?php
namespace WapplerSystems\Meilisearch\Controller\Backend;
/***************************************************************
* Copyright notice
*
* (c) 2012-2015 Ingo Renner <ingo@typo3.org>
* 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 TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
use TYPO3\CMS\Fluid\View\StandaloneView;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Backend\View\PageLayoutView;
/**
* Summary to display flexform settings in the page layout backend module.
*
* @author Ingo Renner <ingo@typo3.org>
* @author Timo Hund <timo.hund@dkd.de>
*/
class PageModuleSummary
{
/**
* PageLayoutView
*
* @var PageLayoutView
*/
protected $pageLayoutView;
/**
* @var array
*/
protected $pluginContentElement = [];
/**
* @var array
*/
protected $flexformData = [];
/**
* @var array
*/
protected $settings = [];
/**
* Returns information about a plugin's flexform configuration
*
* @param array $parameters Parameters to the hook
* @return string Plugin configuration information
*/
public function getSummary(array $parameters)
{
$this->initialize($parameters['row'], $parameters['pObj']);
$this->addTargetPage();
$this->addSettingFromFlexForm('Filter', 'search.query.filter');
$this->addSettingFromFlexForm('Sorting', 'search.query.sortBy');
$this->addSettingFromFlexForm('Results per Page', 'search.results.resultsPerPage');
$this->addSettingFromFlexForm('Boost Function', 'search.query.boostFunction');
$this->addSettingFromFlexForm('Boost Query', 'search.query.boostQuery');
$this->addSettingFromFlexForm('Tie Breaker', 'search.query.tieParameter');
$this->addSettingFromFlexForm('Template', 'view.templateFiles.results');
return $this->render();
}
/**
* @param array $contentElement
* @param PageLayoutView $pObj
*/
protected function initialize(array $contentElement, PageLayoutView $pObj)
{
$this->pageLayoutView = $pObj;
/** @var $service \TYPO3\CMS\Core\Service\FlexFormService::class */
$service = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Service\FlexFormService::class);
$this->flexformData = $service->convertFlexFormContentToArray($contentElement['pi_flexform']);
$this->pluginContentElement = $contentElement;
}
/**
* Adds the target page to the settings.
*/
protected function addTargetPage()
{
$targetPageId = $this->getFieldFromFlexform('search.targetPage');
if (!empty($targetPageId)) {
$page = BackendUtility::getRecord('pages', $targetPageId, 'title');
$this->settings['Target Page'] = '[' . (int)$targetPageId . '] ' . $page['title'];
}
}
/**
* @param string $settingName
* @param string $flexFormField
*/
protected function addSettingFromFlexForm($settingName, $flexFormField)
{
$value = $this->getFieldFromFlexform($flexFormField);
if (is_array($value)) {
$value = $this->addSettingFromFlexFormArray($settingName, $value);
}
$this->addSettingIfNotEmpty($settingName, (string)$value);
}
/**
* @param string $settingName
* @param array $values
* @return bool
*/
protected function addSettingFromFlexFormArray($settingName, $values)
{
foreach ($values as $item) {
if (!isset($item['field'])) {
continue;
}
$field = $item['field'];
$label = $settingName . ' ';
$label .= isset($field['field']) ? $field['field'] : '';
$fieldValue = isset($field['value']) ? $field['value'] : '';
$this->addSettingIfNotEmpty($label, (string)$fieldValue);
}
}
/**
* @param string $settingName
* @param string $value
*/
protected function addSettingIfNotEmpty($settingName, $value)
{
if (!empty($value)) {
$this->settings[$settingName] = $value;
}
}
/**
* Gets a field's value from flexform configuration, will check if
* flexform configuration is available.
*
* @param string $path name of the field
* @return string if nothing found, value if found
*/
protected function getFieldFromFlexform($path)
{
return ObjectAccess::getPropertyPath($this->flexformData, $path);
}
/**
* @return string
*/
protected function render()
{
/** @var $standaloneView StandaloneView */
$standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
$standaloneView->setTemplatePathAndFilename(
GeneralUtility::getFileAbsFileName('EXT:meilisearch/Resources/Private/Templates/Backend/PageModule/Summary.html')
);
$standaloneView->assignMultiple([
'pluginLabel' => $this->getPluginLabel(),
'hidden' => $this->pluginContentElement['hidden'],
'settings' => $this->settings,
]);
return $standaloneView->render();
}
/**
* Returns the plugin label
*
* @return string
*/
protected function getPluginLabel()
{
$label = BackendUtility::getLabelFromItemListMerged($this->pluginContentElement['pid'], 'tt_content', 'list_type', $this->pluginContentElement['list_type']);
if (!empty($label)) {
$label = $this->getLanguageService()->sL($label);
} else {
$label = sprintf($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue'), $this->pluginContentElement['list_type']);
}
return $this->pageLayoutView->linkEditContent(htmlspecialchars($label), $this->pluginContentElement);
}
/**
* Returns the language service
*
* @return LanguageService
*/
protected function getLanguageService(): LanguageService
{
return $GLOBALS['LANG'];
}
}

View File

@@ -0,0 +1,328 @@
<?php
namespace WapplerSystems\Meilisearch\Controller\Backend\Search;
/***************************************************************
* Copyright notice
*
* (c) 2010-2017 dkd Internet Service GmbH <solr-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\ConnectionManager;
use WapplerSystems\Meilisearch\Domain\Site\SiteRepository;
use WapplerSystems\Meilisearch\Domain\Site\Site;
use WapplerSystems\Meilisearch\System\Solr\SolrConnection as SolrCoreConnection;
use WapplerSystems\Meilisearch\System\Mvc\Backend\Component\Exception\InvalidViewObjectNameException;
use WapplerSystems\Meilisearch\System\Mvc\Backend\Service\ModuleDataStorageService;
use TYPO3\CMS\Backend\Template\Components\Menu\Menu;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Messaging\AbstractMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\View\NotFoundView;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Abstract Module
*
* @property BackendTemplateView $view
*/
abstract class AbstractModuleController extends ActionController
{
/**
* Backend Template Container
*
* @var string
*/
protected $defaultViewObjectName = BackendTemplateView::class;
/**
* In the pagetree selected page UID
*
* @var int
*/
protected $selectedPageUID;
/**
* Holds the requested page UID because the selected page uid,
* might be overwritten by the automatic site selection.
*
* @var int
*/
protected $requestedPageUID;
/**
* @var Site
*/
protected $selectedSite;
/**
* @var SiteRepository
*/
protected $siteRepository;
/**
* @var SolrCoreConnection
*/
protected $selectedSolrCoreConnection;
/**
* @var Menu
*/
protected $coreSelectorMenu = null;
/**
* @var ConnectionManager
*/
protected $solrConnectionManager = null;
/**
* @var ModuleDataStorageService
*/
protected $moduleDataStorageService = null;
/**
* @param Site $selectedSite
*/
public function setSelectedSite(Site $selectedSite)
{
$this->selectedSite = $selectedSite;
}
/**
* @param SiteRepository $siteRepository
*/
public function injectSiteRepository(SiteRepository $siteRepository)
{
$this->siteRepository = $siteRepository;
}
/**
* Initializes the controller and sets needed vars.
*/
protected function initializeAction()
{
parent::initializeAction();
$this->solrConnectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
$this->moduleDataStorageService = GeneralUtility::makeInstance(ModuleDataStorageService::class);
$this->selectedPageUID = (int)GeneralUtility::_GP('id');
if ($this->request->hasArgument('id')) {
$this->selectedPageUID = (int)$this->request->getArgument('id');
}
$this->requestedPageUID = $this->selectedPageUID;
if ($this->autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable()) {
return;
}
if ($this->selectedPageUID < 1) {
return;
}
try {
$this->selectedSite = $this->siteRepository->getSiteByPageId($this->selectedPageUID);
} catch (\InvalidArgumentException $exception) {
return;
}
}
/**
* @return bool
* @throws \Exception
*/
protected function autoSelectFirstSiteAndRootPageWhenOnlyOneSiteIsAvailable(): bool
{
if (count($this->siteRepository->getAvailableSites()) == 1) {
$this->selectedSite = $this->siteRepository->getFirstAvailableSite();
// we only overwrite the selected pageUid when no id was passed
if ($this->selectedPageUID === 0) {
$this->selectedPageUID = $this->selectedSite->getRootPageId();
}
return true;
}
return false;
}
/**
* Set up the doc header properly here
*
* @param ViewInterface $view
* @return void
*/
protected function initializeView(ViewInterface $view)
{
parent::initializeView($view);
$sites = $this->siteRepository->getAvailableSites();
$selectOtherPage = count($sites) > 0 || $this->selectedPageUID < 1;
$this->view->assign('showSelectOtherPage', $selectOtherPage);
$this->view->assign('pageUID', $this->selectedPageUID);
if ($view instanceof NotFoundView || $this->selectedPageUID < 1) {
return;
}
$this->view->getModuleTemplate()->addJavaScriptCode('mainJsFunctions', '
top.fsMod.recentIds["searchbackend"] = ' . (int)$this->selectedPageUID . ';'
);
if (null === $this->selectedSite) {
return;
}
/* @var BackendUserAuthentication $beUser */
$beUser = $GLOBALS['BE_USER'];
$permissionClause = $beUser->getPagePermsClause(1);
$pageRecord = BackendUtility::readPageAccess($this->selectedSite->getRootPageId(), $permissionClause);
if (false === $pageRecord) {
throw new \InvalidArgumentException(vsprintf('There is something wrong with permissions for page "%s" for backend user "%s".', [$this->selectedSite->getRootPageId(), $beUser->user['username']]), 1496146317);
}
$this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
}
/**
* Generates selector menu in backends doc header using selected page from page tree.
*
* @param string|null $uriToRedirectTo
*/
public function generateCoreSelectorMenuUsingPageTree(string $uriToRedirectTo = null)
{
if ($this->selectedPageUID < 1 || null === $this->selectedSite) {
return;
}
if ($this->view instanceof NotFoundView) {
$this->initializeSelectedSolrCoreConnection();
return;
}
$this->generateCoreSelectorMenu($this->selectedSite, $uriToRedirectTo);
}
/**
* Generates Core selector Menu for given Site.
*
* @param Site $site
* @param string|null $uriToRedirectTo
* @throws InvalidViewObjectNameException
*/
protected function generateCoreSelectorMenu(Site $site, string $uriToRedirectTo = null)
{
if (!$this->view instanceof BackendTemplateView) {
throw new InvalidViewObjectNameException(vsprintf(
'The controller "%s" must use BackendTemplateView to be able to generate menu for backends docheader. \
Please set `protected $defaultViewObjectName = BackendTemplateView::class;` field in your controller.',
[static::class]), 1493804179);
}
$this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
$this->coreSelectorMenu = $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
$this->coreSelectorMenu->setIdentifier('component_core_selector_menu');
if (!isset($uriToRedirectTo)) {
$uriToRedirectTo = $this->uriBuilder->reset()->uriFor();
}
$this->initializeSelectedSolrCoreConnection();
$cores = $this->solrConnectionManager->getConnectionsBySite($site);
foreach ($cores as $core) {
$coreAdmin = $core->getAdminService();
$menuItem = $this->coreSelectorMenu->makeMenuItem();
$menuItem->setTitle($coreAdmin->getCorePath());
$uri = $this->uriBuilder->reset()->uriFor('switchCore',
[
'corePath' => $coreAdmin->getCorePath(),
'uriToRedirectTo' => $uriToRedirectTo
]
);
$menuItem->setHref($uri);
if ($coreAdmin->getCorePath() == $this->selectedSolrCoreConnection->getAdminService()->getCorePath()) {
$menuItem->setActive(true);
}
$this->coreSelectorMenu->addMenuItem($menuItem);
}
$this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($this->coreSelectorMenu);
}
/**
* Switches used core.
*
* Note: Does not check availability of core in site. All this stuff is done in the generation step.
*
* @param string $corePath
* @param string $uriToRedirectTo
*/
public function switchCoreAction(string $corePath, string $uriToRedirectTo)
{
$moduleData = $this->moduleDataStorageService->loadModuleData();
$moduleData->setCore($corePath);
$this->moduleDataStorageService->persistModuleData($moduleData);
$message = LocalizationUtility::translate('coreselector_switched_successfully', 'solr', [$corePath]);
$this->addFlashMessage($message);
$this->redirectToUri($uriToRedirectTo);
}
/**
* Initializes the solr core connection considerately to the components state.
* Uses and persists default core connection if persisted core in Site does not exist.
*
*/
private function initializeSelectedSolrCoreConnection()
{
$moduleData = $this->moduleDataStorageService->loadModuleData();
$solrCoreConnections = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
$currentSolrCorePath = $moduleData->getCore();
if (empty($currentSolrCorePath)) {
$this->initializeFirstAvailableSolrCoreConnection($solrCoreConnections, $moduleData);
return;
}
foreach ($solrCoreConnections as $solrCoreConnection) {
if ($solrCoreConnection->getAdminService()->getCorePath() == $currentSolrCorePath) {
$this->selectedSolrCoreConnection = $solrCoreConnection;
}
}
if (!$this->selectedSolrCoreConnection instanceof SolrCoreConnection && count($solrCoreConnections) > 0) {
$this->initializeFirstAvailableSolrCoreConnection($solrCoreConnections, $moduleData);
$message = LocalizationUtility::translate('coreselector_switched_to_default_core', 'solr', [$currentSolrCorePath, $this->selectedSite->getLabel(), $this->selectedSolrCoreConnection->getAdminService()->getCorePath()]);
$this->addFlashMessage($message, '', AbstractMessage::NOTICE);
}
}
/**
* @param SolrCoreConnection[] $solrCoreConnections
*/
private function initializeFirstAvailableSolrCoreConnection(array $solrCoreConnections, $moduleData)
{
if (empty($solrCoreConnections)) {
return;
}
$this->selectedSolrCoreConnection = $solrCoreConnections[0];
$moduleData->setCore($this->selectedSolrCoreConnection->getAdminService()->getCorePath());
$this->moduleDataStorageService->persistModuleData($moduleData);
}
}

View File

@@ -0,0 +1,386 @@
<?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);
}
}
}

View File

@@ -0,0 +1,195 @@
<?php
namespace WapplerSystems\Meilisearch\Controller\Backend\Search;
/***************************************************************
* Copyright notice
*
* (c) 2013-2015 Ingo Renner <ingo@typo3.org>
* 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\ConnectionManager;
use WapplerSystems\Meilisearch\IndexQueue\Queue;
use WapplerSystems\Meilisearch\System\Solr\SolrConnection;
use WapplerSystems\Meilisearch\Util;
use TYPO3\CMS\Backend\Routing\UriBuilder as BackendUriBuilder;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Web\ReferringRequest;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Index Administration Module
*
* @author Ingo Renner <ingo@typo3.org>
*/
class IndexAdministrationModuleController extends AbstractModuleController
{
/**
* @var Queue
*/
protected $indexQueue;
/**
* @var ConnectionManager
*/
protected $solrConnectionManager = null;
/**
* @param ConnectionManager $solrConnectionManager
*/
public function setSolrConnectionManager(ConnectionManager $solrConnectionManager)
{
$this->solrConnectionManager = $solrConnectionManager;
}
/**
* Initializes the controller before invoking an action method.
*/
protected function initializeAction()
{
parent::initializeAction();
$this->indexQueue = GeneralUtility::makeInstance(Queue::class);
$this->solrConnectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
}
/**
* Index action, shows an overview of available index maintenance operations.
*
* @return void
*/
public function indexAction()
{
if ($this->selectedSite === null || empty($this->solrConnectionManager->getConnectionsBySite($this->selectedSite))) {
$this->view->assign('can_not_proceed', true);
}
}
/**
* Empties the site's indexes.
*
* @return void
*/
public function emptyIndexAction()
{
$siteHash = $this->selectedSite->getSiteHash();
try {
$affectedCores = [];
$solrServers = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
foreach ($solrServers as $solrServer) {
$writeService = $solrServer->getWriteService();
/* @var $solrServer SolrConnection */
$writeService->deleteByQuery('siteHash:' . $siteHash);
$writeService->commit(false, false, false);
$affectedCores[] = $writeService->getPrimaryEndpoint()->getCore();
}
$message = LocalizationUtility::translate('solr.backend.index_administration.index_emptied_all', 'Solr', [$this->selectedSite->getLabel(), implode(', ', $affectedCores)]);
$this->addFlashMessage($message);
} catch (\Exception $e) {
$this->addFlashMessage(LocalizationUtility::translate('solr.backend.index_administration.error.on_empty_index', 'Solr', [$e->__toString()]), '', FlashMessage::ERROR);
}
$this->redirect('index');
}
/**
* Empties the Index Queue
*
* @return void
*/
public function clearIndexQueueAction()
{
$this->indexQueue->deleteItemsBySite($this->selectedSite);
$this->addFlashMessage(
LocalizationUtility::translate('solr.backend.index_administration.success.queue_emptied', 'Solr',
[$this->selectedSite->getLabel()])
);
$this->redirectToReferrerModule();
}
/**
* Reloads the site's Solr cores.
*
* @return void
*/
public function reloadIndexConfigurationAction()
{
$coresReloaded = true;
$reloadedCores = [];
$solrServers = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
foreach ($solrServers as $solrServer) {
/* @var $solrServer SolrConnection */
$coreAdmin = $solrServer->getAdminService();
$coreReloaded = $coreAdmin->reloadCore()->getHttpStatus() === 200;
$coreName = $coreAdmin->getPrimaryEndpoint()->getCore();
if (!$coreReloaded) {
$coresReloaded = false;
$this->addFlashMessage(
'Failed to reload index configuration for core "' . $coreName . '"',
'',
FlashMessage::ERROR
);
break;
}
$reloadedCores[] = $coreName;
}
if ($coresReloaded) {
$this->addFlashMessage(
'Core configuration reloaded (' . implode(', ', $reloadedCores) . ').',
'',
FlashMessage::OK
);
}
$this->redirect('index');
}
/**
* Redirects to the referrer module index Action.
*
* Fluids <f:form VH can not make urls to other modules properly.
* The module name/key is not provided in the hidden fields __referrer by bulding form.
* So this is currently the single way to make it possible.
*
* @todo: remove this method if f:form works properly between backend modules.
*/
protected function redirectToReferrerModule()
{
$wasFromQueue = $this->request->hasArgument('fromQueue');
if (!$wasFromQueue) {
$this->redirect('index');
return;
}
/* @var BackendUriBuilder $backendUriBuilder */
$backendUriBuilder = GeneralUtility::makeInstance(BackendUriBuilder::class);
$parameters = ['id' => $this->selectedPageUID];
$referringUri = $backendUriBuilder->buildUriFromRoute('searchbackend_SolrIndexqueue', $parameters);
$this->redirectToUri($referringUri);
}
}

View File

@@ -0,0 +1,287 @@
<?php
namespace WapplerSystems\Meilisearch\Controller\Backend\Search;
/***************************************************************
* Copyright notice
*
* (c) 2013-2015 Ingo Renner <ingo@typo3.org>
* 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\Backend\IndexingConfigurationSelectorField;
use WapplerSystems\Meilisearch\Domain\Index\IndexService;
use WapplerSystems\Meilisearch\IndexQueue\Queue;
use TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Index Queue Module
*
* @author Ingo Renner <ingo@typo3.org>
* @property BackendTemplateView $view
*/
class IndexQueueModuleController extends AbstractModuleController
{
/**
* Module name, used to identify a module f.e. in URL parameters.
*
* @var string
*/
protected $moduleName = 'IndexQueue';
/**
* Module title, shows up in the module menu.
*
* @var string
*/
protected $moduleTitle = 'Index Queue';
/**
* @var Queue
*/
protected $indexQueue;
/**
* Initializes the controller before invoking an action method.
*/
protected function initializeAction()
{
parent::initializeAction();
$this->indexQueue = GeneralUtility::makeInstance(Queue::class);
}
/**
* @param Queue $indexQueue
*/
public function setIndexQueue(Queue $indexQueue)
{
$this->indexQueue = $indexQueue;
}
/**
* Set up the doc header properly here
*
* @param ViewInterface $view
* @return void
*/
protected function initializeView(ViewInterface $view)
{
parent::initializeView($view);
}
/**
* Lists the available indexing configurations
*
* @return void
*/
public function indexAction()
{
if (!$this->canQueueSelectedSite()) {
$this->view->assign('can_not_proceed', true);
return;
}
$statistics = $this->indexQueue->getStatisticsBySite($this->selectedSite);
$this->view->assign('indexQueueInitializationSelector', $this->getIndexQueueInitializationSelector());
$this->view->assign('indexqueue_statistics', $statistics);
$this->view->assign('indexqueue_errors', $this->indexQueue->getErrorsBySite($this->selectedSite));
}
/**
* Checks if selected site can be queued.
*
* @return bool
*/
protected function canQueueSelectedSite()
{
if ($this->selectedSite === null || empty($this->solrConnectionManager->getConnectionsBySite($this->selectedSite))) {
return false;
}
$enabledIndexQueueConfigurationNames = $this->selectedSite->getSolrConfiguration()->getEnabledIndexQueueConfigurationNames();
if (empty($enabledIndexQueueConfigurationNames)) {
return false;
}
return true;
}
/**
* Renders a field to select which indexing configurations to initialize.
*
* Uses TCEforms.
*
* @return string Markup for the select field
*/
protected function getIndexQueueInitializationSelector()
{
$selector = GeneralUtility::makeInstance(IndexingConfigurationSelectorField::class, /** @scrutinizer ignore-type */ $this->selectedSite);
$selector->setFormElementName('tx_meilisearch-index-queue-initialization');
return $selector->render();
}
/**
* Initializes the Index Queue for selected indexing configurations
*
* @return void
*/
public function initializeIndexQueueAction()
{
$initializedIndexingConfigurations = [];
$indexingConfigurationsToInitialize = GeneralUtility::_POST('tx_meilisearch-index-queue-initialization');
if ((!empty($indexingConfigurationsToInitialize)) && (is_array($indexingConfigurationsToInitialize))) {
// initialize selected indexing configuration
$initializedIndexingConfigurations = $this->indexQueue->getInitializationService()->initializeBySiteAndIndexConfigurations($this->selectedSite, $indexingConfigurationsToInitialize);
} else {
$messageLabel = 'solr.backend.index_queue_module.flashmessage.initialize.no_selection';
$titleLabel = 'solr.backend.index_queue_module.flashmessage.not_initialized.title';
$this->addFlashMessage(
LocalizationUtility::translate($messageLabel, 'Solr'),
LocalizationUtility::translate($titleLabel, 'Solr'),
FlashMessage::WARNING
);
}
$messagesForConfigurations = [];
foreach (array_keys($initializedIndexingConfigurations) as $indexingConfigurationName) {
$itemCount = $this->indexQueue->getStatisticsBySite($this->selectedSite, $indexingConfigurationName)->getTotalCount();
$messagesForConfigurations[] = $indexingConfigurationName . ' (' . $itemCount . ' records)';
}
if (!empty($initializedIndexingConfigurations)) {
$messageLabel = 'solr.backend.index_queue_module.flashmessage.initialize.success';
$titleLabel = 'solr.backend.index_queue_module.flashmessage.initialize.title';
$this->addFlashMessage(
LocalizationUtility::translate($messageLabel, 'Solr', [implode(', ', $messagesForConfigurations)]),
LocalizationUtility::translate($titleLabel, 'Solr'),
FlashMessage::OK
);
}
$this->redirect('index');
}
/**
* Removes all errors in the index queue list. So that the items can be indexed again.
*
* @return void
*/
public function resetLogErrorsAction()
{
$resetResult = $this->indexQueue->resetAllErrors();
$label = 'solr.backend.index_queue_module.flashmessage.success.reset_errors';
$severity = FlashMessage::OK;
if (!$resetResult) {
$label = 'solr.backend.index_queue_module.flashmessage.error.reset_errors';
$severity = FlashMessage::ERROR;
}
$this->addIndexQueueFlashMessage($label, $severity);
$this->redirect('index');
}
/**
* ReQueues a single item in the indexQueue.
*
* @param string $type
* @param int $uid
*
* @return void
*/
public function requeueDocumentAction(string $type, int $uid)
{
$label = 'solr.backend.index_queue_module.flashmessage.error.single_item_not_requeued';
$severity = FlashMessage::ERROR;
$updateCount = $this->indexQueue->updateItem($type, $uid, time());
if ($updateCount > 0) {
$label = 'solr.backend.index_queue_module.flashmessage.success.single_item_was_requeued';
$severity = FlashMessage::OK;
}
$this->addIndexQueueFlashMessage($label, $severity);
$this->redirect('index');
}
/**
* Shows the error message for one queue item.
*
* @param int $indexQueueItemId
* @return void
*/
public function showErrorAction(int $indexQueueItemId)
{
if (is_null($indexQueueItemId)) {
// add a flash message and quit
$label = 'solr.backend.index_queue_module.flashmessage.error.no_queue_item_for_queue_error';
$severity = FlashMessage::ERROR;
$this->addIndexQueueFlashMessage($label, $severity);
return;
}
$item = $this->indexQueue->getItem($indexQueueItemId);
$this->view->assign('indexQueueItem', $item);
}
/**
* Indexes a few documents with the index service.
* @return void
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
*/
public function doIndexingRunAction()
{
/** @var $indexService \WapplerSystems\Meilisearch\Domain\Index\IndexService */
$indexService = GeneralUtility::makeInstance(IndexService::class, /** @scrutinizer ignore-type */ $this->selectedSite);
$indexWithoutErrors = $indexService->indexItems(10);
$label = 'solr.backend.index_queue_module.flashmessage.success.index_manual';
$severity = FlashMessage::OK;
if (!$indexWithoutErrors) {
$label = 'solr.backend.index_queue_module.flashmessage.error.index_manual';
$severity = FlashMessage::ERROR;
}
$this->addFlashMessage(
LocalizationUtility::translate($label, 'Solr'),
LocalizationUtility::translate('solr.backend.index_queue_module.flashmessage.index_manual', 'Solr'),
$severity
);
$this->redirect('index');
}
/**
* Adds a flash message for the index queue module.
*
* @param string $label
* @param int $severity
*/
protected function addIndexQueueFlashMessage($label, $severity)
{
$this->addFlashMessage(LocalizationUtility::translate($label, 'Solr'), LocalizationUtility::translate('solr.backend.index_queue_module.flashmessage.title', 'Solr'), $severity);
}
}

View File

@@ -0,0 +1,324 @@
<?php
namespace WapplerSystems\Meilisearch\Controller\Backend\Search;
/***************************************************************
* Copyright notice
*
* (c) 2010-2017 dkd Internet Service GmbH <solr-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\Api;
use WapplerSystems\Meilisearch\ConnectionManager;
use WapplerSystems\Meilisearch\Domain\Search\Statistics\StatisticsRepository;
use WapplerSystems\Meilisearch\Domain\Search\ApacheSolrDocument\Repository;
use WapplerSystems\Meilisearch\System\Solr\ResponseAdapter;
use WapplerSystems\Meilisearch\System\Validator\Path;
use TYPO3\CMS\Backend\Template\ModuleTemplate;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Registry;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
/**
* Info Module
*/
class InfoModuleController extends AbstractModuleController
{
/**
* @var ConnectionManager
*/
protected $solrConnectionManager;
/**
* @var Repository
*/
protected $apacheSolrDocumentRepository;
/**
* Initializes the controller before invoking an action method.
*/
protected function initializeAction()
{
parent::initializeAction();
$this->solrConnectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
$this->apacheSolrDocumentRepository = GeneralUtility::makeInstance(Repository::class);
}
/**
* Set up the doc header properly here
*
* @param ViewInterface $view
* @return void
*/
protected function initializeView(ViewInterface $view)
{
parent::initializeView($view);
/* @var ModuleTemplate $module */ // holds the state of chosen tab
$module = GeneralUtility::makeInstance(ModuleTemplate::class);
$coreOptimizationTabs = $module->getDynamicTabMenu([], 'coreOptimization');
$this->view->assign('tabs', $coreOptimizationTabs);
}
/**
* Index action, shows an overview of the state of the Solr index
*
* @return void
*/
public function indexAction()
{
if ($this->selectedSite === null) {
$this->view->assign('can_not_proceed', true);
return;
}
$this->collectConnectionInfos();
$this->collectStatistics();
$this->collectIndexFieldsInfo();
$this->collectIndexInspectorInfo();
}
/**
* @param string $type
* @param int $uid
* @param int $pageId
* @param int $languageUid
* @return void
*/
public function documentsDetailsAction(string $type, int $uid, int $pageId, int $languageUid)
{
$documents = $this->apacheSolrDocumentRepository->findByTypeAndPidAndUidAndLanguageId($type, $uid, $pageId, $languageUid);
$this->view->assign('documents', $documents);
}
/**
* Checks whether the configured Solr server can be reached and provides a
* flash message according to the result of the check.
*
* @return void
*/
protected function collectConnectionInfos()
{
$connectedHosts = [];
$missingHosts = [];
$invalidPaths = [];
/* @var Path $path */
$path = GeneralUtility::makeInstance(Path::class);
$connections = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
if (empty($connections)) {
$this->view->assign('can_not_proceed', true);
return;
}
foreach ($connections as $connection) {
$coreAdmin = $connection->getAdminService();
$coreUrl = (string)$coreAdmin;
if ($coreAdmin->ping()) {
$connectedHosts[] = $coreUrl;
} else {
$missingHosts[] = $coreUrl;
}
if (!$path->isValidSolrPath($coreAdmin->getCorePath())) {
$invalidPaths[] = $coreAdmin->getCorePath();
}
}
$this->view->assignMultiple([
'site' => $this->selectedSite,
'apiKey' => Api::getApiKey(),
'connectedHosts' => $connectedHosts,
'missingHosts' => $missingHosts,
'invalidPaths' => $invalidPaths
]);
}
/**
* Index action, shows an overview of the state of the Solr index
*
* @return void
*/
protected function collectStatistics()
{
// TODO make time frame user adjustable, for now it's last 30 days
$siteRootPageId = $this->selectedSite->getRootPageId();
/* @var StatisticsRepository $statisticsRepository */
$statisticsRepository = GeneralUtility::makeInstance(StatisticsRepository::class);
// @TODO: Do we want Typoscript constants to restrict the results?
$this->view->assign(
'top_search_phrases',
$statisticsRepository->getTopKeyWordsWithHits($siteRootPageId, 30, 5)
);
$this->view->assign(
'top_search_phrases_without_hits',
$statisticsRepository->getTopKeyWordsWithoutHits($siteRootPageId, 30, 5)
);
$this->view->assign(
'search_phrases_statistics',
$statisticsRepository->getSearchStatistics($siteRootPageId, 30, 100)
);
$labels = [];
$data = [];
$chartData = $statisticsRepository->getQueriesOverTime($siteRootPageId, 30, 86400);
foreach ($chartData as $bucket) {
$labels[] = strftime('%x', $bucket['timestamp']);
$data[] = (int)$bucket['numQueries'];
}
$this->view->assign('queriesChartLabels', json_encode($labels));
$this->view->assign('queriesChartData', json_encode($data));
}
/**
* Gets Luke meta data for the currently selected core and provides a list
* of that data.
*
* @return void
*/
protected function collectIndexFieldsInfo()
{
$indexFieldsInfoByCorePaths = [];
$solrCoreConnections = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
foreach ($solrCoreConnections as $solrCoreConnection) {
$coreAdmin = $solrCoreConnection->getAdminService();
$indexFieldsInfo = [
'corePath' => $coreAdmin->getCorePath()
];
if ($coreAdmin->ping()) {
$lukeData = $coreAdmin->getLukeMetaData();
/* @var Registry $registry */
$registry = GeneralUtility::makeInstance(Registry::class);
$limit = $registry->get('tx_meilisearch', 'luke.limit', 20000);
$limitNote = '';
if (isset($lukeData->index->numDocs) && $lukeData->index->numDocs > $limit) {
$limitNote = '<em>Too many terms</em>';
} elseif (isset($lukeData->index->numDocs)) {
$limitNote = 'Nothing indexed';
// below limit, so we can get more data
// Note: we use 2 since 1 fails on Ubuntu Hardy.
$lukeData = $coreAdmin->getLukeMetaData(2);
}
$fields = $this->getFields($lukeData, $limitNote);
$coreMetrics = $this->getCoreMetrics($lukeData, $fields);
$indexFieldsInfo['noError'] = 'OK';
$indexFieldsInfo['fields'] = $fields;
$indexFieldsInfo['coreMetrics'] = $coreMetrics;
} else {
$indexFieldsInfo['noError'] = null;
$this->addFlashMessage(
'',
'Unable to contact Apache Solr server: ' . $this->selectedSite->getLabel() . ' ' . $coreAdmin->getCorePath(),
FlashMessage::ERROR
);
}
$indexFieldsInfoByCorePaths[$coreAdmin->getCorePath()] = $indexFieldsInfo;
}
$this->view->assign('indexFieldsInfoByCorePaths', $indexFieldsInfoByCorePaths);
}
/**
* Retrieves the information for the index inspector.
*
* @return void
*/
protected function collectIndexInspectorInfo()
{
$solrCoreConnections = $this->solrConnectionManager->getConnectionsBySite($this->selectedSite);
$documentsByCoreAndType = [];
foreach ($solrCoreConnections as $languageId => $solrCoreConnection) {
$coreAdmin = $solrCoreConnection->getAdminService();
$documents = $this->apacheSolrDocumentRepository->findByPageIdAndByLanguageId($this->selectedPageUID, $languageId);
$documentsByType = [];
foreach ($documents as $document) {
$documentsByType[$document['type']][] = $document;
}
$documentsByCoreAndType[$languageId]['core'] = $coreAdmin;
$documentsByCoreAndType[$languageId]['documents'] = $documentsByType;
}
$this->view->assignMultiple([
'pageId' => $this->selectedPageUID,
'indexInspectorDocumentsByLanguageAndType' => $documentsByCoreAndType
]);
}
/**
* Gets field metrics.
*
* @param ResponseAdapter $lukeData Luke index data
* @param string $limitNote Note to display if there are too many documents in the index to show number of terms for a field
*
* @return array An array of field metrics
*/
protected function getFields(ResponseAdapter $lukeData, $limitNote)
{
$rows = [];
$fields = (array)$lukeData->fields;
foreach ($fields as $name => $field) {
$rows[$name] = [
'name' => $name,
'type' => $field->type,
'docs' => isset($field->docs) ? $field->docs : 0,
'terms' => isset($field->distinct) ? $field->distinct : $limitNote
];
}
ksort($rows);
return $rows;
}
/**
* Gets general core metrics.
*
* @param ResponseAdapter $lukeData Luke index data
* @param array $fields Fields metrics
*
* @return array An array of core metrics
*/
protected function getCoreMetrics(ResponseAdapter $lukeData, array $fields)
{
$coreMetrics = [
'numberOfDocuments' => $lukeData->index->numDocs,
'numberOfDeletedDocuments' => $lukeData->index->deletedDocs,
'numberOfTerms' => $lukeData->index->numTerms,
'numberOfFields' => count($fields)
];
return $coreMetrics;
}
}