* * This program 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 2 * of the License, or (at your option) any later version. * * This program 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ use Codappix\SearchCore\Configuration\ConfigurationContainerInterface; use Codappix\SearchCore\Configuration\InvalidArgumentException; use Codappix\SearchCore\Connection\ConnectionInterface; use Codappix\SearchCore\Connection\SearchRequestInterface; use Codappix\SearchCore\Connection\SearchResultInterface; use Codappix\SearchCore\DataProcessing\Service as DataProcessorService; use Codappix\SearchCore\Domain\Model\FacetRequest; use Codappix\SearchCore\Domain\Model\SearchResult; use Codappix\SearchCore\Utility\ArrayUtility; use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; /** * Service to process a search request. */ class SearchService implements SearchServiceInterface { /** * @var ConnectionInterface */ protected $connection; /** * @var ConfigurationContainerInterface */ protected $configuration; /** * @var ObjectManagerInterface */ protected $objectManager; /** * @var DataProcessorService */ protected $dataProcessorService; /** * @var FrontendInterface */ protected $cache; /** * @param ConnectionInterface $connection * @param ConfigurationContainerInterface $configuration * @param ObjectManagerInterface $objectManager * @param DataProcessorService $dataProcessorService * @param CacheManager $cacheManager */ public function __construct( ConnectionInterface $connection, ConfigurationContainerInterface $configuration, ObjectManagerInterface $objectManager, DataProcessorService $dataProcessorService, CacheManager $cacheManager ) { $this->connection = $connection; $this->configuration = $configuration; $this->objectManager = $objectManager; $this->dataProcessorService = $dataProcessorService; $this->cache = $cacheManager->getCache('search_core'); } public function search(SearchRequestInterface $searchRequest): SearchResultInterface { $this->addSize($searchRequest); $this->addConfiguredFacets($searchRequest); $this->addConfiguredFilters($searchRequest); // Add connection to request to enable paginate widget support $searchRequest->setConnection($this->connection); $searchRequest->setSearchService($this); $identifier = sha1('search' . serialize($searchRequest)); if ($this->cache->has($identifier)) { return $this->cache->get($identifier); } $result = $this->processResult($this->connection->search($searchRequest)); $this->cache->set($identifier, $result); return $result; } /** * Add configured size of search result items to request. */ protected function addSize(SearchRequestInterface $searchRequest) { $searchRequest->setLimit( $this->configuration->getIfExists('searching.size') ?: 10 ); } /** * Add facets from configuration to request. */ protected function addConfiguredFacets(SearchRequestInterface $searchRequest) { $facetsConfig = $this->configuration->getIfExists('searching.facets'); if ($facetsConfig === null) { return; } foreach ($facetsConfig as $identifier => $facetConfig) { $searchRequest->addFacet($this->objectManager->get( FacetRequest::class, $identifier, $facetConfig )); } } /** * Add filters from configuration, e.g. flexform or TypoScript. */ protected function addConfiguredFilters(SearchRequestInterface $searchRequest) { try { $filter = $searchRequest->getFilter(); ArrayUtility::mergeRecursiveWithOverrule( $filter, $this->configuration->get('searching.filter') ); $searchRequest->setFilter($filter); } catch (InvalidArgumentException $e) { // Nothing todo, no filter configured. } } /** * Processes the result, e.g. applies configured data processing to result. */ public function processResult(SearchResultInterface $searchResult): SearchResultInterface { try { $newSearchResultItems = []; foreach ($this->configuration->get('searching.dataProcessing') as $configuration) { foreach ($searchResult as $resultItem) { $newSearchResultItems[] = [ 'data' => $this->dataProcessorService->executeDataProcessor( $configuration, $resultItem->getPlainData() ), 'type' => $resultItem->getType(), ]; } } return $this->objectManager->get( SearchResult::class, $searchResult, $newSearchResultItems ); } catch (InvalidArgumentException $e) { return $searchResult; } } }