Добавление select с данными из другой таблицы в modExtra

Всем привет. Кто-нибудь на заготовке modExtra делал CоmboBox с данными из других таблиц? У меня есть файл вызывающий модальное окно с полями для заполнения:

assets/components/extras/js/mgr/widgets/categories.window.js
Extras.window.CreateCategory = function (config) {
    config = config || {};
    if (!config.id) {
        config.id = 'extras-category-window-create';
    }
    Ext.applyIf(config, {
        title: _('extras_category_create'),
        width: 550,
        autoHeight: true,
        url: Extras.config.connector_url,
        action: 'mgr/category/create',
        fields: this.getFields(config),
        keys: [{
            key: Ext.EventObject.ENTER, shift: true, fn: function () {
                this.submit()
            }, scope: this
        }]
    });
    Extras.window.CreateCategory.superclass.constructor.call(this, config);
};
Ext.extend(Extras.window.CreateCategory, MODx.Window, {

    getFields: function (config) {
        return [{
            xtype: 'textfield',
            fieldLabel: _('extras_category_name'),
            name: 'name',
            id: config.id + '-name',
            anchor: '99%',
            allowBlank: false,
        }, {
            xtype: 'textfield',
            fieldLabel: _('extras_category_repository'),
            name: 'repository_id',
            id: config.id + '-repository_id',
            anchor: '99%',
            allowBlank: true,
        }, {
            xtype: 'xcheckbox',
            boxLabel: _('extras_category_active'),
            name: 'active',
            id: config.id + '-active',
            checked: true,
        }];
    },

    loadDropZones: function () {
    }

});
Ext.reg('extras-category-window-create', Extras.window.CreateCategory);


Extras.window.UpdateCategory = function (config) {
    config = config || {};
    if (!config.id) {
        config.id = 'extras-category-window-update';
    }
    Ext.applyIf(config, {
        title: _('extras_category_update'),
        width: 550,
        autoHeight: true,
        url: Extras.config.connector_url,
        action: 'mgr/category/update',
        fields: this.getFields(config),
        keys: [{
            key: Ext.EventObject.ENTER, shift: true, fn: function () {
                this.submit()
            }, scope: this
        }]
    });
    Extras.window.UpdateCategory.superclass.constructor.call(this, config);
};
Ext.extend(Extras.window.UpdateCategory, MODx.Window, {

    getFields: function (config) {
        return [{
            xtype: 'hidden',
            name: 'id',
            id: config.id + '-id',
        }, {
            xtype: 'textfield',
            fieldLabel: _('extras_category_name'),
            name: 'name',
            id: config.id + '-name',
            anchor: '99%',
            allowBlank: false,
        }, {
            xtype: 'textfield',
            fieldLabel: _('extras_category_repository'),
            name: 'repository_id',
            id: config.id + '-repository_id',
            anchor: '99%',
            allowBlank: true,
        }, {
            xtype: 'xcheckbox',
            boxLabel: _('extras_category_active'),
            name: 'active',
            id: config.id + '-active',
        }];
    },

    loadDropZones: function () {
    }

});
Ext.reg('extras-category-window-update', Extras.window.UpdateCategory);

тоесть нужно select сделать из

{
            xtype: 'textfield',
            fieldLabel: _('extras_category_repository'),
            name: 'repository_id',
            id: config.id + '-repository_id',
            anchor: '99%',
            allowBlank: true,
        },
В процессоре core/components/extras/processors/mgr/category/getlist.class.php

<?php

class ExtrasCategoriesGetListProcessor extends modObjectGetListProcessor
{
    public $objectType = 'ExtrasCategories';
    public $classKey = 'ExtrasCategories';
    public $defaultSortField = 'id';
    public $defaultSortDirection = 'DESC';
    //public $permission = 'list';


    /**
     * We do a special check of permissions
     * because our objects is not an instances of modAccessibleObject
     *
     * @return boolean|string
     */
    public function beforeQuery()
    {
        if (!$this->checkPermissions()) {
            return $this->modx->lexicon('access_denied');
        }

        return true;
    }


    /**
     * @param xPDOQuery $c
     *
     * @return xPDOQuery
     */
    public function prepareQueryBeforeCount(xPDOQuery $c)
    {
        $query = trim($this->getProperty('query'));
        if ($query) {
            $c->where([
                'name:LIKE' => "%{$query}%",
                'OR:repository_id:LIKE' => "%{$query}%",
            ]);
        }

        return $c;
    }


    /**
     * @param xPDOObject $object
     *
     * @return array
     */
    public function prepareRow(xPDOObject $object)
    {
		if ($this->getProperty('combo')) {
			$data = array(
				'id' => $object->get('id'),
				'name' => $object->get('name'),
			);
		} else {
			$array = $object->toArray();
			if (!$array['resource']) {
				$array['resource'] = null;
			}

			$array['actions'] = [];

			// Edit
			$array['actions'][] = [
				'cls' => '',
				'icon' => 'icon icon-edit',
				'title' => $this->modx->lexicon('extras_category_update'),
				//'multiple' => $this->modx->lexicon('extras_categories_update'),
				'action' => 'updateCategory',
				'button' => true,
				'menu' => true,
			];

			if (!$array['active']) {
				$array['actions'][] = [
					'cls' => '',
					'icon' => 'icon icon-power-off action-green',
					'title' => $this->modx->lexicon('extras_category_enable'),
					'multiple' => $this->modx->lexicon('extras_categories_enable'),
					'action' => 'enableCategory',
					'button' => true,
					'menu' => true,
				];
			} else {
				$array['actions'][] = [
					'cls' => '',
					'icon' => 'icon icon-power-off action-gray',
					'title' => $this->modx->lexicon('extras_category_disable'),
					'multiple' => $this->modx->lexicon('extras_categories_disable'),
					'action' => 'disableCategory',
					'button' => true,
					'menu' => true,
				];
			}

			// Remove
			$array['actions'][] = [
				'cls' => '',
				'icon' => 'icon icon-trash-o action-red',
				'title' => $this->modx->lexicon('extras_category_remove'),
				'multiple' => $this->modx->lexicon('extras_categories_remove'),
				'action' => 'removeCategory',
				'button' => true,
				'menu' => true,
			];
		}

        return $array;
    }

}

return 'ExtrasCategoriesGetListProcessor';
Может кто-нибудь помочь с этим?
SEQUEL.ONE
22 сентября 2018, 17:03
modx.pro
4
1 843
+1

Комментарии: 15

Mikhail Tyrsyna
25 сентября 2018, 17:10
+1
utils.js
Extras.combo.Field = function (config) {
    config = config || {};
    Ext.applyIf(config, {
        url: Extras.config.connector_url, 
        baseParams: {
            action: config.action,
        }, 
        name: 'repository', 
        fields: ['name'], 
        mode: 'remote', 
        displayField: 'name', 
        fieldLabel: _('Extras'),
        valueField: 'name', 
        editable: true, 
        anchor: '99%',
        allowBlank: false,
        autoLoad: false
    });
    Extras.combo.Field.superclass.constructor.call(this, config);
};
Ext.extend(Extras.combo.Field, MODx.combo.ComboBox);
Ext.reg('extras-combo-field', Extras.combo.Field);

Потом просто используешь свой xtype где тебе нужно
{
    xtype: 'extras-combo-field',
    action: 'mgr/load/getlist',
}

Процессор примерно такой
<?php
require_once MODX_CORE_PATH.'components/extras/processors/mgr/extras/getlist.class.php';

class ExtrasLoadFieldProcessor extends ExtrasFieldGetListProcessor {
    public $permission = '';

    public function prepareRow(xPDOObject $object)
    {
        $array = parent::prepareRow($object);
        $array['id'] = $array['name'];
        return $array;
    }

}

return 'ExtrasLoadFieldProcessor';
    SEQUEL.ONE
    25 сентября 2018, 21:14
    +1
    Огромное спасибо, хоть понял как это делать, а потом увидел, что в папке assets/components/extras/js/mgr/misc/combo.js есть пример)))

    Получилось сделать так, добавил в combo.js

    Extras.combo.Repository = function (config) {
        config = config || {};
    
        Ext.applyIf(config, {
            name: 'repository_id',
            fieldLabel: _('repositories_' + config.name || 'repository'),
            hiddenName: 'repository_id',
            displayField: 'name',
            valueField: 'id',
            anchor: '99%',
            fields: ['name', 'id'],
            pageSize: 20,
            url: Extras.config['connector_url'],
            typeAhead: true,
            editable: true,
            allowBlank: true,
            emptyText: _('no'),
            minChars: 1,
            baseParams: {
                action: 'mgr/repository/getlist',
                combo: true,
                id: config.value,
            }
        });
        Extras.combo.Repository.superclass.constructor.call(this, config);
        this.on('expand', function () {
            if (!!this.pageTb) {
                this.pageTb.show();
            }
        });
    };
    Ext.extend(Extras.combo.Repository, MODx.combo.ComboBox);
    а xtype в categories.window.js вышел такой:

    {
                xtype: 'extras-combo-repository',
                fieldLabel: _('extras_category_repository'),
                anchor: '99%',
                allowBlank: true,
            },
    Да, процессоры вообще не трогал, ну кроме изменения классов и лексиконов под себя, всё из дефольтной версии modExtras выводится. Теперь встала задача вывести в grid вместо id название)))
      SEQUEL.ONE
      26 сентября 2018, 08:57
      0
      Каким образом в таблицу выводить название категории вместо его ID? Не понимаю. :|
        Mikhail Tyrsyna
        26 сентября 2018, 10:15
        +1
        Попробуй заджойнить
        Если не ошибаюсь примерно как-то так

        getlist.class.php
        public function prepareQueryBeforeCount(xPDOQuery $c) {
        $c->select(array('Owner.name'));
        $c->leftJoin('Owner','Owner');
        return $c;
        }

        docs.modx.com/xpdo/2.x/class-reference/xpdoquery/xpdoquery.leftjoin
          SEQUEL.ONE
          26 сентября 2018, 10:44
          0
          Тут вопрос скорее как в extjs в файле categories.grid.php это провернуть. Что делать с
          dataIndex: 'repository_id'
            SEQUEL.ONE
            26 сентября 2018, 10:45
            0
            Просто у меня в этой таблице тоже заголовок name
              Mikhail Tyrsyna
              26 сентября 2018, 10:57
              +1
              Попробуй

              $c->select(array('Owner.name as repository_name'));
              и
              dataIndex: 'repository_name'
                SEQUEL.ONE
                26 сентября 2018, 11:53
                0
                Дома попробую и отпишусь сюда. Спасибо. Как же не хватает мануала по этой заготовке)
            SEQUEL.ONE
            26 сентября 2018, 21:33
            +1
            Что-то никаких изменений :( Код getlist.class.php

            Синтаксис lefJoin правильный? Указываем класс модели и его алиас?!

            <?php
            
            class ExtrasCategoriesGetListProcessor extends modObjectGetListProcessor
            {
                public $objectType = 'ExtrasCategories';
                public $classKey = 'ExtrasCategories';
                public $defaultSortField = 'id';
                public $defaultSortDirection = 'DESC';
                //public $permission = 'list';
            
            
                /**
                 * We do a special check of permissions
                 * because our objects is not an instances of modAccessibleObject
                 *
                 * @return boolean|string
                 */
                public function beforeQuery()
                {
                    if (!$this->checkPermissions()) {
                        return $this->modx->lexicon('access_denied');
                    }
            
                    return true;
                }
            
            
                /**
             * @param xPDOQuery $c
             *
             * @return xPDOQuery
             */
            	public function prepareQueryBeforeCount(xPDOQuery $c)
            	{
            		$query = trim($this->getProperty('query'));
            		if ($query) {
            			$c->select(array('ExtrasRepositories.name as repository_name'));
            			$c->leftJoin('ExtrasRepositories','ExtrasRepositories');
            
            			$c->where([
            				'name:LIKE' => "%{$query}%",
            				'OR:repository_id:LIKE' => "%{$query}%",
            				'OR:repository_name:LIKE' => "%{$query}%",
            			]);
            		}
            
            		return $c;
            	}
            
            
                /**
                 * @param xPDOObject $object
                 *
                 * @return array
                 */
                public function prepareRow(xPDOObject $object)
                {
            		if ($this->getProperty('combo')) {
            			$data = array(
            				'id' => $object->get('id'),
            				'name' => $object->get('name'),
            			);
            		} else {
            			$array = $object->toArray();
            			if (!$array['resource']) {
            				$array['resource'] = null;
            			}
            
            			$array['actions'] = [];
            
            			// Edit
            			$array['actions'][] = [
            				'cls' => '',
            				'icon' => 'icon icon-edit',
            				'title' => $this->modx->lexicon('extras_category_update'),
            				//'multiple' => $this->modx->lexicon('extras_categories_update'),
            				'action' => 'updateCategory',
            				'button' => true,
            				'menu' => true,
            			];
            
            			if (!$array['active']) {
            				$array['actions'][] = [
            					'cls' => '',
            					'icon' => 'icon icon-power-off action-green',
            					'title' => $this->modx->lexicon('extras_category_enable'),
            					'multiple' => $this->modx->lexicon('extras_categories_enable'),
            					'action' => 'enableCategory',
            					'button' => true,
            					'menu' => true,
            				];
            			} else {
            				$array['actions'][] = [
            					'cls' => '',
            					'icon' => 'icon icon-power-off action-gray',
            					'title' => $this->modx->lexicon('extras_category_disable'),
            					'multiple' => $this->modx->lexicon('extras_categories_disable'),
            					'action' => 'disableCategory',
            					'button' => true,
            					'menu' => true,
            				];
            			}
            
            			// Remove
            			$array['actions'][] = [
            				'cls' => '',
            				'icon' => 'icon icon-trash-o action-red',
            				'title' => $this->modx->lexicon('extras_category_remove'),
            				'multiple' => $this->modx->lexicon('extras_categories_remove'),
            				'action' => 'removeCategory',
            				'button' => true,
            				'menu' => true,
            			];
            		}
            
                    return $array;
                }
            
            }
            
            return 'ExtrasCategoriesGetListProcessor';
            ну и в самом файле categories.grid.js вставил поле:

            getFields: function () {
                    return ['id', 'name', 'repository_name', 'active', 'actions'];
                },
            И само поле

            {
                        header: _('extras_category_repository'),
                        dataIndex: 'repository_name',
                        sortable: false,
                        width: 250,
                    },
            Поле стало пустым полностью)
              Mikhail Tyrsyna
              26 сентября 2018, 23:40
              0
              Т.к. ты её запихнул в оператор, и join будет срабатывать только после поиска

              Попробуй вынеси выше
              $query = trim($this->getProperty('query'));
              $c->select(array('ExtrasRepositories.name as repository_name'));
              $c->leftJoin('ExtrasRepositories','ExtrasRepositories');
              
              if ($query) {
              // code..
              }
                Mikhail Tyrsyna
                26 сентября 2018, 23:56
                0
                Если что это примеры сходу, с расчетом на то что ты будешь капать в этом направлении:>
                  SEQUEL.ONE
                  13 октября 2018, 22:26
                  0
                  $c->leftJoin('ExtrasRepositories', 'ExtrasRepositories', 'ExtrasRepositories.id = ExtrasCategories.repository_id');
                  		$c->select(array($this->modx->getSelectColumns('ExtrasCategories', 'ExtrasCategories')));
                  		$c->select(array('ExtrasRepositories.name as repository_name'));
                  В блоге оформил в статью, если вдруг кому понадобиться.
        Олег Щавелев
        11 мая 2020, 05:41
        0
        Очень крутая тема для обсуждения. Сейчас разбираюсь с modExtra и как раз разбирал данный вопрос. Прочитал и сделал, мне всегда нравиться такая схема. Автору +1 к статье. Вопрос только у меня. У меня по какой-то причине если добавить в файл getlist.class.php

        if ($query) {
                    $c->where([
                        'name:LIKE' => "%{$query}%",
                        'OR:description:LIKE' => "%{$query}%",
                        'OR:position_name:LIKE' => "%{$query}%",
        
                    ]);
        position_name — это alias присоединенного поля. Поиск не ищет по данному полю. В чем могут быть нюансы.

        $c->leftJoin('infoBlockPosition', 'infoBlockPosition', 'infoBlockPosition.id = infoBlockItem.position_id');
        $c->select(array($this->modx->getSelectColumns('infoBlockItem', 'infoBlockItem')));
        $c->select(array('infoBlockPosition.name as position_name'));
          SEQUEL.ONE
          11 мая 2020, 21:45
          0
          Если ещё не видели:
          modx.pro/development/19942
          github.com/SequelONE/modExtra
            Олег Щавелев
            12 мая 2020, 08:24
            0
            Я Видел данную сборку. В вашей сборке так же фильтр по строке категории не работает при условии добавления alias в getlist столбца по которому необходимо осуществлять поиск. Связи с этим я и задал вопрос. Не логично, что-то каким-то полям не возможно настраивать и осуществлять поиск. Если найду разгадку первым обязательно напишу ответ.
          Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
          15