diff --git a/features/graphql/mutation.feature b/features/graphql/mutation.feature
index af1cc6aff6a..7df064279c1 100644
--- a/features/graphql/mutation.feature
+++ b/features/graphql/mutation.feature
@@ -1052,3 +1052,20 @@ Feature: GraphQL mutation support
And the header "Content-Type" should be equal to "application/json"
And the JSON node "errors" should not exist
And the JSON node "data.deleteActivityLog.activityLog" should exist
+
+ @!mongodb
+ Scenario: Mutation should run before validation
+ When I send the following GraphQL request:
+ """
+ mutation {
+ createActivityLog(input: {name: ""}) {
+ activityLog {
+ name
+ }
+ }
+ }
+ """
+ Then the response status code should be 200
+ And the response should be in JSON
+ And the header "Content-Type" should be equal to "application/json"
+ And the JSON node "data.createActivityLog.activityLog.name" should be equal to "hi"
diff --git a/src/Metadata/GraphQl/Operation.php b/src/Metadata/GraphQl/Operation.php
index 5b3aa7338b8..ee78af138ba 100644
--- a/src/Metadata/GraphQl/Operation.php
+++ b/src/Metadata/GraphQl/Operation.php
@@ -40,6 +40,7 @@ public function __construct(
protected ?array $args = null,
protected ?array $extraArgs = null,
protected ?array $links = null,
+ protected ?bool $validateAfterResolver = null,
?string $shortName = null,
?string $class = null,
@@ -195,4 +196,17 @@ public function withLinks(array $links): self
return $self;
}
+
+ public function canValidateAfterResolver(): ?bool
+ {
+ return $this->validateAfterResolver;
+ }
+
+ public function withValidateAfterResolver(bool $validateAfterResolver = true): self
+ {
+ $self = clone $this;
+ $self->validateAfterResolver = $validateAfterResolver;
+
+ return $self;
+ }
}
diff --git a/src/Symfony/Bundle/Resources/config/graphql/validator.xml b/src/Symfony/Bundle/Resources/config/graphql/validator.xml
index c52f56a3b64..fe74a17f24f 100644
--- a/src/Symfony/Bundle/Resources/config/graphql/validator.xml
+++ b/src/Symfony/Bundle/Resources/config/graphql/validator.xml
@@ -6,5 +6,12 @@
+
+
+
+
+
+ canValidateAfterResolver
+
diff --git a/src/Symfony/Validator/State/ValidateProvider.php b/src/Symfony/Validator/State/ValidateProvider.php
index aff0488ee7e..77bbe4c84db 100644
--- a/src/Symfony/Validator/State/ValidateProvider.php
+++ b/src/Symfony/Validator/State/ValidateProvider.php
@@ -23,7 +23,7 @@
*/
final class ValidateProvider implements ProviderInterface
{
- public function __construct(private readonly ?ProviderInterface $decorated, private readonly ValidatorInterface $validator)
+ public function __construct(private readonly ?ProviderInterface $decorated, private readonly ValidatorInterface $validator, private readonly string $canValidateAccessor = 'canValidate')
{
}
@@ -35,7 +35,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
return $body;
}
- if (!($operation->canValidate() ?? true)) {
+ if (method_exists($operation, $this->canValidateAccessor) && !($operation->{$this->canValidateAccessor}() ?? ('canValidate' === $this->canValidateAccessor))) {
return $body;
}
diff --git a/tests/Fixtures/TestBundle/ApiResource/Issue6354/ActivityLog.php b/tests/Fixtures/TestBundle/ApiResource/Issue6354/ActivityLog.php
index 12e0843e4ec..3063db87966 100644
--- a/tests/Fixtures/TestBundle/ApiResource/Issue6354/ActivityLog.php
+++ b/tests/Fixtures/TestBundle/ApiResource/Issue6354/ActivityLog.php
@@ -16,6 +16,7 @@
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GraphQl\DeleteMutation;
+use ApiPlatform\Metadata\GraphQl\Mutation;
use ApiPlatform\Metadata\Operation;
use Symfony\Component\Validator\Constraints\NotBlank;
@@ -29,6 +30,12 @@
new DeleteMutation(
name: 'delete'
),
+ new Mutation(
+ resolver: 'app.graphql.mutation_resolver.activity_log',
+ name: 'create',
+ validateAfterResolver: true,
+ validate: false
+ ),
]
)]
class ActivityLog
diff --git a/tests/Fixtures/TestBundle/ApiResource/Issue6354/CreateActivityLogResolver.php b/tests/Fixtures/TestBundle/ApiResource/Issue6354/CreateActivityLogResolver.php
new file mode 100644
index 00000000000..316410b0d84
--- /dev/null
+++ b/tests/Fixtures/TestBundle/ApiResource/Issue6354/CreateActivityLogResolver.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6354;
+
+use ApiPlatform\GraphQl\Resolver\MutationResolverInterface;
+
+final class CreateActivityLogResolver implements MutationResolverInterface
+{
+ /**
+ * @param object|null $item
+ * @param mixed[] $context
+ */
+ public function __invoke($item, array $context): ActivityLog
+ {
+ if (!$item instanceof ActivityLog) {
+ throw new \InvalidArgumentException('Missing input of type ActivityLog');
+ }
+
+ $item->id = 0;
+ $item->name = 'hi';
+
+ return $item;
+ }
+}
diff --git a/tests/Fixtures/app/config/config_common.yml b/tests/Fixtures/app/config/config_common.yml
index d9edd6f3308..0807d46806d 100644
--- a/tests/Fixtures/app/config/config_common.yml
+++ b/tests/Fixtures/app/config/config_common.yml
@@ -455,3 +455,8 @@ services:
tags:
- name: 'api_platform.parameter_provider'
key: 'ApiPlatform\Tests\Fixtures\TestBundle\Parameter\CustomGroupParameterProvider'
+
+ app.graphql.mutation_resolver.activity_log:
+ class: 'ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue6354\CreateActivityLogResolver'
+ tags:
+ - name: 'api_platform.graphql.resolver'