Completed
Pull Request — master (#572)
by Tim
02:43
created

Converter::convertToDocument()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 26
rs 8.5806
cc 4
eloc 17
nc 4
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\Result;
13
14
use ONGR\ElasticsearchBundle\Collection\Collection;
15
use ONGR\ElasticsearchBundle\Mapping\MetadataCollector;
16
use ONGR\ElasticsearchBundle\Service\Manager;
17
18
/**
19
 * This class converts array to document object.
20
 */
21
class Converter
22
{
23
    /**
24
     * @var MetadataCollector
25
     */
26
    private $metadataCollector;
27
28
    /**
29
     * Constructor.
30
     *
31
     * @param MetadataCollector $metadataCollector
32
     */
33
    public function __construct($metadataCollector)
34
    {
35
        $this->metadataCollector = $metadataCollector;
36
    }
37
38
    /**
39
     * Converts raw array to document.
40
     *
41
     * @param array   $rawData
42
     * @param Manager $manager
43
     *
44
     * @return object
45
     *
46
     * @throws \LogicException
47
     */
48
    public function convertToDocument($rawData, Manager $manager)
49
    {
50
        $types = $this->metadataCollector->getMappings($manager->getConfig()['mappings']);
51
52
        if (isset($types[$rawData['_type']])) {
53
            $metadata = $types[$rawData['_type']];
54
        } else {
55
            throw new \LogicException("Got document of unknown type '{$rawData['_type']}'.");
56
        }
57
58
        switch (true) {
59
            case isset($rawData['_source']):
60
                $rawData = array_merge($rawData, $rawData['_source']);
61
                break;
62
            case isset($rawData['fields']):
63
                $rawData = array_merge($rawData, $rawData['fields']);
64
                break;
65
            default:
66
                // Do nothing.
67
                break;
68
        }
69
70
        $object = $this->assignArrayToObject($rawData, new $metadata['namespace'](), $metadata['aliases']);
71
72
        return $object;
73
    }
74
75
    /**
76
     * Assigns all properties to object.
77
     *
78
     * @param array            $array
79
     * @param \ReflectionClass $object
80
     * @param array            $aliases
81
     *
82
     * @return object
83
     */
84
    public function assignArrayToObject(array $array, $object, array $aliases)
85
    {
86
        foreach ($array as $name => $value) {
87
            if (!isset($aliases[$name])) {
88
                continue;
89
            }
90
91
            if (isset($aliases[$name]['type'])) {
92
                switch ($aliases[$name]['type']) {
93
                    case 'date':
94
                        $epoch = strtotime($value);
95
                        $value = new \DateTime();
96
                        $value->setTimestamp($epoch);
97
                        break;
98
                    case 'object':
99
                    case 'nested':
100
                        if ($aliases[$name]['multiple']) {
101
                            $value = new ObjectIterator($this, $value, $aliases[$name]);
102
                        } else {
103
                            if (!isset($value)) {
104
                                break;
105
                            }
106
                            $value = $this->assignArrayToObject(
107
                                $value,
108
                                new $aliases[$name]['namespace'](),
109
                                $aliases[$name]['aliases']
110
                            );
111
                        }
112
                        break;
113
                    default:
114
                        // Do nothing here. Default cas is required by our code style standard.
115
                        break;
116
                }
117
            }
118
119 View Code Duplication
            if ($aliases[$name]['propertyType'] == 'private') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
120
                $object->{$aliases[$name]['methods']['setter']}($value);
121
            } else {
122
                $object->{$aliases[$name]['propertyName']} = $value;
123
            }
124
        }
125
126
        return $object;
127
    }
128
129
    /**
130
     * Converts object to an array.
131
     *
132
     * @param mixed $object
133
     * @param array $aliases
134
     * @param array $fields
135
     *
136
     * @return array
137
     */
138
    public function convertToArray($object, $aliases = [], $fields = [])
139
    {
140
        if (empty($aliases)) {
141
            $aliases = $this->getAlias($object);
142
            if (count($fields) > 0) {
143
                $aliases = array_intersect_key($aliases, array_flip($fields));
144
            }
145
        }
146
147
        $array = [];
148
149
        // Variable $name defined in client.
150
        foreach ($aliases as $name => $alias) {
151 View Code Duplication
            if ($aliases[$name]['propertyType'] == 'private') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
                $value = $object->{$aliases[$name]['methods']['getter']}();
153
            } else {
154
                $value = $object->{$aliases[$name]['propertyName']};
155
            }
156
157
            if (isset($value)) {
158
                if (array_key_exists('aliases', $alias)) {
159
                    $new = [];
160
                    if ($alias['multiple']) {
161
                        $this->isCollection($aliases[$name]['propertyName'], $value);
162
                        foreach ($value as $item) {
163
                            $this->checkVariableType($item, [$alias['namespace']]);
164
                            $new[] = $this->convertToArray($item, $alias['aliases']);
165
                        }
166
                    } else {
167
                        $this->checkVariableType($value, [$alias['namespace']]);
168
                        $new = $this->convertToArray($value, $alias['aliases']);
169
                    }
170
                    $value = $new;
171
                }
172
173
                if ($value instanceof \DateTime) {
174
                    $value = $value->format(isset($alias['format']) ? $alias['format'] : \DateTime::ISO8601);
175
                }
176
177
                $array[$name] = $value;
178
            }
179
        }
180
181
        return $array;
182
    }
183
184
    /**
185
     * Check if class matches the expected one.
186
     *
187
     * @param object $object
188
     * @param array  $expectedClasses
189
     *
190
     * @throws \InvalidArgumentException
191
     */
192
    private function checkVariableType($object, array $expectedClasses)
193
    {
194
        if (!is_object($object)) {
195
            $msg = 'Expected variable of type object, got ' . gettype($object) . ". (field isn't multiple)";
196
            throw new \InvalidArgumentException($msg);
197
        }
198
199
        $class = get_class($object);
200
        if (!in_array($class, $expectedClasses)) {
201
            throw new \InvalidArgumentException("Expected object of type {$expectedClasses[0]}, got {$class}.");
202
        }
203
    }
204
205
    /**
206
     * Check if value is instance of Collection.
207
     *
208
     * @param string $property
209
     * @param mixed  $value
210
     *
211
     * @throws \InvalidArgumentException
212
     */
213
    private function isCollection($property, $value)
214
    {
215
        if (!$value instanceof Collection) {
216
            $got = is_object($value) ? get_class($value) : gettype($value);
217
218
            throw new \InvalidArgumentException(
219
                sprintf('Value of "%s" property must be an instance of Collection, got %s.', $property, $got)
220
            );
221
        }
222
    }
223
224
    /**
225
     * Returns aliases for certain document.
226
     *
227
     * @param object $document
228
     *
229
     * @return array
230
     */
231
    private function getAlias($document)
232
    {
233
        $class = get_class($document);
234
        $documentMapping = $this->metadataCollector->getMapping($class);
235
236
        return $documentMapping['aliases'];
237
    }
238
}
239