Completed
Push — master ( 45d3b1...40b0e0 )
by Rafael
04:30
created

ObjectFieldResolver::__invoke()   C

Complexity

Conditions 15
Paths 64

Size

Total Lines 71
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 16.1191

Importance

Changes 0
Metric Value
dl 0
loc 71
ccs 34
cts 41
cp 0.8293
rs 5.545
c 0
b 0
f 0
cc 15
eloc 44
nc 64
nop 4
crap 16.1191

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Resolver;
12
13
use Doctrine\Common\Collections\Collection;
14
use Doctrine\Common\Persistence\Proxy;
15
use GraphQL\Deferred;
16
use GraphQL\Error\Error;
17
use GraphQL\Type\Definition\ResolveInfo;
18
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
19
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
20
use Symfony\Component\DependencyInjection\ContainerInterface;
21
use Symfony\Component\PropertyAccess\PropertyAccessor;
22
use Ynlo\GraphQLBundle\Definition\FieldDefinition;
23
use Ynlo\GraphQLBundle\Definition\FieldsAwareDefinitionInterface;
24
use Ynlo\GraphQLBundle\Definition\QueryDefinition;
25
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
26
use Ynlo\GraphQLBundle\Model\ID;
27
use Ynlo\GraphQLBundle\Model\NodeInterface;
28
use Ynlo\GraphQLBundle\Type\Definition\EndpointAwareInterface;
29
use Ynlo\GraphQLBundle\Type\Definition\EndpointAwareTrait;
30
use Ynlo\GraphQLBundle\Type\Types;
31
32
/**
33
 * Default resolver for all object fields
34
 */
35
class ObjectFieldResolver implements ContainerAwareInterface, EndpointAwareInterface
36
{
37
    use ContainerAwareTrait;
38
    use EndpointAwareTrait;
39
40
    /**
41
     * @var FieldsAwareDefinitionInterface
42
     */
43
    protected $definition;
44
45
    /**
46
     * @var DeferredBuffer
47
     */
48
    protected $deferredBuffer;
49
50
    /**
51
     * @var int
52
     */
53
    private static $concurrentUsages;
54
55
    /**
56
     * ObjectFieldResolver constructor.
57
     *
58
     * @param ContainerInterface             $container
59
     * @param Endpoint                       $endpoint
60
     * @param FieldsAwareDefinitionInterface $definition
61
     */
62 22
    public function __construct(ContainerInterface $container, Endpoint $endpoint, FieldsAwareDefinitionInterface $definition)
63
    {
64 22
        $this->definition = $definition;
65 22
        $this->container = $container;
66 22
        $this->endpoint = $endpoint;
67 22
        $this->deferredBuffer = $container->get(DeferredBuffer::class);
68 22
    }
69
70
    /**
71
     * @param mixed       $root
72
     * @param array       $args
73
     * @param mixed       $context
74
     * @param ResolveInfo $info
75
     *
76
     * @return mixed|null|string
77
     *
78
     * @throws Error
79
     */
80 22
    public function __invoke($root, array $args, $context, ResolveInfo $info)
81
    {
82 22
        $value = null;
83 22
        $fieldDefinition = $this->definition->getField($info->fieldName);
84 22
        $this->verifyConcurrentUsage($fieldDefinition);
85
86
        //when use external resolver or use a object method with arguments
87 22
        if ($fieldDefinition->getResolver() || $fieldDefinition->getArguments()) {
88 19
            $queryDefinition = new QueryDefinition();
89 19
            $queryDefinition->setName($fieldDefinition->getName());
90 19
            $queryDefinition->setType($fieldDefinition->getType());
91 19
            $queryDefinition->setNode($fieldDefinition->getNode());
92 19
            $queryDefinition->setArguments($fieldDefinition->getArguments());
93 19
            $queryDefinition->setList($fieldDefinition->isList());
94 19
            $queryDefinition->setMetas($fieldDefinition->getMetas());
95
96 19
            if (!$fieldDefinition->getResolver()) {
97
                if ($fieldDefinition->getOriginType() === \ReflectionMethod::class) {
98
                    $queryDefinition->setResolver($fieldDefinition->getOriginName());
99
                }
100
            } else {
101 19
                $queryDefinition->setResolver($fieldDefinition->getResolver());
102
            }
103
104 19
            $resolver = new ResolverExecutor($this->container, $this->endpoint, $queryDefinition);
105 19
            $value = $resolver($root, $args, $context, $info);
106
        } else {
107 22
            $accessor = new PropertyAccessor(true);
108 22
            $originName = $fieldDefinition->getOriginName() ?? $fieldDefinition->getName();
109 22
            $value = $accessor->getValue($root, $originName);
110
        }
111
112 22
        if (null !== $value && Types::ID === $fieldDefinition->getType()) {
113
            //ID are formed with base64 representation of the Types and real database ID
114
            //in order to create a unique and global identifier for each resource
115
            //@see https://facebook.github.io/relay/docs/graphql-object-identification.html
116 17
            if (is_array($value)) {
117
                foreach ($value as &$val) {
118
                    if ($val instanceof ID) {
119
                        $val = (string) $val;
120
                    } else {
121
                        $val = (string) new ID($this->definition->getName(), $val);
122
                    }
123
                }
124
                unset($val);
125
            } else {
126 17
                if ($value instanceof ID) {
127 2
                    $value = (string) $value;
128
                } else {
129 16
                    $value = (string) new ID($this->definition->getName(), $value);
130
                }
131
            }
132
        }
133
134 22
        if ($value instanceof Collection) {
135 3
            $value = $value->toArray();
136
        }
137
138 22
        if ($value instanceof Proxy && $value instanceof NodeInterface && !$value->__isInitialized()) {
139 4
            $this->deferredBuffer->add($value);
140
141 4
            return new Deferred(
142 4
                function () use ($value) {
143 4
                    $this->deferredBuffer->loadBuffer();
144
145 4
                    return $this->deferredBuffer->getLoadedEntity($value);
146 4
                }
147
            );
148
        }
149
150 22
        return $value;
151
    }
152
153
    /**
154
     * @param FieldDefinition $definition
155
     *
156
     * @throws Error
157
     */
158 22
    private function verifyConcurrentUsage(FieldDefinition $definition)
159
    {
160 22
        if ($maxConcurrentUsage = $definition->getMaxConcurrentUsage()) {
161 2
            $oid = spl_object_hash($definition);
162 2
            $usages = static::$concurrentUsages[$oid] ?? 1;
0 ignored issues
show
Bug introduced by
Since $concurrentUsages is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $concurrentUsages to at least protected.
Loading history...
163 2
            if ($usages > $maxConcurrentUsage) {
164 1
                if (1 === $maxConcurrentUsage) {
165 1
                    $error = sprintf(
166 1
                        'The field "%s" can be fetched only once per query. This field can`t be used in a list.',
167 1
                        $definition->getName()
168
                    );
169
                } else {
170
                    $error = sprintf(
171
                        'The field "%s" can`t be fetched more than %s times per query.',
172
                        $definition->getName(),
173
                        $maxConcurrentUsage
174
                    );
175
                }
176 1
                throw new Error($error);
177
            }
178 1
            static::$concurrentUsages[$oid] = $usages + 1;
179
        }
180 22
    }
181
}
182