Jump to main content Jump to doc navigation

На прошлом уроке мы разобрались с контроллерами Custom Manager Page (CMP) нашего компонента, и выяснили, что основной смысл их существования — подготовить все нужные файлы для вывода страницы.

Пока у нас используются js файлы от modExtra, и сегодня нам нужно их изучить и переписать для Sendex.

Первым делом нужно понять, что ExtJs — это javascript фреймфорк, куда более мощный чем jQuery. Он не требует HTML верстки, он все генерирует на лету. То есть, вы пишете javascript код, а на странице получаете готовые таблички, кнопочки, пагинацию и т.д.

Причем, все эти элементы уже подчиняются какой-то логике: одна кнопка переключает странички, другая вызывает модальное окно и т.д.

Сначала довольно трудно въехать в ExtJS, особенно если не знаешь javascript, но со временем начинаешь понимать его преимущества, и реально экономить время.

Виджеты

Сразу говорю, я не гуру ExtJS, освоил его на минимальном уровне, необходимом для написания компонентов MODX. Поэтому, буду писать «своими словами», и возможно не всегда верно.

На мой взгляд, 2 основных момента для понимания ExtJS:

  • Все элементы ExtJS являются объектами javascript, со своими свойствами. Когда вы пишите какой-то свой виджет, нужно просто унаследовать и расширить уже готовый от авторов ExtJS или MODX. Например, пишите свою таблицу — расширяете MODx.grid.Grid, в таблицах будут всплывающие окошки — писуете фиджет, расширяющий MODx.Window.

Это очень похоже на Объектно-Ориентированное Программирование (ООП) в PHP и если принять эту логику — жизнь становится очень простой и лёгкой.

  • Практически все видежты или уже работают, или умеют работать через Ajax. Все свои данные они отправляют на сервер без перезагрузки страницы, и ответ получают в формате JSON.

То есть, здесь полнейшее отделение логики от представления. Вам не нужно что-то там парсить или рендерить на PHP, чтобы отдать готовый HTML. Вставлять его тоже никуда не нужно, сервер должен отдать массив в таком формате:

$array = array(
    'success' => false,
    'message' => 'Возника ошибка при сохранении формы',
    'total' => 1
    'data' => array(
        'id' => 'alias',
        'msg' => 'Это поле обязательно'
    )
);

А виджет ExtJS смотрит в этот массив, понимает, что сервер отдал ошибку и выводит сообщение о ней. В данном примере — это требование заполнить alias страницы при её сохранении.

Уверяю вас, такая схема делает работу очень простой и удобной. Вы отдельно пишите код на javascript, отдельно пишите процессоры на PHP, которые с ним будут работать, а потом открываете админку — и начинается магия!

Всё структурировано, никакой мешанины в коде, недоработки легко находятся и исправляются. Готовые виджеты, которые можно вызвать на странице одной строчкой я называю xtype — потому что, именно это и указывается при их вызове.

Процессоры Мы не будем рассматривать старые скучные процессоры, в которых были просто портянки кода, которые возвращали JSON. С версии MODX 2.2 у нас появились «классные процессоры», о которых вы можете почитать вот здесь — с ними мы и будем работать.

Итак, процессор это php файл, который содержит класс, наследующий modProcessor и возвращающий своё имя. В MODX есть уже куча готовых классов на разные случаи жизни, которые можно наследовать для своих целей:

  • modObjectGetProcessor — Получает и возвращает указанный объект
  • modObjectGetListProcessor — Выводит список объектов для таблицы
  • modObjectCreateProcessor — Создаёт новый объект
  • modObjectUpdateProcessor — Обновляет существующий объект
  • modObjectDuplicateProcessor — Делает копию существующего объекта
  • modObjectRemoveProcessor — Удаляет объект То есть, здесь нам тоже, как правило, нужно просто унаследовать уже имеющийся класс, переопределить пару свойств и методов — и всё готово.

Сам файл-процессор состоит из класса, и обязан содержать в конце вернуть своё имя. Вот, простейший пример:

<?php
class SendexItemCreateProcessor extends modObjectCreateProcessor {
    // Тип объекта, с которым будем работать - это имя выводится в логе операций MODX
    // и подставляется в сообщения об ошибках
    public $objectType = 'sxNewsletter';
    // xPDO класс объекта
    public $classKey = 'sxNewsletter';
    // Используемый лексикон - нужен для вывода ошибок
    public $languageTopics = array('sendex');
    // Разрешение, которое проверяеся при работе с процессором
    // Можно оставить пустым - тогда смогут работать все менеджеры
    public $permission = 'new_document';
}
// Обязательно возвращаем имя класса, чтобы MODX знал, что именно нужно инициализировать в процессоре
return 'SendexItemCreateProcessor';

Это процессор абсолютно рабочий, его можно вызвать через $modx->runProcessor(), передать нужные параметры и будет создан объект sxNewsletter (или получена ошибка).

Для того, чтобы узнать, какие методы можно переопределить — просто смотрите в исходник наследуемого modObjectCreateProcessor. Напоминаю, что в PhpStorm нужно просто кликнуть на класс и нажать Ctrl+B.

С теорией покончено, давайте закрепим на практике.

Основные js файлы админки

От modExtra у нас осталась демонстрационная страница, которая создаётся следующими скриптами в /assets/components/sendex/js/mgr/:

  • sendex.js — скрипт с объявлением самого объекта Sendex. В него будут вписываться все остальные объекты компонента. Этот файл мы не трогаем.
  • sections/home.js — Скрипт единственной страницы компонента. Тоже не трогаем, но обращаем внимание на строку: ,renderTo: 'sendex-panel-home-div' И вспоминаем, что именно такой div у нас указан в шаблоне, который загружается контроллером. А потом смотрим на строку, где объявляется xtype нашей страницы: xtype: 'sendex-panel-home' Именно этот xtype у нас и запускает контроллер после полной загрузки страницы. То есть, вот она связь HTML страницы, сгенерированной PHP, и запуск виджета ExtJS на ней.
  • widgects/home.panel.js — виджет «Панель», который содержит в себе заголовок, описание и табы (вкладки). Его мы немножко будем менять, когда будем добавлять новые вкладки на страницу.
  • widgects/items.grid.js — виджет с таблицой предметов modExtra. Основной рабочий файл, который выводит записи из БД и позволяет редактировать их во всплывающих окошках. В основном с ним мы и работаем. Давайте еще раз: у нас есть раздел в админке, он состоит из одного пункта меню и одной страницы. На странице вызывается панель с вкладками, и на первой вкладке у нас таблица. Окошки, создающие новую запись и меняющие существующую, являются частью этой таблицы.

Сегодня работаем именно в этом объеме, другие вкладки добавим позже.

Готовим таблицу для работы с sxNewsletter Первая вкладка посвящена работе с объектами sxNewsletter, то есть — с подписками.

Нужно указать это в widgets/home.panel.js:

{
    // Имя вкладки
    title: _('sendex_newsletters')
    // Массив с содержимым
    ,items: [
    // Блок HTML с описанием этой вкладки
    {
        html: _('sendex_newsletters_intro')
        ,border: false
        ,bodyCssClass: 'panel-desc'
        ,bodyStyle: 'margin-bottom: 10px'
    }
    // Вызов рабочей таблицы
    ,{
        xtype: 'sendex-grid-newsletters'
        ,preventRender: true
    }
}

Как видите, я просто переименовал кое-что. Самый главный момент здесь, это вызов xtype таблицы xtype: 'sendex-grid-newsletters'.

Как только мы его указали — админка ломается, ибо такого xtype не существует.

Как понять, из-за сего сломалось? Ну так нам ExtJS пишет в логе, что перед ошибкой было

create
Ext.Container.Ext.extend.createComponent
Ext.Container.Ext.extend.lookupComponent

То есть: поиск и создание виджета, после чего ошибка. Мы же помним, что мы ег опереименовали — так что всё логично.

Таким образом, нужно поменять имя и в файле widgects/items.grid.js. Хотя стоп, его сначала нужно переименовать в widgects/newsletters.grid.js.

Сразу нужно указать новый файл для загрузки в контроллере controllers/home.class.php на строке 30:

$this->addJavascript($this->Sendex->config['jsUrl'] . 'mgr/widgets/newsletters.grid.js');

Ну а теперь просто меняем в newsletters.grid.js строку 108 с регистрацией виджета:

Ext.reg('sendex-grid-newsletters',Sendex.grid.Items);

Синхронизируем с MODXCloud и обновляем страницу — ошибки нет.

Кстати говоря, обычно с переименованием через SFTP возникают какие-то ошибки, и часто PhpStorm просто создаёт на сервере новый файл рядом со старым. Это не страшно, просто удаляйте его через админку.

У вас должно получиться всё как на скриншоте выше. Обратите внимание, что у меня не отображается заголовок вкладки. Так и должно быть — я же указал несуществующую запись из лексикона.

Вообще, поддержка лексиконов в компонентах сделана отлично, вам нужно просто указывать ключ из ваших файлов лексикона в виде:

_('ключ')

Нижнее подчеркивание здесь — это функция MODX, которая выведет нужную фразу. Очень элегантное решение, не правда ли?

Поэтому редактируем

/core/components/sendex/lexicon/ru/default.inc.php

$_lang['sendex'] = 'Sendex';
$_lang['sendex_menu_desc'] = 'Управление подписками';

$_lang['sendex_newsletters'] = 'Подписки';
$_lang['sendex_newsletters_intro'] = 'На этой странице вы создаёте и редактируете ваши подписки.';

и /core/components/sendex/lexicon/en/default.inc.php.

$_lang['sendex'] = 'Sendex';
$_lang['sendex_menu_desc'] = 'Newsletters management';

$_lang['sendex_newsletters'] = 'Newsletters';
$_lang['sendex_newsletters_intro'] = 'On this page you create and edit your subscription.';

Напоминаю, что лексиконы Sendex загружает контроллер home.class.php.

После синхронизации языковых файлов с сервером, нужно обязательно почистить кэш сайта, ибо MODX постоянно кэширует лексиконы. Как видите, заодно я еще поправил описание нашего пункта меню.

Ну а теперь в newsletters.grid.js осталось переименовать все встречающиеся Items в Newsletters, а item в newsletter. В результате этого пропадает кнопка создания (меняем ей запись на sendex_btn_create и добавляем это в лексиконы) и получается ошибка

Процессор не найден: mgr/newsletter/getlist

Конечно не найден, мы же переименовали всё только в javascript файлах, а php остались где были. Кстати, вот мой коммит со всеми изменениями на текущий момент — сравнивайте.

Вот картинка с изменёнными файлами:

Теперь нужно переделать процессоры.

Готовим процессоры для работы с sxNewsletter

Первым делом переименовывем /core/components/sendex/processors/mgr/item/ в /core/components/sendex/processors/mgr/newsletter/ и заливаем новую директорию на сервер.

У меня получилось, что старая тоже осталась — поэтому я её удаляю в админке:

Затем меняем классы в файлах процессорах. Просто заменяем SendexItem, получившийся при изначальном переименовании modExtra, на sxNewsletter — наш объект с подписками.

После переименования синхронизируем изменения файлов, обновляем страницу в админке и ошибка пропадает. Более того, можно создавать, изменять и удалять подписки, так как основные поля объекта modExtraItem и sxNewsletter совпадают (name и description).

Затем приводим в порядок остальные записи в лексиконе (меняем и там item на newsletter) и получается все довольно приятно:

Вот и всё, для начала. Мы уже может управлять объектами — у нас есть базовый интерфейс на ExtJS, который работает с процессорами и поддерживает сразу 2 языка: русский и английский.

Вот мой коммит с изменениями.

Вот какие файлы я редактировал:

Заключение

Дальнейшая работа сводится к трём пунктам:

  • Придумали и нарисовали что-то на ExtJS
  • Добавили работу с этим в процессоры
  • Добавили нужные записи в словари

Конечно, нужно будет создавать новые javascript файлы и процессоры, подключать их в контроллерах и вызывать из виджетов, но в целом — вот она, основная база дальнейшей разработки. Выходит несложно, если работать с заготовкой modExtra.

На следующем уроке мы плотнее поработаем с ExtJS и сделаем свой интерфейс для sxNewsletter.

Узнать больше

Support the team building MODX with a monthly donation.

The budget raised through OpenCollective is transparent, including payouts, and any contributor can apply to be paid for their work on MODX.

Backers

  • modmore
  • Jens Wittmann – Gestaltung & Entwicklung
  • Raffy
  • Digital Penguin
  • eydolan
  • deJaya
  • Following Sea
  • Sepia River Studios
  • Fabian Christen
  • Dannevang Digital
  • Anton Tarasov
  • Nick Clark
  • Lefthandmedia
  • Murray Wood
  • YJ
  • Chris Fickling
  • CrewMark
  • Richard

Budget

$292 per month—let's make that $500!

Learn more