Passed
Push — master ( 3d645a...097498 )
by Tomáš
05:27
created

SchemaCacheProvider   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 54
dl 0
loc 134
rs 10
c 0
b 0
f 0
wmc 16

7 Methods

Rating   Name   Duplication   Size   Complexity  
B getTypeConfigDecorator() 0 46 9
A save() 0 12 1
A isCached() 0 3 1
A getTypesCacheFile() 0 3 1
A getSchema() 0 15 2
A __construct() 0 8 1
A getSchemaCacheFile() 0 3 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Portiny\GraphQL\GraphQL\Schema;
5
6
use Closure;
7
use GraphQL\Language\AST\DocumentNode;
8
use GraphQL\Language\Parser;
9
use GraphQL\Type\Definition\ObjectType;
10
use GraphQL\Type\Definition\ResolveInfo;
11
use GraphQL\Type\Schema;
12
use GraphQL\Utils\AST;
13
use GraphQL\Utils\BuildSchema;
14
use GraphQL\Utils\SchemaPrinter;
15
use Nette\Utils\FileSystem;
16
use Portiny\GraphQL\Contract\Provider\MutationFieldsProviderInterface;
17
use Portiny\GraphQL\Contract\Provider\QueryFieldsProviderInterface;
18
use Portiny\GraphQL\GraphQL\Type\Types;
19
20
final class SchemaCacheProvider
21
{
22
	/**
23
	 * @var string
24
	 */
25
	private const SCHEMA_FILENAME = 'schema.php';
26
27
	/**
28
	 * @var string
29
	 */
30
	private const TYPES_FILENAME = 'types.php';
31
32
	/**
33
	 * @var string
34
	 */
35
	private $cacheDir;
36
37
	/**
38
	 * @var QueryFieldsProviderInterface
39
	 */
40
	private $queryFieldsProvider;
41
42
	/**
43
	 * @var MutationFieldsProviderInterface
44
	 */
45
	private $mutationFieldsProvider;
46
47
	/**
48
	 * @var Schema
49
	 */
50
	private $schema;
51
52
	public function __construct(
53
		string $cacheDir,
54
		QueryFieldsProviderInterface $queryFieldsProvider,
55
		MutationFieldsProviderInterface $mutationFieldsProvider
56
	) {
57
		$this->cacheDir = $cacheDir;
58
		$this->queryFieldsProvider = $queryFieldsProvider;
59
		$this->mutationFieldsProvider = $mutationFieldsProvider;
60
	}
61
62
	public function isCached(): bool
63
	{
64
		return file_exists($this->getSchemaCacheFile());
65
	}
66
67
	public function save(Schema $schema): void
68
	{
69
		// schema cache
70
		$sdl = SchemaPrinter::doPrint($schema);
71
		$documentNode = Parser::parse($sdl);
72
		FileSystem::write(
73
			$this->getSchemaCacheFile(),
74
			"<?php\nreturn " . var_export(AST::toArray($documentNode), true) . ';'
75
		);
76
77
		// types cache
78
		FileSystem::write($this->getTypesCacheFile(), serialize(Types::getTypeClasses()));
79
	}
80
81
	public function getSchema(): Schema
82
	{
83
		if ($this->schema !== null) {
84
			return $this->schema;
85
		}
86
87
		// load types from cache
88
		Types::loadTypesFromClasses(unserialize(FileSystem::read($this->getTypesCacheFile())));
89
90
		// load schema from cache
91
		/** @var DocumentNode $document */
92
		$document = AST::fromArray(require $this->getSchemaCacheFile());
93
		$this->schema = BuildSchema::build($document, $this->getTypeConfigDecorator());
94
95
		return $this->schema;
96
	}
97
98
	private function getSchemaCacheFile(): string
99
	{
100
		return $this->cacheDir . '/' . self::SCHEMA_FILENAME;
101
	}
102
103
	private function getTypesCacheFile(): string
104
	{
105
		return $this->cacheDir . '/' . self::TYPES_FILENAME;
106
	}
107
108
	private function getTypeConfigDecorator(): Closure
109
	{
110
		return function (array $typeConfig) {
111
			$typeConfig['resolveField'] = function ($value, $args, $context, ResolveInfo $info) use ($typeConfig) {
112
				$fieldName = (string) $info->fieldName;
113
114
				switch ($typeConfig['name']) {
115
					case 'Query':
116
						$queryField = $this->queryFieldsProvider->getField($fieldName);
117
						if ($queryField) {
118
							return $queryField->resolve($value, $args, $context);
119
						}
120
						break;
121
122
					case 'Mutation':
123
						$mutationField = $this->mutationFieldsProvider->getField($fieldName);
124
						if ($mutationField) {
125
							return $mutationField->resolve($value, $args, $context);
126
						}
127
						break;
128
129
					default:
130
						$type = Types::findByName($typeConfig['name']);
131
						if ($type instanceof ObjectType) {
132
							$fieldNameForResolving = $fieldName;
133
							if ($type->hasField($fieldNameForResolving)) {
134
								$typeField = $type->getField($fieldNameForResolving);
135
								$resolver = $typeField->resolveFn;
136
								if (is_callable($resolver)) {
137
									return $resolver($value, $args, $context, $info);
138
								}
139
							}
140
141
							$resolver = $type->resolveFieldFn;
142
							if (is_callable($resolver)) {
143
								return $resolver($value, $args, $context, $info);
144
							}
145
146
							return null;
147
						}
148
				}
149
150
				return null;
151
			};
152
153
			return $typeConfig;
154
		};
155
	}
156
}
157