From 211ec6e3fa929ff6ae9fb859ed93dcb49e25c0f9 Mon Sep 17 00:00:00 2001 From: Florian BLOUET Date: Mon, 23 Nov 2015 16:09:11 +0100 Subject: [PATCH 1/3] PHRAS-821 - sort facet by predefined order - sort facet alphabetically --- www/skins/prod/jquery.main-prod.js | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/www/skins/prod/jquery.main-prod.js b/www/skins/prod/jquery.main-prod.js index 76daf20e0b..de3e7d8bf6 100644 --- a/www/skins/prod/jquery.main-prod.js +++ b/www/skins/prod/jquery.main-prod.js @@ -627,9 +627,48 @@ function loadFacets(facets) { }; }); + treeSource.sort(sortFacets('title', true, function(a){return a.toUpperCase()})); + + treeSource = sortByPredefinedFacets(treeSource, 'name', ['Base', 'Collection', 'Type']); + return getFacetsTree().reload(treeSource); } +function sortByPredefinedFacets(source, field, predefinedFieldOrder) { + var filteredSource = source, + ordered = []; + + _.forEach(predefinedFieldOrder, function(fieldValue, index){ + _.forEach(source, function(facet, facetIndex) { + if (facet[field] === fieldValue) { + ordered.push(facet); + // remove from filtered + filteredSource.splice(facetIndex, 1); + + } + }); + }); + // push reordoned objects on top of array: + // walk backward + var olen = ordered.length; + for(var i = olen-1; i>=0; i--) { + filteredSource.unshift(ordered[i]); + } + + return filteredSource; + +} +// from stackoverflow +// http://stackoverflow.com/questions/979256/sorting-an-array-of-javascript-objects/979325#979325 +function sortFacets(field, reverse, primer) { + var key = function (x) {return primer ? primer(x[field]) : x[field]}; + + return function (a,b) { + var A = key(a), B = key(b); + return ( (A < B) ? -1 : ((A > B) ? 1 : 0) ) * [-1,1][+!!reverse]; + } +} + function getFacetsTree() { var $facetsTree = $('#proposals'); if (!$facetsTree.data('ui-fancytree')) { From 663dbef92ef1d32912362ca4be51f2911e3fc072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Mon, 23 Nov 2015 16:09:56 +0100 Subject: [PATCH 2/3] Add Facet labels --- .../Controller/Prod/QueryController.php | 25 ++++++++++++++++++- .../Provider/SearchEngineServiceProvider.php | 4 +-- .../Elastic/ElasticSearchEngine.php | 6 ++--- .../Elastic/Search/FacetsResponse.php | 17 +++++++------ .../SearchEngine/SearchEngineResult.php | 3 ++- resources/locales/messages.en.xlf | 25 +++++++++++++++---- resources/locales/validators.en.xlf | 2 +- www/skins/prod/jquery.main-prod.js | 2 +- 8 files changed, 63 insertions(+), 21 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php index 1061c608c3..1a1d772ac1 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php @@ -184,7 +184,30 @@ class QueryController extends Controller $json['parsed_query'] = $result->getQuery(); /** End debug */ - $json['facets'] = $result->getFacets(); + $fieldLabels = [ + 'Base_Name' => $this->app->trans('prod::facet:base_label'), + 'Collection_Name' => $this->app->trans('prod::facet:collection_label'), + 'Type_Name' => $this->app->trans('prod::facet:doctype_label'), + ]; + foreach ($this->app->getDataboxes() as $databox) { + foreach ($databox->get_meta_structure() as $field) { + if (!isset($fieldLabels[$field->get_name()])) { + $fieldLabels[$field->get_name()] = $field->get_label($this->app['locale']); + } + } + } + + $facets = []; + + foreach ($result->getFacets() as $facet) { + $facetName = $facet['name']; + + $facet['label'] = isset($fieldLabels[$facetName]) ? $fieldLabels[$facetName] : $facetName; + + $facets[] = $facet; + } + + $json['facets'] = $facets; $json['phrasea_props'] = $proposals; $json['total_answers'] = (int) $result->getAvailable(); $json['next_page'] = ($page < $npages && $result->getAvailable() > 0) ? ($page + 1) : false; diff --git a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php index 25de9918e8..032c58187d 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php @@ -70,13 +70,13 @@ class SearchEngineServiceProvider implements ServiceProviderInterface ); }); - $app['search_engine.structure'] = $app->share(function ($app) { + $app['search_engine.structure'] = $app->share(function (\Alchemy\Phrasea\Application $app) { $databoxes = $app->getDataboxes(); return GlobalStructure::createFromDataboxes($databoxes); }); $app['elasticsearch.facets_response.factory'] = $app->protect(function (array $response) use ($app) { - return new FacetsResponse(new Escaper(), $response); + return new FacetsResponse(new Escaper(), $response, $app['search_engine.structure']); }); diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php index 3d08ea528a..f21152b9a3 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php @@ -422,17 +422,17 @@ class ElasticSearchEngine implements SearchEngineInterface // We always want a collection facet right now $collection_facet_agg = array(); $collection_facet_agg['terms']['field'] = 'collection_name'; - $aggs['Collection'] = $collection_facet_agg; + $aggs['Collection_Name'] = $collection_facet_agg; // We always want a base facet right now $base_facet_agg = array(); $base_facet_agg['terms']['field'] = 'databox_name'; - $aggs['Base'] = $base_facet_agg; + $aggs['Base_Name'] = $base_facet_agg; // We always want a type facet right now $base_facet_agg = array(); $base_facet_agg['terms']['field'] = 'type'; - $aggs['Type'] = $base_facet_agg; + $aggs['Type_Name'] = $base_facet_agg; $structure = $this->context_factory->getLimitedStructure($options); foreach ($structure->getFacetFields() as $name => $field) { diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php index 31d2f5cdb6..4adcc43415 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php @@ -3,11 +3,11 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search; use Alchemy\Phrasea\Exception\RuntimeException; +use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure; use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion; use Doctrine\Common\Collections\ArrayCollection; -use JsonSerializable; -class FacetsResponse implements JsonSerializable +class FacetsResponse { private $escaper; private $facets = array(); @@ -71,14 +71,14 @@ class FacetsResponse implements JsonSerializable private function buildQuery($name, $value) { switch($name) { - case 'Collection': + case 'Collection_Name': return sprintf('collection:%s', $this->escaper->escapeWord($value)); - case 'Base': + case 'Base_Name': return sprintf('database:%s', $this->escaper->escapeWord($value)); - case 'Type': + case 'Type_Name': return sprintf('type:%s', $this->escaper->escapeWord($value)); default: - return sprintf('%s = %s', + return sprintf('field.%s = %s', $this->escaper->escapeWord($name), $this->escaper->escapeWord($value)); } @@ -89,7 +89,10 @@ class FacetsResponse implements JsonSerializable throw new RuntimeException('Invalid aggregation response'); } - public function jsonSerialize() + /** + * @return array + */ + public function toArray() { return $this->facets; } diff --git a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineResult.php b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineResult.php index 5056f165cf..0a489375f5 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineResult.php +++ b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineResult.php @@ -27,6 +27,7 @@ class SearchEngineResult protected $suggestions; protected $propositions; protected $indexes; + /** @var FacetsResponse */ protected $facets; public function __construct(ArrayCollection $results, $query, $duration, $offsetStart, $available, $total, $error, @@ -182,6 +183,6 @@ class SearchEngineResult */ public function getFacets() { - return $this->facets; + return $this->facets->toArray(); } } diff --git a/resources/locales/messages.en.xlf b/resources/locales/messages.en.xlf index 6c4e411228..f753be1145 100644 --- a/resources/locales/messages.en.xlf +++ b/resources/locales/messages.en.xlf @@ -1,14 +1,14 @@ - + - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.
- - + + Form/Configuration/EmailFormType.php Form/Login/PhraseaAuthenticationForm.php @@ -136,7 +136,7 @@ selectionnes]]> - %number% documents<br/>selected + selected]]> Controller/Prod/QueryController.php @@ -10837,6 +10837,21 @@ Find prod/actions/edit_default.html.twig + + prod::facet:base_label + Base + Controller/Prod/QueryController.php + + + prod::facet:collection_label + Collection + Controller/Prod/QueryController.php + + + prod::facet:doctype_label + Document Type + Controller/Prod/QueryController.php + prod::recherche: Attention : la liste des bases selectionnees pour la recherche a ete changee. Warning, list of collections to search in has been changed diff --git a/resources/locales/validators.en.xlf b/resources/locales/validators.en.xlf index 38259502e9..3c33cceb70 100644 --- a/resources/locales/validators.en.xlf +++ b/resources/locales/validators.en.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/www/skins/prod/jquery.main-prod.js b/www/skins/prod/jquery.main-prod.js index de3e7d8bf6..782a5e5cbe 100644 --- a/www/skins/prod/jquery.main-prod.js +++ b/www/skins/prod/jquery.main-prod.js @@ -620,7 +620,7 @@ function loadFacets(facets) { }); // Facet return { - title: facet.name, + title: facet.label, folder: true, children: values, expanded: _.isUndefined(selectedFacetValues[facet.name]) From 33e6a228ba8454c7175d9dabd4227121c280851d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Mon, 23 Nov 2015 16:25:03 +0100 Subject: [PATCH 3/3] Fixup facet namings. PHRAS-821 PHRAS-823 --- www/skins/prod/jquery.main-prod.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/skins/prod/jquery.main-prod.js b/www/skins/prod/jquery.main-prod.js index 782a5e5cbe..48446d0ac9 100644 --- a/www/skins/prod/jquery.main-prod.js +++ b/www/skins/prod/jquery.main-prod.js @@ -620,6 +620,7 @@ function loadFacets(facets) { }); // Facet return { + name: facet.name, title: facet.label, folder: true, children: values, @@ -629,7 +630,7 @@ function loadFacets(facets) { treeSource.sort(sortFacets('title', true, function(a){return a.toUpperCase()})); - treeSource = sortByPredefinedFacets(treeSource, 'name', ['Base', 'Collection', 'Type']); + treeSource = sortByPredefinedFacets(treeSource, 'name', ['Base_Name', 'Collection_Name', 'Type_Name']); return getFacetsTree().reload(treeSource); }