【问题标题】:Define a form option allowed values depending on another option value in a FormType根据 FormType 中的另一个选项值定义表单选项允许的值
【发布时间】:2016-02-04 15:22:05
【问题描述】:

在 Symfony 2.8 中,在自定义表单类型中,是否可以让 setAllowedValues 返回取决于另一个选项的值的结果?据我所知,没有明显的方法可以访问闭包中的 Options 对象。

public function configureOptions(OptionsResolver $resolver) {
    $resolver->setRequired('option1');
    $resolver->setRequired('option2');

    $resolver->setAllowedValues('option2', function ($value) {
        return $based_on_set_restricted_by_option1; // <-- option2 values are allowed or denied depending on what option1 says
    }
}

与我所拥有的解决方案最接近的想法是有一个选项,它是一个封装选项 1 和选项 2 的字典,并在其上执行 setAllowedValues ,但现在重组选项并不容易。

【问题讨论】:

  • 您是否尝试过在该函数中使用$resolver-&gt;offsetGet('option1'); 来获得option1 的解析值,以便您可以将option2 建立在此基础上?我相信您可以通过这种方式获得价值。
  • "数组访问仅在惰性选项和规范化器的闭包中受支持。" Symfony 说。
  • 好吧,看来你必须按照 Heah 建议的方式去做

标签: symfony configuration symfony-forms options


【解决方案1】:

symfony 表单类型的方法configureOptions() 可以做很多事情,因为它提供了一个OptionsResolver 对象(依赖于它自己的组件see)来调整您的配置。

在这种情况下,您需要调用 $resolver-&gt;setNormalizer() (see),这正是您想要的,一旦设置了其他选项并可以调用,它需要一个选项来定义。

当解析器规范化您的选项时,它通过将所有选项的数组作为第一个参数传递,并将要规范化的选项的设置值作为第二个参数传递来执行可调用对象:

// class CustomFormType extends \Symfony\Component\Form\Extension\Core\Type\AbstractType

use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefault('some_option', 'default value');

    // or many at once
    $resolver->setDefaults(array(
        'some_option' => 0,
        'range_condition' => null,
    );

    // what you need
    $someOptionNormalizer = function (Options $options, $someOption) {
        $rangeCondition = $options['range_condition'];

        if (in_array($rangeCondition, range(2, 5))) {
            if (in_array($someOption, range(6, 9))) {

                return $someOption;
            }

            throw new InvalidOptionsException(sprintf('When "range_condition" is inferior or equal to 5, "some_option" should be between 6 and 9, but "%d" given.', $someOption));
        }

        if (in_array($rangeCondition, range(10, 13))) {
            if (in_array($someOption, range(1000, 1005))) {

                return $someOption;
            }

            throw new InvalidOptionsException(sprintf('When "range_condition" is between 10 and 13, "some_option" should be between 1000 and 1005, but "%d" given.', $someOption));
        }
    };

    $resolver->setNormalizer('some_option', $someOptionNormalizer);

    // you can also do
    $resolver->setRequired('some_option');
    $resolver->setAllowedTypes('some_option', array('integer'));
    $resolver->setAllowedTypes('range_condition', array('null', 'integer'));
    $resolver->setAllowedValues('some_option', array_merge(range(6, 9), range(1000, 1005)));
    $resolver->setAllowedValues('range_condition', array_merge(range(2, 5), range(10, 13)));

    // ...

}

【讨论】:

  • 您的解决方案对我没有帮助。如果另一个选项满足或不满足某些约束,我不需要切换布尔值并继续我的快乐方式。我需要:如果 other_option 在范围 [2..5] 内,我需要 some_option 仅允许范围 [6..9],但如果 other_option 在范围 [10..13] 内,则允许 some_option [1000。 ..1005] 代替。如果不满足复合限制,我想要一个例外。 - 编辑:我猜你想让 some_option 在规范化器尝试将其设置为无效值时抛出异常(但你的示例没有这样做)。
  • 当然,我可以自己在规范器中抛出该异常,但我想知道如果我这样做会破坏什么。
  • 我刚刚浏览了 EntityType 源代码,他们就是这样做的:在规范化器中抛出异常。不是我的第一选择,但如果 Symfony 这样做,我也可以。那就是要走的路。
  • @RaduC 这只是一个示例,因为您在问题中没有提供具体的逻辑,但我尝试更新以更好地反映您的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-31
  • 2023-03-13
  • 1970-01-01
  • 2021-12-16
  • 2013-01-13
相关资源
最近更新 更多