Skip to content

Commit

Permalink
Merge pull request #3 from skurfuerst/dev-query-result
Browse files Browse the repository at this point in the history
Highlighting Support in Search
  • Loading branch information
skurfuerst committed Mar 20, 2015
2 parents 3c9cfd4 + d569ecd commit 1f40254
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 32 deletions.
84 changes: 84 additions & 0 deletions Classes/Flowpack/SearchPlugin/Controller/SuggestController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
namespace Flowpack\SearchPlugin\Controller;

/* *
* This script belongs to the TYPO3 Flow package "Flowpack.SearchPlugin". *
* *
* It is free software; you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License, either version 3 *
* of the License, or (at your option) any later version. *
* *
* The TYPO3 project - inspiring people to share! *
* */

use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Mvc\Controller\ActionController;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;

/**
* Class SuggestController
*
* @author Jon Klixbüll Langeland <jon@moc.net>
* @package Flowpack\SearchPlugin\Controller
*/
class SuggestController extends ActionController {

/**
* @Flow\Inject
* @var \Flowpack\ElasticSearch\ContentRepositoryAdaptor\ElasticSearchClient
*/
protected $elasticSearchClient;

/**
* The node inside which searching should happen
*
* @var NodeInterface
*/
protected $contextNode;

/**
* @Flow\Inject
* @var \Flowpack\ElasticSearch\ContentRepositoryAdaptor\LoggerInterface
*/
protected $logger;

/**
* @var boolean
*/
protected $logThisQuery = FALSE;

/**
* @var string
*/
protected $logMessage;

/**
* @var array
*/
protected $viewFormatToObjectNameMap = array(
'json' => 'TYPO3\Flow\Mvc\View\JsonView'
);

/**
* @param NodeInterface $node
* @param string $term
*/
public function indexAction(NodeInterface $node, $term) {
$request = array(
'suggests' => array(
'text' => $term,
'term' => array(
'field' => '_all'
)
)
);

$response = $this->elasticSearchClient->getIndex()->request('GET', '/_suggest', array(), json_encode($request))->getTreatedContent();
$suggestions = array_map(function($option) {
return $option['text'];
}, $response['suggests'][0]['options']);

$this->view->assign('value', $suggestions);
}

}
47 changes: 47 additions & 0 deletions Classes/Flowpack/SearchPlugin/EelHelper/SearchArrayHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
namespace Flowpack\SearchPlugin\EelHelper;

/* *
* This script belongs to the TYPO3 Flow package "Flowpack.SearchPlugin". *
* *
* It is free software; you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License, either version 3 *
* of the License, or (at your option) any later version. *
* *
* The TYPO3 project - inspiring people to share! *
* */
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Eel\ProtectedContextAwareInterface;

/**
* Additional Array Helpers which might once
*
* @Flow\Proxy(false)
*/
class SearchArrayHelper implements ProtectedContextAwareInterface {

/**
* Concatenate arrays or values to a new array
*
* @param array|mixed $array1 First array or value
* @param array|mixed $array2 Second array or value
* @param array|mixed $array_ Optional variable list of additional arrays / values
* @return array The array with concatenated arrays or values
*/
public function flatten($arrays) {
$return = array();
array_walk_recursive($arrays, function($a) use (&$return) { $return[] = $a; });
return $return;
}

/**
* All methods are considered safe
*
* @param string $methodName
* @return boolean
*/
public function allowsCallOfMethod($methodName) {
return TRUE;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


/* *
* This script belongs to the TYPO3 Flow package "Flowpack.SearchPlugin.TypoScriptObjects". *
* This script belongs to the TYPO3 Flow package "Flowpack.SearchPlugin". *
* *
* It is free software; you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License, either version 3 *
Expand Down
11 changes: 11 additions & 0 deletions Configuration/Policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
privilegeTargets:
TYPO3\Flow\Security\Authorization\Privilege\Method\MethodPrivilege:
Flowpack_SearchPlugin_Controller_SuggestController:
matcher: method(Flowpack\SearchPlugin\Controller\SuggestController->indexAction())

roles:
'TYPO3.Flow:Everybody':
privileges:
-
privilegeTarget: Flowpack_SearchPlugin_Controller_SuggestController
permission: GRANT
11 changes: 11 additions & 0 deletions Configuration/Routes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# DataSourceController routes
-
name: 'flowpack/searchplugin - SuggestController->index'
uriPattern: 'flowpack/searchplugin'
defaults:
'@package': 'Flowpack.SearchPlugin'
'@controller': 'Suggest'
'@action': 'index'
'@format': 'json'
appendExceedingArguments: TRUE
httpMethods: ['GET']
6 changes: 5 additions & 1 deletion Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ TYPO3:
Neos:
typoScript:
autoInclude:
'Flowpack.SearchPlugin': TRUE
'Flowpack.SearchPlugin': TRUE

TypoScript:
defaultContext:
Flowpack.SearchPlugin.Array: 'Flowpack\SearchPlugin\EelHelper\SearchArrayHelper'
6 changes: 3 additions & 3 deletions Resources/Private/Templates/NodeTypes/Search.Form.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<form action="" method="GET">
<input type="text" name="search" value="{searchWord}" />
<button type="submit">Send</button>
<form method="GET">
<input type="search" name="search" value="{searchWord}" placeholder="Search" data-autocomplete-source="{f:uri.action(action: 'index', controller: 'Suggest', package: 'Flowpack.SearchPlugin', format: 'json' absolute: 1, arguments: {node: node})}" />
<button type="submit">Search</button>
</form>
15 changes: 10 additions & 5 deletions Resources/Private/Templates/NodeTypes/Search.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{namespace neos=TYPO3\Neos\ViewHelpers}
{namespace ts=TYPO3\TypoScript\ViewHelpers}
{namespace search=TYPO3\TYPO3CR\Search\ViewHelpers}
<div{attributes -> f:format.raw()}>
{searchForm -> f:format.raw()}

{searchForm -> f:format.raw()}

Showing {searchResults -> f:count()} of {totalSearchResults} results

{searchResultRenderer -> f:format.raw()}
<f:if condition="{searchQuery}">
<search:widget.paginate query="{searchQuery}" as="results">
Showing {results.accessibleCount} of {totalSearchResults} results
<ts:render path="searchResultRenderer" context="{searchResults: results}" />
</search:widget.paginate>
</f:if>
</div>
19 changes: 14 additions & 5 deletions Resources/Private/Templates/SearchResult/DocumentSearchResult.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
{namespace neos=TYPO3\Neos\ViewHelpers}
<neos:link.node node="{node}">{title}</neos:link.node>

<b><neos:link.node node="{node}">
{title}
</neos:link.node></b><br />
<f:if condition="{highlight}">
<p>
<f:for each="{highlight}" as="fragment" iteration="fragmentIterator">
{fragment -> f:format.raw()}{f:if(condition: fragmentIterator.isLast, else: '...')}
</f:for>
</p>

<f:if condition="{description}">
{description}
<div class="breadcrumb">
<span>Path:</span>
<f:for each="{parents}" as="parent">
<neos:link.node node="{parent}" />
</f:for>
<neos:link.node node="{node}" />
</div>
</f:if>
9 changes: 3 additions & 6 deletions Resources/Private/TypoScript/ResultRendering.ts2
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@ prototype(Flowpack.SearchPlugin:SingleResult) < prototype(TYPO3.TypoScript:Case)
prototype(TYPO3.Neos:DocumentSearchResult) < prototype(TYPO3.TypoScript:Template) {
templatePath = 'resource://Flowpack.SearchPlugin/Private/Templates/SearchResult/DocumentSearchResult.html'
node = ${node}
highlight = ${Flowpack.SearchPlugin.Array.flatten(searchHit.highlight)}

title = ${q(node).property('title')}
description = ''
parents = ${Array.reverse(q(node).parents('[instanceof TYPO3.Neos:Document]').get())}
}

prototype(TYPO3.Neos.NodeTypes:PageSearchResult) < prototype(TYPO3.Neos:DocumentSearchResult)


prototype(TYPO3.NeosDemoTypo3Org:ChapterSearchResult) < prototype(TYPO3.Neos:DocumentSearchResult) {
description = ${q(node).property('chapterDescription')}
}
prototype(TYPO3.Neos.NodeTypes:PageSearchResult) < prototype(TYPO3.Neos:DocumentSearchResult)
20 changes: 9 additions & 11 deletions Resources/Private/TypoScript/SearchPlugin.ts2
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@

prototype(Flowpack.SearchPlugin:Search) {

// we store the search results in the TypoScript context, so that they bubble through the nested elements like the searchResultRenderer
@override.searchResults = ${this.searchQuery.execute()}


searchQuery = ${Search.query(site).fulltext(request.arguments.search || '')}
searchTerm = ${request.arguments.search}
searchQuery = ${this.searchTerm ? Search.query(site).fulltext(this.searchTerm) : null}

totalSearchResults = ${this.searchQuery.count()}
searchResults = ${searchResults}

searchForm = Flowpack.SearchPlugin:Search.Form

searchResultRenderer = TYPO3.TypoScript:Collection {
// the "searchResults" are filled from the <search:widget.paginate> ViewHelper.
collection = ${searchResults}
itemRenderer = Flowpack.SearchPlugin:SingleResult
itemName = 'node'
// we also make the full ElasticSearch hit available to nested rendering, if possible
itemRenderer.@override.searchHit = ${searchResults.searchHitForNode(node)}
}

searchResultRenderer.@process.wrap = ${'<ul>' + value + '</ul>'}
searchResultRenderer.@process.wrap = ${'<ol>' + value + '</ol>'}
prototype(Flowpack.SearchPlugin:SingleResult).@process.wrap = ${'<li>' + value + '</li>'}

@cache {
Expand All @@ -32,7 +30,7 @@ prototype(Flowpack.SearchPlugin:Search) {


prototype(Flowpack.SearchPlugin:Search.Form) < prototype(TYPO3.TypoScript:Template) {
templatePath = 'resource://Flowpack.SearchPlugin/Private/Templates/NodeTypes/Search.Form.Html'
node = ${site}
templatePath = 'resource://Flowpack.SearchPlugin/Private/Templates/NodeTypes/Search.Form.html'
searchWord = ${request.arguments.search}
}

}

0 comments on commit 1f40254

Please sign in to comment.