Symfony 4 не поддерживает автоматическое подключение динамических контроллеров маршрута

Версия Symfony: 4.1.3

У меня есть приложение, которое загружает динамические маршруты на основе конфигурации с помощью службы загрузчика маршрутов, но кажется, что Symfony 4 не выполняет автоматическое подключение контроллеров динамического маршрута.

Я использую стандартный файл services.yaml приложения Symfony 4:

/config/services.yaml

parameters:
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
Application\Web\:
resource: '../src/*'
exclude: '../src/{Search/Model,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
Application\Web\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']

Маршрутный загрузчик: src/Component/RouteLoader.php

<?php

namespace Application\Web\Component;

use Application\Symfony\Bundle\ConfigBundle\ReaderInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

/**
* Class RouteLoader
* @package Application\Web\Component
*/
class RouteLoader
{
/**
* @var ReaderInterface
*/
private $configurationReader;

public function __construct(ReaderInterface $configurationReader)
{
$this->configurationReader = $configurationReader;
}

public function load(): RouteCollection
{
$routes = new RouteCollection();
foreach ($this->configurationReader->find('category_navigation') as $label => $configuration) {
$slug = strtolower($label);
$route = new Route(
$configuration['url'],
[
'_controller' => [$configuration['controller'], 'dispatch'],
'categories_slug' => $slug,
'category_label' => $label,
'page_title' => $configuration['page_title'] ?? null,
'page_description' => $configuration['page_description'] ?? null,
],
[],
[],
'',
[],
['GET']
);
$routes->add($slug . '.home', $route);
}

return $routes;
}
}

Конструктор контроллера: src/Controller/Page.php

<?php

namespace Application\Web\Controller;

//.... other class code

public function __construct(
ClientInterface $client,
ReaderInterface $configurationReader,
\Twig_Environment $twigEnvironment,
ContentSearcher $contentSearcher,
Environment $environment,
TokenStorageInterface $tokenStorage,
UrlGeneratorInterface $urlGenerator
)

Когда я пытаюсь загрузить страницу, Symfony скулит со следующей ошибкой:

Controller "\Application\Web\Controller\Page" has required constructor arguments and does not exist in the container. Did you forget to define such a service?

Однако, когда я определяю маршрут непосредственно в config/routes.yaml файл, контроллер автоматически подключен в стиле без проблем!

Мои вопросы:

  • Является ли это ограничением возможности автоматической разводки Symfony, то есть не поддерживается для динамических контроллеров маршрутов?
  • Есть ли что-то, что я упускаю, когда дело доходит до определения маршрутов, которые заставят автопроводку работать?
  • Я потенциально обнаружил ошибку?

Есть идеи?

РЕДАКТИРОВАТЬ: следы стека

InvalidArgumentException:
Controller "\Application\Web\Controller\Page" has required constructor arguments and does not exist in the container. Did you forget to define such a service?

at vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php:62
at Symfony\Component\HttpKernel\Controller\ContainerControllerResolver->instantiateController('\\Application\\Web\\Controller\\Page')
(vendor/symfony/framework-bundle/Controller/ControllerResolver.php:54)
at Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver->instantiateController('\\Application\\Web\\Controller\\Page')
(vendor/symfony/http-kernel/Controller/ControllerResolver.php:49)
at Symfony\Component\HttpKernel\Controller\ControllerResolver->getController(object(Request))
(vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php:38)
at Symfony\Component\HttpKernel\Controller\TraceableControllerResolver->getController(object(Request))
(vendor/symfony/http-kernel/HttpKernel.php:132)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
(vendor/symfony/http-kernel/HttpKernel.php:66)
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
(vendor/symfony/http-kernel/Kernel.php:188)
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
(public/index.php:37)


ArgumentCountError:
Too few arguments to function Application\Web\Controller\Base::__construct(), 0 passed in /var/www/html/vendor/symfony/http-kernel/Controller/ControllerResolver.php on line 133 and exactly 7 expected

at src/Controller/Base.php:55
at Application\Web\Controller\Base->__construct()
(vendor/symfony/http-kernel/Controller/ControllerResolver.php:133)
at Symfony\Component\HttpKernel\Controller\ControllerResolver->instantiateController('\\Application\\Web\\Controller\\Page')
(vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php:55)
at Symfony\Component\HttpKernel\Controller\ContainerControllerResolver->instantiateController('\\Application\\Web\\Controller\\Page')
(vendor/symfony/framework-bundle/Controller/ControllerResolver.php:54)
at Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver->instantiateController('\\Application\\Web\\Controller\\Page')
(vendor/symfony/http-kernel/Controller/ControllerResolver.php:49)
at Symfony\Component\HttpKernel\Controller\ControllerResolver->getController(object(Request))
(vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php:38)
at Symfony\Component\HttpKernel\Controller\TraceableControllerResolver->getController(object(Request))
(vendor/symfony/http-kernel/HttpKernel.php:132)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
(vendor/symfony/http-kernel/HttpKernel.php:66)
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
(vendor/symfony/http-kernel/Kernel.php:188)
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
(public/index.php:37)

1

Решение

Отвечая на ваши вопросы:

  1. Нет, по крайней мере, в этом случае. Единственная роль загрузчика маршрутов — это создание набора маршрутов, чтобы запрос мог быть сопоставлен с ним. Предоставляя _controller параметр, вы говорите SF, какой контроллер сопоставлен с этим маршрутом. Компонент Dependency Injection отвечает за автоматическую загрузку контроллеров в контейнер как сервис. Но если контроллер достигает ContainerControllerResolver и переходит от строк 50-52, это определенно связано с тем, что ваш контроллер не зарегистрирован в качестве службы (или, точнее, из-за того, что, каково бы ни было значение $class в ContainerControllerResolver::instantiateController() не существует в контейнере).
  2. Я не могу воспроизвести, так как у меня нет ваших услуг. Но мое лучшее предположение, что, вероятно, не работает прохождение _controller аргумент как своего рода вызываемый массив. Попробуйте передать это как строку Application/Web/Pages::instance, ContainerControllerResolver умеет с этим работать.
  3. У меня есть сомнения, но это вероятно.

Было бы очень полезно увидеть трассировку стека.

ОБНОВИТЬ:

У вас есть двойная обратная косая черта в строке, которая соответствует имени вашего класса. Попробуйте переформатировать, чтобы: Application\Web\Controller\Page,

Если вы хотите быть уверенным в этом исправлении перед рефакторингом, запустите bin/console debug:container Page и проверьте, существует ли ваш Page контроллер как сервис. Если это так, то проблема, скорее всего, заключается в FQCN с двойной обратной косой чертой.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector