1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace GraphQLAPI\GraphQLAPI\ModuleResolvers; |
6
|
|
|
|
7
|
|
|
use GraphQLAPI\GraphQLAPI\Plugin; |
8
|
|
|
use GraphQLAPI\GraphQLAPI\ModuleSettings\Properties; |
9
|
|
|
use GraphQLAPI\GraphQLAPI\Facades\ModuleRegistryFacade; |
10
|
|
|
use GraphQLAPI\GraphQLAPI\ModuleResolvers\ModuleResolverTrait; |
11
|
|
|
use GraphQLAPI\GraphQLAPI\PostTypes\GraphQLSchemaConfigurationPostType; |
12
|
|
|
use PoP\AccessControl\Schema\SchemaModes; |
13
|
|
|
use GraphQLAPI\GraphQLAPI\ComponentConfiguration; |
14
|
|
|
use GraphQLAPI\GraphQLAPI\ModuleTypeResolvers\ModuleTypeResolver; |
15
|
|
|
use WP_Post; |
16
|
|
|
|
17
|
|
|
class SchemaConfigurationFunctionalityModuleResolver extends AbstractFunctionalityModuleResolver |
18
|
|
|
{ |
19
|
|
|
use ModuleResolverTrait; |
20
|
|
|
|
21
|
|
|
public const SCHEMA_CONFIGURATION = Plugin::NAMESPACE . '\schema-configuration'; |
22
|
|
|
public const SCHEMA_NAMESPACING = Plugin::NAMESPACE . '\schema-namespacing'; |
23
|
|
|
public const PUBLIC_PRIVATE_SCHEMA = Plugin::NAMESPACE . '\public-private-schema'; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Setting options |
27
|
|
|
*/ |
28
|
|
|
public const OPTION_SCHEMA_CONFIGURATION_ID = 'schema-configuration-id'; |
29
|
|
|
public const OPTION_USE_NAMESPACING = 'use-namespacing'; |
30
|
|
|
public const OPTION_MODE = 'mode'; |
31
|
|
|
public const OPTION_ENABLE_GRANULAR = 'granular'; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Setting option values |
35
|
|
|
*/ |
36
|
|
|
public const OPTION_VALUE_NO_VALUE_ID = 0; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @return string[] |
40
|
|
|
*/ |
41
|
|
|
public static function getModulesToResolve(): array |
42
|
|
|
{ |
43
|
|
|
return [ |
44
|
|
|
self::SCHEMA_CONFIGURATION, |
45
|
|
|
self::SCHEMA_NAMESPACING, |
46
|
|
|
self::PUBLIC_PRIVATE_SCHEMA, |
47
|
|
|
]; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Enable to customize a specific UI for the module |
52
|
|
|
*/ |
53
|
|
|
public function getModuleType(string $module): string |
54
|
|
|
{ |
55
|
|
|
return ModuleTypeResolver::SCHEMA_CONFIGURATION; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @return array<array> List of entries that must be satisfied, each entry is an array where at least 1 module must be satisfied |
60
|
|
|
*/ |
61
|
|
|
public function getDependedModuleLists(string $module): array |
62
|
|
|
{ |
63
|
|
|
switch ($module) { |
64
|
|
|
case self::SCHEMA_CONFIGURATION: |
65
|
|
|
return [ |
66
|
|
|
[ |
67
|
|
|
EndpointFunctionalityModuleResolver::PERSISTED_QUERIES, |
68
|
|
|
EndpointFunctionalityModuleResolver::CUSTOM_ENDPOINTS, |
69
|
|
|
], |
70
|
|
|
]; |
71
|
|
|
case self::SCHEMA_NAMESPACING: |
72
|
|
|
return [ |
73
|
|
|
[ |
74
|
|
|
self::SCHEMA_CONFIGURATION, |
75
|
|
|
], |
76
|
|
|
]; |
77
|
|
|
case self::PUBLIC_PRIVATE_SCHEMA: |
78
|
|
|
return [ |
79
|
|
|
[ |
80
|
|
|
AccessControlFunctionalityModuleResolver::ACCESS_CONTROL, |
81
|
|
|
], |
82
|
|
|
]; |
83
|
|
|
} |
84
|
|
|
return parent::getDependedModuleLists($module); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
public function getName(string $module): string |
88
|
|
|
{ |
89
|
|
|
$names = [ |
90
|
|
|
self::SCHEMA_CONFIGURATION => \__('Schema Configuration', 'graphql-api'), |
91
|
|
|
self::SCHEMA_NAMESPACING => \__('Schema Namespacing', 'graphql-api'), |
92
|
|
|
self::PUBLIC_PRIVATE_SCHEMA => \__('Public/Private Schema', 'graphql-api'), |
93
|
|
|
]; |
94
|
|
|
return $names[$module] ?? $module; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
public function getDescription(string $module): string |
98
|
|
|
{ |
99
|
|
|
switch ($module) { |
100
|
|
|
case self::SCHEMA_CONFIGURATION: |
101
|
|
|
return \__('Customize the schema accessible to different Custom Endpoints and Persisted Queries, by applying a custom configuration (involving namespacing, access control, cache control, and others) to the grand schema', 'graphql-api'); |
102
|
|
|
case self::SCHEMA_NAMESPACING: |
103
|
|
|
return \__('Automatically namespace types and interfaces with a vendor/project name, to avoid naming collisions', 'graphql-api'); |
104
|
|
|
case self::PUBLIC_PRIVATE_SCHEMA: |
105
|
|
|
return \__('Enable to communicate the existence of some field from the schema to certain users only (private mode) or to everyone (public mode). If disabled, fields are always available to everyone (public mode)', 'graphql-api'); |
106
|
|
|
} |
107
|
|
|
return parent::getDescription($module); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
public function isEnabledByDefault(string $module): bool |
111
|
|
|
{ |
112
|
|
|
switch ($module) { |
113
|
|
|
case self::SCHEMA_NAMESPACING: |
114
|
|
|
return false; |
115
|
|
|
} |
116
|
|
|
return parent::isEnabledByDefault($module); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Default value for an option set by the module |
121
|
|
|
* |
122
|
|
|
* @param string $module |
123
|
|
|
* @param string $option |
124
|
|
|
* @return mixed Anything the setting might be: an array|string|bool|int|null |
125
|
|
|
*/ |
126
|
|
|
public function getSettingsDefaultValue(string $module, string $option) |
127
|
|
|
{ |
128
|
|
|
$defaultValues = [ |
129
|
|
|
self::SCHEMA_CONFIGURATION => [ |
130
|
|
|
self::OPTION_SCHEMA_CONFIGURATION_ID => self::OPTION_VALUE_NO_VALUE_ID, |
131
|
|
|
], |
132
|
|
|
self::SCHEMA_NAMESPACING => [ |
133
|
|
|
self::OPTION_USE_NAMESPACING => false, |
134
|
|
|
], |
135
|
|
|
self::PUBLIC_PRIVATE_SCHEMA => [ |
136
|
|
|
self::OPTION_MODE => SchemaModes::PUBLIC_SCHEMA_MODE, |
137
|
|
|
self::OPTION_ENABLE_GRANULAR => true, |
138
|
|
|
], |
139
|
|
|
]; |
140
|
|
|
return $defaultValues[$module][$option]; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Array with the inputs to show as settings for the module |
145
|
|
|
* |
146
|
|
|
* @return array<array> List of settings for the module, each entry is an array with property => value |
147
|
|
|
*/ |
148
|
|
|
public function getSettings(string $module): array |
149
|
|
|
{ |
150
|
|
|
$moduleSettings = parent::getSettings($module); |
151
|
|
|
$moduleRegistry = ModuleRegistryFacade::getInstance(); |
152
|
|
|
// Do the if one by one, so that the SELECT do not get evaluated unless needed |
153
|
|
|
if ($module == self::SCHEMA_CONFIGURATION) { |
154
|
|
|
$whereModules = []; |
155
|
|
|
$maybeWhereModules = [ |
156
|
|
|
EndpointFunctionalityModuleResolver::CUSTOM_ENDPOINTS, |
157
|
|
|
EndpointFunctionalityModuleResolver::PERSISTED_QUERIES, |
158
|
|
|
]; |
159
|
|
|
foreach ($maybeWhereModules as $maybeWhereModule) { |
160
|
|
|
if ($moduleRegistry->isModuleEnabled($maybeWhereModule)) { |
161
|
|
|
$whereModules[] = '▹ ' . $moduleRegistry->getModuleResolver($maybeWhereModule)->getName($maybeWhereModule); |
162
|
|
|
} |
163
|
|
|
} |
164
|
|
|
// Build all the possible values by fetching all the Schema Configuration posts |
165
|
|
|
$possibleValues = [ |
166
|
|
|
self::OPTION_VALUE_NO_VALUE_ID => \__('None', 'graphql-api'), |
167
|
|
|
]; |
168
|
|
|
/** |
169
|
|
|
* @var WP_Post[] |
170
|
|
|
*/ |
171
|
|
|
$customPosts = \get_posts([ |
172
|
|
|
'posts_per_page' => -1, |
173
|
|
|
'post_type' => GraphQLSchemaConfigurationPostType::POST_TYPE, |
174
|
|
|
'post_status' => 'publish', |
175
|
|
|
]); |
176
|
|
|
if (!empty($customPosts)) { |
177
|
|
|
foreach ($customPosts as $customPost) { |
178
|
|
|
$possibleValues[$customPost->ID] = $customPost->post_title; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
$option = self::OPTION_SCHEMA_CONFIGURATION_ID; |
182
|
|
|
$moduleSettings[] = [ |
183
|
|
|
Properties::INPUT => $option, |
184
|
|
|
Properties::NAME => $this->getSettingOptionName( |
185
|
|
|
$module, |
186
|
|
|
$option |
187
|
|
|
), |
188
|
|
|
Properties::TITLE => \__('Default Schema Configuration', 'graphql-api'), |
189
|
|
|
Properties::DESCRIPTION => sprintf( |
190
|
|
|
\__('Schema Configuration to use when option <code>"Default"</code> is selected (in %s)', 'graphql-api'), |
191
|
|
|
implode( |
192
|
|
|
\__(', ', 'graphql-api'), |
193
|
|
|
$whereModules |
194
|
|
|
) |
195
|
|
|
), |
196
|
|
|
Properties::TYPE => Properties::TYPE_INT, |
197
|
|
|
// Fetch all Schema Configurations from the DB |
198
|
|
|
Properties::POSSIBLE_VALUES => $possibleValues, |
199
|
|
|
]; |
200
|
|
|
} elseif ($module == self::SCHEMA_NAMESPACING) { |
201
|
|
|
$option = self::OPTION_USE_NAMESPACING; |
202
|
|
|
$moduleSettings[] = [ |
203
|
|
|
Properties::INPUT => $option, |
204
|
|
|
Properties::NAME => $this->getSettingOptionName( |
205
|
|
|
$module, |
206
|
|
|
$option |
207
|
|
|
), |
208
|
|
|
Properties::TITLE => \__('Use namespacing?', 'graphql-api'), |
209
|
|
|
Properties::DESCRIPTION => \__('Automatically namespace types and interfaces in the schema', 'graphql-api'), |
210
|
|
|
Properties::TYPE => Properties::TYPE_BOOL, |
211
|
|
|
]; |
212
|
|
|
} elseif ($module == self::PUBLIC_PRIVATE_SCHEMA) { |
213
|
|
|
$whereModules = [ |
214
|
|
|
SchemaConfigurationFunctionalityModuleResolver::SCHEMA_CONFIGURATION, |
215
|
|
|
AccessControlFunctionalityModuleResolver::ACCESS_CONTROL, |
216
|
|
|
]; |
217
|
|
|
$whereModuleNames = array_map( |
218
|
|
|
fn ($whereModule) => '▹ ' . $moduleRegistry->getModuleResolver($whereModule)->getName($whereModule), |
219
|
|
|
$whereModules |
220
|
|
|
); |
221
|
|
|
$option = self::OPTION_MODE; |
222
|
|
|
$moduleSettings[] = [ |
223
|
|
|
Properties::INPUT => $option, |
224
|
|
|
Properties::NAME => $this->getSettingOptionName( |
225
|
|
|
$module, |
226
|
|
|
$option |
227
|
|
|
), |
228
|
|
|
Properties::TITLE => \__('Default visibility', 'graphql-api'), |
229
|
|
|
Properties::DESCRIPTION => sprintf( |
230
|
|
|
\__('Visibility to use for fields and directives in the schema when option <code>"%s"</code> is selected (in %s)', 'graphql-api'), |
231
|
|
|
ComponentConfiguration::getSettingsValueLabel(), |
232
|
|
|
implode( |
233
|
|
|
\__(', ', 'graphql-api'), |
234
|
|
|
$whereModuleNames |
235
|
|
|
) |
236
|
|
|
), |
237
|
|
|
Properties::TYPE => Properties::TYPE_STRING, |
238
|
|
|
Properties::POSSIBLE_VALUES => [ |
239
|
|
|
SchemaModes::PUBLIC_SCHEMA_MODE => \__('Public', 'graphql-api'), |
240
|
|
|
SchemaModes::PRIVATE_SCHEMA_MODE => \__('Private', 'graphql-api'), |
241
|
|
|
], |
242
|
|
|
]; |
243
|
|
|
$option = self::OPTION_ENABLE_GRANULAR; |
244
|
|
|
$moduleSettings[] = [ |
245
|
|
|
Properties::INPUT => $option, |
246
|
|
|
Properties::NAME => $this->getSettingOptionName( |
247
|
|
|
$module, |
248
|
|
|
$option |
249
|
|
|
), |
250
|
|
|
Properties::TITLE => \__('Enable granular control?', 'graphql-api'), |
251
|
|
|
Properties::DESCRIPTION => \__('Enable to select the visibility for a set of fields/directives when editing the Access Control List', 'graphql-api'), |
252
|
|
|
Properties::TYPE => Properties::TYPE_BOOL, |
253
|
|
|
]; |
254
|
|
|
} |
255
|
|
|
return $moduleSettings; |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|