Completed
Push — master ( 70fc90...53ed7f )
by Andreas
04:50
created

TypeConverter::toLegacy()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 6
nop 1
dl 0
loc 18
ccs 14
cts 14
cp 1
crap 5
rs 8.8571
c 0
b 0
f 0
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 163
    public static function fromLegacy($value)
40
    {
41 163
        switch (true) {
42 163
            case $value instanceof TypeInterface:
43 127
                return $value->toBSONType();
44 162
            case $value instanceof BSON\Type:
45 36
                return $value;
46 162
            case is_array($value):
47 162
            case is_object($value);
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
48 162
                $result = [];
49
50 162
                foreach ($value as $key => $item) {
51 159
                    $result[$key] = self::fromLegacy($item);
52 162
                }
53
54 162
                return self::ensureCorrectType($result, is_object($value));
55 153
            default:
56 153
                return $value;
57 153
        }
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 69
    public static function toLegacy($value)
74
    {
75 69
        switch (true) {
76 69
            case $value instanceof BSON\Type:
77 62
                return self::convertBSONObjectToLegacy($value);
78 61
            case is_array($value):
79 61
            case is_object($value):
80 5
                $result = [];
81
82 5
                foreach ($value as $key => $item) {
83 5
                    $result[$key] = self::toLegacy($item);
84 5
                }
85
86 5
                return $result;
87 60
            default:
88 60
                return $value;
89 60
        }
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
101
     *
102
     * @throws \MongoException
103
     */
104 58
    public static function convertProjection($fields)
105
    {
106 58
        if (! is_array($fields) || $fields === []) {
107 24
            return [];
108
        }
109
110 39
        if (! TypeConverter::isNumericArray($fields)) {
111 35
            $projection = TypeConverter::fromLegacy($fields);
112 35
        } else {
113 4
            $projection = array_fill_keys(
114 4
                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
                true
122 3
            );
123
        }
124
125 38
        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 167
    public static function isNumericArray(array $array)
140
    {
141 167
        if ($array === []) {
142 25
            return true;
143
        }
144
145 162
        $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]
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
148 162
        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 62
    private static function convertBSONObjectToLegacy(BSON\Type $value)
158
    {
159 62
        switch (true) {
160 62
            case $value instanceof BSON\ObjectID:
161 40
                return new \MongoId($value);
162 56
            case $value instanceof BSON\Binary:
163 6
                return new \MongoBinData($value);
164 56
            case $value instanceof BSON\Javascript:
165
                return new \MongoCode($value);
166 56
            case $value instanceof BSON\MaxKey:
167
                return new \MongoMaxKey();
168 56
            case $value instanceof BSON\MinKey:
169
                return new \MongoMinKey();
170 56
            case $value instanceof BSON\Regex:
171
                return new \MongoRegex($value);
172 56
            case $value instanceof BSON\Timestamp:
173
                return new \MongoTimestamp($value);
174 56
            case $value instanceof BSON\UTCDatetime:
175 8
                return new \MongoDate($value);
176 56
            case $value instanceof Model\BSONDocument:
177 56
            case $value instanceof Model\BSONArray:
178 56
                return array_map(
179 56
                    ['self', 'toLegacy'],
180 56
                    $value->getArrayCopy()
181 56
                );
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 162
    private static function ensureCorrectType(array $array, $wasObject = false)
195
    {
196 162
        if ($wasObject || ! static::isNumericArray($array)) {
197 158
            return new Model\BSONDocument($array);
198
        }
199
200 41
        return $array;
201
    }
202
}
203