【问题标题】:Could not load type "file" in Symfony3无法在 Symfony3 中加载类型“文件”
【发布时间】:2017-01-26 17:33:38
【问题描述】:

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

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

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

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

这是我正在使用的代码:

ProductType 类:

<?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';
    }
}

services.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 %}

【问题讨论】:

  • @Veve 在 ProductImageType 类中?
  • @Veve 我试过了,现在我的表格是空的。它甚至不会渲染。我也尝试过 self::class 但仍然无法正常工作
  • 对于 Symfony 3,在 ProductImageType.php 中添加的字段,我猜它应该是 FileType 类型(您需要导入),而不是 file 类型。
  • @DanCostinel 我尝试了你的建议,我得到的结果与我在编辑后的段落中包含的结果相同。
  • VichUploaderBundle 捆绑包是您项目的要求吗?如果没有,我可以为您提供一个多上传功能代码的示例。

标签: twig symfony symfony-forms vichuploaderbundle


【解决方案1】:

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

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) 上传将使用here 之类的上传服务完成。所以在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 %}

【讨论】:

    【解决方案2】:

    您应该如何将其添加到表单中:

    use Symfony\Component\Form\Extension\Core\Type\FileType;
    
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
         $builder->add('image', FileType::class);
    }
    

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

    【讨论】:

    • 我试过了,但我在 Twig 模板中遇到了连线问题。您可以在编辑段落下查看树枝的结果
    • 那是什么模板?
    • 是bootstrap_3_layout.html.twig表单模板
    • 文件类型应该在一个 div 中呈现一个类型为 file 的输入,这就是全部。那段 html 来自哪里?
    • 我用树枝文件编辑了我的帖子。我不知道为什么我会得到这个 html 代码。是否与 Vich bundle 有某种联系
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多