Completed
Push — master ( 58b8f7...b71da8 )
by Asmir
23s queued 20s
created

UnionHandler::isPrimitiveType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace JMS\Serializer\Handler;
6
7
use JMS\Serializer\Context;
8
use JMS\Serializer\DeserializationContext;
9
use JMS\Serializer\Exception\NonVisitableTypeException;
10
use JMS\Serializer\Exception\RuntimeException;
11
use JMS\Serializer\GraphNavigatorInterface;
12
use JMS\Serializer\SerializationContext;
13
use JMS\Serializer\Visitor\DeserializationVisitorInterface;
14
use JMS\Serializer\Visitor\SerializationVisitorInterface;
15
16
final class UnionHandler implements SubscribingHandlerInterface
17
{
18
    private static $aliases = ['boolean' => 'bool', 'integer' => 'int', 'double' => 'float'];
0 ignored issues
show
introduced by
The private property $aliases is not used, and could be removed.
Loading history...
19
20
    /**
21
     * {@inheritdoc}
22
     */
23
    public static function getSubscribingMethods()
24
    {
25
        $methods = [];
26
        $formats = ['json', 'xml'];
27
28
        foreach ($formats as $format) {
29
            $methods[] = [
30
                'type' => 'union',
31
                'format' => $format,
32
                'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
33
                'method' => 'deserializeUnion',
34
            ];
35
            $methods[] = [
36
                'type' => 'union',
37
                'format' => $format,
38
                'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
39
                'method' => 'serializeUnion',
40
            ];
41
        }
42
43
        return $methods;
44
    }
45
46
    public function serializeUnion(
47
        SerializationVisitorInterface $visitor,
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed. ( Ignorable by Annotation )

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

47
        /** @scrutinizer ignore-unused */ SerializationVisitorInterface $visitor,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
48
        mixed $data,
49
        array $type,
50
        SerializationContext $context
51
    ): mixed {
52
        if ($this->isPrimitiveType(gettype($data))) {
53
            return $this->matchSimpleType($data, $type, $context);
54
        } else {
55
            $resolvedType = [
56
                'name' => get_class($data),
57
                'params' => [],
58
            ];
59
60
            return $context->getNavigator()->accept($data, $resolvedType);
61
        }
62
    }
63
64
    public function deserializeUnion(DeserializationVisitorInterface $visitor, mixed $data, array $type, DeserializationContext $context): mixed
0 ignored issues
show
Unused Code introduced by
The parameter $visitor is not used and could be removed. ( Ignorable by Annotation )

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

64
    public function deserializeUnion(/** @scrutinizer ignore-unused */ DeserializationVisitorInterface $visitor, mixed $data, array $type, DeserializationContext $context): mixed

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
65
    {
66
        if ($data instanceof \SimpleXMLElement) {
67
            throw new RuntimeException('XML deserialisation into union types is not supported yet.');
68
        }
69
70
        if (3 === count($type['params'])) {
71
            $lookupField = $type['params'][1];
72
            if (empty($data[$lookupField])) {
73
                throw new NonVisitableTypeException(sprintf('Union Discriminator Field "%s" not found in data', $lookupField));
74
            }
75
76
            $unionMap = $type['params'][2];
77
            $lookupValue = $data[$lookupField];
78
            if (empty($unionMap[$lookupValue])) {
79
                throw new NonVisitableTypeException(sprintf('Union Discriminator Map does not contain key "%s"', $lookupValue));
80
            }
81
82
            $finalType = [
83
                'name' => $unionMap[$lookupValue],
84
                'params' => [],
85
            ];
86
87
            return $context->getNavigator()->accept($data, $finalType);
88
        }
89
90
        foreach ($type['params'][0] as $possibleType) {
91
            if ($this->isPrimitiveType($possibleType['name']) && $this->testPrimitive($data, $possibleType['name'], $context->getFormat())) {
92
                return $context->getNavigator()->accept($data, $possibleType);
93
            }
94
        }
95
96
        return null;
97
    }
98
99
    private function matchSimpleType(mixed $data, array $type, Context $context): mixed
100
    {
101
        foreach ($type['params'][0] as $possibleType) {
102
            if ($this->isPrimitiveType($possibleType['name']) && !$this->testPrimitive($data, $possibleType['name'], $context->getFormat())) {
103
                continue;
104
            }
105
106
            try {
107
                return $context->getNavigator()->accept($data, $possibleType);
108
            } catch (NonVisitableTypeException $e) {
109
                continue;
110
            }
111
        }
112
113
        return null;
114
    }
115
116
    private function isPrimitiveType(string $type): bool
117
    {
118
        return in_array($type, ['int', 'integer', 'float', 'double', 'bool', 'boolean', 'string'], true);
119
    }
120
121
    private function testPrimitive(mixed $data, string $type, string $format): bool
0 ignored issues
show
Unused Code introduced by
The parameter $format is not used and could be removed. ( Ignorable by Annotation )

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

121
    private function testPrimitive(mixed $data, string $type, /** @scrutinizer ignore-unused */ string $format): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
122
    {
123
        switch ($type) {
124
            case 'integer':
125
            case 'int':
126
                return (string) (int) $data === (string) $data;
127
128
            case 'double':
129
            case 'float':
130
                return (string) (float) $data === (string) $data;
131
132
            case 'bool':
133
            case 'boolean':
134
                return (string) (bool) $data === (string) $data;
135
136
            case 'string':
137
                return (string) $data === (string) $data;
138
        }
139
140
        return false;
141
    }
142
}
143