2015-03-27 6 views
5

Это ситуация: Я новичок на Yii2 и хотел использовать некоторый файл загрузчик виджет в ActiveForm .. до сих пор я нашел этот EXCELENT одно: \kartik\widget\FileInputyii2 - Картик ввода файл - обновление

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

Проблема в том, что если я нажму кнопку «Обновить» формы без изменения изображения, то yii говорит, что изображение «не может быть пустым», потому что я установил правило «обязательно» в моей модели.

ответ

5

После ужасного дня и более продуктивной ночи, я обнаружил решение, которое работало для меня ..

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

Итак, моим обходным путем было создано еще одно «виртуальное» поле для управления загрузкой файлов под названием «upload_image». Для достижения этой цели я просто добавил общественную собственность с этим именем в моей модели класса: public $upload_image;

Я также добавить проверку folowing методу правил по классу модели:

public function rules() 
{ 
    return [ 
     [['upload_image'], 'file', 'extensions' => 'png, jpg', 'skipOnEmpty' => true], 
     [['image'], 'required'], 
    ]; 
} 

Здесь «upload_image» мой виртуальный колонка. Я добавил «файл» с помощью «skipOnEmpty» = true, а «образ» - это поле в моей базе данных, которое должно быть необходимо в моем случае.

Тогда, на мой взгляд, я настроил «upload_image» виджетом, как следует:

echo FileInput::widget([ 
     'model' => $model, 
     'attribute' => 'upload_image', 
     'pluginOptions' => [ 
      'initialPreview'=>[ 
       Html::img("/uploads/" . $model->image) 
      ], 
      'overwriteInitial'=>true 
     ] 
    ]); 

В опции «initialPreview» Я Asign мое имя изображения, хранящуюся в свойстве «$ модели-> изображение» возвращенную из базы данных.

Наконец, мой контроллер выглядит следующим образом:

public function actionUpdate($id) 
{ 
    $model = $this->findModel($id); 
    $model->load(Yii::$app->request->post()); 

    if(Yii::$app->request->isPost){ 
     //Try to get file info 
     $upload_image = \yii\web\UploadedFile::getInstance($model, 'upload_image'); 

     //If received, then I get the file name and asign it to $model->image in order to store it in db 
     if(!empty($upload_image)){ 
      $image_name = $upload_image->name; 
      $model->image = $image_name; 
     } 

     //I proceed to validate model. Notice that will validate that 'image' is required and also 'image_upload' as file, but this last is optional 
     if ($model->validate() && $model->save()) { 

      //If all went OK, then I proceed to save the image in filesystem 
      if(!empty($upload_image)){ 
       $upload_image->saveAs('uploads/' . $image_name); 
      } 

      return $this->redirect(['view', 'id' => $model->id]); 
     } 
    } 
    return $this->render('update', [ 
     'model' => $model, 
    ]); 
} 
2

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

Я просмотрел kartik file-input widget (хорошая находка, кстати), и я наткнулся на способ сделать это

// Display an initial preview of files with caption 
// (useful in UPDATE scenarios). Set overwrite `initialPreview` 
// to `false` to append uploaded images to the initial preview. 
echo FileInput::widget([ 
    'name' => 'attachment_49[]', 
    'options' => [ 
     'multiple' => true 
    ], 
    'pluginOptions' => [ 
     'initialPreview' => [ 
      Html::img("/images/moon.jpg", ['class'=>'file-preview-image', 'alt'=>'The Moon', 'title'=>'The Moon']), 
      Html::img("/images/earth.jpg", ['class'=>'file-preview-image', 'alt'=>'The Earth', 'title'=>'The Earth']), 
     ], 
     'initialCaption'=>"The Moon and the Earth", 
     'overwriteInitial'=>false 
    ] 
]); 

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

3

Я столкнулся с другим решением, создав сценарии. В вашем случае я бы изменить правила, как это:

public funtion rules() { 
    [['image'], 'file'], 
    [['image'], 'required', 'on'=> 'create'] 
} 

Так поле FileUpload будет требоваться только в создании действия. В действии обновления у меня есть этот код:

public function actionUpdate($id) 
    { 
     $model = $this->findModel($id); 

     if ($model->load(Yii::$app->request->post())) { 

      $newCover = UploadedFile::getInstance($model, 'image'); 

      if (!empty($newCover)) { 
      $newCoverName = Yii::$app->security->generateRandomString(); 
      unlink($model->cover); 
      $model->cover = 'uploads/covers/' . $newCoverName . '.' . $newCover->extension; 
      $newCover->saveAs('uploads/covers/' . $newCoverName . '.' . $newCover->extension); 
      } 

      if ($model->validate() && $model->save()) { 
      return $this->redirect(['view', 'id' => $model->post_id]); 
      } else { 
      // error saving model 
      } 

     } else { 
      return $this->render('update', [ 
      'model' => $model, 
      ]); 
     } 

    } 

В сценарии обновления изображения подано не требуется, но проверки кода, если ничего не было загружено и не изменяет предыдущее значение.

Моя форма файл:

<?= $form->field($model, 'image')->widget(FileInput::classname(), [ 
    'options' => ['accept'=>'image/*'], 
    'pluginOptions'=>[ 
     'allowedFileExtensions'=>['jpg', 'gif', 'png', 'bmp'], 
     'showUpload' => true, 
     'initialPreview' => [ 
      $model->cover ? Html::img($model->cover) : null, // checks the models to display the preview 
     ], 
     'overwriteInitial' => false, 
    ], 
]); ?> 

Я думаю, что это немного проще, чем виртуальное поле. Надеюсь, поможет!

-2

От Krajee:

http://webtips.krajee.com/advanced-upload-using-yii2-fileinput-widget

Создание, удаление, обновление: очень легкий, не смотреть дальше.

(1) Я также установил правило «обязательно» в своей модели.

(2) Для того, чтобы работать на WampServer:

Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/web/uploads/'; 

Yii::$app->params['uploadUrl'] = Yii::$app->urlManager->baseUrl . '/uploads/';