【问题标题】:Silex - Symfony2 : Forms autofilled for text forms, not for choicesSilex - Symfony2:为文本表单自动填充的表单,而不是用于选择
【发布时间】:2016-01-04 15:27:25
【问题描述】:

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

我遇到了一个我自己无法解决的问题。

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

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

我的问题是,当我尝试使用以下控制器修改现有 State 时,文本字段 namecodeunloc 填充了数据库中的数据,而不是选项 @ 987654335@也不是hub(控制器类复制如下)。

请注意,我使用的不是 Doctrine,而是一个自制的(非常基本的)DAO。

这是我的代码和一些信息:

  1. 视图是使用 twig 完成的,“标准”引导示例可以在这里找到:Form Customization,使用 Bootstrap layoutForm layout

    {% extends 'layout.html.twig' %} {% block title %}{{ title }}{% endblock %}
    {% block content %}
        {% if form and is_granted('IS_AUTHENTICATED_FULLY') and is_granted('ROLE_ADMIN')%}
            {% form_theme form 'bootstrap_3_layout.html.twig' %} {{ form_start(form) }}
                <div class="form-group">
                    {{ form_errors(form) }}
                    {{ form_widget(form) }}
                    <input type="submit" class="btn btn-primary" value={% if button is not defined %} "Save"{% else %}"{{ button }}"{% endif %} />
                </div>
            {{ form_end(form) }}
        {% else %}
            <div>
                <p>Ask an admin to add/modify information.</p>
            </div>
        {% endif %}
    {% endblock %}
    
  2. composer.json 内容:

    {
        "require": {
            "silex/silex": "~1.3",
            "doctrine/dbal": "2.5.*",
            "symfony/security": "2.7.*",
            "twig/twig": "1.21.*",
            "symfony/twig-bridge": "2.7.*",
            "symfony/form": "2.7.*",
            "symfony/translation": "2.7.*",
            "symfony/config": "2.7.*",
            "jasongrimes/silex-simpleuser": "*",
            "twig/extensions": "1.3.*",
            "symfony/validator": "2.*",
            "phpoffice/phpexcel": "1.*"
        },
        "require-dev": {
            "phpunit/phpunit": "*",
            "symfony/browser-kit": "*",
            "symfony/css-selector": "*",
            "silex/web-profiler": "*",
            "symfony/monolog-bridge": "*"
        },
        "autoload":{
            "psr-4":{"Easytrip2\\": "src"}
        }
    }
    
  3. 表格代码:

    <?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;
        }
    }
    
  4. 控制器内容:

    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' ) );
            }
        }
    

【问题讨论】:

  • 我看到了那个帖子,但问题略有不同(它适用于文本字段,不适用于选择列表,因为它在帖子中根本不起作用)stackoverflow.com/questions/20500115/…。无论如何我都试过了,但问题仍然存在。

标签: php forms symfony silex autofill


【解决方案1】:

假设由于国家和中心 id 没有传输到 ChoiceList 中,所以选择没有填充来自 DB 的数据

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

【讨论】:

  • 好主意!我正在使用表单工厂,它获取我正在构建的对象。表单不直接获取对象。您知道如何将链接对象传递到表单的较低级别吗?我在这里错误地使用表格吗?谢谢!
  • 假设你的代码是正确的,但是你有一个错误。您仅将国家名称传递给没有 id 的国家/地区名称,因此表单无法根据对象国家/地区属性选择选项。看看我在回答中的例子。
  • 啊,你是对的,我没有注意到变化。我刚试过,现在我得到 Silex 告诉我The option "choice" does not exists,并告诉我这应该是一个很长的列表之一,包含"choice_attr", "choice_label", "choice_list", "choice_loader", "choice_name", "choice_translation_domain", "choice_value", "choices", "choices_as_values"。如果我修改它以匹配 choices,我会收到另一个错误,告诉我 silex 无法加载类型 choices
  • 我有点迷茫,我开始觉得我的设置有误,因为我的行为与文档描述的行为不同:(symfony.com/doc/current/reference/forms/types/choice.html.
  • 选项 - 选择,类型 - 选择。试试$builder-&gt;add('country', Symfony\Component\Form\Extension\Core\Type\ChoiceType::class, array('choices' =&gt; $choices));
【解决方案2】:

将此行添加到您的选择选项中: 'choices_as_values' => true,

必须激活新的选择类型 API http://symfony.com/doc/current/reference/forms/types/choice.html#example-usage

【讨论】:

  • 你好,我之前试过了,确实可以(显示正常),但是在属性是对象的情况下,不会在表单中填写对象数据。我猜在没有给出闭包的情况下会发生一个比较对象,并且由于某种原因而失败。
【解决方案3】:

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

我的理解是:我们将对象作为choices,将其用作值,然后使用闭包来获取idslabels,而不是自己完成工作并给出'ready-to-在表单中使用'数据。

有没有更清洁的方法?

$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'
) );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-24
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多