Добавим в форму редактирования поле для загрузки картинок к статье. Сохраним загруженные изображения в папку на сервере и запишем путь в БД. Покажем на примере ресайза с сохранением пропорций картинки обращаться к другим иногда необходимым методам Imagine.

Этот способ основан на подобном решении для Yii 1.1.x - см. http://loco.ru/materials/127-yii-image-upload
1. В форму редактирования статьи добавим/заменим поле для загрузки файла
<?php if(isset($model->image) && file_exists(Yii::getAlias('@webroot', $model->image))) { echo Html::img($model->image, ['class'=>'img-responsive']); echo $form->field($model,'del_img')->checkBox(['class'=>'span-1']); } ?> <?= $form->field($model, 'file')->fileInput() ?>
Не забудем добавить enctype в опциях вызова формы, раз собираемся загружать файлы через форму
$form = ActiveForm::begin(['id' => 'blog-form', 'options' => ['enctype' => 'multipart/form-data']]);
2. В модели добавим
use yii\web\UploadedFile;
ниже добавим переменные
class Blog extends \yii\db\ActiveRecord { public $file; public $del_img;
в таблице БД поле для картинки у меня называется - image.
Далее в правилах rules() добавим
[['file'], 'file', 'extensions' => 'png, jpg'], [['del_img'], 'boolean'],
3. В базовом контроллере добавим функцию проверки на существование папки и её создание в случае отсутствия (это нужно, чтобы складировать уменьшенные превью изображений отдельно в подпапки thumbs)
public function createDirectory($path) { //$filename = "/folder/{$dirname}/"; if (file_exists($path)) { //echo "The directory {$path} exists"; } else { mkdir($path, 0775, true); //echo "The directory {$path} was successfully created."; } }
4. Теперь в наш контроллер
use app\models\UploadForm; use yii\web\UploadedFile; use yii\imagine\Image;
Image - здесь это для создания превью главной фотки (а также для ресайза оригинала до разумных для веба размеров). Это расширение yii2-imagine от yiisoft - установите его через composer.
Привожу свой экшн actionCreate()
public function actionCreate() { $model = new Blog(); if ($model->load(Yii::$app->request->post())) { $file = UploadedFile::getInstance($model, 'file'); if ($file && $file->tempName) { $model->file = $file; if ($model->validate(['file'])) { switch ($model->material_type) { case 0: $material_type = ''; break; case 1: $material_type = 'news/'; break; case 2: $material_type = 'persons/'; break; case 3: $material_type = 'movies/'; break; case 4: $material_type = 'interview/'; break; } $dir = Yii::getAlias('images/blog/'.$material_type); $fileName = $model->file->baseName . '.' . $model->file->extension; $model->file->saveAs($dir . $fileName); $model->file = $fileName; // без этого ошибка $model->image = '/'.$dir . $fileName; // Для ресайза фотки до 800x800px по большей стороне надо обращаться к функции Box() или widen, так как в обертках доступны только 5 простых функций: crop, frame, getImagine, setImagine, text, thumbnail, watermark $photo = Image::getImagine()->open($dir . $fileName); $photo->thumbnail(new Box(800, 800))->save($dir . $fileName, ['quality' => 90]); //$imagineObj = new Imagine(); //$imageObj = $imagineObj->open(\Yii::$app->basePath . $dir . $fileName); //$imageObj->resize($imageObj->getSize()->widen(400))->save(\Yii::$app->basePath . $dir . $fileName); Yii::$app->controller->createDirectory(Yii::getAlias('images/blog/'.$material_type.'/thumbs')); Image::thumbnail($dir . $fileName, 150, 70) ->save(Yii::getAlias($dir .'thumbs/'. $fileName), ['quality' => 80]); } } if ($model->save()) { return $this->redirect(['view', 'id' => $model->id]); } } else { return $this->render('create', [ 'model' => $model, ]); } }
тут $material_type - для сохранения фоток по подпапкам.
экшн actionUpdate() почти такой же, как actionCreate():
public function actionUpdate($id) { $model = $this->findModel($id); $current_image = $model->image; $model->sections = explode(',', $model->sections); if ($model->load(Yii::$app->request->post())) { $file = UploadedFile::getInstance($model, 'file'); if ($file && $file->tempName) { $model->file = $file; if ($model->validate(['file'])) { //Если отмечен чекбокс «удалить файл» if($model->del_img) { if(file_exists(Yii::getAlias('@webroot'.$current_image))) { //удаляем файл unlink(Yii::getAlias('@webroot'.$current_image)); $model->image = ''; } } switch ($model->material_type) { case 0: $material_type = ''; break; case 1: $material_type = 'news/'; break; case 2: $material_type = 'persons/'; break; case 3: $material_type = 'movies/'; break; case 4: $material_type = 'interview/'; break; } $dir = Yii::getAlias('images/blog/'.$material_type); $fileName = $model->file->baseName . '.' . $model->file->extension; $model->file->saveAs($dir . $fileName); $model->file = $fileName; // без этого ошибка $model->image = '/'.$dir . $fileName; // Для ресайза фотки до 800x800px по большей стороне надо обращаться к функции Box() или widen, так как в обертках доступны только 5 простых функций: crop, frame, getImagine, setImagine, text, thumbnail, watermark $photo = Image::getImagine()->open($dir . $fileName); $photo->thumbnail(new Box(800, 800))->save($dir . $fileName, ['quality' => 90]); //$imagineObj = new Imagine(); //$imageObj = $imagineObj->open(\Yii::$app->basePath . $dir . $fileName); //$imageObj->resize($imageObj->getSize()->widen(400))->save(\Yii::$app->basePath . $dir . $fileName); Yii::$app->controller->createDirectory(Yii::getAlias('images/blog/'.$material_type.'/thumbs')); Image::thumbnail($dir . $fileName, 150, 70) ->save(Yii::getAlias($dir .'thumbs/'. $fileName), ['quality' => 80]); } } if ($model->save()) { return $this->redirect(['view', 'id' => $model->id]); } } else { return $this->render('update', [ 'model' => $model, ]); } }
Ресайз изображений при загрузке.
Чтобы изображения не сохранялись на сервере в большом размере и весе, мы сделали их ресайз. Для этого в контроллере вы видите обращение к getImagine. Метод Box(800, 800) позволит сохранять пропорции картинки. Чтобы к нему обратиться мы и подключили дополнительно Gd, Box, BoxInterface. Второй способ - закомментированные строки - использовать widen(800), чтобы при ресайзе задать ограничение по большей стороне картинки.
use Imagine\Gd; use Imagine\Image\Box; use Imagine\Image\BoxInterface; ... ... // Для ресайза фотки до 800x800px по большей стороне надо обращаться к функции Box() или widen, так как в обертках доступны только 5 простых функций: crop, frame, getImagine, setImagine, text, thumbnail, watermark $photo = Image::getImagine()->open($dir . $fileName); $photo->thumbnail(new Box(800, 800))->save($dir . $fileName, ['quality' => 90]); //$imagineObj = new Imagine(); //$imageObj = $imagineObj->open(\Yii::$app->basePath . $dir . $fileName); //$imageObj->resize($imageObj->getSize()->widen(800))->save(\Yii::$app->basePath . $dir . $fileName);
2 октября 2015, Программирование, веб-кодинг, Расширения, виджеты / Метки: image upload

