Duhamel
Duhamel

Reputation: 147

Custom operation in API Platform doesn't autowire the entity

I'am adding custom POST operation as describe https://api-platform.com/docs/core/operations/#recommended-method

But i each time face an error saying my action doesn't find my entity as service:

"hydra:description": "Cannot autowire argument $user of \"App\Controller\SDK\User\UserCreateAction()\": it references class \"App\Entity\SDK\User\" but no such service exists."

Here is my action:

class UserCreateAction extends BaseAction
{
    private $userService;

    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    public function __invoke(User $user)
    {
        return $this->userService->create($user);
    }
}

Normally, the action should automatically recognise the $user entity

Upvotes: 4

Views: 4185

Answers (4)

Duhamel
Duhamel

Reputation: 147

EDIT (2022/29/11): Please refer to the comment of @Cerad below for the fix.

I realised it's because of my services.yml.
Actually, among resources which should be available to be used as service, the Entity/ folder was excluded:

App\:
    resource: '../src/*'
    exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

So I changed it, I removed the "Entity", and it works fine now:

App\:
    resource: '../src/*'
    exclude: '../src/{DependencyInjection,Migrations,Tests,Kernel.php}'

Upvotes: 5

Akiresu
Akiresu

Reputation: 18

The solution is not currently in any of the answers here but is posted in a comment.

@cerad explained the right solution

Warning: the __invoke() method parameter MUST be called $data, otherwise, it will not be filled correctly!

Renaming the param to $data did the job for me. I could find only one reference though (feel free to add a better one): https://github.com/api-platform/core/issues/2184

Upvotes: 0

pushStack
pushStack

Reputation: 4313

Just like any regular controller, make sure services can be injected :

# symfony/config/services.yaml
    App\ApiPlatform\Controller\CreateBookPublication:
        tags: ['controller.service_arguments']

and

<?php
// App\ApiPlatform\Controller\CreateBookPublication.php

namespace App\ApiPlatform\Controller;

use App\Entity\Book;

class CreateBookPublication
{
    private $bookPublishingHandler;

    public function __construct(BookPublishingHandler $bookPublishingHandler)
    {
        $this->bookPublishingHandler = $bookPublishingHandler;
    }

    public function __invoke(Book $data): Book
    {
        $this->bookPublishingHandler->handle($data);

        return $data;
    }
}

Upvotes: 0

alvery
alvery

Reputation: 1983

This is very strange case - you are trying to create user that already exists (api platform loads it from your request uri) This is illegal operation. Remove User $user argument from __invoke and inject Request:

class UserCreateAction extends BaseAction
{
    private $userService;

    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    public function __invoke(Request $request)
    {
        $userFields = \json_decode($request->getContent(), true);

        return $this->userService->create($userFields);
    }
}

To understand how it works read about ParamConverter in symfony. When you trying to inject entity into you controller __invoke method - api platform tries to find entity by {id} in database. This is applicable for item operations.

 *     itemOperations={
 *         "custom": {
 *             "method": "GET",
 *             "path": "/users/{id}",

Upvotes: 1

Related Questions