From b1a03ae5666628921a9a27d29000f6a4865ebb5b Mon Sep 17 00:00:00 2001 From: Mathieu Darse Date: Thu, 19 Mar 2015 13:38:20 +0100 Subject: [PATCH] Smart facet value escaping --- .../Core/Provider/SearchEngineServiceProvider.php | 11 ++++++++++- .../SearchEngine/Elastic/ElasticSearchEngine.php | 10 ++++++---- .../SearchEngine/Elastic/Search/FacetsResponse.php | 13 +++++++------ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php index 58ff3eff48..2cf76ae22a 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php @@ -20,6 +20,8 @@ use Alchemy\Phrasea\SearchEngine\Elastic\IndexerSubscriber; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\RecordIndexer; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\TermIndexer; use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper; +use Alchemy\Phrasea\SearchEngine\Elastic\Search\Escaper; +use Alchemy\Phrasea\SearchEngine\Elastic\Search\FacetsResponse; use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryParser; use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus; use Alchemy\Phrasea\SearchEngine\Phrasea\PhraseaEngine; @@ -67,10 +69,17 @@ class SearchEngineServiceProvider implements ServiceProviderInterface return new ElasticSearchEngine( $app, $app['elasticsearch.client'], - $app['elasticsearch.options']['index'] + $app['elasticsearch.options']['index'], + $app['locales.available'], + $app['elasticsearch.record_helper'], + $app['elasticsearch.facets_response.factory'] ); }); + $app['elasticsearch.facets_response.factory'] = $app->protect(function (array $response) use ($app) { + return new FacetsResponse(new Excaper(), $response); + }); + /* Indexer related services */ diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php index f8bbc59620..d39cae1975 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\RecordIndexer; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\TermIndexer; +use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper; use Alchemy\Phrasea\SearchEngine\Elastic\Search\FacetsResponse; use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext; use Alchemy\Phrasea\SearchEngine\SearchEngineInterface; @@ -39,12 +40,13 @@ class ElasticSearchEngine implements SearchEngineInterface private $locales; private $recordHelper; - public function __construct(Application $app, Client $client, $indexName) + public function __construct(Application $app, Client $client, $indexName, array $locales, RecordHelper $recordHelper, Closure $facetsResponseFactory) { $this->app = $app; $this->client = $client; - $this->locales = array_keys($app['locales.available']); - $this->recordHelper = $this->app['elasticsearch.record_helper']; + $this->locales = array_keys($locales); + $this->recordHelper = $recordHelper; + $this->facetsResponseFactory = $facetsResponseFactory; if ('' === trim($indexName)) { throw new \InvalidArgumentException('The provided index name is invalid.'); @@ -292,7 +294,7 @@ class ElasticSearchEngine implements SearchEngineInterface $results[] = ElasticsearchRecordHydrator::hydrate($hit['_source'], $n++); } - $facets = new FacetsResponse($res); + $facets = $this->facetsResponseFactory->__invoke($res); $query['ast'] = $this->app['query_parser']->parse($string)->dump(); $query['query_main'] = $recordQuery; diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php index 52d0ccdcd6..c651aebff1 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php @@ -7,10 +7,13 @@ use JsonSerializable; class FacetsResponse implements JsonSerializable { + private $escaper; private $facets = array(); - public function __construct(array $response) + public function __construct(Escaper $escaper, array $response) { + $this->escaper = $escaper; + if (!isset($response['aggregations'])) { return; } @@ -47,12 +50,10 @@ class FacetsResponse implements JsonSerializable private function buildQuery($name, $value) { - // Strip double quotes from values to prevent broken queries - $value = str_replace('/"/u', ' ', $value); - // TODO escape value when escaping is supported in query parser + $value = $this->escaper->escapeWord($value); return ($name === 'Collection') ? - sprintf('collection:"%s"', $value) : - sprintf('"%s" IN %s', $value, $name); + sprintf('collection:%s', $value) : + sprintf('%s IN %s', $value, $name); } private function throwAggregationResponseError()