From e88202101999361e03c5f3bd564373d8a17ec226 Mon Sep 17 00:00:00 2001 From: aynsix Date: Thu, 24 Feb 2022 16:07:54 +0300 Subject: [PATCH 1/3] PHRAS-3642 api return subdefs --- .../Controller/Api/V3/V3Controller.php | 76 +++++++++++++++++++ .../Phrasea/ControllerProvider/Api/V3.php | 14 ++++ 2 files changed, 90 insertions(+) create mode 100644 lib/Alchemy/Phrasea/Controller/Api/V3/V3Controller.php diff --git a/lib/Alchemy/Phrasea/Controller/Api/V3/V3Controller.php b/lib/Alchemy/Phrasea/Controller/Api/V3/V3Controller.php new file mode 100644 index 0000000000..fe865f41c2 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Api/V3/V3Controller.php @@ -0,0 +1,76 @@ +attributes->get('databox_id'))) { + $ret = [ + 'databoxes' => $this->listSubdefsStructure([$this->findDataboxById($request->attributes->get('databox_id'))]) + ]; + } else { + $acl = $this->getAclForUser($this->getAuthenticatedUser()); + + // ensure can see databox structure + $ret = [ + 'databoxes' => $this->listSubdefsStructure($acl->get_granted_sbas([\ACL::BAS_MODIFY_STRUCT])) + ]; + } + + return Result::create($request, $ret)->createResponse(); + } + + /** + * List the subdef structure of databoxes + * @param array $databoxes + * @return array + * @throws \Exception + */ + private function listSubdefsStructure(array $databoxes) + { + $ret = []; + + /** @var \databox $databox */ + foreach ($databoxes as $databox) { + $databoxId = $databox->get_sbas_id(); + $subdefStructure = $databox->get_subdef_structure(); + $subdefs = []; + foreach ($subdefStructure as $subGroup) { + /** @var \databox_subdef $sub */ + foreach ($subGroup->getIterator() as $sub) { + $opt = []; + $data = [ + 'name' => $sub->get_name(), + 'databox_id' => $databoxId, + 'class' => $sub->get_class(), + 'preset' => $sub->get_preset(), + 'downloadable' => $sub->isDownloadable(), + 'devices' => $sub->getDevices(), + 'labels' => [ + 'fr' => $sub->get_label('fr'), + 'en' => $sub->get_label('en'), + 'de' => $sub->get_label('de'), + 'nl' => $sub->get_label('nl'), + ], + ]; + $options = $sub->getOptions(); + foreach ($options as $option) { + $opt[$option->getName()] = $option->getValue(); + } + $data['options'] = $opt; + $subdefs[$subGroup->getName()][$sub->get_name()] = $data; + } + } + $ret[$databoxId]['databox_id'] = $databoxId; + $ret[$databoxId]['subdefs'] = $subdefs; + } + + return $ret; + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Api/V3.php b/lib/Alchemy/Phrasea/ControllerProvider/Api/V3.php index 011000495d..e7797eaf92 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Api/V3.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Api/V3.php @@ -4,6 +4,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Api; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Api\V1Controller; +use Alchemy\Phrasea\Controller\Api\V3\V3Controller; use Alchemy\Phrasea\Controller\Api\V3\V3RecordController; use Alchemy\Phrasea\Controller\Api\V3\V3ResultHelpers; use Alchemy\Phrasea\Controller\Api\V3\V3SearchController; @@ -53,6 +54,9 @@ class V3 extends Api implements ControllerProviderInterface, ServiceProviderInte $app['controller.api.v3.stories'] = $app->share(function (PhraseaApplication $app) { return (new V3StoriesController($app)); }); + $app['controller.api.v3'] = $app->share(function (PhraseaApplication $app) { + return (new V3Controller($app)); + }); } public function boot(Application $app) @@ -150,6 +154,16 @@ class V3 extends Api implements ControllerProviderInterface, ServiceProviderInte $controllers->post('/subdefs_service/', 'controller.api.v3.subdefs_service:indexAction_POST'); } + /** + * @uses V3Controller::getDataboxSubdefsAction() + */ + $controllers->get('/databoxes/{databox_id}/subdefs/', 'controller.api.v3:getDataboxSubdefsAction') + ->before('controller.api.v1:ensureAccessToDatabox') + ->before('controller.api.v1:ensureCanSeeDataboxStructure') + ->assert('databox_id', '\d+'); + + $controllers->get('/databoxes/subdefs/', 'controller.api.v3:getDataboxSubdefsAction'); + return $controllers; } From 406a0ce9532205e6c6def06ef395020ac9fcd270 Mon Sep 17 00:00:00 2001 From: jygaulier Date: Fri, 25 Feb 2022 10:11:49 +0100 Subject: [PATCH 2/3] PHRAS-3602 : add ThumbnailOrientation facet ; add strings --- .../Phrasea/Controller/Api/V1Controller.php | 2 +- .../Controller/Prod/QueryController.php | 5 +- .../Provider/SearchEngineServiceProvider.php | 3 +- .../Elastic/ElasticSearchEngine.php | 16 +++- .../Elastic/ElasticsearchOptions.php | 56 ++++++++---- .../Elastic/ElasticsearchSettingsFormType.php | 2 +- .../Record/Hydrator/SubDefinitionHydrator.php | 86 +++++++++++++------ .../MetadataTagToFieldMappingConverter.php | 19 ++++ .../Elastic/Search/FacetsResponse.php | 16 +++- lib/classes/media/subdef.php | 2 + 10 files changed, 156 insertions(+), 51 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php index 9f1cae2919..1632fe1571 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php @@ -2813,7 +2813,7 @@ class V1Controller extends Controller { $ret = [ "meta_fields" => $this->listUserAuthorizedMetadataFields($this->getAuthenticatedUser()), - "aggregable_fields" => $this->buildUserFieldList(ElasticsearchOptions::getAggregableTechnicalFields(), ['choices']), + "aggregable_fields" => $this->buildUserFieldList(ElasticsearchOptions::getAggregableTechnicalFields($this->app['translator']), ['choices']), "technical_fields" => $this->buildUserFieldList(media_subdef::getTechnicalFieldsList()), ]; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php index 4ca7c3bf0f..d055206d18 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php @@ -76,7 +76,8 @@ class QueryController extends Controller $this->app['elasticsearch.client'], $query_context_factory, $this->app['elasticsearch.facets_response.factory'], - $this->app['elasticsearch.options'] + $this->app['elasticsearch.options'], + $this->app['translator'] ); $autocomplete = $engine->autocomplete($word, $options); @@ -351,7 +352,7 @@ class QueryController extends Controller // add technical fields $fieldsInfosByName = []; - foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) { + foreach(ElasticsearchOptions::getAggregableTechnicalFields($this->app['translator']) as $k => $f) { $fieldsInfosByName[$k] = $f; $fieldsInfosByName[$k]['trans_label'] = $this->app->trans( /** @ignore */ $f['label']); $fieldsInfosByName[$k]['labels'] = []; diff --git a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php index bab1a62f28..71159f028e 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php @@ -96,7 +96,8 @@ class SearchEngineServiceProvider implements ServiceProviderInterface $app['elasticsearch.client'], $app['query_context.factory'], $app['elasticsearch.facets_response.factory'], - $app['elasticsearch.options'] + $app['elasticsearch.options'], + $app['translator'] ); }); diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php index 43dc650c27..5eab435c70 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php @@ -33,6 +33,7 @@ use Closure; use databox_field; use Doctrine\Common\Collections\ArrayCollection; use Elasticsearch\Client; +use Symfony\Component\Translation\TranslatorInterface; class ElasticSearchEngine implements SearchEngineInterface { @@ -59,6 +60,8 @@ class ElasticSearchEngine implements SearchEngineInterface */ private $context_factory; + private $translator; + /** * @param Application $app * @param GlobalStructure $structure @@ -66,8 +69,9 @@ class ElasticSearchEngine implements SearchEngineInterface * @param QueryContextFactory $context_factory * @param Closure $facetsResponseFactory * @param ElasticsearchOptions $options + * @param TranslatorInterface $translator */ - public function __construct(Application $app, GlobalStructure $structure, Client $client, QueryContextFactory $context_factory, Closure $facetsResponseFactory, ElasticsearchOptions $options) + public function __construct(Application $app, GlobalStructure $structure, Client $client, QueryContextFactory $context_factory, Closure $facetsResponseFactory, ElasticsearchOptions $options, TranslatorInterface $translator) { $this->app = $app; $this->structure = $structure; @@ -75,6 +79,7 @@ class ElasticSearchEngine implements SearchEngineInterface $this->context_factory = $context_factory; $this->facetsResponseFactory = $facetsResponseFactory; $this->options = $options; + $this->translator = $translator; $this->indexName = $options->getIndexName(); } @@ -780,7 +785,7 @@ class ElasticSearchEngine implements SearchEngineInterface { $aggs = []; // technical aggregates (enable + optional limit) - foreach (ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) { + foreach (ElasticsearchOptions::getAggregableTechnicalFields($this->translator) as $k => $f) { $size = $this->options->getAggregableFieldLimit($k); if ($size !== databox_field::FACET_DISABLED) { if ($size === databox_field::FACET_NO_LIMIT) { @@ -793,6 +798,13 @@ class ElasticSearchEngine implements SearchEngineInterface ] ]; $aggs[$k] = $agg; + if($options->getIncludeUnsetFieldFacet() === true) { + $aggs[$k . '#empty'] = [ + 'missing' => [ + 'field' => $f['esfield'], + ] + ]; + } } } // fields aggregates diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php index 4f7de4c7af..581bd42982 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic; use databox_field; use igorw; +use Symfony\Component\Translation\TranslatorInterface; class ElasticsearchOptions @@ -312,7 +313,7 @@ class ElasticsearchOptions $this->_customValues = igorw\assoc_in($this->_customValues, $keys, $value); } - public static function getAggregableTechnicalFields() + public static function getAggregableTechnicalFields(TranslatorInterface $translator) { return [ '_base' => [ @@ -338,21 +339,21 @@ class ElasticsearchOptions ], '_camera_model' => [ 'type' => 'string', - 'label' => 'Camera Model', + 'label' => 'prod::facet:CameraModel_label', 'field' => "meta.CameraModel", 'esfield' => 'metadata_tags.CameraModel', - 'query' => 'meta.CameraModel:%s', + 'query' => 'meta.CameraModel=%s', ], '_iso' => [ 'type' => 'number', - 'label' => 'ISO', + 'label' => 'prod::facet:ISO_label', 'field' => "meta.ISO", 'esfield' => 'metadata_tags.ISO', 'query' => 'meta.ISO=%s', ], '_aperture' => [ 'type' => 'number', - 'label' => 'Aperture', + 'label' => 'prod::facet:Aperture_label', 'field' => "meta.Aperture", 'esfield' => 'metadata_tags.Aperture', 'query' => 'meta.Aperture=%s', @@ -362,7 +363,7 @@ class ElasticsearchOptions ], '_shutterspeed' => [ 'type' => 'number', - 'label' => 'Shutter speed', + 'label' => 'prod::facet:ShutterSpeed_label', 'field' => "meta.ShutterSpeed", 'esfield' => 'metadata_tags.ShutterSpeed', 'query' => 'meta.ShutterSpeed=%s', @@ -375,63 +376,86 @@ class ElasticsearchOptions ], '_flashfired' => [ 'type' => 'boolean', - 'label' => 'FlashFired', + 'label' => 'prod::facet:FlashFired_label', 'field' => "meta.FlashFired", 'esfield' => 'metadata_tags.FlashFired', 'query' => 'meta.FlashFired=%s', 'choices' => [ "aggregated (2 values: fired = 0 or 1)" => -1, ], - 'output_formatter' => function($value) { - static $map = ["false"=>"No flash", "true"=>"Flash", '0'=>"No flash", '1'=>"Flash"]; + 'output_formatter' => function($value) use($translator) { + $map = [ + "false" => $translator->trans("facet.flashfired:no"), + "true" => $translator->trans("facet.flashfired:yes"), + '0' => $translator->trans("facet.flashfired:no"), + '1' => $translator->trans("facet.flashfired:yes") + ]; return array_key_exists($value, $map) ? $map[$value] : $value; }, ], '_framerate' => [ 'type' => 'number', - 'label' => 'FrameRate', + 'label' => 'prod::facet:FrameRate_label', 'field' => "meta.FrameRate", 'esfield' => 'metadata_tags.FrameRate', 'query' => 'meta.FrameRate=%s', ], '_audiosamplerate' => [ 'type' => 'number', - 'label' => 'Audio Samplerate', + 'label' => 'prod::facet:AudioSamplerate_label', 'field' => "meta.AudioSamplerate", 'esfield' => 'metadata_tags.AudioSamplerate', 'query' => 'meta.AudioSamplerate=%s', ], '_videocodec' => [ 'type' => 'string', - 'label' => 'Video codec', + 'label' => 'prod::facet:VideoCodec_label', 'field' => "meta.VideoCodec", 'esfield' => 'metadata_tags.VideoCodec', 'query' => 'meta.VideoCodec:%s', ], '_audiocodec' => [ 'type' => 'string', - 'label' => 'Audio codec', + 'label' => 'prod::facet:AudioCodec_label', 'field' => "meta.AudioCodec", 'esfield' => 'metadata_tags.AudioCodec', 'query' => 'meta.AudioCodec:%s', ], '_orientation' => [ 'type' => 'string', - 'label' => 'Orientation', + 'label' => 'prod::facet.Orientation_label', 'field' => "meta.Orientation", 'esfield' => 'metadata_tags.Orientation', 'query' => 'meta.Orientation=%s', ], + '_thumbnail_orientation' => [ + 'type' => 'string', + 'label' => 'prod::facet.ThumbnailOrientation_label', + 'field' => "meta.ThumbnailOrientation", + 'esfield' => 'metadata_tags.ThumbnailOrientation', + 'query' => 'meta.ThumbnailOrientation=%s', + 'choices' => [ + "aggregated (4 values: '', 'S', 'L', 'P')" => -1, + ], + 'output_formatter' => function($value) use($translator) { + $map = [ + "L" => $translator->trans("facet.ThumbnailOrientation:Landscape"), + "P" => $translator->trans("facet.ThumbnailOrientation:Portrait"), + 'S' => $translator->trans("facet.ThumbnailOrientation:Square") + ]; + return array_key_exists($value, $map) ? $map[$value] : $value; + }, + ], '_colorspace' => [ 'type' => 'string', - 'label' => 'Colorspace', + 'label' => 'prod::facet:Colorspace_label', 'field' => "meta.ColorSpace", 'esfield' => 'metadata_tags.ColorSpace', 'query' => 'meta.ColorSpace:%s', ], '_mimetype' => [ 'type' => 'string', - 'label' => 'MimeType', + 'label' => 'prod::facet:MimeType_label', 'field' => "meta.MimeType", 'esfield' => 'metadata_tags.MimeType', 'query' => 'meta.MimeType:%s', diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php index 0b7a3ce9e6..3115055a34 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php @@ -137,7 +137,7 @@ class ElasticsearchSettingsFormType extends AbstractType } // add or replace hardcoded tech fields - foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) { + foreach(ElasticsearchOptions::getAggregableTechnicalFields($this->translator) as $k => $f) { $choices = array_key_exists('choices', $f) ? $f['choices'] : null; // a tech-field can publish it's own choices $help = null; $label = '#' . $k; diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php index a7da16e834..32a06e3781 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php @@ -18,7 +18,18 @@ use media_Permalink_Adapter; class SubDefinitionHydrator implements HydratorInterface { - /** @var Application */ + const ORIENTATION_SQUARE = 'S'; + const ORIENTATION_LANDSCAPE = 'L'; + const ORIENTATION_PORTRAIT = 'P'; + const ORIENTATION_UNKNOW = ''; + +// const ORIENTATION_SQUARE = 1; +// const ORIENTATION_LANDSCAPE = 2; +// const ORIENTATION_PORTRAIT = 3; +// const ORIENTATION_UNKNOW = 0; + + + /** @var Application */ private $app; /** @var databox */ @@ -38,45 +49,50 @@ class SubDefinitionHydrator implements HydratorInterface { if ($this->populatePermalinks) { $this->hydrateRecordsWithPermalinks($records); - } else { + } + else { $this->hydrateRecordsWithoutPermalinks($records); } } private function hydrateRecordsWithPermalinks(&$records) { - foreach(array_keys($records) as $rid) { + foreach (array_keys($records) as $rid) { + + $record = &$records[$rid]; + try { $subdefs = $this->databox->getRecordRepository()->find($rid)->get_subdefs(); $pls = array_map( /** media_Permalink_Adapter|null $plink */ - function($plink) { - return $plink ? ((string) $plink->get_url()) : null; + function ($plink) { + return $plink ? ((string)$plink->get_url()) : null; }, media_Permalink_Adapter::getMany($this->app, $subdefs, false) // false: don't create missing plinks ); - foreach($subdefs as $subdef) { + foreach ($subdefs as $subdef) { $name = $subdef->get_name(); - if(substr(($path = $subdef->get_path()), -1) !== '/') { + if (substr(($path = $subdef->get_path()), -1) !== '/') { $path .= '/'; } - $records[$rid]['subdefs'][$name] = array( - 'path' => $path . $subdef->get_file(), - 'width' => $subdef->get_width(), - 'height' => $subdef->get_height(), - 'size' => $subdef->get_size(), - 'mime' => $subdef->get_mime(), + $record['subdefs'][$name] = [ + 'path' => $path . $subdef->get_file(), + 'width' => $subdef->get_width(), + 'height' => $subdef->get_height(), + 'size' => $subdef->get_size(), + 'mime' => $subdef->get_mime(), 'permalink' => array_key_exists($name, $pls) ? $pls[$name] : null - ); - + ]; + if ($name == "thumbnail") { + $this->setOrientation($record, $subdef->get_width(), $subdef->get_height()); + } } } catch (\Exception $e) { // cant get record ? ignore } - } } @@ -96,22 +112,42 @@ class SubDefinitionHydrator implements HydratorInterface ORDER BY s.record_id SQL; $statement = $this->databox->get_connection()->executeQuery($sql, - array(array_keys($records)), - array(Connection::PARAM_INT_ARRAY) + [array_keys($records)], + [Connection::PARAM_INT_ARRAY] ); $current_rid = null; $record = null; while ($subdef = $statement->fetch()) { + $rid = $subdef['record_id']; + $record = &$records[$rid]; $name = $subdef['name']; - $records[$subdef['record_id']]['subdefs'][$name] = array( - 'path' => $subdef['path'], - 'width' => $subdef['width'], - 'height' => $subdef['height'], - 'size' => $subdef['size'], - 'mime' => $subdef['mime'], + $record['subdefs'][$name] = [ + 'path' => $subdef['path'], + 'width' => $subdef['width'], + 'height' => $subdef['height'], + 'size' => $subdef['size'], + 'mime' => $subdef['mime'], 'permalink' => null - ); + ]; + if ($name == "thumbnail") { + $this->setOrientation($record, $subdef['width'], $subdef['height']); + } } } + + private function setOrientation(&$record, $w, $h) + { + $o = self::ORIENTATION_UNKNOW; + if ($w !== '' && $h !== '' && !is_null($w) && !is_null($h)) { + $w = (int)$w; + $h = (int)$h; + $o = $w == $h ? self::ORIENTATION_SQUARE : ($w > $h ? self::ORIENTATION_LANDSCAPE : self::ORIENTATION_PORTRAIT); + } + if(!array_key_exists('metadata_tags', $record)) { + $record['metadata_tags'] = []; + } + $record['metadata_tags']['ThumbnailOrientation'] = $o; + } } + diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php index 07d186b4e3..ceb7a0a6d9 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php @@ -18,6 +18,25 @@ class MetadataTagToFieldMappingConverter { public function convertTag(Tag $tag) + { + if ($tag->getType() === FieldMapping::TYPE_STRING) { + + $fieldMapping = new StringFieldMapping($tag->getName()); + $fieldMapping->addChild((new StringFieldMapping('raw'))->enableRawIndexing()); + if ($tag->isAnalyzable()) { + $fieldMapping->enableAnalysis(); + } + else { + $fieldMapping->disableAnalysis(); + } + + return $fieldMapping; + } + + return new FieldMapping($tag->getName(), $tag->getType()); + } + + public function dead_convertTag(Tag $tag) { if ($tag->getType() === FieldMapping::TYPE_STRING) { $fieldMapping = new StringFieldMapping($tag->getName()); diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php index 4849ff4693..6f7d0b4655 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php @@ -24,7 +24,7 @@ class FacetsResponse return; } - $atf = ElasticsearchOptions::getAggregableTechnicalFields(); + $atf = ElasticsearchOptions::getAggregableTechnicalFields($this->translator); // sort facets respecting the order defined in options foreach($options->getAggregableFields() as $name=>$foptions) { @@ -35,9 +35,11 @@ class FacetsResponse $tf = null; $valueFormatter = function($v){ return $v; }; // default equality formatter + $label = $name; if(array_key_exists($name, $atf)) { $tf = $atf[$name]; + $label = $tf['label']; if(array_key_exists('output_formatter', $tf)) { $valueFormatter = $tf['output_formatter']; } @@ -56,7 +58,8 @@ class FacetsResponse if($response['aggregations'][$name . '#empty']['doc_count'] > 0) { // don't add a facet for 0 results $aggregation['buckets'][] = [ 'key' => '_unset_', - 'value' => $this->translator->trans('prod:workzone:facetstab:unset_field_facet_label_(%fieldname%)', ['%fieldname%' =>$name]), // special homemade prop to display a human value instead of the key + 'value' => $this->translator->trans('prod:workzone:facetstab:unset_field_facet_label_(%fieldname%)', ['%fieldname%' =>$label]), // special homemade prop to display a human value instead of the key + // 'value' => 'unset '.$name, // special homemade prop to display a human value instead of the key 'doc_count' => $response['aggregations'][$name . '#empty']['doc_count'] ]; } @@ -70,8 +73,15 @@ class FacetsResponse $key = array_key_exists('key_as_string', $bucket) ? $bucket['key_as_string'] : $bucket['key']; if($tf) { // the field is one of the hardcoded tech fields + if($key == '_unset_' && array_key_exists('value', $bucket)) { + // don't use the valueformatter since 'value' if already translated + $v = $bucket['value']; + } + else { + $v = $valueFormatter($key); + } $value = [ - 'value' => $valueFormatter($key), + 'value' => $v, 'raw_value' => $key, 'count' => $bucket['doc_count'], 'query' => sprintf($tf['query'], $this->escaper->escapeWord($key)) diff --git a/lib/classes/media/subdef.php b/lib/classes/media/subdef.php index 8893523fe0..544f838504 100644 --- a/lib/classes/media/subdef.php +++ b/lib/classes/media/subdef.php @@ -109,6 +109,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface const TC_DATA_COLORSPACE = 'ColorSpace'; const TC_DATA_CHANNELS = 'Channels'; const TC_DATA_ORIENTATION = 'Orientation'; + const TC_DATA_THUMBNAILORIENTATION = 'ThumbnailOrientation'; const TC_DATA_COLORDEPTH = 'ColorDepth'; const TC_DATA_DURATION = 'Duration'; const TC_DATA_AUDIOCODEC = 'AudioCodec'; @@ -864,6 +865,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface self::TC_DATA_VIDEOCODEC => ['method' => 'getVideoCodec', 'type' => 'string', 'analyzable' => false], self::TC_DATA_AUDIOCODEC => ['method' => 'getAudioCodec', 'type' => 'string', 'analyzable' => false], self::TC_DATA_ORIENTATION => ['method' => 'getOrientation', 'type' => 'integer', 'analyzable' => false], + self::TC_DATA_THUMBNAILORIENTATION => ['type' => 'string', 'analyzable' => false], self::TC_DATA_LONGITUDE => ['method' => 'getLongitude', 'type' => 'float', 'analyzable' => false], self::TC_DATA_LONGITUDE_REF => ['method' => 'getLongitudeRef'], self::TC_DATA_LATITUDE => ['method' => 'getLatitude', 'type' => 'float', 'analyzable' => false], From ccd460be27d50b647e3d97d32149168959f11108 Mon Sep 17 00:00:00 2001 From: Nicolas Maillat Date: Fri, 25 Feb 2022 23:10:23 +0100 Subject: [PATCH 3/3] Revert "PHRAS-3215 : add ThumbnailOrientation facet ; add strings" --- .../Phrasea/Controller/Api/V1Controller.php | 2 +- .../Controller/Prod/QueryController.php | 5 +- .../Provider/SearchEngineServiceProvider.php | 3 +- .../Elastic/ElasticSearchEngine.php | 16 +--- .../Elastic/ElasticsearchOptions.php | 56 ++++-------- .../Elastic/ElasticsearchSettingsFormType.php | 2 +- .../Record/Hydrator/SubDefinitionHydrator.php | 86 ++++++------------- .../MetadataTagToFieldMappingConverter.php | 19 ---- .../Elastic/Search/FacetsResponse.php | 16 +--- lib/classes/media/subdef.php | 2 - 10 files changed, 51 insertions(+), 156 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php index 1632fe1571..9f1cae2919 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php @@ -2813,7 +2813,7 @@ class V1Controller extends Controller { $ret = [ "meta_fields" => $this->listUserAuthorizedMetadataFields($this->getAuthenticatedUser()), - "aggregable_fields" => $this->buildUserFieldList(ElasticsearchOptions::getAggregableTechnicalFields($this->app['translator']), ['choices']), + "aggregable_fields" => $this->buildUserFieldList(ElasticsearchOptions::getAggregableTechnicalFields(), ['choices']), "technical_fields" => $this->buildUserFieldList(media_subdef::getTechnicalFieldsList()), ]; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php index d055206d18..4ca7c3bf0f 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php @@ -76,8 +76,7 @@ class QueryController extends Controller $this->app['elasticsearch.client'], $query_context_factory, $this->app['elasticsearch.facets_response.factory'], - $this->app['elasticsearch.options'], - $this->app['translator'] + $this->app['elasticsearch.options'] ); $autocomplete = $engine->autocomplete($word, $options); @@ -352,7 +351,7 @@ class QueryController extends Controller // add technical fields $fieldsInfosByName = []; - foreach(ElasticsearchOptions::getAggregableTechnicalFields($this->app['translator']) as $k => $f) { + foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) { $fieldsInfosByName[$k] = $f; $fieldsInfosByName[$k]['trans_label'] = $this->app->trans( /** @ignore */ $f['label']); $fieldsInfosByName[$k]['labels'] = []; diff --git a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php index 71159f028e..bab1a62f28 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php @@ -96,8 +96,7 @@ class SearchEngineServiceProvider implements ServiceProviderInterface $app['elasticsearch.client'], $app['query_context.factory'], $app['elasticsearch.facets_response.factory'], - $app['elasticsearch.options'], - $app['translator'] + $app['elasticsearch.options'] ); }); diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php index 5eab435c70..43dc650c27 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php @@ -33,7 +33,6 @@ use Closure; use databox_field; use Doctrine\Common\Collections\ArrayCollection; use Elasticsearch\Client; -use Symfony\Component\Translation\TranslatorInterface; class ElasticSearchEngine implements SearchEngineInterface { @@ -60,8 +59,6 @@ class ElasticSearchEngine implements SearchEngineInterface */ private $context_factory; - private $translator; - /** * @param Application $app * @param GlobalStructure $structure @@ -69,9 +66,8 @@ class ElasticSearchEngine implements SearchEngineInterface * @param QueryContextFactory $context_factory * @param Closure $facetsResponseFactory * @param ElasticsearchOptions $options - * @param TranslatorInterface $translator */ - public function __construct(Application $app, GlobalStructure $structure, Client $client, QueryContextFactory $context_factory, Closure $facetsResponseFactory, ElasticsearchOptions $options, TranslatorInterface $translator) + public function __construct(Application $app, GlobalStructure $structure, Client $client, QueryContextFactory $context_factory, Closure $facetsResponseFactory, ElasticsearchOptions $options) { $this->app = $app; $this->structure = $structure; @@ -79,7 +75,6 @@ class ElasticSearchEngine implements SearchEngineInterface $this->context_factory = $context_factory; $this->facetsResponseFactory = $facetsResponseFactory; $this->options = $options; - $this->translator = $translator; $this->indexName = $options->getIndexName(); } @@ -785,7 +780,7 @@ class ElasticSearchEngine implements SearchEngineInterface { $aggs = []; // technical aggregates (enable + optional limit) - foreach (ElasticsearchOptions::getAggregableTechnicalFields($this->translator) as $k => $f) { + foreach (ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) { $size = $this->options->getAggregableFieldLimit($k); if ($size !== databox_field::FACET_DISABLED) { if ($size === databox_field::FACET_NO_LIMIT) { @@ -798,13 +793,6 @@ class ElasticSearchEngine implements SearchEngineInterface ] ]; $aggs[$k] = $agg; - if($options->getIncludeUnsetFieldFacet() === true) { - $aggs[$k . '#empty'] = [ - 'missing' => [ - 'field' => $f['esfield'], - ] - ]; - } } } // fields aggregates diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php index 581bd42982..4f7de4c7af 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchOptions.php @@ -11,7 +11,6 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic; use databox_field; use igorw; -use Symfony\Component\Translation\TranslatorInterface; class ElasticsearchOptions @@ -313,7 +312,7 @@ class ElasticsearchOptions $this->_customValues = igorw\assoc_in($this->_customValues, $keys, $value); } - public static function getAggregableTechnicalFields(TranslatorInterface $translator) + public static function getAggregableTechnicalFields() { return [ '_base' => [ @@ -339,21 +338,21 @@ class ElasticsearchOptions ], '_camera_model' => [ 'type' => 'string', - 'label' => 'prod::facet:CameraModel_label', + 'label' => 'Camera Model', 'field' => "meta.CameraModel", 'esfield' => 'metadata_tags.CameraModel', - 'query' => 'meta.CameraModel=%s', + 'query' => 'meta.CameraModel:%s', ], '_iso' => [ 'type' => 'number', - 'label' => 'prod::facet:ISO_label', + 'label' => 'ISO', 'field' => "meta.ISO", 'esfield' => 'metadata_tags.ISO', 'query' => 'meta.ISO=%s', ], '_aperture' => [ 'type' => 'number', - 'label' => 'prod::facet:Aperture_label', + 'label' => 'Aperture', 'field' => "meta.Aperture", 'esfield' => 'metadata_tags.Aperture', 'query' => 'meta.Aperture=%s', @@ -363,7 +362,7 @@ class ElasticsearchOptions ], '_shutterspeed' => [ 'type' => 'number', - 'label' => 'prod::facet:ShutterSpeed_label', + 'label' => 'Shutter speed', 'field' => "meta.ShutterSpeed", 'esfield' => 'metadata_tags.ShutterSpeed', 'query' => 'meta.ShutterSpeed=%s', @@ -376,86 +375,63 @@ class ElasticsearchOptions ], '_flashfired' => [ 'type' => 'boolean', - 'label' => 'prod::facet:FlashFired_label', + 'label' => 'FlashFired', 'field' => "meta.FlashFired", 'esfield' => 'metadata_tags.FlashFired', 'query' => 'meta.FlashFired=%s', 'choices' => [ "aggregated (2 values: fired = 0 or 1)" => -1, ], - 'output_formatter' => function($value) use($translator) { - $map = [ - "false" => $translator->trans("facet.flashfired:no"), - "true" => $translator->trans("facet.flashfired:yes"), - '0' => $translator->trans("facet.flashfired:no"), - '1' => $translator->trans("facet.flashfired:yes") - ]; + 'output_formatter' => function($value) { + static $map = ["false"=>"No flash", "true"=>"Flash", '0'=>"No flash", '1'=>"Flash"]; return array_key_exists($value, $map) ? $map[$value] : $value; }, ], '_framerate' => [ 'type' => 'number', - 'label' => 'prod::facet:FrameRate_label', + 'label' => 'FrameRate', 'field' => "meta.FrameRate", 'esfield' => 'metadata_tags.FrameRate', 'query' => 'meta.FrameRate=%s', ], '_audiosamplerate' => [ 'type' => 'number', - 'label' => 'prod::facet:AudioSamplerate_label', + 'label' => 'Audio Samplerate', 'field' => "meta.AudioSamplerate", 'esfield' => 'metadata_tags.AudioSamplerate', 'query' => 'meta.AudioSamplerate=%s', ], '_videocodec' => [ 'type' => 'string', - 'label' => 'prod::facet:VideoCodec_label', + 'label' => 'Video codec', 'field' => "meta.VideoCodec", 'esfield' => 'metadata_tags.VideoCodec', 'query' => 'meta.VideoCodec:%s', ], '_audiocodec' => [ 'type' => 'string', - 'label' => 'prod::facet:AudioCodec_label', + 'label' => 'Audio codec', 'field' => "meta.AudioCodec", 'esfield' => 'metadata_tags.AudioCodec', 'query' => 'meta.AudioCodec:%s', ], '_orientation' => [ 'type' => 'string', - 'label' => 'prod::facet.Orientation_label', + 'label' => 'Orientation', 'field' => "meta.Orientation", 'esfield' => 'metadata_tags.Orientation', 'query' => 'meta.Orientation=%s', ], - '_thumbnail_orientation' => [ - 'type' => 'string', - 'label' => 'prod::facet.ThumbnailOrientation_label', - 'field' => "meta.ThumbnailOrientation", - 'esfield' => 'metadata_tags.ThumbnailOrientation', - 'query' => 'meta.ThumbnailOrientation=%s', - 'choices' => [ - "aggregated (4 values: '', 'S', 'L', 'P')" => -1, - ], - 'output_formatter' => function($value) use($translator) { - $map = [ - "L" => $translator->trans("facet.ThumbnailOrientation:Landscape"), - "P" => $translator->trans("facet.ThumbnailOrientation:Portrait"), - 'S' => $translator->trans("facet.ThumbnailOrientation:Square") - ]; - return array_key_exists($value, $map) ? $map[$value] : $value; - }, - ], '_colorspace' => [ 'type' => 'string', - 'label' => 'prod::facet:Colorspace_label', + 'label' => 'Colorspace', 'field' => "meta.ColorSpace", 'esfield' => 'metadata_tags.ColorSpace', 'query' => 'meta.ColorSpace:%s', ], '_mimetype' => [ 'type' => 'string', - 'label' => 'prod::facet:MimeType_label', + 'label' => 'MimeType', 'field' => "meta.MimeType", 'esfield' => 'metadata_tags.MimeType', 'query' => 'meta.MimeType:%s', diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php index 3115055a34..0b7a3ce9e6 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticsearchSettingsFormType.php @@ -137,7 +137,7 @@ class ElasticsearchSettingsFormType extends AbstractType } // add or replace hardcoded tech fields - foreach(ElasticsearchOptions::getAggregableTechnicalFields($this->translator) as $k => $f) { + foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) { $choices = array_key_exists('choices', $f) ? $f['choices'] : null; // a tech-field can publish it's own choices $help = null; $label = '#' . $k; diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php index 32a06e3781..a7da16e834 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/SubDefinitionHydrator.php @@ -18,18 +18,7 @@ use media_Permalink_Adapter; class SubDefinitionHydrator implements HydratorInterface { - const ORIENTATION_SQUARE = 'S'; - const ORIENTATION_LANDSCAPE = 'L'; - const ORIENTATION_PORTRAIT = 'P'; - const ORIENTATION_UNKNOW = ''; - -// const ORIENTATION_SQUARE = 1; -// const ORIENTATION_LANDSCAPE = 2; -// const ORIENTATION_PORTRAIT = 3; -// const ORIENTATION_UNKNOW = 0; - - - /** @var Application */ + /** @var Application */ private $app; /** @var databox */ @@ -49,50 +38,45 @@ class SubDefinitionHydrator implements HydratorInterface { if ($this->populatePermalinks) { $this->hydrateRecordsWithPermalinks($records); - } - else { + } else { $this->hydrateRecordsWithoutPermalinks($records); } } private function hydrateRecordsWithPermalinks(&$records) { - foreach (array_keys($records) as $rid) { - - $record = &$records[$rid]; - + foreach(array_keys($records) as $rid) { try { $subdefs = $this->databox->getRecordRepository()->find($rid)->get_subdefs(); $pls = array_map( /** media_Permalink_Adapter|null $plink */ - function ($plink) { - return $plink ? ((string)$plink->get_url()) : null; + function($plink) { + return $plink ? ((string) $plink->get_url()) : null; }, media_Permalink_Adapter::getMany($this->app, $subdefs, false) // false: don't create missing plinks ); - foreach ($subdefs as $subdef) { + foreach($subdefs as $subdef) { $name = $subdef->get_name(); - if (substr(($path = $subdef->get_path()), -1) !== '/') { + if(substr(($path = $subdef->get_path()), -1) !== '/') { $path .= '/'; } - $record['subdefs'][$name] = [ - 'path' => $path . $subdef->get_file(), - 'width' => $subdef->get_width(), - 'height' => $subdef->get_height(), - 'size' => $subdef->get_size(), - 'mime' => $subdef->get_mime(), + $records[$rid]['subdefs'][$name] = array( + 'path' => $path . $subdef->get_file(), + 'width' => $subdef->get_width(), + 'height' => $subdef->get_height(), + 'size' => $subdef->get_size(), + 'mime' => $subdef->get_mime(), 'permalink' => array_key_exists($name, $pls) ? $pls[$name] : null - ]; - if ($name == "thumbnail") { - $this->setOrientation($record, $subdef->get_width(), $subdef->get_height()); - } + ); + } } catch (\Exception $e) { // cant get record ? ignore } + } } @@ -112,42 +96,22 @@ class SubDefinitionHydrator implements HydratorInterface ORDER BY s.record_id SQL; $statement = $this->databox->get_connection()->executeQuery($sql, - [array_keys($records)], - [Connection::PARAM_INT_ARRAY] + array(array_keys($records)), + array(Connection::PARAM_INT_ARRAY) ); $current_rid = null; $record = null; while ($subdef = $statement->fetch()) { - $rid = $subdef['record_id']; - $record = &$records[$rid]; $name = $subdef['name']; - $record['subdefs'][$name] = [ - 'path' => $subdef['path'], - 'width' => $subdef['width'], - 'height' => $subdef['height'], - 'size' => $subdef['size'], - 'mime' => $subdef['mime'], + $records[$subdef['record_id']]['subdefs'][$name] = array( + 'path' => $subdef['path'], + 'width' => $subdef['width'], + 'height' => $subdef['height'], + 'size' => $subdef['size'], + 'mime' => $subdef['mime'], 'permalink' => null - ]; - if ($name == "thumbnail") { - $this->setOrientation($record, $subdef['width'], $subdef['height']); - } + ); } } - - private function setOrientation(&$record, $w, $h) - { - $o = self::ORIENTATION_UNKNOW; - if ($w !== '' && $h !== '' && !is_null($w) && !is_null($h)) { - $w = (int)$w; - $h = (int)$h; - $o = $w == $h ? self::ORIENTATION_SQUARE : ($w > $h ? self::ORIENTATION_LANDSCAPE : self::ORIENTATION_PORTRAIT); - } - if(!array_key_exists('metadata_tags', $record)) { - $record['metadata_tags'] = []; - } - $record['metadata_tags']['ThumbnailOrientation'] = $o; - } } - diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php index ceb7a0a6d9..07d186b4e3 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Mapping/MetadataTagToFieldMappingConverter.php @@ -18,25 +18,6 @@ class MetadataTagToFieldMappingConverter { public function convertTag(Tag $tag) - { - if ($tag->getType() === FieldMapping::TYPE_STRING) { - - $fieldMapping = new StringFieldMapping($tag->getName()); - $fieldMapping->addChild((new StringFieldMapping('raw'))->enableRawIndexing()); - if ($tag->isAnalyzable()) { - $fieldMapping->enableAnalysis(); - } - else { - $fieldMapping->disableAnalysis(); - } - - return $fieldMapping; - } - - return new FieldMapping($tag->getName(), $tag->getType()); - } - - public function dead_convertTag(Tag $tag) { if ($tag->getType() === FieldMapping::TYPE_STRING) { $fieldMapping = new StringFieldMapping($tag->getName()); diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php index 6f7d0b4655..4849ff4693 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Search/FacetsResponse.php @@ -24,7 +24,7 @@ class FacetsResponse return; } - $atf = ElasticsearchOptions::getAggregableTechnicalFields($this->translator); + $atf = ElasticsearchOptions::getAggregableTechnicalFields(); // sort facets respecting the order defined in options foreach($options->getAggregableFields() as $name=>$foptions) { @@ -35,11 +35,9 @@ class FacetsResponse $tf = null; $valueFormatter = function($v){ return $v; }; // default equality formatter - $label = $name; if(array_key_exists($name, $atf)) { $tf = $atf[$name]; - $label = $tf['label']; if(array_key_exists('output_formatter', $tf)) { $valueFormatter = $tf['output_formatter']; } @@ -58,8 +56,7 @@ class FacetsResponse if($response['aggregations'][$name . '#empty']['doc_count'] > 0) { // don't add a facet for 0 results $aggregation['buckets'][] = [ 'key' => '_unset_', - 'value' => $this->translator->trans('prod:workzone:facetstab:unset_field_facet_label_(%fieldname%)', ['%fieldname%' =>$label]), // special homemade prop to display a human value instead of the key - // 'value' => 'unset '.$name, // special homemade prop to display a human value instead of the key + 'value' => $this->translator->trans('prod:workzone:facetstab:unset_field_facet_label_(%fieldname%)', ['%fieldname%' =>$name]), // special homemade prop to display a human value instead of the key 'doc_count' => $response['aggregations'][$name . '#empty']['doc_count'] ]; } @@ -73,15 +70,8 @@ class FacetsResponse $key = array_key_exists('key_as_string', $bucket) ? $bucket['key_as_string'] : $bucket['key']; if($tf) { // the field is one of the hardcoded tech fields - if($key == '_unset_' && array_key_exists('value', $bucket)) { - // don't use the valueformatter since 'value' if already translated - $v = $bucket['value']; - } - else { - $v = $valueFormatter($key); - } $value = [ - 'value' => $v, + 'value' => $valueFormatter($key), 'raw_value' => $key, 'count' => $bucket['doc_count'], 'query' => sprintf($tf['query'], $this->escaper->escapeWord($key)) diff --git a/lib/classes/media/subdef.php b/lib/classes/media/subdef.php index 544f838504..8893523fe0 100644 --- a/lib/classes/media/subdef.php +++ b/lib/classes/media/subdef.php @@ -109,7 +109,6 @@ class media_subdef extends media_abstract implements cache_cacheableInterface const TC_DATA_COLORSPACE = 'ColorSpace'; const TC_DATA_CHANNELS = 'Channels'; const TC_DATA_ORIENTATION = 'Orientation'; - const TC_DATA_THUMBNAILORIENTATION = 'ThumbnailOrientation'; const TC_DATA_COLORDEPTH = 'ColorDepth'; const TC_DATA_DURATION = 'Duration'; const TC_DATA_AUDIOCODEC = 'AudioCodec'; @@ -865,7 +864,6 @@ class media_subdef extends media_abstract implements cache_cacheableInterface self::TC_DATA_VIDEOCODEC => ['method' => 'getVideoCodec', 'type' => 'string', 'analyzable' => false], self::TC_DATA_AUDIOCODEC => ['method' => 'getAudioCodec', 'type' => 'string', 'analyzable' => false], self::TC_DATA_ORIENTATION => ['method' => 'getOrientation', 'type' => 'integer', 'analyzable' => false], - self::TC_DATA_THUMBNAILORIENTATION => ['type' => 'string', 'analyzable' => false], self::TC_DATA_LONGITUDE => ['method' => 'getLongitude', 'type' => 'float', 'analyzable' => false], self::TC_DATA_LONGITUDE_REF => ['method' => 'getLongitudeRef'], self::TC_DATA_LATITUDE => ['method' => 'getLatitude', 'type' => 'float', 'analyzable' => false],