Skip to content

Commit 1693932

Browse files
Store block values in one field (#168)
1 parent 1c82ed9 commit 1693932

File tree

6 files changed

+150
-64
lines changed

6 files changed

+150
-64
lines changed

Search/Factory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,18 @@ public function createMetadataField($name)
7979
return new MetadataField($name);
8080
}
8181

82-
public function createMetadataProperty($path)
82+
public function createMetadataProperty($path, $condition = null)
8383
{
84-
return new Property($path);
84+
return new Property($path, $condition);
8585
}
8686

8787
public function createMetadataValue($value)
8888
{
8989
return new Value($value);
9090
}
9191

92-
public function createMetadataExpression($expression)
92+
public function createMetadataExpression($expression, $condition = null)
9393
{
94-
return new Expression($expression);
94+
return new Expression($expression, $condition);
9595
}
9696
}

Search/Metadata/Field/Expression.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@ class Expression implements FieldInterface
2424
*/
2525
private $expression;
2626

27+
/**
28+
* @var string|null
29+
*/
30+
private $condition;
31+
2732
/**
2833
* @param string $expression
2934
*/
30-
public function __construct($expression)
35+
public function __construct($expression, $condition = null)
3136
{
3237
$this->expression = $expression;
38+
$this->condition = $condition;
3339
}
3440

3541
/**
@@ -41,4 +47,9 @@ public function getExpression()
4147
{
4248
return $this->expression;
4349
}
50+
51+
public function getCondition()
52+
{
53+
return $this->condition;
54+
}
4455
}

Search/Metadata/Field/Property.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@ class Property implements FieldInterface
2424
*/
2525
private $property;
2626

27+
/**
28+
* @var mixed|null
29+
*/
30+
private $condition;
31+
2732
/**
2833
* @param mixed $property
2934
*/
30-
public function __construct($property)
35+
public function __construct($property, $condition = null)
3136
{
3237
$this->property = $property;
38+
$this->condition = $condition;
3339
}
3440

3541
/**
@@ -41,4 +47,9 @@ public function getProperty()
4147
{
4248
return $this->property;
4349
}
50+
51+
public function getCondition()
52+
{
53+
return $this->condition;
54+
}
4455
}

Search/Metadata/FieldEvaluator.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ public function getValue($object, FieldInterface $field)
7070
));
7171
}
7272

73+
public function evaluateCondition($object, string $condition)
74+
{
75+
try {
76+
return $this->expressionLanguage->evaluate($condition, $object);
77+
} catch (\Exception $e) {
78+
throw new \RuntimeException(\sprintf(
79+
'Error encountered when evaluating expression "%s"',
80+
$condition
81+
), null, $e);
82+
}
83+
}
84+
7385
/**
7486
* Evaluate a property (using PropertyAccess).
7587
*

Search/ObjectToDocumentConverter.php

Lines changed: 108 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Massive\Bundle\SearchBundle\Search\Converter\ConverterManagerInterface;
1515
use Massive\Bundle\SearchBundle\Search\Metadata\FieldEvaluator;
16+
use Massive\Bundle\SearchBundle\Search\Metadata\FieldInterface;
1617
use Massive\Bundle\SearchBundle\Search\Metadata\IndexMetadata;
1718

1819
/**
@@ -110,7 +111,14 @@ public function objectToDocument(IndexMetadata $metadata, $object)
110111
$document->setLocale($locale);
111112
}
112113

113-
$this->populateDocument($document, $object, $fieldMapping);
114+
$blockValues = [];
115+
$this->populateDocument($document, $object, $fieldMapping, $blockValues);
116+
117+
foreach ($blockValues as $name => $values) {
118+
$mapping = $this->addMappingOptions();
119+
$values = \implode(' ', $values);
120+
$this->addDocumentField($document, $name, $values, $mapping, Field::TYPE_STRING);
121+
}
114122

115123
return $document;
116124
}
@@ -122,35 +130,23 @@ public function objectToDocument(IndexMetadata $metadata, $object)
122130
* @param Document $document
123131
* @param mixed $object
124132
* @param array $fieldMapping
133+
* @param string[] $blockValues
125134
* @param string $prefix Prefix the document field name (used when called recursively)
126135
*
127136
* @throws \InvalidArgumentException
128137
*/
129-
private function populateDocument($document, $object, $fieldMapping, $prefix = '')
130-
{
131-
foreach ($fieldMapping as $fieldName => $mapping) {
132-
$requiredMappings = ['field', 'type'];
133-
134-
foreach ($requiredMappings as $requiredMapping) {
135-
if (!isset($mapping[$requiredMapping])) {
136-
throw new \RuntimeException(
137-
\sprintf(
138-
'Mapping for "%s" does not have "%s" key',
139-
\get_class($document),
140-
$requiredMapping
141-
)
142-
);
143-
}
144-
}
138+
private function populateDocument(
139+
$document,
140+
$object,
141+
$fieldMapping,
142+
&$blockValues = [],
143+
$prefix = ''
144+
) {
145+
$isBlockScope = '' !== $prefix;
145146

146-
$mapping = \array_merge(
147-
[
148-
'stored' => true,
149-
'aggregate' => false,
150-
'indexed' => true,
151-
],
152-
$mapping
153-
);
147+
foreach ($fieldMapping as $fieldName => $mapping) {
148+
$this->hasRequiredMapping($document, $mapping);
149+
$mapping = $this->addMappingOptions($mapping);
154150

155151
if ('complex' == $mapping['type']) {
156152
if (!isset($mapping['mapping'])) {
@@ -174,15 +170,25 @@ private function populateDocument($document, $object, $fieldMapping, $prefix = '
174170
$document,
175171
$childObject,
176172
$mapping['mapping']->getFieldMapping(),
177-
$prefix . $fieldName . $i
173+
$blockValues,
174+
$prefix . $fieldName . '_'
178175
);
179176
}
180177

181178
continue;
182179
}
183180

184181
$type = $mapping['type'];
185-
$value = $this->fieldEvaluator->getValue($object, $mapping['field']);
182+
/** @var FieldInterface $mappingField */
183+
$mappingField = $mapping['field'];
184+
$condition = method_exists($mappingField, 'getCondition') ? $mappingField->getCondition() : null;
185+
$validField = $condition ? $this->fieldEvaluator->evaluateCondition($object, $condition) : true;
186+
187+
if (false === $validField) {
188+
continue;
189+
}
190+
191+
$value = $this->fieldEvaluator->getValue($object, $mappingField);
186192

187193
if (Field::TYPE_STRING !== $type && Field::TYPE_ARRAY !== $type) {
188194
$value = $this->converterManager->convert($value, $type, $document);
@@ -199,25 +205,17 @@ private function populateDocument($document, $object, $fieldMapping, $prefix = '
199205
);
200206
}
201207

202-
if (\is_array($value) && (isset($value['value']) || isset($value['fields']))) {
208+
if (!$isBlockScope && \is_array($value) && (isset($value['value']) || isset($value['fields']))) {
203209
if (isset($value['value'])) {
204-
$document->addField(
205-
$this->factory->createField(
206-
$prefix . $fieldName,
207-
$value['value'],
208-
$this->getValueType($value['value']),
209-
$mapping['stored'],
210-
$mapping['indexed'],
211-
$mapping['aggregate']
212-
)
213-
);
210+
$valueType = $this->getValueType($value['value']);
211+
$this->addDocumentField($document, $fieldName, $value['value'], $mapping, $valueType);
214212
}
215213

216214
if (isset($value['fields'])) {
217215
/** @var Field $field */
218216
foreach ($value['fields'] as $field) {
219217
$field = clone $field;
220-
$field->setName($prefix . $fieldName . '#' . $field->getName());
218+
$field->setName($fieldName . '#' . $field->getName());
221219
$document->addField($field);
222220
}
223221
}
@@ -226,29 +224,82 @@ private function populateDocument($document, $object, $fieldMapping, $prefix = '
226224
}
227225

228226
if ('complex' !== $mapping['type']) {
229-
$document->addField(
230-
$this->factory->createField(
231-
$prefix . $fieldName,
232-
$value,
233-
$type,
234-
$mapping['stored'],
235-
$mapping['indexed'],
236-
$mapping['aggregate']
237-
)
238-
);
227+
if ($isBlockScope && $value && Field::TYPE_STRING === $type) {
228+
$blockValues[$prefix . $fieldName][] = $value;
229+
} elseif (!$isBlockScope) {
230+
$this->addDocumentField($document, $fieldName, $value, $mapping, $type);
231+
}
239232

240233
continue;
241234
}
242235

243236
foreach ($value as $key => $itemValue) {
244-
$document->addField(
245-
$this->factory->createField(
246-
$prefix . $fieldName . $key,
247-
$itemValue,
248-
$mapping['type'],
249-
$mapping['stored'],
250-
$mapping['indexed'],
251-
$mapping['aggregate']
237+
$itemType = $mapping['type'];
238+
239+
if ($isBlockScope && $itemValue && Field::TYPE_STRING === $itemType) {
240+
$blockValues[$prefix . $fieldName . $key][] = $itemValue;
241+
} elseif (!$isBlockScope) {
242+
$this->addDocumentField($document, $fieldName . $key, $itemValue, $mapping, $itemType);
243+
}
244+
}
245+
}
246+
}
247+
248+
/**
249+
* Adds some default mapping options to the given array.
250+
*/
251+
private function addMappingOptions($mapping = []): array
252+
{
253+
return \array_merge(
254+
[
255+
'stored' => true,
256+
'aggregate' => false,
257+
'indexed' => true,
258+
],
259+
$mapping
260+
);
261+
}
262+
263+
/**
264+
* Adds a search field to the Document.
265+
*
266+
* @param Document $document
267+
* @param string $fieldName
268+
* @param mixed $value
269+
* @param array $mapping
270+
* @param string $type
271+
*/
272+
private function addDocumentField($document, $fieldName, $value, $mapping, $type): void
273+
{
274+
$document->addField(
275+
$this->factory->createField(
276+
$fieldName,
277+
$value,
278+
$type,
279+
$mapping['stored'],
280+
$mapping['indexed'],
281+
$mapping['aggregate']
282+
)
283+
);
284+
}
285+
286+
/**
287+
* Checks if all mandatory options are available in the given mapping.
288+
*
289+
* @param Document $document
290+
* @param array $mapping
291+
*/
292+
private function hasRequiredMapping($document, $mapping): void
293+
{
294+
$requiredMappings = ['field', 'type'];
295+
296+
foreach ($requiredMappings as $requiredMapping) {
297+
if (!isset($mapping[$requiredMapping])) {
298+
throw new \RuntimeException(
299+
\sprintf(
300+
'Mapping for "%s" does not have "%s" key',
301+
\get_class($document),
302+
$requiredMapping
252303
)
253304
);
254305
}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939

4040
"behat/behat": "^3.4.2",
4141

42-
"webmozart/assert": "^1.7"
42+
"webmozart/assert": "^1.7",
43+
"phpspec/prophecy": "^1.15"
4344
},
4445
"suggest": {
4546
"sensio/distribution-bundle": "Required if the SearchScriptHandler is used",

0 commit comments

Comments
 (0)