Symfony 4 Пользовательский конфигурационный yaml-файл для Bundle

Я пытаюсь преобразовать пакет в symfony 4, и мне нужно обновить мой старый файл parameters.yml до современного образа жизни в symfony 4. Как правило, сам пакет - общий для нескольких приложений - должен иметь настраиваемый файл в / config / packages /.

Однако я получаю эту ошибку:

(1/1) InvalidArgumentException

There is no extension able to load the configuration for "ptmr" (in /var/www/html/ptmr/pws_ptmrio_dev/PtmrBundle/DependencyInjection/../../config/packages/ptmr.yaml). Looked for namespace "ptmr", found none

/PtmrBundle/DependencyInjection/<▪PtmrExtension.php

<?php
namespace PtmrBundle\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class PtmrExtension extends Extension
{

    public function load(array $configs, ContainerBuilder $container)
    {

        $configuration = new Configuration(true);
        $config = $this->processConfiguration($configuration, $configs);

        $loader = new YamlFileLoader(
            $container,
            new FileLocator(__DIR__ . '/../../config/packages')
        );

        $loader->load('ptmr.yaml');

    }


}

/PtmrBundle/DependencyInjection/<▪Configuration.php

<?php
namespace PtmrBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

class Configuration implements ConfigurationInterface
{

    private $debug;

    public function  __construct($debug = true)
    {
        $this->debug = (bool) $debug;
    }

    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder('ptmr');

        $treeBuilder->getRootNode()
            ->children()
            ->arrayNode('twitter')
            ->children()
            ->integerNode('client_id')->end()
            ->scalarNode('client_secret')->end()
            ->end()
            ->end() // twitter
            ->end()
        ;

        return $treeBuilder;
    }
}

/config/packages/

ptmr:
  twitter:
    client_id: 123
    client_secret: your_secret

- Примечание: сам пакет работает.

Я добавил эту строку в psr-4 в composer.json:

    "PtmrBundle\\": "PtmrBundle/"

Эти строки в config / routes / annotations.yml

ptmr_bundle:
    resource: ../PtmrBundle/Controller/
    type: annotation

Эти строки в config / services.yaml

services:
    ...

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

    ...

    PtmrBundle\Controller\:
        resource: '../PtmrBundle/Controller'
        tags: ['controller.service_arguments']

И, конечно же, PtmrBundle / PtmrBundle.php

<?php

namespace PtmrBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class PtmrBundle extends Bundle
{

}

Я следую этим инструкциям и действительно не вижу ошибок. Что мне не хватает? Symfony 4.2.


person ptmr.io    schedule 15.04.2019    source источник
comment
вы добавили его в bundles.php? symfony.com/doc/current/bundles.html   -  person myxaxa    schedule 15.04.2019
comment
Привет да конечно :) сама связка работает нормально. Когда я удаляю строку $ loader- ›load ('ptmr.yaml'); все компилируется как положено - недоступны только параметры.   -  person ptmr.io    schedule 15.04.2019
comment
Избавьтесь от $ loader- ›load ('ptmr.yaml'); Содержимое ptmr.yaml будет вставлено в $ config. Это не исправит вашу ошибку, но поможет. И попытки автоматически подключить ваш пакет в config / services.yaml обычно не заканчиваются хорошо. Закомментируйте и эти строки, пока не пройдете базовое сообщение об отсутствии расширения.   -  person Cerad    schedule 15.04.2019
comment
Комментируя $ loader- ›load (), он компилируется правильно, однако параметры тогда недоступны: Параметр ptmr.twitter должен быть определен.   -  person ptmr.io    schedule 15.04.2019
comment
Вы путаете параметры со значениями конфигурации. Две разные концепции. Обычно ваше расширение изменяет определения сервисов и вводит ваши значения конфигурации. Если вы хотите, чтобы ваша конфигурация действительно была параметрами, просто сделайте их параметрами. Если вы действительно действительно хотите использовать конфигурацию, а затем предоставить некоторые значения в качестве параметров, вы можете сделать это внутри своего расширения, используя ContainerBuilder :: setParameter. Но это было бы очень необычно. Конфиги сбивают с толку. Продолжайте читать документацию, пока она не усвоится.   -  person Cerad    schedule 15.04.2019
comment
@Cerad, спасибо. Действительно, будет достаточно просто ввести значения в раздел параметров файла services.yaml. Однако для академических целей, что не так с приведенным выше кодом :)?   -  person ptmr.io    schedule 15.04.2019
comment
$ Loader- ›load ('ptmr.yaml'); используется для загрузки службы и параметров, определенных в вашем пакете. Вы бы никогда не потянулись из пакета и не попытались получить что-то из приложения. Вы также не стали бы пытаться заставить приложение работать с вашими пакетами пакетов и службами пакетов autowire. Взгляните на некоторые из пакетов Symfony и посмотрите, как они работают. Это может показаться сложным.   -  person Cerad    schedule 15.04.2019
comment
@Cerad, спасибо за объяснение. Я тоже пробовал положить некоторые конфиги в папки с пакетами, но это ничего не меняет. Более того, как тогда другие пакеты помещают файлы конфигурации в папку / config / packages /? (веточка, swiftmailer, ...)   -  person ptmr.io    schedule 16.04.2019
comment
Сами пакеты фактически ничего не помещают в папки конфигурации. Вместо этого расширение Symfony (называемое Flex) для композитора позаботится об этом при установке пакета. Он использует то, что они называют рецептом установки пакета. Раньше разработчикам приходилось копировать файлы конфигурации самостоятельно после установки пакета. По-прежнему подходит для большинства комплектов.   -  person Cerad    schedule 16.04.2019


Ответы (2)


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

Обычно ваш пакет загружает __DIR__.'/../Resources/config/services.yaml, который содержит определения service и parameters. Вне вашего пакета, в вашем приложении config/ dir, вы затем загрузите конфигурацию в свойстве ptmr.

person emarref    schedule 16.04.2019
comment
@Malcom, спасибо. Не могли бы вы привести пример? Глядя, например, в FOSUserBundle, как они с этим справляются? github.com/FriendsOfSymfony/FOSUserBundle/tree/master/Resources/ - person ptmr.io; 16.04.2019
comment
@ ptmr.io - Просто для информации, FOSUserBundle не является хорошим примером чего-либо, хотя это наиболее широко используемые сторонние пакеты. Вместо этого посмотрите на некоторые пакеты Symfony, такие как пакет Framework, SecurityBundle или, возможно, MonologBundle. Кроме того, создайте новый проект и попробуйте добавить свой собственный пакет, следуя документации, сосредоточившись только на конфигурации. - person Cerad; 16.04.2019
comment
Здесь происходит несколько шагов, которые неявно обрабатываются пакетом, когда вы добавляете его в свой файл пакетов. Когда контейнер загружается, он перебирает все зарегистрированные пакеты и по соглашению находит класс расширения. Если обнаружено, вызывается метод загрузки расширения. Здесь вы добавляете конфигурацию контейнера из каталога Resources / config для настройки служб и параметров в контейнере. Позже этап компиляции находит класс конфигурации вашего пакета и дополняет ключи верхнего уровня, о которых знает контейнер. Добавление ptmr в список известных ключей, таких как службы и параметры. - person emarref; 17.04.2019
comment
Однако, чтобы ответить на вопрос в вашем комментарии, метод загрузки на Класс расширения используется для загрузки всех / некоторых из этих XML-файлов в каталог Resources / config. Класс конфигурации используется для расширения контейнера путем добавления fos_user дерево для файлов конфигурации в config/ для использования. Вы заметите, что fos_user конфигурация нигде не используется в самом комплекте. - person emarref; 17.04.2019

Я все-таки нашел ответ. Чтобы создать свой собственный файл параметров config/bundle.yaml, просто выполните:

Шаг 1. Создайте файл в своем пакете DependencyInjection/{BundleNameWithoutBundle}Extension.php, например для MyBundle> MyExtension.php

<?php
namespace MyBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;

class MyExtension extends \Symfony\Component\DependencyInjection\Extension\Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

        $container->setParameter('my', $config);
    }
}

Также см. Как загрузить конфигурацию службы внутри пакета

Шаг 2. Создайте файл конфигурации, который предоставляет схему для вашего файла .yaml DependencyInjection/Configuration.php

<?php

namespace MyBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder('my');

        $treeBuilder->getRootNode()
            ->children()
                ->variableNode('project_name')->end()
            ->end()
        ;

        return $treeBuilder;
    }
}

Также см. Как создать удобную конфигурацию для пакета

Шаг 3. Отразите Configuration.php в своем config/my.yaml

my:
  project_name: "My Name"

Теперь доступен параметр my (задается в классе MyExtension). Просто загрузите его в свой контроллер, например:

class IndexController extends AbstractController
{
    public function indexAction(ParameterBagInterface $parameterBag)
    {
        ...
        dump($parameterBag->get('ptmr'));
        return $this->render('index.html.twig');
    }

}

Примечание. Большинство пакетов идут дальше и манипулируют XML-файлами конфигурации пакетов, что выходит за рамки простого вопроса, подобного этому. Простым примером того, как это сделать, является KnpPaginatorBundle > что не слишком сложно понять по параметрам настроек.

Личное примечание: мне кажется, что документация Symfony слишком сложна и должна содержать простой пример. Вы должны знать много номенклатуры, и это трудно выучить, особенно по сравнению с другими хорошо задокументированными разделами Symfony.

person ptmr.io    schedule 06.03.2020