SubscriptionAnnotationParser::parse()   F
last analyzed

Complexity

Conditions 19
Paths 354

Size

Total Lines 111
Code Lines 75

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 380

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 75
c 1
b 0
f 0
dl 0
loc 111
ccs 0
cts 94
cp 0
rs 1.7583
cc 19
nc 354
nop 3
crap 380

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\Definition\Loader\Annotation;
12
13
use Ynlo\GraphQLBundle\Annotation;
14
use Ynlo\GraphQLBundle\Definition\FieldDefinition;
15
use Ynlo\GraphQLBundle\Definition\ObjectDefinition;
16
use Ynlo\GraphQLBundle\Definition\Registry\Endpoint;
17
use Ynlo\GraphQLBundle\Definition\SubscriptionDefinition;
18
use Ynlo\GraphQLBundle\Definition\UnionDefinition;
19
use Ynlo\GraphQLBundle\Definition\UnionTypeDefinition;
20
use Ynlo\GraphQLBundle\Subscription\SubscriptionLink;
21
use Ynlo\GraphQLBundle\Util\ClassUtils;
22
use Ynlo\GraphQLBundle\Util\TypeUtil;
23
24
/**
25
 * Parse subscription annotation to fetch definitions
26
 */
27
class SubscriptionAnnotationParser extends QueryAnnotationParser
28
{
29
    /**
30
     * {@inheritdoc}
31
     */
32
    public function supports($annotation): bool
33
    {
34
        return $annotation instanceof Annotation\Subscription;
35
    }
36
37
    /**
38
     * {@inheritdoc}
39
     *
40
     * @param Annotation\Subscription $annotation
41
     */
42
    public function parse($annotation, \ReflectionClass $refClass, Endpoint $endpoint)
43
    {
44
        /** @var Annotation\Subscription $annotation */
45
46
        if (!preg_match('/\\Subscription\\\\/', $refClass->getName())) {
47
            $error = sprintf(
48
                'Annotation "@Subscription" in the class "%s" is not valid, 
49
            mutations can only be applied to classes inside "...Bundle\Subscription\..."',
50
                $refClass->getName()
51
            );
52
            throw new \RuntimeException($error);
53
        }
54
55
        if (!$annotation->resolver && !$refClass->hasMethod('__invoke')) {
56
            $error = sprintf(
57
                'The class "%s" should have a method "__invoke" to process the subscription.',
58
                $refClass->getName()
59
            );
60
            throw new \RuntimeException($error);
61
        }
62
63
        $subscription = new SubscriptionDefinition();
64
        $subscription->setType(TypeUtil::normalize($annotation->payload));
65
66
        if ($annotation->name) {
67
            $subscription->setName($annotation->name);
68
        } else {
69
            $subscription->setName(lcfirst(ClassUtils::getDefaultName($refClass->getName())));
70
        }
71
72
        if (!$subscription->getType()) {
73
            $nodeType = ClassUtils::getNodeFromClass($refClass->getName());
74
            $objectDefinition = null;
75
            if ($nodeType && $endpoint->hasType($nodeType)) {
76
                $objectDefinition = $endpoint->getType($nodeType);
77
            }
78
            if ($objectDefinition) {
79
                $subscription->setType($objectDefinition->getName());
80
                $subscription->setNode($objectDefinition->getName());
81
            } else {
82
                $error = sprintf('Does not exist any valid type for class "%s"', $refClass->getName());
83
                throw new \RuntimeException($error);
84
            }
85
        }
86
87
        $endpoint->addSubscription($subscription);
88
89
        if (!$annotation->payload) {
90
            if (class_exists($refClass->getName().'Payload')) {
91
                $annotation->payload = $refClass->getName().'Payload';
92
                if (!$endpoint->hasTypeForClass($annotation->payload)) {
93
                    $error = sprintf(
94
                        'The payload "%s" exist but does not exist a valid GraphQL type, is missing ObjectType annotation?',
95
                        $annotation->payload
96
                    );
97
                    throw new \RuntimeException($error);
98
                }
99
            }
100
        }
101
102
        // create subscription event
103
        $subscriptionEvent = new ObjectDefinition();
104
        $subscriptionEvent->setName(ucfirst($subscription->getName()).'Event');
105
        $field = new FieldDefinition();
106
        $field->setName($annotation->fieldName ?? 'data');
107
        $field->setDescription($annotation->fieldDescription ?? null);
108
        $field->setType($subscription->getType());
109
        $field->setNode($subscription->getNode());
110
        $field->setNonNull(TypeUtil::isTypeNonNull($annotation->payload));
111
        $field->setList(TypeUtil::isTypeList($annotation->payload));
112
        $field->setNonNullList(TypeUtil::isTypeNonNullList($annotation->payload));
113
        $subscriptionEvent->addField($field);
114
        $endpoint->addType($subscriptionEvent);
115
116
        // subscription response is a union between SubscriptionLink object and specific Subscription Event
117
        $subscriptionResponse = new UnionDefinition();
118
        $subscriptionResponse->setName(ucfirst($subscription->getName()).'Subscription');
119
        $subscriptionResponse->addType(new UnionTypeDefinition($subscriptionEvent->getName()));
120
        $subscriptionResponse->addType(new UnionTypeDefinition($endpoint->getTypeForClass(SubscriptionLink::class)));
121
        $endpoint->addType($subscriptionResponse);
122
        $subscription->setType(TypeUtil::normalize($subscriptionResponse->getName()));
123
124
        if (!$subscription->getType()) {
125
            $error = sprintf(
126
                'The subscription "%s" does not have a valid payload,
127
                 create a file called %sPayload or specify a payload.',
128
                $subscription->getName(),
129
                $refClass->getName()
130
            );
131
            throw new \RuntimeException($error);
132
        }
133
134
        $argAnnotations = $this->reader->getClassAnnotations($refClass);
135
        foreach ($argAnnotations as $argAnnotation) {
136
            if ($argAnnotation instanceof Annotation\Argument) {
137
                $this->resolveArgument($subscription, $argAnnotation);
138
            }
139
        }
140
141
        if ($annotation->node) {
142
            $subscription->setNode($annotation->node);
143
        } elseif (($node = ClassUtils::getNodeFromClass($refClass->getName())) && $endpoint->hasType($node)) {
144
            $subscription->setNode($node);
145
        }
146
147
        $subscription->setResolver($annotation->resolver ?? $refClass->getName());
148
        $subscription->setDeprecationReason($annotation->deprecationReason);
149
        $subscription->setDescription($annotation->description);
150
151
        foreach ($annotation->options as $option => $value) {
152
            $subscription->setMeta($option, $value);
153
        }
154
    }
155
}
156