Refactor query context

No more private collection map, uses new features from LimitedStructure.
From now on, Context tries to return Field objects instead of strings.

New context methods:
- getUnrestrictedFields()
- getPrivateFields()
- localizeField(Field) (signature changed)
- localizeFieldName(string)

QueryContext::localizeField() now takes a Field object, use localizeFieldName() if you want to pass a string.

Field::getIndexFieldName() renamed to Field::getIndexField().
Raw index fields are now obtained with Field::getIndexField(true).
This commit is contained in:
Mathieu Darse
2015-07-10 17:33:10 +02:00
parent 929705f13e
commit d778ab5126
7 changed files with 70 additions and 54 deletions

View File

@@ -309,7 +309,6 @@ class ElasticSearchEngine implements SearchEngineInterface
{ {
return new QueryContext( return new QueryContext(
new LimitedStructure($this->structure, $options), new LimitedStructure($this->structure, $options),
[],
$this->locales, $this->locales,
$this->app['locale'] $this->app['locale']
); );
@@ -401,8 +400,7 @@ class ElasticSearchEngine implements SearchEngineInterface
// 2015-05-26 (mdarse) Removed databox filtering. // 2015-05-26 (mdarse) Removed databox filtering.
// It was already done by the ACL filter in the query scope, so no // It was already done by the ACL filter in the query scope, so no
// document that shouldn't be displayed can go this far. // document that shouldn't be displayed can go this far.
$field_name = $field->getIndexFieldName(); $aggs[$name]['terms']['field'] = $field->getIndexField(true);
$aggs[$name]['terms']['field'] = sprintf('%s.raw', $field_name);
} }
return $aggs; return $aggs;

View File

@@ -19,13 +19,10 @@ class QueryContext
private $queryLocale; private $queryLocale;
/** @var array */ /** @var array */
private $fields; private $fields;
/** @var array */
private $privateCollectionMap;
public function __construct(Structure $structure, array $privateCollectionMap, array $locales, $queryLocale, array $fields = null) public function __construct(Structure $structure, array $locales, $queryLocale, array $fields = null)
{ {
$this->structure = $structure; $this->structure = $structure;
$this->privateCollectionMap = $privateCollectionMap;
$this->locales = $locales; $this->locales = $locales;
$this->queryLocale = $queryLocale; $this->queryLocale = $queryLocale;
$this->fields = $fields; $this->fields = $fields;
@@ -41,7 +38,7 @@ class QueryContext
} }
} }
return new static($this->structure, $this->privateCollectionMap, $this->locales, $this->queryLocale, $fields); return new static($this->structure, $this->locales, $this->queryLocale, $fields);
} }
public function getRawFields() public function getRawFields()
@@ -51,11 +48,8 @@ class QueryContext
} }
$fields = array(); $fields = array();
foreach ($this->fields as $name) { foreach ($this->getUnrestrictedFields() as $name => $field) {
$field = $this->normalizeField($name); $fields[] = $field->getIndexField(true);
if ($field) {
$fields[] = sprintf('%s.raw', $field);
}
} }
return $fields; return $fields;
@@ -64,39 +58,62 @@ class QueryContext
public function getLocalizedFields() public function getLocalizedFields()
{ {
if ($this->fields === null) { if ($this->fields === null) {
return $this->localizeField('caption_all'); return $this->localizeFieldName('caption_all');
} }
$fields = array(); $fields = array();
foreach ($this->fields as $field) { foreach ($this->getUnrestrictedFields() as $_ => $field) {
$normalized = $this->normalizeField($field); foreach ($this->localizeField($field) as $fields[]);
foreach ($this->localizeField($normalized) as $fields[]);
} }
return $fields; return $fields;
} }
public function getUnrestrictedFields()
{
// TODO Restore search optimization by using "caption_all" field
// (only when $this->fields is null)
return array_intersect_key(
$this->structure->getUnrestrictedFields(),
array_flip($this->fields)
);
}
public function getPrivateFields()
{
$private_fields = $this->structure->getPrivateFields();
if ($this->fields === null) {
return $private_fields;
} else {
return array_intersect_key($private_fields, array_flip($this->fields));
}
}
/**
* @deprecated Use getPrivateFields() instead
*/
public function getAllowedPrivateFields() public function getAllowedPrivateFields()
{ {
$allowed_field_names = array_keys($this->privateCollectionMap); return $this->getPrivateFields();
return array_map(array($this->structure, 'get'), $allowed_field_names);
} }
/**
* @deprecated Use getDependantCollections() on a Field from a LimitedStructure
*/
public function getAllowedCollectionsOnPrivateField(Field $field) public function getAllowedCollectionsOnPrivateField(Field $field)
{ {
$name = $field->getName(); return $field->getDependantCollections();
if (!isset($this->privateCollectionMap[$name])) {
throw new \OutOfRangeException('Given field is not an allowed private field.');
}
return $this->privateCollectionMap[$name];
} }
/** /**
* @todo Maybe we should put this logic in Field class? * @todo Maybe we should put this logic in Field class?
*/ */
public function localizeField($field) public function localizeField(Field $field)
{
return $this->localizeFieldName($field->getIndexField());
}
private function localizeFieldName($field)
{ {
$fields = array(); $fields = array();
foreach ($this->locales as $locale) { foreach ($this->locales as $locale) {
@@ -122,7 +139,7 @@ class QueryContext
return null; return null;
} }
// TODO Field label dereferencing (we only want names) // TODO Field label dereferencing (we only want names)
return $field->getIndexFieldName(); return $field->getIndexField();
} }
public function getFields() public function getFields()

View File

@@ -12,15 +12,15 @@ class QueryHelper
// (instead of a clause for each field, with his collection set) // (instead of a clause for each field, with his collection set)
$fields_map = []; $fields_map = [];
$collections_map = []; $collections_map = [];
foreach ($context->getAllowedPrivateFields() as $field) { foreach ($context->getPrivateFields() as $field) {
$collections = $context->getAllowedCollectionsOnPrivateField($field); $collections = $field->getDependantCollections();
$hash = self::hashCollections($collections); $hash = self::hashCollections($collections);
$collections_map[$hash] = $collections; $collections_map[$hash] = $collections;
if (!isset($fields_map[$hash])) { if (!isset($fields_map[$hash])) {
$fields_map[$hash] = []; $fields_map[$hash] = [];
} }
// Merge fields with others having the same collections // Merge fields with others having the same collections
$fields = $context->localizeField($field->getIndexFieldName()); $fields = $context->localizeField($field);
foreach ($fields as $fields_map[$hash][]); foreach ($fields as $fields_map[$hash][]);
} }

View File

@@ -95,12 +95,13 @@ class Field
return $this->name; return $this->name;
} }
public function getIndexFieldName() public function getIndexField($raw = false)
{ {
return sprintf( return sprintf(
'%scaption.%s', '%scaption.%s%s',
$this->is_private ? 'private_' : '', $this->is_private ? 'private_' : '',
$this->name $this->name,
$raw ? '.raw' : ''
); );
} }

View File

@@ -25,7 +25,7 @@ class QuotedTextNodeTest extends \PHPUnit_Framework_TestCase
{ {
$query_context = $this->prophesize(QueryContext::class); $query_context = $this->prophesize(QueryContext::class);
$query_context->getLocalizedFields()->willReturn(['foo.fr', 'foo.en']); $query_context->getLocalizedFields()->willReturn(['foo.fr', 'foo.en']);
$query_context->getAllowedPrivateFields()->willReturn([]); $query_context->getPrivateFields()->willReturn([]);
$node = new QuotedTextNode('bar'); $node = new QuotedTextNode('bar');
$query = $node->buildQuery($query_context->reveal()); $query = $node->buildQuery($query_context->reveal());
@@ -44,20 +44,20 @@ class QuotedTextNodeTest extends \PHPUnit_Framework_TestCase
public function testQueryBuildWithPrivateFields() public function testQueryBuildWithPrivateFields()
{ {
$public_field = new Field('foo', Mapping::TYPE_STRING, ['private' => false]); $public_field = new Field('foo', Mapping::TYPE_STRING, ['private' => false]);
$private_field = new Field('bar', Mapping::TYPE_STRING, ['private' => true]); $private_field = new Field('bar', Mapping::TYPE_STRING, [
'private' => true,
'used_by_collections' => [1, 2, 3]
]);
$query_context = $this->prophesize(QueryContext::class); $query_context = $this->prophesize(QueryContext::class);
$query_context
->getPrivateFields()
->willReturn([$private_field]);
$query_context $query_context
->getLocalizedFields() ->getLocalizedFields()
->willReturn(['foo.fr', 'foo.en']); ->willReturn(['foo.fr', 'foo.en']);
$query_context $query_context
->getAllowedPrivateFields() ->localizeField($private_field)
->willReturn([$private_field]);
$query_context
->getAllowedCollectionsOnPrivateField($private_field)
->willReturn([1, 2, 3]);
$query_context
->localizeField('private_caption.bar')
->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']); ->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']);
$node = new QuotedTextNode('baz'); $node = new QuotedTextNode('baz');

View File

@@ -44,7 +44,7 @@ class TextNodeTest extends \PHPUnit_Framework_TestCase
{ {
$query_context = $this->prophesize(QueryContext::class); $query_context = $this->prophesize(QueryContext::class);
$query_context->getLocalizedFields()->willReturn(['foo.fr', 'foo.en']); $query_context->getLocalizedFields()->willReturn(['foo.fr', 'foo.en']);
$query_context->getAllowedPrivateFields()->willReturn([]); $query_context->getPrivateFields()->willReturn([]);
$node = new TextNode('bar', new Context('baz')); $node = new TextNode('bar', new Context('baz'));
$query = $node->buildQuery($query_context->reveal()); $query = $node->buildQuery($query_context->reveal());
@@ -63,20 +63,20 @@ class TextNodeTest extends \PHPUnit_Framework_TestCase
public function testQueryBuildWithPrivateFields() public function testQueryBuildWithPrivateFields()
{ {
$public_field = new Field('foo', Mapping::TYPE_STRING, ['private' => false]); $public_field = new Field('foo', Mapping::TYPE_STRING, ['private' => false]);
$private_field = new Field('bar', Mapping::TYPE_STRING, ['private' => true]); $private_field = new Field('bar', Mapping::TYPE_STRING, [
'private' => true,
'used_by_collections' => [1, 2, 3]
]);
$query_context = $this->prophesize(QueryContext::class); $query_context = $this->prophesize(QueryContext::class);
$query_context $query_context
->getLocalizedFields() ->getLocalizedFields()
->willReturn(['foo.fr', 'foo.en']); ->willReturn(['foo.fr', 'foo.en']);
$query_context $query_context
->getAllowedPrivateFields() ->getPrivateFields()
->willReturn([$private_field]); ->willReturn([$private_field]);
$query_context $query_context
->getAllowedCollectionsOnPrivateField($private_field) ->localizeField($private_field)
->willReturn([1, 2, 3]);
$query_context
->localizeField('private_caption.bar')
->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']); ->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']);
$node = new TextNode('baz'); $node = new TextNode('baz');
@@ -118,7 +118,7 @@ class TextNodeTest extends \PHPUnit_Framework_TestCase
->getLocalizedFields() ->getLocalizedFields()
->willReturn(['foo.fr', 'foo.en']); ->willReturn(['foo.fr', 'foo.en']);
$query_context $query_context
->getAllowedPrivateFields() ->getPrivateFields()
->willReturn([]); ->willReturn([]);
$query_context $query_context
->getFields() ->getFields()

View File

@@ -17,7 +17,7 @@ class QueryContextTest extends \PHPUnit_Framework_TestCase
{ {
$structure = $this->prophesize(Structure::class)->reveal(); $structure = $this->prophesize(Structure::class)->reveal();
$available_locales = ['ab', 'cd', 'ef']; $available_locales = ['ab', 'cd', 'ef'];
$context = new QueryContext($structure, [], $available_locales, 'fr'); $context = new QueryContext($structure, $available_locales, 'fr');
$narrowed = $context->narrowToFields(['some_field']); $narrowed = $context->narrowToFields(['some_field']);
$this->assertEquals(['some_field'], $narrowed->getFields()); $this->assertEquals(['some_field'], $narrowed->getFields());
} }
@@ -30,7 +30,7 @@ class QueryContextTest extends \PHPUnit_Framework_TestCase
$structure->get('foo')->willReturn($public_field); $structure->get('foo')->willReturn($public_field);
$structure->get('bar')->willReturn($restricted_field); $structure->get('bar')->willReturn($restricted_field);
$context = new QueryContext($structure->reveal(), [], [], 'fr'); $context = new QueryContext($structure->reveal(), [], 'fr');
$this->assertEquals('caption.foo', $context->normalizeField('foo')); $this->assertEquals('caption.foo', $context->normalizeField('foo'));
$this->assertEquals('private_caption.bar', $context->normalizeField('bar')); $this->assertEquals('private_caption.bar', $context->normalizeField('bar'));
} }