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 @@ ...@@ -2,22 +2,20 @@
namespace Lu\LuSearch\Controller; namespace Lu\LuSearch\Controller;
use HDNET\Calendarize\ViewHelpers\Link\AbstractLinkViewHelper;
use Lu\LuApi\DataSources\SolrSearch; use Lu\LuApi\DataSources\SolrSearch;
use Lu\LuSearch\Domain\Model\Results;
use Lu\LuSearch\Helpers\DataHelper; 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\Context\Context;
use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Exception\SiteNotFoundException;
use TYPO3\CMS\Core\Page\PageRenderer; 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\FileRepository;
use TYPO3\CMS\Core\Resource\ResourceStorage;
use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder; use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
/** /**
* Class SearchController * Class SearchController
...@@ -67,19 +65,12 @@ class SearchController extends ActionController ...@@ -67,19 +65,12 @@ class SearchController extends ActionController
*/ */
private $currentPage; private $currentPage;
/**
* Filter array
*
* @var array
*/
private $filter;
/** /**
* Define pagination limit * Define pagination limit
* *
* @var int * @var int
*/ */
private $limit = 25; private $limit = 10;
/** /**
* Parent IDs * Parent IDs
...@@ -122,25 +113,39 @@ class SearchController extends ActionController ...@@ -122,25 +113,39 @@ class SearchController extends ActionController
// Pre-define variables // Pre-define variables
$data = []; $data = [];
$request = $_REQUEST; $request = $_REQUEST;
$currentPage = $request["tx_lusearch_pi1"]['@widget_0']['currentPage'];
if (empty($request['query'])) { // Check queries
if (empty($request)) {
$request = $this->request->getArguments(); $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']) { if ($this->settings['limitToDomain']) {
// Get page record for tree starting point // 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! // 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 // Fetch data from SOLR
$cleanQuery = strip_tags($request['query']); $cleanQuery = strip_tags($request['query']);
$cleanQuery = strlen($cleanQuery) >= 3 ? $cleanQuery : ''; $cleanQuery = strlen($cleanQuery) >= 3 ? $cleanQuery : '';
if ($cleanQuery) { if ($cleanQuery) {
$data = $this->listResults($cleanQuery); $data = $this->listResults($request);
$dataFacets = $this->listResults($request, true);
} }
// Add highlighting // Add highlighting
...@@ -156,7 +161,6 @@ class SearchController extends ActionController ...@@ -156,7 +161,6 @@ class SearchController extends ActionController
$singleTranslate = true; $singleTranslate = true;
} }
// Add paginate object // Add paginate object
$data['paginate'] = []; $data['paginate'] = [];
for ($k = 0; $k < $numRows; $k++) { for ($k = 0; $k < $numRows; $k++) {
...@@ -169,13 +173,20 @@ class SearchController extends ActionController ...@@ -169,13 +173,20 @@ class SearchController extends ActionController
// Assign variables // Assign variables
$this->view->assign('query', $cleanQuery); $this->view->assign('query', $cleanQuery);
$this->view->assign('orderBy', $request['orderBy']);
$this->view->assign('currentPage', $this->currentPage); $this->view->assign('currentPage', $this->currentPage);
$this->view->assign('singleTranslate', $singleTranslate); $this->view->assign('singleTranslate', $singleTranslate);
$this->view->assign('pageId', $GLOBALS['TSFE']->id); $this->view->assign('pageId', $GLOBALS['TSFE']->id);
$this->view->assign('language', $this->language); $this->view->assign('language', $this->language);
$this->view->assign('newsPageId', $this->language); $this->view->assign('newsPageId', $this->language);
$this->view->assign('pageLimit', $this->limit);
// Assign final data element to view // 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); $this->view->assign('data', $data);
} }
...@@ -188,16 +199,29 @@ class SearchController extends ActionController ...@@ -188,16 +199,29 @@ class SearchController extends ActionController
* *
* @param $query * @param $query
*/ */
private function listResults($query) private function listResults($request, $withFacets = false)
{ {
// Pre-set models and values // Pre-set models and values
$dataHelper = new DataHelper(); $dataHelper = new DataHelper();
$query = $request['query'];
$orderBy = $request['orderBy'];
// Search in SOLR // Search in SOLR
$solr = new SolrSearch(); $solr = new SolrSearch();
$solr->setLimit($this->limit); $solr->setLimit($this->limit);
$solr->setOffset(($this->currentPage - 1) * $this->limit); $solr->setOffset(($this->currentPage - 1) * $this->limit);
if ($withFacets) {
$solr->useFacets(true);
} else {
$solr->setHighlight("<span class=\"searchResults__searchTerm\">|</span>"); $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 // Set filters
$filters = ['title:"'.$query.'"', 'author:"'.$query.'"', 'body:"'.$query.'"']; $filters = ['title:"'.$query.'"', 'author:"'.$query.'"', 'body:"'.$query.'"'];
...@@ -217,14 +241,17 @@ class SearchController extends ActionController ...@@ -217,14 +241,17 @@ class SearchController extends ActionController
// if ($this->settings['searchContacts']) { // if ($this->settings['searchContacts']) {
// $types[] = 'type:contact'; // $types[] = 'type:contact';
// } // }
if ($this->settings['searchEvents']) { // if ($this->settings['searchEvents']) {
$types[] = 'type:event'; // $types[] = 'type:event';
} // }
if ($this->settings['searchPages']) { if ($this->settings['searchPages']) {
$types[] = 'type:page'; $types[] = 'type:page';
} }
$solr->setTypes($types); $solr->setTypes($types);
// Set order
$solr->setOrder($orderBy);
// Fetch data // Fetch data
$jsonData = $solr->fetch(true); $jsonData = $solr->fetch(true);
$result = $dataHelper->APIDecode($jsonData); $result = $dataHelper->APIDecode($jsonData);
...@@ -345,6 +372,8 @@ class SearchController extends ActionController ...@@ -345,6 +372,8 @@ class SearchController extends ActionController
*/ */
public function buildTree($startingPoint, $depth = 100) public function buildTree($startingPoint, $depth = 100)
{ {
GLOBAL $GLOBALS;
// Get page record for tree starting point // Get page record for tree starting point
$pageRecord = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord( $pageRecord = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord(
'pages', 'pages',
...@@ -361,12 +390,11 @@ class SearchController extends ActionController ...@@ -361,12 +390,11 @@ class SearchController extends ActionController
'HTML' => '', 'HTML' => '',
]; ];
// Create the page tree, from the starting point, 2 levels deep // Create the page tree, from the starting point, 2 levels deep with admin rights
$tree->getTree( $GLOBALS['BE_USER'] = new BackendUserAuthentication();
$startingPoint, $GLOBALS['BE_USER']->user['admin'] = 1;
$depth, $tree->getTree($startingPoint, $depth, '');
'' $GLOBALS['BE_USER'] = null;
);
// Fetch only uids and retrn data // Fetch only uids and retrn data
$treeIds = []; $treeIds = [];
...@@ -511,7 +539,8 @@ class SearchController extends ActionController ...@@ -511,7 +539,8 @@ class SearchController extends ActionController
* *
* @return string * @return string
*/ */
private function getPageTitle($page_id) { private function getPageTitle($page_id)
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('page')->createQueryBuilder(); $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), $queryBuilder->expr()->eq('uid', $page_id),
...@@ -573,4 +602,117 @@ class SearchController extends ActionController ...@@ -573,4 +602,117 @@ class SearchController extends ActionController
{ {
return 55699; 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 @@ ...@@ -59,6 +59,55 @@
<trans-unit id="results.page"> <trans-unit id="results.page">
<source><![CDATA[Page]]></source> <source><![CDATA[Page]]></source>
</trans-unit> </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> </body>
</file> </file>
</xliff> </xliff>
...@@ -77,6 +77,70 @@ ...@@ -77,6 +77,70 @@
<source><![CDATA[Page]]></source> <source><![CDATA[Page]]></source>
<target><![CDATA[Lapa]]></target> <target><![CDATA[Lapa]]></target>
</trans-unit> </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> </body>
</file> </file>
</xliff> </xliff>
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<div class="searchResults__resultContent">