Php Silex-Symfony2:表单自动填充用于文本表单,而不是用于选择

Php Silex-Symfony2:表单自动填充用于文本表单,而不是用于选择,php,forms,symfony,silex,autofill,Php,Forms,Symfony,Silex,Autofill,首先,祝大家2016年新年快乐 我面临着一个我自己没能解决的问题 我正在开发Silex(~1.3)应用程序。我在我的域类上编写了简单的CRUD代码。我还创建了一些类型表单,以便能够修改我的基本域类。在这种情况下,我必须在国家内管理国家的概念。每个都是一个特定的类,State有一个Country属性 在我的表单中,我声明了一些文本字段和一个能够选择国家的Choice字段(表单类复制如下) 我的问题是,当我尝试使用以下控制器修改现有的状态时,文本字段name,code,unloc将填充数据库中的数据

首先,祝大家2016年新年快乐

我面临着一个我自己没能解决的问题

我正在开发Silex(
~1.3
)应用程序。我在我的域类上编写了简单的CRUD代码。我还创建了一些类型表单,以便能够修改我的基本域类。在这种情况下,我必须在
国家
内管理
国家
的概念。每个都是一个特定的类,
State
有一个
Country
属性

在我的表单中,我声明了一些文本字段和一个能够选择国家的
Choice
字段(表单类复制如下)

我的问题是,当我尝试使用以下控制器修改现有的
状态时,文本字段
name
code
unloc
将填充数据库中的数据,而不是选择
country
hub
(控制器类复制如下)

请注意,我不是在使用教义,而是一把自制的(非常基本的)刀

以下是我的代码和一些信息:

  • 视图是使用twig完成的,带有“标准”引导示例,可在此处找到:,使用和:

  • 表格编号:

    <?php
    
    namespace Easytrip2\Form\Type;
    
    use Easytrip2\DAO\CountryDAO;
    use Easytrip2\DAO\GeopointDAO;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    
    class StateType extends AbstractType {
        /**
         * @CountryDAO
         * \Easytrip2\DAO\CountryDAO
         * allow to find the Country for the form.
         */
        private $countryDAO;
        /**
         * @GeopointDAO
         * \Easytrip2\DAO\GeopointDAO
         * allow to find the Country for the form.
         */
        private $geopointDAO;
        /**
         *
         * {@inheritDoc}
         *
         * @see \Symfony\Component\Form\AbstractType::buildForm()
         */
        public function buildForm(FormBuilderInterface $builder, array     $options) {
            $builder->add ( 'name', 'text', array (
                    'label' => 'State name'
            ) );
            $builder->add ( 'code', 'text', array (
                    'label' => 'State code'
            ) );
            $builder->add ( 'unloc', 'text', array (
                    'label' => 'State code'
            ) );
            $countries = $this->countryDAO->findAll ();
            $choices = array ();
            $labels = array ();
            foreach ( $countries as $value ) {
                $choices [] = $value;
                $labels [] = $value->getName ();
            }
            $builder->add ( 'country', 'choice', array (
                    'choice_list' => new ChoiceList ( $choices, $labels )
            ) );
    
            $hubs = $this->geopointDAO->findAllHubs ();
            $choices = array ();
            $labels = array ();
            foreach ( $hubs as $value ) {
                $choices [] = $value;
                $labels [] = $value->getName ();
            }
            $builder->add ( 'hub', 'choice', array (
                    'choice_list' => new ChoiceList ( $choices, $labels ),
                    'required' => false
            ) );
        }
    
        /**
         *
         * {@inheritDoc}
         *
         * @see \Symfony\Component\Form\AbstractType::configureOptions()
         */
        public function configureOptions(OptionsResolver $resolver) {
            $resolver->setDefaults ( array (
                    'data_class' => 'Easytrip2\Domain\State'
            ) );
        }
    
        /**
         *
         * {@inheritDoc}
         *
         * @see \Symfony\Component\Form\FormTypeInterface::getName()
         */
        public function getName() {
            return 'state';
        }
        /**
         * allow use of a CountryDAO
         */
        public function __construct(CountryDAO $countryDAO, GeopointDAO     $geopointDAO) {
            $this->geopointDAO = $geopointDAO;
            $this->countryDAO = $countryDAO;
        }
    }
    

  • 假设由于国家/地区和集线器id未传输到ChoiceList,所以选项未填充来自DB的数据

    $choices = array();
    foreach ($countries as $value) {
        $choices[$value->getId()] = $value->getName();
    }
    $builder->add('country', 'choice', array(
        'choices' => $choices
    ));
    

    我设法找到了一个解决方案(可能不是最好的,但它是有效的)

    我的理解是:我们将对象作为
    选项
    ,使用它作为值,然后使用闭包来获取
    ID
    标签
    ,而不是自己完成工作并向表单提供“随时可用”数据

    有没有更干净的方法

    $obj = $this->countryDAO->findAll ();
    $list = array ();
    foreach ( $obj as $value ) {
        $list [$value->getId ()] = $value;
    }
    $builder->add ( 'country', 'choice', array (
        'choices' => $list,
        'choices_as_values' => true,
        'choice_label' => function ($value) {
            return $value->getName ();
        },
        'choice_value' => function ($value) {
        // you mightwant to check for null here, is your form concern
        // a attribute that can be null, as the closure appear to be called
        // on the attribute, and not only on the $obj contents;
            return $value->getId ();
        },
        'placeholder' => 'Select a country'
    ) );
    

    将此行添加到您的选择选项:
    
    “选择作为值”=>true,
    

    必须激活新的choice类型API

    我看到了那篇文章,但问题略有不同(它适用于文本字段,而不适用于选项列表,因为它在文章中根本不起作用)。我试过了,但问题仍然存在。好主意!我使用的是表单工厂,它得到了我正在构建的对象。表单不直接获取对象。您知道如何将链接对象传递到窗体的较低级别吗?我在这里使用表单有误吗?谢谢!假设您的代码是正确的,但您有一个错误。您只将选项传输到没有ID的国家名称,所以窗体不能根据对象国家属性选择选项。看看我回答的例子。啊,你是对的,我没有注意到变化。我刚试过,现在Silex告诉我,
    选项“choice”不存在
    ,告诉我这应该是一个很长的列表,包含
    “choice\u attr”、“choice\u label”、“choice\u list”、“choice\u loader”、“choice\u name”、“choice\u translation\u domain”、“choice\u value”、“choices”、“choices\u as\u values”
    。如果我修改它以匹配
    选项
    ,我会得到另一个错误,告诉我silex无法加载类型
    选项
    。我有点迷茫,我开始觉得我的设置错误,因为我没有与文档描述的行为相同的行为:(.option-choices,type-choice.Try
    $builder->add('country',Symfony\Component\Form\Extension\Core\Type\ChoiceType::class,array('choices'=>$choices));
    您好,我以前试过,它确实有效(它显示正确),但在属性为对象的情况下,不会在表单中填充对象数据。我猜在没有给出闭包的情况下,会发生比较对象,并且由于某种原因而失败。
    public function stateUpdateByIdAction($id, Request $request, Application $app) {
            if ($app ['security.authorization_checker']->isGranted ( 'IS_AUTHENTICATED_FULLY' ) and $app ['security.authorization_checker']->isGranted ( 'ROLE_ADMIN' )) {
                $obj = $app ['dao.state']->findById ( $id );
                $form = $app ['form.factory']->create ( new StateType ( $app ['dao.country'], $app ['dao.geopoint'] ), $obj );
                $form->handleRequest ( $request );
                if ($form->isSubmitted () && $form->isValid ()) {
                    if ($app ['dao.state']->save ( $obj )) {
                        $app ['session']->getFlashBag ()->add ( 'success', 'The state was succesfully updated.' );
                        return $app->redirect ( $app ['url_generator']->generate ( 'state' ) );
                    } else {
                        $app ['session']->getFlashBag ()->add ( 'error', 'Something went wrong...' );
                    }
                }
                return $app ['twig']->render ( 'form.html.twig', array (
                        'form' => $form->createView (),
                        'title' => 'Edit states'
                ) );
            } else {
                $app ['session']->getFlashBag ()->add ( 'error', 'Don\'t have the rights...' );
                return $app->redirect ( $app ['url_generator']->generate ( 'home' ) );
            }
        }
    
    $choices = array();
    foreach ($countries as $value) {
        $choices[$value->getId()] = $value->getName();
    }
    $builder->add('country', 'choice', array(
        'choices' => $choices
    ));
    
    $obj = $this->countryDAO->findAll ();
    $list = array ();
    foreach ( $obj as $value ) {
        $list [$value->getId ()] = $value;
    }
    $builder->add ( 'country', 'choice', array (
        'choices' => $list,
        'choices_as_values' => true,
        'choice_label' => function ($value) {
            return $value->getName ();
        },
        'choice_value' => function ($value) {
        // you mightwant to check for null here, is your form concern
        // a attribute that can be null, as the closure appear to be called
        // on the attribute, and not only on the $obj contents;
            return $value->getId ();
        },
        'placeholder' => 'Select a country'
    ) );