Наверх

Как работают дополнения MODX. Часть 5 — Подготовка процессора

В нашей таблице можно вывести любые объекты MODX. Но для примера создадим свой тип объектов, так как это самая частая задача при разработке дополнений.

Хранить объекты будем в базе данных MODX. Для этого создадим в ней табличку с таким же префиксом, как и у других таблиц:
CREATE TABLE `modx_things_names` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    `description` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    `active` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
    
    PRIMARY KEY (`id`),
    INDEX (`active`)
) ENGINE=MyISAM CHARSET=utf8 COLLATE utf8_general_ci;

Ну и можно через PhpMyAdmin заполнить тестовыми данными


Чтобы MODX мог получать данные из нашей таблицы, ему надо о ней «рассказать». Для этого нужно создать xPDO-модель. Создаём папку /core/components/things/model/things/ и в ней файл metadata.mysql.php
<?php
$xpdo_meta_map = array(
    'xPDOSimpleObject' => // Наши объекты будут расширять xPDOSimpleObject
        array(
            0 => 'ThingsName', // Придумываем название класса для наших объектов
        ),
);

Если мы создаём несколько таблиц в рамках одного дополнения, прописываем все эти таблицы в нашем файле. Теперь для каждой таблицы нужно создать 3 файла:

/core/components/things/model/things/thingsname.class.php
<?php
class ThingsName extends xPDOSimpleObject {}

/core/components/things/model/things/mysql/thingsname.class.php
<?php
require_once (dirname(dirname(__FILE__)) . '/thingsname.class.php');
class ThingsName_mysql extends ThingsName {}

/core/components/things/model/things/things/thingsname.map.inc.php
В этом файле нужно описать все поля объекта и его связи.
<?php
// Указываем, к какому объекту относится описание
$xpdo_meta_map['ThingsName'] = array(
    'package' => 'things',
    'version' => '1.1',
    'table' => 'things_names', // Имя соответствующей таблицы
    'extends' => 'xPDOSimpleObject',
    'fields' => // Список полей объекта
        array(
            'name' => '',
            'description' => '',
            'active' => 1,
        ),
    'fieldMeta' =>
        array( // Описываем свойства каждого поля
            'name' =>
                array(
                    'dbtype' => 'varchar', // Тип поля в БД
                    'precision' => '255', // Длина поля
                    'phptype' => 'string', // Тип поля в PHP
                    'null' => false, // Допустимо ли значение NULL
                    'default' => '', // Значение по умолчанию
                ),
            'description' =>
                array(
                    'dbtype' => 'text',
                    'phptype' => 'text',
                    'null' => true,
                    'default' => '',
                ),
            'active' =>
                array(
                    'dbtype' => 'tinyint',
                    'precision' => '1',
                    'phptype' => 'boolean',
                    'null' => true,
                    'default' => 1,
                ),
        ),
);

Этого достаточно, чтобы следующий код успешно отработал в любом сниппете:
<?php
$modx->addPackage('things', MODX_CORE_PATH . 'components/things/model/');
$things = $modx->getCollection('ThingsName');
$output = array();
foreach ($things as $thing) {
    $output[] = $thing->name;
}
return implode(PHP_EOL, $output);

Но нам нужно, чтобы список объектов был получен в процессоре getlist, чтобы вывести потом в табличке.

Можно вызывать метод addPackage в процессоре, но процессоров у нас потом будет несколько, поэтому вызовем этот метод в коннекторе /assets/components/things/connector.php:
<?php
$base_path = dirname(__FILE__);
while (!file_exists($base_path . '/config.core.php')) {
    $base_path = dirname($base_path);
}

require_once $base_path . '/config.core.php';
require_once MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php';
require_once MODX_CONNECTORS_PATH . 'index.php';

// Подключаем модель наших объектов
$modx->addPackage('things', MODX_CORE_PATH . 'components/things/model/');
$modx->request->handleRequest(array(
	'processors_path' => MODX_CORE_PATH . 'components/things/processors/',
	'location' => '',
));

Теперь в процессоре мы можем получить список всех объектов, подставив свойства limit и start:
<?php
class ThingsGetListProcessor extends modProcessor {

    public function process() {
        $array = array();
        // Создаём запрос
        $q = $this->modx->newQuery('ThingsName');
        // Узнаём общее количество объектов
        $total = $this->modx->getCount('ThingsName', $q);
        // Передаём в запрос start и limit
        $limit = $this->getProperty('limit');
        $start = $this->getProperty('start');
        $q->limit($limit, $start);
        // Получаем объекты и добавляем их в массив
        $objects = $this->modx->getCollection('ThingsName', $q);
        foreach ($objects as $object) {
            $array[] = $object->toArray();
        }
        // Отдаём данные в виде массива табличке ExtJS
        return json_encode(array(
            'success' => true,
            'total' => $total,
            'results' => $array
        ));
    }

}
return "ThingsGetListProcessor";

Как ни удивительно, для таких процессоров в MODX тоже есть заготовки. Всё, что мы прописали здесь (и даже немного больше) уже прописано в классе modObjectGetListProcessor. Мы можем унаследоваться от него, указав только нужный нам класс объекта:
<?php
// Меняем название процессора — просто для удобства
class ThingsNameGetListProcessor extends modObjectGetListProcessor {
    public $classKey = 'ThingsName'; // Класс объекта
    public $defaultSortField = 'id'; // По какому полю сортировать
}
return "ThingsNameGetListProcessor";

В табличке выведем новые поля, которые есть у наших объектов:
Things.grid.Names = function (config) {
    config = config || {};
    Ext.apply(config, {
        columns: [
            {dataIndex: 'id', width: 150, header: 'ID'},
            {dataIndex: 'name', width: 250, header: 'Name'},
            
            // Добавляем новые колонки
            {dataIndex: 'description', width: 500, header: 'Description'},
            {dataIndex: 'active', width: 100, header: 'Active'}
        ],
        autoHeight: true,
        viewConfig: {
            forceFit: true,
            scrollOffset: 0
        },
        url: Things.config.connector_url,
        action: 'mgr/thing/getlist',
        
        // Добавляем новые поля
        fields: ['id','name', 'description', 'active'],
        paging: true,
        pageSize: 1
    });
    Things.grid.Names.superclass.constructor.call(this, config);
}
Ext.extend(Things.grid.Names, MODx.grid.Grid);
Ext.reg('things-grid-names', Things.grid.Names);

У колонок можно указать renderer — это функция, которая определяет, как оформить поле в зависимости от его значения:
// ...
{dataIndex: 'active', width: 100, header: 'Active', renderer: function(value) {
        if (value) { // Если значение поля == true
            return '<span class="green">Yes</span>';
        } else { // Иначе
            return '<span class="red">No</span>';
        }
    }}
// ...

Так же renderer можно использовать, чтобы отобразить картинку, если в базе хранится её адрес:
// ...
{dataIndex: 'image', width: 100, header: 'Image', renderer: function(value) {
        return '<img src="' + value + '">';
    }}
// ...

На этом работу с табличкой, думаю, закончим. В следующих уроках попробуем разобраться с окнами, чтобы создавать или редактировать наши объекты.


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

  1. Саня 28 октября 2017, 20:50 # 0
    Илья, привет.

    При вызове сниппета ничего не происходит, в логах ошибка:
    Could not get table class for class: FormconstructorName
    Error 42000 executing statement: 
    Array
    (
        [0] => 42000
        [1] => 1064
        [2] => You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS `FormconstructorName`' at line 1
    )
    
    P.S. ThingsName заменил на FormconstructorName
    1. Илья Уткин 28 октября 2017, 21:55 # 0
      Точно во всех файлах заменил? Где-то ошибка в модели.
      1. Саня 29 октября 2017, 16:46 # 0
        Сегодня сделал все заново с первого урока. Ничего не менял. Ошибка та же:
        Could not get table name for class: ThingsName
        ...
        
        Если интересно, то могу дать доступ в админку.
        1. Саня 29 октября 2017, 16:54 # +1
          Я нашел проблему.

          Вот этот файл thingsname.map.inc.php должен лежать в
          core/components/things/model/things/mysql/
          
          а у тебя в статье
          core/components/things/model/myextra/things/
          
          1. Илья Уткин 30 октября 2017, 08:42 # 0
            Действительно) Невнимательность моя)
    2. УстюПаша 28 октября 2017, 23:10 # +1
      Очень долгожданно! Осталось самое интересное! Создание и редактирование )
      1. Станислав Однолетко 12 ноября 2017, 01:34 # 0
        Привет, Илья. У меня что-то тоже класс найти не может. Структура файлов такая rgho.st/6sMzfRJNn/thumb.png

        1. Станислав Однолетко 13 ноября 2017, 17:09 # 0
          Илья, пути все на месте, но возникла следующая ошибка Could not get table class for class: ThingsName. Чет не могу догнать в чем дело. Эта ошибка не связана случайно с моделью xml?(догадка)
          1. Станислав Однолетко 13 ноября 2017, 17:15 # 0
            Вообщем, разобрался, все таки в путях проблема была)

          Авторизация

          через сервис Loginza:

          Подписка или RSS

          Буду присылать новые статьи — никакого спама



          Шаблоны MODX

          1 2 Дальше »

          Объектная
          модель
          MODX