RootField   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 286
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 30
eloc 58
c 2
b 1
f 0
dl 0
loc 286
rs 10

19 Methods

Rating   Name   Duplication   Size   Complexity  
A fields() 0 3 1
A __construct() 0 3 1
A getResolver() 0 7 2
A abstractResolver() 0 12 2
A getName() 0 7 1
A guard() 0 15 6
A name() 0 3 1
A getArgs() 0 5 1
A getDescription() 0 3 1
A attributes() 0 3 1
A getFields() 0 3 1
A getType() 0 3 1
A description() 0 3 1
A args() 0 3 1
A setRegistry() 0 5 1
A validate() 0 10 5
A toArray() 0 3 1
A getRegistry() 0 3 1
A getAttributes() 0 9 1
1
<?php
2
3
namespace Bakery\Support;
4
5
use Bakery\Utils\Utils;
6
use Bakery\Errors\ValidationError;
7
use Illuminate\Auth\Access\Response;
8
use Bakery\Types\Definitions\RootType;
9
use GraphQL\Type\Definition\ResolveInfo;
10
use Illuminate\Support\Facades\Validator;
11
use Bakery\Exceptions\UnauthorizedException;
12
use GraphQL\Type\Definition\Type as GraphQLType;
13
use Illuminate\Auth\Access\HandlesAuthorization;
14
use Illuminate\Auth\Access\AuthorizationException;
15
16
abstract class RootField
17
{
18
    use HandlesAuthorization;
19
20
    /**
21
     * @var \Bakery\Support\TypeRegistry
22
     */
23
    protected $registry;
24
25
    /**
26
     * Name of the field.
27
     *
28
     * @var string
29
     */
30
    protected $name;
31
32
    /**
33
     * The fields of the field.
34
     *
35
     * @var array
36
     */
37
    protected $fields;
38
39
    /**
40
     * The description of the field.
41
     *
42
     * @var string
43
     */
44
    protected $description;
45
46
    /**
47
     * The attributes of the RootField.
48
     *
49
     * @var array
50
     */
51
    protected $attributes = [];
52
53
    /**
54
     * RootField constructor.
55
     *
56
     * @param \Bakery\Support\TypeRegistry $registry
57
     */
58
    public function __construct(TypeRegistry $registry)
59
    {
60
        $this->registry = $registry;
61
    }
62
63
    /**
64
     * The attributes of the RootField.
65
     *
66
     * @return array
67
     */
68
    public function attributes()
69
    {
70
        return [];
71
    }
72
73
    /**
74
     * Define the type of the RootField.
75
     *
76
     * @return RootType
77
     */
78
    abstract public function type(): RootType;
79
80
    /**
81
     * Get the underlying field of the type and convert it to a type.
82
     *
83
     * @return \GraphQL\Type\Definition\Type
84
     */
85
    public function getType(): GraphQLType
86
    {
87
        return $this->type()->toType();
88
    }
89
90
    /**
91
     * The name of the field.
92
     *
93
     * @return null|string
94
     */
95
    public function name(): ?string
96
    {
97
        return $this->name;
98
    }
99
100
    /**
101
     * Get the name of the field.
102
     *
103
     * @return string
104
     */
105
    public function getName(): string
106
    {
107
        $name = $this->name();
108
109
        Utils::invariant($name, 'RootField '.get_class($this).' has no name defined.');
110
111
        return $name;
112
    }
113
114
    /**
115
     * The arguments for the RootField.
116
     *
117
     * @return array
118
     */
119
    public function args(): array
120
    {
121
        return [];
122
    }
123
124
    /**
125
     * Get the arguments of the field and convert them to types.
126
     *
127
     * @return array
128
     */
129
    public function getArgs(): array
130
    {
131
        return collect($this->args())->map(function (RootType $type) {
132
            return $type->toType();
133
        })->toArray();
134
    }
135
136
    /**
137
     * Define the fields.
138
     *
139
     * @return array
140
     */
141
    public function fields()
142
    {
143
        return $this->fields;
144
    }
145
146
    /**
147
     * Get the fields for a field.
148
     *
149
     * @return array|null
150
     */
151
    public function getFields(): ?array
152
    {
153
        return $this->fields();
154
    }
155
156
    /**
157
     * Define the description.
158
     *
159
     * @return string
160
     */
161
    public function description()
162
    {
163
        return $this->description;
164
    }
165
166
    /**
167
     * Get the description for a field.
168
     *
169
     * @return null|string
170
     */
171
    public function getDescription(): ?string
172
    {
173
        return $this->description();
174
    }
175
176
    /**
177
     * Retrieve the resolver for the RootField.
178
     *
179
     * @return callable|null
180
     */
181
    private function getResolver()
182
    {
183
        if (! method_exists($this, 'resolve')) {
184
            return null;
185
        }
186
187
        return [$this, 'abstractResolver'];
188
    }
189
190
    /**
191
     * @param $root
192
     * @param array $args
193
     * @param $context
194
     * @param ResolveInfo $info
195
     * @return null
196
     */
197
    public function abstractResolver($root, array $args, $context, ResolveInfo $info)
198
    {
199
        if (! method_exists($this, 'resolve')) {
200
            return null;
201
        }
202
203
        $args = new Arguments($args);
204
205
        $this->validate($args);
206
        $this->guard($args);
207
208
        return $this->resolve($args, $root, $context, $info);
209
    }
210
211
    /**
212
     * Check if the user is authorized to perform the query.
213
     * @param Arguments $args
214
     */
215
    protected function guard(Arguments $args): void
216
    {
217
        if (method_exists($this, 'authorize')) {
218
            try {
219
                $result = $this->authorize($args);
220
221
                if (! $result instanceof Response) {
222
                    $result = $result ? Response::allow() : Response::deny();
223
                }
224
            } catch (AuthorizationException $exception) {
225
                $result = $exception->toResponse();
226
            }
227
228
            if ($result->denied()) {
229
                throw new UnauthorizedException($result->message(), $result->code());
230
            }
231
        }
232
    }
233
234
    /**
235
     * Validate the arguments of the query.
236
     *
237
     * @param  Arguments  $args
238
     * @throws ValidationError
239
     */
240
    protected function validate(Arguments $args): void
241
    {
242
        if (method_exists($this, 'rules')) {
243
            $rules = $this->rules($args);
244
            $messages = method_exists($this, 'messages') ? $this->messages() : [];
245
            $attributes = method_exists($this, 'attributes') ? $this->attributes() : [];
246
            $validator = Validator::make($args->toArray(), $rules, $messages, $attributes);
247
248
            if ($validator->fails()) {
249
                throw new ValidationError($validator);
250
            }
251
        }
252
    }
253
254
    /**
255
     * Get the attributes from the container.
256
     *
257
     * @return array
258
     */
259
    public function getAttributes()
260
    {
261
        return [
262
            'name' => $this->getName(),
263
            'args' => $this->getArgs(),
264
            'type' => $this->getType(),
265
            'fields' => $this->getFields(),
266
            'description' => $this->getDescription(),
267
            'resolve' => $this->getResolver(),
268
        ];
269
    }
270
271
    /**
272
     * Convert the RootField instance to an array.
273
     *
274
     * @return array
275
     */
276
    public function toArray()
277
    {
278
        return $this->getAttributes();
279
    }
280
281
    /**
282
     * Get the registry.
283
     *
284
     * @return \Bakery\Support\TypeRegistry
285
     */
286
    public function getRegistry(): TypeRegistry
287
    {
288
        return $this->registry;
289
    }
290
291
    /**
292
     * Set the registry on the root field.
293
     *
294
     * @param \Bakery\Support\TypeRegistry $registry
295
     * @return $this
296
     */
297
    public function setRegistry(TypeRegistry $registry): self
298
    {
299
        $this->registry = $registry;
300
301
        return $this;
302
    }
303
}
304