无法使用键阵列子集访问数组中的表单值

时间:2017-12-20 10:29:13

标签: php arrays forms symfony twig

对于一个项目,我正在与一家公司合作,该公司的地址与该公司相关。我用公司的物理地址为公司创建了一个表格(这个地址总是存在,它还有与之相关的额外地址。这就是我遇到问题的地方。

我正在使用CollectionType为表单为每个额外的地址使用相同的表单。 我正在创建一个表格,其中包含额外地址的预填充值(可以是1,2,3或甚至4个地址):

    $form_adressen = $this
        ->createForm(AdressenType::class, $result['extra_address'])
        ->handleRequest($request)
    ;

但是,这不会呈现表单,也不会从控制器中获取任何值。 但是,以下代码有效:

    $form_adressen = $this
        ->createForm(AdressenType::class, $result)
        ->handleRequest($request)
    ;

结果['extra_address']打印以下数据:

Array
(
    [1059] => Array
        (
            [AdrGid] => 1059
            [AdrCode] => the address type
            [AdrStraat] => streetname
            [AdrHuisnummer] => number
            [AdrPostcode] => postal code
            [AdrPlaats] => cityname
            [AdrTelefoon] => telephone
            [AdrTelefoon2] => mobile
            [AdrTelefax] => fax
            [AdrNawGid] => 332 //id of companyaddress associating to this 'extra' address
            [NawFactuurAdres] => 1
            [AdrOms] => address type description
        )
        [...] // More addresses
}

$result给了我这个:

Array
(
    [company] => Array
        (
            [AdrGid] => 332
            [NawFilZoekcode] => company code
            [AdrNaam1] => company name
            [email2] => company mail
            [NawWebsite] => company website
            [email1] => second company email
            [AdrStraat] => streetname
            [AdrHuisnummer] => number
            [AdrPostcode] => postal code
            [AdrPlaats] => cityname
            [LndOms] => country
            [AdrTelefoon] => telephone
            [AdrTelefoon2] => mobile
            [AdrTelefax] => fax
            [NawFactuurAdres] => 1
            [AdrCode] => adrress type
            [AdrOms] => address type description
        )

    [extra_address] => Array
        (
            [1059] => Array
                (
                    [AdrGid] => 1059
                    [AdrCode] => address type
                    [AdrStraat] => streetname
                    [AdrHuisnummer] => number
                    [...] // etc etc

我的结果数组如下所示:

foreach ($company as $row) {
    $dataFields = [
        [...]
    ];
    foreach ($dataFields as $dataField) {
        if (empty($result['gegevens'][$dataField])) {
            $result['company'][$dataField] = $row[$dataField];
        }
    }
    if ($row['AdrGid'] != $result['gegevens']['AdrGid']) {
        $result['extra_address'][$row['AdrGid']] = [
            [...]
        ];
    }
}

修改 我的AdressenType用于创建表单:

class AdressenType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('addresses', CollectionType::class, [
                'entry_type' => AddressType::class
            ])
        ;
    }
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
        ));
    }
    public function getBlockPrefix()
    {
        return 'appbundle_form_adressenform';
    }
}
class AddressType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            [...] // Add fields
        ;
    }
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
        ));
    }
}

这是我将表单传递给视图的方式:

return $this->render('pages/company/edit.html.twig', array(
    'client' => $result,
    'form' => $form->createView(),
    'form_adressen' => $form_adressen->createView()
));

正如您所看到的,extra_address循环使用id作为数组的键,我猜这就是地址未在视图中显示或呈现的原因。

我使用以下代码遍历每个表单:

{{ form_start(form_adressen, {'  method': 'POST'}) }}
{{ form_row(form_adressen._token) }}
{% for adres in form_adressen.addresses %} // here 'addresses' is my form collectionType, not to be confusing
    [...] // form_widgets, etc
{{ endfor }}
{{ form_end(form_adressen) }}

其中form_adressen是我的formType名称,'addresses'是form_adressen formType的collectionType。

我的问题是,如果每个地址的数组都是id,那么如何用数据填写地址表?我的猜测是表单无法识别键,因此它会跳过。

1 个答案:

答案 0 :(得分:1)

当前AdressenType尝试在['addresses']找到它的数据,但在控制器中通过直接传入额外地址列表来创建表单。

->createForm(AdressenType::class, $result['extra_address'])

此数组可能没有键'addresses',因此表单就像没有条目一样。

所以:

  1. 传递正确的数据:

    ->createForm(AdressenType::class, [
        'addresses' => $result['extra_address']
    ])
    
  2. AdressenType中的密钥更改为'extra_address'并传入$result

    $builder
        ->add('extra_address', CollectionType::class, [
            'entry_type' => AddressType::class
        ])
    ;
    

    ->createForm(AdressenType::class, $result)
    
  3. 或更好,更改AdressenType以直接扩展CollectionType。哪个(恕我直言)是更好/更清洁的事情,因为它消除了对任意数组键的依赖:

    <?php
    // ...
    use Symfony\Component\Form\Extension\Core\Type\CollectionType;
    
    class AdressenType extends AbstractType
    {
        /**
         * @inheritdoc
         */
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults([
                'entry_type' => AddressType::class,
            ]);
        }
    
        /**
         * @inheritdoc
         */
        public function getParent()
        {
            // extend the collection type
            return CollectionType::class;
        }
    }
    

    使用:

    ->createForm(AdressenType::class, $result['extra_address'])
    

    在视图中,您可以将其用作:

    <h4>Extra addresses</h4>
    {{ form_start(form_adressen) }}
        {% for address in form_adressen.children %}
            {{ form_errors(address) }}
            {{ form_widget(address) }}
            <br>
        {% endfor %}
    
        <button>Submit</button>
    {{ form_end(form_adressen) }}
    
  4. 使用第三个选项,当您尝试自定义表单呈现时,可能会遇到问题。像这样使用自动注入的csrf-token将是地址的兄弟。如果您尝试访问每个子项的单个字段,则可能会导致错误。

    虽然以下情况适用于该情况:

    {% for key, value in form_adressen.vars.data %}
        {{ form_row(form_adressen.children[key].AdrStraat) }}
        {{ form_row(form_adressen.children[key].AdrHuisnummer) }}
        {{ form_row(form_adressen.children[key].AdrPostcode) }}
        <br>
    {% endfor %}