Passed
Pull Request — master (#88)
by
unknown
12:16
created

MongoIdCast::castArray()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 31
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 0
cts 22
cp 0
rs 8.439
c 0
b 0
f 0
cc 6
eloc 24
nc 6
nop 2
crap 42
1
<?php
2
namespace Fathomminds\Rest\Database\MongoDB;
3
4
use Fathomminds\Rest\Schema\TypeValidators\ArrayValidator;
5
use Fathomminds\Rest\Schema\TypeValidators\MongoIdValidator;
6
use MongoDB\BSON\ObjectId;
7
8
9
class MongoIdCast
10
{
11
    private const TYPE_SCHEMA = "TYPE_SCHEMA";
12
    private const TYPE_ARRAY = "TYPE_ARRAY";
13
    private const TYPE_MONGOID = "TYPE_MONGOID";
14
    private const TYPE_OTHER = "TYPE_OTHER";
15
16
    private const WAY_NOT_SET = "WAY_NOT_SET";
17
    private const WAY_TO_MONGO_ID = "WAY_TO_MONGO_ID";
18
    private const WAY_TO_STRING = "WAY_TO_STRING";
19
20
    private $way;
21
22
    public function __construct()
23
    {
24
        $this->resetWay();
25
    }
26
27
    private function resetWay()
28
    {
29
        $this->way = self::WAY_NOT_SET;
30
    }
31
32
    private function toMongoId()
33
    {
34
        $this->way = self::WAY_TO_MONGO_ID;
35
    }
36
37
    private function toString()
38
    {
39
        $this->way = self::WAY_TO_STRING;
40
    }
41
42
    public function castSingleValueToMongoId($propertyName, $propertyValue, $schema)
43
    {
44
        $propertyType = $this->getPropertyType($propertyName, $schema);
45
        if ($propertyType === self::TYPE_MONGOID) {
46
            return new ObjectId($propertyValue);
47
        }
48
        return $propertyValue;
49
    }
50
51
    public function castToMongoId($object, $schema)
52
    {
53
        $this->toMongoId();
54
        $result = $this->cast($object, $schema);
55
        $this->resetWay();
56
        return $result;
57
    }
58
59
    public function castToString($object, $schema)
60
    {
61
        $this->toString();
62
        $result = $this->cast($object, $schema);
63
        $this->resetWay();
64
        return $result;
65
    }
66
67
    private function cast($object, $schema)
68
    {
69
        if (!is_object($object)) {
70
            return $object;
71
        }
72
        return $this->castSchema($object, $schema);
73
    }
74
75
    private function castSchema($object, $schema)
76
    {
77
        $properties = get_object_vars($object);
78
        foreach ($properties as $propertyName => $propertyValue) {
79
            $propertyType = $this->getPropertyType($propertyName, $schema);
80
            switch ($propertyType) {
81
                case self::TYPE_MONGOID:
82
                    $object->{$propertyName} = $this->castMongoId($propertyValue);
83
                    break;
84
                case self::TYPE_SCHEMA:
85
                    $schemaName = $schema[$propertyName]['validator']['class'];
86
                    $object->{$propertyName} = $this->castSchema(
87
                        $propertyValue,
88
                        (new $schemaName())->schema()
89
                    );
90
                    break;
91
                case self::TYPE_ARRAY:
92
                    $itemDetails = $schema[$propertyName]['validator']['params']['item'];
93
                    $object->{$propertyName} = $this->castArray(
94
                        $propertyValue,
95
                        $itemDetails
96
                    );
97
                    break;
98
                default:
99
                    $object->{$propertyName} = $propertyValue;
100
            }
101
        }
102
        return $object;
103
    }
104
105
    private function getPropertyType($propertyName, $schema)
106
    {
107
        if (array_key_exists('type', $schema[$propertyName]) && $schema[$propertyName]['type'] === 'schema') {
108
            return self::TYPE_SCHEMA;
109
        }
110
        if ($schema[$propertyName]['validator']['class'] === ArrayValidator::class) {
111
            return self::TYPE_ARRAY;
112
        }
113
        if ($schema[$propertyName]['validator']['class'] === MongoIdValidator::class) {
114
            return self::TYPE_MONGOID;
115
        }
116
        return self::TYPE_OTHER;
117
    }
118
119
    private function getArrayItemType($itemDetails)
120
    {
121
        if (array_key_exists('type', $itemDetails) && $itemDetails['type'] === 'schema') {
122
            return self::TYPE_SCHEMA;
123
        }
124
        if ($itemDetails['validator']['class'] === ArrayValidator::class) {
125
            return self::TYPE_ARRAY;
126
        }
127
        if ($itemDetails['validator']['class'] === MongoIdValidator::class) {
128
            return self::TYPE_MONGOID;
129
        }
130
        return self::TYPE_OTHER;
131
    }
132
133
    private function castMongoId($value)
134
    {
135
        if ($this->way === self::WAY_TO_STRING) {
136
            return (string)$value;
137
        }
138
        if ($this->way === self::WAY_TO_MONGO_ID) {
139
            return new ObjectId($value);
140
        }
141
        return $value;
142
    }
143
144
    private function castArray($array, $itemDetails)
145
    {
146
        $itemType = $this->getArrayItemType($itemDetails);
147
        if ($itemType === self::TYPE_OTHER) {
148
            return $array;
149
        }
150
        foreach ($array as $key => $item) {
151
            switch ($itemType) {
152
                case self::TYPE_MONGOID:
153
                    $array[$key] = $this->castMongoId($item);
154
                    break;
155
                case self::TYPE_SCHEMA:
156
                    $schemaName = $itemDetails['validator']['class'];
157
                    $array[$key] = $this->castSchema(
158
                        $item,
159
                        (new $schemaName())->schema()
160
                    );
161
                    break;
162
                case self::TYPE_ARRAY:
163
                    $nestedItemDetails = $itemDetails['validator']['params']['item'];
164
                    $array[$key] = $this->castArray(
165
                        $item,
166
                        $nestedItemDetails
167
                    );
168
                    break;
169
                default:
170
                    $array[$key] = $item;
171
            }
172
        }
173
        return $array;
174
    }
175
}