Commit 23d130ce authored by Dainis Abols's avatar Dainis Abols
Browse files

Major search changes. Filters + ordering + solr + TYPO3 v10 compatability

parent e8c1d641
......@@ -2,22 +2,20 @@
namespace Lu\LuSearch\Controller;
use HDNET\Calendarize\ViewHelpers\Link\AbstractLinkViewHelper;
use Lu\LuApi\DataSources\SolrSearch;
use Lu\LuSearch\Domain\Model\Results;
use Lu\LuSearch\Helpers\DataHelper;
use TYPO3\CMS\Beuser\Domain\Model\BackendUser;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Core\Resource\ResourceStorage;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/**
* Class SearchController
......@@ -67,19 +65,12 @@ class SearchController extends ActionController
*/
private $currentPage;
/**
* Filter array
*
* @var array
*/
private $filter;
/**
* Define pagination limit
*
* @var int
*/
private $limit = 25;
private $limit = 10;
/**
* Parent IDs
......@@ -122,25 +113,39 @@ class SearchController extends ActionController
// Pre-define variables
$data = [];
$request = $_REQUEST;
$currentPage = $request["tx_lusearch_pi1"]['@widget_0']['currentPage'];
if (empty($request['query'])) {
$request = $this->request->getArguments();
// Check queries
if (empty($request)) {
$request = $this->request->getArguments();
$currentPage = $this->request->getArguments()['@widget_0']['currentPage'];
}
// Set order
$request['orderBy'] = !empty($request['orderBy']) ? $request['orderBy'] : 'default';
// Clear filter
if (!empty($request['filter'])) {
foreach ($request['filter'] as &$filter) {
$filter = array_unique($filter);
}
}
// Find pagetree if limit set
// Find page tree if limit set
if ($this->settings['limitToDomain']) {
// Get page record for tree starting point
$this->parentIDs = $this->buildTree($this->getParentSite($GLOBALS['TSFE']->id)->getRootPageId());
$this->parentIDs = @$this->buildTree($this->getParentSite($GLOBALS['TSFE']->id)->getRootPageId());
}
// Get current page @FIXME There has to be a better way!
$this->currentPage = !empty($request['@widget_0']['currentPage']) ? (int)$request['@widget_0']['currentPage'] : 1;
$this->currentPage = !empty($currentPage) ? (int)$currentPage : 1;
// Fetch data from SOLR
$cleanQuery = strip_tags($request['query']);
$cleanQuery = strlen($cleanQuery) >= 3 ? $cleanQuery : '';
if ($cleanQuery) {
$data = $this->listResults($cleanQuery);
$data = $this->listResults($request);
$dataFacets = $this->listResults($request, true);
}
// Add highlighting
......@@ -156,7 +161,6 @@ class SearchController extends ActionController
$singleTranslate = true;
}
// Add paginate object
$data['paginate'] = [];
for ($k = 0; $k < $numRows; $k++) {
......@@ -169,13 +173,20 @@ class SearchController extends ActionController
// Assign variables
$this->view->assign('query', $cleanQuery);
$this->view->assign('orderBy', $request['orderBy']);
$this->view->assign('currentPage', $this->currentPage);
$this->view->assign('singleTranslate', $singleTranslate);
$this->view->assign('pageId', $GLOBALS['TSFE']->id);
$this->view->assign('language', $this->language);
$this->view->assign('newsPageId', $this->language);
$this->view->assign('pageLimit', $this->limit);
// Assign final data element to view
$this->view->assign('visual', $this->getVisualsFilter($request['filter']));
$this->view->assign('filters', $request['filter']);
$facets = $this->convertFacets($dataFacets['facet_fields'] ?? []);
$this->view->assign('facets', $facets);
$this->view->assign('data', $data);
}
......@@ -188,16 +199,29 @@ class SearchController extends ActionController
*
* @param $query
*/
private function listResults($query)
private function listResults($request, $withFacets = false)
{
// Pre-set models and values
$dataHelper = new DataHelper();
$query = $request['query'];
$orderBy = $request['orderBy'];
// Search in SOLR
$solr = new SolrSearch();
$solr->setLimit($this->limit);
$solr->setOffset(($this->currentPage - 1) * $this->limit);
$solr->setHighlight("<span class=\"searchResults__searchTerm\">|</span>");
if ($withFacets) {
$solr->useFacets(true);
} else {
$solr->setHighlight("<span class=\"searchResults__searchTerm\">|</span>");
}
// Check facet call
if (!empty($request['filter'])) {
foreach ($request['filter'] as $name => $value) {
$solr->setFacetFilter($name, $value);
}
}
// Set filters
$filters = ['title:"'.$query.'"', 'author:"'.$query.'"', 'body:"'.$query.'"'];
......@@ -217,14 +241,17 @@ class SearchController extends ActionController
// if ($this->settings['searchContacts']) {
// $types[] = 'type:contact';
// }
if ($this->settings['searchEvents']) {
$types[] = 'type:event';
}
// if ($this->settings['searchEvents']) {
// $types[] = 'type:event';
// }
if ($this->settings['searchPages']) {
$types[] = 'type:page';
}
$solr->setTypes($types);
// Set order
$solr->setOrder($orderBy);
// Fetch data
$jsonData = $solr->fetch(true);
$result = $dataHelper->APIDecode($jsonData);
......@@ -262,8 +289,8 @@ class SearchController extends ActionController
$siteData = $this->getParentSite($item['parent_id']);
// Fetch data
$uid = str_replace($item['type'].'-', '', $item['id']);
$title = $highlight[$item['id']]['title'][0] ?? $this->clearAndHighlight($item['title'], $cleanQuery, false);
$uid = str_replace($item['type'].'-', '', $item['id']);
$title = $highlight[$item['id']]['title'][0] ?? $this->clearAndHighlight($item['title'], $cleanQuery, false);
$siteUrl = !empty($siteData) ? 'https://'.$siteData->getBase()->getHost() : '';
if (empty($title)) {
// If title is not still set, try to get parent page title
......@@ -345,6 +372,8 @@ class SearchController extends ActionController
*/
public function buildTree($startingPoint, $depth = 100)
{
GLOBAL $GLOBALS;
// Get page record for tree starting point
$pageRecord = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord(
'pages',
......@@ -361,12 +390,11 @@ class SearchController extends ActionController
'HTML' => '',
];
// Create the page tree, from the starting point, 2 levels deep
$tree->getTree(
$startingPoint,
$depth,
''
);
// Create the page tree, from the starting point, 2 levels deep with admin rights
$GLOBALS['BE_USER'] = new BackendUserAuthentication();
$GLOBALS['BE_USER']->user['admin'] = 1;
$tree->getTree($startingPoint, $depth, '');
$GLOBALS['BE_USER'] = null;
// Fetch only uids and retrn data
$treeIds = [];
......@@ -488,7 +516,7 @@ class SearchController extends ActionController
{
// Fetch image from storage
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
$fileObjects = $fileRepository->findByRelation('tx_news_domain_model_news', 'fal_media', $uid);
$fileObjects = $fileRepository->findByRelation('tx_news_domain_model_news', 'fal_media', $uid);
// Build image
if (!empty($fileObjects)) {
......@@ -511,9 +539,10 @@ class SearchController extends ActionController
*
* @return string
*/
private function getPageTitle($page_id) {
private function getPageTitle($page_id)
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('page')->createQueryBuilder();
$statement = $queryBuilder->select('title', 'slug')->from('pages')->where(
$statement = $queryBuilder->select('title', 'slug')->from('pages')->where(
$queryBuilder->expr()->eq('uid', $page_id),
)->execute();
......@@ -546,12 +575,12 @@ class SearchController extends ActionController
{
// Fetch image from storage
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
$fileObjects = $fileRepository->findByRelation('pages', 'media', $uid);
$fileObjects = $fileRepository->findByRelation('pages', 'media', $uid);
// Fetch level up
if (empty($fileObjects)) {
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('page')->createQueryBuilder();
$statement = $queryBuilder->select('pid')->from('pages')->where(
$statement = $queryBuilder->select('pid')->from('pages')->where(
$queryBuilder->expr()->eq('uid', $uid),
)->execute();
......@@ -567,10 +596,123 @@ class SearchController extends ActionController
// Build first element image
return $this->getPublicPath($fileObjects[0]);
}
}
private function addCalendarId($uid)
{
return 55699;
}
private function addCalendarId($uid)
{
return 55699;
}
/**
* Convert facets to readable array
*
* @param $facets
*
* @return array
*/
private function convertFacets(array $facets): array
{
// Preset models
$myResults = new Results();
// Loop fasets
$result = [];
if (!empty($facets)) {
foreach ($facets as $field => $items) {
// Reformat items
$item = [];
for ($k = 0; $k < count($items); $k = $k + 2) {
if ($items[$k + 1] > 0) {
$item[] = [
'name' => $items[$k],
'visual' => $myResults->getTitleByFacet($field, $items[$k]),
'count' => $items[$k + 1],
'url' => $this->generateUrl($field, $items[$k]),
];
}
}
if (!empty($item)) {
$result[] = [
'name' => $field,
'items' => $item,
];
}
}
}
// Return result
return $result;
}
/**
* Genereate url for facet usage
*
* @param $field
* @param $item
*
* @return string
*/
private function generateUrl($field, $item)
{
// Fetch uri
$uri = parse_url($_SERVER['REQUEST_URI']);
// Build new param
$newParam = 'filter['.$field.'][]='.$item;
// Check if params already present
if (!empty($uri['query'])) {
$params = explode('&', $uri['query']);
$params = array_unique($params);
foreach ($params as $k => $param) {
// Remove own entry
if ($newParam == urldecode($param)) {
unset($params[$k]);
$newParam = '';
}
// Remove page switcher
if (strpos($param, 'currentPage') > 0) {
unset($params[$k]);
}
// Remove hash
if (strpos($param, 'cHash') === 0) {
unset($params[$k]);
}
}
$params[] = $newParam;
$params = array_filter($params);
$uri['query'] = implode('&', $params);
$uri['query'] = !empty($uri['query']) ? '?'.$uri['query'] : '';
}
// Return finalized url
return $uri['path'].$uri['query'];
}
/**
* Build visual filter display
*
* @param $filters
*
* @return array
*/
private function getVisualsFilter($filters)
{
// Preset
$visual = [];
// Fetch title and move value to key
foreach ($filters as $field => $items) {
foreach ($items as $item) {
$myResults = new Results();
$visual[$field][$item] = $myResults->getTitleByFacet($field, $item);
}
}
return $visual;
}
}
<?php
namespace Lu\LuSearch\Domain\Model;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\ConnectionPool;
/**
* Class Results
*
* @package Lu\LuSearch\Domain\Model
*/
class Results
{
/**
* Fetch title by uid and field
*
* @param $field
* @param $uid
*
* @return mixed|string
*/
public function getTitleByFacet($field, $uid)
{
// Fetch titles
switch ($field) {
case 'category':
// Fetch category name
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('sys_category')->createQueryBuilder();
$row = $queryBuilder
->select('title')
->from('sys_category')->where(
$queryBuilder->expr()->eq('uid', $uid)
)
->execute()->fetch();
break;
case 'tag':
// Fetch category name
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_news_domain_model_tag')->createQueryBuilder();
$row = $queryBuilder
->select('title')
->from('tx_news_domain_model_tag')->where(
$queryBuilder->expr()->eq('uid', $uid)
)
->execute()->fetch();
break;
}
// Return
return $row['title'] ?? $uid;
}
}
This diff is collapsed.
......@@ -59,6 +59,55 @@
<trans-unit id="results.page">
<source><![CDATA[Page]]></source>
</trans-unit>
<!-- Filters -->
<trans-unit id="filter.title">
<source><![CDATA[Filters]]></source>
</trans-unit>
<trans-unit id="facet.type">
<source><![CDATA[Types]]></source>
</trans-unit>
<trans-unit id="facet.tag">
<source><![CDATA[Tags]]></source>
</trans-unit>
<trans-unit id="facet.category">
<source><![CDATA[Categories]]></source>
</trans-unit>
<trans-unit id="facet.type.content">
<source><![CDATA[Content]]></source>
</trans-unit>
<trans-unit id="facet.type.news">
<source><![CDATA[News]]></source>
</trans-unit>
<trans-unit id="facet.type.page">
<source><![CDATA[Page]]></source>
</trans-unit>
<trans-unit id="filter.selectedParams">
<source><![CDATA[Active filters]]></source>
</trans-unit>
<trans-unit id="filter.clearFilter">
<source><![CDATA[Clear results and filter]]></source>
</trans-unit>
<trans-unit id="filter.select">
<source><![CDATA[Select]]></source>
</trans-unit>
<trans-unit id="filter.orderBy">
<source><![CDATA[Order By]]></source>
</trans-unit>
<trans-unit id="filter.relevance">
<source><![CDATA[Relevance]]></source>
</trans-unit>
<trans-unit id="filter.newest">
<source><![CDATA[Newest]]></source>
</trans-unit>
<trans-unit id="filter.olest">
<source><![CDATA[Oldest]]></source>
</trans-unit>
<trans-unit id="dateTimeFormat">
<source><![CDATA[d.m.Y H:i]]></source>
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
</xliff>
......@@ -77,6 +77,70 @@
<source><![CDATA[Page]]></source>
<target><![CDATA[Lapa]]></target>
</trans-unit>
<!-- Filters -->
<trans-unit id="filter.title">
<source><![CDATA[Filters]]></source>
<target><![CDATA[Filtri]]></target>
</trans-unit>
<trans-unit id="facet.type">
<source><![CDATA[Types]]></source>
<target><![CDATA[Tipi]]></target>
</trans-unit>
<trans-unit id="facet.tag">
<source><![CDATA[Tags]]></source>
<target><![CDATA[Tagi]]></target>
</trans-unit>
<trans-unit id="facet.category">
<source><![CDATA[Categories]]></source>
<target><![CDATA[Kategorijas]]></target>
</trans-unit>
<trans-unit id="facet.type.content">
<source><![CDATA[Content]]></source>
<target><![CDATA[Saturs]]></target>
</trans-unit>
<trans-unit id="facet.type.news">
<source><![CDATA[News]]></source>
<target><![CDATA[Ziņas]]></target>
</trans-unit>
<trans-unit id="facet.type.page">
<source><![CDATA[Page]]></source>
<target><![CDATA[Lapa]]></target>
</trans-unit>
<trans-unit id="filter.selectedParams">
<source><![CDATA[Active filters]]></source>
<target><![CDATA[Aktīvie filtri]]></target>
</trans-unit>
<trans-unit id="filter.clearFilter">
<source><![CDATA[Clear results and filter]]></source>
<target><![CDATA[Notīrīt filtrus un meklētāju]]></target>
</trans-unit>
<trans-unit id="filter.select">
<source><![CDATA[Select]]></source>
<target><![CDATA[Izvēlēties]]></target>
</trans-unit>
<trans-unit id="filter.orderBy">
<source><![CDATA[Order By]]></source>
<target><![CDATA[Kārtot pēc]]></target>
</trans-unit>
<trans-unit id="filter.relevance">
<source><![CDATA[Relevance]]></source>
<target><![CDATA[Atbilstības]]></target>
</trans-unit>
<trans-unit id="filter.newest">
<source><![CDATA[Newest]]></source>
<target><![CDATA[Jaunākā]]></target>
</trans-unit>
<trans-unit id="filter.olest">
<source><![CDATA[Oldets]]></source>
<target><![CDATA[Vecākā]]></target>
</trans-unit>
<trans-unit id="dateTimeFormat">
<source><![CDATA[d.m.Y H:i]]></source>
<target><![CDATA[d.m.Y. H.i]]></target>
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
</xliff>
......@@ -16,7 +16,7 @@
<div class="searchResults__resultContent">
<div class="searchResults__resultMeta">
<span class="searchResults__resultDate">
<f:format.date format="d.m.Y H:i">{article.date_published}</f:format.date>
<f:format.date format="{f:translate(key:'LLL:EXT:lu_search/Resources/Private/Language/locallang.xlf:dateTimeFormat')}">{article.date_published}</f:format.date>
</span>
<span class="searchResults__resultCategory">
<f:translate key="results.{article.type}"/>
......@@ -32,4 +32,4 @@
</article>
</html>
\ No newline at end of file
</html>
......@@ -15,7 +15,7 @@
<div class="searchResults__resultContent">
<div class="searchResults__resultMeta">
<span class="searchResults__resultDate">
<f:format.date format="d.m.Y H:i">{date_published}</f:format.date>
<f:format.date format="{f:translate(key:'LLL:EXT:lu_search/Resources/Private/Language/locallang.xlf:dateTimeFormat')}">{date_published}</f:format.date>
</span>
<span class="searchResults__resultCategory">
<f:translate key="results.content"/>
......@@ -31,4 +31,4 @@
</article>
</html>
\ No newline at end of file
</html>
......@@ -18,7 +18,7 @@
<div class="searchResults__resultContent">
<div class="searchResults__resultMeta">
<span class="searchResults__resultDate">
<f:format.date format="d.m.Y H:i">{date_published}</f:format.date>
<f:format.date format="{f:translate(key:'LLL:EXT:lu_search/Resources/Private/Language/locallang.xlf:dateTimeFormat')}">{date_published}</f:format.date>
</span>
<span class="searchResults__resultCategory">
<f:translate key="results.events"/>
......@@ -34,4 +34,4 @@
</article>
</html>
\ No newline at end of file
</html>
......@@ -17,7 +17,7 @@
<div class="searchResults__resultContent">
<div class="searchResults__resultMeta">