В качестве примера для загрузки файлов реализуем задачу по добавлению постов на пользовательской стороне сайта. Создадим объект Посты со следующими полями

Spisok-svoistv.png

А также через gii сгенерируем Ygin модуль и Ygin модель, и подключим модуль в protected/config/project.php

  return array(
  'name'=>'Engine macro',
  'language' => 'ru',
  'theme' => 'business',

  // используемые в проекте модули
  'modules' => array(
    'post',
  ),
...

);

Должна получиться следующая структура каталогов:

Struktura-katalogov.png

Саму загрузку файлов будем делать с помощью классов, которые находятся в ygin/components/fileUpload/. Загрузка будет происходить ajax'ом с помощью виджета FileUploadWidget, который основывается на расширении XUpload и jquery-плагине JQuery file upload.

Понадобится три представления:

  • form - сама форма загрузки
  • upload - файл во время загрузки
  • download - файл после загрузки

Можно использовать те, которые лежат в ygin/components/fileUpload/fileUploadWidget/views, но тогда придется писать много js-кода, для обработки событий. Поэтому можно воспользоваться представлениями из ygin/modules/backend/widgets/upload/listFileUpload/views и ygin/modules/backend/widgets/upload/singleFileUpload/views для множественной и одиночной загрузки файлов соответственно.

Скопируем их в protected/modules/post/widgets/upload/list и protected/modules/post/widgets/upload/single. Должна получиться следущая структура каталогов:

Struktura-kataloga-vidghetov.png

Уберем из файлов protected/modules/post/widgets/upload/list/form.php и protected/modules/post/widgets/upload/single/form.php, код связанный с админкой. А именно $.daSticker({text: msg, type: "error"}); (вместо этого можно написать alert(msg);) и строчки, где встречается BackendUploadedFiles, $this->owner->form->error($this->mainModel, $this->objectParameter->getFieldName());

Подключаем к модели Post поведение FileUploadableBehavior

public function behaviors() {
  return array(
    'FileUploadableBehavior' => array(
      'class' => 'fileUpload.FileUploadableBehavior',
      'resetScope' => true,
    ),
  );
}

Подключаем экшен FileUploadAction к контроллеру DefaultController модуля Post

public function actions() {
  return array(
    //для загрузки одиночного файла
    'fileUpload' => array(
      'class' => 'fileUpload.FileUploadAction',
      'multiple' => false,
      'createThumb' => true,
      'thumbConfig' => array(
        'width' => 70,
        'height' => 50,
        'crop' => 'top',
        'postfix' => '_thumb',
      ),
    ),
    //для загрузки списка файлов
    'listFileUpload' => array(
      'class' => 'fileUpload.FileUploadAction',
      'multiple' => true,
      'createThumb' => true,
      'rewriteIfFileExist' => false,
      'thumbConfig' => array(
        'width' => 70,
        'height' => 50,
        'crop' => 'top',
        'postfix' => '_thumb',
      ),
    ),
  );
}

Теперь создадим экшен Defaultcontroller::actionSave и соответствующее представление save.php

public function actionSave($id = null) {
  $model = null;
  if ($id) {
    $model = $this->loadModelOr404('Post', $id);
  } else {
    $model = new Post();
  }
  if ($attributes = (array)HU::post('Post', array())) {
    $model->attributes = $attributes;
    if ($model->save()) {
      $this->redirect(array('save', 'id' => $model->id_post));
    }
  }
  $this->render('save', array(
    'model' => $model,
  ));
}
<?php
/**
 * @var DefaultController $this
 * @var Post $model
 * @var CActiveForm $form
 */
?>
<?php
Yii::import('xupload.models.XUploadForm');

$form = $this->beginWidget('CActiveForm', array(
  'id' => 'post-form',
  'method' => 'post',
  'htmlOptions' => array(
    'class' => 'form-horizontal',
  ),
));
?>
<div class="control-group">
  <?php echo $form->label($model, 'title', array('class' => 'control-label')); ?>
  <div class="controls">
    <?php echo $form->textField($model, 'title', array('class' => 'span5')); ?>
    <?php echo $form->error($model, 'title'); ?>
  </div>
</div>

<div class="control-group">
  <?php echo $form->label($model, 'id_image', array('class' => 'control-label')); ?>
  <div class="controls" id="single-file-upload">
  <?php
  $this->widget('fileUpload.fileUploadWidget.FileUploadWidget', array(
    'id' => 'single-file-upload',
    'multiple' => false,
    'url' =>  array('post/default/fileUpload'),
    'formClass' => 'fileUpload.FileUploadForm',
    'mainModel' => $model,
    'objectParameter' => $model->getObjectInstance()->getParameterObjectByIdParameter(Post::PARAMETER_IMAGE),
    'formView' => 'post.widgets.upload.single.form',
    'uploadView' => 'post.widgets.upload.single.upload',
    'downloadView' => 'post.widgets.upload.single.download',
    'thumbConfig' => array(
      'width' => 70,
      'height' => 50,
      'crop' => 'top',
      'postfix' => '_thumb',
    ),
    'options' => array(
      'prependFiles' => true,
    ),
  ));
  ?>
  </div>
</div>

<div class="control-group">
  <?php echo $form->label($model, 'short', array('class' => 'control-label')); ?>
  <div class="controls">
    <?php echo $form->textArea($model, 'short', array('class' => 'span5', 'rows' => 8)); ?>
    <?php echo $form->error($model, 'short'); ?>
  </div>
</div>

<div class="control-group">
  <label class ="control-label">Загрузка файлов</label>
  <div class="controls" id="list-file-upload">
    <?php
    $this->widget('fileUpload.fileUploadWidget.FileUploadWidget', array(
      'id' => 'list-file-upload',
      'multiple' => true,
      'url' =>  array('post/default/listFileUpload'),
      'formClass' => 'fileUpload.FileUploadForm',
      'mainModel' => $model,
      'objectParameter' => $model->getObjectInstance()->getParameterObjectByIdParameter(Post::PARAMETER_FILE_LIST),
      'formView' => 'post.widgets.upload.list.form',
      'uploadView' => 'post.widgets.upload.list.upload',
      'downloadView' => 'post.widgets.upload.list.download',
      'thumbConfig' => array(
        'width' => 70,
        'height' => 50,
        'crop' => 'top',
        'postfix' => '_thumb',
      ),
    ));
    ?>
  </div>
</div>
<div class="control-group">
  <?php echo $form->label($model, 'content', array('class' => 'control-label')); ?>
  <div class="controls">
    <?php echo $form->textArea($model, 'content', array('class' => 'span5', 'rows' => 8)); ?>
    <?php echo $form->error($model, 'content'); ?>
  </div>
</div>

<div class="control-group">
  <div class="controls">
    <button type="submit" class="btn"><?php echo $model->isNewRecord ? 'Создать' : 'Обновить'; ?></button>
  </div>
</div>

<?php
$this->endWidget();
?>

Теперь перейдем по адресу http://ваш_сайт/post/default/save, должно получиться нечто следующее:

Kartinka-s-formoi.png

Пост после сохранения

Post-posle-sohraneniya.png

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

  public function actionGetFiles($id = null, $tmpId = null) {
    if (empty($id) && empty($tmpId)) {
      throw new CHttpException(400, 'Неверный запрос.');
    }
    $attributes = array(
      'id_parent_file' => null,
      'id_object' => Post::ID_OBJECT,
      'id_parameter' => Post::PARAMETER_FILE_LIST,
    );
    if (!empty($id)) {
      $attributes['id_instance'] = $id;
    } elseif (!empty($tmpId)) {
      $attributes['id_tmp'] = $tmpId;
    }
    $files = File::model()->findAllByAttributes($attributes);
     //дальше обрабатываем в необходимый формат
  }

где tmpId - это $model->tmpId (временный идентификаатор, пока модель новая и еще не сохранена в базу, берется из FileUploadableBehavior)

Скачать исходники

21 августа 2013

Автор: Тимофеев Руслан

Комментарии (5)

Добавить комментарий
  • Денис
    27.05.2016, 12:17:02

    Ошибка

    Здравствуйте.

    Сделал все по примеру. Получилась ошибка
    Fatal error: Undefined class constant 'PARAMETER_IMAGE'
  • Денис
    27.05.2016, 12:49:25

    Ошибка

    Порывшись в исходниках нашел что там должно быть поле файла в базе. допустим у меня это поле image.

    Но возникли еще трудности.
    При аяксе в инспектор браузера возвращается такой ответ:
    Необходимо заполнить поле «Object Id». Необходимо заполнить поле «Parameter Id».

    Не могу понять где их взять и куда их вставить
  • Денис
    27.05.2016, 14:11:56

    Ошибка

    В общем продолжаю вести беседу сам с собой.

    Нашел ошибку в настройках виджета загрузки необходимо поменять строку

    'objectParameter' => $model->getObjectInstance()->getParameterObjectByIdParameter(Post::PARAMETER_IMAGE)

    на строку
    'objectParameter' => $model->getObjectInstance()->getParameterObjectByField('image')

    так как нам необходимо передать объект с параметрами поля картинки для занесения в таблицу файлов. в примере не раскрыто по какому идентификатору можно получить объект, а с помощью метода getParameterObjectByField объект можно получить по названию поля картинки/файла, в моем случае это image
  • Денис
    18.01.2017, 15:22:30

    Несколько записей с загрузкой картинок

    Здравствуйте.

    Появился вопрос. Вывожу несколько записей из базы в которых есть поля для картинок и у каждой есть кнопка загрузки файла и загрузка перестает работать. У первой записи картинка грузится в temp и отображается превью, но в базу не загружается, а у остальных записей при нажатии на кнопку загрузить вообще ничего не происходит.

    Если вывести одну запись, то работает все нормально

    Подскажите, как решить проблему
    • Денис
      18.01.2017, 16:16:03

      Проблему решил подставив id записи