From 1e0c08493bee36753686f61a21f5f1d9f96c3f06 Mon Sep 17 00:00:00 2001 From: Anatoliy Melnikau Date: Mon, 25 Jul 2022 11:23:15 +0300 Subject: [PATCH 1/6] Ignore IDE configs --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 638ad6a42..9730d573c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea phpunit.xml /build /vendor From df90ef08a42f2e4caa5d0616320e2f258d65b88d Mon Sep 17 00:00:00 2001 From: Anatoliy Melnikau Date: Mon, 25 Jul 2022 11:25:56 +0300 Subject: [PATCH 2/6] Define default configs by constant instead of static property --- src/DependencyInjection/Compiler/ConfigParserPass.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/DependencyInjection/Compiler/ConfigParserPass.php b/src/DependencyInjection/Compiler/ConfigParserPass.php index 19178e0de..4e031d349 100644 --- a/src/DependencyInjection/Compiler/ConfigParserPass.php +++ b/src/DependencyInjection/Compiler/ConfigParserPass.php @@ -52,7 +52,7 @@ class ConfigParserPass implements CompilerPassInterface 'attribute' => AttributeParser::class, ]; - private static array $defaultDefaultConfig = [ + private const DEFAULT_CONFIG = [ 'definitions' => [ 'mappings' => [ 'auto_discover' => [ @@ -65,6 +65,12 @@ class ConfigParserPass implements CompilerPassInterface ], ]; + /** + * @deprecated Use {@see ConfigParserPass::PARSERS }. Added for the backward compatibility. + * @var array> + */ + private static array $defaultDefaultConfig = self::DEFAULT_CONFIG; + private array $treatedFiles = []; private array $preTreatedFiles = []; @@ -170,7 +176,7 @@ private function checkTypesDuplication(array $typeConfigs): void private function mappingConfig(array $config, ContainerBuilder $container): array { // use default value if needed - $config = array_replace_recursive(self::$defaultDefaultConfig, $config); + $config = array_replace_recursive(self::DEFAULT_CONFIG, $config); $mappingConfig = $config['definitions']['mappings']; $typesMappings = $mappingConfig['types']; From 3d62d903e96829d5fad4ed26de8ec02bb8e18e20 Mon Sep 17 00:00:00 2001 From: Anatoliy Melnikau Date: Mon, 25 Jul 2022 11:37:52 +0300 Subject: [PATCH 3/6] Update phpDoc --- src/DependencyInjection/Compiler/ConfigParserPass.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DependencyInjection/Compiler/ConfigParserPass.php b/src/DependencyInjection/Compiler/ConfigParserPass.php index 4e031d349..8e1f90722 100644 --- a/src/DependencyInjection/Compiler/ConfigParserPass.php +++ b/src/DependencyInjection/Compiler/ConfigParserPass.php @@ -8,6 +8,7 @@ use Overblog\GraphQLBundle\Config\Parser\AnnotationParser; use Overblog\GraphQLBundle\Config\Parser\AttributeParser; use Overblog\GraphQLBundle\Config\Parser\GraphQLParser; +use Overblog\GraphQLBundle\Config\Parser\ParserInterface; use Overblog\GraphQLBundle\Config\Parser\PreParserInterface; use Overblog\GraphQLBundle\Config\Parser\YamlParser; use Overblog\GraphQLBundle\DependencyInjection\TypesConfiguration; @@ -43,7 +44,7 @@ class ConfigParserPass implements CompilerPassInterface ]; /** - * @var array> + * @var array> */ public const PARSERS = [ 'yaml' => YamlParser::class, From 255bf3afefb10d71b8e9db2a78a04edb13b4c5d7 Mon Sep 17 00:00:00 2001 From: Anatoliy Melnikau Date: Mon, 25 Jul 2022 11:48:27 +0300 Subject: [PATCH 4/6] Make parsers configurable --- .../Compiler/ConfigParserPass.php | 50 +++++++++++++------ src/DependencyInjection/Configuration.php | 28 +++++++++++ 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/DependencyInjection/Compiler/ConfigParserPass.php b/src/DependencyInjection/Compiler/ConfigParserPass.php index 8e1f90722..fb15d2aec 100644 --- a/src/DependencyInjection/Compiler/ConfigParserPass.php +++ b/src/DependencyInjection/Compiler/ConfigParserPass.php @@ -36,21 +36,34 @@ class ConfigParserPass implements CompilerPassInterface { + public const TYPE_YAML = 'yaml'; + public const TYPE_GRAPHQL = 'graphql'; + public const TYPE_ANNOTATION = 'annotation'; + public const TYPE_ATTRIBUTE = 'attribute'; + + public const SUPPORTED_TYPES = [ + self::TYPE_YAML, + self::TYPE_GRAPHQL, + self::TYPE_ANNOTATION, + self::TYPE_ATTRIBUTE, + ]; + public const SUPPORTED_TYPES_EXTENSIONS = [ - 'yaml' => '{yaml,yml}', - 'graphql' => '{graphql,graphqls}', - 'annotation' => 'php', - 'attribute' => 'php', + self::TYPE_YAML => '{yaml,yml}', + self::TYPE_GRAPHQL => '{graphql,graphqls}', + self::TYPE_ANNOTATION => 'php', + self::TYPE_ATTRIBUTE => 'php', ]; /** + * @deprecated They are going to be configurable. * @var array> */ public const PARSERS = [ - 'yaml' => YamlParser::class, - 'graphql' => GraphQLParser::class, - 'annotation' => AnnotationParser::class, - 'attribute' => AttributeParser::class, + self::TYPE_YAML => YamlParser::class, + self::TYPE_GRAPHQL => GraphQLParser::class, + self::TYPE_ANNOTATION => AnnotationParser::class, + self::TYPE_ATTRIBUTE => AttributeParser::class, ]; private const DEFAULT_CONFIG = [ @@ -64,6 +77,7 @@ class ConfigParserPass implements CompilerPassInterface 'types' => [], ], ], + 'parsers' => self::PARSERS, ]; /** @@ -93,6 +107,10 @@ private function getConfigs(ContainerBuilder $container): array $config = $container->getParameterBag()->resolveValue($container->getParameter('overblog_graphql.config')); $container->getParameterBag()->remove('overblog_graphql.config'); $container->setParameter($this->getAlias().'.classes_map', []); + + // use default value if needed + $config = array_replace_recursive(self::DEFAULT_CONFIG, $config); + $typesMappings = $this->mappingConfig($config, $container); // reset treated files $this->treatedFiles = []; @@ -103,7 +121,7 @@ private function getConfigs(ContainerBuilder $container): array // Pre-parse all files AnnotationParser::reset($config); AttributeParser::reset($config); - $typesNeedPreParsing = $this->typesNeedPreParsing(); + $typesNeedPreParsing = $this->typesNeedPreParsing($config['parsers']); foreach ($typesMappings as $params) { if ($typesNeedPreParsing[$params['type']]) { $this->parseTypeConfigFiles($params['type'], $params['files'], $container, $config, true); @@ -122,10 +140,15 @@ private function getConfigs(ContainerBuilder $container): array return $flattenTypeConfig; } - private function typesNeedPreParsing(): array + /** + * @param array $parsers + * + * @return array + */ + private function typesNeedPreParsing(array $parsers): array { $needPreParsing = []; - foreach (self::PARSERS as $type => $className) { + foreach ($parsers as $type => $className) { $needPreParsing[$type] = is_a($className, PreParserInterface::class, true); } @@ -152,7 +175,7 @@ private function parseTypeConfigFiles(string $type, iterable $files, ContainerBu continue; } - $parser = [self::PARSERS[$type], $method]; + $parser = [$configs['parsers'][$type], $method]; if (is_callable($parser)) { $config[] = ($parser)($file, $container, $configs); } @@ -176,9 +199,6 @@ private function checkTypesDuplication(array $typeConfigs): void private function mappingConfig(array $config, ContainerBuilder $container): array { - // use default value if needed - $config = array_replace_recursive(self::DEFAULT_CONFIG, $config); - $mappingConfig = $config['definitions']['mappings']; $typesMappings = $mappingConfig['types']; diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 18a2b335c..7e04a9cef 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -7,6 +7,7 @@ use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter; use GraphQL\Validator\Rules\QueryComplexity; use GraphQL\Validator\Rules\QueryDepth; +use Overblog\GraphQLBundle\Config\Parser\ParserInterface; use Overblog\GraphQLBundle\Definition\Argument; use Overblog\GraphQLBundle\DependencyInjection\Compiler\ConfigParserPass; use Overblog\GraphQLBundle\Error\ErrorHandler; @@ -57,6 +58,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->append($this->securitySection()) ->append($this->doctrineSection()) ->append($this->profilerSection()) + ->append($this->parsersSection()) ->end(); return $treeBuilder; @@ -318,6 +320,32 @@ private function doctrineSection(): ArrayNodeDefinition return $node; } + private function parsersSection(): ArrayNodeDefinition + { + /** @var ArrayNodeDefinition $node */ + $node = (new TreeBuilder('parsers'))->getRootNode(); + $node->useAttributeAsKey('name'); + + $parserPrototype = $node->scalarPrototype(); + $parserPrototype->cannotBeEmpty(); + $parserPrototype->validate() + ->ifTrue(static function (string $x): bool { + return !is_subclass_of($x, ParserInterface::class, true); + }) + ->thenInvalid(sprintf('Parser MUST implement "%s', ParserInterface::class)); + + $node->validate() + ->ifTrue(static function (array $x): bool { + return (bool) array_diff(array_keys($x), ConfigParserPass::SUPPORTED_TYPES); + }) + ->then(static function (array $x) { + $types = implode(', ', array_diff(array_keys($x), ConfigParserPass::SUPPORTED_TYPES)); + throw new \InvalidArgumentException(sprintf('Configured parsers for not supported types: %s', $types)); + }); + + return $node; + } + private function profilerSection(): ArrayNodeDefinition { $builder = new TreeBuilder('profiler'); From 73794470d32d88cf5f6ac10a2557d824c3a62503 Mon Sep 17 00:00:00 2001 From: Anatoliy Melnikau Date: Mon, 25 Jul 2022 15:44:38 +0300 Subject: [PATCH 5/6] Add documentation about parsers configuration --- README.md | 1 + docs/tune_configuration.md | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 docs/tune_configuration.md diff --git a/README.md b/README.md index 241484d34..dbe8cd3ad 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ Documentation - [Errors handling](docs/error-handling/index.md) - [Events](docs/events/index.md) - [Profiler](docs/profiler/index.md) +- [Tune configuration](docs/tune_configuration.md) Talks and slides to help you start ---------------------------------- diff --git a/docs/tune_configuration.md b/docs/tune_configuration.md new file mode 100644 index 000000000..954ffad9b --- /dev/null +++ b/docs/tune_configuration.md @@ -0,0 +1,22 @@ +Tune configuration +================== + +Custom GraphQl configuration parsers +------------------------------------ + +You can configure custom GraphQl configuration parsers. +Your parsers MUST implement at least `\Overblog\GraphQLBundle\Config\Parser\ParserInterface` +and optionally `\Overblog\GraphQLBundle\Config\Parser\PreParserInterface` when required. + +Default values will be applied when omitted. + +```yaml +overblog_graphql: + # ... + parsers: + yaml: 'Overblog\GraphQLBundle\Config\Parser\YamlParser' + graphql: 'Overblog\GraphQLBundle\Config\Parser\GraphQLParser' + annotation: 'Overblog\GraphQLBundle\Config\Parser\AnnotationParser' + attribute: 'Overblog\GraphQLBundle\Config\Parser\AttributeParser' + # ... +``` From 556e1fb07d56f07bdaba383d18834887a6bd6282 Mon Sep 17 00:00:00 2001 From: Anatoliy Melnikau Date: Mon, 25 Jul 2022 21:51:10 +0300 Subject: [PATCH 6/6] Allow plugin phpstan/extension-installer --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 68fb15164..28a3ece10 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,9 @@ } }, "config": { + "allow-plugins": { + "phpstan/extension-installer": true + }, "bin-dir": "bin", "sort-packages": true },