Completed
Pull Request — master (#941)
by
unknown
01:40
created

Converter::convertDocumentToArray()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 1
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
                        $result[$field][] = $this->normalize($item, $fieldMeta['sub_properties']);
75
                    }
76
                } else {
77
                    $result[$field] = $this->normalize($value, $fieldMeta['sub_properties']);
78
                }
79
            } else {
80
                if ($value instanceof \DateTime) {
81
                    $value = $value->format(\DateTime::ISO8601);
82
                }
83
                $result[$field] = $value;
84
            }
85
        }
86
87
        return $result;
88
    }
89
90
    protected function denormalize(array $raw, string $namespace)
91
    {
92
        $metadata = $this->propertyMetadata[$namespace];
93
        $object = new $namespace();
94
95
        foreach ($raw as $field => $value) {
96
            $fieldMeta = $metadata[$field];
97
            $setter = $fieldMeta['setter'];
98
99
            if ($fieldMeta['embeded']) {
100
                $this->addClassMetadata($fieldMeta['class'], $fieldMeta['sub_properties']);
101
                $iterator = new ObjectIterator($fieldMeta['class'], $value, $this);
102
103
                if ($fieldMeta['public']) {
104
                    $object->{$fieldMeta['name']} = $iterator;
105
                } else {
106
                    $object->$setter($iterator);
107
                }
108
            } else {
109
                if ($fieldMeta['type'] == 'date') {
110
                    $value = \DateTime::createFromFormat(\DateTime::ISO8601, $value) ?: null;
111
                }
112
                if ($fieldMeta['public']) {
113
                    $object->{$fieldMeta['name']} = $value;
114
                } else {
115
                    if ($fieldMeta['identifier']) {
116
                        $setter = function ($field, $value) {
117
                            $this->$field = $value;
118
                        };
119
120
                        $setter = \Closure::bind($setter, $object, $object);
121
                        $setter($fieldMeta['name'], $value);
122
                    } else {
123
                        $object->$setter($value);
124
                    }
125
                }
126
            }
127
        }
128
129
        return $object;
130
    }
131
}
132