diff --git a/Classes/Domain/Model/SearchRequest.php b/Classes/Domain/Model/SearchRequest.php index 29756d0..183463e 100644 --- a/Classes/Domain/Model/SearchRequest.php +++ b/Classes/Domain/Model/SearchRequest.php @@ -188,6 +188,20 @@ class SearchRequest implements SearchRequestInterface return $this->offset; } + /** + * Used, e.g. by caching to determine identifier. + */ + public function __sleep() + { + return [ + 'query', + 'filter', + 'facets', + 'offset', + 'limit', + ]; + } + /** * @throws \BadMethodCallException */ diff --git a/Classes/Domain/Search/SearchService.php b/Classes/Domain/Search/SearchService.php index 43b54b8..e5b81d5 100644 --- a/Classes/Domain/Search/SearchService.php +++ b/Classes/Domain/Search/SearchService.php @@ -30,6 +30,8 @@ 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; /** @@ -57,22 +59,30 @@ class SearchService implements SearchServiceInterface */ 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 + 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 @@ -85,7 +95,15 @@ class SearchService implements SearchServiceInterface $searchRequest->setConnection($this->connection); $searchRequest->setSearchService($this); - return $this->processResult($this->connection->search($searchRequest)); + $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; } /** diff --git a/Documentation/source/changelog/0.1.0.rst b/Documentation/source/changelog/0.1.0.rst index 3cfc4ce..bcd0cd6 100644 --- a/Documentation/source/changelog/0.1.0.rst +++ b/Documentation/source/changelog/0.1.0.rst @@ -4,6 +4,7 @@ v0.1.0 .. toctree:: :maxdepth: 1 + 0.1.0/2018-added-caching 0.1.0/2018-added-content-element-wizard 0.1.0/2018-changed-interfaces 0.1.0/2018-elasticsearch-upgrade diff --git a/Documentation/source/changelog/0.1.0/2018-added-caching.rst b/Documentation/source/changelog/0.1.0/2018-added-caching.rst new file mode 100644 index 0000000..bca0fe4 --- /dev/null +++ b/Documentation/source/changelog/0.1.0/2018-added-caching.rst @@ -0,0 +1,22 @@ +Feature "Added caching" +======================= + +Processing searches are now cacheable, the TYPO3 caching framework is used for +caching. By default the ``NullBackend`` is used to keep old behaviour, which matches +searches the best. + +Still if the same search is run multiple times during a single request, the +``TransientMemoryBackend`` is a nice option. + +Depending on search backend, one might also use a different backend for caching and +configure some TTL. + +.. note:: + + Paging is currently not supported for caching. + + Using ``NullBackend`` or ``TransientMemoryBackend`` will work, but using persistent + backends in combination with fluid pagination widget will lead to errors right + now. + +For further information, check out official :ref:`t3explained:caching` documentation. diff --git a/Documentation/source/conf.py b/Documentation/source/conf.py index c559ba3..f339f20 100644 --- a/Documentation/source/conf.py +++ b/Documentation/source/conf.py @@ -304,6 +304,7 @@ texinfo_documents = [ intersphinx_mapping = { 't3tcaref': ('https://docs.typo3.org/typo3cms/TCAReference/', None), 't3tsref': ('https://docs.typo3.org/typo3cms/TyposcriptReference/', None), + 't3explained': ('https://docs.typo3.org/typo3cms/CoreApiReference/', None), } extlinks = { 'project': ('https://github.com/Codappix/search_core/projects/%s', 'Github project: '), diff --git a/Tests/Unit/Domain/Search/SearchServiceTest.php b/Tests/Unit/Domain/Search/SearchServiceTest.php index 3a6bff8..49e821d 100644 --- a/Tests/Unit/Domain/Search/SearchServiceTest.php +++ b/Tests/Unit/Domain/Search/SearchServiceTest.php @@ -30,6 +30,8 @@ use Codappix\SearchCore\Domain\Model\SearchRequest; use Codappix\SearchCore\Domain\Model\SearchResult; use Codappix\SearchCore\Domain\Search\SearchService; use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase; +use TYPO3\CMS\Core\Cache\CacheManager; +use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; class SearchServiceTest extends AbstractUnitTestCase @@ -68,6 +70,13 @@ class SearchServiceTest extends AbstractUnitTestCase { parent::setUp(); + $cacheMock = $this->getMockBuilder(FrontendInterface::class)->getMock(); + $cacheManagerMock = $this->getMockBuilder(CacheManager::class)->getMock(); + $cacheManagerMock->expects($this->any()) + ->method('getCache') + ->with('search_core') + ->willReturn($cacheMock); + $this->result = $this->getMockBuilder(SearchResultInterface::class) ->disableOriginalConstructor() ->getMock(); @@ -88,7 +97,8 @@ class SearchServiceTest extends AbstractUnitTestCase $this->connection, $this->configuration, $this->objectManager, - $this->dataProcessorService + $this->dataProcessorService, + $cacheManagerMock ); } diff --git a/ext_localconf.php b/ext_localconf.php index f400aa5..2934bc4 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -54,6 +54,14 @@ '' ); + if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core'])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core'] = []; + } + if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core']['backend'])) { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['search_core']['backend'] = + \TYPO3\CMS\Core\Cache\Backend\NullBackend::class; + } + if (empty($configuration) || (isset($configuration['disable.']['elasticsearch']) && filter_var($configuration['disable.']['elasticsearch'], FILTER_VALIDATE_BOOLEAN) === false)