1

我正在构建具有多个图像上传的表单,但我找不到标题中提到的问题的解决方案。为了帮助我,我包括了 VichUploaderBundle

现在我被这个错误困住了,我找不到代码中错误的原因和位置:

Could not load type "file"
500 Internal Server Error - InvalidArgumentException

有人知道问题出在哪里吗?

这是我正在使用的代码:

产品类型类:

<?php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Vich\UploaderBundle\Form\Type\VichFileType;
use AppBundle\Entity\Product;



class ProductType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
          ->add('title', TextType::class)
          ->add('content', TextType::class)
          ->add('price', TextType::class)
          ->add('categories')
          ->add('productCondition')
          ->add("images", CollectionType::class, array(
               'entry_type' => ProductImageType::class,
               'allow_add' => true,
               'allow_delete' => true
           )
        );
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Product::class
        ));
    }




}

ProductImageType 类

<?php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;


class ProductImageType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
      $builder
         ->add('image', 'file')
     ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => ProductImage::class
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'product_image';
    }
}

服务.yml

# Learn more about services, parameters and containers at
# http://symfony.com/doc/current/service_container.html
parameters:
#    parameter_name: value

services:
#    service_name:
#        class: AppBundle\Directory\ClassName
#        arguments: ["@another_service_name", "plain_value", "%parameter_name%"]
    app.form.type.file:
        class: AppBundle\Form\Type\ProductImageType
        tags:
            - { name: form.type }

编辑:

我从 ProductImageType 中删除了“文件”,错误消失了,但 Twig 无法呈现表单。我也尝试使用 self::class 而不是 'file' ,但这也没有帮助。

//ProductImageType class
public function buildForm(FormBuilderInterface $builder, array $options)
    {
      $builder
         ->add('image')
     ;
    }

Twig 模板中的结果:

<div class="form-group">
   <label class="control-label required">Images</label>
   <div id="product_images" data-prototype="<div class=&quot;form-group&quot;><label class=&quot;control-label required&quot;>__name__label__</label><div id=&quot;product_images___name__&quot;><div class=&quot;form-group&quot;><label class=&quot;control-label required&quot; for=&quot;product_images___name___image&quot;>Image</label><input type=&quot;text&quot; id=&quot;product_images___name___image&quot; name=&quot;product[images][__name__][image]&quot; required=&quot;required&quot; class=&quot;form-control&quot; /></div></div></div>"></div>
</div>

编辑 2:添加了 Twig 表单

{% extends 'AppBundle::layout.html.twig' %}

{% block stylesheets %}
    {{ parent() }}

    <link href="{{ asset('/assets/vendor/components-font-awesome/css/font-awesome.min.css') }}" rel="stylesheet">
    <link href="{{ asset('assets/css/form-elements.css') }}" rel="stylesheet">
    <link href="{{ asset('assets/css/forms.css') }}" rel="stylesheet">
{% endblock %}

{% block content %}
<div class="top-content">

                    <div class="inner-bg">
                            <div class="container">


                <div class="row">
            <div class="col-md-6 col-md-offset-3">

                <div class="form-box">
                    <div class="form-top">
                        <div class="form-top-left">
                            <h3>Create new product condition!</h3>
                        </div>
                        <div class="form-top-right">
                            <i class="fa fa-plus"></i>
                        </div>
                        </div>
                        <div class="form-bottom">

            {{ form_start(form, { 'attr': {'class': 'product-form'} })  }}
            {% spaceless %}
    {% if not form.vars.valid %}
            <div class="alert alert-error">
                {{ form_errors(form) }}

        {% for children in form.children %}
            {% if not children.vars.valid %}
                {{ form_errors(children) }}

                {# or with field label
                <ul>
                    {% for error in children.vars.errors %}
                        <li><b>{{ children.vars.label }}</b>: {{ error.message }}</li>
                    {% endfor %}
                </ul>
                #}
            {% endif %}
        {% endfor %}
            </div>
    {% endif %}
        {% endspaceless %}
                {{ form_row(form.title) }}
                {{ form_row(form.content) }}
                {{ form_row(form.price) }}
                {{ form_row(form.categories) }}
                {{ form_row(form.productCondition) }}
                {{ form_row(form.images) }}
                        <button type="submit" class="btn">Submit!</button>
                    {{ form_end(form) }}
        </div>
        </div>

    </div>
    </div>
{% endblock content %}
4

2 回答 2

3

正如我所承诺的,我正在为您提供一个小示例,说明如何创建多重上传表单以及如何从表单中获取数据并将其从临时目录移动到您想要的目录,并将路径保存在数据库中.

1)创建实体类。

<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
 * @ORM\Table(name="galleries")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\GalleryRepository")
 */
class Gallery
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name="path", type="string", length=255)
     */
    private $path;

    // getter for $id, setter & getter for $path here
}

2) 创建表格。

use Symfony\Component\Form\Extension\Core\Type\FileType;
//...
$builder->add('path', FileType::class, [
    'data_class' => null,
    'multiple' => true,
    'label' => false
]);

3) 上传将使用此处所述的上传服务完成。所以设置你希望你的文件进入的目录config.yml(不要设置这个参数,parameters.yml因为如果你推送项目,这个文件会被 git 忽略)。

#app/config/config.yml
parameters:
    upload_dir: '%kernel.root_dir%/../web/upload'

4) 声明服务。

#app/config/services.yml
services:
    app.img_upload:
        class: AppBundle\Services\FileUpload
        arguments: ['%upload_dir%']

5) 创建服务。

#AppBundle\Services\FileUpload.php

namespace AppBundle\Services;

use Symfony\Component\HttpFoundation\File\UploadedFile;

class FileUpload
{
    private $targetDir;

    public function __construct($targetDir)
    {
        $this->targetDir = $targetDir;
    }

    public function upload(UploadedFile $file)
    {
        $file_name = $file->getClientOriginalName();

        empty($file_name) ? $file_name = md5(uniqid()).'.'.$file->guessExtension() : $file_name = $file->getClientOriginalName();

        $file->move($this->targetDir, $file_name);

        return $file_name;
    }
}

6)在控制器中创建整个逻辑。

#AppBundle/Controller/DefaultController.php

namespace AppBundle\Controller;
//...
use AppBundle\Entity\Gallery;
use AppBundle\Form\GalleryType;
//class...

/**
 * @Route("/", name="homepage")
 */
public function indexAction(Request $request)
{
    $gallery = new Gallery();
    $form = $this->createForm(GalleryType::class, $gallery, [
        'action'=>$this->generateUrl('homepage'),
        'method'=>'POST'
    ]);

    $form->handleRequest($request);

    if($form->isSubmitted() && $form->isValid()) {
        $paths = $form->get('path')->getData();

        foreach ($paths as $path){
            $img = $this->get('app.img_upload')->upload($path);

            $em = $this->getDoctrine()->getConnection();
            $stmt = $em->prepare('INSERT INTO galleries SET path=?');
            $stmt->execute([$img]);

            // THIS IS THE PROBLEM I ENCOUNTER! I COULDN'T USE NORMAL DOCTRINE WAY TO SAVE EACH IMAGE PATH INTO THE DB. KNOW THE FIX? POST IT HERE PLEASE!
            // $em = $this->getDoctrine()->getManager();
            // $em->persist($gallery);
            // $em->flush();

            //LE: I've found the "bug": you need to instantiate, for each $path, a new $gallery object, then set the data for it, + persist & flush.
        }

        $this->addFlash('success', 'The image(s) were successfully uploaded');

        return $this->redirectToRoute('homepage');
    }

    return $this->render('default/index.html.twig', ['form'=>$form->createView()]);
}

7) 最后,显示表格。

# app/Resource/views/default/index.html.twig
{% extends 'base.html.twig' %}

{% block body %}
{{ form_start(form) }}
    {{ form_row(form.path) }}
    <button type="submit" title="Upload an image">
        Upload
    </button>
{{ form_end(form) }}
{% endblock %}
于 2017-01-27T18:11:24.480 回答
1

这是您应该如何将其添加到表单中的方法:

use Symfony\Component\Form\Extension\Core\Type\FileType;

public function buildForm(FormBuilderInterface $builder, array $options)
{
     $builder->add('image', FileType::class);
}

在 Symfony 3 中,表单类型总是通过其完全限定的类名传递

于 2017-01-27T08:21:53.373 回答