четверг, 18 августа 2011 г.

Вывод картинок в CGridView (к модели «товары»)

В прошлом посте Загрузка картинки к модели (товары) я добавил картинки товаров к своему каталогу. Сегодня я доработал начатое и сейчас расскажу, что получилось.

На практике получилось, что для товаров мало картинки одного размера: надо показать картинку среднего размера, а если пользователю захочется – показать её же в полном размере. Кроме того, когда товары отображаются в контроллере Assortiment.admin то есть списком с помощью CGridView, нужна колонка с совсем маленькими превьюшками:
CGridView с колонкой картинок


Выходит, что из одной загруженной картинки нужно сделать 3 таких же, но разного размера:
До 1000px по любой стороне – самый большой размер
До 200px по любой стороне – для показа в списке товаров
До 50px по любой стороне – для показа в окне manage assortiment
И нужно оставить на сервере исходную картинку без изменений (вдруг понадобится изменить дизайн сайта, тогда можно будет сделать превьюшки других размеров из оригинала)
Картинки хранятся в папках так:


Z:\home\catalog.loc\www\images
|
| assortiment_img (1000px)
|                   |
|                    thumb (200px)
|                    thumb_small (50px)
|
| category_img
|
|
| original_img
                   |
                   assortiment

Итак, когда загружается картинка для товара, она сохраняется в 4-х папках. Для этого я стал использовать расширение CImageHandler

Установил его (скопировал в папку Z:\home\catalog.loc\www\protected\components файл CImageHandler.php). Подключил, добавив в файл Z:\home\catalog.loc\www\protected\config\main.php струку «ih»
// application components
'components'=>array(
'ih'=>array('class'=>'CImageHandler'),
'user'=>array(
// enable cookie-based authentication
'allowAutoLogin'=>true,
),

Теперь можно использовать это расширение в контроллере assortiment в действиях create и update. В файле Z:\home\catalog.loc\www\protected\controllers\AssortimentController.php

/**
* Creates a new model.
* If creation is successful, the browser will be redirected to 
* the 'view' page.
*/
public function actionCreate()
{
			
$model=new Assortiment;

// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Assortiment']))
//Если пользователь отослал данные
{
$model->attributes=$_POST['Assortiment'];
//Заполнить модель данными присланными пользователем
$model->icon=CUploadedFile::getInstance($model,'icon');
//Атрибуту icon присвоить указатель на загружаемый файл
if($model->save())
//Если надо сохранить модель
{
if ($model->icon)
//Если пользователь загрузил файл
{
$file = './images/original_img/assortiment/'.$model->id.'_assortiment.jpg';
//Переменной $file присвоить путь, куда сохранится картинка без изменений
$model->icon->saveAs($file);
//Сохранить картинку без изменений по указанному пути
//Используем функции расширения CImageHandler ; 
$ih = new CImageHandler(); //Инициализация
Yii::app()->ih 
->load($file) //Загрузка оригинала картинки
->thumb('200', '200') //Создание превьюшки размером 200px
->save('./images/assortiment_img/thumb/'.
$model->id.'_assortiment.jpg','IMG_JPEG') 
//Сохранение превьюшки в папку
->reload() //Снова загрузка оригинала картинки
->thumb('50', '50') //Создание превьюшки размером 50px
->save('./images/assortiment_img/thumb_small/'
.$model->id.'_assortiment.jpg','IMG_JPEG')
//Сохранение превьюшки в папку
->reload()//Снова загрузка оригинала картинки
->thumb('1000', '1000') //Создание превьюшки размером 1000px
->save('./images/assortiment_img/'.$model->id.'_assortiment.jpg','IMG_JPEG')
//Сохранение превьюшки в папку
;  
}
$this->redirect(array('view','id'=>$model->id)); 
}
}
$this->render('create',array(
'model'=>$model,
)); 
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$model=$this->loadModel($id);
if(isset($_POST['Assortiment'])){
$model->attributes=$_POST['Assortiment'];
$model->icon=CUploadedFile::getInstance($model,'icon');
if($model->save()){
if($model->del_img)
//Если было отмечено удалить картинку
{
if(file_exists('./images/assortiment_img/thumb/'.$id.'_assortiment.jpg'))
{
//Удаляю все превьюхи этой картинки
@unlink('./images/assortiment_img/thumb/'.$id.'_assortiment.jpg');
@unlink('./images/assortiment_img/thumb_small/'.$id.'_assortiment.jpg');
@unlink('./images/assortiment_img/'.$id.'_assortiment.jpg');
@unlink('./images/original_img/assortiment/'.$id.'_assortiment.jpg');
}
}
if ($model->icon){
$file = './images/original_img/assortiment/'.$model->id.'_assortiment.jpg';
$model->icon->saveAs($file);
//Use CImageHandler extension; 
$ih = new CImageHandler();
Yii::app()->ih 
->load($file)
->thumb('200', '200')
->save('./images/assortiment_img/thumb/'.
$model->id.'_assortiment.jpg','IMG_JPEG')
->reload()
->thumb('50', '50')
->save('./images/assortiment_img/thumb_small/'.
$model->id.'_assortiment.jpg','IMG_JPEG')
->reload()
->thumb('1000', '1000')
->save('./images/assortiment_img/'.$model->id.
'_assortiment.jpg','IMG_JPEG')
;  
}
$this->redirect(array('view','id'=>$model->id)); 
}
}
$this->render('update',array(
'model'=>$model,
));
}

Конечно, действие удалить тоже удаляет все превьюхи удаляемого товара.

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

В файле Z:\home\catalog.loc\www\protected\views\assortiment\admin.php
в CGridView вставим колонку с картинками товаров (буду использовать картинки размером 50px).

<?php 
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'assortiment-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
array(
'name'=>'id',
'headerHtmlOptions'=>array('width'=>'50px')),
'name',
array(
'name'=>'icon',
'type'=>'image',
//тут самое интересное: если файла картинки нет, 
// то отображается файл no_photo.gif
// Значение value обрабатывается функцией eval() поэтому 
// тут такие странные ковычки.
'value'=> 'file_exists($_SERVER[DOCUMENT_ROOT].
Yii::app()->urlManager->baseUrl."/images/assortiment_img/thumb/".
$data->id."_assortiment.jpg") ? Yii::app()->urlManager->baseUrl.
"/images/assortiment_img/thumb_small/".$data->id.
"_assortiment.jpg" : Yii::app()->urlManager->baseUrl.
"/images/assortiment_img/thumb_small/no_photo.gif"',
'filter'=>'',
'headerHtmlOptions'=>array('width'=>'54px'),
),
array(
'name' => 'category_id',
'filter' => CHtml::listData(Category::model()->findAll(), 'id', 'name'),
'value' => '$data->category->name',
),
array(
'name' => 'shown',
'filter' => CHtml::listData(Assortiment::model()->findAll(), 
'shown', 'shown'),
'value' => '$data->shown',
),
array(
'class'=>'CButtonColumn',
),
),
));
?>}
Здесь колонка с картинкой имеет тип «image» В поле value должен приходить url картинки. При использовании типа image, нет возможности передавать значение alt, width или другие атрибуты тэгу «image». Но в данном случае это и не нужно.
Нужет полноценный тэг image, да еще обёрнутый ссылкой при выводе товаров пользователю, для этот изменю уже созданную в предыдущем посте http://psyhos.blogspot.com/2011/07/blog-post_21.html функцию assortiment_image() Находится она в файле контроллена assortiment Z:\home\catalog.loc\www\protected\controllers\AssortimentController.php
/**
* —return html image tag for assortiment. No photo if image not exests
* $id - id of the assortiment
* $name - name of assortiment use for alt
* $class - class of image
* $link - if present, generated <a> tag with href=$link
* $target - target attribute
*/
public function assortiment_image($id,$name,
$class='assortiment_img',$link=null,$target='_self')
{
if(file_exists($_SERVER['DOCUMENT_ROOT'].
Yii::app()->urlManager->baseUrl.
'/images/assortiment_img/thumb/'.
$id.'_assortiment.jpg'))
{          
if ($link)
return CHtml::link(CHtml::image(Yii::app()->urlManager->baseUrl.
'/images/assortiment_img/thumb/'.$id.'_assortiment.jpg',$name,
array(
'class'=>$class,
)), $link ,
array(
'target'=>$target,
)
);
else
return 
CHtml::image(Yii::app()->urlManager->baseUrl.
'/images/assortiment_img/thumb/'.$id.'_assortiment.jpg',$name,
array(
'class'=>$class,
));
		
}
else
return CHtml::image(Yii::app()->urlManager->baseUrl.
'/images/assortiment_img/no_photo.gif','No photo',
array(
'class'=>$class
)
Эта функция возвращает картинку, или картинку, обёрнутую ссылкой. Или картинку, no_photo.gif, если для выбранного товара нет изображения.
Используется эта функция в отображении Z:\home\catalog.loc\www\protected\views\assortiment\_view.php

<?php echo '<a name="'.$data->id.'"></a>'; ?>
<div class="assortimentview">
<b><?php echo CHtml::encode($data->getAttributeLabel
('name')); ?>:</b>
<?php echo CHtml::link(CHtml::encode($data->name), 
array('view', 'id'=>$data->id)); ?>
<br /> 
<b><?php echo CHtml::encode($data->getAttributeLabel('id')); ?>:</b>
<?php echo CHtml::encode($data->id); ?>
<br />
<b><?php echo CHtml::encode($data->getAttributeLabel('category_id')); ?>:</b>
<?php echo CHtml::encode($data->category->name); ?>
<br />
<?php echo $this->assortiment_image($data->id, 
$data->name, 'assortiment_img',array('view', 
'id'=>$data->id) ) ; ?>
<br />
<b><?php echo CHtml::encode($data->getAttributeLabel('description')); ?>:</b>
<?php echo $data->description; ?>
<br />
</div>
И в отображении конкретного товара Z:\home\catalog.loc\www\protected\views\assortiment\view.php

<?php 
$this->widget('zii.widgets.CDetailView', array(
'data'=>$model,
'attributes'=>array(
'name',
'id',
array(
'label'=>'Category',
'type'=>'raw',
'value'=>$model->category->name,
),
array(
'label'=>'Photo',
'type'=>'raw',
// If image exests- show image, else show no photo image
'value'=> $this->assortiment_image($model->id, 
$model->name,'',Yii::app()->urlManager->baseUrl.
'/images/assortiment_img/'.$model->id.'_assortiment.jpg','_blank'),	
),
array(
'label'=>'description',
'type'=>'html',
'value'=>$model->description,
),
),
));  
?>
Теперь загрузкой картинок к товарам я вполне доволен.
Продолжение следует.

1 комментарий:

  1. Такие портянки для CGridView записывать... Лучше уж универсальную ячейку сделать вроде http://www.elisdn.ru/blog/37/custom-cgridview-columns-in-yii

    ОтветитьУдалить