Behat 3 — как получить собственное расширение в контексте

Мне нужно добавить, а затем из контекста получить дополнительные параметры / конфигурации из файла behat.yml.

Behat не позволяет мне добавлять некоторые случайные параметры в файл behat.yml, поэтому я создал новое собственное расширение. Это расширение позволяет мне передавать определенные значения конфигурации

extensions:
App\Behat\DevToolsExtension:
api_url: "https://api.example.com"

Так что теперь behat не жалуется на новую конфигурацию в файле behat.yml.

Теперь я застрял. Как я могу получить эту конфигурацию из моего расширения во время выполнения?

Я устанавливаю существующие параметры в своем расширении в методе публичной функции load (ContainerBuilder $ container, array $ config) следующим образом:

$container->setParameter($configKey . $key, $config[$key]);

Опять же, есть ли способ извлечь этот объект ContainerBuilder или DevToolsExtension в контексте?

Решением было создать сервисный контейнер и передать в него behats ContainerBuilder примерно так:

class AppExtension implements ExtensionInterface
{
// ...
public function load(ContainerBuilder $container, array $config)
{
$configKey = $this->getConfigKey() . '.';

foreach ($this->keys as $key) {
$keyValue = $configKey . $key;
$container->setParameter($keyValue, $config[$key]);
}

$this->getServiceLocator()->setBehatContainer($container);
}

А затем использовать сервисный локатор для получения параметров конфигурации

$value = $this->getBehatContainer()->getParameter($key);

2

Решение

Это хороший вопрос. Базовые контексты не имеют ссылок наверх, поэтому вы не можете узнать, какие расширения загружены. Расширения инициализируются и подключаются к внутренней системе событий. Когда контексты инициализируются, они получают уведомление и могут передавать им необходимые параметры. Зная это, вы можете создать правильное расширение, которое подключается к системе событий Behat и передает конфигурацию в ваш контекст — это был бы способ сделать это.

Расширение Mink является хорошим примером этого, вы, вероятно, не найдете никакой документации, но вы можете создать конструктор в одном из ваших (Mink) контекстов, добавить туда точку останова и следовать трассировке, чтобы узнать, как все это работает. ,

Но … В большинстве случаев это было бы излишним. То же самое может быть (и должно быть) достигнуто с помощью внешнего файла конфигурации, который вы можете загрузить из своего контекста, или путем передачи параметров в ваш контекст (так же, как вы делаете это сейчас с расширением). Последний вариант может работать не очень хорошо, если у вас много контекстов, которые нуждаются в такой конфигурации.

1

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

Я имел эту проблему и решил это для проекта: CLIPBOARD

Наверняка, работает на ~ v3.0
Вероятно, работает на v2.5.

В вашем классе Exntesion после создания расширения вам нужен инициализатор, который инициализирует любой контекст в системе. Для этого вам нужно создать сервис в контейнере с ContextExtension :: INITIALIZER_TAG и зависит от конфигурации. я имею

$container->setParameter('dev_tools_extension.parameters', $config);

А потом

private function loadContextInitializer(ContainerBuilder $container)
{
$definition = new Definition(
'App\Behat\DevToolsExtension\Context\Initializer\DevToolsExtensionInitializer', array(
'%dev_tools_extension.parameters%'
)
);
$definition->addTag(ContextExtension::INITIALIZER_TAG, array('priority' => 0));
$container->setDefinition('dev_tools_extension.context_initializer', $definition);
}

Инициализатор реализует Behat \ Behat \ Context \ Initializer \ ContextInitializer с помощью вызываемого контекста. Затем вы создаете (например, интерфейс) и вызываете функцию в контексте. Я имею:

    /**
* Initializes provided context.
*
* @param Context $context
*/
public function initializeContext(Context $context)
{
if (!$context instanceof ClipboardContextInterface) {
return;
}
/** @var ClipboardContextInterface $context */

$context->setClipboard($this->clipboard);
}
3