TypeUtil::resolveObjectType()   B
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 13.125

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 28
ccs 7
cts 14
cp 0.5
rs 8.8333
cc 7
nc 6
nop 2
crap 13.125
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Util;
12
13
use Doctrine\Common\Util\ClassUtils as DoctrineClassUtils;
14
use Doctrine\Common\Inflector\Inflector;
15
use Symfony\Component\PropertyAccess\PropertyAccessor;
16
use Ynlo\GraphQLBundle\Definition\ClassAwareDefinitionInterface;
17
use Ynlo\GraphQLBundle\Definition\InterfaceDefinition;
18
use Ynlo\GraphQLBundle\Definition\PolymorphicDefinitionInterface;
19
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
20
use Ynlo\GraphQLBundle\Model\PolymorphicObjectInterface;
21
use Ynlo\GraphQLBundle\Type\Types;
22
23
/**
24
 * Util to work with GraphQL types
25
 */
26
final class TypeUtil
27
{
28
    /**
29
     * Resolve the object type for given object instance
30
     *
31
     * @param Endpoint $endpoint
32
     * @param mixed    $object
33
     *
34
     * @return null|string
35
     */
36 5
    public static function resolveObjectType(Endpoint $endpoint, $object): ?string
37
    {
38 5
        if ($object instanceof PolymorphicObjectInterface && $object->getConcreteType()) {
39
            return $object->getConcreteType();
40
        }
41
42 5
        $class = DoctrineClassUtils::getClass($object);
43 5
        if (!$endpoint->hasTypeForClass($class)) {
44
            return null;
45
        }
46
47 5
        $types = $endpoint->getTypesForClass($class);
48
49
        //if only one type for given object class return the type
50 5
        if (count($types) === 1) {
51 5
            return $types[0];
52
        }
53
54
        //in case of multiple types using polymorphic definitions
55
        foreach ($types as $type) {
56
            $definition = $endpoint->getType($type);
57
            if ($definition instanceof PolymorphicDefinitionInterface) {
58
                return self::resolveConcreteType($endpoint, $definition, $object);
59
            }
60
        }
61
62
        //as fallback use the first type in the list
63
        return $types[0];
64
    }
65
66
    /**
67
     * Resolve the object type for given object instance when object use polymorphic definitions
68
     *
69
     * @param Endpoint                       $endpoint
70
     * @param PolymorphicDefinitionInterface $definition
71
     * @param mixed                          $object
72
     *
73
     * @return null|string
74
     */
75
    public static function resolveConcreteType(Endpoint $endpoint, PolymorphicDefinitionInterface $definition, $object)
76
    {
77
        //if discriminator map is set is used to get the value type
78
        if ($map = $definition->getDiscriminatorMap()) {
79
            //get concrete type based on property
80
            if ($definition->getDiscriminatorProperty()) {
81
                $property = $definition->getDiscriminatorProperty();
82
                $accessor = new PropertyAccessor();
83
                $propValue = $accessor->getValue($object, $property);
84
                $resolvedType = $map[$propValue] ?? null;
85
            }
86
87
            //get concrete type based on class
88
            if (!$resolvedType) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $resolvedType does not seem to be defined for all execution paths leading up to this point.
Loading history...
89
                $class = DoctrineClassUtils::getClass($object);
90
                $resolvedType = $map[$class] ?? null;
91
            }
92
        }
93
94
        //final solution in case of not mapping is guess type based on class
95
        if (!$resolvedType && $definition instanceof InterfaceDefinition) {
96
            foreach ($definition->getImplementors() as $implementor) {
97
                $implementorDef = $endpoint->getType($implementor);
98
                if ($implementorDef instanceof ClassAwareDefinitionInterface
99
                    && $implementorDef->getClass() === DoctrineClassUtils::getClass($object)) {
100
                    $resolvedType = $implementorDef->getName();
101
                }
102
            }
103
        }
104
105
        if ($endpoint->hasType($resolvedType)) {
106
            $resolvedTypeDefinition = $endpoint->getType($resolvedType);
107
            if ($resolvedTypeDefinition instanceof PolymorphicDefinitionInterface) {
108
                $resolvedType = self::resolveConcreteType($endpoint, $resolvedTypeDefinition, $object);
109
            }
110
        }
111
112
        return $resolvedType;
113
    }
114
115
    /**
116
     * @param string $type
117
     *
118
     * @return bool
119
     */
120 39
    public static function isTypeList($type): bool
121
    {
122 39
        return (bool) preg_match('/^\[([\\\\\w]*)!?\]!?$/', $type);
123
    }
124
125
    /**
126
     * @param string $type
127
     *
128
     * @return bool
129
     */
130 38
    public static function isTypeNonNullList($type): bool
131
    {
132 38
        return (bool) preg_match('/^\[([\\\\\w]*)!\]!?$/', $type);
133
    }
134
135
    /**
136
     * @param string $type
137
     *
138
     * @return bool
139
     */
140 35
    public static function isTypeNonNull($type): bool
141
    {
142 35
        return (bool) preg_match('/!$/', $type);
143
    }
144
145
    /**
146
     * @param string $type
147
     *
148
     * @return string
149
     */
150 39
    public static function normalize($type)
151
    {
152 39
        if (preg_match('/^\[?([\\\\\w]*)!?\]?!?$/', $type, $matches)) {
153 39
            $type = $matches[1];
154
        }
155
156 39
        switch ($type) {
157 39
            case 'bool':
158 39
            case 'boolean':
159 28
                $type = Types::BOOLEAN;
160 28
                break;
161 39
            case 'decimal':
162 39
            case 'float':
163
                $type = Types::FLOAT;
164
                break;
165 39
            case 'int':
166 39
            case 'integer':
167 6
                $type = Types::INT;
168 6
                break;
169 39
            case 'string':
170 32
                $type = Types::STRING;
171 32
                break;
172 38
            case 'id':
173 28
                $type = Types::ID;
174 28
                break;
175 38
            case 'datetime':
176 38
            case 'date_time':
177 28
                $type = Types::DATETIME;
178 28
                break;
179 38
            case 'date':
180
                $type = Types::DATE;
181
                break;
182 38
            case 'time':
183
                $type = Types::TIME;
184
                break;
185 38
            case 'any':
186
                $type = Types::ANY;
187
                break;
188 38
            case 'dynamic':
189 38
            case 'dynamicObject':
190 38
            case 'dynamic_object':
191
                $type = Types::DYNAMIC_OBJECT;
192
                break;
193
        }
194
195 39
        return Inflector::classify($type);
196
    }
197
}
198