如何以 Symfony 形式创建和渲染对象数组

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

当我手工编写大部分代码时,我有一个由可变数量的 div 元素组成的表单,我在提交时通过 post 作为数组处理这些元素,但是我我这辈子都想不出如何在 Symfony 中做任何类似的事情,我开始感到非常沮丧。这是我对对象的模板 class 的原始实现(使用我自己的简单模板引擎):

<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()));

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

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

事实证明,我正在寻找涉及弃用代码的解决方案,即我的自定义类型的 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'

最后,你的对象类型

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