Как в MODX загрузить несколько изображений к ресурсу

Чего мне всегда не хватало в Revo дак это удобной галереи для менеджера. Для Evo есть EvoGallery, где можно управлять альбомом прямо на странице документа. Менеджеру не нужно постоянно путаться, что редактирование документов осуществляется в дереве документов, а фотографии грузятся через модули. Все в одном месте, удобно. Причем галерея нужна на основе базы данных, а не просто файлы в папке, чтобы можно было указать описания для фотографий, метки, сортировать их итд.

Поэтому решил попытаться сделать похожее в Revo, где в качестве галереи выбрал Gallery. В Revo есть возможность создавать собственные параметры ввода для TV, на основе которых в Gallery сделан тип TV galleryalbumlist, с помощью которого можно привязать альбом к документы, но фотографии по прежнему загружаются через компоненты.

Создадим новый тип galleryalbumview. Принцип работы будет такой: TV хранит ID альбома в галерее, редактирования ID не будет. При редактировании документа проблем не будет, т.к. в TV значение ID альбома уже будет, а для новых документов создавать альбомы и записывать его ID будем при первом сохранении документа.

Для этого в папке core/components/gallery/elements/tv/input/ создадим файл galleryalbumview.class.php

<?php
class GalleryAlbumViewInputRender extends modTemplateVarInputRender {
    public function getTemplate() {
        if(!empty($this->tv->value)){
            $options = array('processors_path'=>$this->modx->getOption('core_path').'components/gallery/'.'processors/');
            if($this->modx->runProcessor('mgr/album/get',array('id'=>$this->tv->value),$options)->isError()){
                $this->tv->value = "";
            }
        }
        return $this->modx->getOption('gallery.core_path',null, $this->modx->getOption('core_path').'components/gallery/').'elements/tv/galleryalbumview.input.tpl';
    }
}
return 'GalleryAlbumViewInputRender';

В папке core/components/gallery/elements/tv создадим шаблон galleryalbumview.input.tpl

<div id="tv{$tv->id}-form"></div>
<input id="tv{$tv->id}" type="hidden" name="tv{$tv->id}" value="{$tv->value}"/>
{if $tv->value ne ''}
{literal}
<script type="text/javascript">
// <![CDATA[
Ext.onReady(function() {
        MODx.load({{/literal}
        xtype: 'gal-panel-album-items'
        ,border: false
        ,autoHeight: true
        ,autoScroll: true
        ,forceLayout: true
        ,width: Ext.getCmp('modx-panel-resource').getWidth() - 300
        ,album: '{$tv->value}'
        ,renderTo: 'tv{$tv->id}-form'
        ,tv: '{$tv->id}'
        ,tvValue: '{$tv->value}'

{literal}
        });
});     
// ]]>
</script>
{/literal}
{else}
<p>Please, save document before create gallery</p>
{/if}

В плагине GalleryCustomTV (ставится вместе с Gallery) допишем нужные нам js и css файлы, в итоге в конце плагина код должен быть таким:

$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/tv/Spotlight.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/gallery.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/widgets/album/album.items.view.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/widgets/album/album.tree.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/tv/gal.browser.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/tv/galtv.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/utils/ddview.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/utils/fileuploader.js');
$modx->controller->addJavascript($gallery->config['assetsUrl'].'js/mgr/widgets/album/album.panel.js');
$modx->controller->addCss($gallery->config['cssUrl'].'mgr.css');
$modx->controller->addCss($gallery->config['cssUrl'].'fileuploader.css');


Теперь у нас появился новый тип TV - "galleryalbumview", создадим с данным типом TV, например GalleryAlbum и привяжем его к шаблону. Удобно такие автосозданные альбомы хранить в отдельном корневом альбоме в галерее, поэтому на вкладке «Параметры» создадим параметр galParentId со значением, к примеру, 1. Это ID родительского альбома (его необходимо предварительно создать).

Далее нам нужен плагин, который при сохранении документа будет создавать альбом в галерее и записывать его ID в TV.
Создадим плагин CreateGalleryAlbum, укажем событие OnDocFormSave и OnResourceDuplicate

Плагин CreateGalleryAlbum:

<?php
switch ($modx->event->name)
{
    case 'OnDocFormSave':
        $GalleryProcessorPath = $modx->getOption('gallery.core_path',$config,$modx->getOption('core_path').'components/gallery/').'processors/';
        $options = array('processors_path'=>$GalleryProcessorPath);
        $galleryName = $resource->get('pagetitle');
        //Получаем все TV текущего ресурса
        $tvs = $resource->getTemplateVars();
        foreach($tvs as $tv) {
            //нам нужны только TV с типом galleryalbumview
            if ($tv->get('type')=='galleryalbumview') {
                $createalbum = false;
                $tvvalue = $tv->getValue($id);
                if(!empty($tvvalue)){
                    $resp = $modx->runProcessor('mgr/album/get',array('id'=>$tvvalue),$options);
                    if (!$resp->isError()) {
                        $album = $resp->getObject();
                        if(!empty($album)){
                            $album['name'] = $galleryName;
                            $modx->runProcessor('mgr/album/update',$album,$options);
                        }else{
                            $createalbum = true;
                        }
                    }else{
                        $createalbum = true;
                    }
                }else{
                    $createalbum = true;
                }
                if ($createalbum) {
                    $tv_prop = $tv->get('properties');
                    $album = array(
                        'name' => $galleryName,
                        'parent' => isset($tv_prop['galParentId']['value'])?$tv_prop['galParentId']['value']:0,
                        'description' => '',
                        'active' => 1,
                        'prominent' => 0
                    );
                    $resp = $modx->runProcessor('mgr/album/create',$album,$options);
                    if (!$resp->isError()) {
                        $album = $resp->getObject();
                        $tv->setValue($id,$album['id']);
                        $tv->save();
                    }
                    
                }
            }
        }
        case 'OnResourceDuplicate':
            if(isset($newResource) && isset($oldResource)){
                $tvs = $newResource->getTemplateVars();
                $new_id = $newResource->get("id");
                $old_id = $oldResource->get("id");
                $GalleryProcessorPath = $modx->getOption('gallery.core_path',$config,$modx->getOption('core_path').'components/gallery/').'processors/';
                $options = array('processors_path'=>$GalleryProcessorPath);
                $pagetitle = $newResource->get('pagetitle');
                $i = 1;
                if(preg_match("/\s[\d]+$/i", $pagetitle, $m)){
                    $i = intval(trim($m[0])) + 1;
                    $pagetitle = preg_replace("/\s[\d]+$/i", " " . $i, $pagetitle);
                }else{
                    $pagetitle .= " " . $i;
                }
                $newResource->set("pagetitle", $pagetitle);
                $galleryName = $pagetitle;
                foreach($tvs as $tv) {
                    if ($tv->get('type')=='galleryalbumview') {
                        $new_value = $tv->getValue($new_id);
                        $old_value = $tv->getValue($old_id);
                        if($old_value == $new_value){
                            $tv_prop = $tv->get('properties');
                            $album = array(
                                'name' => $galleryName,
                                'parent' => isset($tv_prop['galParentId']['value'])?$tv_prop['galParentId']['value']:0,
                                'description' => '',
                                'active' => 1,
                                'prominent' => 0
                                );
                                $resp = $modx->runProcessor('mgr/album/create',$album,$options);
                            if (!$resp->isError()) {
                                $album = $resp->getObject();
                                $tv->setValue($new_id,$album['id']);
                                $tv->save();
                            }
                        }
                    }
                }
            }
        break;
}

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