Расположение дополнений в папках 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 полетит в процессор save.class.php в директории с процессорами твоего дополнения — core/components/things/processors/mgr/item (при условии если соблюдена классическая архитектура дополнения) и будет доступно там через $this->properties или через метод $this->getProperties();
Кстати, используя именно метод модыкса, будет возможность выводить сообщения в виде модалки.
Далее для success прописываешь действия в соответствии с полученными данными
Помогите, пожалуйста, прояснить следующий момент. Насколько я поняла, процессоры — это классы, которые содержат логику работы программы. Их можно запускать как через ajax-запросы, так и через метод runProcessor().
Роль скриптов на js — создание интерфейса.
А для чего нам нужны контроллеры в таком случае? Я просто пытаюсь сейчас состыковать понятия «процессор», «контроллер», понять, как вообще устроена эта система, но не получается.
С паттерном MVC я знакома, но не получается пока в рамки этой модели понятия MODXа уложить. Помогите, пожалуйста.
processors — файлы, выполняющие какую-то одну небольшую функцию. Служат, как правило, для обработки запросов от админки.