如何创建和呈现Symfony形式的对象数组


How to create and render an array of objects in Symfony form

当我手工编写大部分代码时,我有一个由可变数量的div元素组成的表单,我在提交时通过post将其作为数组处理,但我无法为我的生活弄清楚如何在Symfony中做类似的事情,我开始感到非常沮丧。下面是一个对象的模板类的原始实现(使用我自己的简单模板引擎):

<div class="img_transfer">
    <img class="toggle" src="{{src}}">
    <input class="title" type="text" name="title[{{i}}]" placeholder="Title"><br>
    Upload to Sta.sh:
    <input type="radio" name="stash[{{i}}]" value="0" checked="checked"> No
    <input type="radio" name="stash[{{i}}]" value="1"> Yes<br>
    Showcase:
    <input type="radio" name="showcase[{{i}}]" value="0" checked="checked"> No
    <input type="radio" name="showcase[{{i}}]" value="1"> Yes<br>
    <input class="save" type="hidden" name="save[{{i}}]" value="0">
    <input type="hidden" name="old_path[{{i}}]" value="{{old_path}}">
</div>

{{i}}是循环迭代的占位符,这工作得很好,但这是我如何在Symfony中尝试做到的:

$img_tmp = glob('img_tmp/*.*');
$data = array();
foreach ($img_tmp as $src) {
    //$inter = end();
    $parts = explode('/', $src);
    $file = end($parts);
    //$name = explode($inter)[0];
    $name = explode('.', $file)[0];
    $data[$name] = new Art();
}
$builder = $this->createFormBuilder($data);
foreach ($data as $key => $value) {
    //$builder->add($key, (new ArtType())->setSrc($key));
    $builder->add($key, ArtType::class, array('img_src' => $key));
}
$form = $builder->getForm();
return $this->render('img_transfer.html.twig', array('form' => $form->createView()));

这主要是基于另一个关于如何拥有对象形式的建议,但它不会让我将自定义选项发送到要构建的表单,我认为这可能是我最后的障碍,让这个做我很容易实现的手工。我非常欢迎大家的建议,我更喜欢一种不那么黑客的方式来做这件事,我也很想知道我是否只是忽略了一种简单的方法,或者这是否像我认为的那样可怕地不直观。当我有时间的时候,我会编辑和重组这个问题,使它成为一个更好的问题。

Edit:格式和以下附加信息:应用程序的这个特殊部分应该取任意名称和扩展名转储在"web/img_tmp"目录中的图像,并将它们移动到"web/img"目录中,同时使用PHP的uniqid()重命名它们并将它们输入数据库;我想要为每个"/img_tmp/"生成一组字段。"允许我在将它们持久化到DB之前为每个属性设置属性。我找到的所有关于如何同时提交多个对象的资源要么不完整,要么过于复杂。

结果是,我正在寻找涉及弃用代码的解决方案,即我自定义类型的setDefaultOptions(OptionsResolverInterface $resolver)方法,它显然在Symfony 3.0中被删除了。作为参考,以下是如何在表单中提交多个对象并向传递自定义选项的完整代码:

控制器代码
public function someAction()
{
    $vals = array('customVal1', 'customVal2', 'customVal3');
    foreach ($vals as $v) {
        $data[$v] = new YourObject();
    }
    $builder = $this->createFormBuilder($data);
    //I put this here so I don't have to scroll all the way to the bottom to submit;
    //this will render it at the top by default (at least on mine)
    $builder->add('submit', SubmitType::class, array('label' => 'Submit'));
    foreach ($vals as $v) {
        $builder->add($v, YourObjectType::class, array(
            'custom_val' => $v
        ));
    }
    $form = $builder->getForm();
    return $this->render('the_page.html.twig', array('form' => $form->createView()));
}

定制表单模板

{% block yourobject_widget %}
    <div>
        <img src="{{ custom_val }}"> //This is set by the call to setAttribute() in YourObjectType
        {% for child in form %}
            {{ form_row(child) }}
        {% endfor %}
    </div>
{% endblock %}

app/config/config.yml

twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"
    form_themes:
        - 'form/fields.html.twig'

最后,YourObjectType

namespace AppBundle'Form'Type;
use Symfony'Component'Form'AbstractType;
use Symfony'Component'Form'Extension'Core'Type'TextType;
use Symfony'Component'Form'Extension'Core'Type'ChoiceType;
use Symfony'Component'Form'Extension'Core'Type'CollectionType;
use Symfony'Component'Form'Extension'Core'Type'HiddenType;
use Symfony'Component'Form'Extension'Core'Type'SubmitType;
use Symfony'Component'Form'FormView;
use Symfony'Component'Form'FormInterface;
use Symfony'Component'Form'FormBuilderInterface;
use Symfony'Component'OptionsResolver'OptionsResolver;
class YourObjectType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver)
    {
        parent::configureOptions($resolver);
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle'Entity'YourObject',
            'custom_val' => ''  //This is important. You have to set defaults for
                                //options for Symfony to allow you to pass them
        ));
    }
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['custom_val'] = $options['custom_val'];
    }
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('some_text_field', TextType::class)
            ->add('some_choice_field', ChoiceType::class, array(
                'choices' => array('Yes' => true, 'No' => false),
                'expanded' => true
            ))
            ->add('some_hidden_field', HiddenType::class, array('mapped' => false))
            ->setAttribute('custom_val', $options['custom_val']);
    }
}