Skip to content

MutationResolverInterface no longer working properly in v3.3 #6354

Closed
@NicoHaase

Description

@NicoHaase

API Platform version(s) affected: 3.3.x

Description
In my project, I use a MutationResolver to set the value of the currently logged in user to an entity ActivityLog during a GraphQL mutation. The mutation itself does not contain a value for the user, instead it's loaded from Symfony's Security component. A validator ensures that the User entity assigned to ActivityLog matches some conditions.

In v.3.2, this worked properly: the entity was populated properly and validated afterwards. After updating to ApiPlatform v3.3, the validation stage is already run before the MutationResolver can set the User entity. The validation fails, as the User entity on ActivityLog is still null

How to reproduce
Configuration for the entity:

#[ApiResource(
    graphQlOperations: [
        new Mutation(
            resolver: CreateActivityLogResolver::class,
            name: 'create'
        )
    ]
)]
class ActivityLog
{
// some other variables

    #[EqualsLoggedInUser]
    #[ORM\ManyToOne(targetEntity: User::class)]
    private User $user;
}

Configuration for the resolver:

<?php

declare(strict_types=1);

namespace App\Resolver;

use ApiPlatform\GraphQl\Resolver\MutationResolverInterface;
use App\Entity\ActivityLog;
use App\Entity\User;
use InvalidArgumentException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;

class CreateActivityLogResolver implements MutationResolverInterface
{
    public function __construct(
        private readonly TokenStorageInterface $tokenStorage
    ) {
    }

    /**
     * @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');
        }

        $token = $this->tokenStorage->getToken();

        if (!$token instanceof TokenInterface) {
            throw new AccessDeniedHttpException('Missing user');
        }

        $user = $token->getUser();

        if (!$user instanceof User) {
            throw new AccessDeniedHttpException('Missing user');
        }

        $item->setUser($user);

        return $item;
    }
}

Configuration for the validator:

class EqualsLoggedInUserValidator extends ConstraintValidator
{
    /**
     * @param User $value
     */
    public function validate($value, Constraint $constraint): void
    {
        if (!$constraint instanceof EqualsLoggedInUser) {
            throw new UnexpectedTypeException($constraint, EqualsLoggedInUser::class);
        }

        if (!$value instanceof User) {
// this is where the validator stage throws an exception
            throw new UnexpectedTypeException($value, User::class);
        }
   }
}

Possible Solution
I'm not sure where this behaviour changed, but I would expect that the MutationResolver has finished its work before the validator is run

Additional Context

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions