TypeConverter   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 90.91%

Importance

Changes 0
Metric Value
dl 0
loc 179
rs 9.84
c 0
b 0
f 0
ccs 60
cts 66
cp 0.9091
wmc 32
lcom 1
cbo 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
B fromLegacy() 0 20 6
A toLegacy() 0 18 5
A convertProjection() 0 23 5
A isNumericArray() 0 11 2
B convertBSONObjectToLegacy() 0 29 11
A ensureCorrectType() 0 8 3
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 */
15
16
namespace Alcaeus\MongoDbAdapter;
17
18
use MongoDB\BSON;
19
use MongoDB\Model;
20
21
/**
22
 * @internal
23
 */
24
class TypeConverter
25
{
26
    /**
27
     * Converts a legacy type to the new BSON type
28
     *
29
     * This method handles type conversion from ext-mongo to ext-mongodb:
30
     *  - For all types (MongoId, MongoDate, etc.) it returns the correct BSON
31
     *    object instance
32
     *  - For arrays and objects it iterates over properties and converts each
33
     *    item individually
34
     *  - For other types it returns the value unconverted
35
     *
36
     * @param mixed $value
37
     * @return mixed
38
     */
39 211
    public static function fromLegacy($value)
40
    {
41
        switch (true) {
42 211
            case $value instanceof TypeInterface:
43 146
                return $value->toBSONType();
44 210
            case $value instanceof BSON\Type:
45 38
                return $value;
46 210
            case is_array($value):
47 202
            case is_object($value):
48 210
                $result = [];
49
50 210
                foreach ($value as $key => $item) {
51 207
                    $result[$key] = self::fromLegacy($item);
52
                }
53
54 210
                return self::ensureCorrectType($result, is_object($value));
55
            default:
56 201
                return $value;
57
        }
58
    }
59
60
    /**
61
     * Converts a BSON type to the legacy types
62
     *
63
     * This method handles type conversion from ext-mongodb to ext-mongo:
64
     *  - For all instances of BSON\Type it returns an object of the
65
     *    corresponding legacy type (MongoId, MongoDate, etc.)
66
     *  - For arrays and objects it iterates over properties and converts each
67
     *    item individually
68
     *  - For other types it returns the value unconverted
69
     *
70
     * @param mixed $value
71
     * @return mixed
72
     */
73 86
    public static function toLegacy($value)
74
    {
75
        switch (true) {
76 86
            case $value instanceof BSON\Type:
77 81
                return self::convertBSONObjectToLegacy($value);
78 78
            case is_array($value):
79 78
            case is_object($value):
80 5
                $result = [];
81
82 5
                foreach ($value as $key => $item) {
83 5
                    $result[$key] = self::toLegacy($item);
84
                }
85
86 5
                return $result;
87
            default:
88 77
                return $value;
89
        }
90
    }
91
92
    /**
93
     * Converts a projection used in find queries.
94
     *
95
     * This method handles conversion from the legacy syntax (e.g. ['x', 'y', 'z'])
96
     * to the new syntax (e.g. ['x' => true, 'y' => true, 'z' => true]). While
97
     * this was never documented, the legacy driver applied the same conversion.
98
     *
99
     * @param array $fields
100
     * @return array|null
101
     *
102
     * @throws \MongoException
103
     */
104 64
    public static function convertProjection($fields)
105
    {
106 64
        if (! is_array($fields) || $fields === []) {
107 28
            return null;
108
        }
109
110 41
        if (! TypeConverter::isNumericArray($fields)) {
111 37
            $projection = TypeConverter::fromLegacy($fields);
112
        } else {
113 4
            $projection = array_fill_keys(
114
                array_map(function ($field) {
115 4
                    if (!is_string($field)) {
116 1
                        throw new \MongoException('field names must be strings', 8);
117
                    }
118
119 3
                    return $field;
120 4
                }, $fields),
121 3
                true
122
            );
123
        }
124
125 40
        return TypeConverter::fromLegacy($projection);
126
    }
127
128
    /**
129
     * Helper method to find out if an array has numerical indexes
130
     *
131
     * For performance reason, this method checks the first array index only.
132
     * More thorough inspection of the array might be needed.
133
     * Note: Returns true for empty arrays to preserve compatibility with empty
134
     * lists.
135
     *
136
     * @param array $array
137
     * @return bool
138
     */
139 215
    public static function isNumericArray(array $array)
140
    {
141 215
        if ($array === []) {
142 27
            return true;
143
        }
144
145 210
        $keys = array_keys($array);
146
        // array_keys gives us a clean numeric array with keys, so we expect an
147
        // array like [0 => 0, 1 => 1, 2 => 2, ..., n => n]
148 210
        return array_values($keys) === array_keys($keys);
149
    }
150
151
    /**
152
     * Converter method to convert a BSON object to its legacy type
153
     *
154
     * @param BSON\Type $value
155
     * @return mixed
156
     */
157 81
    private static function convertBSONObjectToLegacy(BSON\Type $value)
158
    {
159
        switch (true) {
160 81
            case $value instanceof BSON\ObjectID:
161 42
                return new \MongoId($value);
162 75
            case $value instanceof BSON\Binary:
163 6
                return new \MongoBinData($value);
164 75
            case $value instanceof BSON\Javascript:
165
                return new \MongoCode($value);
166 75
            case $value instanceof BSON\MaxKey:
167
                return new \MongoMaxKey();
168 75
            case $value instanceof BSON\MinKey:
169
                return new \MongoMinKey();
170 75
            case $value instanceof BSON\Regex:
171
                return new \MongoRegex($value);
172 75
            case $value instanceof BSON\Timestamp:
173
                return new \MongoTimestamp($value);
174 75
            case $value instanceof BSON\UTCDatetime:
175 8
                return new \MongoDate($value);
176 75
            case $value instanceof Model\BSONDocument:
177 21
            case $value instanceof Model\BSONArray:
178 75
                return array_map(
179 75
                    ['self', 'toLegacy'],
180 75
                    $value->getArrayCopy()
181
                );
182
            default:
183
                return $value;
184
        }
185
    }
186
187
    /**
188
     * Converts all arrays with non-numeric keys to stdClass
189
     *
190
     * @param array $array
191
     * @param bool $wasObject
192
     * @return array|Model\BSONArray|Model\BSONDocument
193
     */
194 210
    private static function ensureCorrectType(array $array, $wasObject = false)
195
    {
196 210
        if ($wasObject || ! static::isNumericArray($array)) {
197 206
            return new Model\BSONDocument($array);
198
        }
199
200 44
        return $array;
201
    }
202
}
203