Skip to content

Instantly share code, notes, and snippets.

@htuscher
Last active April 26, 2019 17:49
Show Gist options
  • Save htuscher/3bd1fbdd8c43f7b2b412 to your computer and use it in GitHub Desktop.
Save htuscher/3bd1fbdd8c43f7b2b412 to your computer and use it in GitHub Desktop.
TYPO3 Solr Autosuggest and Autocomplete using Extbase and TypeNum Ajax
<?php
if (!defined('TYPO3_MODE')) {
die('Access denied.');
}
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Vendor.' . $_EXTKEY,
'Suggest',
array(
'Suggest' => 'suggest',
),
// non-cacheable actions
array(
'Suggest' => 'suggest',
)
);
plugin.tx_myext {
view {
templateRootPath = {$plugin.tx_myext.view.templateRootPath}
partialRootPath = {$plugin.tx_myext.view.partialRootPath}
layoutRootPath = {$plugin.tx_myext.view.layoutRootPath}
}
settings {
suggest {
resultsPerPage = 3
autocompleteLimit = 10
autocompleteField = spell
returnFieldsQuery = *
}
}
}
suggest_type = PAGE
suggest_type {
typeNum = 1337
config {
disableAllHeaderCode = 1
xhtml_cleaning = 0
admPanel = 0
additionalHeaders = Content-type: text/html
}
10 = USER_INT
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = MyExt
pluginName = Suggest
vendorName = Vendor
controller = Suggest
action = suggest
switchableControllerActions {
Suggest {
1 = suggest
}
}
}
}
page.includeJSFooterlibs.autosuggest = typo3conf/ext/my_ext/Resources/Public/JavaScripts/suggest.js
page.includeCSS.autosuggest = typo3conf/ext/my_ext/Resources/Public/Css/suggest.css
<f:layout name="Default" />
<f:section name="Main">
<button type="button" class="close"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<div class="row">
<div class="col-md-9">
<div class="row">
<f:for each="{suggest}" as="sug">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<a class="figure" href="{sug.url}" title="{sug.title}">
<img src="{sug.thumbnail_stringS}" width="180" height="100" alt="{sug.title}">
</a>
<div class="caption">
<h3 class="shorttitle">{sug.title}</h3>
<p>
<f:format.crop maxCharacters="100" append="&nbsp;...">{sug.content}</f:format.crop>
</p>
</div>
</div>
</div>
</f:for>
</div>
</div>
<div class="col-md-3">
<ul class="list-unstyled">
<f:for each="{autocomplete}" as="keywordCount" key="keyword">
<li>
<f:link.page pageUid="{settings.searchPageUid}" additionalParams="{q : '{keyword}'}">
{keyword} ({keywordCount})
</f:link.page>
</li>
</f:for>
</ul>
</div>
</div>
</f:section>
/*
* Suggest
*/
(function($){
$(document).ready(function(){
var suggestRequest = null;
var inputField = '#inputText'
var flyoutContainer = '#suggest-container';
$(inputField).on('input', function() {
if($(this).val().length >= 3){
suggestRequest = $.ajax({
type: "GET",
url: '/',
data: {
type: '1337',
q : $(this).val()
},
dataType : 'html'
});
suggestRequest.done(function(result) {
$(flyoutContainer).html(result);
if($(flyoutContainer).not(':visible') && $(flyoutContainer + ' .thumbnail').length > 0) {
$(flyoutContainer).fadeIn();
} else if($(flyoutContainer).is(':visible') && $(flyoutContainer + ' .thumbnail').length == 0) {
$(flyoutContainer).fadeOut();
}
});
} else {
if($(flyoutContainer).is(':visible')){
$(flyoutContainer).fadeOut();
}
}
});
$(document).on('click', flyoutContainer + ' button.close', function(){
if($(flyoutContainer).is(':visible')){
$(flyoutContainer).fadeOut();
}
});
$(window).resize(function() {
if($(flyoutContainer).is(':visible')) {
$(flyoutContainer).hide();
}
});
});
})(jQuery);
<?php
namespace Vendor\MyExt\Controller;
use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException;
class SuggestController extends ActionController {
/**
* Initialize Query object with configured parameters
*
* @param string $q
*
* @return \Tx_Solr_Query
*/
protected function initQuery($q) {
$suggestConf = $this->settings['suggest'];
$solrConfiguration = \Tx_Solr_Util::getSolrConfigurationFromPageId($GLOBALS['TSFE']->id, FALSE, $GLOBALS['TSFE']->sys_language_uid);
/** @var \Tx_Solr_Query $query */
$query = GeneralUtility::makeInstance('Tx_Solr_Query', $q . '* OR ' . $q);
/*
* Add configured filters
*/
if (is_array($suggestConf['filter']) && !empty($suggestConf['filter'])) {
foreach ($suggestConf['filter'] as $filter) {
$query->addFilter($filter);
}
}
/*
* Add default parameters
*/
$query->setUserAccessGroups(explode(',', $GLOBALS['TSFE']->gr_list));
$site = \Tx_Solr_Site::getSiteByPageId($GLOBALS['TSFE']->id);
$query->setSiteHashFilter($site->getDomain());
$query->setSpellchecking(TRUE);
$query->setFieldList($suggestConf['returnFieldsQuery']);
$query->setHighlighting(TRUE);
/*
* Add Boost Queries
*/
if (!empty($solrConfiguration['search.']['query.']['boostFunction'])) {
$query->setBoostFunction($solrConfiguration['search.']['query.']['boostFunction']);
}
if (!empty($solrConfiguration['search.']['query.']['boostQuery'])) {
$query->setBoostQuery($solrConfiguration['search.']['query.']['boostQuery']);
}
if (!empty($solrConfiguration['search.']['query.']['boostQuery.'])) {
$boostQueries = array();
$boostConfiguration = $solrConfiguration['search.']['query.']['boostQuery.'];
foreach ($boostConfiguration as $boostQuery) {
$boostQueries[] = $boostQuery;
}
$query->setBoostQuery($boostQueries);
}
return $query;
}
/**
* action suggest
*
* @return string
*/
public function suggestAction() {
/** @var \Tx_Solr_ConnectionManager $solrConnection */
$solrConnection = GeneralUtility::makeInstance('Tx_Solr_ConnectionManager')->
getConnectionByPageId($GLOBALS['TSFE']->id, $GLOBALS['TSFE']->sys_language_uid);
/** @var \Tx_Solr_Search $search */
$search = GeneralUtility::makeInstance('Tx_Solr_Search', $solrConnection);
try {
$q = strtolower(trim(GeneralUtility::_GP('q')));
// Empty paramter is not allowed
if (empty($q)) {
throw new NoSuchArgumentException('Empty query provided, please check your query parameter');
}
//Check for availability
if (!$search->ping()) {
throw new ServiceUnavailableException('Search server not available');
}
$query = $this->initQuery($q);
$this->view->assign('q', $q);
$flyoutResults = json_decode($search->search($query, 0 , $this->settings['suggest']['resultsPerPage'])->getRawResponse());
$this->view->assign('status', 'ok');
$this->view->assign('suggest', $flyoutResults->response->docs);
$query->setQueryString('*:*');
$query->addQueryParameter('facet.prefix',$q);
$query->setFaceting(TRUE);
$query->addFacetField($this->settings['suggest']['autocompleteField']);
$query->addQueryParameter('facet.limit', $this->settings['suggest']['autocompleteLimit']);
$autocompleteResults = json_decode($search->search($query, 0 , $this->settings['suggest']['resultsPerPage'])->getRawResponse());
$this->view->assign('autocomplete', get_object_vars($autocompleteResults->facet_counts->facet_fields->{$this->settings['suggest']['autocompleteField']}));
} catch (NoSuchArgumentException $e) {
$this->view->assign('status', 'error');
$this->view->assign('errorMsg', $e->getMessage());
} catch (ServiceUnavailableException $e) {
$this->view->assign('status', 'error');
$this->view->assign('errorMsg', $e->getMessage());
}
}
}
@nicedp
Copy link

nicedp commented Aug 22, 2016

Where should the 'suggest' plugin will be called on page ? Any instructions doc you have ?

@seanbai
Copy link

seanbai commented Jan 12, 2017

Where should the 'suggest' plugin will be called on page ? Any instructions doc you have ?

@mediaessenz
Copy link

Is there a solr v 9.0 compatible version of this code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment