У меня следующая ситуация, основанная на Компоненты OptionsResolver:
bar
а также foo
, и то и другое null
по умолчанию.bar
вариант принимает B
значение также.foo
вариант принимает A
, B
, C
, D
значения также.Теперь, когда эти параметры разрешены, если foo
опция равна A
, bar
опция должна быть изменена на B
но мне тоже нужно: если foo
опция равна A
или же B
это должно быть изменено на C
,
Я пытался реализовать это, но ожидаемый результат неверен:
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
$resolver = new OptionsResolver();
$resolver->setDefaults(array(
'bar' => null,
'foo' => null,
));
$resolver->setAllowedValues('bar', array(null, 'B'));
$resolver->setAllowedValues('foo', array(null, 'A', 'B', 'C', 'D'));
$resolver->setNormalizer('bar', function (Options $options, $value) {
if ('A' === $options['foo']) {
return 'B';
}
return $value;
});
$resolver->setNormalizer('foo', function (Options $options, $value) {
if ('A' === $value || 'B' === $value) {
$value = 'C';
}
return $value;
});
$options = $resolver->resolve(array('foo' => 'A'));
var_dump($options);
это всегда возвращает:
array(2) {
["foo"] => string(1) "C"["bar"] => NULL // wrong normalization, expected `B` value.
}
Проблема в том, что 'A' === $options['foo']
заявление в bar
нормализатор звонки foo
нормализатор (т.е. $options->offsetGet('foo')
), прежде чем выполнить условие, поэтому для этого теста всегда проверяет 'A' === 'C'
а также bar
опция не нормализована успешно.
Как это работает?
ИМО это ненадежно использовать этот подход. Вам всегда придется полагаться на порядок нормализации, и очень легко заблудиться.
Я предпочел бы использовать третий вариант baz
который не будет изменен и будет как исходные данные для bar
а также foo
,
$resolver = new OptionsResolver();
$resolver->setDefaults(array(
'bar' => null,
'foo' => null,
'baz' => null,
));
$resolver->setAllowedValues('bar', array(null, 'B'));
$resolver->setAllowedValues('foo', array(null, 'A', 'B', 'C', 'D'));
$resolver->setAllowedValues('baz', array(null, 'A', 'B', 'C', 'D'));
$resolver->setNormalizer('bar', function (Options $options, $value) {
if ('A' === $options['baz']) {
return 'B';
}
return $value;
});
$resolver->setNormalizer('foo', function (Options $options, $value) {
if ('A' === $options['baz'] || 'B' === $options['baz']) {
$value = 'C';
} else {
return $options['baz'];
}
});
$options = $resolver->resolve(array('baz' => 'A'));
Ну, это ужасный обходной путь, но это код, который я наконец-то реализовал:
$resolver = new OptionsResolver();
$resolver->setDefaults(array(
'foo' => null, // <-- move to top to make sure to normalize first that bar
'bar' => null, // for internal use
));
$resolver->setAllowedValues('bar', array(null, 'B'));
$resolver->setAllowedValues('foo', array(null, 'A', 'B', 'C', 'D'));
$bar = null;
$resolver->setNormalizer('foo', function (Options $options, $value) use (&$bar) {
if ('A' === $value) {
$bar = 'B';
}
if ('A' === $value || 'B' === $value) {
$value = 'C';
}
return $value;
});
$resolver->setNormalizer('bar', function (Options $options, $value) use (&$bar) {
return $bar;
});
$options = $resolver->resolve(array('foo' => 'A'));