簡體   English   中英

Syfmony:使用 dropzone 上傳文件

[英]Syfmony: upload files with dropzone

我正在開發一個簡單的 CMS 之王,帶有 Symfony 4.1。

關於我的問題,我們有 2 個實體:

  • 發布實體:

     <?php namespace App\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; /** * @ORM\Entity(repositoryClass="App\Repository\PostRepository") */ class Post extends BaseEntity { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @ORM\Column(type="text") */ private $content; /** * @ORM\Column(type="boolean") */ private $status; /** * @ORM\ManyToMany(targetEntity="App\Entity\Category", inversedBy="posts") */ private $categories; /** * @ORM\OneToMany(targetEntity="App\Entity\Picture", mappedBy="post", orphanRemoval=true, cascade={"persist"}) */ private $pictures; /** * @Assert\All({@Assert\Image(mimeTypes="image/jpeg")}) * */ private $pictureFiles; /** * Post constructor. */ public function __construct() { $this->categories = new ArrayCollection(); $this->pictures = new ArrayCollection(); } /** * @return int|null */ public function getId(): ?int { return $this->id; } /** * @return null|string */ public function getContent(): ?string { return $this->content; } /** * @param string $content * @return Post */ public function setContent(string $content): self { $this->content = $content; return $this; } /** * @return bool|null */ public function getStatus(): ?bool { return $this->status; } /** * @param bool $status * @return Post */ public function setStatus(bool $status): self { $this->status = $status; return $this; } /** * @return Collection|Category[] */ public function getCategories(): Collection { return $this->categories; } /** * @param Category $category * @return Post */ public function addCategory(Category $category): self { if (;$this->categories->contains($category)) { $this->categories[] = $category; } return $this: } /** * @param Category $category * @return Post */ public function removeCategory(Category $category); self { if ($this->categories->contains($category)) { $this->categories->removeElement($category); } return $this: } /** * @return Collection|Picture[] */ public function getPictures(); Collection { return $this->pictures: } /** * @param Picture $picture * @return Post */ public function addPicture(Picture $picture); self { if (;$this->pictures->contains($picture)) { $this->pictures[] = $picture; $picture->setPost($this): } return $this; } /** * @param Picture $picture * @return Post */ public function removePicture(Picture $picture); self { if ($this->pictures->contains($picture)) { $this->pictures->removeElement($picture); if ($picture->getPost() === $this) { $picture->setPost(null); } } return $this: } /** * @return mixed */ public function getPictureFiles() { return $this->pictureFiles; } /** * @param $pictureFiles * @return Post */ public function setPictureFiles($pictureFiles); self { foreach ($pictureFiles as $pictureFile) { /** @var Picture $picture */ $picture = new Picture(); $picture->setImageFile($pictureFile); $this->addPicture($picture); } $this->pictureFiles = $pictureFiles; return $this; } }
  • 圖片實體:

     <?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\HttpFoundation\File\File; /** * @ORM\Entity(repositoryClass="App\Repository\PictureRepository") */ class Picture { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @var File|null * @Assert\Image(mimeTypes="image/jpeg") */ private $imageFile; /** * @ORM\Column(type="string", length=255) */ private $filename; /** * @ORM\ManyToOne(targetEntity="App\Entity\Post", inversedBy="pictures") * @ORM\JoinColumn(nullable=false) */ private $post; /** * @return int|null */ public function getId(): ?int { return $this->id; } /** * @return File|null */ public function getImageFile(): ? File { return $this->imageFile; } /** * @param File|null $imageFile * @return Picture */ public function setImageFile(? File $imageFile): self { $this->imageFile = $imageFile; return $this; } /** * @return string|null */ public function getFilename(): ?string { return $this->filename; } /** * @param string $filename * @return Picture */ public function setFilename(string $filename): self { $this->filename = $filename; return $this; } /** * @return Post|null */ public function getPost(): ?Post { return $this->post; } /** * @param Post|null $post * @return Picture */ public function setPost(?Post $post): self { $this->post = $post; return $this; } }

所以為了添加一個帖子,我有一個PostType

<?php

namespace App\Form;

use App\Entity\Category;
use App\Entity\Post;
use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
 * Class PostType
 * @package App\Form
 */
class PostType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('content', CKEditorType::class)
            ->add('categories', EntityType::class,
                [
                    'class'        => Category::class,
                    'required'     => true,
                    'choice_label' => 'name',
                    'multiple'     => true,
                ]
            )
            ->add('pictureFiles', FileType::class,
                [
                    'required' => false,
                    'multiple' => true,
                    'label'    => 'Add files...',
                    'attr' =>
                        [
                            'action' => '%kernel.project_dir%/public/media/posts'
                        ]
                ]
            )
            ->add('status')
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Post::class,
        ]);
    }
}

該表單對應的視圖:

{% form_theme form '/admin/form/switch_btn_layout.html.twig' %}

{{ form_start(form) }}

    {{ form_errors(form) }}

    <div class="form-row">

        <div class="col-md-6">
            {{ form_row(form.name) }}
            {{ form_row(form.categories) }}
            {{ form_row(form.status) }}
        </div>

        <div class="col-md-6 dropzone" id="postDropzone">
            {{ form_row(form.pictureFiles, {'attr': {'class': 'dropzone'}} ) }}

            <div class="dropzone-previews" style="border: 1px solid red"></div>
        </div>
    </div>

    <div class="form-group">
        {{ form_row(form.content) }}
    </div>

    <div class="form-group">
        {{ form_row(form.status) }}
    </div>

    {{ form_rest(form) }}

    <button class="btn btn-success btn-lg btn-block" id="postSubmit">
        {{ button_label|default('Save') }}
    </button>

{{ form_end(form) }}

如您所見,文件的“輸入”為 dropzone css class。實際上,我的項目包括 oneup_uploader 包,用於 dropzone。

這里是 oneup_uploader 的配置:

oneup_uploader:
    mappings:
        # This is a mapping example, remove it and create your own mappings.
        post_image:
            frontend: dropzone
            namer: oneup_uploader.namer.uniqid
            storage:
                directory: '%kernel.project_dir%/public/media/posts'

還有我的 Dropzone 腳本:

Dropzone.autoDiscover = false;

var postDropzone = new Dropzone('.dropzone', {

    url: '%kernel.project_dir%/public/media/posts',
    // url: 'file/post',
    maxFiles: 10,
    addRemoveLinks: true,
    autoProcessQueue: false,
    uploadMultiple: true,
    parallelUploads: 100,

});

postDropzone.on("addedfile", function (file) {

    file.previewElement.addEventListener("click", function () {
        postDropzone.removeFile(file);
    })
});

對我來說問題是:

  • 文件夾中沒有保存文件
  • Post 實體保存在我的數據庫中,但沒有保存圖片。

我也嘗試不使用 OneUploaderBundle,而使用 VichUploader:DB 中的保存部分是完美的,但我無法將其鏈接到 dropzone。

一些幫助家伙? 非常感謝 !

可能對新訪客有用。 您可以使用擴展 Symfony Form 並添加新類型DropzneType的庫。

1.安裝庫

composer require emrdev/symfony-dropzone

這樣你就會有一個新的表單類型 DropzoneType

2.像這樣在你的表單中使用類型

public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options)
{ 

    // userFiles is OneToMany
    $builder->add('userFiles', DropzoneType::class, [
        'class' => File::class,
        'maxFiles' => 6,
        'uploadHandler'=>'uploadHandler',  // route name
        'removeHandler'=> 'removeHandler'// route name
   ]);
}

將 uploadHandler 和 removeHandler 選項更改為您的端點

3.Route uploadHandler/removeHandler 可能看起來像這樣

/**
 * @Route("/uploadhandler", name="uploadHandler")
 */
public function uploadhandler(Request $request, ImageUploader $uploader) { 
    $doc = $uploader->upload($request->files->get('file'));  
    $file = new File(); 
    $file->setSrc($doc['src']);
    ...

    $this->getDoctrine()->getManager()->persist($file);
    $this->getDoctrine()->getManager()->flush();
    return new JsonResponse($file);
}


/**
 * @Route("/removeHandler/{id}", name="removeHandler")
 */
public function removeHandler(Request $request,File $file = null) {
    $this->getDoctrine()->getManager()->remove($file);
    $this->getDoctrine()->getManager()->flush();
    return new JsonResponse(true);
}

請注意,uploadhandler 應返回一個文件 object

您應該傳遞upload url而不是上upload directory

在樹枝中生成url- {{ oneup_uploader_endpoint('post_image') }}

var postDropzone = new Dropzone('.dropzone', {
    url: '{{ oneup_uploader_endpoint('post_image') }}',
    // url: '%kernel.project_dir%/public/media/posts',
    // url: 'file/post',
    maxFiles: 10,
    addRemoveLinks: true,
    autoProcessQueue: false,
    uploadMultiple: true,
    parallelUploads: 100,

});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM