* 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\Meilisearch\MeilisearchConnection as MeilisearchCoreConnection; 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 MeilisearchCoreConnection */ protected $selectedMeilisearchCoreConnection; /** * @var Menu */ protected $coreSelectorMenu = null; /** * @var ConnectionManager */ protected $meilisearchConnectionManager = 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->meilisearchConnectionManager = 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->initializeSelectedMeilisearchCoreConnection(); 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->initializeSelectedMeilisearchCoreConnection(); $cores = $this->meilisearchConnectionManager->getConnectionBySite($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->selectedMeilisearchCoreConnection->getService()->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', 'meilisearch', [$corePath]); $this->addFlashMessage($message); $this->redirectToUri($uriToRedirectTo); } /** * Initializes the meilisearch core connection considerately to the components state. * Uses and persists default core connection if persisted core in Site does not exist. * */ private function initializeSelectedMeilisearchCoreConnection() { $moduleData = $this->moduleDataStorageService->loadModuleData(); $meilisearchCoreConnections = $this->meilisearchConnectionManager->getConnectionBySite($this->selectedSite); $currentMeilisearchCorePath = $moduleData->getCore(); if (empty($currentMeilisearchCorePath)) { $this->initializeFirstAvailableMeilisearchCoreConnection($meilisearchCoreConnections, $moduleData); return; } foreach ($meilisearchCoreConnections as $meilisearchCoreConnection) { if ($meilisearchCoreConnection->getAdminService()->getCorePath() == $currentMeilisearchCorePath) { $this->selectedMeilisearchCoreConnection = $meilisearchCoreConnection; } } if (!$this->selectedMeilisearchCoreConnection instanceof MeilisearchCoreConnection && count($meilisearchCoreConnections) > 0) { $this->initializeFirstAvailableMeilisearchCoreConnection($meilisearchCoreConnections, $moduleData); $message = LocalizationUtility::translate('coreselector_switched_to_default_core', 'meilisearch', [$currentMeilisearchCorePath, $this->selectedSite->getLabel(), $this->selectedMeilisearchCoreConnection->getService()->getCorePath()]); $this->addFlashMessage($message, '', AbstractMessage::NOTICE); } } /** * @param MeilisearchCoreConnection[] $meilisearchCoreConnections */ private function initializeFirstAvailableMeilisearchCoreConnection(array $meilisearchCoreConnections, $moduleData) { if (empty($meilisearchCoreConnections)) { return; } $this->selectedMeilisearchCoreConnection = $meilisearchCoreConnections[0]; $moduleData->setCore($this->selectedMeilisearchCoreConnection->getService()->getCorePath()); $this->moduleDataStorageService->persistModuleData($moduleData); } }