Commit fcc4d6bc authored by Stefan Busemann's avatar Stefan Busemann
Browse files

Merge branch 'feature/build-search-suggest' into 'develop'

Build search suggest

See merge request !432
parents f51a609f e025b835
Pipeline #20153 passed with stages
in 6 minutes and 4 seconds
<?php
declare(strict_types = 1);
namespace T3o\T3orgLayout\Middleware;
/*
* This file is part of a TYPO3 extension.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use ApacheSolrForTypo3\Solr\ConnectionManager;
use ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\SearchResultSetService;
use ApacheSolrForTypo3\Solr\Domain\Search\SearchRequestBuilder;
use ApacheSolrForTypo3\Solr\NoSolrConnectionFoundException;
use ApacheSolrForTypo3\Solr\Search;
use ApacheSolrForTypo3\Solr\System\Configuration\TypoScriptConfiguration;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Core\Http\JsonResponse;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Fluid\View\StandaloneView;
class SolrSearch implements MiddlewareInterface
{
protected $allowedTypes = [
'pages',
'tx_news_domain_model_news',
'tx_sfeventmgt_domain_model_event',
'tx_terfe2_domain_model_extension'
];
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$response = $handler->handle($request);
$queryParams = $request->getQueryParams();
if (!$this->executeAjaxSearch($queryParams)) {
return $response;
}
if ($queryParams['type']) {
$GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_solr.']['search.']['query.']['filter.']['typeFilter'] = 'type:' . $queryParams['type'];
}
if ($queryParams['additional']) {
$GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_solr.']['search.']['query.']['filter.']['additionalFilter'] = urldecode($queryParams['additional']);
}
$typoscriptConfiguration = GeneralUtility::makeInstance(
TypoScriptConfiguration::class,
$GLOBALS['TSFE']->tmpl->setup,
$request->getAttribute('site')->getRootpageId()
);
$searchRequestBuilder = new SearchRequestBuilder($typoscriptConfiguration);
$queryParams = $request->getQueryParams();
$queryParams['q'] .= '*';
$searchRequest = $searchRequestBuilder->buildForSearch(
$queryParams,
$request->getAttribute('site')->getRootpageId(),
$request->getAttribute('language')->getLanguageId()
);
$searchRequest->setResultsPerPage(5);
try {
$solrConnection = GeneralUtility::makeInstance(ConnectionManager::class)->getConnectionByPageId(
$request->getAttribute('site')->getRootpageId(),
$request->getAttribute('language')->getLanguageId()
);
$search = GeneralUtility::makeInstance(Search::class, $solrConnection);
} catch (NoSolrConnectionFoundException $e) {
$response->getBody()->write('No Solr connection available.');
return $response;
}
$searchResultSetService = GeneralUtility::makeInstance(SearchResultSetService::class, $typoscriptConfiguration, $search);
$searchResultSetService->injectObjectManager(GeneralUtility::makeInstance(ObjectManager::class));
$searchResultSet = $searchResultSetService->search($searchRequest);
if ($queryParams['ajaxsearch'] === 'raw') {
$results = [];
foreach ($searchResultSet->getSearchResults()->getArrayCopy() as $result) {
/** @var \ApacheSolrForTypo3\Solr\Domain\Search\ResultSet\Result\SearchResult $result */
$results[] = $result->getFields();
}
return new JsonResponse($results);
}
$template = GeneralUtility::makeInstance(StandaloneView::class);
$template->setTemplatePathAndFilename('EXT:t3org_layout/Resources/Private/Templates/Solr/SolrResults.html');
$template->assign('documents', $searchResultSet->getSearchResults()->getArrayCopy());
$template->assign('type', $request->getQueryParams()['type']);
return new HtmlResponse($template->render());
}
protected function executeAjaxSearch(array $queryParams): bool
{
$paramsSet = isset($queryParams['ajaxsearch'], $queryParams['q'], $queryParams['type']);
$correctType = in_array($queryParams['type'], $this->allowedTypes);
return $paramsSet && $correctType;
}
}
......@@ -7,6 +7,15 @@ return [
'before' => [
'typo3/cms-frontend/timetracker'
]
],
't3org-search' => [
'target' => \T3o\T3orgLayout\Middleware\SolrSearch::class,
'before' => [
'typo3/cms-frontend/shortcut-and-mountpoint-redirect'
],
'after' => [
'typo3/cms-frontend/prepare-tsfe-rendering'
]
]
]
];
......@@ -170,3 +170,8 @@ plugin.tx_solr {
}
}
}
page {
includeJSFooter.search = EXT:t3org_layout/Resources/Public/JavaScript/search.js
includeCSS.ajaxsearch = EXT:t3org_layout/Resources/Public/Css/ajax-search.css
}
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:render section="{type}" arguments="{_all}" />
<f:section name="pages">
<h3>Pages</h3>
<f:if condition="{documents}">
<f:then>
<f:for each="{documents}" as="document">
<a class="small" href="{document.fields.url}">
<p class="mb-3">
<f:format.crop maxCharacters="65">{document.fields.title} &mdash; {document.fields.content}</f:format.crop>
</p>
</a>
</f:for>
</f:then>
<f:else>
<f:render section="nothingfound" />
</f:else>
</f:if>
</f:section>
<f:section name="tx_news_domain_model_news">
<h3>News</h3>
<f:if condition="{documents}">
<f:then>
<f:for each="{documents}" as="document">
<a class="small" href="{document.fields.url}">
<p class="mb-3">
{document.fields.datetime_intS -> f:format.date(format: 'd.m.Y')} &mdash; {document.fields.title}
</p>
</a>
</f:for>
</f:then>
<f:else>
<f:render section="nothingfound" />
</f:else>
</f:if>
</f:section>
<f:section name="tx_sfeventmgt_domain_model_event">
<h3>Events</h3>
<f:if condition="{documents}">
<f:then>
<f:for each="{documents}" as="document">
<a class="small" href="{document.fields.url}">
<p class="mb-3">
{document.fields.startdate_intS -> f:format.date(format: 'd.m.Y')} &mdash; {document.fields.title}
</p>
</a>
</f:for>
</f:then>
<f:else>
<f:render section="nothingfound" />
</f:else>
</f:if>
</f:section>
<f:section name="tx_terfe2_domain_model_extension">
<h3>Extensions</h3>
<f:if condition="{documents}">
<f:then>
<f:for each="{documents}" as="document">
<a class="small" href="{document.fields.url}">
<p class="mb-3">
{document.fields.extensionKey_stringS} &mdash; {document.fields.title}
</p>
</a>
</f:for>
</f:then>
<f:else>
<f:render section="nothingfound" />
</f:else>
</f:if>
</f:section>
<f:section name="nothingfound">
<p>
<small>Nothing found.</small>
</p>
</f:section>
</html>
.main-nav .search-result-list a {
color: #000;
}
let _searchPages = null;
let _searchNews = null;
let _searchEvents = null;
let _searchExtensions = null;
function delay(fn, ms) {
let timer = 0
return function (...args) {
clearTimeout(timer)
timer = setTimeout(fn.bind(this, ...args), ms || 0)
}
}
function doSearch(_searchQuery) {
_searchPages = $.ajax(
{
type: "GET",
url: "/",
data: {
"q": _searchQuery,
"ajaxsearch": 1,
"type": "pages"
},
success: function (response) {
$('.results-list-insert-pages').html(response);
}
}
);
_searchNews = $.ajax(
{
type: "GET",
url: "/",
data: {
"q": _searchQuery,
"ajaxsearch": 1,
"type": "tx_news_domain_model_news"
},
success: function (response) {
$('.results-list-insert-news').html(response);
}
}
);
_searchEvents = $.ajax(
{
type: "GET",
url: "/",
data: {
"q": _searchQuery,
"ajaxsearch": 1,
"type": "tx_sfeventmgt_domain_model_event",
"additional": encodeURI("enddate_dateS:[NOW TO *]"),
"no_cache": 1
},
success: function (response) {
$('.results-list-insert-events').html(response);
}
}
);
_searchExtensions = $.ajax(
{
type: "GET",
url: "/",
data: {
"q": _searchQuery,
"ajaxsearch": 1,
"type": "tx_terfe2_domain_model_extension"
},
success: function (response) {
$('.results-list-insert-extensions').html(response);
}
}
);
$('.show-results').on('click', function () {
$('.main-nav__solr-form').submit();
});
$('.show-results').prop('hidden', false);
}
$(document).ready(function () {
$('.js__full-width-dropdown__search').html('<div class="container"><div class="mt-4 mb-2 row"><div class="col search-result-list results-list-insert-pages"></div><div class="col search-result-list results-list-insert-news"></div><div class="col search-result-list results-list-insert-events"></div><div class="col search-result-list results-list-insert-extensions"></div></div><div class="text-right"><a class="btn btn-secondary show-results" hidden>Show all results</a> </div></div></div>')
$(".js__main-nav__solr-form_input").keyup(delay(function (e) {
var search = $(this).val();
if (search.length > 2) {
if (_searchPages) {
_searchPages.abort();
}
if (_searchNews) {
_searchNews.abort();
}
if (_searchEvents) {
_searchEvents.abort();
}
if (_searchExtensions) {
_searchExtensions.abort();
}
doSearch(search);
} else {
if (_searchPages) {
_searchPages.abort();
}
if (_searchNews) {
_searchNews.abort();
}
if (_searchEvents) {
_searchEvents.abort();
}
if (_searchExtensions) {
_searchExtensions.abort();
}
$('.results-list-insert-pages').html('');
$('.results-list-insert-news').html('');
$('.results-list-insert-events').html('');
$('.results-list-insert-extensions').html('');
}
}, 300));
});
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment