TypeRegistry   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 392
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 39
eloc 75
c 1
b 0
f 0
dl 0
loc 392
rs 9.28

27 Methods

Rating   Name   Duplication   Size   Complexity  
A ID() 0 3 1
A __sleep() 0 3 1
A addModelSchema() 0 9 1
A string() 0 3 1
A hasType() 0 3 1
A setTypes() 0 3 1
A __wakeup() 0 4 1
A getTypes() 0 3 1
A getSchemaForModel() 0 14 1
A getTypeInstances() 0 3 1
A field() 0 7 2
A addTypes() 0 5 3
A boolean() 0 3 1
A int() 0 3 1
A setTypeInstances() 0 3 1
A type() 0 7 2
A getModelSchema() 0 8 1
A polymorphic() 0 3 1
A resolveSchemaForModel() 0 10 1
A hasSchemaForModel() 0 5 2
A __construct() 0 4 1
A getType() 0 20 4
A addType() 0 5 2
A float() 0 3 1
A resolve() 0 20 3
A eloquent() 0 3 1
A addModelSchemas() 0 4 2
1
<?php
2
3
namespace Bakery\Support;
4
5
use Bakery\Utils\Utils;
6
use Bakery\Fields\Field;
7
use Bakery\Eloquent\ModelSchema;
8
use Bakery\Fields\EloquentField;
9
use Bakery\Exceptions\TypeNotFound;
10
use Bakery\Fields\PolymorphicField;
11
use Bakery\Types\Definitions\RootType;
12
use Illuminate\Database\Eloquent\Model;
13
use Bakery\Types\Definitions\InternalType;
14
use Bakery\Types\Definitions\ReferenceType;
15
use GraphQL\Type\Definition\Type as GraphQLType;
16
17
class TypeRegistry
18
{
19
    /**
20
     * The registered types.
21
     *
22
     * @var array
23
     */
24
    protected $types = [];
25
26
    /**
27
     * The GraphQL type instances.
28
     *
29
     * @var array
30
     */
31
    protected $typeInstances = [];
32
33
    /**
34
     * The model schema instances.
35
     *
36
     * @var \Illuminate\Support\Collection
37
     */
38
    protected $modelSchemas;
39
40
    /**
41
     * The model schemas keyed by model class name.
42
     *
43
     * @var \Illuminate\Support\Collection
44
     */
45
    protected $schemasByModel;
46
47
    /**
48
     * Bakery constructor.
49
     */
50
    public function __construct()
51
    {
52
        $this->modelSchemas = collect();
53
        $this->schemasByModel = collect();
54
    }
55
56
    /**
57
     * Add types to the registry.
58
     *
59
     * @param array $classes
60
     */
61
    public function addTypes(array $classes)
62
    {
63
        foreach ($classes as $class) {
64
            $class = is_object($class) ? $class : resolve($class);
65
            $this->addType($class);
0 ignored issues
show
Bug introduced by
It seems like $class can also be of type Illuminate\Contracts\Foundation\Application; however, parameter $type of Bakery\Support\TypeRegistry::addType() does only seem to accept Bakery\Types\Definitions\RootType, maybe add an additional type check? ( Ignorable by Annotation )

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

65
            $this->addType(/** @scrutinizer ignore-type */ $class);
Loading history...
66
        }
67
    }
68
69
    /**
70
     * Explicitly set all the types of the registry.
71
     *
72
     * @param $types
73
     * @return void
74
     */
75
    public function setTypes($types)
76
    {
77
        $this->types = $types;
78
    }
79
80
    /**
81
     * Get all the types of the registry.
82
     *
83
     * @return array
84
     */
85
    public function getTypes()
86
    {
87
        return $this->types;
88
    }
89
90
    /**
91
     * Add a type to the registry.
92
     *
93
     * @param \Bakery\Types\Definitions\RootType $type
94
     * @param string|null $name
95
     */
96
    public function addType(RootType $type, string $name = null)
97
    {
98
        $type->setRegistry($this);
99
        $name = $name ?: $type->getName();
100
        $this->types[$name] = $type;
101
    }
102
103
    /**
104
     * Add the models as model schemas to the registry.
105
     *
106
     * @param \ArrayAccess|array $models
107
     */
108
    public function addModelSchemas($models)
109
    {
110
        foreach ($models as $model) {
111
            $this->addModelSchema($model);
112
        }
113
    }
114
115
    /**
116
     * Add a single model schema to the registry.
117
     *
118
     * @param string $class
119
     */
120
    public function addModelSchema(string $class)
121
    {
122
        Utils::invariant(is_subclass_of($class, ModelSchema::class), 'Model schema '.$class.' does not extend '.ModelSchema::class);
123
124
        /** @var ModelSchema $schema */
125
        $schema = new $class($this);
126
127
        $this->modelSchemas->put($class, $schema);
128
        $this->schemasByModel->put($schema->getModelClass(), $class);
129
    }
130
131
    /**
132
     * Get a model schema instance based on it's class name.
133
     *
134
     * @param string $class
135
     * @return mixed
136
     */
137
    public function getModelSchema(string $class): ModelSchema
138
    {
139
        Utils::invariant(
140
            $this->modelSchemas->has($class),
141
            $class.' is not registered as model schema in the schema\'s type registry.'
142
        );
143
144
        return $this->modelSchemas->get($class);
145
    }
146
147
    /**
148
     * Return a model schema for a Eloquent model instance.
149
     * This 'wraps' a model schema around it.
150
     *
151
     * @param mixed $model
152
     * @return \Bakery\Eloquent\ModelSchema
153
     */
154
    public function getSchemaForModel(Model $model): ModelSchema
155
    {
156
        $class = get_class($model);
157
158
        Utils::invariant(
159
            $this->hasSchemaForModel($class),
160
            $class.' has no registered model schema in the schema\'s type registry.'
161
        );
162
163
        $schemaClass = $this->schemasByModel->get($class);
164
165
        $modelSchema = new $schemaClass($this, $model);
166
167
        return $modelSchema;
168
    }
169
170
    /**
171
     * Resolve the schema for a model based on the class name.
172
     *
173
     * @param string $model
174
     * @return \Bakery\Eloquent\ModelSchema
175
     */
176
    public function resolveSchemaForModel(string $model): ModelSchema
177
    {
178
        Utils::invariant(
179
            $this->hasSchemaForModel($model),
180
            'Model '.$model.' has no registered model schema in the schema\'s type registry.'
181
        );
182
183
        $schema = $this->schemasByModel->get($model);
184
185
        return $this->getModelSchema($schema);
186
    }
187
188
    /**
189
     * Returns if there is a model schema for a model registered.
190
     *
191
     * @param $model
192
     * @return bool
193
     */
194
    public function hasSchemaForModel($model): bool
195
    {
196
        $model = is_string($model) ? $model : get_class($model);
197
198
        return $this->schemasByModel->has($model);
199
    }
200
201
    /**
202
     * Return if the name is registered as a type.
203
     *
204
     * @param string $name
205
     * @return bool
206
     */
207
    public function hasType(string $name): bool
208
    {
209
        return array_key_exists($name, $this->types);
210
    }
211
212
    /**
213
     * Get a type by name.
214
     * This can be a string or a class path of a Type that has that name.
215
     *
216
     * @param string $name
217
     * @return \Bakery\Types\Definitions\RootType|null
218
     */
219
    public function getType(string $name): ?RootType
220
    {
221
        // If the string is the name of the type we return it straight away.
222
        if ($this->hasType($name)) {
223
            return $this->types[$name];
224
        }
225
226
        // If the string is a class, we resolve it, check if it is an instance of type and grab it's name.
227
        // and then call this method again to check.
228
        if (class_exists($name)) {
229
            $instance = resolve($name);
230
231
            if ($instance instanceof RootType) {
232
                $name = $instance->getName();
233
234
                return $this->getType($name);
235
            }
236
        }
237
238
        return null;
239
    }
240
241
    /**
242
     * Resolve a type from the registry.
243
     *
244
     * @param string $name
245
     * @return GraphQLType
246
     * @throws \Bakery\Exceptions\TypeNotFound
247
     */
248
    public function resolve(string $name): GraphQLType
249
    {
250
        $type = $this->getType($name);
251
252
        if (! $type) {
0 ignored issues
show
introduced by
$type is of type Bakery\Types\Definitions\RootType, thus it always evaluated to true.
Loading history...
253
            throw new TypeNotFound('Type '.$name.' not found.');
254
        }
255
256
        $name = $type->getName();
257
258
        // If we already have an instance of this type, return it.
259
        if (isset($this->typeInstances[$name])) {
260
            return $this->typeInstances[$name];
261
        }
262
263
        // Otherwise we create it and store it for future references.
264
        $type = $type->toType();
265
        $this->typeInstances[$name] = $type;
266
267
        return $type;
268
    }
269
270
    /**
271
     * Get the type instances of Bakery.
272
     *
273
     * @return array
274
     */
275
    public function getTypeInstances()
276
    {
277
        return $this->typeInstances;
278
    }
279
280
    /**
281
     * Set the type instances.
282
     *
283
     * @param array $typeInstances
284
     */
285
    public function setTypeInstances(array $typeInstances)
286
    {
287
        $this->typeInstances = $typeInstances;
288
    }
289
290
    /**
291
     * Construct a new field.
292
     *
293
     * @param $type
294
     * @return \Bakery\Fields\Field
295
     */
296
    public function field($type): Field
297
    {
298
        if (is_string($type)) {
299
            $type = new ReferenceType($this, $type);
300
        }
301
302
        return new Field($this, $type);
303
    }
304
305
    /**
306
     * Create a new Eloquent field.
307
     *
308
     * @param string $modelSchema
309
     * @return \Bakery\Fields\EloquentField
310
     */
311
    public function eloquent(string $modelSchema): EloquentField
312
    {
313
        return new EloquentField($this, $modelSchema);
314
    }
315
316
    /**
317
     * Create a new polymorphic field.
318
     *
319
     * @param array $modelSchemas
320
     * @return \Bakery\Fields\PolymorphicField
321
     */
322
    public function polymorphic(array $modelSchemas): PolymorphicField
323
    {
324
        return new PolymorphicField($this, $modelSchemas);
325
    }
326
327
    /**
328
     * Construct a new type.
329
     *
330
     * @param $type
331
     * @return \Bakery\Types\Definitions\RootType
332
     */
333
    public function type($type): RootType
334
    {
335
        if (is_string($type)) {
336
            return (new ReferenceType($this, $type))->setRegistry($this);
337
        }
338
339
        return (new RootType($this))->setRegistry($this);
340
    }
341
342
    /**
343
     * Construct a new ID type.
344
     *
345
     * @return \Bakery\Types\Definitions\InternalType
346
     */
347
    public function ID()
348
    {
349
        return new InternalType($this, GraphQLType::ID());
350
    }
351
352
    /**
353
     * Construct a new boolean type.
354
     *
355
     * @return \Bakery\Types\Definitions\InternalType
356
     */
357
    public function boolean()
358
    {
359
        return new InternalType($this, GraphQLType::boolean());
360
    }
361
362
    /**
363
     * Construct a new string type.
364
     *
365
     * @return \Bakery\Types\Definitions\InternalType
366
     */
367
    public function string()
368
    {
369
        return new InternalType($this, GraphQLType::string());
370
    }
371
372
    /**
373
     * Construct a new int type.
374
     *
375
     * @return \Bakery\Types\Definitions\InternalType
376
     */
377
    public function int()
378
    {
379
        return new InternalType($this, GraphQLType::int());
380
    }
381
382
    /**
383
     * Construct a new float type.
384
     *
385
     * @return \Bakery\Types\Definitions\InternalType
386
     */
387
    public function float()
388
    {
389
        return new InternalType($this, GraphQLType::float());
390
    }
391
392
    /**
393
     * Invoked when the object is being serialized.
394
     *
395
     * @return array
396
     */
397
    public function __sleep()
398
    {
399
        return ['types', 'typeInstances'];
400
    }
401
402
    /**
403
     * Invoked when the object is being unserialized.
404
     */
405
    public function __wakeup()
406
    {
407
        $this->modelSchemas = collect();
408
        $this->schemasByModel = collect();
409
    }
410
}
411