Собираем и устанавливаем первую версию пакета

На прошлом занятии мы определились с примерным функционалом, написали схему таблиц и сгенерировали модель xPDO для работы с БД MySql.

А сегодня нам нужно собрать и установить первую версию пакета и разобраться, как работают Custom Manager Pages (CMP).

Учитывая, что мы используем заготовку modExtra, и уже разобрали, как она работает - сборка пакета заключается в выполнении скрипта build.transport.php на сервере.

Если с конфиге build.config.php выставлена константа PKG_AUTO_INSTALL, то компонент будет сразу установлен на сайт.

Итак, я запускаю http://c2263.paas2.ams.modxcloud.com/Sendex/\_build/build.transport.php и в конфиге у меня включена автоустановка, поэтому сразу после сборки пакета им уже можно пользоваться.

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

Давайте теперь разберем, как же работает CMP - то есть, наш новый раздел админки Sendex.

Меню

Все меню MODX состоят из двух частей: собственно пункт меню и действие, которое он вызывает. Как и всё в Revolution, меню и действие - тоже объекты, и мы устанавливаем их в файле transport.menu.php.

Видите, там в массиве с пунктами меню (у нас он один) modMenu, есть и ключ action - вот это и есть параметры для создаваемого modAction.

Если мы захотим туда добавить еще одни пункт, то будет примерно так:


$tmp = array(
    'sendex' => array(
        'description' => 'sendex_menu_desc',
        'action' => array(
            'controller' => 'index',
        ),
    ),
    'another_menu' => array(
        'description' => 'Мое описание',
        'action' => array(
            'controller' => 'а здесь файл-контроллер',
        ),
    ),

);

Еще мы можем указать, в каком родительском меню будет находиться наш пункт - это параметр parent, и в нашем случае он стандартный - components. А вот у miniShop2, который изначально планировался под расширения, меню находится не в components, корне - вот, посмотрите на его transport.menu.php. Первый пункт там имеет parent = '', а следующие уже parent = 'minishop2'.

Для таких случаев нужно еще использовать параметр handler - это javascript функция, которая будет вызвана при клике на пункт меню. Для основного пункта меню MS2, который является просто контейнером подменю, это return false; - то есть, не делать ничего при клике.

Но у нас случай простой, можно сказать классический - один CMP и один пункт меню, который лежит в components.

Как правило (не не обязательно), modMenu связан с modAction - его цель состоит в запуске определённого контроллера. Поэтому с массиве с action мы указываем пункт controller.

Настройка для разработки

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

Напоминаю, что весь наш проект находится в директории Sendex в корне сайта. А только что установленный пакет распаковался в /core и /assets и теперь, если мы что-то меняем - то это синхронизируется с директорией в корне, а на установленные файлы никак не влияет.

И тут у нас 2 варианта: после каждого изменения собирать и устанавливать пакет, или научить MODX загружать скрипты из директории /Sendex.

Конечно, второй вариант предпочтительнее, поэтому идём в СистемаПространства имён и делаем так: Это позволит MODX обращаться за исходниками в нашу директорию. А теперь нужно создать еще системные настройки sendex_core_path и sendex_assets_url (а демонстрационную настройку sendex_some_setting можно удалить): -

sendex_assets_path необязательна, но тоже может пригодиться. Эти настройки нужны нам, чтобы знать, где искать наши файлы.

В принципе, можно не создавать их, а каждый раз доставать modNamespace, но это не очень удобно.

С этого момента мы можем получать рабочие директории проекта вот так:


$corePath = $this->modx->getOption('sendex_core_path', $config, $this->modx->getOption('core_path') . 'components/sendex/');
$assetsUrl = $this->modx->getOption('sendex_assets_url', $config, $this->modx->getOption('assets_url') . 'components/sendex/');

Ну и последний штрих: нужно добавить

ini_set('display_errors', 1);
ini_set('error_reporting', -1);

в системные файлы MODX: /index.php и /manager/index.php - они нужны нам для того, чтобы MODXCloud не прятал от нас ошибки во время разработки.

Забегая немного вперед, кажу еще что нужно подредактировать /assets/components/sendex/connector.php, потому что он загружает MODX при запросах из админки, и должен уметь работать и при обычном расположении файлов, и при разработке в директории Sendex. Лично я и здесь добавляю вывод ошибок, чтобы видеть ругань при ajax запросах из админки. В итоге у меня получился вот такой коннектор, советую скопипастить.

Контроллеры CMP

Итак, при клике на пункт меню, MODX смотрит, с каким действием тот связан и на какой контроллер ссылается, после чего вызывает этот файл.

Контроллер - это специальный php файл, лежащий в директории core компонента, и наследующий modManagerController. Указывается он просто по имени: если версия MODX У нас контроллер лежит в /core/components/sendex/index.class.php, поэтому в modAction указан index. Учитывая наши настройки для разработки, первым делом меняем загрузку класса Sendex и приводим файл вот к такому виду. Теперь нам не нужно каждый раз собирать пакет, и все изменения сразу будут видны.

Ну а сейчас внимательно смотрим на файл и пытаемся въехать в логику. 1. MODX нужен контроллер index, и в нём он ищет для запуска IndexManagerController - это делается автоматически 2. IndexManagerController наследует абстрактный класс SendexMainController со всеми его методами 3. SendexMainController наследует modExtraManagerController со всеми его методами 4. modExtraManagerController является общим классом всех CMP и содержит основную логику работы. Он запускает свой метод initialize() 5. Этот метод переопределён в дочернем классе SendexMainController, поэтому запускается оттуда. 6. Мы уже смотрим наши системные настройки и подгуржаем класс Sendex из директории, указанной в системных настройках. 7. Создаётся новый экземпляр класса Sendex, при этом в PHP 5 вызывается его метод __construct() - и у нас он задаёт переменную Sendex::config, в которую забивает массив с настройками и путями к файлам. 8. Пути к файлам определяются точно так же, с помощью системных настроек. А значит, мы грузим их из директории /Sendex/... 9. В этот момент мы уже можем обращаться к любым методам и свойствам класса Sendex, включая $sendex->config 10. Где-то в глубинах modExtraManagerController уже был добавлен класс modX, и мы можем к нему обращаться через $this->modx 11. Ну а теперь мы комбинируем конфиг Sendex и методы modX для подключения нужных нам скриптов и стилей их директорий компонента 12. После того, как мы подключили всё, что нам нужно, передааём дальнейшую логику родительскуму классу - пусть делает, что хочет. 13. А он хочет узнать, какой дальше загрузить контроллер и класс IndexManagerController говорит - home 14. Этот класс уже будет загружен из директории /Sendex/core/components/sendex/controllers/home.class.php

Все это вам знать не обязательно! Такая логика используется в 90% всех новых дополнений, и сводится она к тому, чтобы вызвать основной контроллер, тот загрузил основные файлы компонента и передал управление дочернему контроллеру. А тот уже загрузит всё нужное для конкретной страницы компонента.

Обычно у компонента используется одна страница, поэтому все эти сложности можно пропустить мимо ушей. По большому счету, вам вообще больше не понадобится залазить в index.class.php, работать будем только с controllers/home.class.php.

Честно говоря, я и сам не до конца понимаю эту цепочку контроллеров и кто кого загружает, поэтому делаю просто по отлаженной схеме.

Еще одно замечание: у меня в modExtra скрипты и стили загружаются по старинке, методами:


$this->modx->regClientCSS()
$this->modx->regClientStartupScript()
$this->modx->regClientScript()
$this->modx->regClientStartupHTMLBlock()

Если вы хотите, чтобы ваш компонент дружил с AjaxManager - их нужно заменить на


$this->addCss()
$this->addJavascript()
$this->addLastJavascript()
$this->addHtml()

При этом нужно перенести инициализацию страницы из /assets/components/sendex/js/mgr/sections/home.js в home.class.php, иначе при открытии страницы будет ошибка.

Лично я всё это сделал, поэтому просто сверяем и копипастим мои файлы: index.class.php, home.class.php и home.js.

Если вы всё сделали правильно, можно на всякий случай синхронизировать проект, почистить везде кэши и зайти на страницу Sendex в админке: Это страница от modExtra, она вызывает его контроллеры, с его объектами (которые мы удалили), поэтому в логе MODX должны появиться ошибки: Это нормально, они пропадут, когды мы перепишем процессоры.

Можно также и проверить, сраюатывают ли изменения при синхронизации проекта с сервером? Пишем в index.class.php сразу после

echo 'Hello world';die;

Сохраняем и обновляем страницу в админке: Если вы видите то же, что и я - всё хорошо.

Кстати, при последующей сборке и установке пакета наш namespace будет перезаписан на стандартный, поэтому я внес пару измений в установщик. Видите, как просто работать с установщиком? Советую сделать так же.

Основные методы контроллеров

Нужно еще немного рассказать о методах контроллера home.class.php, который будет у нас основным рабочим. getPageTitleВывод текста для тега title страницы CMP. Сейчас там выводится sendex из лексикона, поэтому мы видим его в заголовке:

getTemplateFileЭтот метод отдаёт html шаблон страницы, который будет распарсен Smarty. Учитывая, что вся админка сделана на ExtJS, на файл-шаблон /core/components/sendex/elements/templates/home.tpl выглядит так:

<div id="sendex-panel-home-div"></div>

Можете сразу про него забыть, он просто выводит тег, который будет использован для отрисовки компонента ExtJs.

getLanguageTopicsЭтот метод возвращает массив словарей, которые будут использованы в работе компонента

checkPermissionsПроверять или нет права на доступ к странице. Мы можем указать их в настройке меню: чтобы закрыть страницу от кого-то. Например, можно указать save_document, чтобы пускать только юзеро с правом редактирования документов.

loadCustomCssJsОсновной метод контроллера, именно он загружает все нужные скрипты и стили для работы страницы. В него мы еще будем добавлять всякое.

Заключение

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

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

Посмотреть текущий смотрите на GitHub, в истории изменений файлов.

← Предыдущая заметка
Продумываем логику работы, определяем схему и модель БД
Следующая заметка →
Пишем интерфейс: виджеты ExtJS и процессоры
Комментарии (28)
ilyautkinИлья Уткин
16.11.2013 10:42

А может, один из уроков посвятить тому, как откатить некоторые изменения, если делал-делал и вдруг все сломал?

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

alex.vakhitovAlex Vakhitov
16.11.2013 10:58

Я делаю ветку в git и бекап бд, как в голову что-то взбредет.

bezumkinВасилий Наумкин
16.11.2013 12:01

Что конкретно у тебя сломалось?

На прошлом уроке мы закоммитили изменения в Git, так что ты можешь просто откатить все изменённые файлы к этому состоянию. Это называется revertПотом синхронизизируй изменения с сервером, обнови кэш и можно начинать заново.

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

ilyautkinИлья Уткин
16.11.2013 12:36

Не, ничего не сломалось, но это пока что) Спасибо, буду знать

Сергей Росоловский
16.11.2013 22:08

Василий уверяет что самое сложное позади :) Как по мне так еще впереди. Хотя вроде сложностей не возникает но понимание приходит как-то не спеша.

bezumkinВасилий Наумкин
17.11.2013 02:08

Лично я потратил очень много времени, чтобы прийти к верной организации труда.

А потом все уже просто - сиди, да работай: внёс изменение, страничку обновил, проверил, закомитил, следующее изменение.

5636504Василий
18.11.2013 08:30

Если вы видите то же, что и я — всё хорошо.

Правильно ли понимаю, что это состояние - остаточный результат от modExtra? Т.е. после того, как мы изменяем файлы index.class.php, home.class.php и home.js - админка компонента должна быть пустой?

bezumkinВасилий Наумкин
18.11.2013 08:32

Да, я же написал в конце

Это страница от modExtra, она вызывает его контроллеры, с его объектами (которые мы удалили), поэтому в логе MODX должны появиться ошибки:

Сегодня или завтра будет новая заметка, где мы разберём и перепишем эти файлы.

ershov.ilyaИлья Ершов
22.11.2013 07:50

Все это вам знать не обязательно!

Ну не соглашусь... Статья при первом прочтении самая сложная из всего курса до этого. И если бы не было подробных разъяснений нумерованным списком, то не усвоилось бы ни чего. А так всё в голове улеглось по полочкам!

Из психологии человека: Трудно усваивать информацию которая просто описывает последовательность действий. Человеческий мозг запоминает ассоциативно, поэтому намного лучше усваиваются причинно-следственные связи.

Уже только благодаря этой статье я не пожалел, что вписался в этот курс! Василий спасибо!

bezumkinВасилий Наумкин
22.11.2013 08:07

На здоровье!

Просто, на самом деле, я с этим механизмом разбирался только при разработке miniShop2, а для более простых дополнений там ничего менять не нужно.

Но кругозор всегда расширить полезно, не спорю =)

ershov.ilyaИлья Ершов
22.11.2013 09:59

Блин не понимаю где косяк...

echo 'Hello world';die; // не подхватывается...

настройки: sendex_assets_path {base_path}Sendex/assets/components/sendex/ sendex_assets_url /Sendex/assets/components/sendex/ sendex_core_path {base_path}Sendex/core/components/sendex/

уже качнул с GitHub'а последнюю версию, почистил кэш (удалением папки /core/cache/) и всё равно никакой реакции...

bezumkinВасилий Наумкин
22.11.2013 10:02

Ты забыл про настройки namespace - контроллеры грузятся в зависимости от неё.

ershov.ilyaИлья Ершов
22.11.2013 10:03

:)

ershov.ilyaИлья Ершов
22.11.2013 10:02

Сам уже догнал... после переустановки пакета слетело Пространство имён...

bezumkinВасилий Наумкин
22.11.2013 10:04

Да, и там мы потом делаем новую настроечку, чтобы указывать этот параметр при сборке пакета.

ershov.ilyaИлья Ершов
22.11.2013 10:38

Что-то я пропустил. А где хранится дефолтный конфиг класса Sendex?

ershov.ilyaИлья Ершов
22.11.2013 10:38

Ага,.. в самом классе...

bezumkinВасилий Наумкин
22.11.2013 10:38

Поясни, про что ты.

Если про конфигурацию сборки - то в /_build/build.config.php

ershov.ilyaИлья Ершов
22.11.2013 10:59

Не не, я про то, откуда взялось: $this->Sendex->config['jsUrl']

Нашёл уже.

ElectricaМихаил
29.11.2013 16:43

А меня вот так. Не могу найти кто же его ищет. UPD. Мистика, после 5-ти раз чистки кеша все ок.

bezumkinВасилий Наумкин
29.11.2013 16:48

Ты не забывай, что файлы синхронизируются с удалённым сервером - это может занять какое-то время.

Roman Smile
31.01.2014 12:03

Если мы захотим туда добавить еще одни пункт, то будет примерно так:

$tmp = array(
    'sendex' => array(
        'description' => 'sendex_menu_desc',
        'action' => array(
            'controller' => 'index',
        ),
    ),
    'another_menu' => array(
        'description' => 'Мое описание',
        'action' => array(
            'controller' => 'а здесь файл-контроллер',
        ),
    ),

);

А как теперь убрать этот пункт меню? Нужно вручную его удалять из таблицы modx_menus? Следует что-то еще подчистить?

bezumkinВасилий Наумкин
31.01.2014 12:06

В админке MODX есть управление верхним меню. Просто удали ненужный пункт оттуда, больше ничего чистить не нужно.

Это просто ссылка.

Это сообщение было удалено
Это сообщение было удалено
Это сообщение было удалено
Это сообщение было удалено
Алексей Карташов
13.03.2014 13:12

Вот жеж ёлки-палки! Вот это я стормозил.. Дошло, наконец.

Слушай, аж стыдно за такую глупость. Удали, пожалуйста, эту ветку, чтобы мне не позориться))

bezumkin
Василий Наумкин
04.07.2022 23:34
Что-то странное у тебя произошло: миграция есть, и вроде как выполнена, но таблицы при этом отсутств...
inetlover
Александр Наумов
03.07.2022 20:36
Василий, спасибо! Все понятно!
bezumkin
Василий Наумкин
02.07.2022 20:28
Спасибо, поправил!
bezumkin
Василий Наумкин
30.06.2022 03:58
Есть ли возможность формировать &quot;friendly URL aliases&quot;, используя аналог translit MODx? ...
bezumkin
Василий Наумкин
27.06.2022 03:32
Спасибо за исправления, очень выручаешь =) Но учитывая количество не описаных в заметке дополнительн...
bezumkin
Василий Наумкин
27.06.2022 03:10
что будет использоваться для вывода многоуровневого меню Посмотри как работают комментарии на этом ...
bezumkin
Василий Наумкин
25.06.2022 11:56
Поправил, спасибо!
bezumkin
Василий Наумкин
21.06.2022 01:58
onLoad(data) { this.total = data.total }, и onLoad({total}) { this.total = total }, В нашем случ...
bezumkin
Василий Наумкин
20.06.2022 14:01
Прекрасно тебя понимаю, я когда сам в этом разбирался - голова дымилась. Но зато теперь прямо-таки п...
bezumkin
Василий Наумкин
20.06.2022 09:30
Не надо, оно по умолчанию так - я просто чуть более подробно написал.