Skip to content

Commit 9fbc6d0

Browse files
authored
Merge pull request #889 from einorler/serializer
Serialization makeover
2 parents a2eabad + 4c76fe5 commit 9fbc6d0

File tree

16 files changed

+211
-162
lines changed

16 files changed

+211
-162
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;

Mapping/Converter.php

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,101 @@
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($item, $fieldMeta['sub_properties']);
64+
}
65+
} else {
66+
$result[$field] = $value;
67+
}
68+
}
69+
70+
return $result;
3871
}
3972

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

Mapping/DocumentParser.php

Lines changed: 86 additions & 0 deletions
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;
@@ -186,6 +187,65 @@ private function getClassMetadata(\ReflectionClass $class): array
186187
return $mapping;
187188
}
188189

190+
public function getPropertyMetadata(\ReflectionClass $class, bool $subClass = false): array
191+
{
192+
if ($class->isTrait() || (!$this->reader->getClassAnnotation($class, Index::class) && !$subClass)) {
193+
return [];
194+
}
195+
196+
$metadata = [];
197+
198+
/** @var \ReflectionProperty $property */
199+
foreach ($this->getDocumentPropertiesReflection($class) as $name => $property) {
200+
/** @var AbstractAnnotation $annotation */
201+
foreach ($this->reader->getPropertyAnnotations($property) as $annotation) {
202+
if (!$annotation instanceof PropertiesAwareInterface) {
203+
continue;
204+
}
205+
206+
$propertyMetadata = [
207+
'identifier' => false,
208+
'class' => null,
209+
'embeded' => false,
210+
'public' => $property->isPublic(),
211+
'getter' => null,
212+
'setter' => null,
213+
'sub_properties' => []
214+
];
215+
216+
$name = $property->getName();
217+
$propertyMetadata['name'] = $name;
218+
219+
if (!$propertyMetadata['public']) {
220+
$propertyMetadata['getter'] = $this->guessGetter($class, $name);
221+
}
222+
223+
$fieldMapping = $annotation->getSettings();
224+
225+
if ($annotation instanceof Id) {
226+
$propertyMetadata['identifier'] = true;
227+
} else {
228+
if (!$propertyMetadata['public']) {
229+
$propertyMetadata['setter'] = $this->guessSetter($class, $name);
230+
}
231+
}
232+
233+
if ($annotation instanceof Embedded) {
234+
$propertyMetadata['embeded'] = true;
235+
$propertyMetadata['class'] = $annotation->class;
236+
$propertyMetadata['sub_properties'] = $this->getPropertyMetadata(
237+
new \ReflectionClass($annotation->class),
238+
true
239+
);
240+
}
241+
242+
$metadata[$annotation->getName() ?? Caser::snake($name)] = $propertyMetadata;
243+
}
244+
}
245+
246+
return $metadata;
247+
}
248+
189249
public function getAnalysisConfig(\ReflectionClass $class): array
190250
{
191251
$config = [];
@@ -215,6 +275,32 @@ public function getAnalysisConfig(\ReflectionClass $class): array
215275
return $config;
216276
}
217277

278+
protected function guessGetter(\ReflectionClass $class, $name): string
279+
{
280+
if ($class->hasMethod($name)) {
281+
return $name;
282+
}
283+
284+
if ($class->hasMethod('get' . ucfirst($name))) {
285+
return 'get' . ucfirst($name);
286+
}
287+
288+
if ($class->hasMethod('is' . ucfirst($name))) {
289+
return 'is' . ucfirst($name);
290+
}
291+
292+
throw new \Exception("Could not determine a getter for `$name` of class `{$class->getNamespaceName()}`");
293+
}
294+
295+
protected function guessSetter(\ReflectionClass $class, $name): string
296+
{
297+
if ($class->hasMethod('set' . ucfirst($name))) {
298+
return 'set' . ucfirst($name);
299+
}
300+
301+
throw new \Exception("Could not determine a setter for `$name` of class `{$class->getNamespaceName()}`");
302+
}
303+
218304
private function getListFromArrayByKey(string $searchKey, array $array): array
219305
{
220306
$list = [];

Mapping/NameConverter.php

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

Mapping/ObjectNormalizer.php

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

Resources/config/services.yml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,11 @@ services:
2121
ONGR\ElasticsearchBundle\Service\ExportService: ~
2222
ONGR\ElasticsearchBundle\Service\ImportService: ~
2323
ONGR\ElasticsearchBundle\Service\IndexSuffixFinder: ~
24-
25-
ONGR\ElasticsearchBundle\Mapping\ObjectNormalizer:
26-
arguments: ["@ongr.esb.cache", '@ONGR\ElasticsearchBundle\Mapping\Converter', '@ONGR\ElasticsearchBundle\Mapping\NameConverter']
27-
tags:
28-
- { name: serializer.normalizer, priority: 100}
29-
30-
ONGR\ElasticsearchBundle\Mapping\NameConverter:
31-
arguments: ["@ongr.esb.cache"]
24+
ONGR\ElasticsearchBundle\Mapping\Converter: ~
3225

3326
ONGR\ElasticsearchBundle\Mapping\DocumentParser:
3427
arguments: ["@ongr.esb.cache_reader", "@ongr.esb.cache", "%ongr.esb.analysis%"]
3528

36-
ONGR\ElasticsearchBundle\Mapping\Converter:
37-
arguments: ['@ONGR\ElasticsearchBundle\Mapping\DocumentParser']
38-
3929
ONGR\ElasticsearchBundle\Profiler\Handler\CollectionHandler:
4030
public: false
4131

0 commit comments

Comments
 (0)