vendor/overblog/graphql-bundle/src/DependencyInjection/Configuration.php line 55

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Overblog\GraphQLBundle\DependencyInjection;
  4. use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
  5. use GraphQL\Validator\Rules\QueryComplexity;
  6. use GraphQL\Validator\Rules\QueryDepth;
  7. use Overblog\GraphQLBundle\Definition\Argument;
  8. use Overblog\GraphQLBundle\DependencyInjection\Compiler\ConfigParserPass;
  9. use Overblog\GraphQLBundle\Error\ErrorHandler;
  10. use Overblog\GraphQLBundle\EventListener\ErrorLoggerListener;
  11. use Overblog\GraphQLBundle\Executor\Executor;
  12. use Overblog\GraphQLBundle\ExpressionLanguage\ExpressionLanguage;
  13. use Overblog\GraphQLBundle\Resolver\FieldResolver;
  14. use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
  15. use Symfony\Component\Config\Definition\Builder\EnumNodeDefinition;
  16. use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
  17. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  18. use Symfony\Component\Config\Definition\ConfigurationInterface;
  19. use Symfony\Component\HttpKernel\Kernel;
  20. use function array_keys;
  21. use function is_array;
  22. use function is_int;
  23. use function is_numeric;
  24. use function is_string;
  25. use function sprintf;
  26. class Configuration implements ConfigurationInterface
  27. {
  28. public const NAME = 'overblog_graphql';
  29. private bool $debug;
  30. /**
  31. * @param bool $debug Whether to use the debug mode
  32. */
  33. public function __construct(bool $debug)
  34. {
  35. $this->debug = $debug;
  36. }
  37. public function getConfigTreeBuilder(): TreeBuilder
  38. {
  39. $treeBuilder = new TreeBuilder(self::NAME);
  40. $rootNode = $treeBuilder->getRootNode();
  41. // @phpstan-ignore-next-line
  42. $rootNode
  43. ->children()
  44. ->append($this->batchingMethodSection())
  45. ->append($this->definitionsSection())
  46. ->append($this->errorsHandlerSection())
  47. ->append($this->servicesSection())
  48. ->append($this->securitySection())
  49. ->append($this->doctrineSection())
  50. ->append($this->profilerSection())
  51. ->end();
  52. return $treeBuilder;
  53. }
  54. private function batchingMethodSection(): EnumNodeDefinition
  55. {
  56. $builder = new TreeBuilder('batching_method', 'enum');
  57. /** @var EnumNodeDefinition $node */
  58. $node = $builder->getRootNode();
  59. $node
  60. ->values(['relay', 'apollo'])
  61. ->defaultValue('relay')
  62. ->end();
  63. return $node;
  64. }
  65. private function errorsHandlerSection(): ArrayNodeDefinition
  66. {
  67. $builder = new TreeBuilder('errors_handler');
  68. /** @var ArrayNodeDefinition $node */
  69. $node = $builder->getRootNode();
  70. // @phpstan-ignore-next-line
  71. $node
  72. ->treatFalseLike(['enabled' => false])
  73. ->treatTrueLike(['enabled' => true])
  74. ->treatNullLike(['enabled' => true])
  75. ->addDefaultsIfNotSet()
  76. ->children()
  77. ->booleanNode('enabled')->defaultTrue()->end()
  78. ->scalarNode('internal_error_message')->defaultValue(ErrorHandler::DEFAULT_ERROR_MESSAGE)->end()
  79. ->booleanNode('rethrow_internal_exceptions')->defaultFalse()->end()
  80. ->booleanNode('debug')->defaultValue($this->debug)->end()
  81. ->booleanNode('log')->defaultTrue()->end()
  82. ->scalarNode('logger_service')->defaultValue(ErrorLoggerListener::DEFAULT_LOGGER_SERVICE)->end()
  83. ->booleanNode('map_exceptions_to_parent')->defaultFalse()->end()
  84. ->arrayNode('exceptions')
  85. ->addDefaultsIfNotSet()
  86. ->children()
  87. ->arrayNode('warnings')
  88. ->treatNullLike([])
  89. ->prototype('scalar')->end()
  90. ->end()
  91. ->arrayNode('errors')
  92. ->treatNullLike([])
  93. ->prototype('scalar')->end()
  94. ->end()
  95. ->end()
  96. ->end();
  97. return $node;
  98. }
  99. private function definitionsSection(): ArrayNodeDefinition
  100. {
  101. $builder = new TreeBuilder('definitions');
  102. /** @var ArrayNodeDefinition $node */
  103. $node = $builder->getRootNode();
  104. // @phpstan-ignore-next-line
  105. $node
  106. ->addDefaultsIfNotSet()
  107. ->children()
  108. ->scalarNode('argument_class')->defaultValue(Argument::class)->end()
  109. ->scalarNode('use_experimental_executor')->defaultFalse()->end()
  110. ->scalarNode('default_field_resolver')->defaultValue(FieldResolver::class)->end()
  111. ->scalarNode('class_namespace')->defaultValue('Overblog\\GraphQLBundle\\__DEFINITIONS__')->end()
  112. ->scalarNode('cache_dir')->defaultNull()->end()
  113. ->scalarNode('cache_dir_permissions')->defaultNull()->end()
  114. ->booleanNode('use_classloader_listener')->defaultTrue()->end()
  115. ->scalarNode('auto_compile')->defaultTrue()->end()
  116. ->booleanNode('show_debug_info')->info('Show some performance stats in extensions')->defaultFalse()->end()
  117. ->booleanNode('config_validation')->defaultValue($this->debug)->end()
  118. ->append($this->definitionsSchemaSection())
  119. ->append($this->definitionsMappingsSection())
  120. ->arrayNode('builders')
  121. ->children()
  122. ->append($this->builderSection('field'))
  123. ->append($this->builderSection('fields'))
  124. ->append($this->builderSection('args'))
  125. ->end()
  126. ->end()
  127. ->end()
  128. ->end();
  129. return $node;
  130. }
  131. private function servicesSection(): ArrayNodeDefinition
  132. {
  133. $builder = new TreeBuilder('services');
  134. /** @var ArrayNodeDefinition $node */
  135. $node = $builder->getRootNode();
  136. // @phpstan-ignore-next-line
  137. $node
  138. ->addDefaultsIfNotSet()
  139. ->children()
  140. ->scalarNode('executor')
  141. ->defaultValue(Executor::class)
  142. ->end()
  143. ->scalarNode('promise_adapter')
  144. ->defaultValue(SyncPromiseAdapter::class)
  145. ->end()
  146. ->scalarNode('expression_language')
  147. ->defaultValue(ExpressionLanguage::class)
  148. ->end()
  149. ->scalarNode('cache_expression_language_parser')->end()
  150. ->end()
  151. ->end();
  152. return $node;
  153. }
  154. private function securitySection(): ArrayNodeDefinition
  155. {
  156. $builder = new TreeBuilder('security');
  157. /** @var ArrayNodeDefinition $node */
  158. $node = $builder->getRootNode();
  159. // @phpstan-ignore-next-line
  160. $node
  161. ->addDefaultsIfNotSet()
  162. ->children()
  163. ->append($this->securityQuerySection('query_max_depth', QueryDepth::DISABLED))
  164. ->append($this->securityQuerySection('query_max_complexity', QueryComplexity::DISABLED))
  165. ->booleanNode('enable_introspection')->defaultTrue()->end()
  166. ->booleanNode('handle_cors')->defaultFalse()->end()
  167. ->end()
  168. ->end();
  169. return $node;
  170. }
  171. private function definitionsSchemaSection(): ArrayNodeDefinition
  172. {
  173. $builder = new TreeBuilder('schema');
  174. /** @var ArrayNodeDefinition $node */
  175. $node = $builder->getRootNode();
  176. if (Kernel::VERSION_ID >= 50100) {
  177. $deprecatedArgs = [
  178. 'overblog/graphql-bundle',
  179. '0.13',
  180. 'The "%path%.%node%" configuration is deprecated and will be removed in 1.0. Add the "overblog_graphql.resolver_map" tag to the services instead.',
  181. ];
  182. } else {
  183. $deprecatedArgs = ['The "%path%.%node%" configuration is deprecated since version 0.13 and will be removed in 1.0. Add the "overblog_graphql.resolver_map" tag to the services instead.'];
  184. }
  185. // @phpstan-ignore-next-line
  186. $node
  187. ->beforeNormalization()
  188. ->ifTrue(fn ($v) => isset($v['query']) && is_string($v['query']) || isset($v['mutation']) && is_string($v['mutation']))
  189. ->then(fn ($v) => ['default' => $v])
  190. ->end()
  191. ->useAttributeAsKey('name')
  192. ->prototype('array')
  193. ->addDefaultsIfNotSet()
  194. ->children()
  195. ->scalarNode('query')->defaultNull()->end()
  196. ->scalarNode('mutation')->defaultNull()->end()
  197. ->scalarNode('subscription')->defaultNull()->end()
  198. ->arrayNode('resolver_maps')
  199. ->defaultValue([])
  200. ->prototype('scalar')->end()
  201. ->setDeprecated(...$deprecatedArgs)
  202. ->end()
  203. ->arrayNode('types')
  204. ->defaultValue([])
  205. ->prototype('scalar')->end()
  206. ->end()
  207. ->end()
  208. ->end()
  209. ->end();
  210. return $node;
  211. }
  212. private function definitionsMappingsSection(): ArrayNodeDefinition
  213. {
  214. $builder = new TreeBuilder('mappings');
  215. /** @var ArrayNodeDefinition $node */
  216. $node = $builder->getRootNode();
  217. // @phpstan-ignore-next-line
  218. $node
  219. ->children()
  220. ->arrayNode('auto_discover')
  221. ->treatFalseLike(['bundles' => false, 'root_dir' => false, 'built_in' => true])
  222. ->treatTrueLike(['bundles' => true, 'root_dir' => true, 'built_in' => true])
  223. ->treatNullLike(['bundles' => true, 'root_dir' => true, 'built_in' => true])
  224. ->addDefaultsIfNotSet()
  225. ->children()
  226. ->booleanNode('bundles')->defaultFalse()->end()
  227. ->booleanNode('root_dir')->defaultFalse()->end()
  228. ->booleanNode('built_in')->defaultTrue()->end()
  229. ->end()
  230. ->end()
  231. ->arrayNode('types')
  232. ->prototype('array')
  233. ->addDefaultsIfNotSet()
  234. ->beforeNormalization()
  235. ->ifTrue(fn ($v) => isset($v['type']) && is_string($v['type']))
  236. ->then(function ($v) {
  237. if ('yml' === $v['type']) {
  238. $v['types'] = ['yaml'];
  239. } else {
  240. $v['types'] = [$v['type']];
  241. }
  242. unset($v['type']);
  243. return $v;
  244. })
  245. ->end()
  246. ->children()
  247. ->arrayNode('types')
  248. ->prototype('enum')->values(array_keys(ConfigParserPass::SUPPORTED_TYPES_EXTENSIONS))->isRequired()->end()
  249. ->end()
  250. ->scalarNode('dir')->defaultNull()->end()
  251. ->scalarNode('suffix')->defaultValue(ConfigParserPass::DEFAULT_TYPES_SUFFIX)->end()
  252. ->end()
  253. ->end()
  254. ->end()
  255. ->end()
  256. ;
  257. return $node;
  258. }
  259. private function doctrineSection(): ArrayNodeDefinition
  260. {
  261. $builder = new TreeBuilder('doctrine');
  262. /** @var ArrayNodeDefinition $node */
  263. $node = $builder->getRootNode();
  264. // @phpstan-ignore-next-line
  265. $node
  266. ->addDefaultsIfNotSet()
  267. ->children()
  268. ->arrayNode('types_mapping')
  269. ->defaultValue([])
  270. ->prototype('scalar')->end()
  271. ->end()
  272. ->end()
  273. ;
  274. return $node;
  275. }
  276. private function profilerSection(): ArrayNodeDefinition
  277. {
  278. $builder = new TreeBuilder('profiler');
  279. /** @var ArrayNodeDefinition $node */
  280. $node = $builder->getRootNode();
  281. // @phpstan-ignore-next-line
  282. $node
  283. ->addDefaultsIfNotSet()
  284. ->children()
  285. ->scalarNode('query_match')->defaultNull()->end()
  286. ->end()
  287. ;
  288. return $node;
  289. }
  290. private function builderSection(string $name): ArrayNodeDefinition
  291. {
  292. $builder = new TreeBuilder($name);
  293. /** @var ArrayNodeDefinition $node */
  294. $node = $builder->getRootNode();
  295. $node->beforeNormalization()
  296. ->ifTrue(fn ($v) => is_array($v) && !empty($v))
  297. ->then(function ($v) {
  298. foreach ($v as $key => &$config) {
  299. if (is_string($config)) {
  300. $config = [
  301. 'alias' => $key,
  302. 'class' => $config,
  303. ];
  304. }
  305. }
  306. return $v;
  307. })
  308. ->end();
  309. // @phpstan-ignore-next-line
  310. $node->prototype('array')
  311. ->children()
  312. ->scalarNode('alias')->isRequired()->end()
  313. ->scalarNode('class')->isRequired()->end()
  314. ->end()
  315. ->end()
  316. ;
  317. return $node;
  318. }
  319. /**
  320. * @param mixed $disabledValue
  321. */
  322. private function securityQuerySection(string $name, $disabledValue): ScalarNodeDefinition
  323. {
  324. $builder = new TreeBuilder($name, 'scalar');
  325. /** @var ScalarNodeDefinition $node */
  326. $node = $builder->getRootNode();
  327. $node->beforeNormalization()
  328. ->ifTrue(fn ($v) => is_string($v) && is_numeric($v))
  329. ->then(fn ($v) => (int) $v)
  330. ->end();
  331. $node
  332. ->info('Disabled if equal to false.')
  333. ->beforeNormalization()
  334. ->ifTrue(fn ($v) => false === $v)
  335. ->then(fn () => $disabledValue)
  336. ->end()
  337. ->defaultValue($disabledValue)
  338. ->validate()
  339. ->ifTrue(fn ($v) => is_int($v) && $v < 0)
  340. ->thenInvalid(sprintf('"%s.security.%s" must be greater or equal to 0.', self::NAME, $name))
  341. ->end()
  342. ;
  343. return $node;
  344. }
  345. }