RSS-подписка

RSS-лента

Новые статьи

Последние комментарии


Получать обновления на эл. почту

Ваш e-mail:

Рассылка новостей от Loco

Yii: Фотогалерея через поведение (доработка расширения imagesgallerymanager)

Yii: Фотогалерея через поведение (доработка расширения imagesgallerymanager) Делаю фотогалерею на Yii через поведение.

Для Yii2 это расширение описано тут - http://yiico.ru/blog/501-fotogaleryeya-dlya-yii2-rasshirenie-zxbodya-yii2-gallery-manager

Давненько копилось желание организовать фотогалерею на Yii. Сделал это опираясь на существующие на сегодняшний день расширения для Yii. Так как сам проект начал делать на Yii-app от Chris83, то ожидал как-то использовать yii-imagemanager, который входит в yii-app. Но стало понятно, что оно обрабатывает отдельно фотографии и не предлагает галереи фото.

Попалось расширение от Bogdan Savluk - imagesgallerymanager (на bitbucket). Оно позволяет через поведение подвесить менеджер загрузки (+редактирования информации к фотке) прямо к нужной модели. Несколько доработал это расширение, чтобы фотографии сохранялись на сервере по папкам (название папок формируется по псевдониму записи (можно заменить и на значение любого поля в записи модели) - например, у меня это alias у группы). Папки создаются сами в директории gallery, и при удалении последней картинки из папки, сама папка тоже удаляется.

images gallery manager менеджер фотогалереи для Yii, фотогалерея на Yii

 

фотогалерея для Yii

Устанавливаем сначала imagesgallerymanager (для него понадобится расширение yii-image).

config/main.php

'import' => array(
...
'ext.galleryManager.*',
        'ext.galleryManager.models.*', 
'ext.image.*',
...
// application components
    'components' => array(
        ...
'image' => array(
            'class' => 'application.extensions.image.CImageComponent',
            // GD or ImageMagick
            'driver' => 'GD',
            // ImageMagick setup path
            'params' => array('directory' => '/opt/local/bin'),
        ),  
config/web.php
// controllers mappings
    'controllerMap' => array(
        ...
        'image' => array('class' => 'vendor.crisu83.yii-imagemanager.controllers.ImageController'),
'gallery' => array('class' => 'ext.galleryManager.GalleryController'),
    ),
В папку app/extentions помещаю galleryManager и image (расширения от z_bodya).
 
В нужной моделе Group, к которой хочу подвесить галерею, завожу поле gallery_id и добавляю его в безопасные атрибуты (safe).
 
В models/ar/Group.php добавляю behavior
...
public function behaviors()
{
   return array(
       'galleryBehavior' => array(
           'class' => 'GalleryBehavior',
           'idAttribute' => 'gallery_id',
           'versions' => array(
               'small' => array(
                   'centeredpreview' => array(200, 200), //array(98, 98),
               ),
               'medium' => array(
                   'resize' => array(800, null),
               )
           ),
           'name' => true,
           'description' => true,
       )

   );

}
...
В представлении для редактирования группы app/views/group/_form.php добавляю виджет поведения
...            
<h2>Product galley</h2>
<?php
if ($model->galleryBehavior->getGallery() === null) {
   echo '<p>Before add photos to product gallery, you need to save product</p>';
} else {
   $this->widget('GalleryManager', array(
       'gallery' => $model->galleryBehavior->getGallery(), 
'controllerRoute' => '/gallery'
   ));
}
?>
...
Теперь менеджер галереи работает, но сохраняет все фотки в одну папку gallery.
 

Дорабатываю расширение imagesgallerymanager для сохранения фоток по папкам.

В модель Group.php добавляю передачу пути 'imagePath' сохранения фоток для поведения
...
public function behaviors()
{
   return array(
       'galleryBehavior' => array(
           'class' => 'GalleryBehavior',
'imagePath' => 'gallery/'.$this->alias,
           'idAttribute' => 'gallery_id',
           'versions' => array(
               'small' => array(
                   'centeredpreview' => array(200, 200),
               ),
               'medium' => array(
                   'resize' => array(800, null),
               )
           ),
           'name' => true,
           'description' => true,
       )
   );
} 
...
 
Теперь добавляю переменную эту в GalleryBehavior
 class GalleryBehavior extends CActiveRecordBehavior
 {
   /** @var string Model attribute name to store created gallery id */
   public $imagePath = ''; // вот она
   /** @var string Model attribute name to store created gallery id */
     public $idAttribute;
...
В GalleryController добавляю $galleryDir = 'gallery'
class GalleryController extends Controller
 {
 public $galleryDir = 'gallery';          

 public function filters()
     {
...
В actionDelete этого контроллера тоже этот путь надо перезаписать
public function actionDelete($galleryphotospath = null) // !! id передаётся через POST, а galleryphotospath — через GET
     {
         $id = $_POST['id'];
        //$galleryphotospath = $_POST['galleryphotospath'];
         /** @var $photos GalleryPhoto[] */
         $photos = GalleryPhoto::model()->findAllByPk($id);
//        foreach ($photos as $photo) {
//           if ($photo !== null) $photo->delete();
        foreach ($photos as $photo) {                     
            if ($photo !== null) {
      $photo->galleryDir = $photo->galleryDir."/".$galleryphotospath;
 $photo->delete();
 }
...
 
и в actionAjaxUpdate разумеется тоже (по GET буду передавать $galleryphotopath)
    public function actionAjaxUpload($gallery_id = null, $galleryphotospath = null)
     {
        $model = new GalleryPhoto(); 
 $model->galleryDir = $model->galleryDir."/".$galleryphotospath; 
         $model->gallery_id = $gallery_id;
         $imageFile = CUploadedFile::getInstanceByName('image');
         $model->file_name = $imageFile->getName();
         $model->save();
   

 $this->createDirectory($_SERVER['DOCUMENT_ROOT'].Yii::app()->urlManager->baseUrl. '/' .$model->galleryDir); 
         $model->setImage($imageFile->getTempName());
         header("Content-Type: application/json");
         echo CJSON::encode(
...
 
В GalleryManager.php в начало добавляю
...
public $gallerypath;
...
и ниже в run() несколько изменений
...
$photos = array();
        foreach ($this->gallery->galleryPhotos as $photo) { 
$photo->galleryDir = $photo->galleryDir."/".$this->gallerypath; 
            $photos[] = array(
                'id' => $photo->id,
                'rank' => $photo->rank,
                'name' => (string)$photo->name,
                'description' => (string)$photo->description,
                'preview' => $photo->getPreview(),
            );
        }

        $opts = array(
            'hasName' => $this->gallery->name ? true : false,
            'hasDesc' => $this->gallery->description ? true : false,
            'uploadUrl' => Yii::app()->createUrl($this->controllerRoute . '/ajaxUpload', array('gallery_id' => $this->gallery->id, 'galleryphotospath' => $this->gallerypath)),
            'deleteUrl' => Yii::app()->createUrl($this->controllerRoute . '/delete', array('galleryphotospath' => $this->gallerypath)),
            'updateUrl' => Yii::app()->createUrl($this->controllerRoute . '/changeData'),
            'arrangeUrl' => Yii::app()->createUrl($this->controllerRoute . '/order'),
            'nameLabel' => Yii::t('galleryManager.main', 'Name'),
            'descriptionLabel' => Yii::t('galleryManager.main', 'Description'),
            'photos' => $photos,
        ); 
...
в app/extensions/galleryManager/models/GalleryPhoto.php добавил удаление папки, если она опустевает
...
public function delete()
    {
        $this->removeFile(Yii::getPathOfAlias('webroot') . '/' . $this->galleryDir . '/' . $this->getFileName('') . '.' . $this->galleryExt);
        $this->removeFile(Yii::getPathOfAlias('webroot') . '/' . $this->galleryDir . '/_' . $this->getFileName('') . '.' . $this->galleryExt);
        $this->removeImages();                                                                                                  
@unlink(Yii::getPathOfAlias('webroot') . '/' .$this->galleryDir. '/.DS_Store');
//array_map("unlink", glob(Yii::getPathOfAlias('webroot') . '/' .$this->galleryDir. '/.DS_Store')); // MAC OS X создаёт файл .DS_Store, который мешает удалять папку rmdir, так как она должна быть пустой, чтобы сработала функция rmdir

// если в папке gallery/alias_группы нет изображений, то удалять нахрен эту папку
if($this->regExpFile("/jpg$/", Yii::getPathOfAlias('webroot') . '/' .$this->galleryDir, $regType='P', $case='') === false) {
rmdir(Yii::getPathOfAlias('webroot') . '/' .$this->galleryDir);
}
        return parent::delete();
    }  
...
Про удаление файла из папки с помощью @unlink - PHP: Как удалить файлы по маске?
и ниже regExpFile() нашёл в комментариях на сайте php
function regExpFile($regExp, $dir, $regType='P', $case='') {
# Two parameters accepted by $regType are E for ereg* functions
# and P for preg* functions
$func = ( $regType == 'P' ) ? 'preg_match' : 'ereg' . $case;

# Note, technically anything other than P will use ereg* functions;
# however, you can specify whether to use ereg or eregi by
# declaring $case as "i" to use eregi rather than ereg

$open = opendir($dir);
while( ($file = readdir($open)) !== false ) {
if ( $func($regExp, $file) ) {
return true;
}
} // End while
return false;  
} // End function
Ну и виджет поведения в представлении формы редактирования
//            <h2>Product galley</h2>
            <h2>Фотографии коллектива</h2>
  <?php
  if ($model->galleryBehavior->getGallery() === null) {
      echo '<p>Before add photos to product gallery, you need to save product</p>';
  } else {
      $this->widget('GalleryManager', array(
          'gallery' => $model->galleryBehavior->getGallery(),  
 'controllerRoute' => '/gallery',
 'gallerypath' => $model->alias,
      ));
  }
  ?>
Создать таблицы в базе данных:
-- -----------------------------------------------------
-- Table `tbl_gallery`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `tbl_gallery` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `versions_data` TEXT NOT NULL ,
  `name` TINYINT(1) NOT NULL DEFAULT 1 ,
  `description` TINYINT(1) NOT NULL DEFAULT 1 ,
  PRIMARY KEY (`id`) )
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `tbl_gallery_photo`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `tbl_gallery_photo` (
  `id` INT NOT NULL AUTO_INCREMENT ,
  `gallery_id` INT NOT NULL ,
  `rank` INT NOT NULL DEFAULT 0 ,
  `name` VARCHAR(512) NOT NULL DEFAULT '',
  `description` TEXT NULL,
  `file_name` VARCHAR(128) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`) ,
  INDEX `fk_gallery_photo_gallery1` (`gallery_id` ASC) ,
  CONSTRAINT `fk_gallery_photo_gallery1`
    FOREIGN KEY (`gallery_id` )
    REFERENCES `tbl_gallery` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;
 

А теперь выводим галерею на странице группы (тоже через поведение)

Хочу на colorbox выводить галерею. Расширение не понравилось, поэтому отдельно скачал colorbox и подключаю к представлению страницы о группе view.php (ещё раз оговорюсь — это для yii-app!!)
 
<?php css('css/colorbox.css'); ?>   
<?//php Yii::app()->clientScript->registerCssFile(Yii::app()->request->baseUrl . "/css/colorbox.css", CClientScript::POS_END); ?>
<?php js('js/jquery.colorbox-min.js'); ?>
<script>
            jQuery(document).ready(function () {
                jQuery('a.gallery').colorbox({ opacity:0.5 , rel:'group1', loop:false });
jQuery('a.<?php echo $model->alias;?>').colorbox({ opacity:0.5 , rel:'group1', loop:false });
            });
        </script> 
И виджет поведения
...
<?php if(isset($model->gallery_id) && $model->gallery_id != "0") : ?>
<section id="photo">
<h3>Фото</h3>   
<?php 
$this->widget('GalleryViewer', array(
       'gallery' => $model->galleryBehavior->getGallery(), 
'controllerRoute' => '/gallery',
'gallerypath' => $model->alias,
   ));
?>
</section>    
<?php endif; ?>
...
Этот виджет надо создать по аналогии с GalleryManager, но он проще тем, что нужно лишь выводить фотографии без кнопок редактирования/добавления/удаления. Привожу содержимое файлов
 
/galleryManager/GalleryViewer.php
<?php
class GalleryViewer extends CWidget
{
    /** @var Gallery Model of gallery to manage */
    public $gallery;
    /** @var string Route to gallery controller */
    public $controllerRoute = false;
    public $assets; 
public $gallerypath;
    public $htmlOptions = array();


    /** Render widget */
    public function run()
    {
        /** @var $cs CClientScript */
        $photos = array();
        foreach ($this->gallery->galleryPhotos as $photo) { 
$photo->galleryDir = $photo->galleryDir."/".$this->gallerypath; 
            /*$photos[] = array(
                'id' => $photo->id,
                'rank' => $photo->rank,
                'name' => (string)$photo->name,
                'description' => (string)$photo->description,
                'preview' => $photo->getPreview(),
            );*/
        }

        $this->render('galleryViewer', array('photos'=>$this->gallery->galleryPhotos, 'groupalias'=>$this->gallerypath));
    }

}       
и представление /galleryManager/views/galleryViewer.php
<ul class="thumbnails">
<?php foreach($photos as $photo): ?> 
<li class="span3"><a class="<?php echo $groupalias; ?> thumbnail" href="<?php echo $photo->url; ?>"><img src="<?php echo $photo->getUrl("small"); ?>" alt="<?php echo $photo->name; ?>" /></a></li>
<?php endforeach; ?> 
</ul>
Ну вот, с этим уже можно работать. Можно вешать поведение на необходимые модели и само поведение настраивать на работу с другой таблицей, например, в будущем хочу помимо галерей групп добавить галереи мероприятий и для них использовать другие таблицы вместо tbl_gallery и tbl_gallery_photo.
 
Источник: loco.ru

almix
Разработчик Loco, автор статей по веб-разработке на Yii, CodeIgniter, MODx и прочих инструментах. Создатель Team Sense.

Вы можете почитать все статьи от almix'а.



Другие статьи по этой теме:

Комментарии (2)     Подпишитесь на RSS комментариев к этой статье.

2 комментариев

#1030
Александр говорит:
November 21, 2013 at 01:12 pm

Спасибо Вам, что поделились своим кодом - как раз собирался переделывать галерею под Yii .

Если не сложно, уточните по расширению image

У вас в коде упоминается два (от z_bodya и crisu83 )
причем первый объявлен компонентом, а второй указан в controllerMap

Заранее благодарен, Александр.

#1137
almix говорит:
April 23, 2014 at 04:33 pm
Александр, для галереи здесь использую расширение image от z_bodya. второе ещё не использовал.