Завантаження зображень у YII

Завдання має такий вигляд: сайт - каталог товарів, написаний на фреймворку YII. В адмінці сайту потрібно зробити можливість завантаження зображення товару на сервер. Кожен товар може мати лише одне зображення. Я вже зробив можливість завантаження кількох зображень для товару, але в цій інструкції я не розширюватимуся на цю тему. Робимо зручний інтерфейс 🙂
Отже, зображення завантажується з комп'ютера користувача на сервер та перейменовується. Перейменування робиться на той випадок, якщо раптом у назві файлу зустрінуться українські символи, тоді Linux-сервер може повестися несподівано. Зображення зберігається в папку відповідно до дати додавання зображення (якщо image додано в 2013 році, то зображення зберігається в папку 2013, в 2014 - в папку 2014; а на початок імені файлу прописується місяць і день додавання зображення).
У таблицю БД MySQL додаємо поле image VARCHAR (100), у якому зберігатимемо ім'я файлу.
У модель для якої реалізовуємо функціонал додавання зображення, додаємо 2 нових public атрибути в самому верху, ось так:
Ці атрибути необхідно описати так само, як і ті, що були згенеровані через GII, тобто визначити правила валідації rules(), наприклад:
і описати назви полів у зрозумілому для людини вигляді attributeLabels(), наприклад:
Як я писав вище, це зображення для товару в каталозі товарів і якщо це зображення не завантажено, то на його місці ми виведемо спеціально підготовлене зображення (Немає зображення). Для цього в контролері, для якого ми реалізовуємо функціонал (protected/controllers/PostController.php), створюємо action post_image():
public function post_image($id, $create_year, $alias, $title, $image, $width='150',$class='post_img')< if(isset($image) && file_exists($_SERVER['DOCUMENT_ROOT']. Yii::app()->urlManager->baseUrl. '/images/'.$create_year.'/'.$ image)) return CHtml::image(Yii::app()->getBaseUrl(true).'/images/'.$create_year.'/'.$image, $title, array( 'width'=> $width, 'class'=>$class, )); else return CHtml::image(Yii::app()->getBaseUrl(true).'/images/pics/noimage.gif','Немає картинки', array( 'width'=>$width, 'class '=>$class ) ); >
Тут використовується конструкція виду Yii::app()->getBaseUrl(true) - вона робить url зображення абсолютним. Результатом тут буде HTML тег image з потрібною картинкою або з картинкою noimage.gif (наша заготівля «Немає зображення»).
Далі в нашій формі /protected/views/post/_form.php додаємо виведення картинки до статті, чекбокс на видалення цієї картинки та кнопку для вибору нової картинки:
Ще потрібно не забути додати спеціальний enctype для нашої форми, ось так:
'htmlOptions' => array('enctype' => 'multipart/form-data'),
У нашій новій формі рядка $form->checkBox($model,'del_img'); та CHtml::activeFileField($model, 'icon'); містять імена нових атрибутів, які ми додали на початку модельPost.
Тепер, щоб обробити дані форми повернемося знову до нашого контролера /protected/controllers/PostController.php і змінимо методactionCreate :
public function actionCreate()< $model=new Material; // Uncomment the following line if AJAX validation is needed // $this->performAjaxValidation($model); if(isset($_POST['Material']))< $model->attributes=$_POST['Material']; //Поля icon присвоїти значення поля форми icon $model->icon=CUploadedFile::getInstance($model,'icon'); if ($model->icon)< $sourcePath =pathinfo($model->icon->getName()); $fileName = date('m-d').'-'.$model->alias.'.'.$sourcePath['extension']; $model->image = $fileName; > if($model->save())< //Якщо поле завантаження файлу не було порожнім, if ($model->icon)< //зберегти файл на сервері в каталог images/2013 під ім'ям //month-day-alias.jpg $file = $_SERVER['DOCUMENT_ROOT']. Yii::app()->urlManager->baseUrl. '/images/'.date('Y').'/'.$fileName; $model->icon->saveAs($file); > $this->redirect(array('view','id'=>$model->id)); > > $this->render('create',array( 'model'=>$model, 'sectionnames'=>$sectionnames )); >
Рядок $model->image = $fileName обов'язково має викликатися до збереження форми, інакше до бази даних не запишеться ім'я нашого зображенняimage.
Аналогічно у методіactionUpdate :
public function actionUpdate()< $model=$this->loadModel(); if(isset($_POST['Material']))< $model->attributes=$_POST['Material']; $model->icon=CUploadedFile::getInstance($model,'icon'); if ($model->icon)< $sourcePath = pathinfo($model->icon->getName()); $fileName = substr($model->create_time, 5, 5).'-'.$model->alias.'.'.$sourcePath['extension']; $model->image = $fileName; > if($model->save())< //Якщо відзначено чекбокс «видалити файл» if($model->del_img)< if(file_exists($_SERVER['DOCUMENT_ROOT']. Yii::app()->urlManager->baseUrl. '/images/'.substr($model->create_time, 0, 4).'/' .$model->image))< //видаляємо файл unlink('./images/'.substr($model->create_time, 0, 4).'/'.$model->image); $model->image = ''; > > //Якщо поле завантаження файлу не було порожнім, if ($model->icon)< $file = './images/'.substr($model->create_time, 0, 4).'/'.$fileName;//зберегти файл на сервері під ім'ям //month-day-alias.jpg Якщо файл із таким ім'ям існує, він буде замінений. $model->icon->saveAs($file); > $this->redirect(array('view','id'=>$model->id)); > $this->render('update',array( 'model'=>$model, 'sectionnames'=>$sectionnames )); >
Тепер для відображення картинки у поданні робимо зміни у файлах /protected/views/post/view.php та _view.php:
post_image($data->id, substr($data->create_time, 0, 4), $data->alias, $data->title, $data->image, '150','small_img left');?>
Де за допомогою методуpost_image() виводимо картинки.
Стилі css додаємо, наприклад, у файлі /css/main.css:
Готово. В адмінці YII додавання зображення виглядатиме приблизно так: