Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the concept of "validation_mode" #1185

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/validation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ to validate user input data. It currently supports only GraphQL schemas defined

### Contents:
- [Overview](#overview)
- [Mode](#mode)
- [How does it work?](#how-does-it-work)
- [Applying of validation constraints](#applying-of-validation-constraints)
- [Listing constraints directly](#listing-constraints-directly)
Expand Down Expand Up @@ -109,6 +110,20 @@ The `birthdate` field is of type `input-object` and is marked as `cascade` so it
- **month** is between 1 and 12
- **year** is between 1900 and 2019

# Mode

There are two modes for validation, `full` (default) and `partial`.

`full` mode will always validate _all_ arguments/parameters of the type, even if they are not passed (where the types are optional).

`partial` mode will only validate the arguments/parameters that are passed. This can be useful if you want to validate only the data that is actually sent by the client.

To change the mode, you can set the `validation_mode` option in the main configuration:

```yaml
overblog_graphql:
validation_mode: full | partial
```

## How does it work?

Expand Down
16 changes: 16 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function getConfigTreeBuilder(): TreeBuilder
$rootNode
->children()
->append($this->batchingMethodSection())
->append($this->validationModeSection())
->append($this->definitionsSection())
->append($this->errorsHandlerSection())
->append($this->servicesSection())
Expand All @@ -77,6 +78,21 @@ private function batchingMethodSection(): EnumNodeDefinition
return $node;
}

private function validationModeSection(): EnumNodeDefinition
{
$builder = new TreeBuilder('validation_mode', 'enum');

/** @var EnumNodeDefinition $node */
$node = $builder->getRootNode();

$node
->values(['full', 'partial'])
->defaultValue('full')
->end();

return $node;
}

private function errorsHandlerSection(): ArrayNodeDefinition
{
$builder = new TreeBuilder('errors_handler');
Expand Down
6 changes: 6 additions & 0 deletions src/DependencyInjection/OverblogGraphQLExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public function load(array $configs, ContainerBuilder $container): void
$config = $this->processConfiguration($configuration, $configs);

$this->setBatchingMethod($config, $container);
$this->setValidationMode($config, $container);
$this->setServicesAliases($config, $container);
$this->setSchemaBuilderArguments($config, $container);
$this->setSchemaArguments($config, $container);
Expand Down Expand Up @@ -151,6 +152,11 @@ private function setBatchingMethod(array $config, ContainerBuilder $container):
$container->setParameter($this->getAlias().'.batching_method', $config['batching_method']);
}

private function setValidationMode(array $config, ContainerBuilder $container): void
{
$container->setParameter($this->getAlias().'.validation_mode', $config['validation_mode']);
}

private function setDebugListener(array $config, ContainerBuilder $container): void
{
if ($config['definitions']['show_debug_info']) {
Expand Down
1 change: 1 addition & 0 deletions src/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,6 @@ services:
- "@?validator.validator_factory"
- "@?validator"
- "@?translator.default"
- "%overblog_graphql.validation_mode%"
tags:
- { name: overblog_graphql.service, alias: input_validator_factory, public: false }
7 changes: 5 additions & 2 deletions src/Validator/InputValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ final class InputValidator
private ResolveInfo $info;
private ConstraintValidatorFactoryInterface $constraintValidatorFactory;
private ?TranslatorInterface $defaultTranslator;
private string $validationMode;

/** @var ClassMetadataInterface[] */
private array $cachedMetadata = [];
Expand All @@ -50,14 +51,16 @@ public function __construct(
ResolverArgs $resolverArgs,
ValidatorInterface $validator,
ConstraintValidatorFactoryInterface $constraintValidatorFactory,
?TranslatorInterface $translator
?TranslatorInterface $translator,
string $validationMode
) {
$this->resolverArgs = $resolverArgs;
$this->info = $this->resolverArgs->info;
$this->defaultValidator = $validator;
$this->constraintValidatorFactory = $constraintValidatorFactory;
$this->defaultTranslator = $translator;
$this->metadataFactory = new MetadataFactory();
$this->validationMode = $validationMode;
}

/**
Expand Down Expand Up @@ -140,7 +143,7 @@ private function buildValidationTree(ValidationNode $rootObject, iterable $field
$property = $arg['name'] ?? $name;
$config = static::normalizeConfig($arg['validation'] ?? []);

if (!array_key_exists($property, $inputData)) {
if ("partial" === $this->validationMode && !array_key_exists($property, $inputData)) {
// This field was not provided in the inputData. Do not attempt to validate it.
continue;
}
Expand Down
8 changes: 6 additions & 2 deletions src/Validator/InputValidatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,21 @@ final class InputValidatorFactory
private ?ValidatorInterface $defaultValidator;
private ?ConstraintValidatorFactoryInterface $constraintValidatorFactory;
private ?TranslatorInterface $defaultTranslator;
private string $validationMode;

/**
* InputValidatorFactory constructor.
*/
public function __construct(
?ConstraintValidatorFactoryInterface $constraintValidatorFactory,
?ValidatorInterface $validator,
?TranslatorInterface $translator
?TranslatorInterface $translator,
string $validationMode
) {
$this->defaultValidator = $validator;
$this->defaultTranslator = $translator;
$this->constraintValidatorFactory = $constraintValidatorFactory;
$this->validationMode = $validationMode;
}

public function create(ResolverArgs $args): InputValidator
Expand All @@ -39,7 +42,8 @@ public function create(ResolverArgs $args): InputValidator
$args,
$this->defaultValidator,
$this->constraintValidatorFactory,
$this->defaultTranslator
$this->defaultTranslator,
$this->validationMode
);
}
}
1 change: 1 addition & 0 deletions tests/Functional/App/config/validator/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ framework:
enabled: true

overblog_graphql:
validation_mode: partial
definitions:
config_validation: false
class_namespace: "Overblog\\GraphQLBundle\\Validator\\__DEFINITIONS__"
Expand Down
2 changes: 1 addition & 1 deletion tests/Validator/InputValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function testNoDefaultValidatorException(): void
{
$this->expectException(ServiceNotFoundException::class);

$factory = new InputValidatorFactory(null, null, null);
$factory = new InputValidatorFactory(null, null, null, 'full');

$factory->create(new ResolverArgs(
true,
Expand Down
Loading