Skip to content

Commit 1220084

Browse files
committed
Merge remote-tracking branch 'remotes/origin/6.1-dev'
2 parents a2eabad + c9f626c commit 1220084

20 files changed

+421
-174
lines changed

DependencyInjection/Compiler/MappingPass.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ private function handleDirectoryMapping(ContainerBuilder $container, string $dir
5959
/** @var DocumentParser $parser */
6060
$parser = $container->get(DocumentParser::class);
6161
$indexesOverride = $container->getParameter(Configuration::ONGR_INDEXES_OVERRIDE);
62+
$converterDefinition = $container->getDefinition(Converter::class);
6263

6364
foreach ($this->getNamespaces($dir) as $namespace) {
6465
$class = new \ReflectionClass($namespace);
@@ -71,10 +72,9 @@ private function handleDirectoryMapping(ContainerBuilder $container, string $dir
7172

7273
/** @var Index $document */
7374
$document = $parser->getIndexAnnotation($class);
74-
$indexMapping = $parser->getIndexMetadata($class);
7575
$indexMetadata = $parser->getIndexMetadata($class);
7676

77-
if (!empty($indexMapping)) {
77+
if (!empty($indexMetadata)) {
7878
$indexMetadata['settings'] = array_filter(array_merge_recursive(
7979
$indexMetadata['settings'] ?? [],
8080
[
@@ -99,14 +99,20 @@ private function handleDirectoryMapping(ContainerBuilder $container, string $dir
9999

100100
$indexServiceDefinition = new Definition(IndexService::class, [
101101
$namespace,
102-
$container->getDefinition(Converter::class),
102+
$converterDefinition,
103103
$container->getDefinition('event_dispatcher'),
104-
$container->getDefinition('serializer'),
105104
$indexSettings,
106105
$container->getParameter(Configuration::ONGR_PROFILER_CONFIG)
107106
? $container->getDefinition('ongr.esb.tracer') : null
108107
]);
109108
$indexServiceDefinition->setPublic(true);
109+
$converterDefinition->addMethodCall(
110+
'addClassMetadata',
111+
[
112+
$namespace,
113+
$parser->getPropertyMetadata($class)
114+
]
115+
);
110116

111117
$container->setDefinition($namespace, $indexServiceDefinition);
112118
$this->indexes[$indexAlias] = $namespace;

DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public function getConfigTreeBuilder()
6868

6969
->arrayNode('indexes')
7070
->defaultValue([])
71+
->useAttributeAsKey('namespace')
7172
->info(
7273
'In case you want to override index settings defined in the annotation.' .
7374
' e.g. use env variables instead.'

Mapping/Converter.php

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,107 @@
1111

1212
namespace ONGR\ElasticsearchBundle\Mapping;
1313

14-
use ONGR\ElasticsearchBundle\Annotation\NestedType;
15-
use ONGR\ElasticsearchBundle\Annotation\ObjectType;
16-
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
17-
use Symfony\Component\Serializer\Serializer;
18-
use Symfony\Component\Serializer\SerializerAwareTrait;
19-
use Symfony\Component\Serializer\SerializerInterface;
14+
use ONGR\ElasticsearchBundle\Result\ObjectIterator;
2015

2116
/**
2217
* This class converts array to document object.
2318
*/
2419
class Converter
2520
{
26-
use SerializerAwareTrait;
21+
private $propertyMetadata = [];
2722

28-
private $documentParser;
23+
public function addClassMetadata(string $class, array $metadata): void
24+
{
25+
$this->propertyMetadata[$class] = $metadata;
26+
}
27+
28+
public function convertArrayToDocument(string $namespace, array $raw)
29+
{
30+
if (!isset($this->propertyMetadata[$namespace])) {
31+
throw new \Exception("Cannot convert array to object of class `$class`.");
32+
}
2933

30-
public function __construct(DocumentParser $documentParser)
34+
return $this->denormalize($raw, $namespace);
35+
}
36+
37+
public function convertDocumentToArray($document): array
3138
{
32-
$this->documentParser = $documentParser;
39+
$class = get_class($document);
40+
41+
if (!isset($this->propertyMetadata[$class])) {
42+
throw new \Exception("Cannot convert object of class `$class` to array.");
43+
}
44+
45+
return $this->normalize($document);
3346
}
3447

35-
public function convertArrayToDocument(string $namespace, array $raw, Serializer $serializer)
48+
protected function normalize($document, $metadata = null)
3649
{
37-
return $serializer->denormalize($raw, $namespace);
50+
$metadata = $metadata ?? $this->propertyMetadata[get_class($document)];
51+
$result = [];
52+
53+
foreach ($metadata as $field => $fieldMeta) {
54+
$getter = $fieldMeta['getter'];
55+
$value = $fieldMeta['public'] ? $document->{$fieldMeta['name']} : $document->$getter();
56+
57+
if ($fieldMeta['embeded']) {
58+
if (is_iterable($value)) {
59+
foreach ($value as $item) {
60+
$result[$field][] = $this->normalize($item, $fieldMeta['sub_properties']);
61+
}
62+
} else {
63+
$result[$field] = $this->normalize($value, $fieldMeta['sub_properties']);
64+
}
65+
} else {
66+
if ($value instanceof \DateTime) {
67+
$value = $value->format(\DateTime::ISO8601);
68+
}
69+
$result[$field] = $value;
70+
}
71+
}
72+
73+
return $result;
3874
}
3975

40-
public function convertDocumentToArray($document, Serializer $serializer): array
76+
protected function denormalize(array $raw, string $namespace)
4177
{
42-
return $serializer->normalize($document, 'array');
78+
$metadata = $this->propertyMetadata[$namespace];
79+
$object = new $namespace();
80+
81+
foreach ($raw as $field => $value) {
82+
$fieldMeta = $metadata[$field];
83+
$setter = $fieldMeta['setter'];
84+
85+
if ($fieldMeta['embeded']) {
86+
$this->addClassMetadata($fieldMeta['class'], $fieldMeta['sub_properties']);
87+
$iterator = new ObjectIterator($fieldMeta['class'], $value, $this);
88+
89+
if ($fieldMeta['public']) {
90+
$object->{$fieldMeta['name']} = $iterator;
91+
} else {
92+
$object->$setter($iterator);
93+
}
94+
} else {
95+
if ($fieldMeta['type'] == 'date') {
96+
$value = \DateTime::createFromFormat(\DateTime::ISO8601, $value) ?: null;
97+
}
98+
if ($fieldMeta['public']) {
99+
$object->{$fieldMeta['name']} = $value;
100+
} else {
101+
if ($fieldMeta['identifier']) {
102+
$setter = function ($field, $value) {
103+
$this->$field = $value;
104+
};
105+
106+
$setter = \Closure::bind($setter, $object, $object);
107+
$setter($fieldMeta['name'], $value);
108+
} else {
109+
$object->$setter($value);
110+
}
111+
}
112+
}
113+
}
114+
115+
return $object;
43116
}
44117
}

Mapping/DocumentParser.php

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Doctrine\Common\Cache\Cache;
1717
use ONGR\ElasticsearchBundle\Annotation\AbstractAnnotation;
1818
use ONGR\ElasticsearchBundle\Annotation\Embedded;
19+
use ONGR\ElasticsearchBundle\Annotation\Id;
1920
use ONGR\ElasticsearchBundle\Annotation\Index;
2021
use ONGR\ElasticsearchBundle\Annotation\NestedType;
2122
use ONGR\ElasticsearchBundle\Annotation\ObjectType;
@@ -150,6 +151,9 @@ private function getClassMetadata(\ReflectionClass $class): array
150151

151152
if ($annotation instanceof Property) {
152153
$fieldMapping['type'] = $annotation->type;
154+
if ($annotation->fields) {
155+
$fieldMapping['fields'] = $annotation->fields;
156+
}
153157
$fieldMapping['analyzer'] = $annotation->analyzer;
154158
$fieldMapping['search_analyzer'] = $annotation->searchAnalyzer;
155159
$fieldMapping['search_quote_analyzer'] = $annotation->searchQuoteAnalyzer;
@@ -186,6 +190,70 @@ private function getClassMetadata(\ReflectionClass $class): array
186190
return $mapping;
187191
}
188192

193+
public function getPropertyMetadata(\ReflectionClass $class, bool $subClass = false): array
194+
{
195+
if ($class->isTrait() || (!$this->reader->getClassAnnotation($class, Index::class) && !$subClass)) {
196+
return [];
197+
}
198+
199+
$metadata = [];
200+
201+
/** @var \ReflectionProperty $property */
202+
foreach ($this->getDocumentPropertiesReflection($class) as $name => $property) {
203+
/** @var AbstractAnnotation $annotation */
204+
foreach ($this->reader->getPropertyAnnotations($property) as $annotation) {
205+
if (!$annotation instanceof PropertiesAwareInterface) {
206+
continue;
207+
}
208+
209+
$propertyMetadata = [
210+
'identifier' => false,
211+
'class' => null,
212+
'embeded' => false,
213+
'type' => null,
214+
'public' => $property->isPublic(),
215+
'getter' => null,
216+
'setter' => null,
217+
'sub_properties' => []
218+
];
219+
220+
$name = $property->getName();
221+
$propertyMetadata['name'] = $name;
222+
223+
if (!$propertyMetadata['public']) {
224+
$propertyMetadata['getter'] = $this->guessGetter($class, $name);
225+
}
226+
227+
if ($annotation instanceof Id) {
228+
$propertyMetadata['identifier'] = true;
229+
} else {
230+
if (!$propertyMetadata['public']) {
231+
$propertyMetadata['setter'] = $this->guessSetter($class, $name);
232+
}
233+
}
234+
235+
if ($annotation instanceof Property) {
236+
// we need the type (and possibly settings?) in Converter::denormalize()
237+
$propertyMetadata['type'] = $annotation->type;
238+
$propertyMetadata['settings'] = $annotation->settings;
239+
}
240+
241+
if ($annotation instanceof Embedded) {
242+
$propertyMetadata['embeded'] = true;
243+
$propertyMetadata['class'] = $annotation->class;
244+
$propertyMetadata['sub_properties'] = $this->getPropertyMetadata(
245+
new \ReflectionClass($annotation->class),
246+
true
247+
);
248+
}
249+
250+
$metadata[$annotation->getName() ?? Caser::snake($name)] = $propertyMetadata;
251+
}
252+
}
253+
254+
return $metadata;
255+
}
256+
189257
public function getAnalysisConfig(\ReflectionClass $class): array
190258
{
191259
$config = [];
@@ -202,7 +270,14 @@ public function getAnalysisConfig(\ReflectionClass $class): array
202270
}
203271
}
204272

205-
foreach (['tokenizer', 'filter', 'normalizer', 'char_filter'] as $type) {
273+
$normalizers = $this->getListFromArrayByKey('normalizer', $mapping);
274+
foreach ($normalizers as $normalizer) {
275+
if (isset($this->analysisConfig['normalizer'][$normalizer])) {
276+
$config['normalizer'][$normalizer] = $this->analysisConfig['normalizer'][$normalizer];
277+
}
278+
}
279+
280+
foreach (['tokenizer', 'filter', 'char_filter'] as $type) {
206281
$list = $this->getListFromArrayByKey($type, $config);
207282

208283
foreach ($list as $listItem) {
@@ -215,6 +290,51 @@ public function getAnalysisConfig(\ReflectionClass $class): array
215290
return $config;
216291
}
217292

293+
protected function guessGetter(\ReflectionClass $class, $name): string
294+
{
295+
if ($class->hasMethod($name)) {
296+
return $name;
297+
}
298+
299+
if ($class->hasMethod('get' . ucfirst($name))) {
300+
return 'get' . ucfirst($name);
301+
}
302+
303+
if ($class->hasMethod('is' . ucfirst($name))) {
304+
return 'is' . ucfirst($name);
305+
}
306+
307+
// if there are underscores in the name convert them to CamelCase
308+
if (strpos($name, '_')) {
309+
$name = Caser::camel($name);
310+
if ($class->hasMethod('get' . ucfirst($name))) {
311+
return 'get' . $name;
312+
}
313+
if ($class->hasMethod('is' . ucfirst($name))) {
314+
return 'is' . $name;
315+
}
316+
}
317+
318+
throw new \Exception("Could not determine a getter for `$name` of class `{$class->getNamespaceName()}`");
319+
}
320+
321+
protected function guessSetter(\ReflectionClass $class, $name): string
322+
{
323+
if ($class->hasMethod('set' . ucfirst($name))) {
324+
return 'set' . ucfirst($name);
325+
}
326+
327+
// if there are underscores in the name convert them to CamelCase
328+
if (strpos($name, '_')) {
329+
$name = Caser::camel($name);
330+
if ($class->hasMethod('set' . ucfirst($name))) {
331+
return 'set' . $name;
332+
}
333+
}
334+
335+
throw new \Exception("Could not determine a setter for `$name` of class `{$class->getNamespaceName()}`");
336+
}
337+
218338
private function getListFromArrayByKey(string $searchKey, array $array): array
219339
{
220340
$list = [];

Mapping/NameConverter.php

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)