Completed
Pull Request — master (#941)
by
unknown
02:20
created

Converter::denormalize()   B

Complexity

Conditions 9
Paths 15

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 43
rs 7.6764
c 0
b 0
f 0
cc 9
nc 15
nop 2
1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ONGR\ElasticsearchBundle\Mapping;
13
14
use ONGR\ElasticsearchBundle\Result\ObjectIterator;
15
16
/**
17
 * This class converts array to document object.
18
 */
19
class Converter
20
{
21
    private $propertyMetadata = [];
22
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
        }
33
34
        return $this->denormalize($raw, $namespace);
35
    }
36
37
    public function convertDocumentToArray($document): array
38
    {
39
        $documentClass = get_class($document);
40
        $class = $this->getConvertableClass($documentClass);
41
42
        if ($class !== null) {
43
            return $this->normalize($document, null, $class);
44
        }
45
46
        throw new \Exception("Cannot convert object of class `$documentClass` to array.");
47
    }
48
49
    public function getConvertableClass($class) {
50
        while ($class) {
51
            if (isset($this->propertyMetadata[$class])) {
52
                return $class;
53
            }
54
55
            $class = get_parent_class($class);
56
        }
57
58
        return null;
59
    }
60
61
    protected function normalize($document, $metadata = null, $class = null)
62
    {
63
        $class = $class ?? get_class($document);
64
        $metadata = $metadata ?? $this->propertyMetadata[$class];
65
        $result = [];
66
67
        foreach ($metadata as $field => $fieldMeta) {
68
            $getter = $fieldMeta['getter'];
69
            $value = $fieldMeta['public'] ? $document->{$fieldMeta['name']} : $document->$getter();
70
71
            if ($fieldMeta['embeded']) {
72
                if (is_iterable($value)) {
73
                    foreach ($value as $item) {
74
                        if ($item) {
75
                            $result[$field][] = $this->normalize($item, $fieldMeta['sub_properties']);
76
                        }
77
                    }
78
                } else {
79
                    if ($value) {
80
                        $result[$field] = $this->normalize($value, $fieldMeta['sub_properties']);
81
                    }
82
                }
83
            } else {
84
                if ($value instanceof \DateTime) {
85
                    $value = $value->format(\DateTime::ISO8601);
86
                }
87
                $result[$field] = $value;
88
            }
89
        }
90
91
        return $result;
92
    }
93
94
    protected function denormalize(array $raw, string $namespace)
95
    {
96
        $metadata = $this->propertyMetadata[$namespace];
97
        $object = new $namespace();
98
99
        foreach ($raw as $field => $value) {
100
            $fieldMeta = $metadata[$field];
101
            $setter = $fieldMeta['setter'];
102
103
            if ($fieldMeta['embeded']) {
104
                $this->addClassMetadata($fieldMeta['class'], $fieldMeta['sub_properties']);
105
                $iterator = new ObjectIterator($fieldMeta['class'], $value, $this);
106
107
                if ($fieldMeta['public']) {
108
                    $object->{$fieldMeta['name']} = $iterator;
109
                } else {
110
                    $object->$setter($iterator);
111
                }
112
            } else {
113
                if ($fieldMeta['type'] == 'date') {
114
                    $value = \DateTime::createFromFormat(\DateTime::ISO8601, $value) ?: null;
115
                }
116
                if ($fieldMeta['public']) {
117
                    $object->{$fieldMeta['name']} = $value;
118
                } else {
119
                    if ($fieldMeta['identifier']) {
120
                        $setter = function ($field, $value) {
121
                            $this->$field = $value;
122
                        };
123
124
                        $setter = \Closure::bind($setter, $object, $object);
125
                        $setter($fieldMeta['name'], $value);
126
                    } else {
127
                        if ($setter) {
128
                            $object->$setter($value);
129
                        }
130
                    }
131
                }
132
            }
133
        }
134
135
        return $object;
136
    }
137
}
138