Passed
Pull Request — master (#211)
by Alex
05:13
created

SerialiserLowLevelWriters   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 29
eloc 87
c 1
b 0
f 0
dl 0
loc 170
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
B writeBagValue() 0 29 10
B writeComplexValue() 0 60 9
A writePrimitiveProperties() 0 18 3
B primitiveToString() 0 22 7
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: alex
5
 * Date: 16/02/20
6
 * Time: 12:12 AM.
7
 */
8
namespace AlgoWeb\PODataLaravel\Serialisers;
9
10
use Illuminate\Database\Eloquent\Model;
11
use POData\Common\InvalidOperationException;
12
use POData\Common\Messages;
13
use POData\ObjectModel\ODataBagContent;
14
use POData\ObjectModel\ODataProperty;
15
use POData\ObjectModel\ODataPropertyContent;
16
use POData\Providers\Metadata\ResourceProperty;
17
use POData\Providers\Metadata\ResourcePropertyKind;
18
use POData\Providers\Metadata\ResourceType;
19
use POData\Providers\Metadata\ResourceTypeKind;
20
use POData\Providers\Metadata\Type\Binary;
21
use POData\Providers\Metadata\Type\Boolean;
22
use POData\Providers\Metadata\Type\DateTime;
23
use POData\Providers\Metadata\Type\IType;
24
use POData\Providers\Metadata\Type\StringType;
25
26
abstract class SerialiserLowLevelWriters
27
{
28
    /**
29
     * @param Model $entryObject
30
     * @param ModelSerialiser $modelSerialiser
31
     * @param $nonRelProp
32
     * @return ODataPropertyContent
33
     * @throws InvalidOperationException
34
     */
35
    public static function writePrimitiveProperties(Model $entryObject, ModelSerialiser $modelSerialiser, $nonRelProp)
36
    {
37
        $propertyContent = new ODataPropertyContent();
38
        $cereal = $modelSerialiser->bulkSerialise($entryObject);
39
        $cereal = array_intersect_key($cereal, $nonRelProp);
40
41
        foreach ($cereal as $corn => $flake) {
42
            $corn = strval($corn);
43
            $rType = $nonRelProp[$corn]['type'];
44
            /** @var ResourceProperty $nrp */
45
            $nrp = $nonRelProp[$corn]['prop'];
46
            $subProp = new ODataProperty();
47
            $subProp->name = $corn;
48
            $subProp->value = isset($flake) ? SerialiserLowLevelWriters::primitiveToString($rType, $flake) : null;
49
            $subProp->typeName = $nrp->getResourceType()->getFullName();
50
            $propertyContent->properties[$corn] = $subProp;
51
        }
52
        return $propertyContent;
53
    }
54
55
    /**
56
     * @param ResourceType $resourceType
57
     * @param $result
58
     * @throws InvalidOperationException
59
     * @throws \ReflectionException
60
     * @return ODataBagContent|null
61
     */
62
    public static function writeBagValue(ResourceType &$resourceType, $result)
63
    {
64
        if (!(null == $result || is_array($result))) {
65
            throw new InvalidOperationException('Bag parameter must be null or array');
66
        }
67
        $typeKind = $resourceType->getResourceTypeKind();
68
        $kVal = $typeKind;
69
        if (!(ResourceTypeKind::PRIMITIVE() == $kVal || ResourceTypeKind::COMPLEX() == $kVal)) {
70
            $msg = '$bagItemResourceTypeKind != ResourceTypeKind::PRIMITIVE'
71
                   .' && $bagItemResourceTypeKind != ResourceTypeKind::COMPLEX';
72
            throw new InvalidOperationException($msg);
73
        }
74
        if (null == $result) {
75
            return null;
76
        }
77
        $bag = new ODataBagContent();
78
        $result = array_filter($result);
79
        foreach ($result as $value) {
80
            if (ResourceTypeKind::PRIMITIVE() == $kVal) {
81
                $instance = $resourceType->getInstanceType();
82
                if (!$instance instanceof IType) {
83
                    throw new InvalidOperationException(get_class($instance));
84
                }
85
                $bag->propertyContents[] = SerialiserLowLevelWriters::primitiveToString($instance, $value);
86
            } elseif (ResourceTypeKind::COMPLEX() == $kVal) {
87
                $bag->propertyContents[] = SerialiserLowLevelWriters::writeComplexValue($resourceType, $value);
88
            }
89
        }
90
        return $bag;
91
    }
92
93
    /**
94
     * @param  ResourceType              $resourceType
95
     * @param  object                    $result
96
     * @param  string|null               $propertyName
97
     * @param  array                     $instanceCollection
98
     * @throws InvalidOperationException
99
     * @throws \ReflectionException
100
     * @return ODataPropertyContent
101
     */
102
    public static function writeComplexValue(
103
        ResourceType &$resourceType,
104
        &$result,
105
        $propertyName = null,
106
        array &$instanceCollection = []
107
    ) {
108
        if (!is_object($result)) {
109
            throw new InvalidOperationException('Supplied $customObject must be an object');
110
        }
111
112
        $count = count($instanceCollection);
113
        for ($i = 0; $i < $count; ++$i) {
114
            if ($instanceCollection[$i] === $result) {
115
                throw new InvalidOperationException(
116
                    Messages::objectModelSerializerLoopsNotAllowedInComplexTypes($propertyName)
117
                );
118
            }
119
        }
120
121
        $instanceCollection[$count] = &$result;
122
123
        $internalContent = new ODataPropertyContent();
124
        $resourceProperties = $resourceType->getAllProperties();
125
        // first up, handle primitive properties
126
        foreach ($resourceProperties as $prop) {
127
            $resourceKind = $prop->getKind();
128
            $propName = $prop->getName();
129
            $internalProperty = new ODataProperty();
130
            $internalProperty->name = $propName;
131
            if (SerialiserUtilities::isMatchPrimitive($resourceKind)) {
0 ignored issues
show
Bug introduced by
$resourceKind of type POData\Providers\Metadata\ResourcePropertyKind is incompatible with the type integer expected by parameter $resourceKind of AlgoWeb\PODataLaravel\Se...ies::isMatchPrimitive(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

131
            if (SerialiserUtilities::isMatchPrimitive(/** @scrutinizer ignore-type */ $resourceKind)) {
Loading history...
132
                $iType = $prop->getInstanceType();
133
                if (!$iType instanceof IType) {
134
                    throw new InvalidOperationException(get_class($iType));
135
                }
136
                $internalProperty->typeName = $iType->getFullTypeName();
137
138
                $rType = $prop->getResourceType()->getInstanceType();
139
                if (!$rType instanceof IType) {
140
                    throw new InvalidOperationException(get_class($rType));
141
                }
142
143
                $internalProperty->value = SerialiserLowLevelWriters::primitiveToString($rType, $result->$propName);
144
145
                $internalContent->properties[$propName] = $internalProperty;
146
            } elseif (ResourcePropertyKind::COMPLEX_TYPE == $resourceKind) {
147
                $rType = $prop->getResourceType();
148
                $internalProperty->typeName = $rType->getFullName();
149
                $internalProperty->value = SerialiserLowLevelWriters::writeComplexValue(
150
                    $rType,
151
                    $result->$propName,
152
                    $propName,
153
                    $instanceCollection
154
                );
155
156
                $internalContent->properties[$propName] = $internalProperty;
157
            }
158
        }
159
160
        unset($instanceCollection[$count]);
161
        return $internalContent;
162
    }
163
164
165
    /**
166
     * Convert the given primitive value to string.
167
     * Note: This method will not handle null primitive value.
168
     *
169
     * @param IType &$type          Type of the primitive property needing conversion
170
     * @param mixed $primitiveValue Primitive value to convert
171
     *
172
     * @return string
173
     */
174
    public static function primitiveToString(IType &$type, $primitiveValue)
175
    {
176
        // kludge to enable switching on type of $type without getting tripped up by mocks as we would with get_class
177
        // switch (true) means we unconditionally enter, and then lean on case statements to match given block
178
        switch (true) {
179
            case $type instanceof StringType:
180
                $stringValue = utf8_encode($primitiveValue);
181
                break;
182
            case $type instanceof Boolean:
183
                $stringValue = (true === $primitiveValue) ? 'true' : 'false';
184
                break;
185
            case $type instanceof Binary:
186
                $stringValue = base64_encode($primitiveValue);
187
                break;
188
            case $type instanceof DateTime && $primitiveValue instanceof \DateTime:
189
                $stringValue = $primitiveValue->format(\DateTime::ATOM);
190
                break;
191
            default:
192
                $stringValue = strval($primitiveValue);
193
        }
194
195
        return $stringValue;
196
    }
197
}
198