Наверх

Как работают дополнения MODX. Часть 3 — ExtJS Button

Наверняка вы знаете, что обычно все дополнения MODX хранятся в папках /assets/components/ и /core/components/. Мы же создали папку нашего дополнения прямо в корне сайта. Это для того, чтобы было понятно — расположение файлов значения не имеет, MODX просто «смотрит» путь в пространстве имён и «идёт» по этому пути.

Расположение дополнений в папках core и assets имеет под собой ряд причин.

Во-первых, для безопасности необходимо закрывать доступ к php-файлам, которые не предназначены для запуска из браузера. В MODX есть такая папка, которая всегда должна быть закрыта от пользователей — это папка /core/.

Во-вторых, файлы JS-скриптов, например, должны быть доступны, соответственно, их нельзя размещать внутри /core/ — для них существует папка /assets/

Конечно, вы можете создать папку /things_core/ и закрыть её с помощью .htaccess, а JS-файлы перенести в папку /things_assets/, но есть и третья причина:
В-третьих, так здесь заведено
Другие разработчики, которые будут работать с сайтом, будут искать файлы вашего дополнения именно в тех папках, которые используются и всеми остальными программистами. Да и вы сами в будущем можете не вспомнить такую нестандартную структуру файлов.

Так что давайте, создадим папки
/assets/components/things/
/core/components/things/
и перенесём контроллер в core, а JS в assets. Ну и не забудем изменить путь у пространства имён:


В контроллере тоже надо подправить путь. Кроме того, инициализацию компонента принято оставлять внутри контроллера — чтобы корректно работал AjaxManager. Не знаю, насколько это сейчас актуально, но давайте следовать моде:
public function loadCustomCssJs() {
    $assets = $this->modx->getOption('assets_url');
    $this->addJavascript($assets . 'components/things/home.js?time=' .time());

    // Переносим Ext.onReady из home.js в контроллер
    $this->addHtml('<script type="text/javascript">
        Ext.onReady(function() {
            MODx.add({
                xtype: "things-panel-home"
            });
        });
    </script>');
}

ExtJS Button

Теперь добавим кнопку в первый таб:
title: 'Things 1',
items: [{
    html: 'Things 1 description', 
    cls: 'panel-desc',
}, {
    xtype: 'panel',
    cls: 'container',
    items: [{
        xtype: 'button',
        text: 'Load',
        cls: 'primary-button'
    } ]
} ]

Чтобы при клике на кнопку что-то произошло, используется свойство handler:
xtype: 'button',
text: 'Load',
cls: 'primary-button',
handler: function() {
    Ext.MessageBox.alert('Load','Clicked');
}

Давайте, при нажатии кнопки сделаем Ajax-запрос и покажем результат в окне:
handler: function() {
    MODx.Ajax.request({
        url: MODx.config.connector_url, // запрос пойдёт на адрес /connectors/index.php
        params: { // указываем параметры запроса
            action: 'resource/getlist', // здесь путь к процессору
            // можно указать и дополнительные параметры запроса
            parent: 0
        },
        listeners: {
            success: { // при успешном запросе
                fn: function ( r ) {
                    console.log( r ); // выведем ответ в консоль и покажем окошко
                    Ext.MessageBox.alert('Load', JSON.stringify(r.results));
                }, scope: this
            }
        }
    });
}

Здесь мы выполнили стандартный MODX-процессор, который получает список ресурсов. Но дополнение оно и называется дополнением, потому что выполняет какие-то действия, которые не прописаны в стандартных процессорах. Значит, нам надо создать свои процессоры. Создаём папку /core/components/things/processors/ в ней — папку mgr, внутри которой будет папка thing. Структура папок опять больше продиктована причиной № 3.

Процессор будет называться так же — getlist, поэтому создаём в папке /processors/mgr/thing/ файл getlist.class.php:
<?php
class ThingsGetListProcessor extends modProcessor {
    public function process() {
        return $this->success('Request completed');
    }
}
return "ThingsGetListProcessor";

MODX понятия не имеет, что мы храним свои процессоры в папке /processors/. Поэтому, использовать стандартный коннектор для вызова нашего процессора не получится. Так что создаём свой коннектор, в котором и будет прописан путь к папке с процессорами. Так как на этот коннектор будут приходить Ajax-запросы, его нужно размещать в папке /assets/components/things/:
<?php
$base_path = dirname(__FILE__);
// Ищем MODX
while (!file_exists($base_path . '/config.core.php')) {
    $base_path = dirname($base_path);
}

// Подключаем MODX
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 работать
$modx->request->handleRequest(array(
	'processors_path' => MODX_CORE_PATH . 'components/things/processors/',
	'location' => '',
));

Теперь можем в home.js отправлять Ajax-запросы уже к нашим процессорам:
// ...
MODx.Ajax.request({
    // прописываем адрес нашего коннектора
    url: '/assets/components/things/connector.php',
    params: {
        // меняем путь к процессору
        action: 'mgr/thing/getlist',
    },
// ...

Ajax-запросы — это частая задача при работе с дополнениями, поэтому адрес коннектора лучше вынести в отдельную переменную. JS-файлов часто становится много, поэтому определение переменной с адресом коннектора переносим в файл-контроллер (/core/components/things/index.class.php):
public function loadCustomCssJs() {
    $assets = $this->modx->getOption('assets_url');
    $this->addJavascript($assets . 'components/things/home.js?time=' .time());
    $this->addHtml('<script type="text/javascript">
        Things.config.connector_url = "' . $assets . 'components/things/connector.php";
        Ext.onReady(function() {
            MODx.add({
                xtype: "things-panel-home"
            });
        });
    </script>');
}

И теперь адрес коннектора будет выглядеть так: Things.config.connector_url.

Нам осталось разобраться с тем, как настроить работу со своими, кастомными объектами.


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

  1. meh 23 октября 2017, 17:54 # +1
    Илья, ты отлично пишешь.
    Никакой води и все по делу, с зарплаты обязательно задоначу!
    1. tramp1357 24 октября 2017, 02:04 # +1
      Илья, отличный цикл. Всё просто и понятно расписано!
      1. Саня 27 октября 2017, 03:24 # +1
        Спасибо за подробные описания.
        1. Егор 25 января 2018, 01:21(Комментарий был изменён) # 0
          Илья, доброго времени суток.
          Подскажите, пожалуйста, а как можно отправить с кнопкой определённые данные? Например, есть текстовое поле, в нём информация. Нужно эту информацию отправить на файл-обработчик (php) и получить ответ, что работа закончена. Как это можно сделать? В какую сторону копать?
          Заранее спасибо за ответ.

          p.s. получается, я просто могу в параметре передать эту переменную. Но как этот параметр уже менять на стороне фронта (ванильным js, например)?
          params: { // указываем параметры запроса
                      action: 'resource/getlist', // здесь путь к процессору
                      // можно указать и дополнительные параметры запроса
                      parent: 0
           },
          1. Илья Уткин 01 февраля 2018, 11:44 # 0
            Так сложно подсказать, тут больше к архитектуре вопрос. По идее, надо использовать MODx.load(), чтобы отправить AJAX-запрос с нужными параметрами.
            1. unreal_serg 26 марта 2020, 02:10(Комментарий был изменён) # +1
              Ajax запрос с помощью modExt можно отправить так:
              MODx.Ajax.request({
                          url: Things.config.connector_url,
                          params: {
                              action: 'mgr/item/save',
                              data: params
                          },
                          listeners: {
                              success: {
                                  fn: function (response) {
                              	console.log(response);
                                  }, scope: this
                              },
                              failure: {
                                  fn: function (response) {
                                      console.log(response);
                                  }, scope: this
                              }
                          }
                      });
              
              Все, что лежит в params полетит в процессор save.class.php в директории с процессорами твоего дополнения — core/components/things/processors/mgr/item (при условии если соблюдена классическая архитектура дополнения) и будет доступно там через $this->properties или через метод $this->getProperties();
              Кстати, используя именно метод модыкса, будет возможность выводить сообщения в виде модалки.
              Далее для success прописываешь действия в соответствии с полученными данными
            2. Guest 26 февраля 2018, 20:38 # 0
              Илья, здравствуйте. Спасибо Вам за уроки, это то, что нужно для человека, только начавшего разбираться с написанием дополнений на MODX.
              Помогите, пожалуйста, прояснить следующий момент. Насколько я поняла, процессоры — это классы, которые содержат логику работы программы. Их можно запускать как через ajax-запросы, так и через метод runProcessor().
              Роль скриптов на js — создание интерфейса.
              А для чего нам нужны контроллеры в таком случае? Я просто пытаюсь сейчас состыковать понятия «процессор», «контроллер», понять, как вообще устроена эта система, но не получается.
              С паттерном MVC я знакома, но не получается пока в рамки этой модели понятия MODXа уложить. Помогите, пожалуйста.
              1. Кирилл Киселев 23 апреля 2019, 12:08 # 0
                controllers — файлы для подготовки страниц админки. Загружают нужные скрипты и стили.
                processors — файлы, выполняющие какую-то одну небольшую функцию. Служат, как правило, для обработки запросов от админки.

              Авторизация

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


              Шаблоны MODX

              1 2 Дальше »

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