在实体FormType-Symfony3中使用另一个实体信息

时间:2017-03-01 13:55:49

标签: forms symfony

在Ubuntu16.04上使用PhpStorm.2016.3.2和Symfony3

我有一个与名为Restaurant的实体相关的FormType.php。

在这个实体中,我有一个名为city_id的外键与一个名为city的实体相连。 所以在我的FormType中,我实际上成功地使用EntityType::class来调用我的城市实体:

->add('city', EntityType::class, array(
            'class'                 => 'AppBundle:City',
            'choice_label'          => 'name',
        ))

这实际上有效,我的页面上出现button,我可以从我的数据库中选择我的城市。

enter image description here

但我遇到了一个小问题。如果我的用户想要添加像Amsterdam这样的新城市,该怎么办?

我如何在FormType.php我的实体city

中执行此操作

1 个答案:

答案 0 :(得分:2)

我建议您在表单类型中使用事件侦听器/订阅者。你可以看看how to dynamically modify forms using form events

如何处理:当用户在您选择的字段中选择一个名为" city"然后,监听器/订户添加文本字段以允许用户写入城市名称。

因此,在您的表单类型中,您可以添加如下事件订阅者:

$builder->addEventSubscriber(new CityFieldSubscriber($builder->getFormFactory(), 'city', $options['manager']);

请注意,您需要将实体管理器作为表单类型的选项传递。

然后创建订阅者(这是一个示例。我没有执行此代码,因此可能存在错误):

class CityFieldSubscriber implements EventSubscriberInterface
{
    protected $factory;
    protected $fieldName;
    protected $listenedFieldName;
    protected $repository;
    protected $optionId;

    public function __construct(FormFactoryInterface $factory, ObjectManager $manager)
    {
        $this->factory              = $factory;
        $this->fieldName            = 'cityName'; // text field to add
        $this->listenedFieldName    = 'city'; // entity field to listen
        $this->repository           = $manager->getRepository('AppBundle:City');
        $this->optionId             = 0; // The value of the option in your select field
    }

    public static function getSubscribedEvents()
    {
        return [
            FormEvents::POST_SET_DATA   => 'postSetData',
            FormEvents::PRE_SUBMIT      => 'preSubmit'
        ];
    }

    private function addCityForm(FormInterface $form, City $city = null)
    {
        if (null !== $city) {
            if ($city->getId() === $this->optionId) {
                $form->add($this->fieldName, TextType::class, [
                    'label' => 'app.form.type.cityName.label',
                    'required' => true
                ]);
            }
        }
    }

    public function postSetData(FormEvent $event)
    {
        $city = $event->getForm()->get($this->listenedFieldName)->getData();

        if ($city) {
            $this->addCityForm($event->getForm(), $city);
        } else {
            $this->addCityForm($event->getForm());
        }
    }

    public function preSubmit(FormEvent $event)
    {
        $data = $event->getData();

        if (isset($data[$this->listenedFieldName]) && $data[$this->listenedFieldName] !== '') {
            $this->addCityForm($event->getForm(), $this->repository->find($data[$this->listenedFieldName]));
        }

        if (!isset($data[$this->listenedFieldName])) {
            $this->addCityForm($event->getForm());
        }
    }
}

之后,您需要编写一些javascript代码以在必要时添加文本字段。见这个例子:

<script>
    var form = $('#form');
    var formUrl = '{{ url('app_front_form') }}';

    function replaceIfExistsOrRemove(selector, beforeSelectors, dom) {
        var $new = $(dom).find(selector).parent('.form-group');
        if ($new.length == 0) {
            $(selector).parent('.form-group').remove();
        } else {
            if ($(selector).length > 0) {
                $(selector).parent('.form-group').replaceWith($new);
            } else {
                for (i in beforeSelectors) {
                    if ($(beforeSelectors[i]).length > 0) {
                        $(beforeSelectors[i]).parent('.form-group').after($new);
                        return;
                    }
                }
            }
        }
    }

    form.on('change', '#form_city', function() {
        $('#form_submit_button').prop('disabled', true);
        $.get(formUrl, $form.serialize(), function(html) {
            $('#form_submit_button').prop('disabled', false);
            replaceIfExistsOrRemove('#form_cityName', ['#form_city'], html);
        });
    });
</script>

提交表单后,如果表单有效,则保存此新城市并将其设置在您的实体中。

我希望这会对你有所帮助:)。