Completed
Pull Request — master (#628)
by Joshua
02:41
created

Converter::assignArrayToObject()   D

Complexity

Conditions 17
Paths 361

Size

Total Lines 54
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 2 Features 2
Metric Value
c 5
b 2
f 2
dl 0
loc 54
rs 4.8974
cc 17
eloc 36
nc 361
nop 3

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 ($aliases as $name => $alias) {
87
            $value = isset($array[$name]) ? $array[$name] : null;
88
            if ($alias['field'] === true) {
89
                $value = isset($array['fields']) && isset($array['fields'][$name]) ? $array['fields'][$name] : null;
90
91
                // fields are always returned as arrays. We convert to scalar if only one element is present
92
                if (is_array($value) && count($value) == 1) {
93
                    $value = $value[0];
94
                }
95
            }
96
97
            if (isset($alias['type'])) {
98
                switch ($alias['type']) {
99
                    case 'date':
100
                        if (is_numeric($value) && (int)$value == $value) {
101
                            $time = $value;
102
                        } else {
103
                            $time = strtotime($value);
104
                        }
105
                        $value = new \DateTime();
106
                        $value->setTimestamp($time);
107
                        break;
108
                    case 'object':
109
                    case 'nested':
110
                        if ($alias['multiple']) {
111
                            $value = new ObjectIterator($this, $value, $alias);
112
                        } else {
113
                            if (!isset($value)) {
114
                                break;
115
                            }
116
                            $value = $this->assignArrayToObject(
117
                                $value,
118
                                new $alias['namespace'](),
119
                                $alias['aliases']
120
                            );
121
                        }
122
                        break;
123
                    default:
124
                        // Do nothing here. Default cas is required by our code style standard.
125
                        break;
126
                }
127
            }
128
129
            if ($alias['propertyType'] == 'private') {
130
                $object->{$alias['methods']['setter']}($value);
131
            } else {
132
                $object->{$alias['propertyName']} = $value;
133
            }
134
        }
135
136
        return $object;
137
    }
138
139
    /**
140
     * Converts object to an array.
141
     *
142
     * @param mixed $object
143
     * @param array $aliases
144
     * @param array $fields
145
     *
146
     * @return array
147
     */
148
    public function convertToArray($object, $aliases = [], $fields = [])
149
    {
150
        if (empty($aliases)) {
151
            $aliases = $this->getAlias($object);
152
            if (count($fields) > 0) {
153
                $aliases = array_intersect_key($aliases, array_flip($fields));
154
            }
155
        }
156
157
        $array = [];
158
159
        // Variable $name defined in client.
160
        foreach ($aliases as $name => $alias) {
161
            if ($aliases[$name]['propertyType'] == 'private') {
162
                $value = $object->{$aliases[$name]['methods']['getter']}();
163
            } else {
164
                $value = $object->{$aliases[$name]['propertyName']};
165
            }
166
167
            if (isset($value)) {
168
                if (array_key_exists('aliases', $alias)) {
169
                    $new = [];
170
                    if ($alias['multiple']) {
171
                        $this->isCollection($aliases[$name]['propertyName'], $value);
172
                        foreach ($value as $item) {
173
                            $this->checkVariableType($item, [$alias['namespace']]);
174
                            $new[] = $this->convertToArray($item, $alias['aliases']);
175
                        }
176
                    } else {
177
                        $this->checkVariableType($value, [$alias['namespace']]);
178
                        $new = $this->convertToArray($value, $alias['aliases']);
179
                    }
180
                    $value = $new;
181
                }
182
183
                if ($value instanceof \DateTime) {
184
                    $value = $value->format(isset($alias['format']) ? $alias['format'] : \DateTime::ISO8601);
185
                }
186
187
                if (isset($alias['type'])) {
188
                    switch ($alias['type']) {
189 View Code Duplication
                        case 'float':
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...
190
                            if (is_array($value)) {
191
                                foreach ($value as $key => $item) {
192
                                    $value[$key] = (float)$item;
193
                                }
194
                            } else {
195
                                $value = (float)$value;
196
                            }
197
                            break;
198 View Code Duplication
                        case 'integer':
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...
199
                            if (is_array($value)) {
200
                                foreach ($value as $key => $item) {
201
                                    $value[$key] = (int)$item;
202
                                }
203
                            } else {
204
                                $value = (int)$value;
205
                            }
206
                            break;
207
                        default:
208
                            break;
209
                    }
210
                }
211
212
                $array[$name] = $value;
213
            }
214
        }
215
216
        return $array;
217
    }
218
219
    /**
220
     * Check if class matches the expected one.
221
     *
222
     * @param object $object
223
     * @param array  $expectedClasses
224
     *
225
     * @throws \InvalidArgumentException
226
     */
227
    private function checkVariableType($object, array $expectedClasses)
228
    {
229
        if (!is_object($object)) {
230
            $msg = 'Expected variable of type object, got ' . gettype($object) . ". (field isn't multiple)";
231
            throw new \InvalidArgumentException($msg);
232
        }
233
234
        $class = get_class($object);
235
        if (!in_array($class, $expectedClasses)) {
236
            throw new \InvalidArgumentException("Expected object of type {$expectedClasses[0]}, got {$class}.");
237
        }
238
    }
239
240
    /**
241
     * Check if value is instance of Collection.
242
     *
243
     * @param string $property
244
     * @param mixed  $value
245
     *
246
     * @throws \InvalidArgumentException
247
     */
248
    private function isCollection($property, $value)
249
    {
250
        if (!$value instanceof Collection) {
251
            $got = is_object($value) ? get_class($value) : gettype($value);
252
253
            throw new \InvalidArgumentException(
254
                sprintf('Value of "%s" property must be an instance of Collection, got %s.', $property, $got)
255
            );
256
        }
257
    }
258
259
    /**
260
     * Returns aliases for certain document.
261
     *
262
     * @param object $document
263
     *
264
     * @return array
265
     */
266
    private function getAlias($document)
267
    {
268
        $class = get_class($document);
269
        $documentMapping = $this->metadataCollector->getMapping($class);
270
271
        return $documentMapping['aliases'];
272
    }
273
}
274