Symfony 2.7选择表单元素重复标签错误


Symfony 2.7 choice form element duplicate label error

设置一个带有选项数组的选项元素,值"6 Door"会出现3次。在数组中,键被保留,在symfony生成的元素中,最后一个键覆盖所有值匹配的前一个键。

我是不是忽略了一些简单的事情?

表单元素如下:

->add('category', 'choice', array(
    'required' => false,
    'choices' => $this->form_repository->getOptionsForSelect(),
));
    // configure data_class
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
                'data_class' => ''AppBundle'Model'DirectorySearch'
            ));
    }

form_repository::getOptionsForSelect()

function(){
    $q = ...
    $results = $q->getQuery()->getResult();
    $return = array();
    foreach($results as $form) {
        foreach($form->getElements() as $element){
            $options = array();
            foreach($element->getMultiOptions() as $multi_option) {
                $options[$multi_option->getId()] = $multi_option->getLabel();
            }
            $return[$element->getLabel()] = $options;
        }
    }
    return $return;
}

getOptionsForSelect:返回的数组

array (size=3)
  'Car Brand' => 
    array (size=4)
      221 => string '6 Door' (length=6)
      222 => string 'Toyota' (length=6)
      223 => string 'Jaguar' (length=6)
      224 => string 'Skodai' (length=6)
  'Car Doors Count' => 
    array (size=2)
      226 => string '6 Door' (length=6)
      227 => string 'Green' (length=5)
  'Car Doors' => 
    array (size=5)
      228 => string '1 Door' (length=6)
      229 => string '2 Door' (length=6)
      230 => string '3 Door' (length=6)
      231 => string '4 Door' (length=6)
      232 => string '6 Door' (length=6)

Select生成-注意到所有6个门标签现在都使用值=232:

<select id="category" name="category" class="form-control">
    <option value=""></option>
    <optgroup label="Car Brand">
        <option value="232">6 Door</option>
        <option value="222">Toyota</option>
        <option value="223">Jaguar</option>
        <option value="224">Skodai</option>
    </optgroup>
    <optgroup label="Car Doors Count">
        <option value="232">6 Door</option>
        <option value="227">Green</option>
    </optgroup>
    <optgroup label="Car Doors">
        <option value="228">1 Door</option>
        <option value="229">2 Door</option>
        <option value="230">3 Door</option>
        <option value="231">4 Door</option>
        <option value="232">6 Door</option>
    </optgroup>
</select>

我注意到如果在表单中转储$builder->get('category')->getOptions()
"选项"键显示上面的数组,选项列表显示这一点,缺少所有重复标记的选项。

'choice_list' => 
    object(Symfony'Component'Form'ChoiceList'ArrayKeyChoiceList)[1208]
      private 'useChoicesAsValues' => boolean false
      protected 'choices' => 
        array (size=9)
          '6 Door' => int 232
          'Toyota' => int 222
          'Jaguar' => int 223
          'Skodai' => int 224
          'Green' => int 227
          '1 Door' => int 228
          '2 Door' => int 229
          '3 Door' => int 230
          '4 Door' => int 231
      protected 'values' => 
        array (size=9)
          '6 Door' => string '232' (length=3)
          'Toyota' => string '222' (length=3)
          'Jaguar' => string '223' (length=3)
          'Skodai' => string '224' (length=3)
          'Green' => string '227' (length=3)
          '1 Door' => string '228' (length=3)
          '2 Door' => string '229' (length=3)
          '3 Door' => string '230' (length=3)
          '4 Door' => string '231' (length=3)
      protected 'valueCallback' => 
        object(Closure)[1209]

表单的数据类:

class DirectorySearch implements Search
{
    private $keyword = '';
    private $company_name = '';
    private $stand_number = '';
    private $town_region = '';
    private $postcode = '';
    private $country = null;
    private $category = null;
    private $page = 1;
    public function __construct(array $options = array())
    {
        $this->keyword = isset($options['keyword']) ? $options['keyword'] : '';
        $this->company_name = isset($options['company_name']) ? $options['company_name'] : '';
        $this->stand_number = isset($options['stand_number']) ? $options['stand_number'] : '';
        $this->town_region = isset($options['town_region']) ? $options['town_region'] : '';
        $this->postcode = isset($options['postcode']) ? $options['postcode'] : '';
        $this->country = isset($options['country']) ? $options['country'] : null;
        $this->category = isset($options['category']) ? $options['category'] : null;
        $this->page = isset($options['page']) ? $options['page'] : 1;
    }
    public function getKeyword() { return $this->keyword; }
    public function setKeyword($keyword) { $this->keyword = $keyword; }
    public function getCompanyName() { return $this->company_name; }
    public function setCompanyName($company_name) { $this->company_name = $company_name; }
    public function getStandNumber() { return $this->stand_number; }
    public function setStandNumber($stand_number) { $this->stand_number = $stand_number; }
    public function getTownRegion() { return $this->town_region; }
    public function setTownRegion($town_region) { $this->town_region = $town_region; }
    public function getPostcode() { return $this->postcode; }
    public function setPostcode($postcode) { $this->postcode = $postcode; }
    public function getCountry() { return $this->country; }
    public function setCountry($country) { $this->country = $country; }
    public function getCategory() { return $this->category; }
    public function setCategory($category) { $this->category = $category; }
    public function getPage() { return $this->page; }
    public function setPage($page) { $this->page = $page; }
    public function toArray()
    {
        $data = array(
            'keyword' => $this->getKeyword(),
            'company_name' => $this->getCompanyName(),
            'stand_number' => $this->getStandNumber(),
            'town_region' => $this->getTownRegion(),
            'postcode' => $this->getPostcode(),
            'country' => $this->getCountry(),
            'category' => $this->getCategory(),
            'page' => $this->getPage(),
        );
        return $data;
    }
}

我已经深入研究了Symfony 2.7的源代码,我可以给你一个很好的提示。

首先,在选项中使用数组key,因为在symfony 2.7中不赞成使用html option value,所以由于它会给您带来问题,我认为您应该直接使用"正确"的新方法。您面临的问题是由于内部使用了一些array_flip

从Symfony 2.7开始,您可以将choices_as_value设置为字段(与Symfony 3.0向前兼容),并以html label为键传递一系列选项(在您的模型中,有时它可能是一个类)。

在您的情况下:

function(){
    $q = ...
    $results = $q->getQuery()->getResult();
    $return = array();
    foreach($results as $form) {
        foreach($form->getElements() as $element){
            $options = array();
            foreach($element->getMultiOptions() as $multi_option) {
                // note this line
                $options[$multi_option->getLabel()] = (int) $multi_option->getId();
            }
            $return[$element->getLabel()] = $options;
        }
    }
    return $return;
}

你会得到以下数组:

[
    'Car Brand' => [
        '6 Door' => 221,
        'Toyota' => 222,
        'Jaguar' => 223,
        'Skodai' => 224,
    ],
    'Car Doors Count' => [
        '6 Door' => 226,
        'Green' => 227,
    ],
    'Car Doors' => [
        '1 Door' => 228,
        '2 Door' => 229,
        '3 Door' => 230,
        '4 Door' => 231,
        '6 Door' => 232,
    ]
]

组和条目现在感觉更加一致了。您可以使用choices_as_value:

->add('category', 'choice', array(
    'required' => false,
    'choices' => $this->form_repository->getOptionsForSelect(),
    'choices_as_value' => true,
    'choice_value' => function ($currentChoice) {
        return $currentChoice;
    },
));

选项choice_value用于用您自己的策略覆盖默认的html option value生成策略;因为您使用的是整数,所以只需使用choice作为html value(例如,如果您有一个类,它应该是$currentChoice->getId()