Skip to content

Commit

Permalink
Merge pull request #4 from webcoast-dk/feature/search-suggestions
Browse files Browse the repository at this point in the history
[FEATURE] Search suggestions
  • Loading branch information
thommyhh committed Oct 7, 2022
2 parents 5063414 + 3a0d815 commit 00fcbfd
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Classes/Backend/AbstractBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ public abstract function initialize();
*/
public abstract function search(string $searchString, int $currentPage, $category = null): array;

/**
* Return an array of words for search suggestions
*
* @param string $searchString
* @param int $maxItems
* @param int $languageUid
*
* @return array
*/
public abstract function suggest(string $searchString, int $maxItems, int $languageUid): array;

/**
* Takes the raw result row and converts it into a standardized format to be used in the output.
*
Expand Down
24 changes: 24 additions & 0 deletions Classes/Backend/IndexedSearchBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository;
Expand Down Expand Up @@ -84,6 +85,29 @@ function ($item) {
return $data;
}

public function suggest(string $searchString, int $maxItems, int $languageUid): array
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
$queryBuilder
->select('w.baseword')
->from('index_words', 'w')
->join('w', 'index_rel', 'r', 'w.wid=r.wid')
->join('r', 'index_phash', 'p', 'r.phash=p.phash')
->where(
$queryBuilder->expr()->like('w.baseword', $queryBuilder->createNamedParameter($searchString . '%')),
$queryBuilder->expr()->eq('p.sys_language_uid', $queryBuilder->createNamedParameter($languageUid, \PDO::PARAM_INT))
)
->groupBy('w.baseword')
->setMaxResults($maxItems)
->orderBy('w.baseword', 'asc');

$result = $queryBuilder->executeQuery();
$words = $result->fetchFirstColumn();
$result->free();

return $words;
}

protected function initializeSearchRepository($searchData, int $itemsPerPage)
{
$searchData['languageUid'] = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id', 0);
Expand Down
52 changes: 52 additions & 0 deletions Classes/Middleware/SuggestMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace WEBcoast\VersatileSearch\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationPathDoesNotExistException;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Http\JsonResponse;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use WEBcoast\VersatileSearch\Backend\AbstractBackend;
use WEBcoast\VersatileSearch\Utility\BackendUtility;

class SuggestMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if ($request->getUri()->getPath() === '/search-auto-complete') {
$searchString = $request->getQueryParams()['q'];
try {
$minCharacters = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('versatile_search', 'suggest.minCharacters') ?? 3;
} catch (ExtensionConfigurationPathDoesNotExistException $exception) {
$minCharacters = 3;
}

if (empty($searchString) || mb_strlen($searchString) < $minCharacters) {
return new JsonResponse([]);
}

/** @var AbstractBackend $backend */
$backend = GeneralUtility::makeInstance(BackendUtility::getSearchBackend(), []);
try {
$maxItems = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('versatile_search', 'suggest.maxItems') ?? 10;
} catch (ExtensionConfigurationPathDoesNotExistException $exception) {
$maxItems = 10;
}
/** @var SiteLanguage $language */
$language = $request->getAttribute('language');

$suggestions = $backend->suggest($searchString, $maxItems, $language->getLanguageId());

return new JsonResponse($suggestions);
}

return $handler->handle($request);
}
}
15 changes: 15 additions & 0 deletions Configuration/RequestMiddlewares.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

return [
'frontend' => [
'versatile-search/suggest' => [
'target' => \WEBcoast\VersatileSearch\Middleware\SuggestMiddleware::class,
'after' => [
'typo3/cms-frontend/maintenance-mode'
],
'before' => [
'typo3/cms-frontend/backend-user-authentication'
]
]
]
];
3 changes: 3 additions & 0 deletions ext_conf_template.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
# cat=General; type=options[LLL:EXT:versatile_search/Resources/Private/Language/backend.xlf:conf.search.backend.indexed_search=indexed_search,LLL:EXT:versatile_search/Resources/Private/Language/backend.xlf:conf.search.backend.none=none]; label=LLL:EXT:versatile_search/Resources/Private/Language/backend.xlf:conf.search.backend
search.backend = indexed_search

suggest.maxItems = 10
suggest.minCharacters = 3

0 comments on commit 00fcbfd

Please sign in to comment.