Расположение дополнений в папках 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.
Нам осталось разобраться с тем, как настроить работу со своими, кастомными объектами.
Объектная
Никакой води и все по делу, с зарплаты обязательно задоначу!
Подскажите, пожалуйста, а как можно отправить с кнопкой определённые данные? Например, есть текстовое поле, в нём информация. Нужно эту информацию отправить на файл-обработчик (php) и получить ответ, что работа закончена. Как это можно сделать? В какую сторону копать?
Заранее спасибо за ответ.
p.s. получается, я просто могу в параметре передать эту переменную. Но как этот параметр уже менять на стороне фронта (ванильным js, например)?
params: { // указываем параметры запроса action: 'resource/getlist', // здесь путь к процессору // можно указать и дополнительные параметры запроса parent: 0 },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 прописываешь действия в соответствии с полученными данными
Помогите, пожалуйста, прояснить следующий момент. Насколько я поняла, процессоры — это классы, которые содержат логику работы программы. Их можно запускать как через ajax-запросы, так и через метод runProcessor().
Роль скриптов на js — создание интерфейса.
А для чего нам нужны контроллеры в таком случае? Я просто пытаюсь сейчас состыковать понятия «процессор», «контроллер», понять, как вообще устроена эта система, но не получается.
С паттерном MVC я знакома, но не получается пока в рамки этой модели понятия MODXа уложить. Помогите, пожалуйста.
processors — файлы, выполняющие какую-то одну небольшую функцию. Служат, как правило, для обработки запросов от админки.