@galliard

Почему не работает Extending Action Argument Resolving в symfony4?

Речь пойдет про эту компоненту:
https://symfony.com/doc/current/controller/argumen...

Вроде сделал все по инструкции, код получился такой:
namespace App\ArgumentResolver;

use App\Domain\VO\UserId;
use Generator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;

class UserIdResolver implements ArgumentValueResolverInterface {
    public function supports(Request $request, ArgumentMetadata $argument): bool {
        return UserId::class === $argument->getType();
    }

    public function resolve(Request $request, ArgumentMetadata $argument): Generator {
        yield new UserId($request->get('userId'));
    }
}

namespace App\Domain\VO;

class UserId {
    private $value;

    public function __construct(string $value) {
        $this->value = $value;
    }

    public function __toString(): string {
        return $this->value;
    }
}

namespace App\Controller;

use App\Domain\VO\UserId;
use FOS\RestBundle\Controller\Annotations as Rest;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

class UserController {
    /**
     * @Rest\Get("/users/{userId}")
     */
    public function getUserById(UserId $userId): void {
        var_dump($userId);
        die('1234');
    }
}

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: false       # Allows optimizing the container by removing unused services; this also means
                            # fetching services directly from the container via $container->get() won't work.
                            # The best practice is to be explicit about your dependencies anyway.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/*'
        exclude: '../src/{Domain,Entity,Migrations,Tests,Kernel.php}'

    # controllers are imported separately to make sure services can be injected
    # as action arguments even if you don't extend any base controller class
    App\Controller\:
        resource: '../src/Controller'
        tags: ['controller.service_arguments']

    App\ArgumentResolver\UserIdResolver:
        class: App\ArgumentResolver\UserIdResolver
        tags:
            - { name: controller.argument_value_resolver, priority: 50 }

"require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "friendsofsymfony/rest-bundle": "^2.3",
        "jms/serializer-bundle": "^2.3",
        "sensio/framework-extra-bundle": "^5.1",
        "symfony/apache-pack": "^1.0",
        "symfony/console": "^4.0",
        "symfony/flex": "^1.0",
        "symfony/framework-bundle": "^4.0",
        "symfony/lts": "^4@dev",
        "symfony/yaml": "^4.0"
    },
    "require-dev": {
        "symfony/dotenv": "^4.0",
        "symfony/web-server-bundle": "^4.0"
    },


Всю папку Domain я добавил в exclude, иначе возникает конфликт с автовайрином (пытается создать экземпляр UserId, но натыкается на неизвестный аргумент конструктора).

В данный момент выдает ошибку, что в первый аргумент int, а не UserId. Код в классе UserIdResolver вообще не запускается (не реагирует на die())? хотя сам класс загружается. Изменение приоритета не помогает.

ЧЯДНТ?
  • Вопрос задан
  • 322 просмотра
Решения вопроса 1
BoShurik
@BoShurik Куратор тега Symfony
Symfony developer
Проблема в том, что RequestAttributeValueResolver отрабатывает раньше, соответственно до вашего резолвера дело не доходит.

Варианты решения:
1. Увеличить приоритет (сделать больше 100)
App\ArgumentResolver\UserIdResolver:
        class: App\ArgumentResolver\UserIdResolver
        tags:
            - { name: controller.argument_value_resolver, priority: 101 }

2. В параметрах роута использовать другое название переменных, не совпадающее с параметрами экшена
class UserController {
    /**
     * @Rest\Get("/users/{userId}")
     */
    public function getUserById(UserId $id): void {
        var_dump($id);
        die('1234');
    }
}

Тогда можно будет избавиться от конфига
App\ArgumentResolver\UserIdResolver:
        class: App\ArgumentResolver\UserIdResolver
        tags:
            - { name: controller.argument_value_resolver, priority: 50 }

т.к. тег controller.argument_value_resolver добавляется автоматически на основании интерфейса
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы