Загрузка файла Symfony2 шаг за шагом

Я все еще изучаю Symfony2 и не понимаю, как загрузить файл.

Не волнуйтесь, я уже проверил документация. Это действительно хорошо, но моя проблема не объясняется ни в одном учебнике.

Я ищу руководство по загрузке файла с Symfony2, но со всем, что нужно всем (например, ограничение расширения, переименование файла на основе идентификатора и прочее, сохранение пути в БД и т. д...)

Я нашел хорошие учебники, пытался смешать их, но без успеха. Каждый раз, когда появляется другая проблема: повторная загрузка файла на каждую отправку в форме (даже если поле файла пустое), невозможно использовать guessExtension, путь tmp хранится в базе данных вместо правильного пути, Файл не перемещается, невозможно использовать идентификатор в переименовании, потому что идентификатор находится на автоинкременте и поэтому еще не сгенерирован).

Итак, я поставлю "стандартную" сущность, скажем: фото.в 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
}

и контроллер:

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?

3 ответов


теперь вы знаете, что такое "важная" функция для добавления, чтобы иметь возможность загружать фотографию и переименовывать ее?

посмотреть официальная документация о том, как это сделать. Есть хорошие рабочие примеры для простой загрузки файлов. Также проверьте документацию доктрины для обратный вызов жизненного цикла.

как вы проверяете расширение, чтобы узнать, возможна ли загрузка?

там некоторая проверка HTML-формы в каждом браузере. См.этот вопрос для HTML на input элементы. Также в 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 Примечание. Это очень важно и вам это нужно позже. Мы создаем все основные поля, такие как ID, а что нет. Также нам нужно поле для хранения пути к файлу в:

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

и один для самого образа. Здесь мы также определяем проверку изображений. В моем примере это должно быть 5M большой и одного из определенных mimeTypes. Это должно быть понятно. В противном случае официальные документы помочь, как всегда.

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

это важная часть, где ваш файл фактически перемещается в нужную директорию. Обратите внимание, что я использовал некоторые дополнительные методы. Вы все можете получить их из официальные документы.

следующее, что вам нужно, это форма. Сам класс формы очень прост. Просто убедитесь, что вы установили значение по умолчанию 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 для Вашего лица как что ж. Вы можете найти его здесь. Но так как вы говорили о загрузить я использовал .
  • как я уже упоминал в верхней части этого поста, есть много пакетов, которые обрабатывают все эти вещи для вас. Проверить их, если вы хотите легкой жизни.

Edit:

  • изменилась с DoctrineExtensionsBundle to DoctrineBehaviours поскольку развитие на старом остановилось в пользу DoctrineBehaviours пакета.

Я рекомендую вам использовать vlabs media bundle.


VichUploaderBundle также прост в использовании для загрузки файлов:

https://github.com/dustin10/VichUploaderBundle