api-platform icon indicating copy to clipboard operation
api-platform copied to clipboard

Resolver $item for custom mutation no longer pre-populated in 2.6.8

Open BernardA opened this issue 3 years ago • 0 comments

API Platform version(s) affected: 2.6.8

Description
When updating project to Symfony 5.4 and API-Platform 2.6.8, custom mutation no longer pre-populates $item AND when attempting to set properties manually, the relations are not automatically fetched by API-Platform

How to reproduce
/App/Entity/Ad

    *      graphql={
    *          "withCustomArgsMutation"={
    *              "mutation"=AdMutationResolver::class,
    *              "args"={
    *                  "category"={"type"="String!"},
    *                  "description"={"type"="String!"},
    *                  "rentTime"={"type"="Int"},
    *                  "budgetType"={"type"="String"},
    *                  "budget"={"type"="Int"},
    *                  "isOffer"={"type"="Boolean"},
   *                  "image"={"type"="String"},
   *                  "address"={"type"="String!"}
   *              },
   *              "denormalization_context"={
   *                  "groups"={"post"}
   *              },
   *              "normalization_context"={
   *                  "groups"="get"
   *              },
   *              "validation_groups"={"post"},
   *          },

On the Resolver it was only a pass through, as all properties were automatically set to $item by API-Platform:

  final class AdMutationResolver implements MutationResolverInterface
  {
     /**
      * @param Ad|null $item
      *
      * @return Ad
      */
       public function __invoke($item, array $context)
      {
         return $item;
       }

I have now attempted to set type hint the properties but API-Platform will not convert the IRI string to the entity:

 final class AdMutationResolver implements MutationResolverInterface
 {
     /**
      * @param Ad|null $item
      * 
      * @param array $context
      *   $context = [
      *      'args' => ['input =>  [
      *          'isOffer' => (boolean) $isOffer
      *          'category' => (Category::class) $category,
      *          'address' => (Address::class) $address,
      *          'budgetType' => (string) $budgetType,
      *          'budget' => (int) $budget,
      *          'description' => (string) $description,
      *          'rentTime' => (int) $rentTime,
      *         ]
      *      ]
      *   ]
      * 
      * @return Ad
     */
  public function __invoke($item, array $context)
     {
         $item = new Ad();
    dump($context);
         $item->setIsOffer($context['args']['input']['isOffer']);
         $item->setCategory($context['args']['input']['category']);
         $item->setAddress ($context['args']['input']['address']);
         $item->setBudgetType($context['args']['input']['budgetType']);
         $item->setBudget($context['args']['input']['budget']);
         $item->setDescription($context['args']['input']['description']);
         $item->setRentTime($context['args']['input']['rentTime']);
         return $item;
     }
 }

This will error:

"Argument 1 passed to App\Entity\Ad::setCategory() must be an instance of App\Entity\Category or null, string given

I can, of course, fetch Category and Address manually, but that should not be needed. As below:

    $category = $this->categoryRepository->find(str_replace('/api/categories/', '', $context['args']['input']['category']));
    $address = $this->addressRepository->find(str_replace('/api/addresses/', '', $context['args']['input']['address']));

Possible Solution

Additional Context

BernardA avatar May 03 '22 13:05 BernardA