first commit
This commit is contained in:
558
Classes/Domain/Search/Query/AbstractQueryBuilder.php
Normal file
558
Classes/Domain/Search/Query/AbstractQueryBuilder.php
Normal file
@@ -0,0 +1,558 @@
|
||||
<?php
|
||||
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\BigramPhraseFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Elevation;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Faceting;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\FieldCollapsing;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Grouping;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Highlighting;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Operator;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\PhraseFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\QueryFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\ReturnFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Slops;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Sorting;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Sortings;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Spellchecking;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\TrigramPhraseFields;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
|
||||
/**
|
||||
* The AbstractQueryBuilder contains all logic to initialize solr queries independent from TYPO3.
|
||||
*/
|
||||
abstract class AbstractQueryBuilder {
|
||||
|
||||
/**
|
||||
* @var Query
|
||||
*/
|
||||
protected $queryToBuild = null;
|
||||
|
||||
/**
|
||||
* @param Query $query
|
||||
* @return $this
|
||||
*/
|
||||
public function startFrom(Query $query)
|
||||
{
|
||||
$this->queryToBuild = $query;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Query
|
||||
*/
|
||||
public function getQuery(): Query
|
||||
{
|
||||
return $this->queryToBuild;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $omitHeader
|
||||
* @return $this
|
||||
*/
|
||||
public function useOmitHeader($omitHeader = true)
|
||||
{
|
||||
$this->queryToBuild->setOmitHeader($omitHeader);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses an array of filters and applies them to the query.
|
||||
*
|
||||
* @param array $filterArray
|
||||
* @return $this
|
||||
*/
|
||||
public function useFilterArray(array $filterArray)
|
||||
{
|
||||
foreach ($filterArray as $key => $additionalFilter) {
|
||||
$this->useFilter($additionalFilter, $key);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the queryString that is used to search
|
||||
*
|
||||
* @param string $queryString
|
||||
* @return $this
|
||||
*/
|
||||
public function useQueryString($queryString)
|
||||
{
|
||||
$this->queryToBuild->setQuery($queryString);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the passed queryType to the query.
|
||||
*
|
||||
* @param string $queryType
|
||||
* @return $this
|
||||
*/
|
||||
public function useQueryType(string $queryType)
|
||||
{
|
||||
$this->queryToBuild->addParam('qt', $queryType);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the queryType (qt) from the query.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeQueryType()
|
||||
{
|
||||
$this->queryToBuild->addParam('qt', null);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to remove all sortings from the query.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeAllSortings()
|
||||
{
|
||||
$this->queryToBuild->clearSorts();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the passed sorting to the query.
|
||||
*
|
||||
* @param Sorting $sorting
|
||||
* @return $this
|
||||
*/
|
||||
public function useSorting(Sorting $sorting)
|
||||
{
|
||||
if (strpos($sorting->getFieldName(), 'relevance') !== false) {
|
||||
$this->removeAllSortings();
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->queryToBuild->addSort($sorting->getFieldName(), $sorting->getDirection());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the passed sorting to the query.
|
||||
*
|
||||
* @param Sortings $sortings
|
||||
* @return $this
|
||||
*/
|
||||
public function useSortings(Sortings $sortings)
|
||||
{
|
||||
foreach($sortings->getSortings() as $sorting) {
|
||||
$this->useSorting($sorting);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $resultsPerPage
|
||||
* @return $this
|
||||
*/
|
||||
public function useResultsPerPage($resultsPerPage)
|
||||
{
|
||||
$this->queryToBuild->setRows($resultsPerPage);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
* @return $this
|
||||
*/
|
||||
public function usePage($page)
|
||||
{
|
||||
$this->queryToBuild->setStart($page);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Operator $operator
|
||||
* @return $this
|
||||
*/
|
||||
public function useOperator(Operator $operator)
|
||||
{
|
||||
$this->queryToBuild->setQueryDefaultOperator( $operator->getOperator());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default query operator.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeOperator()
|
||||
{
|
||||
$this->queryToBuild->setQueryDefaultOperator('');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Slops $slops
|
||||
* @return $this
|
||||
*/
|
||||
public function useSlops(Slops $slops)
|
||||
{
|
||||
return $slops->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the passed boostQuer(y|ies) for the query.
|
||||
*
|
||||
* @param string|array $boostQueries
|
||||
* @return $this
|
||||
*/
|
||||
public function useBoostQueries($boostQueries)
|
||||
{
|
||||
$boostQueryArray = [];
|
||||
if(is_array($boostQueries)) {
|
||||
foreach($boostQueries as $boostQuery) {
|
||||
$boostQueryArray[] = ['key' => md5($boostQuery), 'query' => $boostQuery];
|
||||
}
|
||||
} else {
|
||||
$boostQueryArray[] = ['key' => md5($boostQueries), 'query' => $boostQueries];
|
||||
}
|
||||
|
||||
$this->queryToBuild->getEDisMax()->setBoostQueries($boostQueryArray);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all boost queries from the query.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeAllBoostQueries()
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->clearBoostQueries();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the passed boostFunction for the query.
|
||||
*
|
||||
* @param string $boostFunction
|
||||
* @return $this
|
||||
*/
|
||||
public function useBoostFunction(string $boostFunction)
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->setBoostFunctions($boostFunction);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all previously configured boost functions.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeAllBoostFunctions()
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->setBoostFunctions('');
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Uses the passed minimumMatch(mm) for the query.
|
||||
*
|
||||
* @param string $minimumMatch
|
||||
* @return $this
|
||||
*/
|
||||
public function useMinimumMatch(string $minimumMatch)
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->setMinimumMatch($minimumMatch);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any previous passed minimumMatch parameter.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeMinimumMatch()
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->setMinimumMatch('');
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applies the tie parameter to the query.
|
||||
*
|
||||
* @param mixed $tie
|
||||
* @return $this
|
||||
*/
|
||||
public function useTieParameter($tie)
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->setTie($tie);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies custom QueryFields to the query.
|
||||
*
|
||||
* @param QueryFields $queryFields
|
||||
* @return $this
|
||||
*/
|
||||
public function useQueryFields(QueryFields $queryFields)
|
||||
{
|
||||
return $queryFields->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies custom ReturnFields to the query.
|
||||
*
|
||||
* @param ReturnFields $returnFields
|
||||
* @return $this
|
||||
*/
|
||||
public function useReturnFields(ReturnFields $returnFields)
|
||||
{
|
||||
return $returnFields->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to use a specific filter string in the solr query.
|
||||
*
|
||||
* @param string $filterString
|
||||
* @param string $filterName
|
||||
* @return $this
|
||||
*/
|
||||
public function useFilter($filterString, $filterName = '')
|
||||
{
|
||||
$filterName = $filterName === '' ? $filterString : $filterName;
|
||||
|
||||
$nameWasPassedAndFilterIsAllreadySet = $filterName !== '' && $this->queryToBuild->getFilterQuery($filterName) !== null;
|
||||
if($nameWasPassedAndFilterIsAllreadySet) {
|
||||
return $this;
|
||||
}
|
||||
$this->queryToBuild->addFilterQuery(['key' => $filterName, 'query' => $filterString]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a filter by the fieldName.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @return $this
|
||||
*/
|
||||
public function removeFilterByFieldName($fieldName)
|
||||
{
|
||||
return $this->removeFilterByFunction(
|
||||
function($key, $query) use ($fieldName) {
|
||||
$queryString = $query->getQuery();
|
||||
$storedFieldName = substr($queryString,0, strpos($queryString, ":"));
|
||||
return $storedFieldName == $fieldName;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a filter by the name of the filter (also known as key).
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function removeFilterByName($name)
|
||||
{
|
||||
return $this->removeFilterByFunction(
|
||||
function($key, $query) use ($name) {
|
||||
$key = $query->getKey();
|
||||
return $key == $name;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a filter by the filter value.
|
||||
*
|
||||
* @param string $value
|
||||
* @return $this
|
||||
*/
|
||||
public function removeFilterByValue($value)
|
||||
{
|
||||
return $this->removeFilterByFunction(
|
||||
function($key, $query) use ($value) {
|
||||
$query = $query->getQuery();
|
||||
return $query == $value;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Closure $filterFunction
|
||||
* @return $this
|
||||
*/
|
||||
public function removeFilterByFunction($filterFunction)
|
||||
{
|
||||
$queries = $this->queryToBuild->getFilterQueries();
|
||||
foreach($queries as $key => $query) {
|
||||
$canBeRemoved = $filterFunction($key, $query);
|
||||
if($canBeRemoved) {
|
||||
unset($queries[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->queryToBuild->setFilterQueries($queries);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes the alternative query to the Query
|
||||
* @param string $query
|
||||
* @return $this
|
||||
*/
|
||||
public function useAlternativeQuery(string $query)
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->setQueryAlternative($query);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the alternative query from the Query.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeAlternativeQuery()
|
||||
{
|
||||
$this->queryToBuild->getEDisMax()->setQueryAlternative(null);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a custom Faceting configuration to the query.
|
||||
*
|
||||
* @param Faceting $faceting
|
||||
* @return $this
|
||||
*/
|
||||
public function useFaceting(Faceting $faceting)
|
||||
{
|
||||
return $faceting->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FieldCollapsing $fieldCollapsing
|
||||
* @return $this
|
||||
*/
|
||||
public function useFieldCollapsing(FieldCollapsing $fieldCollapsing)
|
||||
{
|
||||
return $fieldCollapsing->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a custom initialized grouping to the query.
|
||||
*
|
||||
* @param Grouping $grouping
|
||||
* @return $this
|
||||
*/
|
||||
public function useGrouping(Grouping $grouping)
|
||||
{
|
||||
return $grouping->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Highlighting $highlighting
|
||||
* @return $this
|
||||
*/
|
||||
public function useHighlighting(Highlighting $highlighting)
|
||||
{
|
||||
return $highlighting->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $debugMode
|
||||
* @return $this
|
||||
*/
|
||||
public function useDebug($debugMode)
|
||||
{
|
||||
if (!$debugMode) {
|
||||
$this->queryToBuild->addParam('debugQuery', null);
|
||||
$this->queryToBuild->addParam('echoParams', null);
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->queryToBuild->addParam('debugQuery', 'true');
|
||||
$this->queryToBuild->addParam('echoParams', 'all');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Elevation $elevation
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useElevation(Elevation $elevation)
|
||||
{
|
||||
return $elevation->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Spellchecking $spellchecking
|
||||
* @return $this
|
||||
*/
|
||||
public function useSpellchecking(Spellchecking $spellchecking)
|
||||
{
|
||||
return $spellchecking->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a custom configured PhraseFields to the query.
|
||||
*
|
||||
* @param PhraseFields $phraseFields
|
||||
* @return $this
|
||||
*/
|
||||
public function usePhraseFields(PhraseFields $phraseFields)
|
||||
{
|
||||
return $phraseFields->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a custom configured BigramPhraseFields to the query.
|
||||
*
|
||||
* @param BigramPhraseFields $bigramPhraseFields
|
||||
* @return $this
|
||||
*/
|
||||
public function useBigramPhraseFields(BigramPhraseFields $bigramPhraseFields)
|
||||
{
|
||||
return $bigramPhraseFields->build($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a custom configured TrigramPhraseFields to the query.
|
||||
*
|
||||
* @param TrigramPhraseFields $trigramPhraseFields
|
||||
* @return $this
|
||||
*/
|
||||
public function useTrigramPhraseFields(TrigramPhraseFields $trigramPhraseFields)
|
||||
{
|
||||
return $trigramPhraseFields->build($this);
|
||||
}
|
||||
}
|
47
Classes/Domain/Search/Query/ExtractingQuery.php
Normal file
47
Classes/Domain/Search/Query/ExtractingQuery.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2010-2015 Ingo Renner <ingo@typo3.org>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use Solarium\QueryType\Extract\Query as SolariumExtractQuery;
|
||||
|
||||
/**
|
||||
* Specialized query for content extraction using Solr Cell
|
||||
*
|
||||
*/
|
||||
class ExtractingQuery extends SolariumExtractQuery
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $file Absolute path to the file to extract content and meta data from.
|
||||
*/
|
||||
public function __construct($file)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->setFile($file);
|
||||
$this->addParam('extractFormat', 'text');
|
||||
}
|
||||
|
||||
}
|
147
Classes/Domain/Search/Query/Helper/EscapeService.php
Normal file
147
Classes/Domain/Search/Query/Helper/EscapeService.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\Helper;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 Timo Hund <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
/**
|
||||
* The EscpaeService is responsible to escape the querystring as expected for Apache Solr.
|
||||
*
|
||||
* This class should have no dependencies since it only contains static functions
|
||||
*
|
||||
* @author Timo Hund <timo.hund@dkd.de>
|
||||
*/
|
||||
class EscapeService {
|
||||
|
||||
/**
|
||||
* Quote and escape search strings
|
||||
*
|
||||
* @param string|int|double $string String to escape
|
||||
* @return string|int|double The escaped/quoted string
|
||||
*/
|
||||
public static function escape($string)
|
||||
{
|
||||
// when we have a numeric string only, nothing needs to be done
|
||||
if (is_numeric($string)) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
// when no whitespaces are in the query we can also just escape the special characters
|
||||
if (preg_match('/\W/', $string) != 1) {
|
||||
return static::escapeSpecialCharacters($string);
|
||||
}
|
||||
|
||||
// when there are no quotes inside the query string we can also just escape the whole string
|
||||
$hasQuotes = strrpos($string, '"') !== false;
|
||||
if (!$hasQuotes) {
|
||||
return static::escapeSpecialCharacters($string);
|
||||
}
|
||||
|
||||
$result = static::tokenizeByQuotesAndEscapeDependingOnContext($string);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies trim and htmlspecialchars on the querystring to use it as output.
|
||||
*
|
||||
* @param mixed $string
|
||||
* @return string
|
||||
*/
|
||||
public static function clean($string): string
|
||||
{
|
||||
$string = trim($string);
|
||||
$string = htmlspecialchars($string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to escape the content in the query string surrounded by quotes
|
||||
* different then when it is not in a quoted context.
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
protected static function tokenizeByQuotesAndEscapeDependingOnContext($string)
|
||||
{
|
||||
$result = '';
|
||||
$quotesCount = substr_count($string, '"');
|
||||
$isEvenAmountOfQuotes = $quotesCount % 2 === 0;
|
||||
|
||||
// go over all quote segments and apply escapePhrase inside a quoted
|
||||
// context and escapeSpecialCharacters outside the quoted context.
|
||||
$segments = explode('"', $string);
|
||||
$segmentsIndex = 0;
|
||||
foreach ($segments as $segment) {
|
||||
$isInQuote = $segmentsIndex % 2 !== 0;
|
||||
$isLastQuote = $segmentsIndex === $quotesCount;
|
||||
|
||||
if ($isLastQuote && !$isEvenAmountOfQuotes) {
|
||||
$result .= '\"';
|
||||
}
|
||||
|
||||
if ($isInQuote && !$isLastQuote) {
|
||||
$result .= static::escapePhrase($segment);
|
||||
} else {
|
||||
$result .= static::escapeSpecialCharacters($segment);
|
||||
}
|
||||
|
||||
$segmentsIndex++;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes a value meant to be contained in a phrase with characters with
|
||||
* special meanings in Lucene query syntax.
|
||||
*
|
||||
* @param string $value Unescaped - "dirty" - string
|
||||
* @return string Escaped - "clean" - string
|
||||
*/
|
||||
protected static function escapePhrase($value)
|
||||
{
|
||||
$pattern = '/("|\\\)/';
|
||||
$replace = '\\\$1';
|
||||
|
||||
return '"' . preg_replace($pattern, $replace, $value) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes characters with special meanings in Lucene query syntax.
|
||||
*
|
||||
* @param string $value Unescaped - "dirty" - string
|
||||
* @return string Escaped - "clean" - string
|
||||
*/
|
||||
protected static function escapeSpecialCharacters($value)
|
||||
{
|
||||
// list taken from http://lucene.apache.org/core/4_4_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description
|
||||
// which mentions: + - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
|
||||
// of which we escape: ( ) { } [ ] ^ " ~ : \ /
|
||||
// and explicitly don't escape: + - && || ! * ?
|
||||
$pattern = '/(\\(|\\)|\\{|\\}|\\[|\\]|\\^|"|~|\:|\\\\|\\/)/';
|
||||
$replace = '\\\$1';
|
||||
|
||||
return preg_replace($pattern, $replace, $value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
abstract class AbstractDeactivatable {
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isEnabled = false;
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsEnabled()
|
||||
{
|
||||
return $this->isEnabled;
|
||||
}
|
||||
/**
|
||||
* @param boolean $isEnabled
|
||||
*/
|
||||
public function setIsEnabled($isEnabled)
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
}
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2010-2017 dkd Internet Service GmbH <solr-support@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The AbstractFieldList class
|
||||
*/
|
||||
abstract class AbstractFieldList extends AbstractDeactivatable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldList = [];
|
||||
|
||||
/**
|
||||
* Parameter key which should be used for Apache Solr URL query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parameterKey = '';
|
||||
|
||||
/**
|
||||
* FieldList parameter builder constructor.
|
||||
*
|
||||
* @param array $fieldList
|
||||
*/
|
||||
public function __construct($isEnabled, array $fieldList = [])
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->fieldList = $fieldList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldListString
|
||||
* @param string $delimiter
|
||||
* @return array
|
||||
*/
|
||||
protected static function buildFieldList(string $fieldListString, string $delimiter):array
|
||||
{
|
||||
$fields = GeneralUtility::trimExplode($delimiter, $fieldListString, true);
|
||||
$fieldList = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$fieldNameAndBoost = explode('^', $field);
|
||||
|
||||
$boost = 1.0;
|
||||
if (isset($fieldNameAndBoost[1])) {
|
||||
$boost = floatval($fieldNameAndBoost[1]);
|
||||
}
|
||||
|
||||
$fieldName = $fieldNameAndBoost[0];
|
||||
$fieldList[$fieldName] = $boost;
|
||||
}
|
||||
return $fieldList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @param float $boost
|
||||
*
|
||||
* @return AbstractFieldList
|
||||
*/
|
||||
public function add(string $fieldName, float $boost = 1.0): AbstractFieldList
|
||||
{
|
||||
$this->fieldList[$fieldName] = (float)$boost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the string representation
|
||||
*
|
||||
* @param string $delimiter
|
||||
* @return string
|
||||
*/
|
||||
public function toString(string $delimiter = ' ')
|
||||
{
|
||||
$fieldListString = '';
|
||||
|
||||
foreach ($this->fieldList as $fieldName => $fieldBoost) {
|
||||
$fieldListString .= $fieldName;
|
||||
|
||||
if ($fieldBoost != 1.0) {
|
||||
$fieldListString .= '^' . number_format($fieldBoost, 1, '.', '');
|
||||
}
|
||||
|
||||
$fieldListString .= $delimiter;
|
||||
}
|
||||
|
||||
return rtrim($fieldListString, $delimiter);
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2010-2017 dkd Internet Service GmbH <solr-support@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The BigramPhraseFields class
|
||||
*/
|
||||
class BigramPhraseFields extends AbstractFieldList implements ParameterBuilder
|
||||
{
|
||||
/**
|
||||
* Parameter key which should be used for Apache Solr URL query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parameterKey = 'pf2';
|
||||
|
||||
/**
|
||||
* Parses the string representation of the fieldList (e.g. content^100, title^10) to the object representation.
|
||||
*
|
||||
* @param string $fieldListString
|
||||
* @param string $delimiter
|
||||
* @return BigramPhraseFields
|
||||
*/
|
||||
public static function fromString(string $fieldListString, string $delimiter = ',') : BigramPhraseFields
|
||||
{
|
||||
return self::initializeFromString($fieldListString, $delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return BigramPhraseFields
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getBigramPhraseSearchIsEnabled();
|
||||
if (!$isEnabled) {
|
||||
return new BigramPhraseFields(false);
|
||||
}
|
||||
|
||||
return self::fromString((string)$solrConfiguration->getSearchQueryBigramPhraseFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string representation of the fieldList (e.g. content^100, title^10) to the object representation.
|
||||
*
|
||||
* @param string $fieldListString
|
||||
* @param string $delimiter
|
||||
* @return BigramPhraseFields
|
||||
*/
|
||||
protected static function initializeFromString(string $fieldListString, string $delimiter = ',') : BigramPhraseFields
|
||||
{
|
||||
$fieldList = self::buildFieldList($fieldListString, $delimiter);
|
||||
return new BigramPhraseFields(true, $fieldList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$bigramPhraseFieldsString = $this->toString();
|
||||
if ($bigramPhraseFieldsString === '' || !$this->getIsEnabled()) {
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
$parentBuilder->getQuery()->getEDisMax()->setPhraseBigramFields($bigramPhraseFieldsString);
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
139
Classes/Domain/Search/Query/ParameterBuilder/Elevation.php
Normal file
139
Classes/Domain/Search/Query/ParameterBuilder/Elevation.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2018 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The Elevation ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the elevation.
|
||||
*/
|
||||
class Elevation extends AbstractDeactivatable implements ParameterBuilder
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isForced = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $markElevatedResults = true;
|
||||
|
||||
/**
|
||||
* Elevation constructor.
|
||||
* @param boolean $isEnabled
|
||||
* @param boolean $isForced
|
||||
* @param boolean $markElevatedResults
|
||||
*/
|
||||
public function __construct($isEnabled = false, $isForced = true, $markElevatedResults = true)
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->isForced = $isForced;
|
||||
$this->markElevatedResults = $markElevatedResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsForced(): bool
|
||||
{
|
||||
return $this->isForced;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $isForced
|
||||
*/
|
||||
public function setIsForced(bool $isForced)
|
||||
{
|
||||
$this->isForced = $isForced;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getMarkElevatedResults(): bool
|
||||
{
|
||||
return $this->markElevatedResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $markElevatedResults
|
||||
*/
|
||||
public function setMarkElevatedResults(bool $markElevatedResults)
|
||||
{
|
||||
$this->markElevatedResults = $markElevatedResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return Elevation
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getSearchElevation();
|
||||
if (!$isEnabled) {
|
||||
return new Elevation(false);
|
||||
}
|
||||
|
||||
$force = $solrConfiguration->getSearchElevationForceElevation();
|
||||
$markResults = $solrConfiguration->getSearchElevationMarkElevatedResults();
|
||||
return new Elevation(true, $force, $markResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Elevation
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Elevation(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$query = $parentBuilder->getQuery();
|
||||
if (!$this->getIsEnabled()) {
|
||||
$query->addParam('enableElevation', null);
|
||||
$query->addParam('forceElevation', null);
|
||||
$query->removeField('isElevated:[elevated]');
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
$query->addParam('enableElevation', 'true');
|
||||
$forceElevationString = $this->getIsForced() ? 'true' : 'false';
|
||||
$query->addParam('forceElevation', $forceElevationString);
|
||||
|
||||
if ($this->getMarkElevatedResults()) {
|
||||
$query->addField('isElevated:[elevated]');
|
||||
}
|
||||
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
282
Classes/Domain/Search/Query/ParameterBuilder/Faceting.php
Normal file
282
Classes/Domain/Search/Query/ParameterBuilder/Faceting.php
Normal file
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\QueryBuilder;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\ResultSet\Facets\SortingExpression;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The Faceting ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the highlighting.
|
||||
*/
|
||||
class Faceting extends AbstractDeactivatable implements ParameterBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $sorting = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $minCount = 1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $limit = 10;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fields = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalParameters = [];
|
||||
|
||||
/**
|
||||
* Faceting constructor.
|
||||
*
|
||||
* @param bool $isEnabled
|
||||
* @param string $sorting
|
||||
* @param int $minCount
|
||||
* @param int $limit
|
||||
* @param array $fields
|
||||
* @param array $additionalParameters
|
||||
*/
|
||||
public function __construct($isEnabled, $sorting = '', $minCount = 1, $limit = 10, $fields = [], $additionalParameters = [])
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->sorting = $sorting;
|
||||
$this->minCount = $minCount;
|
||||
$this->limit = $limit;
|
||||
$this->fields = $fields;
|
||||
$this->additionalParameters = $additionalParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSorting()
|
||||
{
|
||||
return $this->sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sorting
|
||||
*/
|
||||
public function setSorting($sorting)
|
||||
{
|
||||
$this->sorting = $sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMinCount()
|
||||
{
|
||||
return $this->minCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $minCount
|
||||
*/
|
||||
public function setMinCount($minCount)
|
||||
{
|
||||
$this->minCount = $minCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLimit()
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $limit
|
||||
*/
|
||||
public function setLimit($limit)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
*/
|
||||
public function setFields(array $fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
*/
|
||||
public function addField($fieldName)
|
||||
{
|
||||
$this->fields[] = $fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalParameters(): array
|
||||
{
|
||||
return $this->additionalParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $additionalParameters
|
||||
*/
|
||||
public function setAdditionalParameters(array $additionalParameters)
|
||||
{
|
||||
$this->additionalParameters = $additionalParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
*/
|
||||
public function addAdditionalParameter($key, $value)
|
||||
{
|
||||
$this->additionalParameters[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the facet sorting configuration and applies it to the queryParameters.
|
||||
*
|
||||
* @param array $facetParameters
|
||||
* @return array
|
||||
*/
|
||||
protected function applySorting(array $facetParameters)
|
||||
{
|
||||
$sortingExpression = new SortingExpression();
|
||||
$globalSortingExpression = $sortingExpression->getForFacet($this->sorting);
|
||||
|
||||
if (!empty($globalSortingExpression)) {
|
||||
$facetParameters['facet.sort'] = $globalSortingExpression;
|
||||
}
|
||||
|
||||
return $facetParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return Faceting
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getSearchFaceting();
|
||||
if (!$isEnabled) {
|
||||
return new Faceting(false);
|
||||
}
|
||||
|
||||
$minCount = $solrConfiguration->getSearchFacetingMinimumCount();
|
||||
$limit = $solrConfiguration->getSearchFacetingFacetLimit();
|
||||
$sorting = $solrConfiguration->getSearchFacetingSortBy();
|
||||
|
||||
return new Faceting($isEnabled, $sorting, $minCount, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Faceting
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Faceting(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all parameters that are required for faceting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFacetParameters() {
|
||||
$facetParameters = [];
|
||||
$facetParameters['facet'] = 'true';
|
||||
$facetParameters['facet.mincount'] = $this->getMinCount();
|
||||
$facetParameters['facet.limit'] = $this->getLimit();
|
||||
$facetParameters['facet.field'] = $this->getFields();
|
||||
|
||||
foreach ($this->getAdditionalParameters() as $additionalParameterKey => $additionalParameterValue) {
|
||||
$facetParameters[$additionalParameterKey] = $additionalParameterValue;
|
||||
}
|
||||
|
||||
if ($facetParameters['json.facet']) {
|
||||
$facetParameters['json.facet'] = json_encode($facetParameters['json.facet']);
|
||||
}
|
||||
|
||||
$facetParameters = $this->applySorting($facetParameters);
|
||||
return $facetParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$query = $parentBuilder->getQuery();
|
||||
if (!$this->getIsEnabled()) {
|
||||
//@todo use unset functionality when present
|
||||
$query->addParam('facet', null);
|
||||
$query->addParam('lex', null);
|
||||
$query->addParam('json.mincount', null);
|
||||
$query->addParam('json.limit', null);
|
||||
$query->addParam('json.field', null);
|
||||
$query->addParam('facet.sort', null);
|
||||
|
||||
$params = $query->getParams();
|
||||
foreach($params as $key => $value) {
|
||||
if (strpos($key, 'f.') !== false) {
|
||||
$query->addParam($key, null);
|
||||
}
|
||||
}
|
||||
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
//@todo check of $this->queryToBuilder->getFacetSet() can be used
|
||||
$facetingParameters = $this->getFacetParameters();
|
||||
foreach($facetingParameters as $key => $value) {
|
||||
$query->addParam($key, $value);
|
||||
}
|
||||
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
159
Classes/Domain/Search/Query/ParameterBuilder/FieldCollapsing.php
Normal file
159
Classes/Domain/Search/Query/ParameterBuilder/FieldCollapsing.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The FieldCollapsing ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the field collapsing.
|
||||
*/
|
||||
class FieldCollapsing extends AbstractDeactivatable implements ParameterBuilder
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $collapseFieldName = 'variantId';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $expand = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $expandRowCount = 10;
|
||||
|
||||
/**
|
||||
* FieldCollapsing constructor.
|
||||
* @param bool $isEnabled
|
||||
* @param string $collapseFieldName
|
||||
* @param bool $expand
|
||||
* @param int $expandRowCount
|
||||
*/
|
||||
public function __construct($isEnabled, $collapseFieldName = 'variantId', $expand = false, $expandRowCount = 10)
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->collapseFieldName = $collapseFieldName;
|
||||
$this->expand = $expand;
|
||||
$this->expandRowCount = $expandRowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCollapseFieldName(): string
|
||||
{
|
||||
return $this->collapseFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $collapseFieldName
|
||||
*/
|
||||
public function setCollapseFieldName(string $collapseFieldName)
|
||||
{
|
||||
$this->collapseFieldName = $collapseFieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIsExpand(): bool
|
||||
{
|
||||
return $this->expand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $expand
|
||||
*/
|
||||
public function setExpand(bool $expand)
|
||||
{
|
||||
$this->expand = $expand;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getExpandRowCount(): int
|
||||
{
|
||||
return $this->expandRowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $expandRowCount
|
||||
*/
|
||||
public function setExpandRowCount(int $expandRowCount)
|
||||
{
|
||||
$this->expandRowCount = $expandRowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return FieldCollapsing
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getSearchVariants();
|
||||
if (!$isEnabled) {
|
||||
return new FieldCollapsing(false);
|
||||
}
|
||||
|
||||
$collapseField = $solrConfiguration->getSearchVariantsField();
|
||||
$expand = (bool)$solrConfiguration->getSearchVariantsExpand();
|
||||
$expandRows = $solrConfiguration->getSearchVariantsLimit();
|
||||
|
||||
return new FieldCollapsing(true, $collapseField, $expand, $expandRows);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FieldCollapsing
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new FieldCollapsing(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$query = $parentBuilder->getQuery();
|
||||
if(!$this->getIsEnabled()) {
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
$parentBuilder->useFilter('{!collapse field=' . $this->getCollapseFieldName(). '}', 'fieldCollapsing');
|
||||
if($this->getIsExpand()) {
|
||||
$query->addParam('expand', 'true');
|
||||
$query->addParam('expand.rows', $this->getExpandRowCount());
|
||||
}
|
||||
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
158
Classes/Domain/Search/Query/ParameterBuilder/Filters.php
Normal file
158
Classes/Domain/Search/Query/ParameterBuilder/Filters.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The Filters ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the filtering.
|
||||
*/
|
||||
class Filters
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $filters = [];
|
||||
|
||||
/**
|
||||
* Removes a filter on a field
|
||||
*
|
||||
* @param string $filterFieldName The field name the filter should be removed for
|
||||
* @return void
|
||||
*/
|
||||
public function removeByFieldName($filterFieldName)
|
||||
{
|
||||
$this->removeByPrefix($filterFieldName . ':');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filterFieldName
|
||||
*/
|
||||
public function removeByPrefix($filterFieldName)
|
||||
{
|
||||
foreach ($this->filters as $key => $filterString) {
|
||||
if (GeneralUtility::isFirstPartOfStr($filterString, $filterFieldName)) {
|
||||
unset($this->filters[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a filter based on name of filter array
|
||||
*
|
||||
* @param string $name name of the filter
|
||||
*/
|
||||
public function removeByName($name)
|
||||
{
|
||||
unset($this->filters[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $filterString
|
||||
* @param string $name
|
||||
*/
|
||||
public function add($filterString, $name = '')
|
||||
{
|
||||
if ($name !== '') {
|
||||
$this->filters[$name] = $filterString;
|
||||
} else {
|
||||
$this->filters[] = $filterString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add's multiple filters to the filter collection.
|
||||
*
|
||||
* @param array $filterArray
|
||||
* @return Filters
|
||||
*/
|
||||
public function addMultiple($filterArray)
|
||||
{
|
||||
foreach($filterArray as $key => $value) {
|
||||
if (!$this->hasWithName($key)) {
|
||||
$this->add($value, $key);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasWithName($name)
|
||||
{
|
||||
return array_key_exists($name, $this->filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a filter by the filter value. The value has the following format:
|
||||
*
|
||||
* "fieldname:value"
|
||||
*
|
||||
* @param string $filterString The filter to remove, in the form of field:value
|
||||
*/
|
||||
public function removeByValue($filterString)
|
||||
{
|
||||
$key = array_search($filterString, $this->filters);
|
||||
if ($key === false) {
|
||||
// value not found, nothing to do
|
||||
return;
|
||||
}
|
||||
unset($this->filters[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all currently applied filters.
|
||||
*
|
||||
* @return array Array of filters
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return Filters
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
return new Filters();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Filters
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Filters();
|
||||
}
|
||||
}
|
254
Classes/Domain/Search/Query/ParameterBuilder/Grouping.php
Normal file
254
Classes/Domain/Search/Query/ParameterBuilder/Grouping.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The Grouping ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the grouping.
|
||||
*/
|
||||
class Grouping extends AbstractDeactivatable implements ParameterBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fields = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $sortings = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $queries = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $numberOfGroups = 5;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $resultsPerGroup = 1;
|
||||
|
||||
/**
|
||||
* Grouping constructor.
|
||||
*
|
||||
* @param bool $isEnabled
|
||||
* @param array $fields
|
||||
* @param array $sortings
|
||||
* @param array $queries
|
||||
* @param int $numberOfGroups
|
||||
* @param int $resultsPerGroup
|
||||
*/
|
||||
public function __construct($isEnabled, array $fields = [], array $sortings = [], array $queries = [], $numberOfGroups = 5, $resultsPerGroup = 1)
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->fields = $fields;
|
||||
$this->sortings = $sortings;
|
||||
$this->queries = $queries;
|
||||
$this->numberOfGroups = $numberOfGroups;
|
||||
$this->resultsPerGroup = $resultsPerGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fields
|
||||
*/
|
||||
public function setFields(array $fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*/
|
||||
public function addField(string $field)
|
||||
{
|
||||
$this->fields[] = $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSortings()
|
||||
{
|
||||
return $this->sortings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sorting
|
||||
*/
|
||||
public function addSorting($sorting)
|
||||
{
|
||||
$this->sortings[] = $sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $sortings
|
||||
*/
|
||||
public function setSortings(array $sortings)
|
||||
{
|
||||
$this->sortings = $sortings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getQueries(): array
|
||||
{
|
||||
return $this->queries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
*/
|
||||
public function addQuery($query)
|
||||
{
|
||||
$this->queries[] = $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $queries
|
||||
*/
|
||||
public function setQueries(array $queries)
|
||||
{
|
||||
$this->queries = $queries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getNumberOfGroups()
|
||||
{
|
||||
return $this->numberOfGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $numberOfGroups
|
||||
*/
|
||||
public function setNumberOfGroups($numberOfGroups)
|
||||
{
|
||||
$this->numberOfGroups = $numberOfGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getResultsPerGroup()
|
||||
{
|
||||
return $this->resultsPerGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $resultsPerGroup
|
||||
*/
|
||||
public function setResultsPerGroup($resultsPerGroup)
|
||||
{
|
||||
$resultsPerGroup = max(intval($resultsPerGroup), 0);
|
||||
$this->resultsPerGroup = $resultsPerGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return Grouping
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getSearchGrouping();
|
||||
if (!$isEnabled) {
|
||||
return new Grouping(false);
|
||||
}
|
||||
|
||||
$fields = [];
|
||||
$queries = [];
|
||||
$sortings = [];
|
||||
|
||||
$resultsPerGroup = $solrConfiguration->getSearchGroupingHighestGroupResultsLimit();
|
||||
$configuredGroups = $solrConfiguration->getSearchGroupingGroupsConfiguration();
|
||||
$numberOfGroups = $solrConfiguration->getSearchGroupingNumberOfGroups();
|
||||
$sortBy = $solrConfiguration->getSearchGroupingSortBy();
|
||||
|
||||
foreach ($configuredGroups as $groupName => $groupConfiguration) {
|
||||
if (isset($groupConfiguration['field'])) {
|
||||
$fields[] = $groupConfiguration['field'];
|
||||
} elseif (isset($groupConfiguration['query'])) {
|
||||
$queries[] = $groupConfiguration['query'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty(trim($sortBy))) {
|
||||
$sortings[] = $sortBy;
|
||||
}
|
||||
|
||||
return new Grouping($isEnabled, $fields, $sortings, $queries, $numberOfGroups, $resultsPerGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Grouping
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Grouping(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$query = $parentBuilder->getQuery();
|
||||
if(!$this->getIsEnabled()) {
|
||||
$query->removeComponent($query->getGrouping());
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
$query->getGrouping()->setFields($this->getFields());
|
||||
$query->getGrouping()->setLimit($this->getResultsPerGroup());
|
||||
$query->getGrouping()->setQueries($this->getQueries());
|
||||
$query->getGrouping()->setFormat('grouped');
|
||||
$query->getGrouping()->setNumberOfGroups(true);
|
||||
|
||||
$query->setRows($this->getNumberOfGroups());
|
||||
|
||||
$sorting = implode(' ', $this->getSortings());
|
||||
$query->getGrouping()->setSort($sorting);
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
211
Classes/Domain/Search/Query/ParameterBuilder/Highlighting.php
Normal file
211
Classes/Domain/Search/Query/ParameterBuilder/Highlighting.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\QueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The Highlighting ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the highlighting.
|
||||
*/
|
||||
class Highlighting extends AbstractDeactivatable implements ParameterBuilder
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $fragmentSize = 200;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $highlightingFieldList = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $postfix = '';
|
||||
|
||||
/**
|
||||
* Highlighting constructor.
|
||||
*
|
||||
* @param bool $isEnabled
|
||||
* @param int $fragmentSize
|
||||
* @param string $highlightingFieldList
|
||||
* @param string $prefix
|
||||
* @param string $postfix
|
||||
*/
|
||||
public function __construct($isEnabled = false, $fragmentSize = 200, $highlightingFieldList = '', $prefix = '', $postfix = '')
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->fragmentSize = $fragmentSize;
|
||||
$this->highlightingFieldList = $highlightingFieldList;
|
||||
$this->prefix = $prefix;
|
||||
$this->postfix = $postfix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getFragmentSize(): int
|
||||
{
|
||||
return $this->fragmentSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fragmentSize
|
||||
*/
|
||||
public function setFragmentSize(int $fragmentSize)
|
||||
{
|
||||
$this->fragmentSize = $fragmentSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHighlightingFieldList(): string
|
||||
{
|
||||
return $this->highlightingFieldList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $highlightingFieldList
|
||||
*/
|
||||
public function setHighlightingFieldList(string $highlightingFieldList)
|
||||
{
|
||||
$this->highlightingFieldList = $highlightingFieldList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPrefix(): string
|
||||
{
|
||||
return $this->prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
*/
|
||||
public function setPrefix(string $prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPostfix(): string
|
||||
{
|
||||
return $this->postfix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $postfix
|
||||
*/
|
||||
public function setPostfix(string $postfix)
|
||||
{
|
||||
$this->postfix = $postfix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getUseFastVectorHighlighter()
|
||||
{
|
||||
return ($this->fragmentSize >= 18);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return Highlighting
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getSearchResultsHighlighting();
|
||||
if (!$isEnabled) {
|
||||
return new Highlighting(false);
|
||||
}
|
||||
|
||||
$fragmentSize = $solrConfiguration->getSearchResultsHighlightingFragmentSize();
|
||||
$highlightingFields = $solrConfiguration->getSearchResultsHighlightingFields();
|
||||
$wrap = explode('|', $solrConfiguration->getSearchResultsHighlightingWrap());
|
||||
$prefix = isset($wrap[0]) ? $wrap[0] : '';
|
||||
$postfix = isset($wrap[1]) ? $wrap[1] : '';
|
||||
|
||||
|
||||
return new Highlighting($isEnabled, $fragmentSize, $highlightingFields, $prefix, $postfix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Highlighting
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Highlighting(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$query = $parentBuilder->getQuery();
|
||||
if(!$this->getIsEnabled()) {
|
||||
$query->removeComponent($query->getHighlighting());
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
$query->getHighlighting()->setFragSize($this->getFragmentSize());
|
||||
$query->getHighlighting()->setFields(GeneralUtility::trimExplode(",", $this->getHighlightingFieldList()));
|
||||
|
||||
if ($this->getUseFastVectorHighlighter()) {
|
||||
$query->getHighlighting()->setUseFastVectorHighlighter(true);
|
||||
$query->getHighlighting()->setTagPrefix($this->getPrefix());
|
||||
$query->getHighlighting()->setTagPostfix($this->getPostfix());
|
||||
} else {
|
||||
$query->getHighlighting()->setUseFastVectorHighlighter(false);
|
||||
$query->getHighlighting()->setTagPrefix('');
|
||||
$query->getHighlighting()->setTagPostfix('');
|
||||
}
|
||||
|
||||
if ($this->getPrefix() !== '' && $this->getPostfix() !== '') {
|
||||
$query->getHighlighting()->setSimplePrefix($this->getPrefix());
|
||||
$query->getHighlighting()->setSimplePostfix($this->getPostfix());
|
||||
}
|
||||
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
106
Classes/Domain/Search/Query/ParameterBuilder/Operator.php
Normal file
106
Classes/Domain/Search/Query/ParameterBuilder/Operator.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* The Operator ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the operator q.op.
|
||||
*/
|
||||
class Operator extends AbstractDeactivatable
|
||||
{
|
||||
const OPERATOR_AND = 'AND';
|
||||
const OPERATOR_OR = 'OR';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $operator = 'AND';
|
||||
|
||||
/**
|
||||
* Faceting constructor.
|
||||
*
|
||||
* @param bool $isEnabled
|
||||
* @param string $operator
|
||||
*/
|
||||
public function __construct($isEnabled, $operator = Operator::OPERATOR_AND)
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->setOperator($operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operator
|
||||
*/
|
||||
public function setOperator($operator)
|
||||
{
|
||||
if (!in_array($operator, [self::OPERATOR_AND, self::OPERATOR_OR])) {
|
||||
throw new \InvalidArgumentException("Invalid operator");
|
||||
}
|
||||
|
||||
$this->operator = $operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOperator(): string
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Operator
|
||||
*/
|
||||
public static function getEmpty(): Operator
|
||||
{
|
||||
return new Operator(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Operator
|
||||
*/
|
||||
public static function getAnd(): Operator
|
||||
{
|
||||
return new Operator(true, static::OPERATOR_AND);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Operator
|
||||
*/
|
||||
public static function getOr(): Operator
|
||||
{
|
||||
return new Operator(true, static::OPERATOR_OR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $operator
|
||||
* @return Operator
|
||||
*/
|
||||
public static function fromString($operator)
|
||||
{
|
||||
return new Operator(true, $operator);
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
|
||||
/**
|
||||
* The implementation of ParameterBuilder is responsible to build an array with
|
||||
* the query parameter that are needed for solr
|
||||
*
|
||||
* Interface ParameterProvider
|
||||
*/
|
||||
interface ParameterBuilder {
|
||||
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder;
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2010-2017 dkd Internet Service GmbH <solr-support@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The PhraseFields class
|
||||
*/
|
||||
class PhraseFields extends AbstractFieldList implements ParameterBuilder
|
||||
{
|
||||
/**
|
||||
* Parameter key which should be used for Apache Solr URL query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parameterKey = 'pf';
|
||||
|
||||
/**
|
||||
* Parses the string representation of the fieldList (e.g. content^100, title^10) to the object representation.
|
||||
*
|
||||
* @param string $fieldListString
|
||||
* @param string $delimiter
|
||||
* @return PhraseFields
|
||||
*/
|
||||
public static function fromString(string $fieldListString, string $delimiter = ',') : PhraseFields
|
||||
{
|
||||
return self::initializeFromString($fieldListString, $delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return PhraseFields
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getPhraseSearchIsEnabled();
|
||||
if (!$isEnabled) {
|
||||
return new PhraseFields(false);
|
||||
}
|
||||
|
||||
return self::fromString((string)$solrConfiguration->getSearchQueryPhraseFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string representation of the fieldList (e.g. content^100, title^10) to the object representation.
|
||||
*
|
||||
* @param string $fieldListString
|
||||
* @param string $delimiter
|
||||
* @return PhraseFields
|
||||
*/
|
||||
protected static function initializeFromString(string $fieldListString, string $delimiter = ',') : PhraseFields
|
||||
{
|
||||
$fieldList = self::buildFieldList($fieldListString, $delimiter);
|
||||
return new PhraseFields(true, $fieldList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$phraseFieldString = $this->toString();
|
||||
if ($phraseFieldString === '' || !$this->getIsEnabled()) {
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
$parentBuilder->getQuery()->getEDisMax()->setPhraseFields($phraseFieldString);
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
117
Classes/Domain/Search/Query/ParameterBuilder/QueryFields.php
Normal file
117
Classes/Domain/Search/Query/ParameterBuilder/QueryFields.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The QueryFields class holds all information for the query which fields should be used to query (Solr qf parameter).
|
||||
*/
|
||||
class QueryFields implements ParameterBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $queryFields = [];
|
||||
|
||||
/**
|
||||
* QueryFields constructor.
|
||||
*
|
||||
* @param array $queryFields
|
||||
*/
|
||||
public function __construct(array $queryFields = [])
|
||||
{
|
||||
$this->queryFields = $queryFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
* @param float $boost
|
||||
*/
|
||||
public function set($fieldName, $boost = 1.0)
|
||||
{
|
||||
$this->queryFields[$fieldName] = (float)$boost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the string representation
|
||||
*
|
||||
* @param string $delimiter
|
||||
* @return string
|
||||
*/
|
||||
public function toString($delimiter = ' ') {
|
||||
$queryFieldString = '';
|
||||
|
||||
foreach ($this->queryFields as $fieldName => $fieldBoost) {
|
||||
$queryFieldString .= $fieldName;
|
||||
|
||||
if ($fieldBoost != 1.0) {
|
||||
$queryFieldString .= '^' . number_format($fieldBoost, 1, '.', '');
|
||||
}
|
||||
|
||||
$queryFieldString .= $delimiter;
|
||||
}
|
||||
|
||||
return rtrim($queryFieldString, $delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string representation of the queryFields (e.g. content^100, title^10) to the object representation.
|
||||
*
|
||||
* @param string $queryFieldsString
|
||||
* @param string $delimiter
|
||||
* @return QueryFields
|
||||
*/
|
||||
public static function fromString($queryFieldsString, $delimiter = ',') {
|
||||
$fields = GeneralUtility::trimExplode($delimiter, $queryFieldsString, true);
|
||||
$queryFields = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$fieldNameAndBoost = explode('^', $field);
|
||||
|
||||
$boost = 1.0;
|
||||
if (isset($fieldNameAndBoost[1])) {
|
||||
$boost = floatval($fieldNameAndBoost[1]);
|
||||
}
|
||||
|
||||
$fieldName = $fieldNameAndBoost[0];
|
||||
$queryFields[$fieldName] = $boost;
|
||||
}
|
||||
|
||||
return new QueryFields($queryFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$parentBuilder->getQuery()->getEDisMax()->setQueryFields($this->toString());
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
128
Classes/Domain/Search/Query/ParameterBuilder/ReturnFields.php
Normal file
128
Classes/Domain/Search/Query/ParameterBuilder/ReturnFields.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The ReturnFields class is responsible to hold a list of field names that should be returned from
|
||||
* solr.
|
||||
*/
|
||||
class ReturnFields implements ParameterBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldList = [];
|
||||
|
||||
/**
|
||||
* FieldList constructor.
|
||||
*
|
||||
* @param array $fieldList
|
||||
*/
|
||||
public function __construct(array $fieldList = [])
|
||||
{
|
||||
$this->fieldList = $fieldList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a field to the list of fields to return. Also checks whether * is
|
||||
* set for the fields, if so it's removed from the field list.
|
||||
*
|
||||
* @param string $fieldName Name of a field to return in the result documents
|
||||
*/
|
||||
public function add($fieldName)
|
||||
{
|
||||
if (strpos($fieldName, '[') === false && strpos($fieldName, ']') === false && in_array('*', $this->fieldList)) {
|
||||
$this->fieldList = array_diff($this->fieldList, ['*']);
|
||||
}
|
||||
|
||||
$this->fieldList[] = $fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a field from the list of fields to return (fl parameter).
|
||||
*
|
||||
* @param string $fieldName Field to remove from the list of fields to return
|
||||
*/
|
||||
public function remove($fieldName)
|
||||
{
|
||||
$key = array_search($fieldName, $this->fieldList);
|
||||
|
||||
if ($key !== false) {
|
||||
unset($this->fieldList[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $delimiter
|
||||
* @return string
|
||||
*/
|
||||
public function toString($delimiter = ',')
|
||||
{
|
||||
return implode($delimiter, $this->fieldList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldList
|
||||
* @param string $delimiter
|
||||
* @return ReturnFields
|
||||
*/
|
||||
public static function fromString($fieldList, $delimiter = ',')
|
||||
{
|
||||
$fieldListArray = GeneralUtility::trimExplode($delimiter, $fieldList);
|
||||
return static::fromArray($fieldListArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $fieldListArray
|
||||
* @return ReturnFields
|
||||
*/
|
||||
public static function fromArray(array $fieldListArray)
|
||||
{
|
||||
return new ReturnFields($fieldListArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return array_unique(array_values($this->fieldList));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$parentBuilder->getQuery()->setFields($this->getValues());
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
257
Classes/Domain/Search/Query/ParameterBuilder/Slops.php
Normal file
257
Classes/Domain/Search/Query/ParameterBuilder/Slops.php
Normal file
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The Slops ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the several slop arguments.
|
||||
*/
|
||||
class Slops implements ParameterBuilder
|
||||
{
|
||||
const NO_SLOP = null;
|
||||
|
||||
/**
|
||||
* The qs parameter
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $querySlop = self::NO_SLOP;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $phraseSlop = self::NO_SLOP;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $bigramPhraseSlop = self::NO_SLOP;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $trigramPhraseSlop = self::NO_SLOP;
|
||||
|
||||
/**
|
||||
* Slops constructor.
|
||||
* @param int|null $querySlop
|
||||
* @param int|null $phraseSlop
|
||||
* @param int|null $bigramPhraseSlop
|
||||
* @param int|null $trigramPhraseSlop
|
||||
*/
|
||||
public function __construct($querySlop = self::NO_SLOP, $phraseSlop = self::NO_SLOP, $bigramPhraseSlop = self::NO_SLOP, $trigramPhraseSlop = self::NO_SLOP)
|
||||
{
|
||||
$this->querySlop = $querySlop;
|
||||
$this->phraseSlop = $phraseSlop;
|
||||
$this->bigramPhraseSlop = $bigramPhraseSlop;
|
||||
$this->trigramPhraseSlop = $trigramPhraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getHasQuerySlop()
|
||||
{
|
||||
return $this->querySlop !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getQuerySlop()
|
||||
{
|
||||
return $this->querySlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $querySlop
|
||||
*/
|
||||
public function setQuerySlop(int $querySlop)
|
||||
{
|
||||
$this->querySlop = $querySlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getHasPhraseSlop()
|
||||
{
|
||||
return $this->phraseSlop !== null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPhraseSlop()
|
||||
{
|
||||
return $this->phraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $phraseSlop
|
||||
*/
|
||||
public function setPhraseSlop(int $phraseSlop)
|
||||
{
|
||||
$this->phraseSlop = $phraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getHasBigramPhraseSlop()
|
||||
{
|
||||
return $this->bigramPhraseSlop !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getBigramPhraseSlop()
|
||||
{
|
||||
return $this->bigramPhraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $bigramPhraseSlop
|
||||
*/
|
||||
public function setBigramPhraseSlop(int $bigramPhraseSlop)
|
||||
{
|
||||
$this->bigramPhraseSlop = $bigramPhraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getHasTrigramPhraseSlop()
|
||||
{
|
||||
return $this->trigramPhraseSlop !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTrigramPhraseSlop()
|
||||
{
|
||||
return $this->trigramPhraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trigramPhraseSlop
|
||||
*/
|
||||
public function setTrigramPhraseSlop(int $trigramPhraseSlop)
|
||||
{
|
||||
$this->trigramPhraseSlop = $trigramPhraseSlop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return Slops
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$searchConfiguration = $solrConfiguration->getSearchConfiguration();
|
||||
$querySlop = static::getQuerySlopFromConfiguration($searchConfiguration);
|
||||
$phraseSlop = static::getPhraseSlopFromConfiguration($searchConfiguration);
|
||||
$bigramPhraseSlop = static::getBigramPhraseSlopFromConfiguration($searchConfiguration);
|
||||
$trigramPhraseSlop = static::getTrigramPhraseSlopFromConfiguration($searchConfiguration);
|
||||
return new Slops($querySlop, $phraseSlop, $bigramPhraseSlop, $trigramPhraseSlop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $searchConfiguration
|
||||
* @return int|null
|
||||
*/
|
||||
protected static function getPhraseSlopFromConfiguration($searchConfiguration)
|
||||
{
|
||||
$phraseEnabled = !(empty($searchConfiguration['query.']['phrase']) || $searchConfiguration['query.']['phrase'] !== 1);
|
||||
$phraseSlopConfigured = !empty($searchConfiguration['query.']['phrase.']['slop']);
|
||||
return ($phraseEnabled && $phraseSlopConfigured) ? $searchConfiguration['query.']['phrase.']['slop'] : self::NO_SLOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $searchConfiguration
|
||||
* @return int|null
|
||||
*/
|
||||
protected static function getQuerySlopFromConfiguration($searchConfiguration)
|
||||
{
|
||||
$phraseEnabled = !(empty($searchConfiguration['query.']['phrase']) || $searchConfiguration['query.']['phrase'] !== 1);
|
||||
$querySlopConfigured = !empty($searchConfiguration['query.']['phrase.']['querySlop']);
|
||||
return ($phraseEnabled && $querySlopConfigured) ? $searchConfiguration['query.']['phrase.']['querySlop'] : self::NO_SLOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $searchConfiguration
|
||||
* @return int|null
|
||||
*/
|
||||
protected static function getBigramPhraseSlopFromConfiguration($searchConfiguration)
|
||||
{
|
||||
$bigramPhraseEnabled = !empty($searchConfiguration['query.']['bigramPhrase']) && $searchConfiguration['query.']['bigramPhrase'] === 1;
|
||||
$bigramSlopConfigured = !empty($searchConfiguration['query.']['bigramPhrase.']['slop']);
|
||||
return ($bigramPhraseEnabled && $bigramSlopConfigured) ? $searchConfiguration['query.']['bigramPhrase.']['slop'] : self::NO_SLOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $searchConfiguration
|
||||
* @return int|null
|
||||
*/
|
||||
protected static function getTrigramPhraseSlopFromConfiguration($searchConfiguration)
|
||||
{
|
||||
$trigramPhraseEnabled = !empty($searchConfiguration['query.']['trigramPhrase']) && $searchConfiguration['query.']['trigramPhrase'] === 1;
|
||||
$trigramSlopConfigured = !empty($searchConfiguration['query.']['trigramPhrase.']['slop']);
|
||||
return ($trigramPhraseEnabled && $trigramSlopConfigured) ? $searchConfiguration['query.']['trigramPhrase.']['slop'] : self::NO_SLOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$query = $parentBuilder->getQuery();
|
||||
|
||||
if ($this->getHasPhraseSlop()) {
|
||||
$query->getEDisMax()->setPhraseSlop($this->getPhraseSlop());
|
||||
}
|
||||
|
||||
if ($this->getHasBigramPhraseSlop()) {
|
||||
$query->getEDisMax()->setPhraseBigramSlop($this->getBigramPhraseSlop());
|
||||
}
|
||||
|
||||
if ($this->getHasTrigramPhraseSlop()) {
|
||||
$query->getEDisMax()->setPhraseTrigramSlop($this->getTrigramPhraseSlop());
|
||||
}
|
||||
|
||||
if ($this->getHasQuerySlop()) {
|
||||
$query->getEDisMax()->setQueryPhraseSlop($this->getQuerySlop());
|
||||
}
|
||||
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
112
Classes/Domain/Search/Query/ParameterBuilder/Sorting.php
Normal file
112
Classes/Domain/Search/Query/ParameterBuilder/Sorting.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The Sorting ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the sorting.
|
||||
*/
|
||||
class Sorting extends AbstractDeactivatable
|
||||
{
|
||||
const SORT_ASC = 'ASC';
|
||||
const SORT_DESC = 'DESC';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $direction = self::SORT_ASC;
|
||||
|
||||
/**
|
||||
* Debug constructor.
|
||||
*
|
||||
* @param bool $isEnabled
|
||||
* @param string $fieldName
|
||||
* @param string $direction
|
||||
*/
|
||||
public function __construct($isEnabled = false, $fieldName = '', $direction = self::SORT_ASC)
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->setFieldName($fieldName);
|
||||
$this->setDirection($direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Sorting
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Sorting(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldName(): string
|
||||
{
|
||||
return $this->fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fieldName
|
||||
*/
|
||||
public function setFieldName(string $fieldName)
|
||||
{
|
||||
$this->fieldName = $fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDirection(): string
|
||||
{
|
||||
return $this->direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $direction
|
||||
*/
|
||||
public function setDirection(string $direction)
|
||||
{
|
||||
$this->direction = $direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a sorting representation "<fieldName> <direction>"
|
||||
* @param string $sortingString
|
||||
* @return Sorting
|
||||
*/
|
||||
public static function fromString($sortingString)
|
||||
{
|
||||
$parts = GeneralUtility::trimExplode(' ', $sortingString);
|
||||
return new Sorting(true, $parts[0], $parts[1]);
|
||||
}
|
||||
}
|
99
Classes/Domain/Search/Query/ParameterBuilder/Sortings.php
Normal file
99
Classes/Domain/Search/Query/ParameterBuilder/Sortings.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* The Sorting ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the sorting.
|
||||
*/
|
||||
class Sortings extends AbstractDeactivatable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $sortings = [];
|
||||
|
||||
/**
|
||||
* Sortings constructor.
|
||||
* @param bool $isEnabled
|
||||
* @param array $sortings
|
||||
*/
|
||||
public function __construct($isEnabled = false, $sortings = [])
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->setSortings($sortings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Sortings
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Sortings(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Sorting[]
|
||||
*/
|
||||
public function getSortings(): array
|
||||
{
|
||||
return $this->sortings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $sortings
|
||||
*/
|
||||
public function setSortings(array $sortings)
|
||||
{
|
||||
$this->sortings = $sortings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Sorting $sorting
|
||||
*/
|
||||
public function addSorting(Sorting $sorting)
|
||||
{
|
||||
$this->sortings[] = $sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a sortings representation "<fieldName> <direction>,<fieldName> <direction>"
|
||||
* @param string $sortingsString
|
||||
* @return Sortings
|
||||
*/
|
||||
public static function fromString($sortingsString)
|
||||
{
|
||||
$sortFields = GeneralUtility::trimExplode(',',$sortingsString);
|
||||
$sortings = [];
|
||||
foreach($sortFields as $sortField) {
|
||||
$sorting = Sorting::fromString($sortField);
|
||||
$sortings[] = $sorting;
|
||||
}
|
||||
|
||||
return new Sortings(true, $sortings);
|
||||
}
|
||||
}
|
102
Classes/Domain/Search/Query/ParameterBuilder/Spellchecking.php
Normal file
102
Classes/Domain/Search/Query/ParameterBuilder/Spellchecking.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The Spellchecking ParameterProvider is responsible to build the solr query parameters
|
||||
* that are needed for the spellchecking.
|
||||
*/
|
||||
class Spellchecking extends AbstractDeactivatable implements ParameterBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $maxCollationTries = 0;
|
||||
|
||||
/**
|
||||
* Spellchecking constructor.
|
||||
*
|
||||
* @param bool $isEnabled
|
||||
* @param int $maxCollationTries
|
||||
*/
|
||||
public function __construct($isEnabled = false, int $maxCollationTries = 0)
|
||||
{
|
||||
$this->isEnabled = $isEnabled;
|
||||
$this->maxCollationTries = $maxCollationTries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxCollationTries(): int
|
||||
{
|
||||
return $this->maxCollationTries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return Spellchecking
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getSearchSpellchecking();
|
||||
if (!$isEnabled) {
|
||||
return new Spellchecking(false);
|
||||
}
|
||||
|
||||
$maxCollationTries = $solrConfiguration->getSearchSpellcheckingNumberOfSuggestionsToTry();
|
||||
|
||||
return new Spellchecking($isEnabled, $maxCollationTries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Spellchecking
|
||||
*/
|
||||
public static function getEmpty()
|
||||
{
|
||||
return new Spellchecking(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$query = $parentBuilder->getQuery();
|
||||
if (!$this->getIsEnabled()) {
|
||||
$query->removeComponent($query->getSpellcheck());
|
||||
return $parentBuilder;
|
||||
}
|
||||
|
||||
$query->getSpellcheck()->setMaxCollationTries($this->getMaxCollationTries());
|
||||
$query->getSpellcheck()->setCollate(true);
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2010-2017 dkd Internet Service GmbH <solr-support@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\AbstractQueryBuilder;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The TrigramPhraseFields class
|
||||
*/
|
||||
class TrigramPhraseFields extends AbstractFieldList implements ParameterBuilder
|
||||
{
|
||||
/**
|
||||
* Parameter key which should be used for Apache Solr URL query
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parameterKey = 'pf3';
|
||||
|
||||
/**
|
||||
* Parses the string representation of the fieldList (e.g. content^100, title^10) to the object representation.
|
||||
*
|
||||
* @param string $fieldListString
|
||||
* @param string $delimiter
|
||||
* @return TrigramPhraseFields
|
||||
*/
|
||||
public static function fromString(string $fieldListString, string $delimiter = ',') : TrigramPhraseFields
|
||||
{
|
||||
return self::initializeFromString($fieldListString, $delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
* @return TrigramPhraseFields
|
||||
*/
|
||||
public static function fromTypoScriptConfiguration(TypoScriptConfiguration $solrConfiguration)
|
||||
{
|
||||
$isEnabled = $solrConfiguration->getTrigramPhraseSearchIsEnabled();
|
||||
if (!$isEnabled) {
|
||||
return new TrigramPhraseFields(false);
|
||||
}
|
||||
|
||||
return self::fromString((string)$solrConfiguration->getSearchQueryTrigramPhraseFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the string representation of the fieldList (e.g. content^100, title^10) to the object representation.
|
||||
*
|
||||
* @param string $fieldListString
|
||||
* @param string $delimiter
|
||||
* @return TrigramPhraseFields
|
||||
*/
|
||||
protected static function initializeFromString(string $fieldListString, string $delimiter = ',') : TrigramPhraseFields
|
||||
{
|
||||
$fieldList = self::buildFieldList($fieldListString, $delimiter);
|
||||
return new TrigramPhraseFields(true, $fieldList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractQueryBuilder $parentBuilder
|
||||
* @return AbstractQueryBuilder
|
||||
*/
|
||||
public function build(AbstractQueryBuilder $parentBuilder): AbstractQueryBuilder
|
||||
{
|
||||
$trigramPhraseFieldsString = $this->toString();
|
||||
if ($trigramPhraseFieldsString === '' || !$this->getIsEnabled()) {
|
||||
return $parentBuilder;
|
||||
}
|
||||
$parentBuilder->getQuery()->getEDisMax()->setPhraseTrigramFields($trigramPhraseFieldsString);
|
||||
return $parentBuilder;
|
||||
}
|
||||
}
|
47
Classes/Domain/Search/Query/Query.php
Normal file
47
Classes/Domain/Search/Query/Query.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2009-2015 Ingo Renner <ingo@typo3.org>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use Solarium\QueryType\Select\Query\Query as SolariumQuery;
|
||||
|
||||
class Query extends SolariumQuery {
|
||||
|
||||
/**
|
||||
* Returns the query parameters that should be used.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getQueryParameters() {
|
||||
return $this->getParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getQuery();
|
||||
}
|
||||
}
|
587
Classes/Domain/Search/Query/QueryBuilder.php
Normal file
587
Classes/Domain/Search/Query/QueryBuilder.php
Normal file
@@ -0,0 +1,587 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2017 <timo.hund@dkd.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\BigramPhraseFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Elevation;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Faceting;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\FieldCollapsing;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Filters;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Grouping;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Highlighting;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\PhraseFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\QueryFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\ReturnFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Slops;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Sorting;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Sortings;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\Spellchecking;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\TrigramPhraseFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Site\SiteHashService;
|
||||
use WapplerSystems\Meilisearch\Domain\Site\SiteRepository;
|
||||
use WapplerSystems\Meilisearch\FieldProcessor\PageUidToHierarchy;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
use WapplerSystems\Meilisearch\System\Logging\SolrLogManager;
|
||||
use WapplerSystems\Meilisearch\Util;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
|
||||
/**
|
||||
* The concrete QueryBuilder contains all TYPO3 specific initialization logic of solr queries, for TYPO3.
|
||||
*/
|
||||
class QueryBuilder extends AbstractQueryBuilder {
|
||||
|
||||
/**
|
||||
* Additional filters, which will be added to the query, as well as to
|
||||
* suggest queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalFilters = [];
|
||||
|
||||
/**
|
||||
* @var TypoScriptConfiguration
|
||||
*/
|
||||
protected $typoScriptConfiguration = null;
|
||||
|
||||
/**
|
||||
* @var SolrLogManager;
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* @var SiteHashService
|
||||
*/
|
||||
protected $siteHashService = null;
|
||||
|
||||
/**
|
||||
* QueryBuilder constructor.
|
||||
* @param TypoScriptConfiguration|null $configuration
|
||||
* @param SolrLogManager|null $solrLogManager
|
||||
* @param SiteHashService|null $siteHashService
|
||||
*/
|
||||
public function __construct(TypoScriptConfiguration $configuration = null, SolrLogManager $solrLogManager = null, SiteHashService $siteHashService = null)
|
||||
{
|
||||
$this->typoScriptConfiguration = $configuration ?? Util::getSolrConfiguration();
|
||||
$this->logger = $solrLogManager ?? GeneralUtility::makeInstance(SolrLogManager::class, /** @scrutinizer ignore-type */ __CLASS__);
|
||||
$this->siteHashService = $siteHashService ?? GeneralUtility::makeInstance(SiteHashService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $queryString
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function newSearchQuery($queryString): QueryBuilder
|
||||
{
|
||||
$this->queryToBuild = $this->getSearchQueryInstance((string)$queryString);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $queryString
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function newSuggestQuery($queryString): QueryBuilder
|
||||
{
|
||||
$this->queryToBuild = $this->getSuggestQueryInstance($queryString);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Query object and SearchComponents and returns
|
||||
* the initialized query object, when a search should be executed.
|
||||
*
|
||||
* @param string|null $rawQuery
|
||||
* @param int $resultsPerPage
|
||||
* @param array $additionalFiltersFromRequest
|
||||
* @return SearchQuery
|
||||
*/
|
||||
public function buildSearchQuery($rawQuery, $resultsPerPage = 10, array $additionalFiltersFromRequest = []) : SearchQuery
|
||||
{
|
||||
if ($this->typoScriptConfiguration->getLoggingQuerySearchWords()) {
|
||||
$this->logger->log(SolrLogManager::INFO, 'Received search query', [$rawQuery]);
|
||||
}
|
||||
|
||||
/* @var $query SearchQuery */
|
||||
return $this->newSearchQuery($rawQuery)
|
||||
->useResultsPerPage($resultsPerPage)
|
||||
->useReturnFieldsFromTypoScript()
|
||||
->useQueryFieldsFromTypoScript()
|
||||
->useInitialQueryFromTypoScript()
|
||||
->useFiltersFromTypoScript()
|
||||
->useFilterArray($additionalFiltersFromRequest)
|
||||
->useFacetingFromTypoScript()
|
||||
->useVariantsFromTypoScript()
|
||||
->useGroupingFromTypoScript()
|
||||
->useHighlightingFromTypoScript()
|
||||
->usePhraseFieldsFromTypoScript()
|
||||
->useBigramPhraseFieldsFromTypoScript()
|
||||
->useTrigramPhraseFieldsFromTypoScript()
|
||||
->useOmitHeader(false)
|
||||
->getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a SuggestQuery with all applied filters.
|
||||
*
|
||||
* @param string $queryString
|
||||
* @param array $additionalFilters
|
||||
* @param integer $requestedPageId
|
||||
* @param string $groupList
|
||||
* @return SuggestQuery
|
||||
*/
|
||||
public function buildSuggestQuery(string $queryString, array $additionalFilters, int $requestedPageId, string $groupList) : SuggestQuery
|
||||
{
|
||||
$this->newSuggestQuery($queryString)
|
||||
->useFiltersFromTypoScript()
|
||||
->useSiteHashFromTypoScript($requestedPageId)
|
||||
->useUserAccessGroups(explode(',', $groupList))
|
||||
->useOmitHeader();
|
||||
|
||||
|
||||
if (!empty($additionalFilters)) {
|
||||
$this->useFilterArray($additionalFilters);
|
||||
}
|
||||
|
||||
return $this->queryToBuild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Query for Search which finds document for given page.
|
||||
* Note: The Connection is per language as recommended in ext-solr docs.
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function buildPageQuery($pageId)
|
||||
{
|
||||
$siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
|
||||
$site = $siteRepository->getSiteByPageId($pageId);
|
||||
|
||||
return $this->newSearchQuery('')
|
||||
->useQueryString('*:*')
|
||||
->useFilter('(type:pages AND uid:' . $pageId . ') OR (*:* AND pid:' . $pageId . ' NOT type:pages)', 'type')
|
||||
->useFilter('siteHash:' . $site->getSiteHash(), 'siteHash')
|
||||
->useReturnFields(ReturnFields::fromString('*'))
|
||||
->useSortings(Sortings::fromString('type asc, title asc'))
|
||||
->useQueryType('standard')
|
||||
->getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a query for single record
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
public function buildRecordQuery($type, $uid, $pageId): Query
|
||||
{
|
||||
$siteRepository = GeneralUtility::makeInstance(SiteRepository::class);
|
||||
$site = $siteRepository->getSiteByPageId($pageId);
|
||||
|
||||
return $this->newSearchQuery('')
|
||||
->useQueryString('*:*')
|
||||
->useFilter('type:' . $type . ' AND uid:' . $uid, 'type')
|
||||
->useFilter('siteHash:' . $site->getSiteHash(), 'siteHash')
|
||||
->useReturnFields(ReturnFields::fromString('*'))
|
||||
->useSortings(Sortings::fromString('type asc, title asc'))
|
||||
->useQueryType('standard')
|
||||
->getQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useSlopsFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useSlops(Slops::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the configured boost queries from typoscript
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useBoostQueriesFromTypoScript(): QueryBuilder
|
||||
{
|
||||
$searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
|
||||
|
||||
if (!empty($searchConfiguration['query.']['boostQuery'])) {
|
||||
return $this->useBoostQueries($searchConfiguration['query.']['boostQuery']);
|
||||
}
|
||||
|
||||
if (!empty($searchConfiguration['query.']['boostQuery.'])) {
|
||||
$boostQueries = $searchConfiguration['query.']['boostQuery.'];
|
||||
return $this->useBoostQueries(array_values($boostQueries));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the configured boostFunction from the typoscript configuration.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useBoostFunctionFromTypoScript(): QueryBuilder
|
||||
{
|
||||
$searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
|
||||
if (!empty($searchConfiguration['query.']['boostFunction'])) {
|
||||
return $this->useBoostFunction($searchConfiguration['query.']['boostFunction']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the configured minimumMatch from the typoscript configuration.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useMinimumMatchFromTypoScript(): QueryBuilder
|
||||
{
|
||||
$searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
|
||||
if (!empty($searchConfiguration['query.']['minimumMatch'])) {
|
||||
return $this->useMinimumMatch($searchConfiguration['query.']['minimumMatch']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useTieParameterFromTypoScript(): QueryBuilder
|
||||
{
|
||||
$searchConfiguration = $this->typoScriptConfiguration->getSearchConfiguration();
|
||||
if (empty($searchConfiguration['query.']['tieParameter'])) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->useTieParameter($searchConfiguration['query.']['tieParameter']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured query fields from the typoscript configuration.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useQueryFieldsFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useQueryFields(QueryFields::fromString($this->typoScriptConfiguration->getSearchQueryQueryFields()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured return fields from the typoscript configuration.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useReturnFieldsFromTypoScript(): QueryBuilder
|
||||
{
|
||||
$returnFieldsArray = (array)$this->typoScriptConfiguration->getSearchQueryReturnFieldsAsArray(['*', 'score']);
|
||||
return $this->useReturnFields(ReturnFields::fromArray($returnFieldsArray));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Can be used to apply the allowed sites from plugin.tx_meilisearch.search.query.allowedSites to the query.
|
||||
*
|
||||
* @param int $requestedPageId
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useSiteHashFromTypoScript(int $requestedPageId): QueryBuilder
|
||||
{
|
||||
$queryConfiguration = $this->typoScriptConfiguration->getObjectByPathOrDefault('plugin.tx_meilisearch.search.query.', []);
|
||||
$allowedSites = $this->siteHashService->getAllowedSitesForPageIdAndAllowedSitesConfiguration($requestedPageId, $queryConfiguration['allowedSites']);
|
||||
return $this->useSiteHashFromAllowedSites($allowedSites);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to apply a list of allowed sites to the query.
|
||||
*
|
||||
* @param string $allowedSites
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useSiteHashFromAllowedSites($allowedSites): QueryBuilder
|
||||
{
|
||||
$isAnySiteAllowed = trim($allowedSites) === '*';
|
||||
if ($isAnySiteAllowed) {
|
||||
// no filter required
|
||||
return $this;
|
||||
}
|
||||
|
||||
$allowedSites = GeneralUtility::trimExplode(',', $allowedSites);
|
||||
$filters = [];
|
||||
foreach ($allowedSites as $site) {
|
||||
$siteHash = $this->siteHashService->getSiteHashForDomain($site);
|
||||
$filters[] = 'siteHash:"' . $siteHash . '"';
|
||||
}
|
||||
|
||||
$siteHashFilterString = implode(' OR ', $filters);
|
||||
return $this->useFilter($siteHashFilterString, 'siteHash');
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to filter the result on an applied list of user groups.
|
||||
*
|
||||
* @param array $groups
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useUserAccessGroups(array $groups): QueryBuilder
|
||||
{
|
||||
$groups = array_map('intval', $groups);
|
||||
$groups[] = 0; // always grant access to public documents
|
||||
$groups = array_unique($groups);
|
||||
sort($groups, SORT_NUMERIC);
|
||||
|
||||
$accessFilter = '{!typo3access}' . implode(',', $groups);
|
||||
$this->queryToBuild->removeFilterQuery('access');
|
||||
return $this->useFilter($accessFilter, 'access');
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured initial query settings to set the alternative query for solr as required.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useInitialQueryFromTypoScript(): QueryBuilder
|
||||
{
|
||||
if ($this->typoScriptConfiguration->getSearchInitializeWithEmptyQuery() || $this->typoScriptConfiguration->getSearchQueryAllowEmptyQuery()) {
|
||||
// empty main query, but using a "return everything"
|
||||
// alternative query in q.alt
|
||||
$this->useAlternativeQuery('*:*');
|
||||
}
|
||||
|
||||
if ($this->typoScriptConfiguration->getSearchInitializeWithQuery()) {
|
||||
$this->useAlternativeQuery($this->typoScriptConfiguration->getSearchInitializeWithQuery());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured facets from the typoscript configuration on the query.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useFacetingFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useFaceting(Faceting::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured variants from the typoscript configuration on the query.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useVariantsFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useFieldCollapsing(FieldCollapsing::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured groupings from the typoscript configuration to the query.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useGroupingFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useGrouping(Grouping::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured highlighting from the typoscript configuration to the query.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useHighlightingFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useHighlighting(Highlighting::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured filters (page section and other from typoscript).
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useFiltersFromTypoScript(): QueryBuilder
|
||||
{
|
||||
$filters = Filters::fromTypoScriptConfiguration($this->typoScriptConfiguration);
|
||||
$this->queryToBuild->setFilterQueries($filters->getValues());
|
||||
|
||||
$this->useFilterArray($this->getAdditionalFilters());
|
||||
|
||||
$searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
|
||||
|
||||
if (!is_array($searchQueryFilters) || count($searchQueryFilters) <= 0) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// special filter to limit search to specific page tree branches
|
||||
if (array_key_exists('__pageSections', $searchQueryFilters)) {
|
||||
$pageIds = GeneralUtility::trimExplode(',', $searchQueryFilters['__pageSections']);
|
||||
$this->usePageSectionsFromPageIds($pageIds);
|
||||
$this->typoScriptConfiguration->removeSearchQueryFilterForPageSections();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured elevation from the typoscript configuration.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useElevationFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useElevation(Elevation::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured spellchecking from the typoscript configuration.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useSpellcheckingFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useSpellchecking(Spellchecking::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the passed pageIds as __pageSection filter.
|
||||
*
|
||||
* @param array $pageIds
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function usePageSectionsFromPageIds(array $pageIds = []): QueryBuilder
|
||||
{
|
||||
$filters = [];
|
||||
|
||||
/** @var $processor PageUidToHierarchy */
|
||||
$processor = GeneralUtility::makeInstance(PageUidToHierarchy::class);
|
||||
$hierarchies = $processor->process($pageIds);
|
||||
|
||||
foreach ($hierarchies as $hierarchy) {
|
||||
$lastLevel = array_pop($hierarchy);
|
||||
$filters[] = 'rootline:"' . $lastLevel . '"';
|
||||
}
|
||||
|
||||
$pageSectionsFilterString = implode(' OR ', $filters);
|
||||
return $this->useFilter($pageSectionsFilterString, 'pageSections');
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured phrase fields from the typoscript configuration to the query.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function usePhraseFieldsFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->usePhraseFields(PhraseFields::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured bigram phrase fields from the typoscript configuration to the query.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useBigramPhraseFieldsFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useBigramPhraseFields(BigramPhraseFields::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the configured trigram phrase fields from the typoscript configuration to the query.
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function useTrigramPhraseFieldsFromTypoScript(): QueryBuilder
|
||||
{
|
||||
return $this->useTrigramPhraseFields(TrigramPhraseFields::fromTypoScriptConfiguration($this->typoScriptConfiguration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the configuration filters from the TypoScript configuration, except the __pageSections filter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalFilters() : array
|
||||
{
|
||||
// when we've build the additionalFilter once, we could return them
|
||||
if (count($this->additionalFilters) > 0) {
|
||||
return $this->additionalFilters;
|
||||
}
|
||||
|
||||
$searchQueryFilters = $this->typoScriptConfiguration->getSearchQueryFilterConfiguration();
|
||||
if (!is_array($searchQueryFilters) || count($searchQueryFilters) <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
|
||||
|
||||
// all other regular filters
|
||||
foreach ($searchQueryFilters as $filterKey => $filter) {
|
||||
// the __pageSections filter should not be handled as additional filter
|
||||
if ($filterKey === '__pageSections') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filterIsArray = is_array($searchQueryFilters[$filterKey]);
|
||||
if ($filterIsArray) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hasSubConfiguration = is_array($searchQueryFilters[$filterKey . '.']);
|
||||
if ($hasSubConfiguration) {
|
||||
$filter = $cObj->stdWrap($searchQueryFilters[$filterKey], $searchQueryFilters[$filterKey . '.']);
|
||||
}
|
||||
|
||||
$this->additionalFilters[$filterKey] = $filter;
|
||||
}
|
||||
|
||||
return $this->additionalFilters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $rawQuery
|
||||
* @return SearchQuery
|
||||
*/
|
||||
protected function getSearchQueryInstance(string $rawQuery): SearchQuery
|
||||
{
|
||||
$query = GeneralUtility::makeInstance(SearchQuery::class);
|
||||
$query->setQuery($rawQuery);
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $rawQuery
|
||||
* @return SuggestQuery
|
||||
*/
|
||||
protected function getSuggestQueryInstance($rawQuery): SuggestQuery
|
||||
{
|
||||
$query = GeneralUtility::makeInstance(SuggestQuery::class, /** @scrutinizer ignore-type */ $rawQuery, /** @scrutinizer ignore-type */ $this->typoScriptConfiguration);
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
27
Classes/Domain/Search/Query/SearchQuery.php
Normal file
27
Classes/Domain/Search/Query/SearchQuery.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2009-2015 Ingo Renner <ingo@typo3.org>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
class SearchQuery extends Query {}
|
86
Classes/Domain/Search/Query/SuggestQuery.php
Normal file
86
Classes/Domain/Search/Query/SuggestQuery.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
namespace WapplerSystems\Meilisearch\Domain\Search\Query;
|
||||
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2009-2015 Ingo Renner <ingo@typo3.org>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\ParameterBuilder\ReturnFields;
|
||||
use WapplerSystems\Meilisearch\Domain\Search\Query\Helper\EscapeService;
|
||||
use WapplerSystems\Meilisearch\System\Configuration\TypoScriptConfiguration;
|
||||
use WapplerSystems\Meilisearch\Util;
|
||||
|
||||
/**
|
||||
* A query specialized to get search suggestions
|
||||
*
|
||||
* @author Ingo Renner <ingo@typo3.org>
|
||||
*/
|
||||
class SuggestQuery extends Query
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $configuration;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix;
|
||||
|
||||
/**
|
||||
* SuggestQuery constructor.
|
||||
*
|
||||
* @param string $keywords
|
||||
* @param TypoScriptConfiguration $solrConfiguration
|
||||
*/
|
||||
public function __construct($keywords, $solrConfiguration = null)
|
||||
{
|
||||
parent::__construct();
|
||||
$keywords = (string)$keywords;
|
||||
|
||||
$solrConfiguration = $solrConfiguration ?? Util::getSolrConfiguration();
|
||||
|
||||
$this->setQuery($keywords);
|
||||
$this->configuration = $solrConfiguration->getObjectByPathOrDefault('plugin.tx_meilisearch.suggest.', []);
|
||||
|
||||
if (!empty($this->configuration['treatMultipleTermsAsSingleTerm'])) {
|
||||
$this->prefix = EscapeService::escape($keywords);
|
||||
} else {
|
||||
$matches = [];
|
||||
preg_match('/^(:?(.* |))([^ ]+)$/', $keywords, $matches);
|
||||
$fullKeywords = trim($matches[2]);
|
||||
$partialKeyword = trim($matches[3]);
|
||||
|
||||
$this->setQuery($fullKeywords);
|
||||
$this->prefix = EscapeService::escape($partialKeyword);
|
||||
}
|
||||
|
||||
$this->getEDisMax()->setQueryAlternative('*:*');
|
||||
$this->setFields(ReturnFields::fromString($this->configuration['suggestField'])->getValues());
|
||||
$this->addParam('facet', 'on');
|
||||
$this->addParam('facet.prefix', $this->prefix);
|
||||
$this->addParam('facet.field', $this->configuration['suggestField']);
|
||||
$this->addParam('facet.limit', $this->configuration['numberOfSuggestions']);
|
||||
$this->addParam('facet.mincount', 1);
|
||||
$this->addParam('facet.method', 'enum');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user