Completed
Push — master ( 5db45c...f208af )
by Arthur
02:39
created

SchemaFactory::loadSchemaContainer()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 12
rs 9.4286
cc 2
eloc 7
nc 2
nop 0
1
<?php
2
3
namespace Arthem\GraphQLMapper\Schema;
4
5
use Arthem\GraphQLMapper\Mapping\Cache\CacheDriverInterface;
6
use Arthem\GraphQLMapper\Mapping\Driver\DriverInterface;
7
use Arthem\GraphQLMapper\Mapping\Field;
8
use Arthem\GraphQLMapper\Mapping\FieldContainer;
9
use Arthem\GraphQLMapper\Mapping\InterfaceType;
10
use Arthem\GraphQLMapper\Mapping\MappingNormalizer;
11
use Arthem\GraphQLMapper\Mapping\SchemaContainer;
12
use Arthem\GraphQLMapper\Schema\Resolve\CallableResolver;
13
use Arthem\GraphQLMapper\Schema\Resolve\ResolverInterface;
14
use GraphQL\Schema;
15
use GraphQL\Type\Definition as GQLDefinition;
16
17
class SchemaFactory
18
{
19
    /**
20
     * @var string
21
     */
22
    protected $cacheKey = 'Arthem:GraphQL:Mapping';
23
24
    /**
25
     * @var CacheDriverInterface
26
     */
27
    private $cacheDriver;
28
29
    /**
30
     * @var DriverInterface
31
     */
32
    private $driver;
33
34
    /**
35
     * @var TypeResolver
36
     */
37
    private $typeResolver;
38
39
    /**
40
     * @var ResolverInterface[]
41
     */
42
    private $resolveFactories = [];
43
44
    /**
45
     * @var MappingNormalizer
46
     */
47
    private $normalizer;
48
49
    /**
50
     * @param DriverInterface $driver
51
     */
52
    public function __construct(DriverInterface $driver, TypeResolver $typeResolver)
53
    {
54
        $this->driver       = $driver;
55
        $this->typeResolver = $typeResolver;
56
        $this->normalizer   = new MappingNormalizer();
57
        $this->addResolver(new CallableResolver());
58
    }
59
60
    /**
61
     * @param CacheDriverInterface $cacheDriver
62
     */
63
    public function setCacheDriver(CacheDriverInterface $cacheDriver = null)
64
    {
65
        $this->cacheDriver = $cacheDriver;
66
    }
67
68
    /**
69
     * @return Schema
70
     */
71
    public function createSchema()
72
    {
73
        $schemaContainer = $this->getSchemaContainer();
74
75
        foreach ($schemaContainer->getInterfaces() as $type) {
76
            $GQLType = $this->createInterface($type);
77
            $this->typeResolver->addType($type->getName(), $GQLType);
78
        }
79
80
        foreach ($schemaContainer->getTypes() as $type) {
81
            $GQLType = $this->createType($type);
82
            $this->typeResolver->addType($type->getName(), $GQLType);
83
        }
84
85
        $querySchema  = $schemaContainer->getQuerySchema();
86
        $mutationType = $schemaContainer->getMutationSchema();
87
        $queryType    = null !== $querySchema ? $this->createType($querySchema) : null;
88
        $mutationType = null !== $mutationType ? $this->createType($mutationType) : null;
89
90
        return new Schema($queryType, $mutationType);
91
    }
92
93
    /**
94
     * @return SchemaContainer
95
     */
96
    private function getSchemaContainer()
97
    {
98
        if (null !== $this->cacheDriver) {
99
            $schemaContainer = $this->cacheDriver->load();
100
            if (false !== $schemaContainer) {
101
                return $schemaContainer;
102
            }
103
        }
104
105
        return $this->loadSchemaContainer();
106
    }
107
108
    /**
109
     * @return SchemaContainer
110
     */
111
    private function loadSchemaContainer()
112
    {
113
        $schemaContainer = new SchemaContainer();
114
        $this->driver->load($schemaContainer);
115
        $this->normalizer->normalize($schemaContainer);
116
117
        if (null !== $this->cacheDriver) {
118
            $this->cacheDriver->save($schemaContainer);
119
        }
120
121
        return $schemaContainer;
122
    }
123
124
    /**
125
     * @param InterfaceType $type
126
     * @return GQLDefinition\InterfaceType
127
     */
128
    private function createInterface(InterfaceType $type)
129
    {
130
        if (null !== $type->getFields()) {
131
            $this->prepareFields($type->getFields());
132
        }
133
        $type = new GQLDefinition\InterfaceType($type->toMapping());
134
135
        return $type;
136
    }
137
138
    /**
139
     * @param FieldContainer $type
140
     * @return GQLDefinition\ObjectType
141
     */
142
    private function createType(FieldContainer $type)
143
    {
144
        if (null !== $type->getFields()) {
145
            $this->prepareFields($type->getFields());
146
        }
147
        $type = new GQLDefinition\ObjectType($type->toMapping());
148
149
        return $type;
150
    }
151
152
    /**
153
     * @param Field[] $fields
154
     */
155
    private function prepareFields(array $fields)
156
    {
157
        foreach ($fields as $field) {
158
159
            if (null !== $field->getArguments()) {
160
                $this->prepareFields($field->getArguments());
161
            }
162
163
            $resolveConfig = $field->getResolveConfig();
164
            if (isset($resolveConfig['handler'])) {
165
                $handler  = $resolveConfig['handler'];
166
                $resolver = $this->resolveFactories[$handler]->getFunction($resolveConfig, $field);
167
                $field->setResolve($resolver);
168
            }
169
170
            $typeName = $field->getType();
171
            $field->setResolvedType(function () use ($typeName) {
172
                return $this->typeResolver->resolveType($typeName);
173
            });
174
        }
175
    }
176
177
    /**
178
     * @param ResolverInterface $factory
179
     */
180
    public function addResolver(ResolverInterface $factory)
181
    {
182
        $this->resolveFactories[$factory->getName()] = $factory;
183
    }
184
}
185