Revert "PHRAS-3215 : add ThumbnailOrientation facet ; add strings"

This commit is contained in:
Nicolas Maillat
2022-02-25 23:10:23 +01:00
committed by GitHub
parent 264bed6c7b
commit ccd460be27
10 changed files with 51 additions and 156 deletions

View File

@@ -2813,7 +2813,7 @@ class V1Controller extends Controller
{ {
$ret = [ $ret = [
"meta_fields" => $this->listUserAuthorizedMetadataFields($this->getAuthenticatedUser()), "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()), "technical_fields" => $this->buildUserFieldList(media_subdef::getTechnicalFieldsList()),
]; ];

View File

@@ -76,8 +76,7 @@ class QueryController extends Controller
$this->app['elasticsearch.client'], $this->app['elasticsearch.client'],
$query_context_factory, $query_context_factory,
$this->app['elasticsearch.facets_response.factory'], $this->app['elasticsearch.facets_response.factory'],
$this->app['elasticsearch.options'], $this->app['elasticsearch.options']
$this->app['translator']
); );
$autocomplete = $engine->autocomplete($word, $options); $autocomplete = $engine->autocomplete($word, $options);
@@ -352,7 +351,7 @@ class QueryController extends Controller
// add technical fields // add technical fields
$fieldsInfosByName = []; $fieldsInfosByName = [];
foreach(ElasticsearchOptions::getAggregableTechnicalFields($this->app['translator']) as $k => $f) { foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) {
$fieldsInfosByName[$k] = $f; $fieldsInfosByName[$k] = $f;
$fieldsInfosByName[$k]['trans_label'] = $this->app->trans( /** @ignore */ $f['label']); $fieldsInfosByName[$k]['trans_label'] = $this->app->trans( /** @ignore */ $f['label']);
$fieldsInfosByName[$k]['labels'] = []; $fieldsInfosByName[$k]['labels'] = [];

View File

@@ -96,8 +96,7 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
$app['elasticsearch.client'], $app['elasticsearch.client'],
$app['query_context.factory'], $app['query_context.factory'],
$app['elasticsearch.facets_response.factory'], $app['elasticsearch.facets_response.factory'],
$app['elasticsearch.options'], $app['elasticsearch.options']
$app['translator']
); );
}); });

View File

@@ -33,7 +33,6 @@ use Closure;
use databox_field; use databox_field;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Elasticsearch\Client; use Elasticsearch\Client;
use Symfony\Component\Translation\TranslatorInterface;
class ElasticSearchEngine implements SearchEngineInterface class ElasticSearchEngine implements SearchEngineInterface
{ {
@@ -60,8 +59,6 @@ class ElasticSearchEngine implements SearchEngineInterface
*/ */
private $context_factory; private $context_factory;
private $translator;
/** /**
* @param Application $app * @param Application $app
* @param GlobalStructure $structure * @param GlobalStructure $structure
@@ -69,9 +66,8 @@ class ElasticSearchEngine implements SearchEngineInterface
* @param QueryContextFactory $context_factory * @param QueryContextFactory $context_factory
* @param Closure $facetsResponseFactory * @param Closure $facetsResponseFactory
* @param ElasticsearchOptions $options * @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->app = $app;
$this->structure = $structure; $this->structure = $structure;
@@ -79,7 +75,6 @@ class ElasticSearchEngine implements SearchEngineInterface
$this->context_factory = $context_factory; $this->context_factory = $context_factory;
$this->facetsResponseFactory = $facetsResponseFactory; $this->facetsResponseFactory = $facetsResponseFactory;
$this->options = $options; $this->options = $options;
$this->translator = $translator;
$this->indexName = $options->getIndexName(); $this->indexName = $options->getIndexName();
} }
@@ -785,7 +780,7 @@ class ElasticSearchEngine implements SearchEngineInterface
{ {
$aggs = []; $aggs = [];
// technical aggregates (enable + optional limit) // technical aggregates (enable + optional limit)
foreach (ElasticsearchOptions::getAggregableTechnicalFields($this->translator) as $k => $f) { foreach (ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) {
$size = $this->options->getAggregableFieldLimit($k); $size = $this->options->getAggregableFieldLimit($k);
if ($size !== databox_field::FACET_DISABLED) { if ($size !== databox_field::FACET_DISABLED) {
if ($size === databox_field::FACET_NO_LIMIT) { if ($size === databox_field::FACET_NO_LIMIT) {
@@ -798,13 +793,6 @@ class ElasticSearchEngine implements SearchEngineInterface
] ]
]; ];
$aggs[$k] = $agg; $aggs[$k] = $agg;
if($options->getIncludeUnsetFieldFacet() === true) {
$aggs[$k . '#empty'] = [
'missing' => [
'field' => $f['esfield'],
]
];
}
} }
} }
// fields aggregates // fields aggregates

View File

@@ -11,7 +11,6 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic;
use databox_field; use databox_field;
use igorw; use igorw;
use Symfony\Component\Translation\TranslatorInterface;
class ElasticsearchOptions class ElasticsearchOptions
@@ -313,7 +312,7 @@ class ElasticsearchOptions
$this->_customValues = igorw\assoc_in($this->_customValues, $keys, $value); $this->_customValues = igorw\assoc_in($this->_customValues, $keys, $value);
} }
public static function getAggregableTechnicalFields(TranslatorInterface $translator) public static function getAggregableTechnicalFields()
{ {
return [ return [
'_base' => [ '_base' => [
@@ -339,21 +338,21 @@ class ElasticsearchOptions
], ],
'_camera_model' => [ '_camera_model' => [
'type' => 'string', 'type' => 'string',
'label' => 'prod::facet:CameraModel_label', 'label' => 'Camera Model',
'field' => "meta.CameraModel", 'field' => "meta.CameraModel",
'esfield' => 'metadata_tags.CameraModel', 'esfield' => 'metadata_tags.CameraModel',
'query' => 'meta.CameraModel=%s', 'query' => 'meta.CameraModel:%s',
], ],
'_iso' => [ '_iso' => [
'type' => 'number', 'type' => 'number',
'label' => 'prod::facet:ISO_label', 'label' => 'ISO',
'field' => "meta.ISO", 'field' => "meta.ISO",
'esfield' => 'metadata_tags.ISO', 'esfield' => 'metadata_tags.ISO',
'query' => 'meta.ISO=%s', 'query' => 'meta.ISO=%s',
], ],
'_aperture' => [ '_aperture' => [
'type' => 'number', 'type' => 'number',
'label' => 'prod::facet:Aperture_label', 'label' => 'Aperture',
'field' => "meta.Aperture", 'field' => "meta.Aperture",
'esfield' => 'metadata_tags.Aperture', 'esfield' => 'metadata_tags.Aperture',
'query' => 'meta.Aperture=%s', 'query' => 'meta.Aperture=%s',
@@ -363,7 +362,7 @@ class ElasticsearchOptions
], ],
'_shutterspeed' => [ '_shutterspeed' => [
'type' => 'number', 'type' => 'number',
'label' => 'prod::facet:ShutterSpeed_label', 'label' => 'Shutter speed',
'field' => "meta.ShutterSpeed", 'field' => "meta.ShutterSpeed",
'esfield' => 'metadata_tags.ShutterSpeed', 'esfield' => 'metadata_tags.ShutterSpeed',
'query' => 'meta.ShutterSpeed=%s', 'query' => 'meta.ShutterSpeed=%s',
@@ -376,86 +375,63 @@ class ElasticsearchOptions
], ],
'_flashfired' => [ '_flashfired' => [
'type' => 'boolean', 'type' => 'boolean',
'label' => 'prod::facet:FlashFired_label', 'label' => 'FlashFired',
'field' => "meta.FlashFired", 'field' => "meta.FlashFired",
'esfield' => 'metadata_tags.FlashFired', 'esfield' => 'metadata_tags.FlashFired',
'query' => 'meta.FlashFired=%s', 'query' => 'meta.FlashFired=%s',
'choices' => [ 'choices' => [
"aggregated (2 values: fired = 0 or 1)" => -1, "aggregated (2 values: fired = 0 or 1)" => -1,
], ],
'output_formatter' => function($value) use($translator) { 'output_formatter' => function($value) {
$map = [ static $map = ["false"=>"No flash", "true"=>"Flash", '0'=>"No flash", '1'=>"Flash"];
"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; return array_key_exists($value, $map) ? $map[$value] : $value;
}, },
], ],
'_framerate' => [ '_framerate' => [
'type' => 'number', 'type' => 'number',
'label' => 'prod::facet:FrameRate_label', 'label' => 'FrameRate',
'field' => "meta.FrameRate", 'field' => "meta.FrameRate",
'esfield' => 'metadata_tags.FrameRate', 'esfield' => 'metadata_tags.FrameRate',
'query' => 'meta.FrameRate=%s', 'query' => 'meta.FrameRate=%s',
], ],
'_audiosamplerate' => [ '_audiosamplerate' => [
'type' => 'number', 'type' => 'number',
'label' => 'prod::facet:AudioSamplerate_label', 'label' => 'Audio Samplerate',
'field' => "meta.AudioSamplerate", 'field' => "meta.AudioSamplerate",
'esfield' => 'metadata_tags.AudioSamplerate', 'esfield' => 'metadata_tags.AudioSamplerate',
'query' => 'meta.AudioSamplerate=%s', 'query' => 'meta.AudioSamplerate=%s',
], ],
'_videocodec' => [ '_videocodec' => [
'type' => 'string', 'type' => 'string',
'label' => 'prod::facet:VideoCodec_label', 'label' => 'Video codec',
'field' => "meta.VideoCodec", 'field' => "meta.VideoCodec",
'esfield' => 'metadata_tags.VideoCodec', 'esfield' => 'metadata_tags.VideoCodec',
'query' => 'meta.VideoCodec:%s', 'query' => 'meta.VideoCodec:%s',
], ],
'_audiocodec' => [ '_audiocodec' => [
'type' => 'string', 'type' => 'string',
'label' => 'prod::facet:AudioCodec_label', 'label' => 'Audio codec',
'field' => "meta.AudioCodec", 'field' => "meta.AudioCodec",
'esfield' => 'metadata_tags.AudioCodec', 'esfield' => 'metadata_tags.AudioCodec',
'query' => 'meta.AudioCodec:%s', 'query' => 'meta.AudioCodec:%s',
], ],
'_orientation' => [ '_orientation' => [
'type' => 'string', 'type' => 'string',
'label' => 'prod::facet.Orientation_label', 'label' => 'Orientation',
'field' => "meta.Orientation", 'field' => "meta.Orientation",
'esfield' => 'metadata_tags.Orientation', 'esfield' => 'metadata_tags.Orientation',
'query' => 'meta.Orientation=%s', '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' => [ '_colorspace' => [
'type' => 'string', 'type' => 'string',
'label' => 'prod::facet:Colorspace_label', 'label' => 'Colorspace',
'field' => "meta.ColorSpace", 'field' => "meta.ColorSpace",
'esfield' => 'metadata_tags.ColorSpace', 'esfield' => 'metadata_tags.ColorSpace',
'query' => 'meta.ColorSpace:%s', 'query' => 'meta.ColorSpace:%s',
], ],
'_mimetype' => [ '_mimetype' => [
'type' => 'string', 'type' => 'string',
'label' => 'prod::facet:MimeType_label', 'label' => 'MimeType',
'field' => "meta.MimeType", 'field' => "meta.MimeType",
'esfield' => 'metadata_tags.MimeType', 'esfield' => 'metadata_tags.MimeType',
'query' => 'meta.MimeType:%s', 'query' => 'meta.MimeType:%s',

View File

@@ -137,7 +137,7 @@ class ElasticsearchSettingsFormType extends AbstractType
} }
// add or replace hardcoded tech fields // 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 $choices = array_key_exists('choices', $f) ? $f['choices'] : null; // a tech-field can publish it's own choices
$help = null; $help = null;
$label = '#' . $k; $label = '#' . $k;

View File

@@ -18,18 +18,7 @@ use media_Permalink_Adapter;
class SubDefinitionHydrator implements HydratorInterface class SubDefinitionHydrator implements HydratorInterface
{ {
const ORIENTATION_SQUARE = 'S'; /** @var Application */
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; private $app;
/** @var databox */ /** @var databox */
@@ -49,50 +38,45 @@ class SubDefinitionHydrator implements HydratorInterface
{ {
if ($this->populatePermalinks) { if ($this->populatePermalinks) {
$this->hydrateRecordsWithPermalinks($records); $this->hydrateRecordsWithPermalinks($records);
} } else {
else {
$this->hydrateRecordsWithoutPermalinks($records); $this->hydrateRecordsWithoutPermalinks($records);
} }
} }
private function hydrateRecordsWithPermalinks(&$records) private function hydrateRecordsWithPermalinks(&$records)
{ {
foreach (array_keys($records) as $rid) { foreach(array_keys($records) as $rid) {
$record = &$records[$rid];
try { try {
$subdefs = $this->databox->getRecordRepository()->find($rid)->get_subdefs(); $subdefs = $this->databox->getRecordRepository()->find($rid)->get_subdefs();
$pls = array_map( $pls = array_map(
/** media_Permalink_Adapter|null $plink */ /** media_Permalink_Adapter|null $plink */
function ($plink) { function($plink) {
return $plink ? ((string)$plink->get_url()) : null; return $plink ? ((string) $plink->get_url()) : null;
}, },
media_Permalink_Adapter::getMany($this->app, $subdefs, false) // false: don't create missing plinks 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(); $name = $subdef->get_name();
if (substr(($path = $subdef->get_path()), -1) !== '/') { if(substr(($path = $subdef->get_path()), -1) !== '/') {
$path .= '/'; $path .= '/';
} }
$record['subdefs'][$name] = [ $records[$rid]['subdefs'][$name] = array(
'path' => $path . $subdef->get_file(), 'path' => $path . $subdef->get_file(),
'width' => $subdef->get_width(), 'width' => $subdef->get_width(),
'height' => $subdef->get_height(), 'height' => $subdef->get_height(),
'size' => $subdef->get_size(), 'size' => $subdef->get_size(),
'mime' => $subdef->get_mime(), 'mime' => $subdef->get_mime(),
'permalink' => array_key_exists($name, $pls) ? $pls[$name] : null 'permalink' => array_key_exists($name, $pls) ? $pls[$name] : null
]; );
if ($name == "thumbnail") {
$this->setOrientation($record, $subdef->get_width(), $subdef->get_height());
}
} }
} }
catch (\Exception $e) { catch (\Exception $e) {
// cant get record ? ignore // cant get record ? ignore
} }
} }
} }
@@ -112,42 +96,22 @@ class SubDefinitionHydrator implements HydratorInterface
ORDER BY s.record_id ORDER BY s.record_id
SQL; SQL;
$statement = $this->databox->get_connection()->executeQuery($sql, $statement = $this->databox->get_connection()->executeQuery($sql,
[array_keys($records)], array(array_keys($records)),
[Connection::PARAM_INT_ARRAY] array(Connection::PARAM_INT_ARRAY)
); );
$current_rid = null; $current_rid = null;
$record = null; $record = null;
while ($subdef = $statement->fetch()) { while ($subdef = $statement->fetch()) {
$rid = $subdef['record_id'];
$record = &$records[$rid];
$name = $subdef['name']; $name = $subdef['name'];
$record['subdefs'][$name] = [ $records[$subdef['record_id']]['subdefs'][$name] = array(
'path' => $subdef['path'], 'path' => $subdef['path'],
'width' => $subdef['width'], 'width' => $subdef['width'],
'height' => $subdef['height'], 'height' => $subdef['height'],
'size' => $subdef['size'], 'size' => $subdef['size'],
'mime' => $subdef['mime'], 'mime' => $subdef['mime'],
'permalink' => null '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;
}
} }

View File

@@ -18,25 +18,6 @@ class MetadataTagToFieldMappingConverter
{ {
public function convertTag(Tag $tag) 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) { if ($tag->getType() === FieldMapping::TYPE_STRING) {
$fieldMapping = new StringFieldMapping($tag->getName()); $fieldMapping = new StringFieldMapping($tag->getName());

View File

@@ -24,7 +24,7 @@ class FacetsResponse
return; return;
} }
$atf = ElasticsearchOptions::getAggregableTechnicalFields($this->translator); $atf = ElasticsearchOptions::getAggregableTechnicalFields();
// sort facets respecting the order defined in options // sort facets respecting the order defined in options
foreach($options->getAggregableFields() as $name=>$foptions) { foreach($options->getAggregableFields() as $name=>$foptions) {
@@ -35,11 +35,9 @@ class FacetsResponse
$tf = null; $tf = null;
$valueFormatter = function($v){ return $v; }; // default equality formatter $valueFormatter = function($v){ return $v; }; // default equality formatter
$label = $name;
if(array_key_exists($name, $atf)) { if(array_key_exists($name, $atf)) {
$tf = $atf[$name]; $tf = $atf[$name];
$label = $tf['label'];
if(array_key_exists('output_formatter', $tf)) { if(array_key_exists('output_formatter', $tf)) {
$valueFormatter = $tf['output_formatter']; $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 if($response['aggregations'][$name . '#empty']['doc_count'] > 0) { // don't add a facet for 0 results
$aggregation['buckets'][] = [ $aggregation['buckets'][] = [
'key' => '_unset_', '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' => $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' => 'unset '.$name, // special homemade prop to display a human value instead of the key
'doc_count' => $response['aggregations'][$name . '#empty']['doc_count'] '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']; $key = array_key_exists('key_as_string', $bucket) ? $bucket['key_as_string'] : $bucket['key'];
if($tf) { if($tf) {
// the field is one of the hardcoded tech fields // 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 = [
'value' => $v, 'value' => $valueFormatter($key),
'raw_value' => $key, 'raw_value' => $key,
'count' => $bucket['doc_count'], 'count' => $bucket['doc_count'],
'query' => sprintf($tf['query'], $this->escaper->escapeWord($key)) 'query' => sprintf($tf['query'], $this->escaper->escapeWord($key))

View File

@@ -109,7 +109,6 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
const TC_DATA_COLORSPACE = 'ColorSpace'; const TC_DATA_COLORSPACE = 'ColorSpace';
const TC_DATA_CHANNELS = 'Channels'; const TC_DATA_CHANNELS = 'Channels';
const TC_DATA_ORIENTATION = 'Orientation'; const TC_DATA_ORIENTATION = 'Orientation';
const TC_DATA_THUMBNAILORIENTATION = 'ThumbnailOrientation';
const TC_DATA_COLORDEPTH = 'ColorDepth'; const TC_DATA_COLORDEPTH = 'ColorDepth';
const TC_DATA_DURATION = 'Duration'; const TC_DATA_DURATION = 'Duration';
const TC_DATA_AUDIOCODEC = 'AudioCodec'; 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_VIDEOCODEC => ['method' => 'getVideoCodec', 'type' => 'string', 'analyzable' => false],
self::TC_DATA_AUDIOCODEC => ['method' => 'getAudioCodec', '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_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 => ['method' => 'getLongitude', 'type' => 'float', 'analyzable' => false],
self::TC_DATA_LONGITUDE_REF => ['method' => 'getLongitudeRef'], self::TC_DATA_LONGITUDE_REF => ['method' => 'getLongitudeRef'],
self::TC_DATA_LATITUDE => ['method' => 'getLatitude', 'type' => 'float', 'analyzable' => false], self::TC_DATA_LATITUDE => ['method' => 'getLatitude', 'type' => 'float', 'analyzable' => false],