Symfony2 télécharger le fichier étape par étape

j'apprends encore le Symfony2 et je ne comprends pas comment télécharger un fichier.

Ne vous inquiétez pas, j'ai déjà vérifié la documentation . C'est vraiment bien, mais mon problème n'est expliqué dans aucun tutoriel.

je cherche des conseils sur la façon de télécharger un fichier avec Symfony2, mais avec tout ce dont tout le monde a besoin (comme la contrainte d'extension, renommer le fichier en fonction de l'id et des trucs, stocker le chemin dans la base de données, etc...)

j'ai trouvé des bons tutoriels, essayé de les mélanger mais sans succès. Chaque fois qu'un problème différent apparaît: le fichier recharge sur chaque submit sur le formulaire (même si le champ du fichier est vide), l'extension de la supposition impossible à utiliser, le chemin tmp stocké dans la base de données au lieu du bon chemin, le fichier non déplacé, impossible d'utiliser l'id dans le renommage parce que l'id est sur auto-increment et donc pas encore généré).

donc, je vais mettre une entité "standard", laissez dire: la Photo.151930920 php"

/**
 * Photo
 *
 * @ORMTable(name="photo")
 * @ORMEntity
 * @ORMHasLifecycleCallbacks
 */
class Photo
{
    // Annotation for the id and auto increment etc
    private $id;

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

    private $title

    private $description

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

et le contrôleur:

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

savez-vous maintenant quelle est la fonction "importante" à ajouter pour pouvoir télécharger la photo et la renommer ?

Comment vérifier l'extension pour voir si le téléchargement est possible?

Quelle est votre véritable façon de faire une telle chose avec Symfony2? Je sais qu'il y a beaucoup de paquet qui font toutes ces choses pour toi Mais je veux apprendre à le faire et de comprendre le processus.

Quelle est la manière "classique" d'implémenter un formulaire de téléchargement de fichier et de renommer la fonction avec Symfony2?

53
demandé sur halfer 2013-07-30 19:31:40

3 réponses

savez-vous maintenant quelle est la fonction "importante" à ajouter pour pouvoir télécharger la photo et la renommer?

voir la documentation officielle sur la façon de procéder. Il existe de bons exemples de travail pour un simple téléchargement de fichier. Vérifiez également la documentation de doctrine pour cycle de vie callbacks .

Comment vérifier l'extension pour voir si le le téléchargement est possible?

il y a une validation HTML dans chaque navigateur. Voir cette question pour l'attribut HTML accept="" dans input elements. Aussi dans Symfony2 vous pouvez spécifier le type MIME d'un fichier téléchargé en utilisant cette annotation:

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

même si vous ne vouliez pas utiliser de paquets, je vous recommande le KnpDoctrineBehavioursBundle qui rend le téléchargement de fichier beaucoup plus facile.


étape par étape:

parce que vous avez déjà lu la documentation, je vais vous donner un exemple de code étape par étape.

tout d'Abord, vous avez besoin d'une entité. Appelons-le Image :

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

Note l'annotation @ORM\HasLifecycleCallbacks . Il est très important et vous besoin plus tard. Nous créons tous les champs de base comme ID et ce qui ne l'est pas. Nous avons aussi besoin d'un champ pour stocker le chemin du fichier dans:

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

et un pour L'Image elle-même. Ici, nous définissons également la Validation des images. Dans mon exemple, il doit être 5M grand et de l'un des définis mimeTypes . Il devrait être auto-explicatif. Sinon le documents officiels aide comme toujours.

    /**
     * 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;

tout ajouter le Getters & Setters et mettre à jour votre schéma de base de données avec cette commande:

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

nous avons ensuite besoin du lifecycles . Ce sont des méthodes dans le Entity qui sont appelées sur certains événements. Par exemple, l'annotation @ORM\PreUpdate() avant une méthode indique que cette méthode est appelée juste avant que l'entité soit mise à jour.

/**
 * 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();
    }
}

avant que l'entité soit stockée ou mise à jour, cette méthode est appelée. Vous pouvez utiliser, par exemple, générer un nom de fichier unique.

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

appelé avant que l'entité soit retirée. Cela vous donne le temps de supprimer l'image de vos dossiers ou log un message si vous voulez.

/**
 * 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;
}

C'est la partie importante où votre fichier est déplacé vers le bon répertoire. Notez que j'ai utilisé quelques méthodes supplémentaires. Vous pouvez tous les obtenir à partir du documents officiels .

La prochaine chose dont vous avez besoin est un formulaire. La classe de forme elle-même est très simple. Assurez-vous juste que vous définissez la valeur par défaut data_class comme ceci:

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

un champ de téléchargement de fichier peut être créé très facilement dans la méthode buildForm() :

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

les méthodes pour votre Controller sont un peu longues pour simplement les coller ici et IMHO il ne fait pas partie de répondre à votre question. Il ya d'innombrables exemples pour la rédaction d'un bon Controller Action pour votre but.


plus de choses que vous devez garder à l'esprit:

  • vous devez donner vos permissions d'écriture app aux dossiers dans lesquels vous téléchargez les fichiers. Bien que cela semble évident, il peut être gênant si vous avez plusieurs serveurs vous exécutez l'application sur.
  • il y a aussi un Image Constraint pour votre entité. Vous pouvez le trouver ici . Mais puisque vous parliez d'un fichier upload j'ai utilisé le File Constraint à la place.
  • comme je l'ai mentionné dans le haut de ce post, Il ya beaucoup de paquets qui traitent toutes ces choses pour vous. Découvrez si vous voulez une vie facile.

Edit:

  • changé de DoctrineExtensionsBundle à DoctrineBehaviours depuis le développement sur l'ancien arrêté en faveur de la DoctrineBehaviours bundle.
109
répondu ferdynator 2017-05-23 11:33:17

je vous recommande d'utiliser vlabs médias bundle .

13
répondu Sidali Hallak 2015-05-24 16:16:33

le VichUploaderBundle est également facile à utiliser pour le téléchargement de fichiers:

https://github.com/dustin10/VichUploaderBundle

6
répondu Tim Hovius 2015-02-05 10:25:01