duanlie7962 2015-02-27 09:38
浏览 64

Symfony 2搜索表单呈现不需要的搜索字段。 我可以禁用此行为吗?

Edit: This question refers to Symfony 2.7, for Symfony 2.8+ see Ogi's answer below.

The require section in my composer.json looks like this:

"require": {
    "php": ">=5.3.3",
    "symfony/symfony": "2.3.*",
    "doctrine/orm": "~2.2,>=2.2.3,<2.5",
    "doctrine/dbal": "<2.5",
    "doctrine/doctrine-bundle": "~1.2",
    "twig/extensions": "1.0.*",
    "symfony/assetic-bundle": "~2.3",
    "symfony/swiftmailer-bundle": "~2.3",
    "symfony/monolog-bundle": "~2.4",
    "sensio/distribution-bundle": "~2.3",
    "sensio/framework-extra-bundle": "~3.0,>=3.0.2",
    "sensio/generator-bundle": "~2.3",
    "incenteev/composer-parameter-handler": "~2.0",

    "braincrafted/bootstrap-bundle": "~2.0",
    "twbs/bootstrap": "3.2.*",
    "jquery/jquery": "1.11.*",
    "stof/doctrine-extensions-bundle": "~1.1@dev"
},

NOTE: The last four packages are added on top of Symfony2 standard edition.

Following the Symfony 2 Forms docs chapter, I'm trying to create a search form. So, I have created an entity class:

<?php
namespace AppBundle\Entity;

use Symfony\Component\Validator\Constraints as Assert;

class SearchQuery
{
/**
 * @Assert\NotBlank()
     * @Assert\Type(type="string", message="form.search.query.validation.type")
     * @Assert\Length(
     *      min = 3,
     *      max = 50,
     *      minMessage = "form.search.query.validation.min",
     *      maxMessage = "form.search.query.validation.max"
     * )
     */
    protected $query;

    public function __construct($query = '')
    {
        $this->setQuery($query);
    }

    public function getQuery()
    {
        return $this->query;
    }

    public function setQuery($query)
    {
        $this->query = $query;
    }
}

And a form type class:

<?php
namespace AppBundle\Form\Type;

use 
    Symfony\Component\OptionsResolver\OptionsResolverInterface,    
    Symfony\Component\Form\AbstractType,
    Symfony\Component\Form\FormBuilderInterface
;

class SearchType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('query', 'text', array(
                'label' => '',
                'attr' => array(

                ),
            ))
            ->add('save', 'submit', array(
                'label' => '',
            ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\SearchQuery',
            'attr' => array(
                'id' => 'search-form'
            )
        ));
    }

    public function getName()
    {
        return 'search';
    }
}

The rendered output:

<form name="search" method="post" action="/app_dev.php/search" id="search-form" role="form">

    <input type="search" id="search" name="search" required="required" class="form-control" value="">

    <div class="form-group">
        <label class="control-label required" for="search_query">Query</label>
        <input type="text" id="search_query" name="search[query]" required="required" class="form-control">
    </div>
    <div class="form-group">
        <button type="submit" id="search_save" name="search[save]" class="btn btn-primary">Save</button>
    </div>
    <input type="hidden" id="search__token" name="search[_token]" class="form-control" value="5f0e9c4a9d4e251fc62e25686cf810eaa0ff4331">
</form>

The problem is that something between Symfony 2 Forms, BraincraftedBootstrapBundle and Twig is trying to play smart and adds this unwanted field:

<input type="search" id="search" name="search" required="required" class="form-control" value="">

I've noticed that this happens only if the SearchType::getName() method returns 'search'. If I change this to something like:

class SearchType extends AbstractType
{

    [...]

    public function getName()
    {
        return 'search_foo';
    }

    [...]

}    

everything works as expected, the rendered output is:

<form name="search_foo" method="post" action="/app_dev.php/cautare" id="search-form" role="form">
    <div id="search_foo">
        <div class="form-group">
            <label class="control-label required" for="search_foo_query">Query</label>
            <input type="text" id="search_foo_query" name="search_foo[query]" required="required" class="form-control">
        </div>
        <div class="form-group">
            <button type="submit" id="search_foo_save" name="search_foo[save]" class="btn btn-primary">Save</button>
        </div>
        <input type="hidden" id="search_foo__token" name="search_foo[_token]" class="form-control" value="68ee88cb3adef211b993806029ba3fa989322c80">
    </div>
</form>

Of course, I can change the name to something else and move on, but it's like a nail being hammered in my head to do so without understanding what's really happening behind the curtains.

I've even tried to set the field type to search instead of text hoping that if it sees that there is a search field would leave me alone and won't try to guess what my intentions are, but no, it still prints the unwanted field.

  • 写回答

1条回答 默认 最新

  • dpwh11290 2015-12-14 22:52
    关注

    You might have seen or not the issue created by @aistis in its comment.

    I see from your composer.json file that you seems to use symfony 2.3. So this error is strange because it should only happens since 2.8...

    Anyway, the solution is pretty straightforward, but not obvious: you should implement the getBlockPrefix method in your form type:

    <?php
    namespace AppBundle\Form\Type;
    
    // [...]
    
    class SearchType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            // [...]
        }
    
        public function getBlockPrefix()
        {
            return 'app_search'
        }
    }
    

    To keep it short: This is explained by the latest changes in the Symfony Form component, getting rid of the form aliases and getName() method.
    A form type is now identified by its fully-qualified-class-name.
    When a form is rendered, it'll compute the form name from the FQCN, by only keeping the lowercased & snake cased class name minus Type. Then it'll use this computed name to render the form theme block matching this name.

    As a drawback, however, naming a form type identical to an existing one will lead to unexpected behaviors like you experienced.
    Good news are that you can override the way the form theme name is computed by overriding the getBlockPrefix method in your form type. Thus, the solution above.

    P.S: If you're really using Symfony 2.8+, you should get rid of the setDefaultOptions method deprecated in 2.7, in favor of the new configureOptions one: https://github.com/symfony/symfony/blob/2.8/UPGRADE-2.7.md#form

    Also see the list of deprecations and upgrade paths for the Symfony Form component in 2.8 here: https://github.com/symfony/symfony/blob/2.8/UPGRADE-2.8.md#form

    评论

报告相同问题?

悬赏问题

  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图