Как реализовать классы Configuration и AppExtension для приложения в Symfony 4?

Это для Symfony 4.

Мне нужно реализовать приложение (не пакет), параметры конфигурации с помощью DependencyInjection \ Configuration и DependencyInjection \ AppExtension.

Я создал оба класса, как и для связки. Пространство имен для каждого - App \ DependencyInjection.

Имена файла и класса - Configuration и AppExtension, соответственно, находятся в src / DependencyInjection /.

В настоящее время Конфигурация просто определяет два скалярных узла для простоты.

// src/DependencyInjection/Configuration.php

namespace App\DependencyInjection;

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

class Configuration implements ConfigurationInterface
{
  public function getConfigTreeBuilder( )
  {
    $treeBuilder = new TreeBuilder();
    $rootNode    = $treeBuilder->root( 'app' );
    $rootNode
      ->addDefaultsIfNotSet()
      ->children()
        ->scalarNode( 'a1' )
          ->defaultValue( 'I am the default value for a1' )
        ->end()
        ->scalarNode( 'a2' )
          ->defaultValue( 'I am the default value for a2' )
        ->end()
      ->end();
    return $treeBuilder;
  }    
} 

Класс AppExtension реализует два метода: __construct () и load ().
Метод __construct () просто повторяет имя своего метода.
В настоящее время метод load () умирает (__METHOD__); просто чтобы убедиться, что я знаю, называется ли он. Это не так.

// src/DependencyInjection/AppExtension.php

namespace App\DependencyInjection;

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

class AppExtension extends Extension
{
  public function __construct()
  {
    echo __METHOD__ . "()\n";
  }

  public function load( array $configs, ContainerBuilder $container )
  {
    die( __METHOD__ );
  }
}

Я также создал файл конфигурации:

# config/app.yml
app:
  a1: 'A one'
  a2: 'A two'

Ответ на этот вопрос указывает, что мне нужно включить вызов $ container-> registerExtension () в метод configureContainer () моего файла src / kernel.php, поэтому я добавил это.

protected function configureContainer( ContainerBuilder $container, LoaderInterface $loader )
{
  $container->registerExtension( new AppExtension() );
  ...
}

Когда я запускаю команду console cache: clear, вызывается конструктор AppExtension, но никогда не вызывается метод load ().

Выполнение команды console debug: config app приводит к этой ошибке:

Нет расширений с конфигурацией, доступной для "приложения".

Что мне не хватает?
TIA


person David Patterson    schedule 19.02.2018    source источник
comment
Вам нужно будет зарегистрировать класс App Bundle, чтобы расширение и конфигурация работали должным образом. Раньше с самим названием пакета было связано какое-то majic. Не уверен, сколько осталось. Придется немного поэкспериментировать с наименованием. Конечно, весь смысл перехода на приложение без связки состоит в том, чтобы избежать всего этого. Так что вы можете расслабиться и убедиться, что вы точно понимаете, чего пытаетесь достичь.   -  person Cerad    schedule 20.02.2018
comment
Я не возражаю против создания пакета для приложения. Я вижу выгоды, достигнутые за счет устранения этого требования и упрощения src / tree. Что мне не нравится, так это то, что я не могу определять иерархическую конфигурацию для моих приложений. У меня есть приложения под Symfony 3, где конфигурация приложения (а не пакетов) составляет от трех до четырех уровней (да, это сложные приложения, работающие с устаревшими данными на большом железе). Итак, нет возможности реализовать настоящую конфигурацию приложения без пакета приложений? Если так, то это настоящий облом. :-(   -  person David Patterson    schedule 20.02.2018
comment
Чтобы создать пакет, вам нужен только один файл, поэтому я не уверен, что назвал бы это большим обломом. Я не собираюсь заходить так далеко, чтобы сказать, что создание файла пакета - это единственный способ реализовать настоящую конфигурацию. У вас есть полный контроль над ядром, и вы можете переопределить несколько методов. Похоже, вы ее решили. Здорово.   -  person Cerad    schedule 20.02.2018
comment
@Cerad, спасибо за подсказку о необходимости использовать бандл. Оказывается, довольно просто (см. Мой ответ). Похоже, мы не должны этого делать. Я не могу быть единственным разработчиком Symfony, которому иногда требуются сложные конфигурации приложений.   -  person David Patterson    schedule 20.02.2018
comment
Я думаю, что использование бандла - правильный подход. И пакет, и расширение для внедрения зависимостей являются частью компонента http-ядра. Использование пакета - вот как вы должны расширить контейнер.   -  person Cerad    schedule 20.02.2018
comment
Вообще-то я согласен. Так как в нужном месте нужен только пустой класс пакета, единственная реальная проблема - не забыть добавить соответствующие комментарии, чтобы бедняга, появившийся через год, не ушел. Это Symfony 4. Приложение не предназначено. чтобы иметь файл пакета. и удалите его. Этим парнем, вероятно, был бы я. :-) Кроме того, он сохраняет простоту нового макета каталога приложений.   -  person David Patterson    schedule 20.02.2018


Ответы (2)


Так. У меня есть решение.
Это требует трех вещей помимо обычных классов Configuration и AppExtension в src / DependencyInjection /

Реализуйте пустой класс App \ AppBundle, который расширяет Bundle, и поместите его в src /

// src/AppBundle.php
namespace App;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle {}

Добавьте запись для пакета в массив, возвращаемый config / bundles.php

<?php
// config/bundles.php
return [
    ...
    App\AppBundle::class => ['all' => true],
]

Поместите параметры конфигурации в config / packages / app.yaml

# config/packages/app.yaml
app:
  a1: 'A1 from app.yaml'
  a2: 'A2 from app.yaml'

  array_one:
    a:  { attr1: 'attribute one', attr2: 'two' }
    b:  { attr1: 'attribute one', attr2: 'two' }

У меня это действительно работает.
Между прочим, в этом случае вам не нужно регистрировать расширение в Kernel.php.

person David Patterson    schedule 19.02.2018

В первоначальном посте не хватало только одной строчки, чтобы заставить его работать без создания лишнего пакета:

src / DependencyInjection.
- AppExtension.
- AppConfiguration

В src / Kernel.php:

protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader)
{
    //...

    $container->registerExtension(new AppExtension());
    $container->loadFromExtension('app'); //this was missing in initial question

    //...
}
person Mr.B    schedule 30.10.2018