web-dev-qa-db-ja.com

Symfony2ファイルのアップロード手順

私はまだSymfony2を学んでいますが、ファイルのアップロード方法がわかりません。

心配しないで、私はすでに ドキュメント をチェックしています。それは本当に良いことですが、私の問題はどのチュートリアルでも説明されていません。

Symfony2でファイルをアップロードする方法についてのガイダンスを探していますが、すべての人が必要とするすべてのもの(拡張子の制約、IDやものに基づいたファイルの名前変更、dbにパスを保存するなど)

私は良いチュートリアルを見つけ、それらを混ぜようとしましたが、成功しませんでした。異なる問題が発生するたびに:フォーム上のすべての送信でファイルが再アップロードされる(ファイルフィールドが空であっても)、guessExtensionが使用できない、tmpパスが正しいパスの代わりにデータベースに保存される、ファイルが移動されない、不可能IDが自動インクリメントにあり、まだ生成されていないため、名前変更でIDを使用しました。

そこで、「標準」のエンティティを配置します。Photo.php

/**
 * Photo
 *
 * @ORM\Table(name="photo")
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class Photo
{
    // Annotation for the id and auto increment etc
    private $id;

    /**
     * @var string
     * @Assert\File( maxSize = "3072k", mimeTypesMessage = "Please upload a valid Image")
     * @ORM\Column(name="image", type="string", length=245, nullable=false)
     */
    private $image

    private $title

    private $description

    // all the function get, set for the 4 previous variables
}

およびコントローラー:

public function addPhotoAction()
{
    $add_photo = new Photo;
    $formBuilderPhoto = $this->createFormBuilder($add_photo);
    $formBuilderPhoto
        ->add('title','text',array('label'  => 'Title of the photo', 'required' => true))
        ->add('image','file', array('required' => true, 'data_class' => null))
        ->add('description','textarea',array('label' => 'Description of your photo', 'required' => false))
    ;

    $form_photo = $formBuilderPhoto->getForm();

    if ($request->getMethod() == 'POST') {
        $form_photo->bind($request);
        if ($form_photo->isValid()) {
            // ...
        }
    }
    return $this->render('MyBundle:frontend:photo.html.twig',
        array('form_photo' => $form_photo->createView())
    );
}

写真をアップロードして名前を変更できるようにするために追加する「重要な」機能は何ですか?

拡張機能をチェックして、アップロードが可能かどうかを確認するにはどうすればよいですか?

Symfony2でそのようなことを行う実際の方法は何ですか?私はあなたのためにそれらすべてを行う多くのバンドルがあることを知っていますが、私はそれをすることを学び、プロセスを理解したいと思います。

Symfony2でファイルアップロードフォームを実装し、関数の名前を変更する「クラシック」な方法は何ですか?

54
Tyrael

写真をアップロードして名前を変更できるようにするために追加する「重要な」機能は何ですか?

これを行う方法については 公式ドキュメント をご覧ください。単純なファイルのアップロードには、適切な実例があります。 ライフサイクルコールバック のdoctrineドキュメントも確認してください。

拡張機能をチェックして、アップロードが可能かどうかを確認するにはどうすればよいですか?

各ブラウザにはHTMLフォームの検証がいくつかあります。 input要素のHTML accept=""属性については、 この質問 を参照してください。また、Symfony2では、この注釈を使用して、アップロードされたファイルの MIMEタイプを指定 を実行できます。

/**
 * @Assert\File(
 *     maxSize = "1024k",
 *     mimeTypes = {"application/pdf", "application/x-pdf"},
 *     mimeTypesMessage = "Please upload a valid PDF"
 * )
 */

バンドルを使用したくなかったとしても、ファイルのアップロードを簡単にする KnpDoctrineBehavioursBundle を推奨する必要があります。


ステップバイステップ:

すでにドキュメントを読んでいるので、ステップバイステップのコード例を紹介します。

まず、エンティティが必要です。それをImageと呼びましょう:

/**
 * Class Image
 *
 * @ORM\Entity()
 * @ORM\HasLifecycleCallbacks
 */
class Image extends BaseEntity
{

@ORM\HasLifecycleCallbacks注釈に注意してください。これはvery重要であり、後で必要になります。 IDなどのすべての基本フィールドを作成します。また、ファイルパスを保存するフィールドが必要です。

    /**
     * Image path
     *
     * @var string
     *
     * @ORM\Column(type="text", length=255, nullable=false)
     */
    protected $path;

そして、画像自体用です。ここでは、画像の検証も定義します。私の例では、5M大きく、定義されたmimeTypesのいずれかでなければなりません。自明であるべきです。それ以外の場合は、 official docs help as always。

    /**
     * Image file
     *
     * @var File
     *
     * @Assert\File(
     *     maxSize = "5M",
     *     mimeTypes = {"image/jpeg", "image/gif", "image/png", "image/tiff"},
     *     maxSizeMessage = "The maxmimum allowed file size is 5MB.",
     *     mimeTypesMessage = "Only the filetypes image are allowed."
     * )
     */
    protected $file;

すべてのGetters & Settersを追加し、次のコマンドでデータベーススキーマを更新します。

php app/console doctrine:schema:update --force

次に、ライフサイクルが必要です。これらは、特定のイベントで呼び出されるEntityのメソッドです。たとえば、メソッドの前の@ORM\PreUpdate()アノテーションは、エンティティが更新される直前にこのメソッドが呼び出されていることを示しています。

/**
 * Called before saving the entity
 * 
 * @ORM\PrePersist()
 * @ORM\PreUpdate()
 */
public function preUpload()
{   
    if (null !== $this->file) {
        // do whatever you want to generate a unique name
        $filename = sha1(uniqid(mt_Rand(), true));
        $this->path = $filename.'.'.$this->file->guessExtension();
    }
}

エンティティが保存または更新される前に、このメソッドが呼び出されます。それを使用して、例えば一意のファイル名を生成します。

/**
 * Called before entity removal
 *
 * @ORM\PreRemove()
 */
public function removeUpload()
{
    if ($file = $this->getAbsolutePath()) {
        unlink($file); 
    }
}

エンティティが削除される前に呼び出されます。これにより、フォルダから画像を削除したり、必要に応じてメッセージを記録したりできます。

/**
 * Called after entity persistence
 *
 * @ORM\PostPersist()
 * @ORM\PostUpdate()
 */
public function upload()
{
    // The file property can be empty if the field is not required
    if (null === $this->file) {
        return;
    }

    // Use the original file name here but you should
    // sanitize it at least to avoid any security issues

    // move takes the target directory and then the
    // target filename to move to
    $this->file->move(
        $this->getUploadRootDir(),
        $this->path
    );

    // Set the path property to the filename where you've saved the file
    //$this->path = $this->file->getClientOriginalName();

    // Clean up the file property as you won't need it anymore
    $this->file = null;
}

これは、ファイルが実際に正しいディレクトリに移動される重要な部分です。いくつかの追加の方法を使用したことに注意してください。これらはすべて official docs から取得できます。

次に必要なのはフォームです。フォームクラス自体は非常に単純です。次のようにデフォルトのdata_classを設定してください:

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(
        array(
            'data_class' => 'FSchubert\SiyabongaBundle\Entity\Image',
       )
    );
}

ファイルアップロードフィールドは、buildForm()メソッドで非常に簡単に作成できます。

$builder->add('file', 'file');

Controllerのメソッドは、ここに貼り付けるだけでは少し長くなりますが、私見はあなたの質問に答える部分ではありません。目的に合った適切なController Actionを書くための無数の例があります。


あなたが心に留めておく必要があるより多くのもの:

  • ファイルをアップロードするフォルダーにapp書き込み権限を付与する必要があります。明らかなように思えますが、アプリケーションを実行するサーバーが複数ある場合は迷惑になります。
  • エンティティにもImage Constraintがあります。あなたはそれを見つけることができます こちら 。しかし、あなたはfileアップロードについて話していたので、代わりにFile Constraintを使用しました。
  • この投稿の冒頭で述べたように、これらすべてを処理する多くのバンドルがあります。あなたが簡単な生活をしたい場合はそれらをチェックしてください。

編集:

  • 古いものの開発がDoctrineExtensionsBundleバンドルを支持して停止したため、DoctrineBehavioursからDoctrineBehavioursに変更されました。
109
ferdynator

vlabs media bundle を使用することをお勧めします。

13
Sidali Hallak

VichUploaderBundleは、ファイルのアップロードにも簡単に使用できます。

https://github.com/dustin10/VichUploaderBundle

6
Tim Hovius