Разработка дополнения в MODX Revolution. Часть 2.

Этот урок состоит из серии статей:

Содержание:

В данном уроке расскрывается создание Пользовательской страницы в менеджере для нашего дополнения Doodles, которое мы уже создали в предыдущем уроке. Здесь объясняется создание контроллеров/коннекторов/процессоров, создание Пространства имён, Действия и элементов Меню и работа с ExtJS для создания Пользовательского интерфейса.

Первые шаги при установке

У нас есть наш сниппет и базовая структура каталогов. Теперь нам нужно сделать пару вещей перед началом разработки нашей пользовательской страницы в менеджере. Первая - это Пространства имён.

Пространства имён

Пространства имён в MODX Revolution - это в бункеры разработки в системе. Они загружают основной путь вашей пользовательской страницы менеджера (ПСМ) и сообщают MODX где брать файлы для неё и для файлов Словарей (i18n). Они позволяют вам разрабатывать и запускать ваши Дополнения без надобности изменения файлов ядра MODX или организовывать размещение MODX в Git/SVN.

Давайте создадим наше пространство имён. Нажмём в меню на "Пространство имён" находится в "Система":

Продолжим дальше и нажмём "Создать новый" чуть выше разметки для загрузки окна создания пространства имён. Введите следующие данные в форму:

  • Name - doodles
  • Core Path - /www/doodles/core/components/doodles/
  • Assets Path - /www/doodles/assets/components/doodles/

Объясняю: мы назначаем ключ Пространства имён 'doodles', с помощью которого мы можем ссылаться на наше пространство имён. Во-вторых мы указываем путь к ядру нашего каталога doodles, в котором мы ведём разработку. Он говорит MODX загружать файлы контроллера, которые загружают ПСМ из этого каталога, что нам именно и нужно. Когда кто-то позже будет устанавливать данный компонент, путь его Пространства имён будет иметь следующий вид:

{core_path}components/doodles/

Вот так мы будем устанавливать файлы с помощью Транспортного пакета. В то же время установка его как абсолютного пути позволит нам разрабатывать дополнение вне корневого каталога MODX.

Как обычно и все пути к объектам - Assets Path сообщают MODX место, где находятся наши файлы.

Теперь можно зайти в системные настройки и отредактировать две настройки, которые вы добавили для doodles.core_path и doodles.assets_url и установить их пространство имён в 'doodles' и их Область словарей (Area Lexicon Entry) в 'Doodles'.

Действия и меню

Далее нужно создать наши Действия и меню для ПСМ. Что же такое "Действие" (Action) в MODX? Ну это абстрактное представление страницы менеджера. Каждая страница менеджера содержит Действие в таблице modx_actions, на которую можно сослаться. Это позволяет вам создавать любое количество "Действий", которые могут быть использованы как ПСМ в менеджере.

Загрузите страницу Действий в Система-> Действия. Должно загрузиться 2 дерева:

Вначале мы сфокусируем внимание на левом дереве, которое содержит Действия. Первый уровень нашего дерева - это всё наше Пространство имён, которое выводится в виде компьютерных иконок. Ниже него показываются все Действия для этого Пространства имён. Наше 'doodles' пространство имён выводится там, но оно пусто и всередине нет никаких Действий. Давайте устраним это. Правым кликом на нашей иконке 'doodles' Пространства имён и нажмите "Создать действие".

Это должно загрузить окно, в котором мы хотим ввести эти значения (на самом деле важны лишь Пространство имён и поле Контроллер):

  • Controller - index
  • Namespace - doodles
  • Parent Controller - (выберите "no action")

Давайте разберёмся что значит каждое из полей.

Контроллер (Controller): сообщает MODX где находится файл-контроллер для данного Действия, относительно пути Пространства имён без расширения .php. Наш файл будет находиться в /www/doodles/core/components/doodles/index.class.php. Таким образом минус наш путь к Пространству имён он заканчивается на index.class.php. Отбрасываем .class.php и получаем "index".

Пространство имён (Namespace): Это часть ссылки Действия на Пространство имён. Оно должно автоматически заполняться.

Родительский контроллер (Parent Controller): Для иерархического вывода, Действия могут быть структурированы в форме дерева. Это не затрагивает их поведения и не должно нас волновать, поэтому выбираем Нет действия (No Action).

Отлично, наконец-то мы добрались к Действию. Теперь нужно связать данное Действие к элементу меню, который отобразится в нашем главном меню вверху менеджера. Объекты 'Menu' в MODX позволяют вам полностью преображать (и скрывать) элементы меню в интерфейсе мнеджера, позволяя вам полностью настраивать навигацию для вашей собственной MODX установки.

Мы создадим наш элемент меню для Doodles под элементом меню Компоненты ('Components'), где обычно содержаться компоненты 3ей стороны. Мы можем разместить их где угодно, но соблюдая стандарт разместим именно там. Правый клик на узле дерева Компоненты ('Components') в правом дереве и нажимаем на Создать действие ('Place Action Here'). Загрузиться окно, в которое введём следующие значения:

  • Ключ словаря (Lexicon Key) - doodles
  • Описание (Description) - doodles.desc
  • Действие (Action) - doodles - index
  • Иконка (Icon) -
  • Параметры (Parameters) -
  • Обработчик (Handler) -
  • Разрешения (Permissions) -

Разберёмся с каждым полем:

Ключ словаря (Lexicon Key): Это ключ словаря для элемента меню. Так как MODx позволяет многоязычие менеджера, то есть такая опция загрузки строки Словаря (по поводу этого ранее мы загружали действие doodles:default) для перевода. Мы назначим как doodles и добавим строку Словаря чуть позже.

Описание (Description): Как и первое поле это позволяет нам сделать прямое описание или перевод ключа словаря. Мы назначим ключ словаря, так как нам нужно, чтобы это переводилось.

Действие (Action) - Сообщает MODX какое действие нужно загрузить при нажатии на элемент меню.

Иконка (Icon) - В данный момент не используется в менеджере, позволяет элементам меню иметь иконку. Пропустим это.

Параметры (Parameters) - Это позволяет вам прикреплять GET параметры к элементу меню при его нажатии. Это нам тоже не нужно, поэтому пропускаем.

Обработчик (Handler) - Это позволяет вам запускать JavaScript вместо загрузки страницы при запуске элемента меню. Полезно для элементов меню, которые не загружают страницу, но делают такие вещи как "Очистка кеша". Тоже пропускаем.

Разрешения (Permissions) - Здесь можно указать MODX разрешения, которые MODX проверит у пользователя при загрузке меню. Если у пользователя нет этого Разрешения, то этот элемент меню не загрузится. Нам не нужно ограничивать наши ПСМ, поэтому оставляем это поле пустым.

Отлично! Теперь у нас есть и Действие и Меню. Давайте двигаться дальше и создадим наш раздел Словаря по-умолчанию.

Словари

Словари MODX Revolution позволяет вам создавать переводы в ваших Дополнениях на любой язык. Нужно, чтобы наше Дополнение было i18n-совместимым, поэтому будем использовать данную функцию. Каждая строка ввода будет иметь собственный ключ, такой как, например, 'doodles.desc' показанный выше. Обычно ключём для Словаря служит префикс названия Пространства имён с точкой. Это предотвращает путаницу с другими дополнениями.

Строки словарей объединены в файлы называемые Разделы словаря ('Lexicon Topics'). Это значит, что ваши строки могут быть изолированы в одной специфической области (схоже с тем как это делается в каталоге core/lexicon/) и это делается для того, чтобы вы не загружали все строки для вашего Дополнения, когда вам нужно загрузить лишь парочку строк.

Если вам нужно использовать ваш словарь в Сниппете, то вы можете использовать метод $modx->lexicon->load('doodles:default'). Он загрузит 'default' раздел из Пространства имён 'doodles'. Для ПСМ это немного отличается: вы загружаете его в класс Контроллера через метод getLanguageTopics. Этот метод выдаёт массив, который определит Раздел словаря для загрузки, чтобы мы могли иметь легкий доступ к нему.

Но мы ещё не создали этот файл Раздела словаря, поэтому сделаем это сейчас. Словари в файловой системе структурирован следующим образом:

{namespace_path}/lexicon/{language}/{topic}.inc.php

Давайте создадим тут наш файл: /www/doodles/core/components/doodles/lexicon/en/default.inc.php и вставим туда следующий код:

Тут много строк! Мы все их используем, не волнуйтесь. Обратите внимание, что всё что мы делаем - это заполняем PHP массив называемый $_lang. Вот и всё, остальное сделает MODX.

Вы также можете заметить наши строки 'doodles' и 'doodles.desc', на которые мы ссылались чуть ранее.

Отлично! Теперь, когда мы всё установили, можно начинать разработку нашего ПСМ.

Установка контроллеров с помощью MODExt

ПСМы в MODX генерируются с помощью ExtJS, JavaScript фреймворка от Sencha, который позволяет быструю и мощную разработку пользовательских интерфейсов. MODX добавляет функциональность к некоторым ExtJS инструментам (и далее называет их MODExt). Мы будем использовать эти инструменты в наших ПСМ. Этот урок не имеет целью обучить вас ExtJS, так как есть множество уроков в сети на сайте главный сайт Sencha. Но мы разберёмся в том как использовать его для создания сетки которая будет способна выполнять CRUD действия.

Нам нужно будет установить вначале некоторые базовые контроллеры, прежде чем начнём разработку.

Базовый контроллер

Давайте создадим наш базовый контроллер в: /www/doodles/core/components/doodles/index.class.php. И вставим туда следующий код:

Давайте чуть объясню. Здесь мы создали абстрактный Класс контроллера (DoodlesManagerController) для нашего Дополнения, который расширяет modExtraManagerController, специальный класс для разработки Дополнений. MODX 2.2 запрашивает маршрутизацию через классы Контроллера, которые являются мощными. Но в наших Контроллерах для нашего Дополнения, мы хотим прикреплять некоторые CSS/JS файлы и также давать нашим Контроллерам доступ к объекту Doodles класса.

Это мы сделаем в методе initialize(), который вызывается при загрузке контроллера. Во-вторых мы определим метод getLanguageTopics(), чтобы сказать MODX загрузить наш файл словаря в менеджер. Наконец, мы определим метод checkPermissions(), который если не возвращает true, то запретить доступ к этой странице контроллера.

Вот такой наш абстрактный класс. Нам нужно определить действительный класс для использования, поэтому мы создали "IndexManagerController", так как наше действие "index" (как вы помните мы вставили это в диалоге Действия чуть ранее?), то MODX будет искать (ИмяДействия)ManagerController: поэтому и IndexManagerController. Далее мы сообщаем MODX через статический метод "getDefaultController()", что мы вообщето хотим чтобы наш домашний контроллер будет "home". Скоро мы и его сделаем.

Обратите внимание, что здесь мы также загружаем общий JS файл, mgr/doodles.js, в наш JS каталог. Далее он запускает JS метод (при загрузке ExtJS), который загружает переменные конфигурации для нашей $doodles->config в 'Doodles.config' JS объекте (который мы будем использовать для указания путей. В нашем doodles.js файле (который находиться в www/doodles/assets/components/doodles/js/mgr/doodles.js), у нас есть следующее:

Мы загружаем объект Doodles, который расширяет Ext.Component класс. Что даёт нам отличное JavaScript пространство имён 'Doodles'. Мы закончили с заголовком. Давайте начнём разработку нашего домашнего контроллера.

ПСМ Doodles страница

Создайте файл в /www/doodles/core/components/doodles/controllers/home.class.php (помните, что в нашем index.class.php базовом контроллере, наш контроллер по-умолчанию - "home"?) и вставьте туда этот код:

Далее создайте ваш файл шаблона в /www/doodles/core/components/doodles/templates/home.tpl и вставьте туда этот код:

Отлично! Мы тут проделали несколько вещей. Мы определили метод process(), который необходим для каждого контроллера менеджера. Мы не будем использовать его для чего-либо, поэтому оставим его пустым.

Далее мы сообщаем MODX, что мы хотим чтобы название страницы определялось через метод getPageTitle(). Мы установим его через нашу переведённую верстю "Doodles".

Далее мы определяем loadCustomCssJs() метод, который позволяет нам регистрировать все специфические CSS/JS для определённой страницы. Мы загружем несколько "виджетов" и далее загружаем "секцию". Это произвольные названия, но мы используем так же как и MODX использует их в MODExt для рендера интерфейса менеджера. Обычно, виджет - это что-то наподобие сетки объектов (таких как Doodles) или дерево, или какая-либо панель. Разнесение их в отдельных файлах, позволяет их использование на различных страницах без дублирования кода. Секция - это кусок JS, который загружает виджеты на страницу. Включение виджета не загрузит его и не отрендерит - секция рендерит его.

Мы будем загружать вначале doodles.grid.js, это виджет, который выводит сетку из Doodles. Далее, мы загрузим 'home' панель - нашу главную домашную панель, в которой разместится наша сетка. И в конце, мы загрузим 'index' секцию, которая отрендерит пользовательский интерфейс.

Пока не буду комментировать сетку, но вернёмся к ней позже обязательно.

Мы могли бы поместить код из этих JS файлов в один файл, что ускоряло бы загрузку страницы. Для илюстрирования, мы разместим их в 3 разных файлов, для того, чтобы урок был понятнее. Можете делать всё что угодно при разработке вашей ПСМ.

Наконец, мы сообщаем MODX где найти файл Шаблона для этого Контроллера. Это шаблон Smarty, который будет использовать MODX при рендере контроллера.

JS файл секции

Давайте вначале создадим index.js файл в /www/doodles/assets/components/doodles/js/mgr/sections/index.js:

Отлично, двайте объясню, что происходит. Во-первых, мы сообщаем ExtJS, что когда загружена страница, нужно загрузить комопнент (или виджет/объект/панель) с 'xtype' doodles-page-home. Как работает ExtJS - он позволяет вам определить компоненты с помощью 'xtype', это что-то наподобие уникального идентификатора для панели, дерева и др. Думайте об этом как ИД для класса. MODx.load просто instantiates этот объект.

Ниже мы определяем объект 'doodles-page-home' и назначаем его как расширение MODx.Component. MODx.Component - это абстрактный JS класс, который рендерит страницу в менеджере интерфейса MODX. Он обеспечивает несколько вспомогательных методов, которые делают генерацию MODX страниц более плавной. Всё что нам нужно - это передать в него компоненты, которые мы хотим загрузить; в нашем случае, это компонент 'doodles-panel-home' (который мы ещё не определили, это будет сделано в файле home.panel.js упомянутом ранее). Мы также хотим, чтобы он отрендерился в DOM ID - 'doodles-panel-home-div', который, как вы возможно помните был тем контейнером "div", который мы возвращали ранее в нашем контроллере mgr/index.php.

Наконец, мы регистрируем эту страницу в тип 'doodles-page-home' xtype, который мы упомянули чуть ранее в вызове MODx.load.

Отлично! Возвращаемся к панели.

JS файл панели

У нас есть наша страница, но теперь мы хотим загрузить в ней панель. Давайте создадим файл в w/doodles/assets/components/doodles/js/mgr/widgets/home.panel.js и вставим туда код:

Поэтому, во-первых, внизу, обратите внимание как мы регистрируем эту панель 'doodles-panel-home', которую мы упомянули в нашей секции. Также обратите внимание, что эта панель расширяет MODx.Panel, которая в свою очередь расширяет Ext.Panel. Почему бы не взять просто и расширить Ext.Panel? Ну расширение MODx.Panel сделает то же самое и добавит CSS класс к панели, чтобы она отобразилась со стилями MODX менеджера.

Мы собираемся назначить этой панели базовый класс baseCls 'modx-formpanel', который позволит нашей верхней части иметь прозрачный бекграунд. А также класс 'container', который будет создавать промежутки. Далее уберём границы.

Далее, мы определим элементы на панели. Добавим заголовок:

Он просто вставляет некоторый HTML на верх панели с классом 'modx-page-header' и размещает там h2 тег. Обратите внимание на на метод _(). Это способ MODX делать i18n (Словари) в JS менеджера. Это говорит MODX перевести этот ключ. Если вы помните, мы определили строку 'doodles.management' ранее как: "Doodles Management". Поэтому это отрендерит перевод этого ключа в h2 тег.

Далее мы добавим TabPanel. Мы могли просто загрузить панель прямо без вкладок, но что будем делать тогда если далее нам нужно будет добавить ещё одну вкладку? Давайте определим их:

Обратите внимание - мы загрузили нашу панель вкладки с помощью xtype 'modx-tabs'. Это загружает особенную вкладку-панель, которая имеет MODX-специфические опции конфигурации. Далее мы указываем некоторые особенности отображения и далее добавляем саму вкладку:

Отлично, это загрузит нашу первую вкладку с названием вкладки 'Doodles'. Далее мы разместим кое-что в этой вкладке (которая Ext.Panel, кстати). Вначале мы разместим маленькое описание с помощью строки словаря "doodles.management_desc".

Давайте загрузим страницу и взглянём на неё. Вам будет нунжно обновить страницу менеджера для получения компонента Doodles загруженного в Меню компонентов.

Получилось! У нас появилась панель в MODX-стиле. К сожалению, она совсем бесполезна. Нам нужно добавить сетку для управления Doodles. Давайте продолжим и сделаем это.

Сетка Doodles

Во-первых продолжим и расскоментируем эту строку в вашем контроллере home.class.php controller:

Это говорит MODX загрузить файл разметки виджета, который мы создадим сейчас в /www/doodles/assets/components/doodles/js/mgr/widgets/doodles.grid.js:

Давайте начнём с конфигурационных параметров, установленных нами.

  • id: назначаем этой панели ИД 'doodles-grid-doodles'.
  • url: назначаем это к файлу коннектору в Doodles.config.connectorUrl.
  • baseParams: устанаваливаем его базовые параметры для отправки при получении записей для сетки через ЗАПРОС с ключом 'action' и значением 'mgr/doodle/getList'.
  • fields: устанавливаем поля, которые получаем из AJAX запроса для заполнения сетки. Это поля нашего компонента Doodle.
  • paging: нужна пагинация для нашей сетки, и MODExt обеспечивает нам её простой установкой 'paging: true'.
  • remoteSort: устанавливаем это значение в true и Ext позволит колонкам нашей сетки сортироваться.
  • anchor: нужно, чтобы сетка растягивалась по ширине панели поэтому выставляем в 97% (3% идёт на отступ).
  • autoExpandColumn: нужно растянуть колонку 'name' чтобы она автоматически была наибольшей колонкой на сетке.

Далее определим некоторые колонки нашей сетке. Мы также зададим возможность редактирования 'name' и 'description' назначив редактор к каждой колонке. Обратите внимание, как параметр 'dataIndex' соответствует имени поля Doodles, которое мы хотим отобразить.

Наконец добавим сетку к нашей панели. Уберём комментирующие теги в файле the home.panel.js на строках 22 и 26 :

Это загрузит нашу сетку прямо после сообщения выводимого ранее в нашей панели с классным отступом. Атрибут preventRender сообщает Ext не рендерить сетку пока не загрузится вся панель.

Если вы попытаетесь теперь загрузить страницу, то сетка появится, но не загрузятся какие-либо данные - у нас ещё нет нашего коннектора и сетке неоткуда получить свои данные. Давайте сделаем следующее:

Сцепление с помощью коннекторов

Что такое Коннектор в MODX? Коннектор - это файл, который соединяется со слоем модели в MODX или Процессорами. Процессоры - это файлы слоя формы, которые запускают запросы к БД и другие вещи, которые модифицируют модель и/или базу данных.

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

Вернёмся к нашему дополнению. Нашей ExtJS сетке нужно загружать свои данные для строк через AJAX с помощью нашего коннектора. Но нам нужно вначале создать этот коннектор. Давайте создадим его в /www/doodles/assets/components/doodles/connector.php:

Ну вот и всё. Вначале мы загружаем config.core.php файл. Далее продолжим и добавим его в наше рабочее окружение в стандартной MODX установке это уже существует.

Создадим файл в /www/doodles/config.core.php и вставим туда код:

Очевидно, что вам нужно поменять эти значения на ваши пути MODX установки. Если Вы используете используете SVN или Git для вашего Дополнения, то вы захотите добавить эти пути в файл игнорирования (например, .gitignore), чтобы они не появились в вашем репозитории.

Далее в нашем коннекторе мы загрузим конфигурационный файл и файл connectors/index.php.

Далее мы загрузим наш Doodles класс (с нашими системными настройками!), который добавим нашу пользовательскую xPDO Doodles модель в MODX и затем загрузит наш doodles раздел словарей. Наконец, мы "обработаем" запрос используя наши пути к пользовательским процессорам, которые мы определили в нашем Doodles классе и сообщим MODX загрузить процессоры.

Этот файл не делает сам по себе ничего при доступе к нему. Прямая его загрузка даст вам следующее:

{"success":false,"message":"Access denied.","total":0,"data":[],"object":[]}

Есть несколько причин сделать это. Одна - это то, что коннекторы заблокированы и не дадут к себе доступ без сессии MODX менеджера. Во-вторых все запросы к коннекторам ДОЛЖНЫ передавать уникальный для вашего сайта ключ авторизации, который предотвращает CRSF атаки. Он может быть передан в заголовках HTTP как 'modAuth' или в переменной запроса как HTTP_MODAUTH. Значение будет $modx->siteId, которое задаётся при новой установке и загружается при загрузке MODX.

Никогда не копируйте или делитесь с кем-либо вашим $modx->siteId или HTTP_MODAUTH ключом. Это обезопасит ваш сайт.

Отлично то, что вам не нужно об этом волноваться: MODX уже позаботился об этом в MODExt - все HTTP запросы сделанные ExtJS в MODX передают эту переменную через свои HTTP заголовки.

Второй причиной почему прямая загрузка файла коннектора напряму не сработает - это потому что мы не указали корневой путь - помните baseParams на сетке? Помните как мы устанавливали параметр 'action' в нём в 'mgr/doodle/getList'? Это и есть наш корневой путь. Он сообщает коннектору какой нужно загрузить файл:

/www/doodles/core/components/doodles/processors/mgr/doodle/getlist.class.php

Давайте продолжим и заставим этот файл передавать нашей сетке данные:

Отлично. Несколько ещё моментов: вы обратили внимание, что мы снова в классе - MODX 2.2 имеет новые Процессорные классы, включая поддержку класса с названием modObjectGetListProcessor, который мы тут расширяем. Этот класс автоматически делает всю базовую логику для управления действиями CRUD, такими как это. Всё что нам нужно - это определить некоторые переменные класса - такие как $classKey, $objectType и остальные. Давайте разберём их:

  • $classKey - сообщает Процессору какой нужно взять MODX Класс. Нам нужно взять наши Doodle объекты.
  • $languageTopics - массив языковых разделов для загрузки для этого процессора.
  • $defaultSortField - поле сортировки по-умолчанию при отборе данных.
  • $defaultSortDirection - направление сортировки по-умолчанию при отборе данных.
  • $objectType - это часто используется для определения какие строки лексикона об ошибке загружать при отборе данных. Так как в нашем файле словаря находяться все строки в виде $_lang['doodles.doodle_blahblah'] или схожем, то мы определим префикс как "doodles.doodle". MODX далее будет прикреплять префикс к стандартным сообщениям об ошибке.

Класс поддержки разберётся со всем остальным, поэтому нам не нужно по этому поводу волноваться. Всё, что нам нужно - это "возвратить" имя класса обработчика, чтобы MODX знал где его искать.

Ну вот и всё. Давайте загрузим нашу таблицу:

Отлично! У нас теперь работающая таблица. Давайте добавим кое-какой функционал, сейчас она выводит просто список Дудлов.

Добавление поиска

Добавьте кусок этого кода к вашей разметке панели в файл widgets/doodles.grid.js, прямо после колонок: определение на строке 29:

Сейчас мы добавили текстовое поле к верхней строке нашей сетке и дали значение 'emptyText', что значит: когда пусто выдавать этот текст. Также мы дали ей DOM ID -'doodles-search-filter' и запускать метод 'this.search', когда оно меняется. Также код в 'render' лисенере значит запустить событие изменения, когда кто-то нажимает ENTER при редактировании поля.

Давайте определим метод 'this.search' - так как наша панель - это OOP, что значит, что this.search может быть определён в нашем объекте. Чтобы сделать это, найдите этот код (строка 52):

Ext.extend(Doodles.grid.Doodles,MODx.grid.Grid);

И замените его следующим:

Здесь мы расширяем класс MODx.grid.Grid и далее добавляем другой метод, с названием 'search'. В этом методе, мы получаем сетку "Store", это то место, где храняться данные для таблицы и что определяет откуда приходят данные. Далее мы добавляем параметр 'query' к нашему baseParams (упоминали о нём ранее), меняя текущую страницу сетки назад к 1 и обновляя её.

Это передаст REQUEST параметр 'query' нашему getList процессору в файл getlist.class.php. Так как мы ничего не делаем для обработки этого, давайте откроем его. Добавим этот метод после 7 строки:

Класс поддержки modObjectGetListProcessor позволяет вам расширять мето prepareQueryBeforeCount() для модификации объекта xPDOQuery перед тем, как он передасться методу getCount(). Всё что нам нужно сделать - это возвратить наш модифицированный объект. Мы собираемся расширить его здесь, чтобы добавить функцию поиска к нашей сетке через "query" параметр. Обратите внимание, что мы можем получить любой параметр через метод ->getProperty().

Теперь загрузите вашу сетку и вы получите:

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

Добавление окна "Обновить"

Во-первых, MODX сетка обычно имеет контекст меню, когда вы нажимаете на них. У нашей такого нет, это потому что мы ещё её не определили. Давайте определим. Добавим метод 'getMenu' к нашему определению Doodles.grid.Grid прямо ниже нашего поиска: метод, который мы только добавили строка 48:

MODX ищет метод getMenu на сетке, которая расширяет его и если находит, то запускает. Он добавляет далее любой элемент меню, который вы возвращаете. Здесь я добавил 2 элемента меню для нашего контекст меню, один запускается методом this.updateDoodle и другой запускается методом this.removeDoodle. Мы вернёмся к методу removeDoodle чуть позже. Сейчас давайте добавим JS метод под вызовом getMenu строка 58 и назовём его updateDoodle:

Этот код проверяет переменную класса с именем 'updateDoodleWindow'. Если он не находит её, то создаёт её. Это предотвращает от необходимости для ExtJS создавать новое окно каждый раз(это быстрее и лучше предотвращает DOM ID конфликты). Также он передаёт пару значений:

  • xtype - наш уникальный xtype для окна, в данный момент - 'doodles-window-doodle-update'. Мы к этому ещё вернёмся.
  • record - MODx.Window объекты будут автоматически заполнять свои поля всем что передаётся в конфигурационном параметре 'record'. Также, MODx.grid.Grid объекты всегда хранят значения текущего ряда в объекте 'this.menu.record'. Поэтому мы просто передадим его в наше Окно.
  • listeners - исполняются при различных событиях в окне. В данный момент мы хотим просто обновить сетку (через 'this.refresh' метод для MODx.grid.Grid) при успешной выдаче окна; что значит, что когда окно формы возвращает 'success' - ответ об успехе.

После осздания окна мы запустим метод show() для его показа. 'e.target' просто сообщает ему, что нужно анимировать открытие в точке, где находиться курсор. Если у нас уже есть объект окно, перед тем как мы вызываем setValues, что устанавливает значения формы Окна в передаваемые значения (схоже с записью param). Это позволяет нам повторно использовать окна.

Давайте теперь определим окно с этим кодом в конце нашего файла:

Схожее с тем, что вы видели в сетках, за исключением того, что сейчас у нас есть 'fields' как поля формы Окна. Мы задали несколько полей для редактирования и так как это форма обновления "Update", то нам нужно обеспечить ИД Doodle, передаваемый в скрытом поле.

MODx.Window обворачивает Ext.Window, но задаёт форму внутри, что автоматически попытает и соединится с url: param с baseParams: параметры, а также значения полей. Оно также автоматически задаёт OK/Cancel кнопки. После правого клика на записи сетки ваше окно будет выглядеть так:

Отлично! Теперь у нас есть окно обновления. Как вы уже должно быть заметили в наших baseParams, мы ищем теперь процессор 'mgr/doodle/update'. Давайте создадим файл: /www/doodles/core/components/doodles/processors/mgr/doodle/update.class.php:

Снова мы собираемся создать наш класс-процессор расширяя существующий класс-процессор, который MODX уже содержит. Он автоматически проделает всю грязную работу по сохранению объекта. Всё, что нам нужно это определить classKey и парочку других параметров. Он разберётся с сохранением и автоматически ответит. Теперь у нас есть работающая форма обновления!

Добавления опции Удалить в контекстном меню

Давайте закончим недостающую часть нашего UI. У нас уже есть в контекст меню многое, осталось только добавить метод JS и запустить процессор. После этого наш метод updateDoodle в нашей JS сетке, добавьте это на строке 70:

MODx.msg.confirm всплывёт в диалоге и при подтверждении запустит процессор через коннектор. Давайте взгянем на каждый параметр:

  • title - это название диалога подтверждения.
  • text - содержимое диалога. Обычно тут спрашивается действительно ли мы хотим удалить Doodle.
  • url - URL к коннектору.
  • params - любой REQUEST параметр, отсылаемый к процессору. Мы посылаем путь к процессору и ИД удаляемого Doodle.
  • listeners - схоже с нашими лисенерами в обновлении, при успехе обновляет сетку.

Давайте создадим наш процессор для удаления www/doodles/core/components/doodles/processors/mgr/doodle/remove.class.php:

Очень схоже с процессором для обновления, кроме того, что в этот раз мы расширяем modObjectRemoveProcessor, который отвечает за удаление Doodle из БД. Вот и всё! Мы теперь можем удалять Doodles.

Форма создания

Итак у нас есть R, U и D в нашем CRUD интерфейсе. Давайте создадим C! Поработаем над формой создания. Добавим кнопку к верхнему тулбару сетки для загрузки окна создания. Добавим это к тулбару: свойство конфигурации сетки в doodles.grid.js, сразу после текстового поля поиска на строке 48. Будьте осторожны при вставке его после закрывающей фигурной скобки текстового поля поиска и закрывающей квадратной скобкой тулбара:

MODExt позволяет передавать JSON объекты в хендлер: метод тулбара. Он в свою очередь загружает Окно с xtype 'doodles-window-doodle-create', проверяет на пустоту значений при загрузке запускает this.success при успехе отправки формы окна (если коротко о том, что будет происходить). Это как раз то, что нам нужно, давайте определим окно в конце нашего файла:

Это очень схоже с нашим окном Обновить, кроме того, что это не имеет ID поля и передаёт 'create' как процессор. Итак процессор будет у нас в: /www/doodles/core/components/doodles/processors/mgr/doodle/create.class.php:

Как и в обновить и удалить методах, снова, кроме того, что мы не берём объект, но создаём его. Мы расширяем поддерживающий класс modObjectCreateProcessor.

Также у нас есть форма валидации - проверим пустое ли имя и если да, то возвращаем пользовательское сообщение об ошибке по именно этому полю. Если оно не пустое, тогда проверяем нет ли еще Doodles с этим же именем. Обратите внимание, что мы расширили метод beforeSave() для этих действий и далее возвратили родительский класс запускающий этот же метод. Далее всередине его мы сделали две вещи:

  1. Проверили имя на пустоту и если да, то добавляем сообщение об ошибке поля в поле "name"
  2. В ином случае смотрим, существует ли уже Doodle (используя вспомогательный метод doesAlreadyExist, который проверяет массив), в этом случае возвращает ошибку поля в поле "name"

Встроенная валидация полей. Теперь у нас есть полностью работающая форма!

Добавление встроенного редактирования

MODExt также имеет автоматическую встроенную возможность редактирования. Просто добавьте это к вашему конфигобъекту Doodles.grid.Grid сразу после свойства 'autoExpandColumn':

Это сообщает сетке включить строчное редактирование и сохранение, а также отправляет любые сохранения в процессор mgr/doodle/updateFromGrid. Давайте создадим это в: /www/doodles/core/components/doodles/processors/mgr/doodle/updatefromgrid.class.php:

Обратите внимание как мы сейчас расширили наш процессор-класс Update (после включения его) и метода initialize(), который парсит наше "data" свойство из JSON (который посылается нашей сеткой с обновлённой записью) и устанавливает это как свойства процессора. Далее процессор Update делает всё остальное. Просто правда?

Итоги

Мы построили отличный CRUD пользовательский интерфейс с созданием, обновлением, удалением, поиском, пагинацией и сортировкой. Всё легко и просто.

Далее, в 3 части, мы будем исследовать создание Транспортного пакета для нашего Doodles Дополнения, чтобы мы могли распростанить его на modxcms.com и через Управление пакетами в MODX Revo.

Оригинал статьи "Developing an Extra in MODX Revolution, Part II"