在我们的Symfony2项目中,我们对具有嵌入表单的表单有一个非常复杂的结构....现在我们需要以特定的顺序带来表单的输出。
问题在于:我们使用form_widget(表单),现在我们正在寻找对象中的解决方案(例如通过注释)或formbuilder将特定字段移动到表单的末尾。在symfony 1.4中,它是widget-movefield()函数,我猜......
... THX
答案 0 :(得分:9)
您可以使用此捆绑包重新排序字段:https://github.com/egeloen/IvoryOrderedFormBundle
这允许你做这样的事情:
$builder
->add('g', 'text', array('position' => 'last'))
->add('a', 'text', array('position' => 'first'))
->add('c', 'text')
->add('f', 'text')
->add('e', 'text', array('position' => array('before' => 'f')))
->add('d', 'text', array('position' => array('after' => 'c')))
->add('b', 'text', array('position' => 'first'));
这将成为核心,但被拒绝并被捆绑出来。
答案 1 :(得分:5)
今天我遇到了与表单元素排序相同的问题。
使用将覆盖finishView方法的特征并重新排序FormView的children属性中的项目:
trait OrderedTrait
{
abstract function getFieldsOrder();
public function finishView(FormView $view, FormInterface $form, array $options)
{
/** @var FormView[] $fields */
$fields = [];
foreach ($this->getFieldsOrder() as $field) {
if ($view->offsetExists($field)) {
$fields[$field] = $view->offsetGet($field);
$view->offsetUnset($field);
}
}
$view->children = $fields + $view->children;
parent::finishView($view, $form, $options);
}
}
然后在类型实现getFieldsOrder方法:
use OrderedTrait;
function getFieldsOrder()
{
return [
'first',
'second',
'next',
'etc.',
];
}
答案 2 :(得分:3)
无需“重新排序”字段。您只需要为每个字段单独调用form_label
和/或form_widget
即可。假设您使用Twig
,例如,您可以:
<div>{{ form_label(form.firstName) }}</div>
<div>{{ form_widget(form.firstName) }}</div>
<div>{{ form_label(form.lastName) }}</div>
<div>{{ form_widget(form.lastName) }}</div>
答案 3 :(得分:3)
这是我提出的解决方案。
我创建了一个我的类型扩展的类。
namespace WF\CORE\CoreBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class WfBaseForm extends AbstractType
{
protected function useFields(FormBuilderInterface $builder, $fields)
{
foreach ($builder->all() as $field) {
if (!in_array($field->getName(), $fields))
$builder->remove($field->getName());
}
}
public function reorder(FormBuilderInterface $builder, $keys = array())
{
$fields = $builder->all();
$ordered_fields = array_merge(array_flip($keys), $fields);
$this->useFields($builder, array());
foreach($ordered_fields as $field)
$builder->add($field);
}
public function getName()
{
return 'base';
}
}
然后你可以在你继承的类中使用它。
class AddressType extends WfBaseForm
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// I add as many fields as I need
$builder->add( '…');
}
这个类扩展了上面的那个
class ModifyAddressType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder->add('title', 'text', array('constraints' => array(new NotBlank())));
$this->reorder($builder, array('title', 'firstname', 'lastname'));
}
}
答案 4 :(得分:0)
据我了解,您希望在最终模板中仅使用form_widget(form)。
假设我们有两个继承的模型(ModelA,ModelB)和它们的表单类型(ModelAType,ModelBType)
class ModelA {
private $A;
private $B;
// Getters and setters
}
class ModelB extends ModelA {
private $C;
// Getters and setters
}
/**
* @DI\Service(id = "form.type.modelA")
* @DI\Tag("form.type", attributes={ "alias":"model_a_type" })
*/
class FormAType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('A')
->add('B')
;
}
// getName and so on
}
/**
* @DI\Service(id = "form.type.modelA")
* @DI\Tag("form.type", attributes={ "alias":"model_b_type" })
*/
class FormAType extends AbstractType {
public function getParent() {
return "model_a_type";
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('C')
;
}
// getName and so on
}
如果渲染formB,您将获得A,B,C顺序,但是您需要A,C,B。 为此,请创建表单模板并添加对app的引用。配置文件:
#app/config/config.yml
twig:
....
form:
resources:
- YourAppBundle:Form:fields.html.twig
{# src/YourAppBundle/Resources/views/Form/fields.html.twig #}
{% block model_a_type_widget %}
{{ form_widget(form.A) }}
{{ form_widget(form.B) }}
{% endblock model_a_type_widget %}
{% block model_b_type_widget %}
{{ form_widget(form.A) }}
{{ form_widget(form.C) }}
{{ block('model_a_type_widget') }}
{% endblock model_b_type_widget %}
现在,当您渲染formB时,您将看到所需的顺序并保持代码结构化。 这是因为每个窗口小部件只渲染一次,所以如果在调用父块之前渲染它,则会更改它们的顺序。
答案 5 :(得分:0)
您可以在渲染模板之前在控制器中执行此操作:
$form = ...
$view = $form->createView();
// Perform standard array operations to reorder: `$view->children`
// Here's a very simple example:
$firstField = $view->children['firstField'];
unset($view->children['firstField']);
$view->children['firstField'] = $firstField;
return array('form' => $view);
uasort
也适用,但usort
会创建一个非关联数组,以后会破坏表单呈现。
答案 6 :(得分:0)
{{ form_start(form) }}
<div>{{ form_label(form.title) }}</div>
<div>{{ form_widget(form.title,{'id': 'blog_title'} )}}</div>
<div>{{ form_label(form.tag) }}</div>
<div>{{ form_widget(form.tag,{'id': 'blog_tag'} )}}</div>
<div>{{ form_label(form.category) }}</div>
<div>{{ form_widget(form.category,{'id': 'blog_category'} )}}</div>
<div>{{ form_label(form.image) }}</div>
<div>{{ form_widget(form.image,{'id': 'blog_image'} )}}</div>
<div>{{ form_label(form.body) }}</div>
<div>{{ form_widget(form.body,{'id': 'editor'} )}}</div>
<input type="submit" class="btn btn-success" value="Create" />
{{ form_end(form) }}
答案 7 :(得分:0)
我遇到了同样的问题,但是以不同的方式解决了它。这是我的解决方案,以作为其他正在寻找此问题的人的想法。
您可以将所有表单字段添加到事件侦听器中,因为在这里您具有所有对象数据来决定字段顺序。例如,您可以使用数据对象中的方法来确定字段顺序:
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Don't use $builder->add(), or just for those fields which are always
// at the beginning of the form.
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$entry = $event->getData();
$form = $event->getForm();
// Now add all the fields in the order you need them to be, e.g by reading
// the needed order from the data entry.
if ($entry->isFieldAFirst()) {
$form->add(fieldA);
$form->add(fieldB);
} else {
$form->add(fieldB);
$form->add(fieldA);
}
}
}