Completed
Pull Request — master (#530)
by Mantas
06:01
created

Converter::convertToArray()   C

Complexity

Conditions 11
Paths 45

Size

Total Lines 45
Code Lines 27

Duplication

Lines 5
Ratio 11.11 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 5
loc 45
rs 5.2653
cc 11
eloc 27
nc 45
nop 3

How to fix   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\Mapping\MetadataCollector;
15
use ONGR\ElasticsearchBundle\Service\Manager;
16
17
/**
18
 * This class converts array to document object.
19
 */
20
class Converter
21
{
22
    /**
23
     * @var MetadataCollector
24
     */
25
    private $metadataCollector;
26
27
    /**
28
     * Constructor.
29
     *
30
     * @param MetadataCollector $metadataCollector
31
     */
32
    public function __construct($metadataCollector)
33
    {
34
        $this->metadataCollector = $metadataCollector;
35
    }
36
37
    /**
38
     * Converts raw array to document.
39
     *
40
     * @param array   $rawData
41
     * @param Manager $manager
42
     *
43
     * @return object
44
     *
45
     * @throws \LogicException
46
     */
47
    public function convertToDocument($rawData, Manager $manager)
48
    {
49
        $types = $this->metadataCollector->getMappings($manager->getConfig()['mappings']);
50
51
        if (isset($types[$rawData['_type']])) {
52
            $metadata = $types[$rawData['_type']];
53
        } else {
54
            throw new \LogicException("Got document of unknown type '{$rawData['_type']}'.");
55
        }
56
57
        switch (true) {
58
            case isset($rawData['_source']):
59
                $rawData = array_merge($rawData, $rawData['_source']);
60
                break;
61
            case isset($rawData['fields']):
62
                $rawData = array_merge($rawData, $rawData['fields']);
63
                break;
64
            default:
65
                // Do nothing.
66
                break;
67
        }
68
69
        $object = $this->assignArrayToObject($rawData, new $metadata['namespace'](), $metadata['aliases']);
70
71
        return $object;
72
    }
73
74
    /**
75
     * Assigns all properties to object.
76
     *
77
     * @param array            $array
78
     * @param \ReflectionClass $object
79
     * @param array            $aliases
80
     *
81
     * @return object
82
     */
83
    public function assignArrayToObject(array $array, $object, array $aliases)
84
    {
85
        foreach ($array as $name => $value) {
86
            if (!isset($aliases[$name])) {
87
                continue;
88
            }
89
90
            if (isset($aliases[$name]['type'])) {
91
                switch ($aliases[$name]['type']) {
92
                    case 'date':
93
                        $value = \DateTime::createFromFormat(
94
                            isset($aliases[$name]['format']) ? $aliases[$name]['format'] : \DateTime::ISO8601,
95
                            $value
96
                        );
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->isTraversable($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 object is traversable, throw exception otherwise.
207
     *
208
     * @param mixed $value
209
     *
210
     * @return bool
211
     *
212
     * @throws \InvalidArgumentException
213
     */
214
    private function isTraversable($value)
215
    {
216
        if (!(is_array($value) || (is_object($value) && $value instanceof \Traversable))) {
217
            throw new \InvalidArgumentException("Variable isn't traversable, although field is set to multiple.");
218
        }
219
220
        return true;
221
    }
222
223
    /**
224
     * Returns aliases for certain document.
225
     *
226
     * @param object $document
227
     *
228
     * @return array
229
     *
230
     * @throws \DomainException
231
     */
232
    private function getAlias($document)
233
    {
234
        $class = get_class($document);
235
        $documentMapping = $this->metadataCollector->getMapping($class);
236
        if (is_array($documentMapping) && isset($documentMapping['aliases'])) {
237
            return $documentMapping['aliases'];
238
        }
239
240
        throw new \DomainException("Aliases could not be found for {$class} document.");
241
    }
242
}
243